def printStatus(self, args): wsDir = utility.workspaceDir() statusArgs = "" if args["-u"]: statusArgs += "-u " if args["--uno"]: statusArgs += "-uno " launcher = utility.MultiRepoCommandLauncher( getStatus, runInSubmodules=True, runInSubprojects=True, runInOuter=True, globalArgs=[statusArgs, wsDir]) stati = launcher.launchFromWorkspaceDir(noPause=True) status = {} for s, r in (zip(stati, launcher.repos)): status[r] = s for sub in status.keys(): for line in status[sub]: lstripped = line.strip() if lstripped: # filter out branch tracking status # ## bugfix/bugfixday/DLThreadSafety...remotes/origin/bugfix/bugfixday/DLThreadSafety [ahead 1] # ## bugfix/bugfixday/DLThreadSafety...remotes/origin/bugfix/bugfixday/DLThreadSafety [behind 29] if lstripped[0:2] == "##": if "[ahead" in lstripped or "[behind" in lstripped: print os.path.abspath(os.path.join( wsDir, sub)) + ': ' + lstripped continue # print other statuses print ' ' + lstripped
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 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 safeSwitchWorkspaceToBranch(branch, checkoutArgs, sync): # Ensure local branches that you are about to check out are up to date with the remote if sync: launcher = utility.MultiRepoCommandLauncher( ensureLocalUpToDateWithRemote, branch=branch, globalArgs=[checkoutArgs]) launcher.launchFromWorkspaceDir(handleMRE=handleEnsureLocalUpToDateMRE) # Do a checkout # Pass False instead of sync since if sync is True ensureLocalUpToDateWithRemote will have already performed the fetch launcher = utility.MultiRepoCommandLauncher( checkout.handledCheckout, branch=branch, globalArgs=[checkoutArgs, False]) launcher.launchFromWorkspaceDir(handleMRE=checkout.handleCheckoutMRE) return
def execute(self, args): if args["pop"]: launcher = utility.MultiRepoCommandLauncher(popHelper) elif args["list"]: launcher = utility.MultiRepoCommandLauncher(listHelper) else: launcher = utility.MultiRepoCommandLauncher(stashHelper) try: retvals = launcher.launchFromWorkspaceDir() for r in retvals: if r[1]: print "%s: %s" % (r[0], r[1]) except utility.MultiRepoException as mre: for e, r in zip(mre, mre.repos): print("%s:\n%s" % (r, e.gitOutput)) return True
def execute(self, args): cmd = args["<cmd>"] retvals = utility.MultiRepoCommandLauncher( foreach, runInOuter=not args["--noTopLevel"], skipSubmodules=args["--noSubmodules"], runInSubprojects=not args["--noSubprojects"], globalArgs=args).launchFromWorkspaceDir(handleMRE=handleForeachMRE) return 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 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 handleDeleteBranchMRE(mre, force=False): detachTuples = [] for e1, branch, repo in zip(mre.exceptions(), mre.branches(), mre.repos()): try: raise e1 except git.GrapeGitError as e: with utility.cd(repo): if "Cannot delete the branch" in e.gitOutput and \ "which you are currently on." in e.gitOutput: if force: detachTuples.append((repo, branch, None)) else: utility.printMsg( "call grape db -D %s to force deletion of branch you are currently on." % branch) elif "not deleting branch" in e.gitOutput and "even though it is merged to HEAD." in e.gitOutput: git.branch("-D %s" % branch) elif "error: branch" in e.gitOutput and "not found" in e.gitOutput: "%s not found in %s" % (branch, repo) pass elif "is not fully merged" in e.gitOutput: if force: utility.printMsg("**DELETING UNMERGED BRANCH %s" % branch) git.branch("-D %s" % branch) else: print "%s is not fully merged in %s. Run grape db -D %s to force the deletion" % ( branch, repo, branch) elif e.commError: utility.printMsg( "Could not connect to origin to delete remote references to your branch " "You may want to call grape db %s again once you've reconnected." % branch) else: utility.printMsg( "Deletion of %s failed for unhandled reason." % branch) print e.gitOutput raise e utility.MultiRepoCommandLauncher( detachThenForceDeleteBranch, listOfRepoBranchArgTuples=detachTuples).launchFromWorkspaceDir( handleMRE=handleDetachThenForceMRE)
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): branch = args["<branch>"] force = args["-D"] if not branch: branch = utility.userInput("Enter name of branch to delete") if args["--verify"]: proceed = utility.userInput( "Would you like to delete the branch %s" % branch, 'y') if not proceed: return True launcher = utility.MultiRepoCommandLauncher(deleteBranch, branch=branch, globalArgs=[force]) try: launcher.launchFromWorkspaceDir() except utility.MultiRepoException as e: handleDeleteBranchMRE(e, force) return True
def handleCheckoutMRE(mre): global _skipBranchCreation global _createNewBranch newBranchReposArgTuples = [] newBranches = [] for e1, branch, project, checkoutargs in zip(mre.exceptions(), mre.branches(), mre.repos(), mre.args()): try: raise e1 except git.GrapeGitError as e: with utility.cd(project): if "pathspec" in e.gitOutput: createNewBranch = _createNewBranch if _skipBranchCreation: utility.printMsg("Skipping checkout of %s in %s" % (branch, project)) createNewBranch = False elif not createNewBranch: createNewBranch = utility.userInput( "Branch not found locally or remotely. Would you like to create a " "new branch called %s in %s? \n" "(select 'a' to say yes for (a)ll, 's' to (s)kip creation for branches that don't exist )" "\n(y,n,a,s)" % (branch, project), 'y') if str(createNewBranch).lower()[0] == 'a': _createNewBranch = True createNewBranch = True if str(createNewBranch).lower()[0] == 's': _skipBranchCreation = True createNewBranch = False if createNewBranch: newBranchReposArgTuples.append((project, branch, { "checkout": checkoutargs[0] })) else: continue elif "already exists" in e.gitOutput: utility.printMsg("Branch %s already exists in %s." % (branch, project)) branchDescription = git.commitDescription(branch) headDescription = git.commitDescription("HEAD") if branchDescription == headDescription: utility.printMsg( "Branch %s and HEAD are the same. Switching to %s." % (branch, branch)) action = "k" else: utility.printMsg( "Branch %s and HEAD are not the same." % branch) action = '' valid = False while not valid: action = utility.userInput( "Would you like to \n (k)eep it as is at: %s \n" " or \n (f)orce it to: %s? \n(k,f)" % (branchDescription, headDescription), 'k') valid = (action == 'k') or (action == 'f') if not valid: utility.printMsg( "Invalid input. Enter k or f. ") if action == 'k': git.checkout(branch) elif action == 'f': git.checkout("-B %s" % branch) elif "conflict" in e.gitOutput.lower(): utility.printMsg( "CONFLICT occurred when pulling %s from origin." % branch) elif "does not appear to be a git repository" in e.gitOutput.lower( ): utility.printMsg( "Remote 'origin' does not exist. " "This branch was not updated from a remote repository." ) elif "Couldn't find remote ref" in e.gitOutput: utility.printMsg( "Remote of %s does not have reference to %s. You may want to push this branch. " % (project, branch)) else: raise e if len(newBranchReposArgTuples) > 0: utility.MultiRepoCommandLauncher( createNewBranches, listOfRepoBranchArgTuples=newBranchReposArgTuples ).launchFromWorkspaceDir(handleMRE=createNewBranchesMREHandler)
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