2012-04-06 13:10:11 +00:00
import os , os . path , sys
import urllib , zipfile
import shutil , glob , fnmatch
import subprocess , logging , re
2012-08-05 02:29:54 +00:00
import csv , shutil
2012-08-04 09:33:46 +00:00
import pprint
2012-04-06 13:10:11 +00:00
forge_dir = os . path . dirname ( os . path . abspath ( __file__ ) )
mcp_dir = os . path . abspath ( ' .. ' )
src_dir = os . path . join ( mcp_dir , ' src ' )
sys . path . append ( mcp_dir )
def reset_logger ( ) :
log = logging . getLogger ( )
while len ( log . handlers ) > 0 :
log . removeHandler ( log . handlers [ 0 ] )
version_reg = re . compile ( r ' (([a-z]+)Version[ \ s]+=[ \ s]+)( \ d+); ' )
def load_version ( build = 0 ) :
info = { ' major ' : - 1 ,
' minor ' : - 1 ,
' revision ' : - 1 ,
' build ' : - 1
}
2012-08-05 05:42:17 +00:00
hook_file = os . path . join ( forge_dir , ' common/net/minecraftforge/common/ForgeVersion.java ' . replace ( ' / ' , os . sep ) )
2012-04-06 13:10:11 +00:00
with open ( hook_file , ' r ' ) as fh :
buf = fh . read ( )
def proc ( match ) :
try :
info [ match . group ( 2 ) ] = int ( match . group ( 3 ) )
except :
pass
return match . group ( 0 )
buf = version_reg . sub ( proc , buf )
info [ ' build ' ] = build
return info
def inject_version ( src_file , build = 0 ) :
version = load_version ( build )
tmp_file = src_file + ' .tmp '
with open ( src_file , ' r ' ) as fh :
buf = fh . read ( )
def mapname ( match ) :
try :
return ' %s %s ; ' % ( match . group ( 1 ) , version [ match . group ( 2 ) ] )
except KeyError :
pass
return match . group ( 0 )
2012-04-06 14:16:14 +00:00
buf = version_reg . sub ( mapname , buf ) . replace ( ' \r \n ' , ' \n ' )
2012-04-06 13:10:11 +00:00
2012-04-06 14:16:14 +00:00
with open ( tmp_file , ' wb ' ) as fh :
2012-04-06 13:10:11 +00:00
fh . write ( buf )
shutil . move ( tmp_file , src_file )
def zip_folder ( path , key , zip ) :
files = os . listdir ( path )
for file in files :
file_path = os . path . join ( path , file )
file_key = os . path . join ( key , file )
if os . path . isdir ( file_path ) :
zip_folder ( file_path , file_key , zip )
else :
print file_key
zip . write ( file_path , file_key )
def zip_create ( path , key , zip_name ) :
zip = zipfile . ZipFile ( zip_name , ' w ' , zipfile . ZIP_DEFLATED )
if os . path . isdir ( path ) :
zip_folder ( path , key , zip )
else :
zip . write ( path , key )
2012-05-27 08:52:02 +00:00
zip . close ( )
2012-08-04 07:55:17 +00:00
def apply_forge_patches ( fml_dir , mcp_dir , forge_dir , src_dir , copy_files = True ) :
sys . path . append ( fml_dir )
from fml import copytree , apply_patches
2012-05-27 08:52:02 +00:00
2012-08-04 07:55:17 +00:00
has_client = os . path . isdir ( os . path . join ( src_dir , ' minecraft ' ) )
has_server = os . path . isdir ( os . path . join ( src_dir , ' minecraft_server ' ) )
2012-06-03 02:19:32 +00:00
2012-08-04 07:55:17 +00:00
#patch files
print ' Applying Minecraft Forge patches '
sys . stdout . flush ( )
if has_client :
if os . path . isdir ( os . path . join ( forge_dir , ' patches ' , ' minecraft ' ) ) :
apply_patches ( mcp_dir , os . path . join ( forge_dir , ' patches ' , ' minecraft ' ) , src_dir )
if copy_files and os . path . isdir ( os . path . join ( forge_dir , ' client ' ) ) :
copytree ( os . path . join ( forge_dir , ' client ' ) , os . path . join ( src_dir , ' minecraft ' ) )
2012-06-03 02:19:32 +00:00
2012-08-04 07:55:17 +00:00
if has_server :
if os . path . isdir ( os . path . join ( forge_dir , ' patches ' , ' minecraft_server ' ) ) :
apply_patches ( mcp_dir , os . path . join ( forge_dir , ' patches ' , ' minecraft_server ' ) , src_dir )
if copy_files and os . path . isdir ( os . path . join ( forge_dir , ' server ' ) ) :
copytree ( os . path . join ( forge_dir , ' server ' ) , os . path . join ( src_dir , ' minecraft_server ' ) )
if os . path . isdir ( os . path . join ( forge_dir , ' patches ' , ' common ' ) ) :
apply_patches ( mcp_dir , os . path . join ( forge_dir , ' patches ' , ' common ' ) , src_dir )
if copy_files and os . path . isdir ( os . path . join ( forge_dir , ' common ' ) ) :
2012-08-04 09:33:46 +00:00
copytree ( os . path . join ( forge_dir , ' common ' ) , os . path . join ( src_dir , ' common ' ) )
def get_conf_copy ( mcp_dir , forge_dir ) :
#Lets grab the files we dont work on
2012-08-04 09:40:21 +00:00
for file in [ ' astyle.cfg ' , ' version.cfg ' , ' patches/minecraft_ff.patch ' , ' patches/minecraft_server_ff.patch ' , ' newids.csv ' ] :
2012-08-04 09:35:34 +00:00
dst_file = os . path . normpath ( os . path . join ( forge_dir , ' conf ' , file ) )
2012-08-04 09:33:46 +00:00
src_file = os . path . normpath ( os . path . join ( mcp_dir , ' conf ' , file ) )
if os . path . exists ( dst_file ) :
os . remove ( dst_file )
2012-08-04 09:35:34 +00:00
shutil . copy ( src_file , dst_file )
2012-08-04 09:33:46 +00:00
print ' Grabbing: ' + src_file
2012-08-04 10:17:57 +00:00
common_srg = gen_merged_srg ( mcp_dir , forge_dir )
common_exc = gen_merged_exc ( mcp_dir , forge_dir )
common_map = gen_shared_searge_names ( common_srg , common_exc )
#ToDo use common_map to merge the remaining csvs, client taking precidense, setting the common items to side '2' and editing commands.py in FML to have 'if csv_side == side || csv_side == '2''
2012-08-05 02:29:54 +00:00
gen_merged_csv ( common_map , os . path . join ( mcp_dir , ' conf ' , ' fields.csv ' ) , os . path . join ( forge_dir , ' conf ' , ' fields.csv ' ) )
gen_merged_csv ( common_map , os . path . join ( mcp_dir , ' conf ' , ' methods.csv ' ) , os . path . join ( forge_dir , ' conf ' , ' methods.csv ' ) )
gen_merged_csv ( common_map , os . path . join ( mcp_dir , ' conf ' , ' params.csv ' ) , os . path . join ( forge_dir , ' conf ' , ' params.csv ' ) , main_key = ' param ' )
2012-08-04 09:33:46 +00:00
2012-08-04 09:35:34 +00:00
def gen_merged_srg ( mcp_dir , forge_dir ) :
2012-08-04 09:33:46 +00:00
print ' Generating merged Retroguard data '
srg_client = os . path . join ( mcp_dir , ' conf ' , ' client.srg ' )
srg_server = os . path . join ( mcp_dir , ' conf ' , ' server.srg ' )
if not os . path . isfile ( srg_client ) or not os . path . isfile ( srg_server ) :
print ' Could not find client and server srg files in " %s " ' % mcp_dir
return False
client = { ' PK: ' : { } , ' CL: ' : { } , ' FD: ' : { } , ' MD: ' : { } }
with open ( srg_client , ' r ' ) as fh :
for line in fh :
pts = line . rstrip ( ' \r \n ' ) . split ( ' ' )
if pts [ 0 ] == ' MD: ' :
client [ pts [ 0 ] ] [ pts [ 1 ] + ' ' + pts [ 2 ] ] = pts [ 3 ] + ' ' + pts [ 4 ]
else :
client [ pts [ 0 ] ] [ pts [ 1 ] ] = pts [ 2 ]
server = { ' PK: ' : { } , ' CL: ' : { } , ' FD: ' : { } , ' MD: ' : { } }
with open ( srg_server , ' r ' ) as fh :
for line in fh :
pts = line . rstrip ( ' \r \n ' ) . split ( ' ' )
if pts [ 0 ] == ' MD: ' :
server [ pts [ 0 ] ] [ pts [ 1 ] + ' ' + pts [ 2 ] ] = pts [ 3 ] + ' ' + pts [ 4 ]
else :
server [ pts [ 0 ] ] [ pts [ 1 ] ] = pts [ 2 ]
common = { ' PK: ' : { } , ' CL: ' : { } , ' FD: ' : { } , ' MD: ' : { } }
for type in common :
for key , value in client [ type ] . items ( ) :
if key in server [ type ] :
if value == server [ type ] [ key ] :
client [ type ] . pop ( key )
server [ type ] . pop ( key )
common [ type ] [ key ] = value
2012-08-05 02:29:54 +00:00
2012-08-04 09:33:46 +00:00
for type in common :
for key , value in client [ type ] . items ( ) :
2012-08-05 02:29:54 +00:00
common [ type ] [ key ] = value #+ ' #C'
2012-08-04 09:33:46 +00:00
for type in common :
for key , value in server [ type ] . items ( ) :
2012-08-05 02:29:54 +00:00
common [ type ] [ key ] = value #+ ' #S'
2012-08-04 09:33:46 +00:00
#Print joined retroguard files
with open ( os . path . join ( forge_dir , ' conf ' , ' joined.srg ' ) , ' w ' ) as f :
for type in [ ' PK: ' , ' CL: ' , ' FD: ' , ' MD: ' ] :
for key in sorted ( common [ type ] ) :
f . write ( ' %s %s %s \n ' % ( type , key , common [ type ] [ key ] ) )
2012-08-04 10:17:57 +00:00
return common
2012-08-04 09:33:46 +00:00
def gen_merged_exc ( mcp_dir , forge_dir ) :
print ' Generating merged MCInjector config '
exc_client = os . path . join ( mcp_dir , ' conf ' , ' client.exc ' )
exc_server = os . path . join ( mcp_dir , ' conf ' , ' server.exc ' )
client = { }
with open ( exc_client , ' r ' ) as fh :
for line in fh :
if not line . startswith ( ' # ' ) :
pts = line . rstrip ( ' \r \n ' ) . split ( ' = ' )
client [ pts [ 0 ] ] = pts [ 1 ]
server = { }
with open ( exc_server , ' r ' ) as fh :
for line in fh :
if not line . startswith ( ' # ' ) :
pts = line . rstrip ( ' \r \n ' ) . split ( ' = ' )
server [ pts [ 0 ] ] = pts [ 1 ]
common = { }
for key , value in client . items ( ) :
if key in server :
if value != server [ key ] :
print ' Error: Exec for shared function does not match client and server: '
print ' Function: ' + key
print ' Client: ' + value
print ' Server: ' + server [ value ]
if value != ' | ' :
common [ key ] = value
client . pop ( key )
server . pop ( key )
else :
if value != ' | ' :
common [ key ] = value
2012-08-05 02:29:54 +00:00
joined = dict ( common . items ( ) + server . items ( ) )
2012-08-04 09:33:46 +00:00
#Print joined mcinjector files
with open ( os . path . join ( forge_dir , ' conf ' , ' joined.exc ' ) , ' w ' ) as f :
2012-08-05 02:29:54 +00:00
for key in sorted ( joined ) :
f . write ( ' %s = %s \n ' % ( key , joined [ key ] ) )
2012-08-04 10:17:57 +00:00
return common
def gen_shared_searge_names ( common_srg , common_exc ) :
field = re . compile ( r ' field_[0-9]+_[a-zA-Z_]+$ ' )
method = re . compile ( r ' func_[0-9]+_[a-zA-Z_]+ ' )
param = re . compile ( r ' p_[ \ w]+_ \ d+_ ' )
2012-08-05 02:29:54 +00:00
print ' Gathering list of common searge names '
2012-08-04 10:17:57 +00:00
searge = [ ]
for key , value in common_srg [ ' FD: ' ] . items ( ) :
m = field . search ( value )
if not m is None :
if not m . group ( 0 ) in searge :
searge . append ( m . group ( 0 ) )
for key , value in common_srg [ ' MD: ' ] . items ( ) :
m = method . search ( value )
if not m is None and not ' # ' in value :
if not m . group ( 0 ) in searge :
searge . append ( m . group ( 0 ) )
for key , value in common_exc . items ( ) :
m = param . findall ( value )
if not m is None :
for p in m :
if not p in searge :
searge . append ( p )
return searge
2012-08-05 02:29:54 +00:00
def gen_merged_csv ( common_map , in_file , out_file , main_key = ' searge ' ) :
reader = csv . DictReader ( open ( in_file , ' r ' ) )
print ' Generating merged csv for %s ' % os . path . basename ( in_file )
sides = { ' client ' : [ ] , ' server ' : [ ] , ' common ' : [ ] }
added = [ ]
for row in reader :
side = int ( row [ ' side ' ] )
if row [ main_key ] in common_map :
if not row [ main_key ] in added :
row [ ' side ' ] = ' 2 '
sides [ ' common ' ] . append ( row )
added . append ( row [ main_key ] )
elif side == 0 :
sides [ ' client ' ] . append ( row )
else :
sides [ ' server ' ] . append ( row )
writer = csv . DictWriter ( open ( out_file , ' wb ' ) , fieldnames = reader . fieldnames )
writer . writeheader ( )
for key in [ ' client ' , ' server ' , ' common ' ] :
for row in sorted ( sides [ key ] , key = lambda row : row [ main_key ] ) :
writer . writerow ( row )
def setup_forge_mcp ( mcp_dir , forge_dir , dont_gen_conf = True ) :
mcp_conf = os . path . join ( mcp_dir , ' conf ' )
mcp_conf_bak = os . path . join ( mcp_dir , ' conf.bak ' )
forge_conf = os . path . join ( forge_dir , ' conf ' )
if os . path . isdir ( mcp_conf_bak ) :
print ' Removing old conf backup folder '
shutil . rmtree ( mcp_conf_bak )
if not dont_gen_conf :
get_conf_copy ( mcp_dir , forge_dir )
print ' Backing up MCP Conf '
os . rename ( mcp_conf , mcp_conf_bak )
print ' Copying Forge conf '
shutil . copytree ( forge_conf , mcp_conf )
2012-08-05 05:42:17 +00:00
def build_forge_dev ( mcp_dir , forge_dir , fml_dir , build_num = 0 ) :
version = load_version ( build_num )
print ' =================================== Build %d . %d . %d . %d Start ================================= ' % ( version [ ' major ' ] , version [ ' minor ' ] , version [ ' revision ' ] , version [ ' build ' ] )
src_dir = os . path . join ( mcp_dir , ' src ' )
if os . path . isdir ( src_dir ) :
shutil . rmtree ( src_dir )
sys . path . append ( fml_dir )
from fml import copytree
print ' src_work -> src '
copytree ( os . path . join ( mcp_dir , ' src_work ' ) , src_dir )
print ' \n Copying Client Code '
copytree ( os . path . join ( forge_dir , ' client ' ) , os . path . join ( src_dir , ' minecraft ' ) , - 1 )
print ' \n Copying Server Code '
copytree ( os . path . join ( forge_dir , ' server ' ) , os . path . join ( src_dir , ' minecraft_server ' ) , - 1 )
print ' \n Copying Common Code '
copytree ( os . path . join ( forge_dir , ' common ' ) , os . path . join ( src_dir , ' common ' ) , - 1 )
print
inject_version ( os . path . join ( src_dir , ' common/net/minecraftforge/common/ForgeVersion.java ' . replace ( ' / ' , os . sep ) ) , build_num )
error_level = 0
try :
sys . path . append ( mcp_dir )
from runtime . recompile import recompile
os . chdir ( mcp_dir )
reset_logger ( )
recompile ( None )
reset_logger ( )
os . chdir ( forge_dir )
except SystemExit , e :
print ' Recompile Exception: %d ' % e . code
error_level = e . code
print ' =================================== Build Finished %d ================================= ' % error_level
return error_level