?? mailer.py
字號:
"""Figure out the common portion/parent (commondir) of all the paths in DIRLIST and return a tuple consisting of commondir, dirlist. If a commondir is found, the dirlist returned is rooted in that commondir. If no commondir is found, dirlist is returned unchanged, and commondir is the empty string.""" if len(dirlist) == 1 or '/' in dirlist: commondir = '' newdirs = dirlist else: common = string.split(dirlist[0], '/') for j in range(1, len(dirlist)): d = dirlist[j] parts = string.split(d, '/') for i in range(len(common)): if i == len(parts) or common[i] != parts[i]: del common[i:] break commondir = string.join(common, '/') if commondir: # strip the common portion from each directory l = len(commondir) + 1 newdirs = [ ] for d in dirlist: if d == commondir: newdirs.append('.') else: newdirs.append(d[l:]) else: # nothing in common, so reset the list of directories newdirs = dirlist return commondir, newdirsclass Lock(Messenger): def __init__(self, pool, cfg, repos, author, do_lock): self.author = author self.do_lock = do_lock Messenger.__init__(self, pool, cfg, repos, (do_lock and 'lock_subject_prefix' or 'unlock_subject_prefix')) # read all the locked paths from STDIN and strip off the trailing newlines self.dirlist = map(lambda x: x.rstrip(), sys.stdin.readlines()) # collect the set of groups and the unique sets of params for the options self.groups = { } for path in self.dirlist: for (group, params) in self.cfg.which_groups(path): # turn the params into a hashable object and stash it away param_list = params.items() param_list.sort() # collect the set of paths belonging to this group if self.groups.has_key( (group, tuple(param_list)) ): old_param, paths = self.groups[group, tuple(param_list)] else: paths = { } paths[path] = None self.groups[group, tuple(param_list)] = (params, paths) commondir, dirlist = get_commondir(self.dirlist) # compose the basic subject line. later, we can prefix it. dirlist.sort() dirlist = string.join(dirlist) if commondir: self.output.subject = '%s: %s' % (commondir, dirlist) else: self.output.subject = '%s' % (dirlist) # The lock comment is the same for all paths, so we can just pull # the comment for the first path in the dirlist and cache it. self.lock = svn.fs.svn_fs_get_lock(self.repos.fs_ptr, self.dirlist[0], self.pool) def generate(self): for (group, param_tuple), (params, paths) in self.groups.items(): self.output.start(group, params) self.output.write('Author: %s\n' '%s paths:\n' % (self.author, self.do_lock and 'Locked' or 'Unlocked')) self.dirlist.sort() for dir in self.dirlist: self.output.write(' %s\n\n' % dir) if self.do_lock: self.output.write('Comment:\n%s\n' % (self.lock.comment or '')) self.output.finish()class DiffSelections: def __init__(self, cfg, group, params): self.add = False self.copy = False self.delete = False self.modify = False gen_diffs = cfg.get('generate_diffs', group, params) ### Do a little dance for deprecated options. Note that even if you ### don't have an option anywhere in your configuration file, it ### still gets returned as non-None. if len(gen_diffs): list = string.split(gen_diffs, " ") for item in list: if item == 'add': self.add = True if item == 'copy': self.copy = True if item == 'delete': self.delete = True if item == 'modify': self.modify = True else: self.add = True self.copy = True self.delete = True self.modify = True ### These options are deprecated suppress = cfg.get('suppress_deletes', group, params) if suppress == 'yes': self.delete = False suppress = cfg.get('suppress_adds', group, params) if suppress == 'yes': self.add = Falseclass DiffURLSelections: def __init__(self, cfg, group, params): self.cfg = cfg self.group = group self.params = params def _get_url(self, action, repos_rev, change): # The parameters for the URLs generation need to be placed in the # parameters for the configuration module, otherwise we may get # KeyError exceptions. params = self.params.copy() params['path'] = change.path and urllib.quote(change.path) or None params['base_path'] = change.base_path and urllib.quote(change.base_path) or None params['rev'] = repos_rev params['base_rev'] = change.base_rev return self.cfg.get("diff_%s_url" % action, self.group, params) def get_add_url(self, repos_rev, change): return self._get_url('add', repos_rev, change) def get_copy_url(self, repos_rev, change): return self._get_url('copy', repos_rev, change) def get_delete_url(self, repos_rev, change): return self._get_url('delete', repos_rev, change) def get_modify_url(self, repos_rev, change): return self._get_url('modify', repos_rev, change)def generate_content(renderer, cfg, repos, changelist, group, params, paths, pool): svndate = repos.get_rev_prop(svn.core.SVN_PROP_REVISION_DATE) ### pick a different date format? date = time.ctime(svn.core.secs_from_timestr(svndate, pool)) diffsels = DiffSelections(cfg, group, params) diffurls = DiffURLSelections(cfg, group, params) show_nonmatching_paths = cfg.get('show_nonmatching_paths', group, params) \ or 'yes' params_with_rev = params.copy() params_with_rev['rev'] = repos.rev commit_url = cfg.get('commit_url', group, params_with_rev) # figure out the lists of changes outside the selected path-space other_added_data = other_removed_data = other_modified_data = [ ] if len(paths) != len(changelist) and show_nonmatching_paths != 'no': other_added_data = generate_list('A', changelist, paths, False) other_removed_data = generate_list('R', changelist, paths, False) other_modified_data = generate_list('M', changelist, paths, False) if len(paths) != len(changelist) and show_nonmatching_paths == 'yes': other_diffs = DiffGenerator(changelist, paths, False, cfg, repos, date, group, params, diffsels, diffurls, pool) else: other_diffs = None data = _data( author=repos.author, date=date, rev=repos.rev, log=repos.get_rev_prop(svn.core.SVN_PROP_REVISION_LOG) or '', commit_url=commit_url, added_data=generate_list('A', changelist, paths, True), removed_data=generate_list('R', changelist, paths, True), modified_data=generate_list('M', changelist, paths, True), show_nonmatching_paths=show_nonmatching_paths, other_added_data=other_added_data, other_removed_data=other_removed_data, other_modified_data=other_modified_data, diffs=DiffGenerator(changelist, paths, True, cfg, repos, date, group, params, diffsels, diffurls, pool), other_diffs=other_diffs, ) renderer.render(data)def generate_list(changekind, changelist, paths, in_paths): if changekind == 'A': selection = lambda change: change.added elif changekind == 'R': selection = lambda change: change.path is None elif changekind == 'M': selection = lambda change: not change.added and change.path is not None items = [ ] for path, change in changelist: if selection(change) and paths.has_key(path) == in_paths: item = _data( path=path, is_dir=change.item_kind == svn.core.svn_node_dir, props_changed=change.prop_changes, text_changed=change.text_changed, copied=change.added and change.base_path, base_path=change.base_path, base_rev=change.base_rev, ) items.append(item) return itemsclass DiffGenerator: "This is a generator-like object returning DiffContent objects." def __init__(self, changelist, paths, in_paths, cfg, repos, date, group, params, diffsels, diffurls, pool): self.changelist = changelist self.paths = paths self.in_paths = in_paths self.cfg = cfg self.repos = repos self.date = date self.group = group self.params = params self.diffsels = diffsels self.diffurls = diffurls self.pool = pool self.diff = self.diff_url = None self.idx = 0 def __nonzero__(self): # we always have some items return True def __getitem__(self, idx): while 1: if self.idx == len(self.changelist): raise IndexError path, change = self.changelist[self.idx] self.idx = self.idx + 1 diff = diff_url = None kind = None label1 = None label2 = None src_fname = None dst_fname = None binary = None singular = None content = None # just skip directories. they have no diffs. if change.item_kind == svn.core.svn_node_dir: continue # is this change in (or out of) the set of matched paths? if self.paths.has_key(path) != self.in_paths: continue # figure out if/how to generate a diff if not change.path: # it was delete. kind = 'D' # get the diff url, if any is specified diff_url = self.diffurls.get_delete_url(self.repos.rev, change) # show the diff? if self.diffsels.delete: diff = svn.fs.FileDiff(self.repos.get_root(change.base_rev), change.base_path, None, None, self.pool) label1 = '%s\t%s' % (change.base_path, self.date) label2 = '(empty file)' singular = True elif change.added: if change.base_path and (change.base_rev != -1): # this file was copied. kind = 'C' # any diff of interest? if change.text_changed: # get the diff url, if any is specified diff_url = self.diffurls.get_copy_url(self.repos.rev, change) # show the diff? if self.diffsels.copy: diff = svn.fs.FileDiff(self.repos.get_root(change.base_rev), change.base_path, self.repos.root_this, change.path, self.pool) label1 = change.base_path + '\t(original)' label2 = '%s\t%s' % (change.path, self.date) singular = False else: # the file was added. kind = 'A' # get the diff url, if any is specified diff_url = self.diffurls.get_add_url(self.repos.rev, change) # show the diff? if self.diffsels.add: diff = svn.fs.FileDiff(None, None, self.repos.root_this, change.path, self.pool) label1 = '(empty file)' label2 = '%s\t%s' % (change.path, self.date) singular = True elif not change.text_changed: # the text didn't change, so nothing to show. continue else: # a simple modification. kind = 'M' # get the diff url, if any is specified diff_url = self.diffurls.get_modify_url(self.repos.rev, change) # show the diff? if self.diffsels.modify: diff = svn.fs.FileDiff(self.repos.get_root(change.base_rev), change.base_path, self.repos.root_this, change.path, self.pool) label1 = change.base_path + '\t(original)' label2 = '%s\t%s' % (change.path, self.date) singular = False if diff: binary = diff.either_binary() if binary: content = src_fname = dst_fname = None else: src_fname, dst_fname = diff.get_files() content = DiffContent(self.cfg.get_diff_cmd(self.group, { 'label_from' : label1, 'label_to' : label2, 'from' : src_fname, 'to' : dst_fname, })) # return a data item for this diff return _data( path=change.path, base_path=change.base_path, base_rev=change.base_rev, diff=diff, diff_url=diff_url, kind=kind, label_from=label1, label_to=label2, from_fname=src_fname, to_fname=dst_fname, binary=binary, singular=singular, content=content, )class DiffContent: "This is a generator-like object returning annotated lines of a diff." def __init__(self, cmd): self.seen_change = False # By default we choose to incorporate child stderr into the output self.pipe = Popen4(cmd) def __nonzero__(self): # we always have some items return True def __getitem__(self, idx): if self.pipe is None: raise IndexError line = self.pipe.fromchild.readline() if not line: # wait on the child so we don't end up with a billion zombies self.pipe.wait() self.pipe = None raise IndexError # classify the type of line. first = line[:1] if first == '@': self.seen_change = True ltype = 'H' elif first == '-': if self.seen_change: ltype = 'D' else: ltype = 'F' elif first == '+': if self.seen_change: ltype = 'A' else: ltype = 'T' elif first == ' ': ltype = 'C' else: ltype = 'U' return _data( raw=line, text=line[1:-1], # remove indicator and newline type=ltype, )
?? 快捷鍵說明
復(fù)制代碼
Ctrl + C
搜索代碼
Ctrl + F
全屏模式
F11
切換主題
Ctrl + Shift + D
顯示快捷鍵
?
增大字號
Ctrl + =
減小字號
Ctrl + -