📄 svnmerge.py
字号:
"""Show change sets already merged. This set of revisions is calculated from taking svnmerge-integrated property from the branch, and subtracting any revision older than the branch creation revision.""" # Extract the integration info for the branch_dir branch_props = get_merge_props(branch_dir) check_old_prop_version(branch_dir, branch_props) revs = merge_props_to_revision_set(branch_props, opts["head-path"]) # Lookup the oldest revision on the branch path. oldest_src_rev = get_created_rev(opts["head-url"]) # Subtract any revisions which pre-date the branch. report("subtracting revisions which pre-date the source URL (%d)" % oldest_src_rev) revs = revs - RevisionSet(range(1, oldest_src_rev)) # Limit to revisions specified by -r (if any) if opts["revision"]: revs = revs & RevisionSet(opts["revision"]) display_revisions(revs, opts["integrated-display"], "revisions already integrated are:", opts["head-url"])def action_merge(branch_dir, branch_props): """Record merge meta data, and do the actual merge (if not requested otherwise via --record-only).""" # Check branch directory is ready for being modified check_dir_clean(branch_dir) head_revs, phantom_revs, reflected_revs = \ analyze_head_revs(branch_dir, opts["head-url"], find_reflected=opts["bidirectional"]) if opts["revision"]: revs = RevisionSet(opts["revision"]) else: revs = head_revs blocked_revs = get_blocked_revs(branch_dir, opts["head-path"]) merged_revs = opts["merged-revs"] # Show what we're doing if opts["verbose"]: # just to avoid useless calculations if merged_revs & revs: report('"%s" already contains revisions %s' % (branch_dir, merged_revs & revs)) if phantom_revs: report('memorizing phantom revision(s): %s' % phantom_revs) if reflected_revs: report('memorizing reflected revision(s): %s' % reflected_revs) if blocked_revs & revs: report('skipping blocked revisions(s): %s' % (blocked_revs & revs)) # Compute final merge set. revs = revs - merged_revs - blocked_revs - reflected_revs - phantom_revs if not revs: report('no revisions to merge, exiting') return # When manually marking revisions as merged, we only update the # integration meta data, and don't perform an actual merge. record_only = opts["record-only"] if record_only: report('recording merge of revision(s) %s from "%s"' % (revs, opts["head-url"])) else: report('merging in revision(s) %s from "%s"' % (revs, opts["head-url"])) # Do the merge(s). Note: the starting revision number to 'svn merge' # is NOT inclusive so we have to subtract one from start. # We try to keep the number of merge operations as low as possible, # because it is faster and reduces the number of conflicts. old_merge_props = branch_props merge_metadata = logs[opts["head-url"]].merge_metadata() for start,end in minimal_merge_intervals(revs, phantom_revs): # Set merge props appropriately if bidirectional support is enabled if opts["bidirectional"]: new_merge_props = merge_metadata.get(start-1) if new_merge_props != old_merge_props: set_merge_props(branch_dir, new_merge_props) old_merge_props = new_merge_props if not record_only: # Do the merge svn_command("merge -r %d:%d %s %s" % \ (start - 1, end, opts["head-url"], branch_dir)) # Write out commit message if desired if opts["commit-file"]: f = open(opts["commit-file"], "w") if record_only: print >>f, 'Recorded merge of revisions %s via %s from ' % \ (revs | phantom_revs, NAME) else: print >>f, 'Merged revisions %s via %s from ' % \ (revs | phantom_revs, NAME) print >>f, '%s' % opts["head-url"] if opts["commit-verbose"]: print >>f print >>f, construct_merged_log_message(opts["head-url"], revs), f.close() report('wrote commit message to "%s"' % opts["commit-file"]) # Update the set of merged revisions. merged_revs = merged_revs | revs | reflected_revs | phantom_revs branch_props[opts["head-path"]] = str(merged_revs) set_merge_props(branch_dir, branch_props)def action_block(branch_dir, branch_props): """Block revisions.""" # Check branch directory is ready for being modified check_dir_clean(branch_dir) head_revs, phantom_revs, reflected_revs = \ analyze_head_revs(branch_dir, opts["head-url"]) revs_to_block = head_revs - opts["merged-revs"] # Limit to revisions specified by -r (if any) if opts["revision"]: revs_to_block = RevisionSet(opts["revision"]) & revs_to_block if not revs_to_block: error('no available revisions to block') # Change blocked information blocked_revs = get_blocked_revs(branch_dir, opts["head-path"]) blocked_revs = blocked_revs | revs_to_block set_blocked_revs(branch_dir, opts["head-path"], blocked_revs) # Write out commit message if desired if opts["commit-file"]: f = open(opts["commit-file"], "w") print >>f, 'Blocked revisions %s via %s' % (revs_to_block, NAME) if opts["commit-verbose"]: print >>f print >>f, construct_merged_log_message(opts["head-url"], revs_to_block), f.close() report('wrote commit message to "%s"' % opts["commit-file"])def action_unblock(branch_dir, branch_props): """Unblock revisions.""" # Check branch directory is ready for being modified check_dir_clean(branch_dir) blocked_revs = get_blocked_revs(branch_dir, opts["head-path"]) revs_to_unblock = blocked_revs # Limit to revisions specified by -r (if any) if opts["revision"]: revs_to_unblock = revs_to_unblock & RevisionSet(opts["revision"]) if not revs_to_unblock: error('no available revisions to unblock') # Change blocked information blocked_revs = blocked_revs - revs_to_unblock set_blocked_revs(branch_dir, opts["head-path"], blocked_revs) # Write out commit message if desired if opts["commit-file"]: f = open(opts["commit-file"], "w") print >>f, 'Unblocked revisions %s via %s' % (revs_to_unblock, NAME) if opts["commit-verbose"]: print >>f print >>f, construct_merged_log_message(opts["head-url"], revs_to_unblock), f.close() report('wrote commit message to "%s"' % opts["commit-file"])def action_rollback(branch_dir, branch_props): """Rollback previously integrated revisions.""" # Make sure the revision arguments are present if not opts["revision"]: error("The '-r' option is mandatory for rollback") # Check branch directory is ready for being modified check_dir_clean(branch_dir) # Extract the integration info for the branch_dir branch_props = get_merge_props(branch_dir) check_old_prop_version(branch_dir, branch_props) # Get the list of all revisions already merged into this source-path. merged_revs = merge_props_to_revision_set(branch_props, opts["head-path"]) # At which revision was the src created? oldest_src_rev = get_created_rev(opts["head-url"]) src_pre_exist_range = RevisionSet("1-%d" % oldest_src_rev) # Limit to revisions specified by -r (if any) revs = merged_revs & RevisionSet(opts["revision"]) # make sure theres some revision to rollback if not revs: report("Nothing to rollback in revision range r%s" % opts["revision"]) return # If even one specified revision lies outside the lifetime of the # source head, error out. if revs & src_pre_exist_range: err_str = "Specified revision range falls out of the rollback range.\n" err_str += "%s was created at r%d" % (opts["head-path"], oldest_src_rev) error(err_str) record_only = opts["record-only"] if record_only: report('recording rollback of revision(s) %s from "%s"' % (revs, opts["head-url"])) else: report('rollback of revision(s) %s from "%s"' % (revs, opts["head-url"])) # Do the reverse merge(s). Note: the starting revision number # to 'svn merge' is NOT inclusive so we have to subtract one from start. # We try to keep the number of merge operations as low as possible, # because it is faster and reduces the number of conflicts. rollback_intervals = minimal_merge_intervals(revs, []) # rollback in the reverse order of merge rollback_intervals.reverse() for start, end in rollback_intervals: if not record_only: # Do the merge svn_command("merge -r %d:%d %s %s" % \ (end, start - 1, opts["head-url"], branch_dir)) # Write out commit message if desired # calculate the phantom revs first if opts["commit-file"]: f = open(opts["commit-file"], "w") if record_only: print >>f, 'Recorded rollback of revisions %s via %s from ' % \ (revs , NAME) else: print >>f, 'Rolled back revisions %s via %s from ' % \ (revs , NAME) print >>f, '%s' % opts["head-url"] f.close() report('wrote commit message to "%s"' % opts["commit-file"]) # Update the set of merged revisions. merged_revs = merged_revs - revs branch_props[opts["head-path"]] = str(merged_revs) set_merge_props(branch_dir, branch_props)def action_uninit(branch_dir, branch_props): """Uninit HEAD URL.""" # Check branch directory is ready for being modified check_dir_clean(branch_dir) # If the head-path does not have an entry in the svnmerge-integrated # property, simply error out. if not branch_props.has_key(opts["head-path"]): error('"%s" does not contain merge tracking information for "%s"' \ % (opts["head-path"], branch_dir)) del branch_props[opts["head-path"]] # Set merge property with the selected head deleted set_merge_props(branch_dir, branch_props) # Set blocked revisions for the selected head to None set_blocked_revs(branch_dir, opts["head-path"], None) # Write out commit message if desired if opts["commit-file"]: f = open(opts["commit-file"], "w") print >>f, 'Removed merge tracking for "%s" for ' % NAME print >>f, '%s' % opts["head-url"] f.close() report('wrote commit message to "%s"' % opts["commit-file"])################################################################################ Command line parsing -- options and commands management###############################################################################class OptBase: def __init__(self, *args, **kwargs): self.help = kwargs["help"] del kwargs["help"] self.lflags = [] self.sflags = [] for a in args: if a.startswith("--"): self.lflags.append(a) elif a.startswith("-"): self.sflags.append(a) else: raise TypeError, "invalid flag name: %s" % a if kwargs.has_key("dest"): self.dest = kwargs["dest"] del kwargs["dest"] else: if not self.lflags: raise TypeError, "cannot deduce dest name without long options" self.dest = self.lflags[0][2:] if kwargs: raise TypeError, "invalid keyword arguments: %r" % kwargs.keys() def repr_flags(self): f = self.sflags + self.lflags r = f[0] for fl in f[1:]: r += " [%s]" % fl return rclass Option(OptBase): def __init__(self, *args, **kwargs): self.default = kwargs.setdefault("default", 0) del kwargs["default"] self.value = kwargs.setdefault("value", None) del kwargs["value"] OptBase.__init__(self, *args, **kwargs) def apply(self, state, value): assert value == "" if self.value is not None: state[self.dest] = self.value else: state[self.dest] += 1class OptionArg(OptBase): def __init__(self, *args, **kwargs): self.default = kwargs["default"] del kwargs["default"] self.metavar = kwargs.setdefault("metavar", None) del kwargs["metavar"] OptBase.__init__(self, *args, **kwargs) if self.metavar is None: if self.dest is not None: self.metavar = self.dest.upper() else: self.metavar = "arg" if self.default: self.help += " (default: %s)" % self.default def apply(self, state, value): assert value is not None state[self.dest] = value def repr_flags(self): r = OptBase.repr_flags(self) return r + " " + self.metavarclass CommandOpts: class Cmd: def __init__(self, *args): self.name, self.func, self.usage, self.help, self.opts = args def short_help(self): return self.help.split(".")[0] def __str__(self): return self.name def __call__(self, *args, **kwargs): return self.func(*args, **kwargs) def __init__(self, global_opts, common_opts, command_table, version=None):
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -