def PUSH(self, sRepoUrl): sChangeId = gerrit.getChangeId() if not sChangeId: raise FatalError("Unable to extract Change-Id") sProject = gerrit.getProjectName() oRepoData = self.getRepoData() sLocalCommit = git.getLastCommit() try: dChangeData = self.getApiClient().getChangeData( sChangeId, sProject, lAdditionalData=["CURRENT_REVISION"]) except requests.HTTPError as e: if e.response.status_code != 404: raise else: sRemoteCommit = dChangeData["current_revision"] sLastPushedCommit = oRepoData.getLastPushedCommit( sProject, sChangeId) if sRemoteCommit == sLocalCommit: warning("No new changes") return elif sRemoteCommit != sLastPushedCommit: warning("You are about to overwrite unknown changes.") sInput = input("Continue? (y/n): ") if sInput != "y": raise FatalError("Operation aborted") print("Pushing changes to %s" % sRepoUrl) gerrit.push() oRepoData.setLastPushedCommit(sProject, sChangeId, sLocalCommit) self.saveRepoData(oRepoData)
def DOWNLOAD(self, dRepos): bFound = False def download(sRepoUrl): nonlocal bFound sPatchRef = self.getPatchRef(sRepoUrl, self.oArgs.change) if sPatchRef: print("Downloading change %s from %s" % (self.oArgs.change, sRepoUrl)) gerrit.download(sPatchRef, bDetach=self.oArgs.detach) bFound = True else: sErrMsg = "Change %s not found within this project" % self.oArgs.change if self.oArgs.project: raise FatalError(sErrMsg) else: print("Skipped: %s" % sErrMsg) dFilteredRepos = { sRepoUrl: sDirPath for sRepoUrl, sDirPath in dRepos.items() if not self.oArgs.project or self.oArgs.project == urlparse( sRepoUrl, allow_fragments=True).path[1:] } if not dFilteredRepos: raise FatalError("No project \"%s\" found." % self.oArgs.project) lErrorRepos = self.runInRepos(dFilteredRepos, download) if not lErrorRepos and not bFound: raise FatalError("Change %s was not found in any project." % self.oArgs.change) return lErrorRepos
def readManifest(self, bKeepInvalid=False): if not os.path.isfile(self.oArgs.manifest): raise FatalError("The manifest file %s does not exist." % self.oArgs.manifest) dRepos = OrderedDict() try: with open(self.oArgs.manifest) as oFile: for sLine in oFile: sLine = sLine.strip() if sLine: lElements = sLine.split(" ") (sRepoUrl, sDirPath) = lElements[0], " ".join(lElements[1:]) if not sDirPath: sDirPath = unquote( urlparse( sRepoUrl, allow_fragments=True).path.split("/")[-1]) sDirPath = os.path.join(self.sRootFolder, sDirPath) if not bKeepInvalid and not os.path.isdir(sDirPath): warning("Directory %s does not exist, skipped." % sDirPath) else: dRepos[sRepoUrl] = sDirPath except OSError as e: raise FatalError(e) return dRepos
def runInRepos(self, dRepos, xFunction, bPrint=True, bCheckTopic=True): if bCheckTopic: lBranches = set() try: for sDirPath in dRepos.values(): if os.path.isdir(sDirPath): with changeWorkingDir(sDirPath): lBranches.add( strOrDefault(git.getCurrentBranch(), "(none)")) except (subprocess.CalledProcessError, OSError) as e: raise FatalError(e) if len(lBranches) > 1: warning("Topic is not consistent across your repositories. " "Found following topics: %s" % ", ".join(lBranches)) sInput = input("Do you wish to proceed anyway? (y/n): ") if sInput != "y": raise FatalError("Operation cancelled") lErrorRepos = [] for sRepoUrl, sDirPath in dRepos.items(): sRepoName = os.path.basename(sDirPath) try: os.makedirs(sDirPath, exist_ok=True) with changeWorkingDir(sDirPath): if bPrint: highlight("\n### %s ###" % os.path.basename(os.getcwd())) xFunction(sRepoUrl) if bPrint: success("Done") except (subprocess.CalledProcessError, FatalError, OSError) as e: error("[%s] %s" % (sRepoName, e)) lErrorRepos.append(sDirPath) return lErrorRepos
def run(self): oMethod = getattr(self, self.oArgs.command.upper()) if oMethod is not None and callable(oMethod): try: return oMethod() except (subprocess.CalledProcessError, OSError) as e: raise FatalError(e) raise FatalError("Command %s is not implemented." % self.oArgs.command)
def getApiClient(self): sConfigFilePath = os.path.join(os.path.expanduser("~"), ".repolite") if not os.path.isfile(sConfigFilePath): raise FatalError("The config file %s does not exist." % sConfigFilePath) sWorkingDir = os.path.normcase( os.path.abspath(os.path.dirname(os.getcwd()))) oConfig = ConfigParser() oConfig.read(sConfigFilePath) dSection = oConfig["DEFAULT"] for sSection in oConfig.sections(): sTarget = oConfig.get(sSection, "target", fallback=None) if sTarget: sTarget = os.path.normcase( os.path.abspath( os.path.join(os.path.dirname(sConfigFilePath), sTarget))) if sWorkingDir == sTarget: dSection = oConfig[sSection] break def getNotEmpty(sKey): sValue = dSection.get(sKey, fallback=None) if sValue is None: raise FatalError( "No value provided for %s in the config file" % sKey) return sValue self.oApiClient = gerrit.ApiClient(getNotEmpty("url"), getNotEmpty("username"), getNotEmpty("password")) return self.oApiClient
def DOWNLOAD(self): oMatch = re.match(r"(\d+)/\d+", self.oArgs.patch) if oMatch is None: raise FatalError("%s is not a valid patch ID" % self.oArgs.patch) sPatchChecksum = "%02d" % int(oMatch.group(1)[-2:]) gerrit.download("refs/changes/%s/%s" % (sPatchChecksum, self.oArgs.patch), bDetach=self.oArgs.detach)
def RENAME(self): sCurrentBranch = git.getCurrentBranch() if sCurrentBranch: print("Renaming topic: %s -> %s" % (sCurrentBranch, self.oArgs.topic)) subprocess.run(["git", "branch", "-m", self.oArgs.topic], check=True) else: raise FatalError("There is no topic")
def download(sRepoUrl): nonlocal bFound sPatchRef = self.getPatchRef(sRepoUrl, self.oArgs.change) if sPatchRef: print("Downloading change %s from %s" % (self.oArgs.change, sRepoUrl)) gerrit.download(sPatchRef, bDetach=self.oArgs.detach) bFound = True else: sErrMsg = "Change %s not found within this project" % self.oArgs.change if self.oArgs.project: raise FatalError(sErrMsg) else: print("Skipped: %s" % sErrMsg)
def onError(): while True: sInput = input( "You may have merge conflicts. Fix them and press enter, or enter 'abort' now to quit: " ) if sInput == "abort": print("Aborting.") subprocess.run(["git", "cherry-pick", "--abort"]) if xOnAbort is not None: xOnAbort() raise FatalError("Process aborted.") elif not sInput: print("Continuing...") break
def PULL(self, sRepoUrl): sChangeId = gerrit.getChangeId() if not sChangeId: raise FatalError("Unable to extract Change-Id") sProject = gerrit.getProjectName() try: dChangeData = self.getApiClient().getChangeData( sChangeId, sProject, lAdditionalData=["ALL_REVISIONS"]) except requests.HTTPError as e: if e.response.status_code == 404: warning("No remote patch") return raise e sRemoteCommit = dChangeData["current_revision"] sLocalCommit = git.getLastCommit() sLastPushedCommit = self.getRepoData().getLastPushedCommit( sProject, sChangeId) if sRemoteCommit == sLocalCommit: print("Already up-to-date.") return elif sRemoteCommit == sLastPushedCommit: print("You are ahead of Gerrit.") return elif sLocalCommit in dChangeData["revisions"]: print("Pulling changes from %s" % sRepoUrl) sBranch = git.getCurrentBranch() dFetchData = dChangeData["revisions"][sRemoteCommit]["fetch"][ "ssh"] subprocess.run( ["git", "fetch", dFetchData["url"], dFetchData["ref"]], check=True) subprocess.run(["git", "checkout", "FETCH_HEAD"], check=True) if sBranch: subprocess.run(["git", "branch", "-D", sBranch], check=True) subprocess.run(["git", "checkout", "-b", sBranch], check=True) else: raise FatalError("You have local commits unknown to Gerrit")
def executeForAll(self, xFunction): dRepos = self.readManifest( bKeepInvalid=getattr(xFunction, "bKeepInvalid", False)) if not dRepos: raise FatalError("There is no valid repository defined.") if getattr(xFunction, "bForAll", False): return xFunction(dRepos) else: def doCallFunction(sRepoUrl): if len(inspect.getfullargspec(xFunction)[0]) > 1: xFunction(sRepoUrl) else: xFunction() return self.runInRepos(dRepos, doCallFunction)
def save(self, sFile): try: with open(sFile, "w") as oFile: json.dump(self.dRaw, oFile) except (ValueError, OSError) as e: raise FatalError(e)
def load(self, sFile): try: with open(sFile, "r") as oFile: self.dRaw = json.load(oFile) except (ValueError, OSError) as e: raise FatalError(e)
def run(self): oMethod = getattr(self, self.oArgs.command.upper()) if oMethod is not None and callable(oMethod): return self.executeForAll(oMethod) raise FatalError("Command %s is not implemented." % self.oArgs.command)
def getNotEmpty(sKey): sValue = dSection.get(sKey, fallback=None) if sValue is None: raise FatalError( "No value provided for %s in the config file" % sKey) return sValue