/buildit.py
Python | 416 lines | 397 code | 8 blank | 11 comment | 10 complexity | 878adad671816bb7d6617cb892464b24 MD5 | raw file
Possible License(s): GPL-3.0
- #!/usr/bin/env python
- # Axe GUI Library (InfinGUI?) Builder v1.0
- # (C) Copyright 2011 Albert Huang.
- #
- import tokenizer
- import os, sys
- import getopt
- import webbrowser
- import subprocess
- import datetime
- from cStringIO import StringIO
- # Version variable
- VERSION="1.0"
- # Core variables
- # Debugging?
- global DEBUG
- DEBUG=0
- # Where to get help?
- global webhelpurl
- webhelpurl='http://www.omnimaga.org/index.php?board=146.0'
- # Builder actions
- global actions
- actions=[]
- # What to build?
- global tobuild
- tobuild=[]
- # SPASM path
- global spasmpath
- spasmpath=""
- # What files need to be tokenized?
- # Format: [ 'source file', 'target 8xp file' ]
- # Separate each spec array with a comma.
- TOTOKEN = [
- ['AXEGUI.txt', 'AXEGUI.8xp'],
- ['GUIDEMO.txt', 'GUIDEMO.8xp']
- ]
- # What files need to be assembled?
- # Format: [ 'Z80 source file', 'target 8xp file' ]
- # Separate each spec array with a comma.
- TOASSEM = [
- ['DCSAxiom.z80', 'DCSAxiom.8xp']
- ]
- ##################################################
- # Core functions
- ##################################################
- # Hexidecimal to decimal converter
- def hex2dec(s):
- return int(str(s), 16)
- # Find element in array
- def findelement(string, thelist):
- """Return first item in sequence where f(item) == True."""
- dprint("[DEBUG] [FindElement] Search item is "+string)
- dprint("[DEBUG] [FindElement] List to look inside of is "+str(thelist))
- for item in thelist:
- dprint("[DEBUG] [FindElement] String is "+string+", item is "+item)
- if string == item:
- return True
- break
- return False
- ##################################################
- # CLI functions
- ##################################################
- # Help/usage
- def help_usage():
- print "Axe GUI Builder v"+VERSION+""
- bar=""
- for i in range(0,len("Axe GUI Builder v"+VERSION+"")):
- bar=bar+"="
- print bar
- print "Usage: "+sys.argv[0]+" [option(s)]\n"
- print "General options:"
- print "\t"+"-b, --build"+"\t\t"+"Build Axe GUI. (Default) This implies -n"
- print "\t\t\t\t"+"(building regular Axe GUI source code) and -s (building Axe"
- print "\t\t\t\t"+"GUI DCS edition/wrapper)."
- print "\t"+"-r, --reverse"+"\t\t"+"Detokenize Axe GUI source to raw text."
- print "\t\t\t\t"+"Useful for recovering the raw text source of Axe GUI."
- print "\t"+"-c, --clean"+"\t\t"+"Remove any built files."
- print "\t"+"-t, --test"+"\t\t"+"Test the built files - send them to WabbitEmu."
- print "Building choice options:"
- print "\t"+"-n, --normalbuild"+"\t"+"Build regular Axe GUI source code (the"
- print "\t\t\t\t"+"'original' Axe GUI)."
- print "\t"+"-s, --dcsbuild"+"\t\t"+"Build Axe GUI DCS edition/wrapper."
- print "Building options:"
- print "\t"+"-p, --spasmpath=[path]"+"\t"+"Specify path to the SPASM assembler."
- print "\t\t\t\t"+"This is usually automatically detected by the builder."
- print "\t"+"-d, --debug"+"\t"+"Enable builder debugging."
- print "Help/About:"
- print "\t"+"-h, --help"+"\t\t"+"Get help! :) (Shows this help)"
- print "\t"+"-w, --webhelp"+"\t\t"+"Go to PRIZM hacking site for more info/help! :)"
- #print "\t"+"-c, --credits"+"\t\t"+"Who made this awesome program? :D"
- print "\t\t\t\t"+"(This also shows the license of this program.)"
- print ""
- print "You may specify multiple commands to the builder, and the builder"
- print "will execute each based on the order of the commands (arguments)."
- # Credits/license
- def credits_license():
- print "Axe GUI Builder v"+VERSION+""
- bar=""
- for i in range(0,len("Axe GUI Builder v"+VERSION+"")):
- bar=bar+"="
- print bar
- print "(C) Copyright 2011 Albert Huang."
- print ""
- print "This program is under.... [insert license here, GPL perhaps?]"
-
- # Pretty printing?
- def tprint(str="\n"):
- if str=="\n":
- print ""
- else:
- print " == "+str
- # Debug printing - only prints if debugging is enabled, either from the
- # commandline or in the script.
- def dprint(str="\n"):
- global DEBUG
- if DEBUG==1:
- if str=="\n":
- print ""
- else:
- print " ++ "+str
- # Web help function
- def LaunchWebHelp():
- tprint("Opening online help...")
- webbrowser.open(webhelpurl)
- tprint("Online help launched. If nothing happens after a few")
- tprint("moments, please open the following URL:")
- tprint(webhelpurl)
- # Builder functions
- def doclean():
- tprint("Cleaning source tree...")
- for file in [ "src/AXEGUI_READY.txt", "src/AXEGUI.8xp", "src/dcs7axiom/DCSAxiom.8xp" ]:
- try:
- os.remove(file)
- tprint("Removed file "+file+"!")
- except:
- tprint("The file "+file+" doesn't exist, so skipping.")
- def dobuild():
- tprint("Building...")
- for build in tobuild:
- if build == 'normal':
- tprint("\tBuilding Axe GUI...")
- for src in TOTOKEN:
- fileexist = 0
- try:
- open(os.path.join("src", "axegui", src[1]), "r").close()
- fileexist = 1
- except:
- fileexist = 0
- if fileexist == 1:
- tprint("\t\tSkipping "+src[0]+", since it's already built ("+src[1]+" already exists)!")
- else:
- # Create the header!
- tprint("\t\tAdding header to "+src[0]+"...")
- # Read the original source file
- origsrcf = open(os.path.join("src", "axegui", src[0]), "r")
- origsrc = origsrcf.read()
- origsrcf.close()
-
- # Check name, and pad with null characters if necessary (\x00)
- # or trim it down.
- name = src[0].split('.')[0].upper()
- if len(name) < 8:
- remain = 8 - len(name)
- for n in range(0, remain):
- name = name + "\x00"
- if len(name) > 8:
- name = name[:8]
-
- # Create comment!
- # The length of the comment is 42, padded by null bytes if necessary.
- # Comment is "Prgm by AGLBldr v1.0 on xx/xx/xx xx:xx:xx"
- # Comment is "Single file dated Fri Mar 19 16:27:39 20 "
- datestr = datetime.datetime.now().strftime("%m/%d/%y %H:%M:%S")
- comment = "Prgm by AGLBldr v1.0 on "+datestr
-
- if len(comment) < 42:
- remain = 42 - len(comment)
- for n in range(0, remain):
- comment = comment + "\x00"
- if len(name) > 42:
- comment = comment[:42]
-
- # Is the program protected?
- protectedfield = "not protected"
-
- # Put it all together! :D
- finalsrc = name + "\n" + protectedfield + "\n" + comment + "\n" + origsrc
-
- newname = src[0].replace('.txt', '_READY.txt')
- tprint("\t\tFormatting "+src[0]+" to "+newname+"...")
- ftmp = open(os.path.join("src", "axegui", newname), "w")
- ftmp.write(finalsrc)
- ftmp.close()
-
- tprint("\t\tTokenizing "+src[0]+" (using formatted "+newname+")...")
- savedstdout = sys.stdout
- sys.stdout = compileout = StringIO()
- ret = tokenizer.recompile(os.path.join("src", "axegui", newname), os.path.join("src", "axegui", src[1]))
- sys.stdout = savedstdout
- print("\t\t\t"+compileout.getvalue().strip())
- if ret:
- tprint("\t\tTokenization successful! :D")
- else:
- print "Tokenization failed! :( See the above error messages for details."
- sys.exit(1)
- if build == 'dcs':
- tprint("\tBuilding Axe GUI, DCS edition/wrapper...")
- for src in TOASSEM:
- fileexist = 0
- try:
- open(os.path.join("src", "dcs7axiom", src[1]), "r").close()
- fileexist = 1
- except:
- fileexist = 0
- if fileexist == 1:
- tprint("\t\tSkipping "+src[0]+", since it's already built ("+src[1]+" already exists)!")
- else:
- tprint("\t\tAssembling "+src[0]+"...")
- olddir=os.getcwd()
- os.chdir(os.path.join("src", "dcs7axiom"))
- ASM_PROC = subprocess.Popen([spasmpath, '-N', src[0], src[1]], shell=False, stdout=subprocess.PIPE, stderr=subprocess.STDOUT)
- ASM_OUTPUT = ASM_PROC.stdout.read()
- ASM_ERRCODE = ASM_PROC.wait()
- os.chdir(olddir)
- for line in ASM_OUTPUT.strip().split("\n"):
- tprint("\t\t\t"+line)
- if (ASM_ERRCODE != 0) and (ASM_ERRCODE != 1):
- print "SPASM returned error code: "+str(ASM_ERRCODE)
- print "Assembling failed! :( See the above error messages for details."
- sys.exit(1)
- def doreverse():
- tprint("Detokenizing files...")
- for src in TOTOKEN:
- fileexist = 0
- try:
- open(os.path.join("src", src[1]), "r").close()
- fileexist = 1
- except:
- fileexist = 0
- if fileexist == 1:
- tprint("\t\tDetokenizing "+src[1]+"...")
- savedstdout = sys.stdout
- sys.stdout = decompileout = StringIO()
- ret = tokenizer.decompile(os.path.join("src", src[1]), os.path.join("src", "rev_"+src[0]))
- sys.stdout = savedstdout
- print("\t\t\t"+decompileout.getvalue().strip())
- if ret:
- tprint("\t\tDetokenization successful! :D")
- else:
- print "Detokenization failed! :( See the above error messages for details."
- sys.exit(1)
- else:
- tprint("\t\tCouldn't find "+src[1]+", so not detokenizing...")
- # The main function!
- def main(argv=None):
- global actions, DEBUG, tobuild, spasmpath
- if argv is None:
- argv = sys.argv
-
- args = []
-
- try:
- # NOTE TO SELF: for short args, ":" will require argument,
- # "=" in long args to require an argument
- opts, args = getopt.gnu_getopt(argv[1:], "brctnsp:dhwl", ["build", "reverse", "clean", "test", "normalbuild", "dcsbuild", "spasmpath", "debug", "help", "webhelp", "credits"])
- except getopt.error, err:
- print "ERROR: "+str(err.msg)+"\n"
- help_usage()
- sys.exit(2)
-
- for opt, arg in opts:
- # Is the user asking for help?
- if opt in ("-h", "--help"):
- help_usage()
- sys.exit()
- # ...or do they like web help?
- if opt in ("-w", "--webhelp"):
- LaunchWebHelp()
- sys.exit()
- # Maybe they want to know who wrote this program!
- if opt in ("-l", "--credits"):
- credits_license()
- sys.exit()
- if opt in ("-b", "--build"):
- if (not(findelement("normal", tobuild))):
- tobuild.append("normal")
- if(not(findelement("dcs", tobuild))):
- tobuild.append("dcs")
- actions.append("build")
- if opt in ("-n", "--normalbuild"):
- if (not(findelement("normal", tobuild))):
- tobuild.append("normal")
- if(not(findelement("build", actions))):
- actions.append("build")
- if opt in ("-s", "--dcsbuild"):
- if(not(findelement("dcs", tobuild))):
- tobuild.append("dcs")
- if(not(findelement("build", actions))):
- actions.append("build")
- # Other tasks
- # Detokenize the compiled file?
- if opt in ("-r", "--reverse"):
- actions.append("reverse")
- # Clean the source tree?
- if opt in ("-c", "--clean"):
- actions.append("clean")
- # Grab assembler path, if specified
- if opt in ("-p", "--spasmpath"):
- spasmpath = arg
- # Does the user want to debug?
- if opt in ("-d", "--debug"):
- global DEBUG
- DEBUG=1
- if not len(sys.argv)>1:
- print "ERROR: No arguments specified!"
- help_usage()
- sys.exit(1)
-
- tprint("Doing sanity checks...")
-
- # Check for SPASM and a valid SPASM path.
- if spasmpath != '':
- tprint("Checking if SPASM path is correct...")
- try:
- open(spasmpath, "r").close()
- except:
- print "ERROR: The SPASM assembler path you have specified is invalid!"
- print "Check to make sure that the program exists, there are no"
- print "permission problems, and that the program is accessible, and"
- print "then try again."
- sys.exit(1)
- else:
- paths=os.environ["PATH"].split(":")
- found=[]
- finalpick=""
- tprint("Searching for spasm in PATH...")
- for path in paths:
- try:
- if sys.platform == 'win32':
- open(os.path.join(path, "spasm.exe")).close()
- found.append(os.path.join(path, "spasm.exe"))
- else:
- open(os.path.join(path, "spasm")).close()
- found.append(os.path.join(path, "spasm"))
- except:
- # Do nothing
- continue
- if len(found) == 0:
- print "ERROR: The SPASM assembler couldn't be found!"
- print "Check to make sure that the program exists, there are no"
- print "permission problems, and that the program is accessible, and"
- print "then try again. It's likely that you will need to install"
- print "SPASM assembler before you can run this again."
- sys.exit(1)
- if len(found) > 1:
- print "Multiple SPASM assemblers have been found!"
- n=1
- for pick in found:
- print str(n)+": "+pick
- n=n+1
- print "Enter the number of the SPASM assembler you want to use, then"
- print "press ENTER."
- choice = raw_input("Choose: ")
- if 1 < int(choice) < (len(found)):
- spasmpath = found[int(choice)-1]
- else:
- spasmpath = found[0]
- tprint("Using SPASM assembler found in "+spasmpath+"...")
-
- if len(actions) > 1:
- tprint("The builder will:")
- for n in range(0, len(actions)):
- if actions[n] == 'clean':
- desc = "clean up source tree"
- if actions[n] == 'build':
- desc = "build the source code"
- if actions[n] == 'reverse':
- desc = "detokenize files into source code"
- if n == (len(actions) - 1):
- tprint("\t"+"and "+desc+"!")
- else:
- tprint("\t"+desc+",")
- dprint("Friendly print debug: Actions array is "+str(actions))
- dprint("Friendly print debug: for loop range array is "+str(range(0, len(actions))))
-
- for act in actions:
- if act == 'clean':
- doclean()
- if act == 'build':
- dobuild()
- if act == 'reverse':
- doreverse()
- if __name__ == "__main__":
- sys.exit(main())