123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111 |
- # mailmap.py -- Mailmap reader
- # Copyright (C) 2018 Jelmer Vernooij <jelmer@jelmer.uk>
- #
- # Dulwich is dual-licensed under the Apache License, Version 2.0 and the GNU
- # General Public License as public by the Free Software Foundation; version 2.0
- # or (at your option) any later version. You can redistribute it and/or
- # modify it under the terms of either of these two licenses.
- #
- # Unless required by applicable law or agreed to in writing, software
- # distributed under the License is distributed on an "AS IS" BASIS,
- # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- # See the License for the specific language governing permissions and
- # limitations under the License.
- #
- # You should have received a copy of the licenses; if not, see
- # <http://www.gnu.org/licenses/> for a copy of the GNU General Public License
- # and <http://www.apache.org/licenses/LICENSE-2.0> for a copy of the Apache
- # License, Version 2.0.
- #
- """Mailmap file reader."""
- def parse_identity(text):
- # TODO(jelmer): Integrate this with dulwich.fastexport.split_email and
- # dulwich.repo.check_user_identity
- (name, email) = text.rsplit(b"<", 1)
- name = name.strip()
- email = email.rstrip(b">").strip()
- if not name:
- name = None
- if not email:
- email = None
- return (name, email)
- def read_mailmap(f):
- """Read a mailmap.
- :param f: File-like object to read from
- :return: Iterator over
- ((canonical_name, canonical_email), (from_name, from_email)) tuples
- """
- for line in f:
- # Remove comments
- line = line.split(b'#')[0]
- line = line.strip()
- if not line:
- continue
- (canonical_identity, from_identity) = line.split(b'>', 1)
- canonical_identity += b">"
- if from_identity.strip():
- parsed_from_identity = parse_identity(from_identity)
- else:
- parsed_from_identity = None
- parsed_canonical_identity = parse_identity(canonical_identity)
- yield parsed_canonical_identity, parsed_from_identity
- class Mailmap(object):
- """Class for accessing a mailmap file."""
- def __init__(self, map=None):
- self._table = {}
- if map:
- for (canonical_identity, from_identity) in map:
- self.add_entry(canonical_identity, from_identity)
- def add_entry(self, canonical_identity, from_identity=None):
- """Add an entry to the mail mail.
- Any of the fields can be None, but at least one of them needs to be
- set.
- :param canonical_identity: The canonical identity (tuple)
- :param from_identity: The from identity (tuple)
- """
- if from_identity is None:
- from_name, from_email = None, None
- else:
- (from_name, from_email) = from_identity
- (canonical_name, canonical_email) = canonical_identity
- if from_name is None and from_email is None:
- self._table[canonical_name, None] = canonical_identity
- self._table[None, canonical_email] = canonical_identity
- else:
- self._table[from_name, from_email] = canonical_identity
- def lookup(self, identity):
- """Lookup an identity in this mailmail."""
- if not isinstance(identity, tuple):
- was_tuple = False
- identity = parse_identity(identity)
- else:
- was_tuple = True
- for query in [identity, (None, identity[1]), (identity[0], None)]:
- canonical_identity = self._table.get(query)
- if canonical_identity is not None:
- identity = (
- canonical_identity[0] or identity[0],
- canonical_identity[1] or identity[1])
- break
- if was_tuple:
- return identity
- else:
- return identity[0] + b" <" + identity[1] + b">"
- @classmethod
- def from_path(cls, path):
- with open(path, 'rb') as f:
- return cls(read_mailmap(f))
|