def read(additionalFileNames=None): # initialize a ConfigParser with all defaults needed by the grapeMenu if additionalFileNames is None: additionalFileNames = [] defaultFiles = [] if os.name == "nt": defaultFiles.append( os.path.join(os.environ["USERPROFILE"], ".grapeconfig")) else: defaultFiles.append(os.path.join(os.environ["HOME"], ".grapeconfig")) globalconfigfile = defaultFiles[0] try: defaultFiles.append( os.path.join( utility.workspaceDir(warnIfNotFound=False, throwIfNotFound=False), ".grapeconfig")) except: pass try: defaultFiles.append( os.path.join( utility.workspaceDir(warnIfNotFound=False, throwIfNotFound=False), ".git", ".grapeuserconfig")) except: pass files = defaultFiles + additionalFileNames readFiles = grapeConfig().read(files) if len(readFiles) == 0: utility.writeDefaultConfig(globalconfigfile)
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 readWorkspaceUserConfigFile(self): try: self.read( os.path.join(utility.workspaceDir(), ".git", ".grapeuserconfig")) except IOError: pass
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 _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): 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 _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): 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 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 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 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 getAllActiveNestedSubprojectPrefixes(workspaceDir=None): config = grapeConfig() if (workspaceDir is None or workspaceDir is utility.workspaceDir() ) else GrapeConfigParser(workspaceDir) return [ config.get("nested-%s" % name, "prefix") for name in GrapeConfigParser.getAllActiveNestedSubprojects(workspaceDir) ]
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 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 getActiveSubmodules(): cwd = os.getcwd() wsDir = utility.workspaceDir() os.chdir(wsDir) if os.name == "nt": submoduleList = submodule("foreach --quiet \"echo $path\"") else: submoduleList = submodule("foreach --quiet \"echo \$path\"") submoduleList = [] if not submoduleList else submoduleList.split('\n') submoduleList = [x.strip() for x in submoduleList] os.chdir(cwd) return submoduleList
def read(additionalFileNames=None): # initialize a ConfigParser with all defaults needed by the grapeMenu if additionalFileNames is None: additionalFileNames = [] defaultFiles = [] if os.name == "nt": defaultFiles.append(os.path.join(os.environ["USERPROFILE"], ".grapeconfig")) else: defaultFiles.append(os.path.join(os.environ["HOME"], ".grapeconfig")) globalconfigfile = defaultFiles[0] try: defaultFiles.append(os.path.join(utility.workspaceDir(warnIfNotFound=False, throwIfNotFound=False), ".grapeconfig")) except: pass try: defaultFiles.append(os.path.join(utility.workspaceDir(warnIfNotFound=False, throwIfNotFound=False), ".git", ".grapeuserconfig")) except: pass files = defaultFiles + additionalFileNames readFiles = grapeConfig().read(files) if len(readFiles) == 0: utility.writeDefaultConfig(globalconfigfile)
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 getAllModifiedNestedSubprojects(since, now="HEAD", workspaceDir=None): config = grapeConfig() if workspaceDir is None else GrapeConfigParser(workspaceDir) publicBranches = config.getPublicBranchList() if workspaceDir is None: workspaceDir = utility.workspaceDir() active = GrapeConfigParser.getAllActiveNestedSubprojects(workspaceDir) modified = [] cwd = os.getcwd() for repo in active: prefix = config.get("nested-%s" % repo, "prefix") os.chdir(os.path.join(workspaceDir,prefix)) configOption.Config.ensurePublicBranchesExist(config,os.path.join(workspaceDir,prefix), publicBranches) if git.log("--oneline %s..%s" % (since, now)): modified.append(repo) os.chdir(cwd) return modified
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 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 getAllModifiedNestedSubprojects(since, now="HEAD", workspaceDir=None): config = grapeConfig() if workspaceDir is None else GrapeConfigParser( workspaceDir) publicBranches = config.getPublicBranchList() if workspaceDir is None: workspaceDir = utility.workspaceDir() active = GrapeConfigParser.getAllActiveNestedSubprojects(workspaceDir) modified = [] cwd = os.getcwd() for repo in active: prefix = config.get("nested-%s" % repo, "prefix") os.chdir(os.path.join(workspaceDir, prefix)) configOption.Config.ensurePublicBranchesExist( config, os.path.join(workspaceDir, prefix), publicBranches) if git.log("--oneline %s..%s" % (since, now)): modified.append(repo) os.chdir(cwd) return modified
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 checkForConsistentWorkspaceBranches(self, args): consistentBranchState = True cfg = config.grapeConfig.grapeConfig() publicBranches = cfg.getPublicBranchList() wsDir = utility.workspaceDir() os.chdir(wsDir) wsBranch = git.currentBranch() subPubMap = cfg.getMapping("workspace", "submodulepublicmappings") if wsBranch in publicBranches: for sub in git.getActiveSubmodules(): os.chdir(os.path.join(wsDir, sub)) subbranch = git.currentBranch() if subbranch != subPubMap[wsBranch]: consistentBranchState = False utility.printMsg( "Submodule %s on branch %s when grape expects it to be on %s" % (sub, subbranch, subPubMap[wsBranch])) else: for sub in git.getActiveSubmodules(): os.chdir(os.path.join(wsDir, sub)) subbranch = git.currentBranch() if subbranch != wsBranch: consistentBranchState = False utility.printMsg( "Submodule %s on branch %s when grape expects it to be on %s" % (sub, subbranch, wsBranch)) # check that nested subproject branching is consistent for nested in config.grapeConfig.GrapeConfigParser.getAllActiveNestedSubprojectPrefixes( ): os.chdir(os.path.join(wsDir, nested)) nestedbranch = git.currentBranch() if nestedbranch != wsBranch: consistentBranchState = False utility.printMsg( "Nested Project %s on branch %s when grape expects it to be on %s" % (nested, nestedbranch, wsBranch)) return consistentBranchState
def execute(self, args): with utility.cd(utility.workspaceDir()): if not args["--checkWSOnly"]: self.printStatus(args) # Sanity check workspace layout publicBranchesExist = self.checkForLocalPublicBranches(args) # Check that submodule branching is consistent consistentBranchState = self.checkForConsistentWorkspaceBranches( args) retval = True if args["--failIfInconsistent"]: retval = retval and publicBranchesExist and consistentBranchState if args["--failIfMissingPublicBranches"]: retval = retval and publicBranchesExist if args["--failIfBranchesInconsistent"]: retval = retval and consistentBranchState return retval
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 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): 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): 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 initFiles(self, index): self.filelist.delete(0,Tk.END) dir = self.projects[index] type = self.projtype[index] self.diffbranchA = self.branchA self.diffbranchB = self.branchB if type.endswith("Submodule"): self.diffbranchA = self.getSubBranch(self.branchA) self.diffbranchB = self.getSubBranch(self.branchB) if type.startswith("Inactive"): remotels = git.gitcmd("ls-remote") self.filelist.insert(Tk.END, "<Unable to diff>") self.filenames.append("") else: # TODO handle non-existent branches on subprojects os.chdir(os.path.join(utility.workspaceDir(), dir)) self.diffbranchA = self.getBranch(self.diffbranchA) self.diffbranchB = self.getBranch(self.diffbranchB) self.filenames = [] diffoutput = git.diff("--name-status --find-renames --find-copies %s %s ." % (self.diffargs, self.diffBranchSpec(self.diffbranchA, self.diffbranchB))).splitlines() statusdict = { "A":"<Only in B>", "C":"<File copied>", "D":"<Only in A>", "M":"", "R":"<File renamed>", "T":"<File type changed>", "U":"<File unmerged>", "X":"<Unknown status>" } if len(diffoutput) > 0: for line in diffoutput: [status, file] = line.split(None, 1) statusstring = statusdict[status[0]] if status[0] == 'R' or status[0] == 'C': files = file.split(None,1) if status[1:] == '100': filename = "" else: statusstring += "*" filename = files filedisplay = " -> ".join(files) else: filedisplay = file filename = file if type == "Outer": if filename in self.submodules: continue inSubtree = False for subtree in self.subtrees: if filename.startswith(subtree+os.path.sep): inSubtree = True break if inSubtree: continue self.filelist.insert(Tk.END, "%s %s" % (filedisplay, statusstring)) self.filenames.append(filename) if len(self.filelist) == 0: self.filelist.insert(Tk.END, "<No differences>") self.filenames.append("") if self.branchA == "--cached": self.diffAnnotationA.set("%s <cached>" % self.diffbranchB) self.diffAnnotationB.set("<staged>") elif self.branchB == "--": self.diffAnnotationA.set(self.diffbranchA) self.diffAnnotationB.set("<workspace>") else: self.diffAnnotationA.set(self.diffbranchA) self.diffAnnotationB.set(self.diffbranchB)
def __init__(self, master, **kwargs): validDiffTools = [ 'kdiff3', 'kompare', 'tkdiff', 'meld', 'xxdiff', 'emerge', 'gvimdiff', 'ecmerge', 'diffuse', 'opendiff', 'p4merge', 'araxis' ] # Configurable parameters difftool = kwargs.get('difftool', None) if difftool == None: try: difftool = git.config("--get diff.tool") except: pass if difftool == "vimdiff": utility.printMsg("Using gvimdiff instead of vimdiff.") difftool = "gvimdiff" if difftool not in validDiffTools: utility.printMsg("Using default difftool.") self.difftool = "default difftool" self.difftoolarg = "" else: self.difftool = difftool self.difftoolarg = "-t %s" % difftool self.diffargs = kwargs.get('diffargs', "") self.noFetch = kwargs.get('noFetch', False) self.branchA = self.getBranch(kwargs.get('branchA', "")) self.branchB = self.getBranch(kwargs.get('branchB', "")) self.diffbranchA = "" self.diffAnnotationA = Tk.StringVar() self.diffAnnotationA.set(self.branchA) self.diffbranchB = "" self.diffAnnotationB = Tk.StringVar() self.diffAnnotationB.set(self.branchB) self.showUnchanged = kwargs.get('showUnchanged', False) self.doMergeDiff = kwargs.get('doMergeDiff', True) # Branch specification pane self.branchpane = Tk.Frame(master) self.branchlabelA= Tk.Label(self.branchpane, text="Branch A:") self.branchnameA= Tk.Label(self.branchpane, textvariable=self.diffAnnotationA) self.branchlabelB= Tk.Label(self.branchpane, text="Branch B:") self.branchnameB= Tk.Label(self.branchpane, textvariable=self.diffAnnotationB) self.branchlabelA.pack(side=Tk.LEFT, fill=Tk.Y) self.branchnameA.pack(side=Tk.LEFT, fill=Tk.Y) self.branchlabelB.pack(side=Tk.LEFT, fill=Tk.Y) self.branchnameB.pack(side=Tk.LEFT, fill=Tk.Y) self.branchpane.pack(side=Tk.TOP) ProjectManager.__init__(self, master, **kwargs) # If we are diffing against the workspace, get the status of the workspace # and save the set of changed files in the outer project (including submodules). changedFiles = None if self.showToplevel or len(self.submodules) > 0: utility.printMsg("Gathering status in outer level project...") changedFiles = git.diff("--name-only %s" % self.diffBranchSpec(self.branchA, self.branchB)).split() utility.printMsg("Done.") # Get the url mapping for all submodules if len(self.submodules) > 0: submoduleURLMap = git.getAllSubmoduleURLMap() utility.printMsg("Examining projects...") os.chdir(utility.workspaceDir()) # Loop over list backwards so we can delete entries for index in reversed(range(self.numprojects)): dir = self.projects[index] type = self.projtype[index] haveDiff = False if type == "Outer": # Outer is always last in the reverse iteration, # so all submodule entries should have already been removed. haveDiff = len(changedFiles) > 0 elif type.endswith("Submodule"): if not type.startswith("Inactive") or self.showInactive: if dir in changedFiles: haveDiff = True changedFiles.remove(dir) elif type.endswith("Nested"): if type.startswith("Inactive"): # It might not be worth the time to check for differences in inactive subprojects #TODO pass else: os.chdir(os.path.join(utility.workspaceDir(), dir)) utility.printMsg("Gathering status in %s..." % dir) try: haveDiff = len(git.diff("--name-only %s" % self.diffBranchSpec(self.branchA, self.branchB)).split()) > 0 except git.GrapeGitError as e: if "unknown revision or path not in the working tree" in e.gitOutput: utility.printMsg("Could not diff %s. Branch may not exist in %s." % (self.diffBranchSpec(self.branchA, self.branchB), dir)) else: raise haveDiff = False utility.printMsg("Done.") os.chdir(utility.workspaceDir()) pass elif type.endswith("Subtree"): nestedFiles = git.diff("--name-only %s %s" % (self.diffBranchSpec(self.branchA, self.branchB), dir)).split() if len(nestedFiles) > 0: haveDiff = True for changedFile in changedFiles: if changedFile.startswith(dir+os.path.sep): changedFiles.remove(changedFile) if haveDiff: self.setProjectStatus(index, "*") elif self.showUnchanged: self.setProjectStatus(index, " ") else: self.removeProjectEntry(index) utility.printMsg("Done.") self.filepanelabel.set("Double click to launch %s" % self.difftool) if len(self.projects) > 0: self.projpanelabel.set("Double click to choose a project") else: self.projpanelabel.set("No differences")
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): 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 readWorkspaceGrapeConfigFile(self): self.read(os.path.join(utility.workspaceDir(), ".grapeconfig"))
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 readWorkspaceUserConfigFile(self): try: self.read(os.path.join(utility.workspaceDir(), ".git", ".grapeuserconfig")) except IOError: pass
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 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): 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 getAllActiveNestedSubprojectPrefixes(workspaceDir = None): config = grapeConfig() if (workspaceDir is None or workspaceDir is utility.workspaceDir()) else GrapeConfigParser(workspaceDir) return [config.get("nested-%s" % name, "prefix") for name in GrapeConfigParser.getAllActiveNestedSubprojects(workspaceDir)]
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 initFiles(self, index): self.filelist.delete(0, Tk.END) dir = self.projects[index] type = self.projtype[index] self.diffbranchA = self.branchA self.diffbranchB = self.branchB if type.endswith("Submodule"): self.diffbranchA = self.getSubBranch(self.branchA) self.diffbranchB = self.getSubBranch(self.branchB) if type.startswith("Inactive"): remotels = git.gitcmd("ls-remote") self.filelist.insert(Tk.END, "<Unable to diff>") self.filenames.append("") else: # TODO handle non-existent branches on subprojects os.chdir(os.path.join(utility.workspaceDir(), dir)) self.diffbranchA = self.getBranch(self.diffbranchA) self.diffbranchB = self.getBranch(self.diffbranchB) self.filenames = [] diffoutput = git.diff( "--name-status --find-renames --find-copies %s %s ." % (self.diffargs, self.diffBranchSpec(self.diffbranchA, self.diffbranchB))).splitlines() statusdict = { "A": "<Only in B>", "C": "<File copied>", "D": "<Only in A>", "M": "", "R": "<File renamed>", "T": "<File type changed>", "U": "<File unmerged>", "X": "<Unknown status>" } if len(diffoutput) > 0: for line in diffoutput: [status, file] = line.split(None, 1) statusstring = statusdict[status[0]] if status[0] == 'R' or status[0] == 'C': files = file.split(None, 1) if status[1:] == '100': filename = "" else: statusstring += "*" filename = files filedisplay = " -> ".join(files) else: filedisplay = file filename = file if type == "Outer": if filename in self.submodules: continue inSubtree = False for subtree in self.subtrees: if filename.startswith(subtree + os.path.sep): inSubtree = True break if inSubtree: continue self.filelist.insert(Tk.END, "%s %s" % (filedisplay, statusstring)) self.filenames.append(filename) if len(self.filelist) == 0: self.filelist.insert(Tk.END, "<No differences>") self.filenames.append("") if self.branchA == "--cached": self.diffAnnotationA.set("%s <cached>" % self.diffbranchB) self.diffAnnotationB.set("<staged>") elif self.branchB == "--": self.diffAnnotationA.set(self.diffbranchA) self.diffAnnotationB.set("<workspace>") else: self.diffAnnotationA.set(self.diffbranchA) self.diffAnnotationB.set(self.diffbranchB)
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): 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 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 readWorkspaceGrapeConfigFile(self): self.read(os.path.join(utility.workspaceDir(), ".grapeconfig"))
def __init__(self, master, **kwargs): validDiffTools = [ 'kdiff3', 'kompare', 'tkdiff', 'meld', 'xxdiff', 'emerge', 'gvimdiff', 'ecmerge', 'diffuse', 'opendiff', 'p4merge', 'araxis' ] # Configurable parameters difftool = kwargs.get('difftool', None) if difftool == None: try: difftool = git.config("--get diff.tool") except: pass if difftool == "vimdiff": utility.printMsg("Using gvimdiff instead of vimdiff.") difftool = "gvimdiff" if difftool not in validDiffTools: utility.printMsg("Using default difftool.") self.difftool = "default difftool" self.difftoolarg = "" else: self.difftool = difftool self.difftoolarg = "-t %s" % difftool self.diffargs = kwargs.get('diffargs', "") self.noFetch = kwargs.get('noFetch', False) self.branchA = self.getBranch(kwargs.get('branchA', "")) self.branchB = self.getBranch(kwargs.get('branchB', "")) self.diffbranchA = "" self.diffAnnotationA = Tk.StringVar() self.diffAnnotationA.set(self.branchA) self.diffbranchB = "" self.diffAnnotationB = Tk.StringVar() self.diffAnnotationB.set(self.branchB) self.showUnchanged = kwargs.get('showUnchanged', False) self.doMergeDiff = kwargs.get('doMergeDiff', True) # Branch specification pane self.branchpane = Tk.Frame(master) self.branchlabelA = Tk.Label(self.branchpane, text="Branch A:") self.branchnameA = Tk.Label(self.branchpane, textvariable=self.diffAnnotationA) self.branchlabelB = Tk.Label(self.branchpane, text="Branch B:") self.branchnameB = Tk.Label(self.branchpane, textvariable=self.diffAnnotationB) self.branchlabelA.pack(side=Tk.LEFT, fill=Tk.Y) self.branchnameA.pack(side=Tk.LEFT, fill=Tk.Y) self.branchlabelB.pack(side=Tk.LEFT, fill=Tk.Y) self.branchnameB.pack(side=Tk.LEFT, fill=Tk.Y) self.branchpane.pack(side=Tk.TOP) ProjectManager.__init__(self, master, **kwargs) # If we are diffing against the workspace, get the status of the workspace # and save the set of changed files in the outer project (including submodules). changedFiles = None if self.showToplevel or len(self.submodules) > 0: utility.printMsg("Gathering status in outer level project...") changedFiles = git.diff( "--name-only %s" % self.diffBranchSpec(self.branchA, self.branchB)).split() utility.printMsg("Done.") # Get the url mapping for all submodules if len(self.submodules) > 0: submoduleURLMap = git.getAllSubmoduleURLMap() utility.printMsg("Examining projects...") os.chdir(utility.workspaceDir()) # Loop over list backwards so we can delete entries for index in reversed(range(self.numprojects)): dir = self.projects[index] type = self.projtype[index] haveDiff = False if type == "Outer": # Outer is always last in the reverse iteration, # so all submodule entries should have already been removed. haveDiff = len(changedFiles) > 0 elif type.endswith("Submodule"): if not type.startswith("Inactive") or self.showInactive: if dir in changedFiles: haveDiff = True changedFiles.remove(dir) elif type.endswith("Nested"): if type.startswith("Inactive"): # It might not be worth the time to check for differences in inactive subprojects #TODO pass else: os.chdir(os.path.join(utility.workspaceDir(), dir)) utility.printMsg("Gathering status in %s..." % dir) try: haveDiff = len( git.diff("--name-only %s" % self.diffBranchSpec( self.branchA, self.branchB)).split()) > 0 except git.GrapeGitError as e: if "unknown revision or path not in the working tree" in e.gitOutput: utility.printMsg( "Could not diff %s. Branch may not exist in %s." % (self.diffBranchSpec(self.branchA, self.branchB), dir)) else: raise haveDiff = False utility.printMsg("Done.") os.chdir(utility.workspaceDir()) pass elif type.endswith("Subtree"): nestedFiles = git.diff( "--name-only %s %s" % (self.diffBranchSpec( self.branchA, self.branchB), dir)).split() if len(nestedFiles) > 0: haveDiff = True for changedFile in changedFiles: if changedFile.startswith(dir + os.path.sep): changedFiles.remove(changedFile) if haveDiff: self.setProjectStatus(index, "*") elif self.showUnchanged: self.setProjectStatus(index, " ") else: self.removeProjectEntry(index) utility.printMsg("Done.") self.filepanelabel.set("Double click to launch %s" % self.difftool) if len(self.projects) > 0: self.projpanelabel.set("Double click to choose a project") else: self.projpanelabel.set("No differences")