1 # Copyright (C) 2012 W. Trevor King
3 # This file is part of update-copyright.
5 # update-copyright is free software: you can redistribute it and/or
6 # modify it under the terms of the GNU General Public License as
7 # published by the Free Software Foundation, either version 3 of the
8 # License, or (at your option) any later version.
10 # update-copyright is distributed in the hope that it will be useful,
11 # but WITHOUT ANY WARRANTY; without even the implied warranty of
12 # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
13 # General Public License for more details.
15 # You should have received a copy of the GNU General Public License
16 # along with update-copyright. If not, see
17 # <http://www.gnu.org/licenses/>.
19 """Useful utilities for backend classes."""
21 import email.utils as _email_utils
22 import os.path as _os_path
23 import subprocess as _subprocess
26 from .. import LOG as LOG
27 from ..utils import ENCODING as _ENCODING
30 _MSWINDOWS = _sys.platform == 'win32'
31 _POSIX = not _MSWINDOWS
34 def invoke(args, stdin=None, stdout=_subprocess.PIPE, stderr=_subprocess.PIPE,
35 cwd=None, expect=(0,), unicode_output=False, encoding=None):
36 """Invoke an external program and return the results
38 ``expect`` should be a tuple of allowed exit codes.
40 When ``unicode_output`` is ``True``, convert stdout and stdin
41 strings to unicode before returing them.
43 LOG.debug('{}$ {}'.format(cwd, args))
46 q = _subprocess.Popen(args, stdin=_subprocess.PIPE,
47 stdout=stdout, stderr=stderr,
48 close_fds=True, cwd=cwd)
50 assert _MSWINDOWS == True, 'invalid platform'
51 # win32 don't have os.execvp() so run the command in a shell
52 q = _subprocess.Popen(args, stdin=_subprocess.PIPE,
53 stdout=stdout, stderr=stderr, shell=True,
56 raise ValueError([args, e])
57 stdout,stderr = q.communicate(input=stdin)
59 if unicode_output == True:
62 if stdout is not None:
63 stdout = unicode(stdout, encoding)
64 if stderr is not None:
65 stderr = unicode(stderr, encoding)
66 if status not in expect:
67 raise ValueError([args, status, stdout, stderr])
68 return status, stdout, stderr
71 """Recursively split a path into elements.
77 >>> splitpath(os.path.join('a', 'b', 'c'))
79 >>> splitpath(os.path.join('.', 'a', 'b', 'c'))
82 path = _os_path.normpath(path)
85 dirname,basename = _os_path.split(path)
86 elements.insert(0,basename)
87 if dirname in ['/', '', '.']:
90 return tuple(elements)
92 def strip_email(*args):
93 """Remove email addresses from a series of names.
98 >>> strip_email('J Doe')
100 >>> strip_email('J Doe <jdoe@a.com>')
102 >>> strip_email('J Doe <jdoe@a.com>', 'JJJ Smith <jjjs@a.com>')
103 ['J Doe', 'JJJ Smith']
106 for i,arg in enumerate(args):
109 author,addr = _email_utils.parseaddr(arg)
115 def reverse_aliases(aliases):
116 """Reverse an `aliases` dict.
118 Input: key: canonical name, value: list of aliases
119 Output: key: alias, value: canonical name
125 ... 'J Doe <jdoe@a.com>':['Johnny <jdoe@b.edu>', 'J'],
126 ... 'JJJ Smith <jjjs@a.com>':['Jingly <jjjs@b.edu>'],
127 ... None:['Anonymous <a@a.com>'],
129 >>> r = reverse_aliases(aliases)
130 >>> for item in sorted(r.items()):
132 ('Anonymous <a@a.com>', None)
133 ('J', 'J Doe <jdoe@a.com>')
134 ('Jingly <jjjs@b.edu>', 'JJJ Smith <jjjs@a.com>')
135 ('Johnny <jdoe@b.edu>', 'J Doe <jdoe@a.com>')
138 for canonical_name,_aliases in aliases.items():
139 for alias in _aliases:
140 output[alias] = canonical_name
143 def replace_aliases(authors, with_email=True, aliases=None):
144 """Consolidate and sort `authors`.
146 Make the replacements listed in the `aliases` dict (key: canonical
147 name, value: list of aliases). If `aliases` is ``None``, default
151 ... 'J Doe <jdoe@a.com>':['Johnny <jdoe@b.edu>'],
152 ... 'JJJ Smith <jjjs@a.com>':['Jingly <jjjs@b.edu>'],
153 ... None:['Anonymous <a@a.com>'],
156 ... 'JJJ Smith <jjjs@a.com>', 'Johnny <jdoe@b.edu>',
157 ... 'Jingly <jjjs@b.edu>', 'J Doe <jdoe@a.com>', 'Anonymous <a@a.com>']
158 >>> replace_aliases(authors, with_email=True, aliases=aliases)
159 ['J Doe <jdoe@a.com>', 'JJJ Smith <jjjs@a.com>']
160 >>> replace_aliases(authors, with_email=False, aliases=aliases)
161 ['J Doe', 'JJJ Smith']
165 rev_aliases = reverse_aliases(aliases)
166 for i,author in enumerate(authors):
167 if author in rev_aliases:
168 authors[i] = rev_aliases[author]
169 authors = sorted(list(set(authors)))
172 if with_email == False:
173 authors = strip_email(*authors)