def _commit(self, date, author, patchname, changelog=None, entries=None, tags=[], isinitialcommit=False): """ Commit the changeset. """ logmessage = [] logmessage.append( date.astimezone(UTC).strftime('%Y/%m/%d %H:%M:%S UTC')) logmessage.append(author) if patchname: logmessage.append(patchname) if changelog: logmessage.append(changelog) if not patchname and not changelog: logmessage.append('Unnamed patch') cmd = self.repository.command("record", "--all", "--pipe") if not entries: entries = ['.'] record = ExternalCommand(cwd=self.repository.basedir, command=cmd) record.execute(input=self.repository.encode('\n'.join(logmessage))) if record.exit_status: raise ChangesetApplicationFailure( "%s returned status %d" % (str(record), record.exit_status))
def _commit(self, date, author, patchname, changelog=None, entries=None, tags=[], isinitialcommit=False): """ Commit the changeset. """ encode = self.repository.encode logmessage = [] if patchname: logmessage.append(patchname) if changelog: logmessage.append(changelog) # If we cannot use propset, fall back to old behaviour of # appending these info to the changelog if not self.repository.use_propset: logmessage.append('') logmessage.append('Original author: %s' % encode(author)) logmessage.append('Date: %s' % date) elif not self.repository.propset_date: logmessage.append('') logmessage.append('Date: %s' % date) rontf = ReopenableNamedTemporaryFile('svn', 'tailor') log = open(rontf.name, "w") log.write(encode('\n'.join(logmessage))) log.close() cmd = self.repository.command("commit", "--file", rontf.name) commit = ExternalCommand(cwd=self.repository.basedir, command=cmd) if not entries or self.repository.commit_all_files: entries = ['.'] out, err = commit.execute(entries, stdout=PIPE, stderr=PIPE) if commit.exit_status: raise ChangesetApplicationFailure( "%s returned status %d saying\n%s" % (str(commit), commit.exit_status, err.read())) revision = self._propsetRevision(out, commit, date, author) if not revision: # svn did not find anything to commit return cmd = self.repository.command("update", "--quiet") if self.repository.ignore_externals: cmd.append("--ignore-externals") cmd.extend(["--revision", revision]) ExternalCommand(cwd=self.repository.basedir, command=cmd).execute()
def _commit(self, date, author, patchname, changelog=None, entries=None, tags=[], isinitialcommit=False): """ Commit the changeset. """ encode = self.repository.encode logmessage = [] if patchname: logmessage.append(patchname) if changelog: logmessage.append(changelog.replace('%', '%%')) cmd = self.repository.command("commit", "-s", encode('\n'.join(logmessage)), "--author", encode(author), "--date", date.isoformat()) c = ExternalCommand(cwd=self.repository.basedir, command=cmd) c.execute() if c.exit_status: raise ChangesetApplicationFailure("%s returned status %d" % (str(c), c.exit_status))
def _addPathnames(self, names): """ Add some new filesystem objects, skipping directories. In monotone *explicit* directory addition is always recursive, so adding a directory here might interfere with renames. Adding files without directories doesn't cause problems, because adding a file implicitly adds the parent directory (non-recursively). """ fnames = [] for fn in names: if isdir(join(self.repository.basedir, fn)): self.log.debug( "ignoring addition of directory %r " "(dirs are implicitly added by files)", fn) else: fnames.append(fn) if len(fnames): # ok, we still have something to add cmd = self.repository.command("add", "--") add = ExternalCommand(cwd=self.repository.basedir, command=cmd) add.execute(fnames, stdout=PIPE, stderr=PIPE) if add.exit_status: raise ChangesetApplicationFailure("%s returned status %s" % (str(add), add.exit_status))
def _commit(self, date, author, patchname, changelog=None, entries=None, tags = [], isinitialcommit = False): """ Commit the changeset. """ encode = self.repository.encode logmessage = [] if patchname: logmessage.append(patchname) if changelog: logmessage.append(changelog.replace('%', '%%')) cmd = self.repository.command("-u", encode(author), "commit", "-m", encode('\n'.join(logmessage)), "-D", date.astimezone(UTC).strftime('%Y/%m/%d %H:%M:%S UTC')) if not entries: entries = ['...'] c = ExternalCommand(cwd=self.repository.basedir, command=cmd) c.execute(entries) if c.exit_status: raise ChangesetApplicationFailure("%s returned status %d" % (str(c), c.exit_status))
def _tag(self, tagname, date, author): """ Apply a tag. """ # Sanitize tagnames for CVS: start with [a-zA-z], only include letters, # numbers, '-' and '_'. # str.isalpha et al are locale-dependent def iscvsalpha(chr): return (chr >= 'a' and chr <= 'z') or (chr >= 'A' and chr <= 'Z') def iscvsdigit(chr): return chr >= '0' and chr <= '9' def iscvschar(chr): return iscvsalpha(chr) or iscvsdigit( chr) or chr == '-' or chr == '_' def cvstagify(chr): if iscvschar(chr): return chr else: return '_' tagname = ''.join([cvstagify(chr) for chr in tagname]) if not iscvsalpha(tagname[0]): tagname = 'tag-' + tagname cmd = self.repository.command("-f", "tag") c = ExternalCommand(cwd=self.repository.basedir, command=cmd) c.execute(tagname) if c.exit_status: raise ChangesetApplicationFailure("%s returned status %d" % (str(c), c.exit_status))
def _tag(self, tag, date, author): # in single-repository mode, only update the relevant branch if self.repository.branch_name: refname = self.repository.branch_name else: refname = 'HEAD' # Allow a new tag to overwrite an older one with -f args = [ "tag", "-a", ] if self.repository.overwrite_tags: args.append("-f") # Escape the tag name for git import re tag_git = re.sub('_*$', '', re.sub('__', '_', re.sub('[^A-Za-z0-9_-]', '_', tag))) args += ["-m", tag, tag_git, refname] cmd = self.repository.command(*args) c = GitExternalCommand(self.repository, cwd=self.repository.basedir, command=cmd) c.execute() if c.exit_status: raise ChangesetApplicationFailure("%s returned status %d" % (str(c), c.exit_status))
def __move_file(self, old_name, new_name): # # The aegis command to rename files does not have the -keep # option to preserve the content of the file, do it manually. # fp = open(os.path.join(self.repository.basedir, new_name), 'rb') content = fp.read() fp.close() cmd = self.repository.command("-move", "-not-logging", "-project", self.repository.module, "-change", self.change_number) move_file = ExternalCommand(cwd=self.repository.basedir, command=cmd) output = move_file.execute(old_name, new_name, stdout=PIPE, stderr=STDOUT)[0] if move_file.exit_status > 0: raise ChangesetApplicationFailure( "%s returned status %d, saying: %s" % (str(move_file), move_file.exit_status, output.read())) # # Restore the previously saved content of the renamed file. # fp = open(os.path.join(self.repository.basedir, new_name), 'wb') fp.write(content) fp.close()
def __delta_name(self, delta): cmd = self.repository.command("-delta_name", "-project", self.repository.module) delta_name = ExternalCommand(cwd="/tmp", command=cmd) output = delta_name.execute(delta, stdout=PIPE, stderr=STDOUT)[0] if delta_name.exit_status > 0: raise ChangesetApplicationFailure( "%s returned status %d, saying: %s" % (str(delta_name), delta_name.exit_status, output.read()))
def __apply_changeset(self, changeset): c = ExternalCommand(cwd=self.repository.basedir, command=self.repository.command("update")) out, err = c.execute(changeset.revision, stdout=PIPE, stderr=PIPE) if not c.exit_status in [0, 1]: raise ChangesetApplicationFailure( "%s returned status %d saying\n%s" % (str(c), c.exit_status, err.read())) return self.__parse_apply_changeset_output(changeset, out)
def _renamePathname(self, oldname, newname): """ Rename a filesystem object. """ cmd = self.repository.command("rename", "--") rename = ExternalCommand(cwd=self.repository.basedir, command=cmd) rename.execute(oldname, newname, stdout=PIPE, stderr=PIPE) if rename.exit_status: raise ChangesetApplicationFailure( "%s returned status %s" % (str(rename), rename.exit_status))
def __remove_file(self, file_name): cmd = self.repository.command("-remove", "-not-logging", "-project", self.repository.module, "-change", self.change_number) remove_file = ExternalCommand(cwd=self.repository.basedir, command=cmd) output = remove_file.execute(file_name, stdout=PIPE, stderr=STDOUT)[0] if remove_file.exit_status > 0: raise ChangesetApplicationFailure( "%s returned status %d, saying: %s" % (str(remove_file), remove_file.exit_status, output.read()))
def _addSubtree(self, subdir): """ Add a whole subtree (recursively) """ cmd = self.repository.command("add", "--recursive", "--") add = ExternalCommand(cwd=self.repository.basedir, command=cmd) add.execute(subdir, stdout=PIPE, stderr=PIPE) if add.exit_status: raise ChangesetApplicationFailure("%s returned status %s" % (str(add), add.exit_status))
def __finish(self): cmd = self.repository.command("-finish", "-project", self.repository.module, "-change", self.change_number) finish = ExternalCommand(cwd="/tmp", command=cmd) output = finish.execute(stdout=PIPE, stderr=STDOUT)[0] if finish.exit_status > 0: raise ChangesetApplicationFailure( "%s returned status %d, saying: %s" % (str(finish), finish.exit_status, output.read()))
def __change_attribute(self, file): cmd = self.repository.command("-change_attr", "-project", self.repository.module, "-change", self.change_number) change_attr = ExternalCommand(cwd="/tmp", command=cmd) output = change_attr.execute("-file", file, stdout=PIPE, stderr=STDOUT)[0] if change_attr.exit_status > 0: raise ChangesetApplicationFailure( "%s returned status %d, saying: %s" % (str(change_attr), change_attr.exit_status, output.read()))
def __integrate_begin(self): cmd = self.repository.command("-integrate_begin", "-project", self.repository.module, "-change", self.change_number) integrate_begin = ExternalCommand(cwd="/tmp", command=cmd) output = integrate_begin.execute(stdout=PIPE, stderr=STDOUT)[0] if integrate_begin.exit_status > 0: raise ChangesetApplicationFailure( "%s returned status %d, saying: %s" % (str(integrate_begin), integrate_begin.exit_status, output.read()))
def __develop_begin(self): cmd = self.repository.command("-develop_begin", "-project", self.repository.module, "-change", self.change_number, "-directory", self.repository.basedir) develop_begin = ExternalCommand(cwd="/tmp", command=cmd) output = develop_begin.execute(stdout=PIPE, stderr=STDOUT)[0] if develop_begin.exit_status > 0: raise ChangesetApplicationFailure( "%s returned status %d, saying: %s" % (str(develop_begin), develop_begin.exit_status, output.read())) self.log.info(output.read())
def _removePathnames(self, names): """ Remove some filesystem object. """ cmd = self.repository.command("drop", "--recursive", "--") drop = ExternalCommand(cwd=self.repository.basedir, command=cmd) dum, error = drop.execute(names, stdout=PIPE, stderr=PIPE) if drop.exit_status: errtext = error.read() self.log.error("Monotone drop said: %s", errtext) raise ChangesetApplicationFailure("%s returned status %s" % (str(drop), drop.exit_status))
def _applyChangeset(self, changeset): cmd = self.repository.command("update", "--revision", changeset.revision) mtl = ExternalCommand(cwd=self.repository.basedir, command=cmd) mtl.execute(stdout=PIPE, stderr=PIPE) if mtl.exit_status: raise ChangesetApplicationFailure("'mtn update' returned " "status %s" % mtl.exit_status) mtr = MonotoneRevToCset(repository=self.repository, working_dir=self.repository.basedir, branch=self.repository.module) mtr.updateCset(changeset) return False # no conflicts
def _renamePathname(self, oldname, newname): """ Rename a filesystem object. """ from os import rename from os.path import join, exists, isdir from time import sleep from datetime import datetime # --force in case the file has been changed and moved in one revision cmd = self.repository.command("mv", "--quiet", "--force") # Subversion does not seem to allow # $ mv a.txt b.txt # $ svn mv a.txt b.txt # Here we are in this situation, since upstream VCS already # moved the item. # It may be better to let subversion do the move itself. For one thing, # svn's cp+rm is different from rm+add (cp preserves history). unmoved = False oldpath = join(self.repository.basedir, oldname) newpath = join(self.repository.basedir, newname) if not exists(oldpath): try: rename(newpath, oldpath) except OSError: self.log.critical('Cannot rename %r back to %r', newpath, oldpath) raise unmoved = True # Ticket #135: Need a timediff between rsync and directory move if isdir(oldpath): now = datetime.now() if hasattr(self, '_last_svn_move'): last = self._last_svn_move else: last = now if not (now - last).seconds: sleep(1) self._last_svn_move = now move = ExternalCommand(cwd=self.repository.basedir, command=cmd) out, err = move.execute(oldname, newname, stdout=PIPE, stderr=PIPE) if move.exit_status: if unmoved: rename(oldpath, newpath) raise ChangesetApplicationFailure( "%s returned status %d saying\n%s" % (str(move), move.exit_status, err.read()))
def _commit(self, date, author, patchname, changelog=None, entries=None, tags=[], isinitialcommit=False): """ Commit the changeset. """ encode = self.repository.encode logmessage = [] if patchname: logmessage.append(patchname) if changelog: logmessage.append(changelog) rontf = ReopenableNamedTemporaryFile('mtn', 'tailor') log = open(rontf.name, "w") log.write(encode('\n'.join(logmessage))) log.close() date = date.astimezone(UTC).replace(microsecond=0, tzinfo=None) # monotone wants UTC cmd = self.repository.command("commit", "--author", encode(author), "--date", date.isoformat(), "--message-file", rontf.name) commit = ExternalCommand(cwd=self.repository.basedir, command=cmd) # Always commit everything, ignoring given entries... # XXX is this right? entries = ['.'] output, error = commit.execute(entries, stdout=PIPE, stderr=PIPE) # monotone complaints if there are no changes from the last commit. # we ignore those errors ... if commit.exit_status: text = error.read() if not "mtn: misuse: no changes to commit" in text: self.log.error("Monotone commit said: %s", text) raise ChangesetApplicationFailure( "%s returned status %s" % (str(commit), commit.exit_status)) else: self.log.info("No changes to commit - changeset ignored")
def _tag(self, tag, date, author): """ TAG current revision. """ # Get current revision from working copy # FIXME: Should cache the last revision somethere cmd = self.repository.command("automate", "get_base_revision_id") mtl = ExternalCommand(cwd=self.repository.basedir, command=cmd) outstr = mtl.execute(stdout=PIPE, stderr=PIPE) if mtl.exit_status: raise ChangesetApplicationFailure("%s returned status %s" % (str(mtl), mtl.exit_status)) revision = outstr[0].getvalue().split() effective_rev = revision[0] # Add the tag cmd = self.repository.command("tag", effective_rev, tag) mtl = ExternalCommand(cwd=self.repository.basedir, command=cmd) outstr = mtl.execute(stdout=PIPE, stderr=PIPE) if mtl.exit_status: raise ChangesetApplicationFailure("%s returned status %s" % (str(mtl), mtl.exit_status))
def _tag(self, tag, date, author): # in single-repository mode, only update the relevant branch if self.repository.branch_name: refname = self.repository.branch_name else: refname = 'HEAD' # Allow a new tag to overwrite an older one with -f args = [ "tag", "-a", ] if self.repository.overwrite_tags: args.append("-f") # Escape the tag name for git import re tag_git = re.sub('_*$', '', re.sub('__', '_', re.sub('[^A-Za-z0-9_-]', '_', tag))) args += ["-m", tag, tag_git, refname] cmd = self.repository.command(*args) c = GitExternalCommand(self.repository, cwd=self.repository.basedir, command=cmd) from os import environ env = {} env.update(environ) (name, email) = self.__parse_author(author) if name: env['GIT_AUTHOR_NAME'] = self.repository.encode(name) env['GIT_COMMITTER_NAME'] = self.repository.encode(name) if email: env['GIT_AUTHOR_EMAIL'] = email env['GIT_COMMITTER_EMAIL'] = email if date: env['GIT_AUTHOR_DATE'] = date.strftime("%Y-%m-%d %H:%M:%S %z") env['GIT_COMMITTER_DATE'] = env['GIT_AUTHOR_DATE'] c.execute(env=env) if c.exit_status: if not self.repository.overwrite_tags: self.log.critical("Couldn't set tag '%s': maybe it's a " "conflict with a previous tag, and " "overwrite-tags=True may help" % tag_git) raise ChangesetApplicationFailure("%s returned status %d" % (str(c), c.exit_status))
def __parse_apply_changeset_output(self, changeset, output): conflicts = [] skip = True for line in output: # skip comment lines, detect beginning and end of change list if line[0] == '*': if line.startswith("* applying changeset"): skip = False elif line.startswith("* reapplying local changes"): break continue if skip: continue l = line.split() l1 = self.__normalize_path(l[1]) l2 = None if len(l) > 2: l2 = self.__normalize_path(l[2]) # ignore permission changes and changes in the {arch} directory if l[0] in ['--', '-/'] or l1.startswith("{arch}"): continue if self.repository.IGNORE_IDS and l1.find('.arch-ids') >= 0: continue rev = changeset.revision if l[0][0] == 'M' or l[0] in ['ch', 'cl']: # 'ch': file <-> symlink, 'cl': ChangeLog updated e = changeset.addEntry(l1, rev) e.action_kind = e.UPDATED elif l[0][0] == 'A': e = changeset.addEntry(l1, rev) e.action_kind = e.ADDED elif l[0][0] == 'D': e = changeset.addEntry(l1, rev) e.action_kind = e.DELETED elif l[0] in ['=>', '/>']: e = changeset.addEntry(l2, rev) e.old_name = l1 e.action_kind = e.RENAMED elif l[0] in ['C', '?']: conflicts.append(l1) if l2: conflicts.append(l2) else: raise ChangesetApplicationFailure( "unhandled changeset operation: \"%s\"" % line.strip()) return conflicts
def __new_change(self, title="none", description="none"): change_attr_file = \ self.__change_attribute_file(brief_description = title, description = description) change_number_file = ReopenableNamedTemporaryFile('aegis', 'tailor') cmd = self.repository.command("-new_change", "-project", self.repository.module, "-file", change_attr_file.name, "-output", change_number_file.name) new_change = ExternalCommand(cwd="/tmp", command=cmd) output = new_change.execute(stdout=PIPE, stderr=STDOUT)[0] if new_change.exit_status > 0: raise ChangesetApplicationFailure( "%s returned status %d, saying: %s" % (str(new_change), new_change.exit_status, output.read())) fd = open(change_number_file.name, "rb") change_number = fd.read() fd.close() return change_number.strip()
def _tag(self, tag, date, author): """ TAG current revision. """ if self.repository.setupTagsDirectory(): src = self.repository.repository + self.repository.module dest = self.repository.repository + self.repository.tags_path \ + '/' + tag.replace('/', '_') cmd = self.repository.command("copy", src, dest, "-m", tag) svntag = ExternalCommand(cwd=self.repository.basedir, command=cmd) out, err = svntag.execute(stdout=PIPE, stderr=PIPE) if svntag.exit_status: raise ChangesetApplicationFailure( "%s returned status %d saying\n%s" % (str(svntag), svntag.exit_status, err.read())) self._propsetRevision(out, svntag, date, author)
def _commit(self, date, author, patchname, changelog=None, entries=None, tags=[], isinitialcommit=False): """ Commit the changeset. """ from os import environ encode = self.repository.encode logmessage = [] if patchname: logmessage.append(patchname) if changelog: logmessage.append(changelog) env = {} env.update(environ) (name, email) = self.__parse_author(author) if name: env['GIT_AUTHOR_NAME'] = encode(name) if email: env['GIT_AUTHOR_EMAIL'] = email if date: env['GIT_AUTHOR_DATE'] = date.strftime('%Y-%m-%d %H:%M:%S %z') # '-f' flag means we can get empty commits, which # shouldn't be a problem. cmd = self.repository.command("commit", "-f") c = ExternalCommand(cwd=self.repository.basedir, command=cmd) c.execute(env=env, input=encode('\n'.join(logmessage))) if c.exit_status: raise ChangesetApplicationFailure("%s returned status %d" % (str(c), c.exit_status))
def _applyChangeset(self, changeset): from time import sleep cmd = self.repository.command("update") if self.repository.ignore_externals: cmd.append("--ignore-externals") cmd.extend(["--revision", changeset.revision]) svnup = ExternalCommand(cwd=self.repository.basedir, command=cmd) retry = 0 while True: out, err = svnup.execute(".", stdout=PIPE, stderr=PIPE) if svnup.exit_status == 1: retry += 1 if retry > 3: break delay = 2**retry self.log.error("%s returned status %s saying\n%s", str(svnup), svnup.exit_status, err.read()) self.log.warning("Retrying in %d seconds...", delay) sleep(delay) else: break if svnup.exit_status: raise ChangesetApplicationFailure( "%s returned status %s saying\n%s" % (str(svnup), svnup.exit_status, err.read())) self.log.debug("%s updated to %s", ','.join([e.name for e in changeset.entries]), changeset.revision) result = [] for line in out: if len(line) > 2 and line[0] == 'C' and line[1] == ' ': self.log.warning("Conflict after svn update: %r", line) result.append(line[2:-1]) return result
def __new_file(self, file_names, usage=None): # # Tailor try to add also the aegis own log file and it's forbidden. # if file_names == "./aegis.log": return if usage == "config": cmd = self.repository.command("-new_file", "-keep", "-config", "-not-logging", "-project", self.repository.module, "-change", self.change_number) else: cmd = self.repository.command("-new_file", "-keep", "-not-logging", "-project", self.repository.module, "-change", self.change_number) new_file = ExternalCommand(cwd=self.repository.basedir, command=cmd) output = new_file.execute(file_names, stdout=PIPE, stderr=STDOUT)[0] if new_file.exit_status > 0: raise ChangesetApplicationFailure( "%s returned status %d, saying: %s" % (str(new_file), new_file.exit_status, output.read()))
def _commit(self, date, author, patchname, changelog=None, entries=None, tags=[], isinitialcommit=False): """ Commit the changeset. """ from vcpx.shwrap import ReopenableNamedTemporaryFile encode = self.repository.encode logmessage = [] if patchname: logmessage.append(patchname) if changelog: logmessage.append(changelog) logmessage.append('') logmessage.append('Original author: %s' % author) logmessage.append('Date: %s' % date) rontf = ReopenableNamedTemporaryFile('cvs', 'tailor') log = open(rontf.name, "w") log.write(encode('\n'.join(logmessage))) log.close() cmd = self.repository.command("-f", "-q", "ci", "-F", rontf.name) if not entries: entries = ['.'] c = ExternalCommand(cwd=self.repository.basedir, command=cmd) c.execute(entries) if c.exit_status: raise ChangesetApplicationFailure("%s returned status %d" % (str(c), c.exit_status))