Advertisement
ijontichy

packagepk3.py

Apr 29th, 2012
77
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
Python 8.10 KB | None | 0 0
  1. #!/usr/bin/env python3
  2.  
  3. import sys, os, shutil, zipfile, tempfile
  4. from subprocess import Popen, PIPE
  5.  
  6. import which
  7. from pathwalker import pathwalker
  8. from decpreproc import *
  9.  
  10. LINEPROCS   = [defineproc.DefineProc(), includeproc.IncludeDirProc()]
  11.  
  12. NUMBERS     = "0123456789"
  13.  
  14. MAKE_ACT    = "make"
  15. TEST_ACT    = "test"
  16. PACKAGE_ACT = "package"
  17. HELP_ACT    = "help"
  18.  
  19. USAGE = "usage: {} [{}] <args>".format(os.path.basename(sys.argv[0]), "|".join([MAKE_ACT, TEST_ACT, PACKAGE_ACT, HELP_ACT]))
  20.  
  21. USAGE_FULL = """
  22. - make: Builds a PK3 from the files in the pk3/ directory, with the name being
  23.  that of the current directory.
  24.  
  25. - test [port=skulltag] <args>: Runs 'make', and then runs 'port' with the PK3,
  26.  along with any arguments you choose.
  27.  
  28. - package [version]: Runs 'make', with 'version' at the end of the name, copies
  29.  it to a ZIP with the same name, and copies the PK3 to "$HOME/.zdoom" if the
  30.  directory exists.
  31.  
  32. - help: Prints this.
  33.  
  34. Examples:
  35.  # PWD is /home/derp/derpPK3
  36.  packagepk3.py make  # derpPK3.pk3
  37.  packagepk3.py test skulltag -file nuts
  38.  packagepk3.py package 1_5  # derpPK3_1_5.pk3, derpPK3_1_5.zip,
  39.                             # /home/derp/.zdoom/derpPK3_1_5.pk3
  40.  # PWD is /home/derp/derpWAD
  41.  packagepk3.py package 1_5  # derpWAD1_5.pk3, derpWAD1_5.zip,
  42.                             # /home/derp/.zdoom/derpWAD1_5.pk3
  43. """
  44.  
  45. DECORATE_EXTS   = ("dec",)
  46. ACS_EXTS        = ("c", "acs")
  47. ACS_OBJ_EXTS    = ("o",)
  48.  
  49. ACC_ERROR   = "**** ERROR ****"
  50.  
  51. DEFAULT_ARGS = ["-iwad doom2", "-warp 01"]
  52.  
  53. def warn(reason):
  54.     print("warning:", reason, file=sys.stderr)
  55.  
  56.  
  57. def errorExit(code = 1, reason = None):
  58.     if reason:
  59.         print("ERROR:", reason, file=sys.stderr)
  60.  
  61.     sys.exit(code)
  62.  
  63. def usageExit(code = 1, reason = None):
  64.     if reason:
  65.         print("error:", reason, file=sys.stderr)
  66.  
  67.     usage()
  68.     sys.exit(code)
  69.  
  70. def usage():
  71.     print(USAGE)
  72.  
  73. def usageFull():
  74.     usage()
  75.     print(USAGE_FULL)
  76.  
  77. NO_ARGS, NO_PK3, NO_ACC, NO_VERSION, ACC_FAIL, NO_BINARY, PREPROC_FAIL = range(4, 11)
  78.  
  79. PK3NAME = os.path.basename(os.path.realpath("."))
  80.  
  81. WAD_DIR = os.environ["HOME"] + "/.zdoom"
  82.  
  83. if not os.path.isdir(WAD_DIR):
  84.     warn("{} does not exist - no pk3 auto-installation will be done".format(WAD_DIR))
  85.     WAD_DIR = None
  86.  
  87. zdoomExe = "zdoom" + (".exe" if sys.platform[:3] == "win" else "")
  88. skulltagExe = "skulltag" + (".exe" if sys.platform[:3] == "win" else "")
  89.  
  90. if which.is_exe(zdoomExe):
  91.     ZDOOM = os.path.realpath(zdoomExe)
  92. else:
  93.     ZDOOM = which.which(zdoomExe)
  94.  
  95.     if ZDOOM is None:
  96.         warn("no zdoom in PATH or PWD")
  97.  
  98. if which.is_exe(skulltagExe):
  99.     SKULLTAG = os.path.realpath(skulltagExe)
  100. else:
  101.     SKULLTAG = which.which(skulltagExe)
  102.  
  103.     if SKULLTAG is None:
  104.         warn("no skulltag in PATH or PWD")
  105.  
  106.  
  107. if which.is_exe("acc"):
  108.     ACC = os.path.realpath("acc")
  109. else:
  110.     ACC = which.which("acc")
  111.  
  112.     if ACC is None:
  113.         ACC_DIR = None
  114.         errorExit(NO_ACC, "no acc in PATH or PWD")
  115.     else:
  116.         ACC_DIR = ACC.rpartition("/")[0]
  117.  
  118.  
  119.  
  120. def playPK3(pk3, binary=SKULLTAG, *args):
  121.  
  122.     if binary is None:
  123.         errorExit(1, "no binary")
  124.  
  125.     pk3 = os.path.realpath(pk3)
  126.  
  127.     if not os.path.isfile(pk3):
  128.         errorExit(NO_BINARY, "somehow, {} doesn't exist")
  129.  
  130.     if not args:
  131.         args = DEFAULT_ARGS
  132.     elif isinstance(args, str):
  133.         args = [i for i in args.split(" ") if i]
  134.     else:
  135.         args = list(args)
  136.  
  137.     pk3Game = Popen([binary, "-file {}".format(pk3)] + args)
  138.     pk3Game.wait()
  139.  
  140.     return 0
  141.  
  142.  
  143. def compileACS(file):
  144.     file2 = file
  145.     file = os.path.realpath(file)
  146.  
  147.     if not os.path.isfile(file):
  148.         errorExit(ACC_FAIL, "must provide name of actual file")
  149.  
  150.     newFile = file.rpartition(".")[:2] + ("o",)
  151.     newFile = "".join(newFile)
  152.  
  153.     newFile2 = file2.rpartition(".")[:2] + ("o",)
  154.     newFile2 = "".join(newFile2)
  155.  
  156.     accProc = Popen([ACC, "-i", ACC_DIR, file, newFile], stdout=PIPE, stderr=PIPE)
  157.  
  158.     accOut, accErr = (i.decode().split("\n") for i in accProc.communicate())
  159.  
  160.     if ACC_ERROR in accErr:
  161.         reasonLines = accErr[accErr.index(ACC_ERROR)+1:]
  162.         reason = "\n".join(reasonLines)
  163.  
  164.         raise RuntimeError(reason)
  165.  
  166.     return newFile2
  167.  
  168.  
  169. def makePK3(aArgs):
  170.     if not os.path.isdir("pk3"):
  171.         errorExit(NO_PK3, "no pk3/ directory")
  172.  
  173.     pk3Walk = pathwalker.PathWalker('pk3')
  174.  
  175.     oldDir = os.getcwd()
  176.     os.chdir("pk3")
  177.  
  178.     pk3Name     = "{}.pk3".format(PK3NAME)
  179.     pk3Name2    = os.path.realpath("../{}.pk3".format(PK3NAME) )
  180.     pk3Zip      = zipfile.ZipFile(pk3Name2, "w")
  181.     pk3Files    = pk3Walk.walk(abs=1, fFilter=lambda x: not x.endswith("*.o")).flattenFiles(rel=1)
  182.     pk3Total    = len(pk3Files)
  183.     nLen        = 0
  184.  
  185.     print("making... ", end="")
  186.  
  187.     try:
  188.         for i, file in enumerate(pk3Files):
  189.             j = i + 1
  190.  
  191.             oLen = nLen
  192.             perc = "{}%".format(int( ( (j / pk3Total) * 100) ) )
  193.             nLen = len(perc)
  194.  
  195.             print(("\b"*oLen) + perc, end="")
  196.  
  197.             sys.stdout.flush()
  198.            
  199.             fPath, fName = os.path.realpath(file).rsplit("/", 1)
  200.             fExt = file.rsplit(".", 1)[1]
  201.  
  202.             zipFName = file.lstrip("./")
  203.  
  204.             if fExt in DECORATE_EXTS:  # DECORATE
  205.                 prevDir = os.getcwd()
  206.  
  207.                 os.chdir(fPath)
  208.  
  209.                 dTmpName = tempfile.mkstemp(prefix="dec")[1]
  210.                 dTmp     = open(dTmpName, "w")
  211.                
  212.                 try:
  213.                     dTmp.write(fileproc.processFile(fName, LINEPROCS))
  214.                 except lineproc.LineProcError as exc:
  215.                     reason = exc.args[0]
  216.  
  217.                     print("\n !!! ERROR !!!", file=sys.stderr)
  218.                     print("  In file {}:".format(fPath), file=sys.stderr)
  219.                     print("    {}".format(reason), file=sys.stderr)
  220.                     sys.exit(PREPROC_FAIL)
  221.  
  222.                 finally:
  223.                     dTmp.close()
  224.                
  225.                 os.chdir(prevDir)
  226.  
  227.                 pk3Zip.write(dTmpName, zipFName)
  228.            
  229.             elif fExt in ACS_OBJ_EXTS:  # ACS .o - will be handled later
  230.                 pass
  231.  
  232.             elif fExt in ACS_EXTS:  # ACS
  233.                 objFile = compileACS(file)
  234.                 pk3Zip.write(objFile, objFile.lstrip("./"))
  235.                 pk3Zip.write(file, zipFName)
  236.            
  237.             else:
  238.                 pk3Zip.write(file, zipFName)
  239.  
  240.     except KeyboardInterrupt:
  241.         print( ("\b" * (nLen + 2)) + "aborted.")
  242.         os.remove(pk3Name2)
  243.         sys.exit(127)
  244.  
  245.     except RuntimeError as exc:
  246.         print()
  247.         errorExit(1, "\n" + exc.args[0])
  248.  
  249.     pk3Zip.close()
  250.     os.chdir(oldDir)
  251.     print( ("\b" * nLen) + "done.")
  252.  
  253.     return pk3Name
  254.  
  255. def testPK3(aArgs):
  256.     pk3 = makePK3([])
  257.     playPK3(pk3, *aArgs)
  258.  
  259.  
  260. def packagePK3(aArgs):
  261.  
  262.     if len(aArgs) < 1:
  263.         usageExit(NO_VERSION, "no version supplied")
  264.  
  265.     pk3 = makePK3([])
  266.  
  267.     print("renaming... ", end="")
  268.     sys.stdout.flush()
  269.  
  270.     pk3Name = os.path.basename(pk3)
  271.     pk3Base = pk3Name.rsplit(".", 1)[0]
  272.  
  273.     zipBase = [pk3Base, aArgs[0]]
  274.  
  275.     if pk3Base[-1] in NUMBERS:
  276.         zipBase = "_".join(zipBase)
  277.     else:
  278.         zipBase = "".join(zipBase)
  279.  
  280.     zipName  = "{}.zip".format(zipBase)
  281.     pk3Name2 = "{}.pk3".format(zipBase)
  282.  
  283.     shutil.move(pk3, pk3Name2)
  284.     print("done.")
  285.  
  286.     print("packaging... ", end="")
  287.     sys.stdout.flush()
  288.  
  289.  
  290.     pk3Zip = zipfile.ZipFile(zipName, "w")
  291.  
  292.     for file in (pk3Name2, "README", "README.txt", "CHANGELOG", "CHANGELOG.txt"):
  293.         if os.path.isfile(file):
  294.             pk3Zip.write(file, file)
  295.  
  296.     pk3Zip.close()
  297.  
  298.     print(zipName)
  299.  
  300.     if WAD_DIR is not None:
  301.         pk3Name3 = WAD_DIR + "/" + pk3Name2
  302.  
  303.         print("copying {} to {}... ".format(pk3Name2, pk3Name3), end="")
  304.         sys.stdout.flush()
  305.  
  306.         shutil.copy(pk3Name2, pk3Name3)
  307.         print("done.")
  308.  
  309. def printHelp(aArgs):
  310.     usageFull()
  311.  
  312.  
  313. choices = {MAKE_ACT: makePK3, TEST_ACT: testPK3, PACKAGE_ACT: packagePK3,
  314.             HELP_ACT: printHelp}
  315.  
  316. #######
  317. ##
  318. #   MAIN CODE
  319. ##
  320. ###
  321.  
  322. def main(*args, **kwargs):
  323.  
  324.     if len(args) < 2:
  325.         usageExit(NO_ARGS, "not enough arguments")
  326.  
  327.     action = args[1].lower()
  328.     aArgs  = args[2:]
  329.  
  330.     if action in choices:
  331.         choices[action](aArgs)
  332.     else:
  333.         usageExit(127, "not a valid command")
  334.  
  335. if __name__ == "__main__":
  336.     main(*sys.argv)
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement