def execute(self, args): wsDir = args["--wd"] if args["--wd"] else utility.workspaceDir() wsDir = os.path.abspath(wsDir) os.chdir(wsDir) cwd = os.getcwd() config = grapeConfig.grapeConfig() recurseSubmodules = config.getboolean( "workspace", "manageSubmodules") or args["--recurse"] skipSubmodules = args["--noRecurse"] recurseNestedSubprojects = not args["--noRecurse"] or args[ "--recurseSubprojects"] publicBranches = [x.strip() for x in args["--public"].split()] launchers = [] for branch in publicBranches: launchers.append( utility.MultiRepoCommandLauncher( fetchLocal, runInSubmodules=recurseSubmodules, runInSubprojects=recurseNestedSubprojects, branch=branch, listOfRepoBranchArgTuples=None, skipSubmodules=skipSubmodules, outer=wsDir)) if len(launchers): launcher = launchers[0] for l in launchers[1:]: launcher.MergeLaunchSet(l) launcher.collapseLaunchSetBranches() launcher.launchFromWorkspaceDir(handleMRE=fetchLocalHandler) return True
def initializeCommands(self): config = grapeConfig.grapeConfig() currentBranch = git.currentBranch() if not self.branchArg else self.branchArg publicBranches = config.getPublicBranchList() wsDir = dir # don't reinit if self.repos: return if self.launchTuple is not None: self.repos = [os.path.abspath(x[0]) for x in self.launchTuple] self.branches = [x[1] for x in self.launchTuple] self.perRepoArgs = [x[2] for x in self.launchTuple] else: if self.runSubprojects: activeSubprojects = grapeConfig.GrapeConfigParser.getAllActiveNestedSubprojectPrefixes() self.repos = self.repos + [os.path.join(workspaceDir(), sub) for sub in activeSubprojects] self.branches = self.branches + [currentBranch for x in activeSubprojects] if self.runSubmodules: activeSubmodules = git.getActiveSubmodules() self.repos = self.repos + [os.path.join(workspaceDir(), r) for r in activeSubmodules] subPubMap = config.getMapping("workspace", "submodulepublicmappings") submoduleBranch = subPubMap[currentBranch] if currentBranch in publicBranches else currentBranch self.branches = self.branches + [ submoduleBranch for x in activeSubmodules ] if self.runOuter: self.repos.append(self.outer) self.branches.append(currentBranch) if not self.perRepoArgs: if not self.globalArgs: self.perRepoArgs = [[] for x in self.repos] else: self.perRepoArgs = [self.globalArgs for x in self.repos]
def __init__(self, lmbda, nProcesses=-1, runInSubmodules=False, runInSubprojects=True, runInOuter=True, branch="", globalArgs=None,perRepoArgs=[], listOfRepoBranchArgTuples=None, skipSubmodules=False, outer=""): self.lmbda = lmbda config = grapeConfig.grapeConfig() recurseSubmodules = config.getboolean("workspace", "manageSubmodules") if not recurseSubmodules: self.runSubmodules = runInSubmodules else: self.runSubmodules = recurseSubmodules # apply the skipSubmodules override self.runSubmodules = self.runSubmodules and not skipSubmodules self.runSubprojects = runInSubprojects self.runOuter = runInOuter if nProcesses < 0: nProcesses = MultiRepoCommandLauncher.numProcs self.pool = MyPool(nProcesses) self.branchArg = branch self.perRepoArgs = perRepoArgs self.globalArgs = globalArgs self.launchTuple = listOfRepoBranchArgTuples self.repos = [] self.branches = [] if outer: self.outer = outer else: self.outer = workspaceDir()
def readVersion(self, fileName, args): config = grapeConfig.grapeConfig() prefix = args["--prefix"] if args["--suffix"]: suffix = args["--suffix"] else: try: suffixMapping = config.getMapping("versioning", "branchSuffixMappings") suffix = suffixMapping[config.getPublicBranchFor(git.currentBranch())] except KeyError: suffix = "" args["--suffix"] = suffix regex = args["--matchTo"] try: regexMappings = config.getMapping("versioning", "branchVersionRegexMappings") public = config.getPublicBranchFor(git.currentBranch()) regex = regexMappings[public] except ConfigParser.NoOptionError: pass #tweaked from http://stackoverflow.com/questions/2020180/increment-a-version-id-by-one-and-write-to-mk-file regex = regex.replace("<prefix>", prefix) regex = regex.replace("<suffix>", suffix) self.r = re.compile(regex) VERSION_ID = None for l in fileName: m1 = self.r.match(l) if m1: VERSION_ID = map(int, m1.group(3).split(".")) self.matchedLine = l if VERSION_ID is None: print("GRAPE: .") return VERSION_ID
def launchFromWorkspaceDir(self, handleMRE=None, noPause=False): with cd(workspaceDir()): argLists = self.perRepoArgs config = grapeConfig.grapeConfig() self.initializeCommands() retvals = [] if noPause: # for purely local operations, run them all at once. if len(self.repos) > 0: retvals = self.pool.map(runCommandOnRepoBranch, [(repo, branch, self.lmbda, arg) for repo, branch, arg in zip(self.repos, self.branches, self.perRepoArgs)]) else: # run the first entry first so that things like logging in to the project's server happen up front if len(self.repos) > 0: retvals.append(runCommandOnRepoBranch((self.repos[0], self.branches[0], self.lmbda, self.perRepoArgs[0]))) if isinstance(retvals[0], Exception): retvals[0] = runCommandOnRepoBranch((self.repos[0], self.branches[0], self.lmbda, self.perRepoArgs[0])) if len(self.repos) > 1: retvals = retvals + self.pool.map(runCommandOnRepoBranch, [(repo, branch, self.lmbda, arg) for repo, branch, arg in zip(self.repos[1:], self.branches[1:], self.perRepoArgs[1:])]) self.pool.close() MRE = MultiRepoException() for val in zip(retvals, self.repos, self.branches, self.perRepoArgs): if isinstance(val[0], Exception): MRE.addException(val[0], val[1], val[2], val[3]) if MRE.hasException(): if handleMRE: handleMRE(MRE) else: raise MRE return retvals
def execute(self, args): wsDir = args["--wd"] if args["--wd"] else utility.workspaceDir() wsDir = os.path.abspath(wsDir) os.chdir(wsDir) cwd = os.getcwd() config = grapeConfig.grapeConfig() recurseSubmodules = config.getboolean("workspace", "manageSubmodules") or args["--recurse"] skipSubmodules = args["--noRecurse"] recurseNestedSubprojects = not args["--noRecurse"] or args["--recurseSubprojects"] publicBranches = [x.strip() for x in args["--public"].split()] launchers = [] for branch in publicBranches: launchers.append(utility.MultiRepoCommandLauncher(fetchLocal, runInSubmodules=recurseSubmodules, runInSubprojects=recurseNestedSubprojects, branch=branch, listOfRepoBranchArgTuples=None, skipSubmodules=skipSubmodules, outer=wsDir)) if len(launchers): launcher = launchers[0] for l in launchers[1:]: launcher.MergeLaunchSet(l) launcher.collapseLaunchSetBranches() launcher.launchFromWorkspaceDir(handleMRE=fetchLocalHandler) return True
def repoFromWorkspaceRepoPath(self, path, isSubmodule=False, isNested=False, topLevelRepo=None, topLevelProject=None): config = grapeConfig.grapeConfig() if isNested: proj = os.path.split(path)[1] nestedProjectURL = config.get("nested-%s" % proj , "url") url = utility.parseSubprojectRemoteURL(nestedProjectURL) urlTokens = url.split('/') proj = urlTokens[-2] repo_name = urlTokens[-1] # strip off the git extension repo_name = '.'.join(repo_name.split('.')[:-1]) elif isSubmodule: fullpath = os.path.abspath(path) wsdir = utility.workspaceDir() + os.path.sep proj = fullpath.split(wsdir)[1].replace("\\","/") url = git.config("--get submodule.%s.url" % proj).split('/') proj = url[-2] repo_name = url[-1] # strip off the .git extension repo_name = '.'.join(repo_name.split('.')[:-1]) else: if topLevelRepo is None: topLevelRepo = config.get("repo", "name") if topLevelProject is None: topLevelProject = config.get("project", "name") repo_name = topLevelRepo proj = topLevelProject repo = self.project(proj).repo(repo_name) return repo
def gitcmd(cmd, errmsg): _cmd = None try: cnfg = grapeConfig.grapeConfig() _cmd = cnfg.get("git", "executable") except ConfigParser.NoOptionError: pass except ConfigParser.NoSectionError: pass if _cmd: _cmd += " %s" % cmd elif os.name == "nt": _cmd = "\"C:\\Program Files\\Git\\bin\\git.exe\" %s" % cmd else: _cmd = "git %s" % cmd cwd = os.getcwd() process = utility.executeSubProcess(_cmd, cwd, verbose=-1) if process.returncode != 0: raise GrapeGitError("Error: %s " % errmsg, process.returncode, process.output, _cmd, cwd=cwd) return process.output.strip()
def execute(self, args): remotepath = args["<url>"] destpath = args["<path>"] rstr = "--recursive" if args["--recursive"] else "" utility.printMsg("Cloning %s into %s %s" % (remotepath, destpath, "recursively" if args["--recursive"] else "")) git.clone(" %s %s %s" % (rstr, remotepath, destpath)) utility.printMsg("Clone succeeded!") os.chdir(destpath) grapeConfig.read() # ensure you start on a reasonable publish branch menu = grapeMenu.menu() config = grapeConfig.grapeConfig() publicBranches = config.getPublicBranchList() if publicBranches: if "develop" in publicBranches: initialBranch = "develop" elif "master" in publicBranches: initialBranch = "master" else: initialBranch = publicBranches[0] menu.applyMenuChoice("checkout", args=[initialBranch]) if args["--allNested"]: configArgs = ["--uv", "--uvArg=--allNestedSubprojects"] else: configArgs = [] return menu.applyMenuChoice("config", configArgs)
def execute(self, args): remotepath = args["<url>"] destpath = args["<path>"] rstr = "--recursive" if args["--recursive"] else "" utility.printMsg("Cloning %s into %s %s" % (remotepath, destpath, "recursively" if args["--recursive"] else "")) git.clone(" %s %s %s" % (rstr, remotepath, destpath)) utility.printMsg("Clone succeeded!") os.chdir(destpath) grapeConfig.read() # ensure you start on a reasonable publish branch menu = grapeMenu.menu() config = grapeConfig.grapeConfig() publicBranches = config.getPublicBranchList() if publicBranches: if "develop" in publicBranches: initialBranch = "develop" elif "master" in publicBranches: initialBranch = "master" else: initialBranch = publicBranches[0] menu.applyMenuChoice("checkout", args=[initialBranch]) if args["--allNested"]: configArgs = ["--uv","--uvArg=--allNestedSubprojects"] else: configArgs = [] return menu.applyMenuChoice("config", configArgs)
def dumpProgress(self, args, msg=""): print(msg) self._saveProgress(args) args["--continue"] = True self.progress["args"] = args self.progress["config"] = grapeConfig.grapeConfig() with open(self.progressFile, 'w') as f: p = pickle.Pickler(f) p.dump(self.progress)
def dumpProgress(self, args,msg=""): print(msg) self._saveProgress(args) args["--continue"] = True self.progress["args"] = args self.progress["config"] = grapeConfig.grapeConfig() with open(self.progressFile,'w') as f: p = pickle.Pickler(f) p.dump(self.progress)
def applyMenuChoice(self, choice, args=None, option_args=None, globalArgs=None): chosen_option = self.getOption(choice) if chosen_option is None: return False if args is None or len(args) == 0: args = [chosen_option._key] #first argument better be the key if args[0] != chosen_option._key: args = [chosen_option._key] + args # use optdoc to parse arguments to the chosen_option. # utility.argParse also does the magic of filling in defaults from the config files as appropriate. if option_args is None and chosen_option.__doc__: try: config = chosen_option._config if config is None: config = grapeConfig.grapeConfig() else: config = grapeConfig.grapeRepoConfig(config) option_args = utility.parseArgs(chosen_option.__doc__, args[1:], config) except SystemExit as e: if len(args) > 1 and "--help" != args[1] and "-h" != args[1]: print("GRAPE PARSING ERROR: could not parse %s\n" % (args[1:])) raise e if globalArgs is not None: utility.applyGlobalArgs(globalArgs) try: if isinstance(chosen_option, resumable.Resumable): if option_args["--continue"]: return chosen_option._resume(option_args) return chosen_option.execute(option_args) except git.GrapeGitError as e: print traceback.print_exc() print( "GRAPE: Uncaught Error %s in grape-%s when executing '%s' in '%s'\n%s" % (e.code, chosen_option._key, e.gitCommand, e.cwd, e.gitOutput)) exit(e.code) except utility.NoWorkspaceDirException as e: print("GRAPE: grape %s must be run from a grape workspace." % chosen_option.key) print("GRAPE: %s" % e.message) exit(1) finally: if globalArgs is not None: utility.popGlobalArgs()
def execute(self, args): self.parseArgs(args) if args["init"]: self.initializeVersioning(args) if args["tick"]: self.tickVersion(args) if args["read"]: config = grapeConfig.grapeConfig() fileName = config.get("versioning","file") try: with open(fileName) as f: slots = self.readVersion(f, args) self.ver = self.slotsToString(args, slots) except IOError: self.ver = "" return True
def execute(self, args): baseDir = utility.workspaceDir() cwd = os.getcwd() os.chdir(baseDir) currentBranch = git.currentBranch() config = grapeConfig.grapeConfig() publicBranches = config.getPublicBranchList() submodules = git.getActiveSubmodules() retvals = utility.MultiRepoCommandLauncher( push).launchFromWorkspaceDir(handleMRE=handlePushMRE) os.chdir(cwd) utility.printMsg("Pushed current branch to origin") return False not in retvals
def tickVersion(self, args): config = grapeConfig.grapeConfig() fileName = config.get("versioning", "file") with open(fileName) as f: slots = self.readVersion(f, args) self.ver = self.slotsToString(args, slots) if not args["--notick"]: slot = args["--slot"] if not slot: slotMappings = config.getMapping("versioning", "branchSlotMappings") if args["--public"]: publicBranch = args["--public"] else: publicBranch = config.getPublicBranchFor(git.currentBranch()) slot = int(slotMappings[publicBranch]) else: slot = int(slot) if args["--minor"]: slot = 2 if args["--major"]: slot = 1 # extend the version number if slot comes in too large. while len(slots) < slot: slots.append(0) slots[slot - 1] += 1 while slot < len(slots): slots[slot] = 0 slot += 1 # write the new version number to the version file. with open(fileName, 'r+') as f: self.ver = self.writeVersion(f, slots, args) self.stageVersionFile(fileName) if not args["--nocommit"]: git.commit("-m \"GRAPE: ticked version to %s\"" % self.ver) if (not args["--nocommit"]) or args["--tag"]: self.tagVersion(self.ver, args) if args["--tagNested"]: cwd = os.getcwd() wsDir = utility.workspaceDir() for subproject in grapeConfig.GrapeConfigParser.getAllActiveNestedSubprojectPrefixes(): os.chdir(os.path.join(wsDir, subproject)) self.tagVersion(self.ver, args) os.chdir(cwd)
def applyMenuChoice(self, choice, args=None, option_args=None, globalArgs=None): chosen_option = self.getOption(choice) if chosen_option is None: return False if args is None or len(args) == 0: args = [chosen_option._key] #first argument better be the key if args[0] != chosen_option._key: args = [chosen_option._key]+args # use optdoc to parse arguments to the chosen_option. # utility.argParse also does the magic of filling in defaults from the config files as appropriate. if option_args is None and chosen_option.__doc__: try: config = chosen_option._config if config is None: config = grapeConfig.grapeConfig() else: config = grapeConfig.grapeRepoConfig(config) option_args = utility.parseArgs(chosen_option.__doc__, args[1:], config) except SystemExit as e: if len(args) > 1 and "--help" != args[1] and "-h" != args[1]: print("GRAPE PARSING ERROR: could not parse %s\n" % (args[1:])) raise e if globalArgs is not None: utility.applyGlobalArgs(globalArgs) try: if isinstance(chosen_option, resumable.Resumable): if option_args["--continue"]: return chosen_option._resume(option_args) return chosen_option.execute(option_args) except git.GrapeGitError as e: print traceback.print_exc() print ("GRAPE: Uncaught Error %s in grape-%s when executing '%s' in '%s'\n%s" % (e.code, chosen_option._key, e.gitCommand, e.cwd, e.gitOutput)) exit(e.code) except utility.NoWorkspaceDirException as e: print ("GRAPE: grape %s must be run from a grape workspace." % chosen_option.key) print ("GRAPE: %s" % e.message) exit(1) finally: if globalArgs is not None: utility.popGlobalArgs()
def initializeVersioning(self, args): config = grapeConfig.grapeConfig() version = StringIO.StringIO() version.write("VERSION_ID = %s" % args["<version>"]) version.seek(0) version = self.readVersion(version, args) if args["--file"]: fname = args["--file"] with open(fname, 'w+') as f: version = self.writeVersion(f, version, args) self.stageVersionFile(fname) config.set("versioning", "file", fname) configFile = os.path.join(git.baseDir(), ".grapeconfig") grapeConfig.writeConfig(config, configFile) self.stageGrapeconfigFile(configFile) if not args["--nocommit"]: git.commit("%s %s -m \"GRAPE: added initial version info file %s\"" % (fname, configFile, fname)) self.tagVersion(version, args)
def lookupPublicBranch(): config = grapeConfig.grapeConfig() try: currentBranch = git.currentBranch() except git.GrapeGitError: return 'unknown' if currentBranch in config.get('flow', 'publicBranches'): return currentBranch try: branch = config.getPublicBranchFor(currentBranch) except KeyError: branchPrefix = git.branchPrefix(currentBranch) print("WARNING: prefix %s does not have an associated topic branch, nor is a default" "public branch configured. \n" "use --public=<branch> to define, or add %s:<branch> or ?:<branch> to \n" "[flow].publicBranches in your .grapeconfig or .git/.grapeuserconfig. " % (branchPrefix, branchPrefix)) branch = None return branch
def execute(self, args): baseDir = utility.workspaceDir() cwd = os.getcwd() os.chdir(baseDir) currentBranch = git.currentBranch() config = grapeConfig.grapeConfig() publicBranches = config.getPublicBranchList() submodules = git.getActiveSubmodules() retvals = utility.MultiRepoCommandLauncher(push).launchFromWorkspaceDir(handleMRE=handlePushMRE) os.chdir(cwd) utility.printMsg("Pushed current branch to origin") return False not in retvals
def updateSubtree(self, args): clean = utility.isWorkspaceClean() os.chdir(utility.workspaceDir()) if not clean: utility.printMsg("git-subtree requires a clean working tree before attempting a subtree update") return False name = args["--name"] branch = args["--branch"] config = grapeConfig.grapeConfig() subtreePrefix = config.get("subtree-%s" % name, "prefix") subtreeRemote = config.get("subtree-%s" % name, "remote") fullURL = utility.parseSubprojectRemoteURL(subtreeRemote) doSquash = config.get("subtrees", "mergePolicy").strip().lower() == "squash" squashArg = "--squash" if doSquash else "" git.subtree("pull --prefix %s %s %s %s" % (subtreePrefix, fullURL, branch, squashArg)) return True
def lookupPublicBranch(): config = grapeConfig.grapeConfig() try: currentBranch = git.currentBranch() except git.GrapeGitError: return 'unknown' if currentBranch in config.get('flow', 'publicBranches'): return currentBranch try: branch = config.getPublicBranchFor(currentBranch) except KeyError: branchPrefix = git.branchPrefix(currentBranch) print( "WARNING: prefix %s does not have an associated topic branch, nor is a default" "public branch configured. \n" "use --public=<branch> to define, or add %s:<branch> or ?:<branch> to \n" "[flow].publicBranches in your .grapeconfig or .git/.grapeuserconfig. " % (branchPrefix, branchPrefix)) branch = None return branch
def execute(self, args): start = args["--start"] if not start: start = self._public # decide whether to recurse recurse = grapeConfig.grapeConfig().get('workspace', 'manageSubmodules') if args["--recurse"]: recurse = True if args["--noRecurse"]: recurse = False if not args["<descr>"]: args["<descr>"] = utility.userInput( "Enter one word description for branch:") if not args["--user"]: args["--user"] = utility.getUserName() branchName = self._key + "/" + args["--user"] + "/" + args["<descr>"] launcher = utility.MultiRepoCommandLauncher(createBranch, runInSubmodules=recurse, runInSubprojects=recurse, runInOuter=True, branch=start, globalArgs=branchName) launcher.initializeCommands() utility.printMsg("About to create the following branches:") for repo, branch in zip(launcher.repos, launcher.branches): utility.printMsg("\t%s off of %s in %s" % (branchName, branch, repo)) proceed = utility.userInput("Proceed? [y/n]", default="y") if proceed: grapeMenu.menu().applyMenuChoice( 'up', ['up', '--public=%s' % start]) launcher.launchFromWorkspaceDir() else: utility.printMsg("branches not created")
def activateNestedSubproject(subprojectName, userconfig): wsDir = utility.workspaceDir() config = grapeConfig.grapeConfig() prefix = config.get("nested-%s" % subprojectName, "prefix") url = config.get("nested-%s" % subprojectName, "url") fullurl = utility.parseSubprojectRemoteURL(url) section = "nested-%s" % subprojectName userconfig.ensureSection(section) currentlyActive = userconfig.getboolean(section, "active") if not currentlyActive: destDir = os.path.join(wsDir, prefix) if not (os.path.isdir(destDir) and os.listdir(destDir)): git.clone("%s %s" % (fullurl, prefix)) elif '.git' in os.listdir(destDir): pass else: utility.printMsg("WARNING: inactive nested subproject %s has files but is not a git repo" % prefix) return False userconfig.set(section, "active", "True") grapeConfig.writeConfig(userconfig, os.path.join(wsDir, ".git", ".grapeuserconfig")) return True
def execute(self, args): # this is necessary due to the unholy relationships between mr, m, and md. if not "<<cmd>>" in args: args["<<cmd>>"] = 'm' otherBranch = args["<branch>"] if args["<branch>"] else utility.userInput("Enter name of branch you would like" " to merge into this branch") args["<branch>"] = otherBranch config = grapeConfig.grapeConfig() publicBranches = config.getPublicBranchList() toks = otherBranch.split("origin/") if toks[-1] in publicBranches: public = toks[-1] publicMapping = config.getMapping("workspace", "submodulePublicMappings") subpublic = publicMapping[public] toks[-1] = subpublic subpublic = 'origin/'.join(toks) else: subpublic = otherBranch mdArgs = {} mdArgs["--am"] = args["--am"] mdArgs["--as"] = args["--as"] mdArgs["--at"] = args["--at"] mdArgs["--aT"] = args["--aT"] mdArgs["--ay"] = args["--ay"] mdArgs["--aY"] = args["--aY"] mdArgs["--askAll"] = args["--askAll"] mdArgs["--public"] = args["<branch>"] mdArgs["--subpublic"] = subpublic mdArgs["--recurse"] = not args["--noRecurse"] mdArgs["--noRecurse"] = args["--noRecurse"] mdArgs["--continue"] = args["--continue"] mdArgs["<<cmd>>"] = args["<<cmd>>"] mdArgs["--noUpdate"] = args["--noUpdate"] mdArgs["--squash"] = args["--squash"] return grapeMenu.menu().getOption("md").execute(mdArgs)
def execute(self, args): start = args["--start"] if not start: start = self._public # decide whether to recurse recurse = grapeConfig.grapeConfig().get('workspace', 'manageSubmodules') if args["--recurse"]: recurse = True if args["--noRecurse"]: recurse = False if not args["<descr>"]: args["<descr>"] = utility.userInput("Enter one word description for branch:") if not args["--user"]: args["--user"] = utility.getUserName() branchName = self._key + "/" + args["--user"] + "/" + args["<descr>"] launcher = utility.MultiRepoCommandLauncher(createBranch, runInSubmodules=recurse, runInSubprojects=recurse, runInOuter=True, branch=start, globalArgs=branchName) launcher.initializeCommands() utility.printMsg("About to create the following branches:") for repo, branch in zip(launcher.repos, launcher.branches): utility.printMsg("\t%s off of %s in %s" % (branchName, branch, repo)) proceed = utility.userInput("Proceed? [y/n]", default="y") if proceed: grapeMenu.menu().applyMenuChoice('up', ['up', '--public=%s' % start]) launcher.launchFromWorkspaceDir() else: utility.printMsg("branches not created")
def execute(self, args): # this is necessary due to the unholy relationships between mr, m, and md. if not "<<cmd>>" in args: args["<<cmd>>"] = 'm' otherBranch = args["<branch>"] if args[ "<branch>"] else utility.userInput( "Enter name of branch you would like" " to merge into this branch") args["<branch>"] = otherBranch config = grapeConfig.grapeConfig() publicBranches = config.getPublicBranchList() toks = otherBranch.split("origin/") if toks[-1] in publicBranches: public = toks[-1] publicMapping = config.getMapping("workspace", "submodulePublicMappings") subpublic = publicMapping[public] toks[-1] = subpublic subpublic = 'origin/'.join(toks) else: subpublic = otherBranch mdArgs = {} mdArgs["--am"] = args["--am"] mdArgs["--as"] = args["--as"] mdArgs["--at"] = args["--at"] mdArgs["--aT"] = args["--aT"] mdArgs["--ay"] = args["--ay"] mdArgs["--aY"] = args["--aY"] mdArgs["--askAll"] = args["--askAll"] mdArgs["--public"] = args["<branch>"] mdArgs["--subpublic"] = subpublic mdArgs["--recurse"] = not args["--noRecurse"] mdArgs["--noRecurse"] = args["--noRecurse"] mdArgs["--continue"] = args["--continue"] mdArgs["<<cmd>>"] = args["<<cmd>>"] mdArgs["--noUpdate"] = args["--noUpdate"] mdArgs["--squash"] = args["--squash"] return grapeMenu.menu().getOption("md").execute(mdArgs)
def repoFromWorkspaceRepoPath(self, path, isSubmodule=False, isNested=False, topLevelRepo=None, topLevelProject=None): config = grapeConfig.grapeConfig() if isNested: proj = os.path.split(path)[1] nestedProjectURL = config.get("nested-%s" % proj, "url") url = utility.parseSubprojectRemoteURL(nestedProjectURL) urlTokens = url.split('/') proj = urlTokens[-2] repo_name = urlTokens[-1] # strip off the git extension repo_name = '.'.join(repo_name.split('.')[:-1]) elif isSubmodule: fullpath = os.path.abspath(path) wsdir = utility.workspaceDir() + os.path.sep proj = fullpath.split(wsdir)[1].replace("\\", "/") url = git.config("--get submodule.%s.url" % proj).split('/') proj = url[-2] repo_name = url[-1] # strip off the .git extension repo_name = '.'.join(repo_name.split('.')[:-1]) else: if topLevelRepo is None: topLevelRepo = config.get("repo", "name") if topLevelProject is None: topLevelProject = config.get("project", "name") repo_name = topLevelRepo proj = topLevelProject repo = self.project(proj).repo(repo_name) return repo
def activateNestedSubproject(subprojectName, userconfig): wsDir = utility.workspaceDir() config = grapeConfig.grapeConfig() prefix = config.get("nested-%s" % subprojectName, "prefix") url = config.get("nested-%s" % subprojectName, "url") fullurl = utility.parseSubprojectRemoteURL(url) section = "nested-%s" % subprojectName userconfig.ensureSection(section) currentlyActive = userconfig.getboolean(section, "active") if not currentlyActive: destDir = os.path.join(wsDir, prefix) if not (os.path.isdir(destDir) and os.listdir(destDir)): git.clone("%s %s" % (fullurl, prefix)) elif '.git' in os.listdir(destDir): pass else: utility.printMsg( "WARNING: inactive nested subproject %s has files but is not a git repo" % prefix) return False userconfig.set(section, "active", "True") grapeConfig.writeConfig( userconfig, os.path.join(wsDir, ".git", ".grapeuserconfig")) return True
def execute(self, args): if TkinterImportError: utility.printMsg( "grape w requires Tkinter.\n The following error was raised during the import:\n\n%s\n" % TkinterImportError) return True config = grapeConfig.grapeConfig() difftool = args["--difftool"] height = args["--height"] width = args["--width"] doMergeDiff = True if args["--rawDiff"]: doMergeDiff = False elif args["--mergeDiff"]: # This is already the default doMergeDiff = True cwd = os.getcwd() os.chdir(utility.workspaceDir()) b1 = args["<b1>"] if not b1: b1 = git.currentBranch() b2 = args["<b2>"] if args["--staged"]: b2 = b1 b1 = "--cached" doMergeDiff = False elif args["--workspace"]: b2 = "--" doMergeDiff = False else: if not b2: try: # put the public branch first so merge diff shows # changes on the current branch. b2 = b1 b1 = config.getPublicBranchFor(b2) except: b2 = "" doMergeDiff = False diffargs = "" root = Tk.Tk() root.title("GRAPE walkthrough") diffmanager = DiffManager( master=root, height=height, width=width, branchA=b1, branchB=b2, difftool=difftool, diffargs=diffargs, doMergeDiff=doMergeDiff, showUnchanged=args["--showUnchanged"], showInactive=not args["--noInactive"], showToplevel=not args["--noTopLevel"], showSubmodules=not args["--noSubmodules"], showSubtrees=not args["--noSubtrees"], showNestedSubprojects=not args["--noNestedSubprojects"], noFetch=args["--noFetch"]) root.mainloop() os.chdir(cwd) try: root.destroy() except: pass return True
def execute(self,args): if TkinterImportError: utility.printMsg("grape w requires Tkinter.\n The following error was raised during the import:\n\n%s\n" % TkinterImportError) return True config = grapeConfig.grapeConfig() difftool = args["--difftool"] height = args["--height"] width = args["--width"] doMergeDiff = True if args["--rawDiff"]: doMergeDiff = False elif args["--mergeDiff"]: # This is already the default doMergeDiff = True cwd = os.getcwd() os.chdir(utility.workspaceDir()) b1 = args["<b1>"] if not b1: b1 = git.currentBranch() b2 = args["<b2>"] if args["--staged"]: b2 = b1 b1 = "--cached" doMergeDiff = False elif args["--workspace"]: b2 = "--" doMergeDiff = False else: if not b2: try: # put the public branch first so merge diff shows # changes on the current branch. b2 = b1 b1 = config.getPublicBranchFor(b2) except: b2 = "" doMergeDiff = False diffargs = "" root = Tk.Tk() root.title("GRAPE walkthrough") diffmanager = DiffManager(master=root, height=height, width=width, branchA=b1, branchB=b2, difftool=difftool, diffargs=diffargs, doMergeDiff=doMergeDiff, showUnchanged=args["--showUnchanged"], showInactive=not args["--noInactive"], showToplevel=not args["--noTopLevel"], showSubmodules=not args["--noSubmodules"], showSubtrees=not args["--noSubtrees"], showNestedSubprojects=not args["--noNestedSubprojects"], noFetch=args["--noFetch"]) root.mainloop() os.chdir(cwd) try: root.destroy() except: pass return True
def execute(self, args): sync = args["--sync"].lower().strip() sync = sync == "true" or sync == "yes" args["--sync"] = sync checkoutargs = '' branch = args["<branch>"] if args['-b']: checkoutargs += " -b" workspaceDir = utility.workspaceDir() os.chdir(workspaceDir) currentSHA = git.shortSHA("HEAD") utility.printMsg("Performing checkout of %s in outer level project." % branch) launcher = utility.MultiRepoCommandLauncher(handledCheckout, listOfRepoBranchArgTuples=[ (workspaceDir, branch, [checkoutargs, sync]) ]) if not launcher.launchFromWorkspaceDir(handleMRE=handleCheckoutMRE)[0]: return False previousSHA = currentSHA submoduleListDidChange = ".gitmodules" in git.diff( "--name-only %s %s" % (previousSHA, branch)) addedModules = [] removedModules = [] uvArgs = [] submodulesDidChange = False if submoduleListDidChange and grapeConfig.grapeConfig().getboolean( "workspace", "manageSubmodules"): self.parseGitModulesDiffOutput( git.diff("%s %s --no-ext-diff -- .gitmodules" % (previousSHA, branch)), addedModules, removedModules) if not addedModules and not removedModules: pass else: submodulesDidChange = True if removedModules: for sub in removedModules: try: os.chdir(os.path.join(workspaceDir, sub)) if git.isWorkingDirectoryClean(): cleanBehaviorSet = args[ "--noUpdateView"] or args["--updateView"] if not cleanBehaviorSet: clean = utility.userInput( "Would you like to remove the submodule %s ?" % sub, 'n') elif args["--noUpdateView"]: clean = False elif args["--updateView"]: clean = True if clean: utility.printMsg( "Removing clean submodule %s." % sub) os.chdir(workspaceDir) shutil.rmtree( os.path.join(workspaceDir, sub)) else: utility.printMsg( "Unstaged / committed changes in %s, not removing." % sub) os.chdir(workspaceDir) except OSError: pass # check to see if nested project list changed addedProjects = [] removedProjects = [] removedProjectPrefices = {} nestedProjectListDidChange = False os.chdir(workspaceDir) if ".grapeconfig" in git.diff("--name-only %s %s" % (previousSHA, branch)): configDiff = git.diff("--no-ext-diff %s %s -- %s" % (previousSHA, branch, ".grapeconfig")) nestedProjectListDidChange = "[nestedprojects]" in configDiff.lower( ) self.parseGrapeConfigNestedProjectDiffOutput( configDiff, addedProjects, removedProjects, removedProjectPrefices) if removedProjects: config = grapeConfig.grapeConfig() for proj in removedProjects: projPrefix = removedProjectPrefices[proj] try: os.chdir(os.path.join(workspaceDir, proj)) except OSError as e: if e.errno == 2: # directory doesn't exist, that's OK since we're thinking about removing it # anyways at this point... continue if git.isWorkingDirectoryClean(): removeBehaviorSet = args["--noUpdateView"] or args[ "--updateView"] if not removeBehaviorSet: remove = utility.userInput( "Would you like to remove the nested subproject %s? \n" "All work that has not been pushed will be lost. " % projPrefix, 'n') elif args["--noUpdateView"]: remove = False elif args["--updateView"]: remove = True if remove: remove = utility.userInput( "Are you sure you want to remove %s? When you switch back to the previous branch, you will have to\n" "reclone %s." % (projPrefix, projPrefix), 'n') if remove: os.chdir(workspaceDir) shutil.rmtree( os.path.join(workspaceDir, projPrefix)) else: utility.printMsg( "Unstaged / committed changes in %s, not removing. \n" "Note this project is NOT active in %s. " % (projPrefix, branch)) os.chdir(workspaceDir) if not submodulesDidChange and not nestedProjectListDidChange: uvArgs.append("--checkSubprojects") else: updateViewSet = args["--noUpdateView"] or args["--updateView"] if not updateViewSet: updateView = utility.userInput( "Submodules or subprojects were added/removed as a result of this checkout. \n" + "%s" % ("Added Projects: %s\n" % ','.join(addedProjects) if addedProjects else "") + "%s" % ("Added Submodules: %s\n" % ','.join(addedModules) if addedModules else "") + "%s" % ("Removed Projects: %s\n" % ','.join(removedProjects) if removedProjects else "") + "%s" % ("Removed Submodules: %s\n" % ','.join(removedModules) if removedModules else "") + "Would you like to update your workspace view? [y/n]", 'n') elif args["--noUpdateView"]: updateView = False elif args["--updateView"]: updateView = True if not updateView: uvArgs.append("--checkSubprojects") if args["-b"]: uvArgs.append("-b") if sync: uvArgs.append("--sync=True") else: uvArgs.append("--sync=False") # in case the user switches to a branch without corresponding branches in the submodules, make sure active submodules # are at the right commit before possibly creating new branches at the current HEAD. git.submodule("update") utility.printMsg( "Calling grape uv %s to ensure branches are consistent across all active subprojects and submodules." % ' '.join(uvArgs)) grapeConfig.read() grapeMenu.menu().applyMenuChoice('uv', uvArgs) os.chdir(workspaceDir) if sync: utility.printMsg( "Switched to %s. Updating from remote...\n\t (use --sync=False or .grapeconfig.post-checkout.syncWithOrigin to change behavior.)" % branch) if args["-b"]: grapeMenu.menu().applyMenuChoice("push") else: grapeMenu.menu().applyMenuChoice("pull") else: utility.printMsg("Switched to %s." % branch) global _skipBranchCreation global _createNewBranch _skipBranchCreation = False _createNewBranch = False return True
def parseArgs(self, args): config = grapeConfig.grapeConfig() # parse tagSuffix for version mappings if args["--tagSuffix"] is None: branch2suffix = config.getMapping("versioning", "branchtagsuffixmappings") args["--tagSuffix"] = branch2suffix[git.currentBranch()]
def execute(self,args): base = git.baseDir() if base == "": return False dotGit = git.gitDir() utility.printMsg("Optimizing git performance on slow file systems...") #runs file system intensive tasks such as git status and git commit # in parallel (important for NFS systems such as LC) git.config("core.preloadindex","true") #have git automatically do some garbage collection / optimization utility.printMsg("Setting up automatic git garbage collection...") git.config("gc.auto","1") #prevents false conflict detection due to differences in filesystem # time stamps utility.printMsg("Optimizing cross platform portability...") git.config("core.trustctime","false") # stores login info for 12 hrs (max allowed by RZBitbucket) if not args["--nocredcache"]: cache = args["--credcache"] if not cache: cache = utility.userInput("Would you like to enable git-managed credential caching?", 'y') if cache: utility.printMsg("Enabling 12 hr caching of https credentials...") if os.name == "nt": git.config("--global credential.helper", "wincred") else : git.config("--global credential.helper", "cache --timeout=43200") # enables 'as' option for merge strategies -forces a conflict if two branches # modify the same file mergeVerifyPath = os.path.join(os.path.dirname(__file__),"..","merge-and-verify-driver") if os.path.exists(mergeVerifyPath): utility.printMsg("Enabling safe merges (triggers conflicts any time same file is modified),\n\t see 'as' option for grape m and grape md...") git.config("merge.verify.name","merge and verify driver") git.config("merge.verify.driver","%s/merge-and-verify-driver %A %O %B") else: utility.printMsg("WARNING: merge and verify script not detected, safe merges ('as' option to grape m / md) will not work!") # enables lg as an alias to print a pretty-font summary of # key junctions in the history for this branch. utility.printMsg("Setting lg as an alias for a pretty log call...") git.config("alias.lg","log --graph --pretty=format:'%Cred%h%Creset -%C(yellow)%d%Creset %s %Cgreen(%cr) %C(bold blue)<%an>%Creset' --abbrev-commit --date=relative --simplify-by-decoration") # perform an update of the active subprojects if asked. ask = not args["--nouv"] updateView = ask and (args["--uv"] or utility.userInput("Do you want to edit your active subprojects?" " (you can do this later using grape uv) [y/n]", "n")) if updateView: grapeMenu.menu().applyMenuChoice("uv", args["--uvArg"]) # configure git to use p4merge for conflict resolution # and diffing useP4Merge = not args["--nop4merge"] and (args["--p4merge"] or utility.userInput("Would you like to use p4merge as your merge tool? [y/n]","y")) # note that this relies on p4merge being in your path somewhere if (useP4Merge): git.config("merge.keepBackup","false") git.config("merge.tool","p4merge") git.config("mergetool.keepBackup","false") git.config("mergetool.p4merge.cmd",'p4merge \"\$BASE\" \"\$LOCAL\" \"\$REMOTE\" \"\$MERGED\"') git.config("mergetool.p4merge.keepTemporaries","false") git.config("mergetool.p4merge.trustExitCode","false") git.config("mergetool.p4merge.keepBackup","false") utility.printMsg("Configured repo to use p4merge for conflict resolution") else: git.config("merge.tool","tkdiff") useP4Diff = not args["--nop4diff"] and (args["--p4diff"] or utility.userInput("Would you like to use p4merge as your diff tool? [y/n]","y")) # this relies on p4diff being defined as a custom bash script, with the following one-liner: # [ $# -eq 7 ] && p4merge "$2" "$5" if (useP4Diff): p4diffScript = os.path.join(os.path.dirname(__file__),"..","p4diff") if os.path.exists(p4diffScript): git.config("diff.external",p4diffScript) utility.printMsg("Configured repo to use p4merge for diff calls - p4merge must be in your path") else: utility.printMsg("Could not find p4diff script at %s" % p4diffScript) useGitP4 = args["--git-p4"] if (useGitP4 ): git.config("git-p4.useclientspec","true") # create p4 references to enable imports from p4 p4remotes = os.path.join(dotGit,"refs","remotes","p4","") utility.ensure_dir(p4remotes) commit = utility.userInput("Please enter a descriptor (e.g. SHA, branch if tip, tag name) of the current git commit that mirrors the p4 repo","master") sha = git.SHA(commit) with open(os.path.join(p4remotes,"HEAD"),'w') as f: f.write(sha) with open(os.path.join(p4remotes,"master"),'w') as f: f.write(sha) # to enable exports to p4, a maindev client needs to be set up haveCopied = False while (not haveCopied): p4settings = utility.userInput("Enter a path to a .p4settings file describing the maindev client you'd like to use for p4 updates",".p4settings") try: shutil.copyfile(p4settings,os.path.join(base,".p4settings")) haveCopied = True except: print("could not find p4settings file, please check your path and try again") return False # install hooks here and in all submodules utility.printMsg("Installing hooks in all repos...") cwd = git.baseDir() grapeMenu.menu().applyMenuChoice("installHooks") # ensure all public branches are available in all repos submodules = git.getActiveSubmodules() config = grapeConfig.grapeConfig() publicBranches = config.getPublicBranchList() submodulePublicBranches = set(config.getMapping('workspace', 'submoduleTopicPrefixMappings').values()) for sub in submodules: self.ensurePublicBranchesExist(grapeConfig.grapeRepoConfig(sub),sub, submodulePublicBranches) # reset config to the workspace grapeconfig, use that one for all nested projects' public branches. wsDir = utility.workspaceDir() config = grapeConfig.grapeRepoConfig(wsDir) for proj in grapeConfig.GrapeConfigParser.getAllActiveNestedSubprojectPrefixes(): self.ensurePublicBranchesExist(config, os.path.join(wsDir,proj), publicBranches) self.ensurePublicBranchesExist(config, wsDir, publicBranches) return True
def postInit(self): # add dynamically generated (dependent on grapeConfig) options here self._options = self._options + newFlowBranch.NewBranchOptionFactory( ).createNewBranchOptions(grapeConfig.grapeConfig()) for currOption in self._options: self._optionLookup[currOption.key] = currOption
def __init__(self, master, **kwargs): height = kwargs.get('height', 0) width = kwargs.get('width', 0) self.master = master self.grapeconfig = grapeConfig.grapeConfig() self.oldprojindex = 0 self.showInactive = kwargs.get('showInactive', True) self.showToplevel = kwargs.get('showToplevel', True) self.showSubmodules = kwargs.get('showSubmodules', True) self.showSubtrees = kwargs.get('showSubtrees', True) self.showNestedSubprojects = kwargs.get('showNestedSubprojects', True) # Colors self.fginit = kwargs.get('fginit', 'black') self.bginit = kwargs.get('bginit', 'gray') self.fgvisited = kwargs.get('fgvisited', 'slate gray') self.bgvisited = kwargs.get('bgvisited', 'light gray') self.fgselected = kwargs.get('fgselected', 'black') self.bgselected = kwargs.get('bgselected', 'goldenrod') self.fgactive = kwargs.get('fgactive', 'black') self.bgactive = kwargs.get('bgactive', 'light goldenrod') # Panel labels # These variables should be set by derived classes self.filepanelabel = Tk.StringVar() self.projpanelabel = Tk.StringVar() # Main resizable window self.main = Tk.PanedWindow(master, height=height, width=width, sashwidth=4) # Create file navigation pane widgets self.filepanel = Tk.Frame() self.filelabel = Tk.Label(self.filepanel, textvariable=self.filepanelabel) self.filescroll = Tk.Scrollbar(self.filepanel, width=10) self.filelist = Tk.Listbox(self.filepanel, background=self.bginit, foreground=self.fginit, selectbackground=self.bgselected, selectforeground=self.fgselected, yscrollcommand=self.filescroll.set, selectmode=Tk.SINGLE) self.filescroll.config(command=self.filelist.yview) self.filelist.bind("<Double-Button-1>", lambda e: self.spawnDiff()) # Place file navigation pane widgets self.filelabel.pack(side=Tk.TOP, fill=Tk.X) self.filescroll.pack(side=Tk.RIGHT, fill=Tk.Y) self.filelist.pack(side=Tk.LEFT, fill=Tk.BOTH, expand=1) self.filepanel.pack(fill=Tk.BOTH, expand=1) # Create subproject navigation widgets self.projpanel = Tk.Frame() self.projlabel = Tk.Label(self.projpanel, textvariable=self.projpanelabel) self.projscroll = Tk.Scrollbar(self.projpanel, width=10) self.projlist = Tk.Listbox(self.projpanel, background=self.bginit, foreground=self.fginit, selectbackground=self.bgselected, selectforeground=self.fgselected, yscrollcommand=self.projscroll.set, selectmode=Tk.SINGLE) self.projscroll.config(command=self.projlist.yview) self.projlist.bind("<Double-Button-1>", lambda e: self.chooseProject()) # Place subproject navigation widgets self.projscroll.pack(side=Tk.LEFT, fill=Tk.Y) self.projlabel.pack(side=Tk.TOP, fill=Tk.X) self.projlist.pack(side=Tk.LEFT, fill=Tk.BOTH, expand=1) self.projpanel.pack(fill=Tk.BOTH, expand=1) # Populate subproject navigation list utility.printMsg("Populating projects list...") self.projects = [] self.projstatus = [] self.projtype = [] # Outer level repo if self.showToplevel: status = "?" self.projects.append("") self.projlist.insert(Tk.END, "%s <Outer Level Project>" % status) self.projstatus.append(status) self.projtype.append("Outer") # Nested subprojects self.subprojects = [] if self.showNestedSubprojects: activeNestedSubprojects = (grapeConfig.GrapeConfigParser. getAllActiveNestedSubprojectPrefixes()) self.projects.extend(activeNestedSubprojects) self.subprojects.extend(activeNestedSubprojects) for proj in activeNestedSubprojects: status = "?" self.projlist.insert( Tk.END, "%s %s <Nested Subproject>" % (status, proj)) self.projstatus.append(status) self.projtype.append("Active Nested") if self.showInactive: inactiveNestedSubprojects = list( set(grapeConfig.grapeConfig().getAllNestedSubprojects()) - set(grapeConfig.GrapeConfigParser. getAllActiveNestedSubprojects())) self.projects.extend(inactiveNestedSubprojects) self.subprojects.extend(inactiveNestedSubprojects) for proj in inactiveNestedSubprojects: status = "?" self.projlist.insert( Tk.END, "%s %s <Inactive Nested Subproject>" % (status, proj)) self.projstatus.append(status) self.projtype.append("Inactive Nested") # Submodules self.submodules = [] if self.showSubmodules: activeSubmodules = (git.getActiveSubmodules()) self.projects.extend(activeSubmodules) self.submodules.extend(activeSubmodules) for proj in activeSubmodules: status = "?" self.projlist.insert(Tk.END, "%s %s <Submodule>" % (status, proj)) self.projstatus.append(status) self.projtype.append("Submodule") if self.showInactive: inactiveSubmodules = list( set(git.getAllSubmodules()) - set(git.getActiveSubmodules())) self.projects.extend(inactiveSubmodules) self.submodules.extend(inactiveSubmodules) for proj in inactiveSubmodules: status = "?" self.projlist.insert( Tk.END, "%s %s <Inactive Submodule>" % (status, proj)) self.projstatus.append(status) self.projtype.append("Inactive Submodule") # Subtrees self.subtrees = [] if self.showSubtrees: self.subtrees = [ self.grapeconfig.get('subtree-%s' % proj, 'prefix') for proj in self.grapeconfig.get('subtrees', 'names').strip().split() ] self.projects.extend(self.subtrees) for proj in self.subtrees: status = "?" self.projlist.insert(Tk.END, "%s %s <Subtree>" % (status, proj)) self.projstatus.append(status) self.projtype.append("Subtree") utility.printMsg("Done.") # Resize the project pane based on its contents self.projlistwidth = 0 self.numprojects = 0 for proj in self.projlist.get(0, Tk.END): if len(proj) > self.projlistwidth: self.projlistwidth = len(proj) self.numprojects += 1 self.projlist.config(width=self.projlistwidth) # Place the panes in the main window self.main.add(self.projpanel) self.main.add(self.filepanel) self.main.pack(fill=Tk.BOTH, expand=1, side=Tk.BOTTOM)
def defineActiveSubmodules(projectType="submodule"): """ Queries the user for the submodules (projectType == "submodule") or nested subprojects (projectType == "nested subproject") they would like to activate. """ if projectType == "submodule": allSubprojects = git.getAllSubmodules() activeSubprojects = git.getActiveSubmodules() if projectType == "nested subproject": config = grapeConfig.grapeConfig() allSubprojectNames = config.getAllNestedSubprojects() allSubprojects = [] for project in allSubprojectNames: allSubprojects.append( config.get("nested-%s" % project, "prefix")) activeSubprojects = grapeConfig.GrapeConfigParser.getAllActiveNestedSubprojectPrefixes( ) toplevelDirs = {} toplevelActiveDirs = {} toplevelSubs = [] for sub in allSubprojects: # we are taking advantage of the fact that branchPrefixes are the same as directory prefixes for local # top-level dirs. prefix = git.branchPrefix(sub) if sub != prefix: toplevelDirs[prefix] = [] toplevelActiveDirs[prefix] = [] for sub in allSubprojects: prefix = git.branchPrefix(sub) if sub != prefix: toplevelDirs[prefix].append(sub) else: toplevelSubs.append(sub) for sub in activeSubprojects: prefix = git.branchPrefix(sub) if sub != prefix: toplevelActiveDirs[prefix].append(sub) included = {} for directory, subprojects in toplevelDirs.items(): activeDir = toplevelActiveDirs[directory] if len(activeDir) == 0: defaultValue = "none" elif set(activeDir) == set(subprojects): defaultValue = "all" else: defaultValue = "some" opt = utility.userInput( "Would you like all, some, or none of the %ss in %s?" % (projectType, directory), default=defaultValue) if opt.lower()[0] == "a": for subproject in subprojects: included[subproject] = True if opt.lower()[0] == "n": for subproject in subprojects: included[subproject] = False if opt.lower()[0] == "s": for subproject in subprojects: included[subproject] = utility.userInput( "Would you like %s %s? [y/n]" % (projectType, subproject), 'y' if (subproject in activeSubprojects) else 'n') for subproject in toplevelSubs: included[subproject] = utility.userInput( "Would you like %s %s? [y/n]" % (projectType, subproject), 'y' if (subproject in activeSubprojects) else 'n') return included
def execute(self, args): sync = args["--sync"].lower().strip() sync = sync == "true" or sync == "yes" args["--sync"] = sync config = grapeConfig.grapeConfig() origwd = os.getcwd() wsDir = utility.workspaceDir() os.chdir(wsDir) base = git.baseDir() if base == "": return False hasSubmodules = len( git.getAllSubmodules()) > 0 and not args["--skipSubmodules"] includedSubmodules = {} includedNestedSubprojectPrefixes = {} allSubmodules = git.getAllSubmodules() allNestedSubprojects = config.getAllNestedSubprojects() addedSubmodules = [] addedNestedSubprojects = [] addedProjects = args["--add"] notFound = [] for proj in addedProjects: if proj in allSubmodules: addedSubmodules.append(proj) elif proj in allNestedSubprojects: addedNestedSubprojects.append(proj) else: notFound.append(proj) rmSubmodules = [] rmNestedSubprojects = [] rmProjects = args["--rm"] for proj in rmProjects: if proj in allSubmodules: rmSubmodules.append(proj) elif proj in allNestedSubprojects: rmNestedSubprojects.append(proj) else: notFound.append(proj) if notFound: utility.printMsg( "\"%s\" not found in submodules %s \nor\n nested subprojects %s" % (",".join(notFound), ",".join(allSubmodules), ",".join(allNestedSubprojects))) return False if not args["--checkSubprojects"]: # get submodules to update if hasSubmodules: if args["--allSubmodules"]: includedSubmodules = {sub: True for sub in allSubmodules} elif args["--add"] or args["--rm"]: includedSubmodules = { sub: True for sub in git.getActiveSubmodules() } includedSubmodules.update( {sub: True for sub in addedSubmodules}) includedSubmodules.update( {sub: False for sub in rmSubmodules}) else: includedSubmodules = self.defineActiveSubmodules() # get subprojects to update if not args["--skipNestedSubprojects"]: nestedPrefixLookup = lambda x: config.get( "nested-%s" % x, "prefix") if args["--allNestedSubprojects"]: includedNestedSubprojectPrefixes = { nestedPrefixLookup(sub): True for sub in allNestedSubprojects } elif args["--add"] or args["--rm"]: includedNestedSubprojectPrefixes = { sub: True for sub in grapeConfig.GrapeConfigParser. getAllActiveNestedSubprojectPrefixes() } includedNestedSubprojectPrefixes.update({ nestedPrefixLookup(sub): True for sub in addedNestedSubprojects }) includedNestedSubprojectPrefixes.update({ nestedPrefixLookup(sub): False for sub in rmNestedSubprojects }) else: includedNestedSubprojectPrefixes = self.defineActiveNestedSubprojects( ) if hasSubmodules: initStr = "" deinitStr = "" rmCachedStr = "" resetStr = "" for submodule, nowActive in includedSubmodules.items(): if nowActive: initStr += ' %s' % submodule else: deinitStr += ' %s' % submodule rmCachedStr += ' %s' % submodule resetStr += ' %s' % submodule if args["-f"] and deinitStr: deinitStr = "-f" + deinitStr utility.printMsg("Configuring submodules...") utility.printMsg("Initializing submodules...") git.submodule("init %s" % initStr.strip()) if deinitStr: utility.printMsg( "Deiniting submodules that were not requested... (%s)" % deinitStr) done = False while not done: try: git.submodule("deinit %s" % deinitStr.strip()) done = True except git.GrapeGitError as e: if "the following file has local modifications" in e.gitOutput: print e.gitOutput utility.printMsg( "A submodule that you wanted to remove has local modifications. " "Use grape uv -f to force removal.") return False elif "use 'rm -rf' if you really want to remove it including all of its history" in e.gitOutput: if not args["-f"]: raise e # it is safe to move the .git of the submodule to the .git/modules area of the workspace... module = None for l in e.gitOutput.split('\n'): if "Submodule work tree" in l and "contains a .git directory" in l: module = l.split("'")[1] break if module: src = os.path.join(module, ".git") dest = os.path.join( wsDir, ".git", "modules", module) utility.printMsg("Moving %s to %s" % (src, dest)) shutil.move(src, dest) else: raise e else: raise e git.rm("--cached %s" % rmCachedStr) git.reset(" %s" % resetStr) if initStr: utility.printMsg("Updating active submodules...(%s)" % initStr) git.submodule("update") # handle nested subprojects if not args["--skipNestedSubprojects"]: reverseLookupByPrefix = { nestedPrefixLookup(sub): sub for sub in allNestedSubprojects } userConfig = grapeConfig.grapeUserConfig() updatedActiveList = [] for subproject, nowActive in includedNestedSubprojectPrefixes.items( ): subprojectName = reverseLookupByPrefix[subproject] section = "nested-%s" % reverseLookupByPrefix[subproject] userConfig.ensureSection(section) previouslyActive = userConfig.getboolean(section, "active") previouslyActive = previouslyActive and os.path.exists( os.path.join(base, subproject, ".git")) userConfig.set(section, "active", "True" if previouslyActive else "False") if nowActive and previouslyActive: updatedActiveList.append(subprojectName) if nowActive and not previouslyActive: utility.printMsg("Activating Nested Subproject %s" % subproject) if not addSubproject.AddSubproject.activateNestedSubproject( subprojectName, userConfig): utility.printMsg("Can't activate %s. Exiting..." % subprojectName) return False updatedActiveList.append(subprojectName) if not nowActive and not previouslyActive: pass if not nowActive and previouslyActive: #remove the subproject subprojectdir = os.path.join( base, utility.makePathPortable(subproject)) proceed = args["-f"] or \ utility.userInput("About to delete all contents in %s. Any uncommitted changes, committed changes " "that have not been pushed, or ignored files will be lost. Proceed?" % subproject, 'n') if proceed: shutil.rmtree(subprojectdir) userConfig.setActiveNestedSubprojects(updatedActiveList) grapeConfig.writeConfig( userConfig, os.path.join(utility.workspaceDir(), ".git", ".grapeuserconfig")) checkoutArgs = "-b" if args["-b"] else "" safeSwitchWorkspaceToBranch(git.currentBranch(), checkoutArgs, sync) os.chdir(origwd) return True
def execute(self, args): name = args["--name"] prefix = args["--prefix"] url = args["--url"] fullurl = utility.parseSubprojectRemoteURL(url) branch = args["--branch"] config = grapeConfig.grapeConfig() projectType = self.parseSubprojectType(config, args) proceed = args["--noverify"] if projectType == "subtree": # whether or not to squash squash = args["--squash"] or config.get( "subtrees", "mergePolicy").strip().lower() == "squash" squash = squash and not args["--nosquash"] squash_arg = "--squash" if squash else "" # expand the URL if not proceed: proceed = utility.userInput( "About to create a subtree called %s at path %s,\n" "cloned from %s at %s " % (name, prefix, fullurl, branch) + ("using a squash merge." if squash else "") + "\nProceed? [y/n]", "y") if proceed: os.chdir(utility.workspaceDir()) git.subtree("add %s --prefix=%s %s %s" % (squash_arg, prefix, fullurl, branch)) #update the configuration file current_cfg_names = config.get("subtrees", "names").split() if not current_cfg_names or current_cfg_names[0].lower( ) == "none": config.set("subtrees", "names", name) else: current_cfg_names.append(name) config.set("subtrees", "names", ' '.join(current_cfg_names)) section = "subtree-%s" % name config.add_section(section) config.set(section, "prefix", prefix) config.set(section, "remote", url) config.set(section, "topicPrefixMappings", "?:%s" % branch) with open(os.path.join(utility.workspaceDir(), ".grapeconfig"), "w") as f: config.write(f) utility.printMsg( "Successfully added subtree branch. \n" "Updated .grapeconfig file. Review changes and then commit. " ) elif projectType == "submodule": if not proceed: proceed = utility.userInput( "about to add %s as a submodule at path %s,\n" "cloned from %s at branch %s.\nproceed? [y/n]" % (name, prefix, url, branch), "y") if proceed: git.submodule("add --name %s --branch %s %s %s" % (name, branch, url, prefix)) print( "Successfully added submodule %s at %s. Please review changes and commit." % (name, prefix)) elif projectType == "nested": if not proceed: proceed = utility.userInput( " about to clone %s as a nested git repo at path %s,\n" "cloned from %s at branch %s.\nProceed? [y/n]" % (name, prefix, url, branch), 'y') if proceed: git.clone("%s %s" % (fullurl, prefix)) ignorePath = os.path.join(git.baseDir(), ".gitignore") with open(ignorePath, 'a') as ignore: ignore.writelines([prefix + '\n']) git.add(ignorePath) wsConfig = grapeConfig.workspaceConfig() currentSubprojects = wsConfig.getList("nestedProjects", "names") currentSubprojects.append(name) wsConfig.set("nestedProjects", "names", ' '.join(currentSubprojects)) newSection = "nested-%s" % name wsConfig.ensureSection(newSection) wsConfig.set(newSection, "prefix", prefix) wsConfig.set(newSection, "url", url) configFileName = os.path.join(utility.workspaceDir(), ".grapeconfig") with open(os.path.join(configFileName), 'w') as f: wsConfig.write(f) git.add(configFileName) git.commit("%s %s -m \"GRAPE: Added nested subproject %s\"" % (ignorePath, configFileName, prefix)) # update the runtime config with the new workspace .grapeconfig's settings. grapeConfig.read() userConfig = grapeConfig.grapeUserConfig() userConfig.ensureSection(newSection) userConfig.set(newSection, "active", "True") grapeConfig.writeConfig( userConfig, os.path.join(utility.workspaceDir(), ".git", ".grapeuserconfig")) return True
def execute(self, args): name = args["--name"] prefix = args["--prefix"] url = args["--url"] fullurl = utility.parseSubprojectRemoteURL(url) branch = args["--branch"] config = grapeConfig.grapeConfig() projectType = self.parseSubprojectType(config, args) proceed = args["--noverify"] if projectType == "subtree": # whether or not to squash squash = args["--squash"] or config.get("subtrees", "mergePolicy").strip().lower() == "squash" squash = squash and not args["--nosquash"] squash_arg = "--squash" if squash else "" # expand the URL if not proceed: proceed = utility.userInput("About to create a subtree called %s at path %s,\n" "cloned from %s at %s " % (name, prefix, fullurl, branch) + ("using a squash merge." if squash else "") + "\nProceed? [y/n]", "y") if proceed: os.chdir(utility.workspaceDir()) git.subtree("add %s --prefix=%s %s %s" % (squash_arg, prefix, fullurl, branch)) #update the configuration file current_cfg_names = config.get("subtrees", "names").split() if not current_cfg_names or current_cfg_names[0].lower() == "none": config.set("subtrees", "names", name) else: current_cfg_names.append(name) config.set("subtrees", "names", ' '.join(current_cfg_names)) section = "subtree-%s" % name config.add_section(section) config.set(section, "prefix", prefix) config.set(section, "remote", url) config.set(section, "topicPrefixMappings", "?:%s" % branch) with open(os.path.join(utility.workspaceDir(), ".grapeconfig"), "w") as f: config.write(f) utility.printMsg("Successfully added subtree branch. \n" "Updated .grapeconfig file. Review changes and then commit. ") elif projectType == "submodule": if not proceed: proceed = utility.userInput("about to add %s as a submodule at path %s,\n" "cloned from %s at branch %s.\nproceed? [y/n]" % (name, prefix, url, branch), "y") if proceed: git.submodule("add --name %s --branch %s %s %s" % (name, branch, url, prefix)) print("Successfully added submodule %s at %s. Please review changes and commit." % (name, prefix)) elif projectType == "nested": if not proceed: proceed = utility.userInput(" about to clone %s as a nested git repo at path %s,\n" "cloned from %s at branch %s.\nProceed? [y/n]" % (name, prefix, url, branch), 'y') if proceed: git.clone("%s %s" % (fullurl, prefix)) ignorePath = os.path.join(git.baseDir(), ".gitignore") with open(ignorePath, 'a') as ignore: ignore.writelines([prefix+'\n']) git.add(ignorePath) wsConfig = grapeConfig.workspaceConfig() currentSubprojects = wsConfig.getList("nestedProjects", "names") currentSubprojects.append(name) wsConfig.set("nestedProjects", "names", ' '.join(currentSubprojects)) newSection = "nested-%s" % name wsConfig.ensureSection(newSection) wsConfig.set(newSection, "prefix", prefix) wsConfig.set(newSection, "url", url) configFileName = os.path.join(utility.workspaceDir(), ".grapeconfig") with open(os.path.join(configFileName), 'w') as f: wsConfig.write(f) git.add(configFileName) git.commit("%s %s -m \"GRAPE: Added nested subproject %s\"" % (ignorePath, configFileName, prefix)) # update the runtime config with the new workspace .grapeconfig's settings. grapeConfig.read() userConfig = grapeConfig.grapeUserConfig() userConfig.ensureSection(newSection) userConfig.set(newSection, "active", "True") grapeConfig.writeConfig(userConfig, os.path.join(utility.workspaceDir(), ".git", ".grapeuserconfig")) return True
def execute(self, args): """ A fair chunk of this stuff relies on stashy's wrapping of the STASH REST API, which is posted at https://developer.atlassian.com/static/rest/stash/2.12.1/stash-rest.html """ config = grapeConfig.grapeConfig() name = args["--user"] if not name: name = utility.getUserName() utility.printMsg("Logging onto %s" % args["--bitbucketURL"]) if args["--test"]: bitbucket = Atlassian.TestAtlassian(name) else: verify = True if args["--verifySSL"].lower() == "true" else False bitbucket = Atlassian.Atlassian(name, url=args["--bitbucketURL"], verify=verify) # default project (outer level project) project_name = args["--project"] # default repo (outer level repo) repo_name = args["--repo"] # determine source branch and target branch branch = args["--source"] if not branch: branch = git.currentBranch() # make sure we are in the outer level repo before we push wsDir = utility.workspaceDir() os.chdir(wsDir) #ensure branch is pushed utility.printMsg("Pushing %s to bitbucket..." % branch) git.push("origin %s" % branch) #target branch for outer level repo target_branch = args["--target"] if not target_branch: target_branch = config.getPublicBranchFor(branch) # load pull request from Bitbucket if it already exists wsRepo = bitbucket.project(project_name).repo(repo_name) existingOuterLevelRequest = getReposPullRequest(wsRepo, branch, target_branch, args) # determine pull request title title = args["--title"] if existingOuterLevelRequest is not None and not title: title = existingOuterLevelRequest.title() #determine pull request URL outerLevelURL = None if existingOuterLevelRequest: outerLevelURL = existingOuterLevelRequest.link() # determine pull request description descr = self.parseDescriptionArgs(args) if not descr and existingOuterLevelRequest: descr = existingOuterLevelRequest.description() # determine pull request reviewers reviewers = self.parseReviewerArgs(args) if reviewers is None and existingOuterLevelRequest is not None: reviewers = [r[0] for r in existingOuterLevelRequest.reviewers()] # if we're in append mode, only append what was asked for: if args["--append"] or args["--prepend"]: title = args["--title"] descr = self.parseDescriptionArgs(args) reviewers = self.parseReviewerArgs(args) ## Submodule Repos missing = utility.getModifiedInactiveSubmodules(target_branch, branch) if missing: utility.printMsg("The following submodules that you've modified are not currently present in your workspace.\n" "You should activate them using grape uv and then call grape review again. If you haven't modified " "these submodules, you may need to do a grape md to proceed.") utility.printMsg(','.join(missing)) return False pullRequestLinks = {} if not args["--norecurse"] and (args["--recurse"] or config.getboolean("workspace", "manageSubmodules")): modifiedSubmodules = git.getModifiedSubmodules(target_branch, branch) submoduleBranchMappings = config.getMapping("workspace", "submoduleTopicPrefixMappings") for submodule in modifiedSubmodules: if not submodule: continue # push branch os.chdir(submodule) utility.printMsg("Pushing %s to bitbucket..." % branch) git.push("origin %s" % branch) os.chdir(wsDir) repo = bitbucket.repoFromWorkspaceRepoPath(submodule, isSubmodule=True) # determine branch prefix prefix = branch.split('/')[0] sub_target_branch = submoduleBranchMappings[prefix] prevSubDescr = getReposPullRequestDescription(repo, branch, sub_target_branch, args) #amend the subproject pull request description with the link to the outer pull request subDescr = addLinkToDescription(descr, outerLevelURL, True) if args["--prepend"] or args["--append"]: subDescr = descr newRequest = postPullRequest(repo, title, branch, sub_target_branch, subDescr, reviewers, args) if newRequest: pullRequestLinks[newRequest.link()] = True else: # if a pull request could not be generated, just add a link to browse the branch pullRequestLinks["%s%s/browse?at=%s" % (bitbucket.rzbitbucketURL, repo.repo.url(), urllib.quote_plus("refs/heads/%s" % branch))] = False ## NESTED SUBPROJECT REPOS nestedProjects = grapeConfig.GrapeConfigParser.getAllModifiedNestedSubprojects(target_branch) nestedProjectPrefixes = grapeConfig.GrapeConfigParser.getAllModifiedNestedSubprojectPrefixes(target_branch) for proj, prefix in zip(nestedProjects, nestedProjectPrefixes): with utility.cd(prefix): git.push("origin %s" % branch) repo = bitbucket.repoFromWorkspaceRepoPath(proj, isSubmodule=False, isNested=True) newRequest = postPullRequest(repo, title, branch, target_branch,descr, reviewers, args) if newRequest: pullRequestLinks[newRequest.link()] = True else: # if a pull request could not be generated, just add a link to browse the branch pullRequestLinks["%s%s/browse?at=%s" % (bitbucket.rzbitbucketURL, repo.repo.url(), urllib.quote_plus("refs/heads/%s" % branch))] = False ## OUTER LEVEL REPO # load the repo level REST resource if not args["--subprojectsOnly"]: if not git.hasBranch(branch): utility.printMsg("Top level repository does not have a branch %s, not generating a Pull Request" % (branch)) return True if git.branchUpToDateWith(target_branch, branch): utility.printMsg("%s up to date with %s, not generating a Pull Request in Top Level repo" % (target_branch, branch)) return True repo_name = args["--repo"] repo = bitbucket.repoFromWorkspaceRepoPath(wsDir, topLevelRepo=repo_name, topLevelProject=project_name) utility.printMsg("Posting pull request to %s,%s" % (project_name, repo_name)) request = postPullRequest(repo, title, branch, target_branch, descr, reviewers, args) updatedDescription = request.description() for link in pullRequestLinks: updatedDescription = addLinkToDescription(updatedDescription, link, pullRequestLinks[link]) if updatedDescription != request.description(): request = postPullRequest(repo, title, branch, target_branch, updatedDescription, reviewers, args) utility.printMsg("Request generated/updated:\n\n%s" % request) return True
def __init__(self, master, **kwargs): height = kwargs.get('height', 0) width = kwargs.get('width', 0) self.master = master self.grapeconfig = grapeConfig.grapeConfig() self.oldprojindex = 0 self.showInactive = kwargs.get('showInactive', True) self.showToplevel = kwargs.get('showToplevel', True) self.showSubmodules = kwargs.get('showSubmodules', True) self.showSubtrees = kwargs.get('showSubtrees', True) self.showNestedSubprojects = kwargs.get('showNestedSubprojects', True) # Colors self.fginit = kwargs.get('fginit', 'black') self.bginit = kwargs.get('bginit', 'gray') self.fgvisited = kwargs.get('fgvisited', 'slate gray') self.bgvisited = kwargs.get('bgvisited', 'light gray') self.fgselected = kwargs.get('fgselected', 'black') self.bgselected = kwargs.get('bgselected', 'goldenrod') self.fgactive = kwargs.get('fgactive', 'black') self.bgactive = kwargs.get('bgactive', 'light goldenrod') # Panel labels # These variables should be set by derived classes self.filepanelabel = Tk.StringVar() self.projpanelabel = Tk.StringVar() # Main resizable window self.main = Tk.PanedWindow(master, height=height, width=width, sashwidth=4) # Create file navigation pane widgets self.filepanel = Tk.Frame() self.filelabel = Tk.Label(self.filepanel, textvariable=self.filepanelabel) self.filescroll = Tk.Scrollbar(self.filepanel, width=10) self.filelist = Tk.Listbox(self.filepanel, background=self.bginit, foreground=self.fginit, selectbackground=self.bgselected, selectforeground=self.fgselected, yscrollcommand=self.filescroll.set, selectmode=Tk.SINGLE) self.filescroll.config(command=self.filelist.yview) self.filelist.bind("<Double-Button-1>", lambda e: self.spawnDiff()) # Place file navigation pane widgets self.filelabel.pack(side=Tk.TOP, fill=Tk.X) self.filescroll.pack(side=Tk.RIGHT, fill=Tk.Y) self.filelist.pack(side=Tk.LEFT, fill=Tk.BOTH, expand=1) self.filepanel.pack(fill=Tk.BOTH, expand=1) # Create subproject navigation widgets self.projpanel = Tk.Frame() self.projlabel = Tk.Label(self.projpanel, textvariable=self.projpanelabel) self.projscroll = Tk.Scrollbar(self.projpanel, width=10) self.projlist = Tk.Listbox(self.projpanel, background=self.bginit, foreground=self.fginit, selectbackground=self.bgselected, selectforeground=self.fgselected, yscrollcommand=self.projscroll.set, selectmode=Tk.SINGLE) self.projscroll.config(command=self.projlist.yview) self.projlist.bind("<Double-Button-1>", lambda e: self.chooseProject()) # Place subproject navigation widgets self.projscroll.pack(side=Tk.LEFT, fill=Tk.Y) self.projlabel.pack(side=Tk.TOP, fill=Tk.X) self.projlist.pack(side=Tk.LEFT, fill=Tk.BOTH, expand=1) self.projpanel.pack(fill=Tk.BOTH, expand=1) # Populate subproject navigation list utility.printMsg("Populating projects list...") self.projects = [] self.projstatus = [] self.projtype = [] # Outer level repo if self.showToplevel: status = "?" self.projects.append("") self.projlist.insert(Tk.END, "%s <Outer Level Project>" % status) self.projstatus.append(status) self.projtype.append("Outer") # Nested subprojects self.subprojects = [] if self.showNestedSubprojects: activeNestedSubprojects = (grapeConfig.GrapeConfigParser.getAllActiveNestedSubprojectPrefixes()) self.projects.extend(activeNestedSubprojects) self.subprojects.extend(activeNestedSubprojects) for proj in activeNestedSubprojects: status = "?" self.projlist.insert(Tk.END, "%s %s <Nested Subproject>" % (status, proj)) self.projstatus.append(status) self.projtype.append("Active Nested") if self.showInactive: inactiveNestedSubprojects = list(set(grapeConfig.grapeConfig().getAllNestedSubprojects()) - set(grapeConfig.GrapeConfigParser.getAllActiveNestedSubprojects())) self.projects.extend(inactiveNestedSubprojects) self.subprojects.extend(inactiveNestedSubprojects) for proj in inactiveNestedSubprojects: status = "?" self.projlist.insert(Tk.END, "%s %s <Inactive Nested Subproject>" % (status, proj)) self.projstatus.append(status) self.projtype.append("Inactive Nested") # Submodules self.submodules = [] if self.showSubmodules: activeSubmodules = (git.getActiveSubmodules()) self.projects.extend(activeSubmodules) self.submodules.extend(activeSubmodules) for proj in activeSubmodules: status = "?" self.projlist.insert(Tk.END, "%s %s <Submodule>" % (status, proj)) self.projstatus.append(status) self.projtype.append("Submodule") if self.showInactive: inactiveSubmodules = list(set(git.getAllSubmodules()) - set(git.getActiveSubmodules())) self.projects.extend(inactiveSubmodules) self.submodules.extend(inactiveSubmodules) for proj in inactiveSubmodules: status = "?" self.projlist.insert(Tk.END, "%s %s <Inactive Submodule>" % (status, proj)) self.projstatus.append(status) self.projtype.append("Inactive Submodule") # Subtrees self.subtrees = [] if self.showSubtrees: self.subtrees = [ self.grapeconfig.get('subtree-%s' % proj, 'prefix') for proj in self.grapeconfig.get('subtrees', 'names').strip().split() ] self.projects.extend(self.subtrees) for proj in self.subtrees: status = "?" self.projlist.insert(Tk.END, "%s %s <Subtree>" % (status, proj)) self.projstatus.append(status) self.projtype.append("Subtree") utility.printMsg("Done.") # Resize the project pane based on its contents self.projlistwidth = 0 self.numprojects = 0 for proj in self.projlist.get(0, Tk.END): if len(proj) > self.projlistwidth: self.projlistwidth = len(proj) self.numprojects += 1 self.projlist.config(width=self.projlistwidth) # Place the panes in the main window self.main.add(self.projpanel) self.main.add(self.filepanel) self.main.pack(fill=Tk.BOTH, expand=1, side=Tk.BOTTOM)
def execute(self, args): base = git.baseDir() if base == "": return False dotGit = git.gitDir() utility.printMsg("Optimizing git performance on slow file systems...") #runs file system intensive tasks such as git status and git commit # in parallel (important for NFS systems such as LC) git.config("core.preloadindex", "true") #have git automatically do some garbage collection / optimization utility.printMsg("Setting up automatic git garbage collection...") git.config("gc.auto", "1") #prevents false conflict detection due to differences in filesystem # time stamps utility.printMsg("Optimizing cross platform portability...") git.config("core.trustctime", "false") # stores login info for 12 hrs (max allowed by RZBitbucket) if not args["--nocredcache"]: cache = args["--credcache"] if not cache: cache = utility.userInput( "Would you like to enable git-managed credential caching?", 'y') if cache: utility.printMsg( "Enabling 12 hr caching of https credentials...") if os.name == "nt": git.config("--global credential.helper", "wincred") else: git.config("--global credential.helper", "cache --timeout=43200") # enables 'as' option for merge strategies -forces a conflict if two branches # modify the same file mergeVerifyPath = os.path.join(os.path.dirname(__file__), "..", "merge-and-verify-driver") if os.path.exists(mergeVerifyPath): utility.printMsg( "Enabling safe merges (triggers conflicts any time same file is modified),\n\t see 'as' option for grape m and grape md..." ) git.config("merge.verify.name", "merge and verify driver") git.config("merge.verify.driver", "%s/merge-and-verify-driver %A %O %B") else: utility.printMsg( "WARNING: merge and verify script not detected, safe merges ('as' option to grape m / md) will not work!" ) # enables lg as an alias to print a pretty-font summary of # key junctions in the history for this branch. utility.printMsg("Setting lg as an alias for a pretty log call...") git.config( "alias.lg", "log --graph --pretty=format:'%Cred%h%Creset -%C(yellow)%d%Creset %s %Cgreen(%cr) %C(bold blue)<%an>%Creset' --abbrev-commit --date=relative --simplify-by-decoration" ) # perform an update of the active subprojects if asked. ask = not args["--nouv"] updateView = ask and (args["--uv"] or utility.userInput( "Do you want to edit your active subprojects?" " (you can do this later using grape uv) [y/n]", "n")) if updateView: grapeMenu.menu().applyMenuChoice("uv", args["--uvArg"]) # configure git to use p4merge for conflict resolution # and diffing useP4Merge = not args["--nop4merge"] and ( args["--p4merge"] or utility.userInput( "Would you like to use p4merge as your merge tool? [y/n]", "y")) # note that this relies on p4merge being in your path somewhere if (useP4Merge): git.config("merge.keepBackup", "false") git.config("merge.tool", "p4merge") git.config("mergetool.keepBackup", "false") git.config( "mergetool.p4merge.cmd", 'p4merge \"\$BASE\" \"\$LOCAL\" \"\$REMOTE\" \"\$MERGED\"') git.config("mergetool.p4merge.keepTemporaries", "false") git.config("mergetool.p4merge.trustExitCode", "false") git.config("mergetool.p4merge.keepBackup", "false") utility.printMsg( "Configured repo to use p4merge for conflict resolution") else: git.config("merge.tool", "tkdiff") useP4Diff = not args["--nop4diff"] and ( args["--p4diff"] or utility.userInput( "Would you like to use p4merge as your diff tool? [y/n]", "y")) # this relies on p4diff being defined as a custom bash script, with the following one-liner: # [ $# -eq 7 ] && p4merge "$2" "$5" if (useP4Diff): p4diffScript = os.path.join(os.path.dirname(__file__), "..", "p4diff") if os.path.exists(p4diffScript): git.config("diff.external", p4diffScript) utility.printMsg( "Configured repo to use p4merge for diff calls - p4merge must be in your path" ) else: utility.printMsg("Could not find p4diff script at %s" % p4diffScript) useGitP4 = args["--git-p4"] if (useGitP4): git.config("git-p4.useclientspec", "true") # create p4 references to enable imports from p4 p4remotes = os.path.join(dotGit, "refs", "remotes", "p4", "") utility.ensure_dir(p4remotes) commit = utility.userInput( "Please enter a descriptor (e.g. SHA, branch if tip, tag name) of the current git commit that mirrors the p4 repo", "master") sha = git.SHA(commit) with open(os.path.join(p4remotes, "HEAD"), 'w') as f: f.write(sha) with open(os.path.join(p4remotes, "master"), 'w') as f: f.write(sha) # to enable exports to p4, a maindev client needs to be set up haveCopied = False while (not haveCopied): p4settings = utility.userInput( "Enter a path to a .p4settings file describing the maindev client you'd like to use for p4 updates", ".p4settings") try: shutil.copyfile(p4settings, os.path.join(base, ".p4settings")) haveCopied = True except: print( "could not find p4settings file, please check your path and try again" ) return False # install hooks here and in all submodules utility.printMsg("Installing hooks in all repos...") cwd = git.baseDir() grapeMenu.menu().applyMenuChoice("installHooks") # ensure all public branches are available in all repos submodules = git.getActiveSubmodules() config = grapeConfig.grapeConfig() publicBranches = config.getPublicBranchList() submodulePublicBranches = set( config.getMapping('workspace', 'submoduleTopicPrefixMappings').values()) for sub in submodules: self.ensurePublicBranchesExist(grapeConfig.grapeRepoConfig(sub), sub, submodulePublicBranches) # reset config to the workspace grapeconfig, use that one for all nested projects' public branches. wsDir = utility.workspaceDir() config = grapeConfig.grapeRepoConfig(wsDir) for proj in grapeConfig.GrapeConfigParser.getAllActiveNestedSubprojectPrefixes( ): self.ensurePublicBranchesExist(config, os.path.join(wsDir, proj), publicBranches) self.ensurePublicBranchesExist(config, wsDir, publicBranches) return True
def execute(self, args): """ A fair chunk of this stuff relies on stashy's wrapping of the STASH REST API, which is posted at https://developer.atlassian.com/static/rest/stash/2.12.1/stash-rest.html """ config = grapeConfig.grapeConfig() name = args["--user"] if not name: name = utility.getUserName() utility.printMsg("Logging onto %s" % args["--bitbucketURL"]) if args["--test"]: bitbucket = Atlassian.TestAtlassian(name) else: verify = True if args["--verifySSL"].lower() == "true" else False bitbucket = Atlassian.Atlassian(name, url=args["--bitbucketURL"], verify=verify) # default project (outer level project) project_name = args["--project"] # default repo (outer level repo) repo_name = args["--repo"] # determine source branch and target branch branch = args["--source"] if not branch: branch = git.currentBranch() # make sure we are in the outer level repo before we push wsDir = utility.workspaceDir() os.chdir(wsDir) #ensure branch is pushed utility.printMsg("Pushing %s to bitbucket..." % branch) git.push("origin %s" % branch) #target branch for outer level repo target_branch = args["--target"] if not target_branch: target_branch = config.getPublicBranchFor(branch) # load pull request from Bitbucket if it already exists wsRepo = bitbucket.project(project_name).repo(repo_name) existingOuterLevelRequest = getReposPullRequest( wsRepo, branch, target_branch, args) # determine pull request title title = args["--title"] if existingOuterLevelRequest is not None and not title: title = existingOuterLevelRequest.title() #determine pull request URL outerLevelURL = None if existingOuterLevelRequest: outerLevelURL = existingOuterLevelRequest.link() # determine pull request description descr = self.parseDescriptionArgs(args) if not descr and existingOuterLevelRequest: descr = existingOuterLevelRequest.description() # determine pull request reviewers reviewers = self.parseReviewerArgs(args) if reviewers is None and existingOuterLevelRequest is not None: reviewers = [r[0] for r in existingOuterLevelRequest.reviewers()] # if we're in append mode, only append what was asked for: if args["--append"] or args["--prepend"]: title = args["--title"] descr = self.parseDescriptionArgs(args) reviewers = self.parseReviewerArgs(args) ## Submodule Repos missing = utility.getModifiedInactiveSubmodules(target_branch, branch) if missing: utility.printMsg( "The following submodules that you've modified are not currently present in your workspace.\n" "You should activate them using grape uv and then call grape review again. If you haven't modified " "these submodules, you may need to do a grape md to proceed.") utility.printMsg(','.join(missing)) return False pullRequestLinks = {} if not args["--norecurse"] and (args["--recurse"] or config.getboolean( "workspace", "manageSubmodules")): modifiedSubmodules = git.getModifiedSubmodules( target_branch, branch) submoduleBranchMappings = config.getMapping( "workspace", "submoduleTopicPrefixMappings") for submodule in modifiedSubmodules: if not submodule: continue # push branch os.chdir(submodule) utility.printMsg("Pushing %s to bitbucket..." % branch) git.push("origin %s" % branch) os.chdir(wsDir) repo = bitbucket.repoFromWorkspaceRepoPath(submodule, isSubmodule=True) # determine branch prefix prefix = branch.split('/')[0] sub_target_branch = submoduleBranchMappings[prefix] prevSubDescr = getReposPullRequestDescription( repo, branch, sub_target_branch, args) #amend the subproject pull request description with the link to the outer pull request subDescr = addLinkToDescription(descr, outerLevelURL, True) if args["--prepend"] or args["--append"]: subDescr = descr newRequest = postPullRequest(repo, title, branch, sub_target_branch, subDescr, reviewers, args) if newRequest: pullRequestLinks[newRequest.link()] = True else: # if a pull request could not be generated, just add a link to browse the branch pullRequestLinks[ "%s%s/browse?at=%s" % (bitbucket.rzbitbucketURL, repo.repo.url(), urllib.quote_plus("refs/heads/%s" % branch))] = False ## NESTED SUBPROJECT REPOS nestedProjects = grapeConfig.GrapeConfigParser.getAllModifiedNestedSubprojects( target_branch) nestedProjectPrefixes = grapeConfig.GrapeConfigParser.getAllModifiedNestedSubprojectPrefixes( target_branch) for proj, prefix in zip(nestedProjects, nestedProjectPrefixes): with utility.cd(prefix): git.push("origin %s" % branch) repo = bitbucket.repoFromWorkspaceRepoPath(proj, isSubmodule=False, isNested=True) newRequest = postPullRequest(repo, title, branch, target_branch, descr, reviewers, args) if newRequest: pullRequestLinks[newRequest.link()] = True else: # if a pull request could not be generated, just add a link to browse the branch pullRequestLinks["%s%s/browse?at=%s" % (bitbucket.rzbitbucketURL, repo.repo.url(), urllib.quote_plus( "refs/heads/%s" % branch))] = False ## OUTER LEVEL REPO # load the repo level REST resource if not args["--subprojectsOnly"]: if not git.hasBranch(branch): utility.printMsg( "Top level repository does not have a branch %s, not generating a Pull Request" % (branch)) return True if git.branchUpToDateWith(target_branch, branch): utility.printMsg( "%s up to date with %s, not generating a Pull Request in Top Level repo" % (target_branch, branch)) return True repo_name = args["--repo"] repo = bitbucket.repoFromWorkspaceRepoPath( wsDir, topLevelRepo=repo_name, topLevelProject=project_name) utility.printMsg("Posting pull request to %s,%s" % (project_name, repo_name)) request = postPullRequest(repo, title, branch, target_branch, descr, reviewers, args) updatedDescription = request.description() for link in pullRequestLinks: updatedDescription = addLinkToDescription( updatedDescription, link, pullRequestLinks[link]) if updatedDescription != request.description(): request = postPullRequest(repo, title, branch, target_branch, updatedDescription, reviewers, args) utility.printMsg("Request generated/updated:\n\n%s" % request) return True
def execute(self, args): if not "<<cmd>>" in args: args["<<cmd>>"] = "md" branch = args["--public"] if not branch: currentBranch = git.currentBranch() branch = grapeConfig.grapeConfig().getPublicBranchFor( git.currentBranch()) if not branch: utility.printMsg( "ERROR: public branches must be configured for grape md to work." ) args["--public"] = branch # determine whether to merge in subprojects that have changed try: submodules = self.progress["submodules"] except KeyError: modifiedSubmodules = git.getModifiedSubmodules( branch, git.currentBranch()) activeSubmodules = git.getActiveSubmodules() submodules = [ sub for sub in modifiedSubmodules if sub in activeSubmodules ] try: nested = self.progress["nested"] except KeyError: nested = grapeConfig.GrapeConfigParser.getAllActiveNestedSubprojectPrefixes( ) config = grapeConfig.grapeConfig() recurse = config.getboolean("workspace", "manageSubmodules") or args["--recurse"] recurse = recurse and (not args["--noRecurse"]) and len(submodules) > 0 args["--recurse"] = recurse # if we stored cwd in self.progress, make sure we end up there if "cwd" in self.progress: cwd = self.progress["cwd"] else: cwd = utility.workspaceDir() os.chdir(cwd) if "conflictedFiles" in self.progress: conflictedFiles = self.progress["conflictedFiles"] else: conflictedFiles = [] # take note of whether all submodules are currently present, assume user wants to add any new submodules to WS if so activeSubmodulesCheck0 = git.getActiveSubmodules() self.progress["allActive"] = set(git.getAllSubmodules()) == set( git.getActiveSubmodules()) # checking for a consistent workspace before doing a merge utility.printMsg( "Checking for a consistent workspace before performing merge...") ret = grapeMenu.menu().applyMenuChoice("status", ['--failIfInconsistent']) if ret is False: utility.printMsg( "Workspace inconsistent! Aborting attempt to do the merge. Please address above issues and then try again." ) return False if not "updateLocalDone" in self.progress and not args["--noUpdate"]: # make sure public branches are to date in outer level repo. utility.printMsg( "Calling grape up to ensure topic and public branches are up-to-date. " ) grapeMenu.menu().applyMenuChoice( 'up', ['up', '--public=%s' % args["--public"]]) self.progress["updateLocalDone"] = True # do an outer merge if we haven't done it yet if not "outerLevelDone" in self.progress: self.progress["outerLevelDone"] = False if not self.progress["outerLevelDone"]: conflictedFiles = self.outerLevelMerge(args, branch) # outerLevelMerge returns False if there was a non-conflict related issue if conflictedFiles is False: utility.printMsg( "Initial merge failed. Resolve issue and try again. ") return False # merge nested subprojects for subproject in nested: if not self.mergeSubproject( args, subproject, branch, nested, cwd, isSubmodule=False): # stop for user to resolve conflicts self.progress["nested"] = nested self.dumpProgress(args) os.chdir(cwd) return False os.chdir(cwd) # merge submodules if recurse: if len(submodules) > 0: if args["--subpublic"]: # respect the callers wishes (usually this is grape m , mr, or pull) subPublic = args["--subpublic"] else: # default is to merge the submodule branch that is mapped to the public branch subBranchMappings = config.getMapping( "workspace", "submodulePublicMappings") subPublic = subBranchMappings[config.getPublicBranchFor( branch)] for submodule in submodules: if not self.mergeSubproject(args, submodule, subPublic, submodules, cwd, isSubmodule=True): # stop for user to resolve conflicts self.progress["conflictedFiles"] = conflictedFiles self.dumpProgress(args) return False os.chdir(cwd) conflictedFiles = git.conflictedFiles() # now that we resolved the submodule conflicts, continue the outer level merge if len(conflictedFiles) == 0: self.continueLocalMerge(args) conflictedFiles = git.conflictedFiles() if conflictedFiles: self.progress["stopPoint"] = "resolve conflicts" self.progress["cwd"] = cwd self.dumpProgress( args, "GRAPE: Outer level merge generated conflicts. Please resolve using git mergetool " "and then \n continue by calling 'grape md --continue' .") return False else: grapeMenu.menu().applyMenuChoice("runHook", ["post-merge", '0', "--noExit"]) # ensure all submodules are currently present in WS if all submodules were present at the beginning of merge if self.progress["allActive"]: activeSubmodulesCheck1 = git.getActiveSubmodules() if (set(activeSubmodulesCheck0) != set(activeSubmodulesCheck1)): utility.printMsg( "Updating new submodules using grape uv --allSubmodules") grapeMenu.menu().applyMenuChoice( "uv", ["--allSubmodules", "--skipNestedSubprojects"]) return True
def execute(self, args): if not "<<cmd>>" in args: args["<<cmd>>"] = "md" branch = args["--public"] if not branch: currentBranch = git.currentBranch() branch = grapeConfig.grapeConfig().getPublicBranchFor(git.currentBranch()) if not branch: utility.printMsg("ERROR: public branches must be configured for grape md to work.") args["--public"] = branch # determine whether to merge in subprojects that have changed try: submodules = self.progress["submodules"] except KeyError: modifiedSubmodules = git.getModifiedSubmodules(branch, git.currentBranch()) activeSubmodules = git.getActiveSubmodules() submodules = [sub for sub in modifiedSubmodules if sub in activeSubmodules] try: nested = self.progress["nested"] except KeyError: nested = grapeConfig.GrapeConfigParser.getAllActiveNestedSubprojectPrefixes() config = grapeConfig.grapeConfig() recurse = config.getboolean("workspace", "manageSubmodules") or args["--recurse"] recurse = recurse and (not args["--noRecurse"]) and len(submodules) > 0 args["--recurse"] = recurse # if we stored cwd in self.progress, make sure we end up there if "cwd" in self.progress: cwd = self.progress["cwd"] else: cwd = utility.workspaceDir() os.chdir(cwd) if "conflictedFiles" in self.progress: conflictedFiles = self.progress["conflictedFiles"] else: conflictedFiles = [] # take note of whether all submodules are currently present, assume user wants to add any new submodules to WS if so activeSubmodulesCheck0 = git.getActiveSubmodules() self.progress["allActive"] = set(git.getAllSubmodules()) == set(git.getActiveSubmodules()) # checking for a consistent workspace before doing a merge utility.printMsg("Checking for a consistent workspace before performing merge...") ret = grapeMenu.menu().applyMenuChoice("status", ['--failIfInconsistent']) if ret is False: utility.printMsg("Workspace inconsistent! Aborting attempt to do the merge. Please address above issues and then try again.") return False if not "updateLocalDone" in self.progress and not args["--noUpdate"]: # make sure public branches are to date in outer level repo. utility.printMsg("Calling grape up to ensure topic and public branches are up-to-date. ") grapeMenu.menu().applyMenuChoice('up', ['up','--public=%s' % args["--public"]]) self.progress["updateLocalDone"] = True # do an outer merge if we haven't done it yet if not "outerLevelDone" in self.progress: self.progress["outerLevelDone"] = False if not self.progress["outerLevelDone"]: conflictedFiles = self.outerLevelMerge(args, branch) # outerLevelMerge returns False if there was a non-conflict related issue if conflictedFiles is False: utility.printMsg("Initial merge failed. Resolve issue and try again. ") return False # merge nested subprojects for subproject in nested: if not self.mergeSubproject(args, subproject, branch, nested, cwd, isSubmodule=False): # stop for user to resolve conflicts self.progress["nested"] = nested self.dumpProgress(args) os.chdir(cwd) return False os.chdir(cwd) # merge submodules if recurse: if len(submodules) > 0: if args["--subpublic"]: # respect the callers wishes (usually this is grape m , mr, or pull) subPublic = args["--subpublic"] else: # default is to merge the submodule branch that is mapped to the public branch subBranchMappings = config.getMapping("workspace", "submodulePublicMappings") subPublic = subBranchMappings[config.getPublicBranchFor(branch)] for submodule in submodules: if not self.mergeSubproject(args, submodule, subPublic, submodules, cwd, isSubmodule=True): # stop for user to resolve conflicts self.progress["conflictedFiles"] = conflictedFiles self.dumpProgress(args) return False os.chdir(cwd) conflictedFiles = git.conflictedFiles() # now that we resolved the submodule conflicts, continue the outer level merge if len(conflictedFiles) == 0: self.continueLocalMerge(args) conflictedFiles = git.conflictedFiles() if conflictedFiles: self.progress["stopPoint"] = "resolve conflicts" self.progress["cwd"] = cwd self.dumpProgress(args, "GRAPE: Outer level merge generated conflicts. Please resolve using git mergetool " "and then \n continue by calling 'grape md --continue' .") return False else: grapeMenu.menu().applyMenuChoice("runHook", ["post-merge", '0', "--noExit"]) # ensure all submodules are currently present in WS if all submodules were present at the beginning of merge if self.progress["allActive"]: activeSubmodulesCheck1 = git.getActiveSubmodules() if (set(activeSubmodulesCheck0) != set(activeSubmodulesCheck1)): utility.printMsg("Updating new submodules using grape uv --allSubmodules") grapeMenu.menu().applyMenuChoice("uv", ["--allSubmodules", "--skipNestedSubprojects"]) return True
def execute(self, args): sync = args["--sync"].lower().strip() sync = sync == "true" or sync == "yes" args["--sync"] = sync checkoutargs = '' branch = args["<branch>"] if args['-b']: checkoutargs += " -b" workspaceDir = utility.workspaceDir() os.chdir(workspaceDir) currentSHA = git.shortSHA("HEAD") utility.printMsg("Performing checkout of %s in outer level project." % branch) launcher = utility.MultiRepoCommandLauncher(handledCheckout, listOfRepoBranchArgTuples=[(workspaceDir, branch, [checkoutargs, sync])]) if not launcher.launchFromWorkspaceDir(handleMRE=handleCheckoutMRE)[0]: return False previousSHA = currentSHA submoduleListDidChange = ".gitmodules" in git.diff("--name-only %s %s" % (previousSHA, branch)) addedModules = [] removedModules = [] uvArgs = [] submodulesDidChange = False if submoduleListDidChange and grapeConfig.grapeConfig().getboolean("workspace", "manageSubmodules"): self.parseGitModulesDiffOutput(git.diff("%s %s --no-ext-diff -- .gitmodules" % (previousSHA, branch)), addedModules, removedModules) if not addedModules and not removedModules: pass else: submodulesDidChange = True if removedModules: for sub in removedModules: try: os.chdir(os.path.join(workspaceDir, sub)) if git.isWorkingDirectoryClean(): cleanBehaviorSet = args["--noUpdateView"] or args["--updateView"] if not cleanBehaviorSet: clean = utility.userInput("Would you like to remove the submodule %s ?" % sub, 'n') elif args["--noUpdateView"]: clean = False elif args["--updateView"]: clean = True if clean: utility.printMsg("Removing clean submodule %s." % sub) os.chdir(workspaceDir) shutil.rmtree(os.path.join(workspaceDir, sub)) else: utility.printMsg("Unstaged / committed changes in %s, not removing." % sub) os.chdir(workspaceDir) except OSError: pass # check to see if nested project list changed addedProjects = [] removedProjects = [] removedProjectPrefices = {} nestedProjectListDidChange = False os.chdir(workspaceDir) if ".grapeconfig" in git.diff("--name-only %s %s" % (previousSHA, branch)): configDiff = git.diff("--no-ext-diff %s %s -- %s" % (previousSHA, branch, ".grapeconfig")) nestedProjectListDidChange = "[nestedprojects]" in configDiff.lower() self.parseGrapeConfigNestedProjectDiffOutput(configDiff, addedProjects, removedProjects, removedProjectPrefices) if removedProjects: config = grapeConfig.grapeConfig() for proj in removedProjects: projPrefix = removedProjectPrefices[proj] try: os.chdir(os.path.join(workspaceDir, proj)) except OSError as e: if e.errno == 2: # directory doesn't exist, that's OK since we're thinking about removing it # anyways at this point... continue if git.isWorkingDirectoryClean(): removeBehaviorSet = args["--noUpdateView"] or args["--updateView"] if not removeBehaviorSet: remove = utility.userInput("Would you like to remove the nested subproject %s? \n" "All work that has not been pushed will be lost. " % projPrefix, 'n' ) elif args["--noUpdateView"]: remove = False elif args["--updateView"]: remove = True if remove: remove = utility.userInput("Are you sure you want to remove %s? When you switch back to the previous branch, you will have to\n" "reclone %s." % (projPrefix, projPrefix), 'n') if remove: os.chdir(workspaceDir) shutil.rmtree(os.path.join(workspaceDir,projPrefix)) else: utility.printMsg("Unstaged / committed changes in %s, not removing. \n" "Note this project is NOT active in %s. " % (projPrefix, branch)) os.chdir(workspaceDir) if not submodulesDidChange and not nestedProjectListDidChange: uvArgs.append("--checkSubprojects") else: updateViewSet = args["--noUpdateView"] or args["--updateView"] if not updateViewSet: updateView = utility.userInput("Submodules or subprojects were added/removed as a result of this checkout. \n" + "%s" % ("Added Projects: %s\n" % ','.join(addedProjects) if addedProjects else "") + "%s" % ("Added Submodules: %s\n"% ','.join(addedModules) if addedModules else "") + "%s" % ("Removed Projects: %s\n" % ','.join(removedProjects) if removedProjects else "") + "%s" % ("Removed Submodules: %s\n" % ','.join(removedModules) if removedModules else "") + "Would you like to update your workspace view? [y/n]", 'n') elif args["--noUpdateView"]: updateView = False elif args["--updateView"]: updateView = True if not updateView: uvArgs.append("--checkSubprojects") if args["-b"]: uvArgs.append("-b") if sync: uvArgs.append("--sync=True") else: uvArgs.append("--sync=False") # in case the user switches to a branch without corresponding branches in the submodules, make sure active submodules # are at the right commit before possibly creating new branches at the current HEAD. git.submodule("update") utility.printMsg("Calling grape uv %s to ensure branches are consistent across all active subprojects and submodules." % ' '.join(uvArgs)) grapeConfig.read() grapeMenu.menu().applyMenuChoice('uv', uvArgs) os.chdir(workspaceDir) if sync: utility.printMsg("Switched to %s. Updating from remote...\n\t (use --sync=False or .grapeconfig.post-checkout.syncWithOrigin to change behavior.)" % branch) if args["-b"]: grapeMenu.menu().applyMenuChoice("push") else: grapeMenu.menu().applyMenuChoice("pull") else: utility.printMsg("Switched to %s." % branch) global _skipBranchCreation global _createNewBranch _skipBranchCreation = False _createNewBranch = False return True
def defineActiveSubmodules(projectType="submodule"): """ Queries the user for the submodules (projectType == "submodule") or nested subprojects (projectType == "nested subproject") they would like to activate. """ if projectType == "submodule": allSubprojects = git.getAllSubmodules() activeSubprojects = git.getActiveSubmodules() if projectType == "nested subproject": config = grapeConfig.grapeConfig() allSubprojectNames = config.getAllNestedSubprojects() allSubprojects = [] for project in allSubprojectNames: allSubprojects.append(config.get("nested-%s" % project, "prefix")) activeSubprojects = grapeConfig.GrapeConfigParser.getAllActiveNestedSubprojectPrefixes() toplevelDirs = {} toplevelActiveDirs = {} toplevelSubs = [] for sub in allSubprojects: # we are taking advantage of the fact that branchPrefixes are the same as directory prefixes for local # top-level dirs. prefix = git.branchPrefix(sub) if sub != prefix: toplevelDirs[prefix] = [] toplevelActiveDirs[prefix] = [] for sub in allSubprojects: prefix = git.branchPrefix(sub) if sub != prefix: toplevelDirs[prefix].append(sub) else: toplevelSubs.append(sub) for sub in activeSubprojects: prefix = git.branchPrefix(sub) if sub != prefix: toplevelActiveDirs[prefix].append(sub) included = {} for directory, subprojects in toplevelDirs.items(): activeDir = toplevelActiveDirs[directory] if len(activeDir) == 0: defaultValue = "none" elif set(activeDir) == set(subprojects): defaultValue = "all" else: defaultValue = "some" opt = utility.userInput("Would you like all, some, or none of the %ss in %s?" % (projectType,directory), default=defaultValue) if opt.lower()[0] == "a": for subproject in subprojects: included[subproject] = True if opt.lower()[0] == "n": for subproject in subprojects: included[subproject] = False if opt.lower()[0] == "s": for subproject in subprojects: included[subproject] = utility.userInput("Would you like %s %s? [y/n]" % (projectType, subproject), 'y' if (subproject in activeSubprojects) else 'n') for subproject in toplevelSubs: included[subproject] = utility.userInput("Would you like %s %s? [y/n]" % (projectType, subproject), 'y' if (subproject in activeSubprojects) else 'n') return included
def execute(self, args): sync = args["--sync"].lower().strip() sync = sync == "true" or sync == "yes" args["--sync"] = sync config = grapeConfig.grapeConfig() origwd = os.getcwd() wsDir = utility.workspaceDir() os.chdir(wsDir) base = git.baseDir() if base == "": return False hasSubmodules = len(git.getAllSubmodules()) > 0 and not args["--skipSubmodules"] includedSubmodules = {} includedNestedSubprojectPrefixes = {} allSubmodules = git.getAllSubmodules() allNestedSubprojects = config.getAllNestedSubprojects() addedSubmodules = [] addedNestedSubprojects = [] addedProjects = args["--add"] notFound = [] for proj in addedProjects: if proj in allSubmodules: addedSubmodules.append(proj) elif proj in allNestedSubprojects: addedNestedSubprojects.append(proj) else: notFound.append(proj) rmSubmodules = [] rmNestedSubprojects = [] rmProjects = args["--rm"] for proj in rmProjects: if proj in allSubmodules: rmSubmodules.append(proj) elif proj in allNestedSubprojects: rmNestedSubprojects.append(proj) else: notFound.append(proj) if notFound: utility.printMsg("\"%s\" not found in submodules %s \nor\n nested subprojects %s" % (",".join(notFound),",".join(allSubmodules),",".join(allNestedSubprojects))) return False if not args["--checkSubprojects"]: # get submodules to update if hasSubmodules: if args["--allSubmodules"]: includedSubmodules = {sub:True for sub in allSubmodules} elif args["--add"] or args["--rm"]: includedSubmodules = {sub:True for sub in git.getActiveSubmodules()} includedSubmodules.update({sub:True for sub in addedSubmodules}) includedSubmodules.update({sub:False for sub in rmSubmodules}) else: includedSubmodules = self.defineActiveSubmodules() # get subprojects to update if not args["--skipNestedSubprojects"]: nestedPrefixLookup = lambda x : config.get("nested-%s" % x, "prefix") if args["--allNestedSubprojects"]: includedNestedSubprojectPrefixes = {nestedPrefixLookup(sub):True for sub in allNestedSubprojects} elif args["--add"] or args["--rm"]: includedNestedSubprojectPrefixes = {sub:True for sub in grapeConfig.GrapeConfigParser.getAllActiveNestedSubprojectPrefixes()} includedNestedSubprojectPrefixes.update({nestedPrefixLookup(sub):True for sub in addedNestedSubprojects}) includedNestedSubprojectPrefixes.update({nestedPrefixLookup(sub):False for sub in rmNestedSubprojects}) else: includedNestedSubprojectPrefixes = self.defineActiveNestedSubprojects() if hasSubmodules: initStr = "" deinitStr = "" rmCachedStr = "" resetStr = "" for submodule, nowActive in includedSubmodules.items(): if nowActive: initStr += ' %s' % submodule else: deinitStr += ' %s' % submodule rmCachedStr += ' %s' % submodule resetStr += ' %s' % submodule if args["-f"] and deinitStr: deinitStr = "-f"+deinitStr utility.printMsg("Configuring submodules...") utility.printMsg("Initializing submodules...") git.submodule("init %s" % initStr.strip()) if deinitStr: utility.printMsg("Deiniting submodules that were not requested... (%s)" % deinitStr) done = False while not done: try: git.submodule("deinit %s" % deinitStr.strip()) done = True except git.GrapeGitError as e: if "the following file has local modifications" in e.gitOutput: print e.gitOutput utility.printMsg("A submodule that you wanted to remove has local modifications. " "Use grape uv -f to force removal.") return False elif "use 'rm -rf' if you really want to remove it including all of its history" in e.gitOutput: if not args["-f"]: raise e # it is safe to move the .git of the submodule to the .git/modules area of the workspace... module = None for l in e.gitOutput.split('\n'): if "Submodule work tree" in l and "contains a .git directory" in l: module = l.split("'")[1] break if module: src = os.path.join(module, ".git") dest = os.path.join(wsDir, ".git", "modules", module) utility.printMsg("Moving %s to %s"%(src, dest)) shutil.move(src, dest ) else: raise e else: raise e git.rm("--cached %s" % rmCachedStr) git.reset(" %s" % resetStr) if initStr: utility.printMsg("Updating active submodules...(%s)" % initStr) git.submodule("update") # handle nested subprojects if not args["--skipNestedSubprojects"]: reverseLookupByPrefix = {nestedPrefixLookup(sub) : sub for sub in allNestedSubprojects} userConfig = grapeConfig.grapeUserConfig() updatedActiveList = [] for subproject, nowActive in includedNestedSubprojectPrefixes.items(): subprojectName = reverseLookupByPrefix[subproject] section = "nested-%s" % reverseLookupByPrefix[subproject] userConfig.ensureSection(section) previouslyActive = userConfig.getboolean(section, "active") previouslyActive = previouslyActive and os.path.exists(os.path.join(base, subproject, ".git")) userConfig.set(section, "active", "True" if previouslyActive else "False") if nowActive and previouslyActive: updatedActiveList.append(subprojectName) if nowActive and not previouslyActive: utility.printMsg("Activating Nested Subproject %s" % subproject) if not addSubproject.AddSubproject.activateNestedSubproject(subprojectName, userConfig): utility.printMsg("Can't activate %s. Exiting..." % subprojectName) return False updatedActiveList.append(subprojectName) if not nowActive and not previouslyActive: pass if not nowActive and previouslyActive: #remove the subproject subprojectdir = os.path.join(base, utility.makePathPortable(subproject)) proceed = args["-f"] or \ utility.userInput("About to delete all contents in %s. Any uncommitted changes, committed changes " "that have not been pushed, or ignored files will be lost. Proceed?" % subproject, 'n') if proceed: shutil.rmtree(subprojectdir) userConfig.setActiveNestedSubprojects(updatedActiveList) grapeConfig.writeConfig(userConfig, os.path.join(utility.workspaceDir(), ".git", ".grapeuserconfig")) checkoutArgs = "-b" if args["-b"] else "" safeSwitchWorkspaceToBranch( git.currentBranch(), checkoutArgs, sync) os.chdir(origwd) return True
def config(self): return grapeConfig.grapeConfig()