def postMerge(args): updateSubmodule = args["--mergeSubmodule"] if updateSubmodule and updateSubmodule.lower() == 'true': utility.printMsg("Post-Merge Hook: Syncing submodule URLs...") git.submodule("--quiet sync") utility.printMsg("Post-Merge Hook: Updating submodules...") git.submodule("--quiet update --merge")
def _resume(self, args, deleteProgressFile=True): try: self._readProgressFile() except IOError: # give the workspace level progress file a shot try: self.progressFile = os.path.join(utility.workspaceDir(), ".git", "grapeProgress") self._readProgressFile() except IOError as e: try: # look for it at the home directory level self.progressFile = os.path.join(os.path.expanduser('~'), ".grapeProgress") self._readProgressFile() except: utility.printMsg( "No progress file found to continue from. Please enter a command without the " "--continue option. ") raise e newArgs = self.progress["args"] #overwrite args with the loaded args for key in newArgs.keys(): args[key] = newArgs[key] #load the config grapeConfig.resetGrapeConfig(self.progress["config"]) if deleteProgressFile: self._removeProgressFile()
def execute(self, args): mrArgs = {} currentBranch = git.currentBranch() mrArgs["<branch>"] = currentBranch # the <<cmd>> stuff is for consistent --continue output if not "<<cmd>>" in args: args["<<cmd>>"] = "pull" mrArgs["<<cmd>>"] = args["<<cmd>>"] mrArgs["--am"] = True mrArgs["--as"] = False mrArgs["--at"] = False mrArgs["--aT"] = False mrArgs["--ay"] = False mrArgs["--aY"] = False mrArgs["--askAll"] = False mrArgs["--continue"] = args["--continue"] mrArgs["--noRecurse"] = False mrArgs["--squash"] = False if args["--noRecurse"]: git.pull("origin %s" % currentBranch) utility.printMsg("Pulled current branch from origin") return True else: val = grapeMenu.menu().getOption("mr").execute(mrArgs) if val: utility.printMsg("Pulled current branch from origin") return val
def postCheckout(args): updateSubmodule = args["--checkoutSubmodule"] if updateSubmodule and updateSubmodule.lower() == 'true': utility.printMsg("Post-Checkout Hook: Syncing submodule URLs...") git.submodule("--quiet sync") utility.printMsg("Post-Checkout Hook: Updating submodules...") git.submodule("--quiet update")
def getModifiedSubmodules(branch1="", branch2=""): cwd = os.getcwd() wsDir = utility.workspaceDir() os.chdir(wsDir) submodules = getAllSubmodules() # if there are no submodules, then return the empty list if len(submodules) == 0 or (len(submodules) == 1 and not submodules[0]): return [] submodulesString = ' '.join(submodules) try: modifiedSubmodules = diff( "--name-only %s %s -- %s" % (branch1, branch2, submodulesString)).split('\n') except GrapeGitError as e: if "bad revision" in e.gitOutput: utility.printMsg( "getModifiedSubmodules: requested difference between one or more branches that do not exist. Assuming no modifications." ) return [] if len(modifiedSubmodules) == 1 and not modifiedSubmodules[0]: return [] # make sure everything in modifiedSubmodules is in the original list of submodules # (this can not be the case if the module existed as a regular directory / subtree in the other branch, # in which case the diff command will list the contents of the directory as opposed to just the submodule) verifiedSubmodules = [] for s in modifiedSubmodules: if s in submodules: verifiedSubmodules.append(s) os.chdir(cwd) return verifiedSubmodules
def _resume(self, args, deleteProgressFile=True): try: self._readProgressFile() except IOError: # give the workspace level progress file a shot try: self.progressFile = os.path.join(utility.workspaceDir(), ".git", "grapeProgress") self._readProgressFile() except IOError as e: try: # look for it at the home directory level self.progressFile = os.path.join(os.path.expanduser('~'), ".grapeProgress") self._readProgressFile() except: utility.printMsg("No progress file found to continue from. Please enter a command without the " "--continue option. ") raise e newArgs = self.progress["args"] #overwrite args with the loaded args for key in newArgs.keys(): args[key] = newArgs[key] #load the config grapeConfig.resetGrapeConfig(self.progress["config"]) if deleteProgressFile: self._removeProgressFile()
def commit(self, commitargs, repo): try: git.commit(commitargs) return True except git.GrapeGitError as e: utility.printMsg("Commit in %s failed. Perhaps there were no staged changes? Use -a to commit all modified files." % repo) return False
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 ensureLocalUpToDateWithRemote(repo = '', branch = 'master'): utility.printMsg( "Ensuring local branch %s in %s is up to date with origin" % (branch, repo)) with utility.cd(repo): # attempt to fetch the requested branch try: git.fetch("origin", "%s:%s" % (branch, branch)) except: # the branch may not exist, but this is ok pass if git.currentBranch() == branch: return if not git.hasBranch(branch): # switch to corresponding public branch if the branch does not exist public = grapeConfig.workspaceConfig().getPublicBranchFor(branch) # figure out if this is a submodule relpath = os.path.relpath(repo, utility.workspaceDir()) relpath = relpath.replace('\\',"/") with utility.cd(utility.workspaceDir()): # if this is a submodule, get the appropriate public mapping if relpath in git.getAllSubmoduleURLMap().keys(): public = grapeConfig.workspaceConfig().getMapping("workspace", "submodulepublicmappings")[public] utility.printMsg("Branch %s does not exist in %s, switching to %s and detaching" % (branch, repo, public)) git.checkout(public) git.pull("origin %s" % (public)) git.checkout("--detach HEAD")
def ensureLocalUpToDateWithRemote(repo='', branch='master'): utility.printMsg( "Ensuring local branch %s in %s is up to date with origin" % (branch, repo)) with utility.cd(repo): # attempt to fetch the requested branch try: git.fetch("origin", "%s:%s" % (branch, branch)) except: # the branch may not exist, but this is ok pass if git.currentBranch() == branch: return if not git.hasBranch(branch): # switch to corresponding public branch if the branch does not exist public = grapeConfig.workspaceConfig().getPublicBranchFor(branch) # figure out if this is a submodule relpath = os.path.relpath(repo, utility.workspaceDir()) relpath = relpath.replace('\\', "/") with utility.cd(utility.workspaceDir()): # if this is a submodule, get the appropriate public mapping if relpath in git.getAllSubmoduleURLMap().keys(): public = grapeConfig.workspaceConfig().getMapping( "workspace", "submodulepublicmappings")[public] utility.printMsg( "Branch %s does not exist in %s, switching to %s and detaching" % (branch, repo, public)) git.checkout(public) git.pull("origin %s" % (public)) git.checkout("--detach HEAD")
def pull(branch="develop", repo=".", rebase=False): if rebase: argStr = "--rebase origin %s" % branch else: argStr = "origin %s " % branch utility.printMsg("Pulling %s in %s..." % (branch, repo)) git.pull(argStr, throwOnFail=True)
def bundlecmdMRE(mre): print mre try: raise mre except utility.MultiRepoException as errors: utility.printMsg("WARNING: ERRORS WERE GENERATED DURING GRAPE BUNDLE") for e, b in zip(errors.exceptions(), errors.branches()): print b, e
def createNewBranches(repo='', branch='', args={}): project = repo checkoutargs = args["checkout"] with utility.cd(project): utility.printMsg("Creating new branch %s in %s." % (branch, project)) git.checkout(checkoutargs + " -b " + branch) git.push("-u origin %s" % branch) return True
def createNewBranches(repo='', branch='', args={}): project = repo checkoutargs = args["checkout"] with utility.cd(project): utility.printMsg("Creating new branch %s in %s." % (branch, project)) git.checkout(checkoutargs+" -b "+branch) git.push("-u origin %s" % branch) return True
def execute(self, args): workspaceDir = utility.workspaceDir() utility.printMsg("Installing hooks in %s." % workspaceDir) self.installHooksInRepo(workspaceDir, args) if not args["--noRecurse"]: for sub in utility.getActiveSubprojects(): utility.printMsg("Installing hooks in %s." % sub) self.installHooksInRepo(os.path.join(workspaceDir, sub), args) return True
def detachThenForceDeleteBranch(repo='', branch='master', args=None): with utility.cd(repo): utility.printMsg( "*** WARNING ***: Detaching in order to delete %s in %s. You will be in a headless state." % (branch, repo)) git.checkout("--detach HEAD") git.branch("-D %s" % branch) if "origin/%s" % branch in git.remoteBranches(): git.push("--delete origin %s" % branch, throwOnFail=False)
def commit(self, commitargs, repo): try: git.commit(commitargs) return True except git.GrapeGitError as e: utility.printMsg( "Commit in %s failed. Perhaps there were no staged changes? Use -a to commit all modified files." % repo) return False
def handleForeachMRE(mre): for e1 in mre.exceptions(): try: raise e1 except git.GrapeGitError as e: utility.printMsg("Foreach failed.") print e.gitCommand print e.cwd print e.gitOutput return False
def showRemote(): try: return gitcmd("remote show origin", "unable to show remote") except GrapeGitError as e: if e.code == 128: utility.printMsg("WARNING: %s failed. Ignoring..." % e.gitCommand) return e.gitOutput else: raise e
def execute(self, file): try: cmd = "difftool --find-renames --find-copies %s -y %s %s -- " % (self.difftoolarg, self.diffargs, self.diffBranchSpec(self.diffbranchA, self.diffbranchB)) if isinstance(file,list): cmd += "\"%s\" \"%s\"" % (file[0], file[1]) else: cmd += "\"%s\"" % file difftooloutput = git.gitcmd(cmd, "Failed to launch difftool") except git.GrapeGitError as e: utility.printMsg("%s (return code %d)\n%s" % (e.msg, e.returnCode, e.gitOutput))
def handlePushMRE(mre): for e1 in mre.exceptions(): try: raise e1 except git.GrapeGitError as e: utility.printMsg("Failed to push branch.") print e.gitCommand print e.cwd print e.gitOutput return False
def deleteBranch(repo='', branch='master', args=None): force = args[0] forceStr = "-D" if force is True else "-d" with utility.cd(repo): utility.printMsg("deleting %s in %s..." % (branch, repo)) git.branch("%s %s" % (forceStr, branch)) if "origin/%s" % branch in git.branch("-r"): try: git.push("--delete origin %s" % branch, throwOnFail=True) except git.GrapeGitError as e: if "remote ref does not exist" in e.gitOutput: pass
def parseSubprojectType(config, args): projectType = config.get("workspace", "subprojectType").strip().lower() if args["--subtree"]: projectType = "subtree" if args["--submodule"]: projectType = "submodule" if args["--nested"]: projectType = "nested" # can happen with invalid type in .grapeconfig and no type specified at command line if projectType != "subtree" and projectType != "submodule" and projectType != "nested": utility.printMsg("Invalid subprojectType specified in .grapeconfig section [workspace].") return projectType
def push(args, throwOnFail=False): try: return gitcmd("push --porcelain %s" % args, "Push failed") except GrapeGitError as e: if e.commError: utility.printMsg( "WARNING: Push failed due to connectivity issues.") if throwOnFail: raise e else: return e.gitOutput else: raise e
def execute(self, file): try: cmd = "difftool --find-renames --find-copies %s -y %s %s -- " % ( self.difftoolarg, self.diffargs, self.diffBranchSpec(self.diffbranchA, self.diffbranchB)) if isinstance(file, list): cmd += "\"%s\" \"%s\"" % (file[0], file[1]) else: cmd += "\"%s\"" % file difftooloutput = git.gitcmd(cmd, "Failed to launch difftool") except git.GrapeGitError as e: utility.printMsg("%s (return code %d)\n%s" % (e.msg, e.returnCode, e.gitOutput))
def ensurePublicBranchesExist(config,repo, publicBranches): cwd = os.getcwd() os.chdir(repo) allBranches = git.allBranches() missingBranches = [] for branch in publicBranches: if ("remotes/origin/%s" % branch) not in allBranches: missingBranches.append(branch) if ("remotes/origin/%s" % branch in allBranches) and (branch not in allBranches): utility.printMsg("Public branch %s does not have local version in %s. Creating it now." % (branch, repo)) git.branch("%s origin/%s" % (branch, branch)) if len(missingBranches) > 0: utility.printMsg("WARNING: the following public branches do not appear to exist on the remote origin of %s:\n%s" % (repo, " ".join(missingBranches))) os.chdir(cwd)
def parseSubprojectType(config, args): projectType = config.get("workspace", "subprojectType").strip().lower() if args["--subtree"]: projectType = "subtree" if args["--submodule"]: projectType = "submodule" if args["--nested"]: projectType = "nested" # can happen with invalid type in .grapeconfig and no type specified at command line if projectType != "subtree" and projectType != "submodule" and projectType != "nested": utility.printMsg( "Invalid subprojectType specified in .grapeconfig section [workspace]." ) return projectType
def outerLevelMerge(self, args, branch): utility.printMsg("Merging changes from %s into your current branch..." % branch) conflict = not self.mergeIntoCurrent(branch, args, "outer level project") if conflict: conflictedFiles = git.conflictedFiles() if conflictedFiles: return conflictedFiles else: utility.printMsg("Merge issued error, but no conflicts. Aborting...") return False else: self.progress["outerLevelDone"] = True return []
def handledCheckout(repo='', branch='master', args=[]): checkoutargs = args[0] sync = args[1] with utility.cd(repo): if sync: # attempt to fetch the requested branch try: git.fetch("origin", "%s:%s" % (branch, branch)) except: # the branch may not exist, but ignore the exception # and allow the checkout to throw the exception. pass git.checkout(checkoutargs + ' ' + branch) utility.printMsg("Checked out %s in %s" % (branch, repo)) return True
def handledCheckout(repo = '', branch = 'master', args = []): checkoutargs = args[0] sync = args[1] with utility.cd(repo): if sync: # attempt to fetch the requested branch try: git.fetch("origin", "%s:%s" % (branch, branch)) except: # the branch may not exist, but ignore the exception # and allow the checkout to throw the exception. pass git.checkout(checkoutargs + ' ' + branch) utility.printMsg("Checked out %s in %s" % (branch, repo)) return True
def fetch(repo="", branchArg="", raiseOnCommError=False, warnOnCommError=False): try: return gitcmd("fetch %s %s" % (repo, branchArg), "Fetch failed") except GrapeGitError as e: if e.commError: if warnOnCommError: utility.printMsg( "WARNING: could not fetch due to communication error.") if raiseOnCommError: raise e else: return e.gitOutput else: raise e
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 handleEnsureLocalUpToDateMRE(mre): _pushBranch = False _skipPush = False cleanupPushArgs = [] for e1, repo, branch in zip(mre.exceptions(), mre.repos(), mre.branches()): try: raise e1 except git.GrapeGitError as e: if ("[rejected]" in e.gitOutput and "(non-fast-forward)" in e.gitOutput ) or "Couldn't find remote ref" in e.gitOutput: if "Couldn't find remote ref" in e.gitOutput: if not _pushBranch: utility.printMsg( "No remote reference to %s in %s's origin. You may want to push this branch." % (branch, repo)) else: utility.printMsg( "Fetch of %s rejected as non-fast-forward in repo %s" % (branch, repo)) pushBranch = _pushBranch if _skipPush: pushBranch = False elif not pushBranch: pushBranch = utility.userInput( "Would you like to push your local branch? \n" "(select 'a' to say yes for (a)ll subprojects, 's' to (s)kip push for all subprojects)" "\n(y,n,a,s)", 'y') if str(pushBranch).lower()[0] == 'a': _pushBranch = True pushBranch = True if str(pushBranch).lower()[0] == 's': _skipPush = True pushBranch = False if pushBranch: cleanupPushArgs.append((repo, branch, None)) else: utility.printMsg("Skipping push of local %s in %s" % (branch, repo)) elif e.commError: utility.printMsg( "Could not update %s from origin due to a connectivity issue. Checking out most recent\n" "local version. " % branch) else: raise (e) # do another MRC launch to do any follow up pushes that were requested. utility.MultiRepoCommandLauncher( cleanupPush, listOfRepoBranchArgTuples=cleanupPushArgs).launchFromWorkspaceDir( handleMRE=handleCleanupPushMRE) return
def outerLevelMerge(self, args, branch): utility.printMsg( "Merging changes from %s into your current branch..." % branch) conflict = not self.mergeIntoCurrent(branch, args, "outer level project") if conflict: conflictedFiles = git.conflictedFiles() if conflictedFiles: return conflictedFiles else: utility.printMsg( "Merge issued error, but no conflicts. Aborting...") return False else: self.progress["outerLevelDone"] = True return []
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 fetchLocal(repo='unknown', branch='master'): # branch is actually the list of branches branches = branch with utility.cd(repo): currentBranch = git.currentBranch() if len(branches) > 0: git.fetch("--prune --tags") allRemoteBranches = git.remoteBranches() fetchArgs = "origin " toFetch = [] for b in branches: if b != currentBranch: if "origin/%s" % b in allRemoteBranches: fetchArgs += "%s:%s " % (b, b) toFetch.append(b) else: try: utility.printMsg("Pulling current branch %s in %s" % (currentBranch, repo)) git.pull("origin %s" % currentBranch) except git.GrapeGitError: print( "GRAPE: Could not pull %s from origin. Maybe you haven't pushed it yet?" % currentBranch) try: if toFetch: utility.printMsg("updating %s in %s" % (','.join(toFetch), repo)) git.fetch(fetchArgs) except git.GrapeGitError as e: # let non-fast-forward fetches slide if "rejected" in e.gitOutput and "non-fast-forward" in e.gitOutput: print e.gitCommand print e.gitOutput print( "GRAPE: WARNING: one of your public branches %s in %s has local commits! " "Did you forget to create a topic branch?" % (",".join(branches), repo)) pass elif "Refusing to fetch into current branch" in e.gitOutput: print e.gitOutput else: raise e
def ensurePublicBranchesExist(config, repo, publicBranches): cwd = os.getcwd() os.chdir(repo) allBranches = git.allBranches() missingBranches = [] for branch in publicBranches: if ("remotes/origin/%s" % branch) not in allBranches: missingBranches.append(branch) if ("remotes/origin/%s" % branch in allBranches) and (branch not in allBranches): utility.printMsg( "Public branch %s does not have local version in %s. Creating it now." % (branch, repo)) git.branch("%s origin/%s" % (branch, branch)) if len(missingBranches) > 0: utility.printMsg( "WARNING: the following public branches do not appear to exist on the remote origin of %s:\n%s" % (repo, " ".join(missingBranches))) os.chdir(cwd)
def checkForLocalPublicBranches(self, args): publicBranchesExist = True # Check that all public branches exist locally. cfg = config.grapeConfig.grapeConfig() publicBranches = cfg.getPublicBranchList() missingBranches = config.Config.checkIfPublicBranchesExist( cfg, utility.workspaceDir(), publicBranches) if (len(missingBranches) > 0): for mb in missingBranches: utility.printMsg( "Repository is missing public branch %s, attempting to fetch it now..." % mb) try: git.fetch("origin %s:%s" % (mb, mb)) utility.printMsg("%s added as a local branch" % mb) except git.GrapeGitError as e: print e.gitOutput publicBranchesExist = False return publicBranchesExist
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): commitargs = "" if args['-a']: commitargs = commitargs + " -a" elif args["<filetree>"]: commitargs = commitargs + " %s" % args["<filetree>"] if not args['-m']: args["-m"] = utility.userInput("Please enter commit message:") commitargs += " -m \"%s\"" % args["-m"] wsDir = utility.workspaceDir() os.chdir(wsDir) submodules = [(True, x) for x in git.getModifiedSubmodules()] subprojects = [(False, x) for x in grapeConfig.GrapeConfigParser. getAllActiveNestedSubprojectPrefixes()] for stage, sub in submodules + subprojects: os.chdir(os.path.join(wsDir, sub)) subStatus = git.status("--porcelain -uno") if subStatus: utility.printMsg("Committing in %s..." % sub) if self.commit(commitargs, sub) and stage: os.chdir(wsDir) utility.printMsg("Staging committed change in %s..." % sub) git.add(sub) os.chdir(wsDir) if submodules or git.status("--porcelain"): utility.printMsg("Performing commit in outer level project...") self.commit(commitargs, wsDir) return True
def execute(self, args): commitargs = "" if args['-a']: commitargs = commitargs + " -a" elif args["<filetree>"]: commitargs = commitargs + " %s"% args["<filetree>"] if not args['-m']: args["-m"] = utility.userInput("Please enter commit message:") commitargs += " -m \"%s\"" % args["-m"] wsDir = utility.workspaceDir() os.chdir(wsDir) submodules = [(True, x ) for x in git.getModifiedSubmodules()] subprojects = [(False, x) for x in grapeConfig.GrapeConfigParser.getAllActiveNestedSubprojectPrefixes()] for stage,sub in submodules + subprojects: os.chdir(os.path.join(wsDir,sub)) subStatus = git.status("--porcelain -uno") if subStatus: utility.printMsg("Committing in %s..." % sub) if self.commit(commitargs, sub) and stage: os.chdir(wsDir) utility.printMsg("Staging committed change in %s..." % sub) git.add(sub) os.chdir(wsDir) if submodules or git.status("--porcelain"): utility.printMsg("Performing commit in outer level project...") self.commit(commitargs, wsDir) return True
def merge(self, branch, strategy, args): squashArg = "--squash" if args["--squash"] else "" try: git.merge("%s %s %s" % (squashArg, branch, strategy)) return True except git.GrapeGitError as error: print error.gitOutput if "conflict" in error.gitOutput.lower(): if args['--at'] or args['--ay']: if args['--at']: utility.printMsg("Resolving conflicted files by accepting changes from %s." % branch) checkoutArg = "--theirs" else: utility.printMsg("Resolving conflicted files by accepting changes from your branch.") checkoutArg = "--ours" try: path = git.baseDir() git.checkout("%s %s" % (checkoutArg, path)) git.add("%s" % path) git.commit("-m 'Resolve conflicts using %s'" % checkoutArg) return True except git.GrapeGitError as resolveError: print resolveError.gitOutput return False else: utility.printMsg("Conflicts generated. Resolve using git mergetool, then continue " "with grape %s --continue. " % args["<<cmd>>"]) return False else: print("Merge command %s failed. Quitting." % error.gitCommand) return False
def handleCleanupPushMRE(mre): for e, repo, branch in zip(mre.exceptions(), mre.repos(), mre.branches()): try: raise e except git.GrapeGitError as e2: utility.printMsg("Local and remote versions of %s may have diverged in %s" % (branch, repo)) utility.printMsg("%s" % e2.gitOutput) utility.printMsg("Use grape pull to merge the remote version into the local version.")
def fetchLocal(repo='unknown', branch='master'): # branch is actually the list of branches branches = branch with utility.cd(repo): currentBranch = git.currentBranch() if len(branches) > 0: git.fetch("--prune --tags") allRemoteBranches = git.remoteBranches() fetchArgs = "origin " toFetch = [] for b in branches: if b != currentBranch: if "origin/%s" % b in allRemoteBranches: fetchArgs += "%s:%s " % (b, b) toFetch.append(b) else: try: utility.printMsg("Pulling current branch %s in %s" % (currentBranch, repo)) git.pull("origin %s" % currentBranch) except git.GrapeGitError: print("GRAPE: Could not pull %s from origin. Maybe you haven't pushed it yet?" % currentBranch) try: if toFetch: utility.printMsg("updating %s in %s" % (','.join(toFetch), repo)) git.fetch(fetchArgs) except git.GrapeGitError as e: # let non-fast-forward fetches slide if "rejected" in e.gitOutput and "non-fast-forward" in e.gitOutput: print e.gitCommand print e.gitOutput print("GRAPE: WARNING: one of your public branches %s in %s has local commits! " "Did you forget to create a topic branch?" % (",".join(branches), repo)) pass elif "Refusing to fetch into current branch" in e.gitOutput: print e.gitOutput else: raise e
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 handleEnsureLocalUpToDateMRE(mre): _pushBranch = False _skipPush = False cleanupPushArgs = [] for e1, repo, branch in zip(mre.exceptions(), mre.repos(), mre.branches()): try: raise e1 except git.GrapeGitError as e: if ("[rejected]" in e.gitOutput and "(non-fast-forward)" in e.gitOutput) or "Couldn't find remote ref" in e.gitOutput: if "Couldn't find remote ref" in e.gitOutput: if not _pushBranch: utility.printMsg("No remote reference to %s in %s's origin. You may want to push this branch." % (branch, repo)) else: utility.printMsg("Fetch of %s rejected as non-fast-forward in repo %s" % (branch, repo)) pushBranch = _pushBranch if _skipPush: pushBranch = False elif not pushBranch: pushBranch = utility.userInput("Would you like to push your local branch? \n" "(select 'a' to say yes for (a)ll subprojects, 's' to (s)kip push for all subprojects)" "\n(y,n,a,s)", 'y') if str(pushBranch).lower()[0] == 'a': _pushBranch = True pushBranch = True if str(pushBranch).lower()[0] == 's': _skipPush = True pushBranch = False if pushBranch: cleanupPushArgs.append((repo, branch, None)) else: utility.printMsg("Skipping push of local %s in %s" % (branch, repo)) elif e.commError: utility.printMsg("Could not update %s from origin due to a connectivity issue. Checking out most recent\n" "local version. " % branch) else: raise(e) # do another MRC launch to do any follow up pushes that were requested. utility.MultiRepoCommandLauncher(cleanupPush, listOfRepoBranchArgTuples=cleanupPushArgs).launchFromWorkspaceDir(handleMRE=handleCleanupPushMRE) return
def mergeSubproject(self, args, subproject, subPublic, subprojects, cwd, isSubmodule=True): # if we did this merge in a previous run, don't do it again try: if self.progress["Subproject: %s" % subproject] == "finished": return True except KeyError: pass os.chdir(os.path.join(git.baseDir(), subproject)) mergeArgs = args.copy() mergeArgs["--public"] = subPublic utility.printMsg("Merging %s into %s for %s %s" % (subPublic, git.currentBranch(), "submodule" if isSubmodule else "subproject", subproject)) git.fetch("origin") # update our local reference to the remote branch so long as it's fast-forwardable or we don't have it yet..) hasRemote = git.hasBranch("origin/%s" % subPublic) hasBranch = git.hasBranch(subPublic) if hasRemote and (git.branchUpToDateWith(subPublic, "origin/%s" % subPublic) or not hasBranch): git.fetch("origin %s:%s" % (subPublic, subPublic)) ret = self.mergeIntoCurrent(subPublic, mergeArgs, subproject) conflict = not ret if conflict: self.progress["stopPoint"] = "Subproject: %s" % subproject subprojectKey = "submodules" if isSubmodule else "nested" self.progress[subprojectKey] = subprojects self.progress["cwd"] = cwd conflictedFiles = git.conflictedFiles() if conflictedFiles: if isSubmodule: typeStr = "submodule" else: typeStr = "nested subproject" utility.printMsg("Merge in %s %s from %s to %s issued conflicts. Resolve and commit those changes \n" "using git mergetool and git commit in the submodule, then continue using grape\n" "%s --continue" % (typeStr, subproject, subPublic, git.currentBranch(), args["<<cmd>>"])) else: utility.printMsg("Merge in %s failed for an unhandled reason. You may need to stash / commit your current\n" "changes before doing the merge. Inspect git output above to troubleshoot. Continue using\n" "grape %s --continue." % (subproject, args["<<cmd>>"])) return False # if we are resuming from a conflict, the above grape m call would have taken care of continuing. # clear out the --continue flag. args["--continue"] = False # stage the updated submodule os.chdir(cwd) if isSubmodule: git.add(subproject) self.progress["Subproject: %s" % subproject] = "finished" return True
def execute(self,args): if not "<<cmd>>" in args: args["<<cmd>>"] = "mr" otherBranch = args['<branch>'] if not otherBranch: # list remote branches that are available print git.branch('-r') otherBranch = utility.userInput("Enter name of branch you would like to merge into this branch (without the origin/ prefix)") # make sure remote references are up to date utility.printMsg("Fetching remote references in all projects...") try: utility.MultiRepoCommandLauncher(fetchHelper).launchFromWorkspaceDir() except utility.MultiRepoException as mre: commError = False commErrorRepos = [] for e, r in zip(mre.exceptions(), mre.repos()): if e.commError: commErrorRepos.append(r) commError = True if commError: utility.printMsg("ERROR: can't communicate with remotes for %s. Halting remote merge." % commErrorRepos) return False # update our local reference to the remote branch so long as it's fast-forwardable or we don't have it yet..) hasRemote = ("origin/%s" % otherBranch) in git.remoteBranches() hasBranch = git.hasBranch(otherBranch) currentBranch = git.currentBranch() remoteUpToDateWithLocal = git.branchUpToDateWith("remotes/origin/%s" % otherBranch, otherBranch) updateLocal = hasRemote and (remoteUpToDateWithLocal or not hasBranch) and currentBranch != otherBranch if updateLocal: utility.printMsg("updating local branch %s from %s" % (otherBranch, "origin/%s" % otherBranch)) utility.MultiRepoCommandLauncher(updateBranchHelper, branch=otherBranch).launchFromWorkspaceDir(handleMRE=updateBranchHandleMRE) args["<branch>"] = otherBranch if updateLocal else "origin/%s" % otherBranch # we've handled the update, we don't want m or md to update the local branch. args["--noUpdate"] = True # if mr is called by the user, need to initialize the --continue argument. # if it is called by md, it will be set already. if not "--continue" in args: args["--continue"] = False return grapeMenu.menu().getOption('m').execute(args)
def createBranch(repo="unknown", branch="master", args=[]): branchPoint = branch fullBranch = args with utility.cd(repo): utility.printMsg("creating and switching to %s in %s" % (fullBranch, repo)) try: git.checkout("-b %s %s " % (fullBranch, branchPoint)) except git.GrapeGitError as e: print "%s:%s" % (repo, e.gitOutput) utility.printMsg("WARNING: %s in %s will not be pushed." % (fullBranch, repo)) return utility.printMsg("pushing %s to origin in %s" % (fullBranch, repo)) try: git.push("-u origin %s" % fullBranch) except git.GrapeGitError as e: print "%s: %s" % (repo, e.gitOutput) return
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")