def shipIOS(game): buildPath = game.getIOSBuildPath() setLocaleToUTF8() subprocess.call(utils.parList("fastlane fmcproduce"), cwd=buildPath) subprocess.call(utils.parList("fastlane fmcmatch"), cwd=buildPath) subprocess.call(utils.parList("fastlane fmctestflight"), cwd=buildPath) subprocess.call(utils.parList("fastlane fmcsettestinfo"), cwd=buildPath) subprocess.call(utils.parList("fastlane fmccreatetestgroup"), cwd=buildPath) updateIOSTesters(game)
def updateIOSTesters(game): #for these commands, I currently cannot use a lane, because they are sub actions. print("Distributing build to testers: " + str(config.getTestersMails())) gameCgf = game.getConfig() subprocess.call(utils.parList( f"fastlane pilot add -u {config.getAppStoreMail()} -a {gameCgf.bundleId} -g fmctesters" ) + config.getTestersMails(), cwd=game.gamePath) subprocess.call(utils.parList( f"fastlane pilot distribute --username {config.getAppStoreMail()} --app_identifier {gameCgf.bundleId} -g fmctesters --distribute_external true" ), cwd=game.gamePath)
def checkIOSBuilds(game): gameCgf = game.getConfig() if gameCgf is None: print(game.internalGameName + " was not built on this machine. Unable to get config.") else: subprocess.call(utils.parList( f"fastlane pilot builds -u {config.getAppStoreMail()} -a {gameCgf.bundleId}" ), cwd=game.gamePath)
def fillIOSTestInfo(game): gameBuildPath = game.getBuildFolderPath() if os.path.isdir(gameBuildPath): print("Found build folder", gameBuildPath) iOSBuildPath = game.getIOSBuildPath() if os.path.isdir(iOSBuildPath): initFastlane(game) subprocess.call(utils.parList("fastlane fmcfilltestinfo"), cwd=iOSBuildPath)
def runUnityMethod(self, methodName): unityExePath = config.getUnityExePath() try: pars = [unityExePath] + utils.parList('-quit -batchmode -executeMethod', methodName) + ['-projectPath', self.gamePath] subprocess.check_call(pars) print("SUCCESS") except subprocess.CalledProcessError: # handle errors in the called executable print("FAILED") errorsOccured = True except OSError: # executable not found errorsOccured = True
def hasFilesToCommit(self, showWhich, showNothingToCommitMessage): statusOutput = subprocess.check_output(utils.parList("git status -s"), cwd=self.gamePath) out = statusOutput.decode('ascii').strip(); hasFiles = len(out) > 0; if showWhich: if hasFiles: print(self.internalGameName + ":") out = "\n".join((" ") + i.strip() for i in out.splitlines()) print(out) elif showNothingToCommitMessage: print(self.internalGameName + " has nothing to commit") return hasFiles;
def launchUnity(self, methodName, waitForExit): print("Launching " + self.internalGameName + "...") unityExePath = config.getUnityExePath() try: method = utils.parList('-executeMethod', methodName) if methodName is not None else [] pars = [unityExePath] + method + ['-projectPath', self.gamePath] if waitForExit: subprocess.check_call(pars) else: subprocess.Popen(pars) print("SUCCESS") except subprocess.CalledProcessError: # handle errors in the called executable print("FAILED") errorsOccured = True except OSError: # executable not found errorsOccured = True
def sign(game): #These fields must not contain spaces! If you need them, modify utils.parList. password = config.getKeystorePassword() companyName = config.getCompanyName() keystoreName = "fmc.keystore" alias = "fmc" keystorePath = os.path.join(game.gamePath, keystoreName) if os.path.isfile(keystorePath): print("SKIPPING: A keystore already exist in: " + keystorePath) else: print("OK, SIGNING: ", game.gamePath) pars = (f'keytool -genkey -v -keystore {keystoreName} -sigalg SHA1withRSA -alias {alias} ' + f'-keyalg RSA -keysize 2048 -validity 30000 -keypass {password} ' + f'-storepass {password} -dname O={companyName}') subprocess.call(utils.parList(pars), cwd=game.gamePath) game.gitPull() game.gitAdd(keystoreName) game.gitCommit("Added keystore file") game.gitPush() utils.printWhiteLines(1)
def gitSubtreePush(self): subprocess.call(utils.parList("git subtree push --prefix", config.gitSubtreePrefix, config.getFMCRepoURL(), "master"), cwd=self.gamePath)
def gitPush(self): subprocess.call(utils.parList("git push"), cwd=self.gamePath)
def gitCommit(self, message): subprocess.call(utils.parList('git commit -m') + [message], cwd=self.gamePath)
def gitAdd(self, filePath): subprocess.call(utils.parList("git add " + filePath), cwd=self.gamePath)
def gitResetHard(self): subprocess.call(utils.parList("git reset --hard"), cwd=self.gamePath)
def shipAndroid(buildPath): setLocaleToUTF8() subprocess.call(utils.parList("fastlane fmcsupply"), cwd=buildPath)
def createNewProject(gameName): unityExePath = config.getUnityExePath() unityExeFolderPath = os.path.abspath(os.path.join(unityExePath, os.pardir)) gamesFolderPath = config.getFMCGamesFolderPath() nguiFolderPath = config.getNGUIFolderPath() parentRemoteURL = config.getParentRemoteURL() fmcRepoURL = config.getFMCRepoURL() #asking for project name gamePath = os.path.join(gamesFolderPath, gameName) ok = isGameNameValid(gamePath, gameName) if not ok: printIntro() while not ok: gameName = input( 'Enter the internal game name (no spaces, all lowercase! - e.g. stopthefall): ' ) gamePath = os.path.join(gamesFolderPath, gameName) ok = isGameNameValid(gamePath, gameName) repoUrl = parentRemoteURL + gameName #we have a valid game path and git repo. Ask for confirm... utils.printWhiteLines(2) utils.openPar("\nProject root: " + gamePath + "\nRemote repo: " + repoUrl + "\nInternal name:" + gameName) utils.waitForEnterKey() #creating Unity project... print('Creating Unity project. This will take some time...') pars = [unityExePath] + utils.parList( '-quit -batchmode -nographics -createproject') + [gamePath] subprocess.call(pars) print('Unity project created!') time.sleep(1) game = Game(gamePath) #init local git repo... subprocess.call(utils.parList("git init"), cwd=gamePath) subprocess.call(utils.parList("git remote add origin", repoUrl), cwd=gamePath) #adding .gitignore... shutil.copy(config.unityGitignorePath, os.path.join(gamePath, ".gitignore")) game.gitAdd(".gitignore") game.gitCommit("Added .gitignore") #creating remote repo... remoteURL = parentRemoteURL + gameName + ".git" subprocess.call(utils.parList("git push --set-upstream", remoteURL, "master"), cwd=gamePath) #first commit... game.gitAdd(".") game.gitCommit("Initial commit") #adding subtree... subprocess.call(utils.parList("git pull -u origin master"), cwd=gamePath) subprocess.call(utils.parList("git subtree add --prefix", config.gitSubtreePrefix, fmcRepoURL, "master --squash"), cwd=gamePath) subprocess.call(utils.parList("git push -u origin master"), cwd=gamePath) #adding NGUI... shutil.copytree(nguiFolderPath, os.path.join(gamePath, "Assets", "NGUI")) game.gitAdd(".") game.gitCommit("Added NGUI") #creating _content folders... utils.createFolder(os.path.join(gamePath, config.fmcContentFolder)) utils.createFolder( os.path.join(gamePath, config.fmcContentFolder, "Images")) utils.createFolder( os.path.join(gamePath, config.fmcContentFolder, "Prefabs")) utils.createFolder( os.path.join(gamePath, config.fmcContentFolder, "Scripts")) #Launching project and creating game settings print("Opening the game and creating settings...") game.runUnityMethod(config.unityUpdateSettingsMethodName) game.gitAdd(".") game.gitCommit("Added game settings") game.gitPush() webbrowser.open(remoteURL) os.startfile(os.path.realpath(gamePath)) game.launchUnity(config.unityFirstProjectLaunchMethodName, False) utils.closePar("FINISHED")
def reactToCommand(command): commandList = utils.parList(command) targetedGame = config.getTargetGame() games = config.getFMCGames() firstCommand = commandList[0]; secondCommand = None if len(commandList) > 1: secondCommand = commandList[1]; #Since platforms are useful for more commands, let's check them here targetAndroid = False targetIOS = False if "android" in commandList: targetAndroid = True if "ios" in commandList: targetIOS = True if not (targetAndroid or targetIOS): targetAndroid = True targetIOS = True if command == "info": printInfo() elif firstCommand == "create": gameName = "" if secondCommand is not None: gameName = secondCommand creator.createNewProject(gameName) elif firstCommand == "untarget": targeter.untarget() else: #if here, we are working on existing games #trying to find the targeted game toTarget = targetedGame if secondCommand is not None: if secondCommand != "" and secondCommand != "all" and not Game.isValidGame(secondCommand): for g in games: if g.internalGameName.startswith(secondCommand) and utils.readYesNo("Did you mean " + g.internalGameName + "?", True): secondCommand = g.internalGameName break if Game.isValidGame(secondCommand): toTarget = Game.fromInternalName(secondCommand) if firstCommand == "target": if toTarget is not None: targeter.target(secondCommand) else: targeter.target(None) elif firstCommand == "unity": if "all" in commandList: Game.launchUnityForAllGames("ask" in commandList) else: if toTarget is None: toTarget = Game.pick(True, "All") if toTarget is None: Game.launchUnityForAllGames("ask" in commandList) #The user selected "All" else: toTarget.launchUnity(None, False) elif firstCommand == "status": if toTarget is not None and secondCommand != "all": toTarget.hasFilesToCommit(True,True) else: gamesWithFilesToCommit = Game.getGamesWithFilesToCommit(True,False) if len(gamesWithFilesToCommit) <= 0: print("CLEAN - All games have no files to commit!") elif firstCommand == "pull": if "all" in commandList: puller.pullAll() else: if toTarget is None: toTarget = Game.pick(True, "All") if toTarget is None: puller.pullAll() #The user selected "All" else: puller.pull(toTarget, True) elif firstCommand == "push": #By default uses targeted game. If overridden, use the given one if toTarget is None: toTarget = Game.pick(False) pusher.push(toTarget) #if targeted game is None, a picker will appear elif firstCommand == "sign": if "all" in commandList: signer.signAll() else: if toTarget is None: toTarget = Game.pick(True, "All") if toTarget is None: signer.signall() #The user selected "All" else: signer.sign(toTarget) elif firstCommand == "build": if "all" in commandList: builder.buildAll(targetAndroid, targetIOS) else: if toTarget is None: toTarget = Game.pick(True, "All") if toTarget is None: builder.buildAll(targetAndroid, targetIOS) #The user selected "All" else: builder.build(toTarget, targetAndroid, targetIOS) elif firstCommand == "ship": if "all" in commandList: shipper.shipAll(targetAndroid, targetIOS) else: if toTarget is None: toTarget = Game.pick(True, "All") if toTarget is None: shipper.shipAll(targetAndroid, targetIOS) #The user selected "All" else: shipper.ship(toTarget, targetAndroid, targetIOS) elif firstCommand == "test": if "all" in commandList: shipper.updateAllIOSTesters() else: if toTarget is None: toTarget = Game.pick(True, "All") if toTarget is None: shipper.updateAllIOSTesters() #The user selected "All" else: shipper.updateIOSTesters(toTarget) elif firstCommand == "check": if "all" in commandList: shipper.checkAllIOS() else: if toTarget is None: toTarget = Game.pick(True, "All") if toTarget is None: shipper.checkAllIOS(targetAndroid, targetIOS) #The user selected "All" else: shipper.checkIOS(toTarget) elif firstCommand == "fill": if "all" in commandList: shipper.fillAllIOSTestInfo() else: if toTarget is None: toTarget = Game.pick(True, "All") if toTarget is None: shipper.fillAllIOSTestInfo() #The user selected "All" else: shipper.fillIOSTestInfo(toTarget) else: if command != "": print("invalid command. Use 'info' to get a list of available commands.")