Hello community, here is the log from the commit of package hg-git for openSUSE:Factory checked in at 2017-05-03 15:58:06 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ Comparing /work/SRC/openSUSE:Factory/hg-git (Old) and /work/SRC/openSUSE:Factory/.hg-git.new (New) ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Package is "hg-git" Wed May 3 15:58:06 2017 rev:21 rq:492464 version:0.8.6 Changes: -------- --- /work/SRC/openSUSE:Factory/hg-git/hg-git.changes 2016-08-25 09:56:40.000000000 +0200 +++ /work/SRC/openSUSE:Factory/.hg-git.new/hg-git.changes 2017-05-03 15:58:16.786996137 +0200 @@ -1,0 +2,14 @@ +Tue May 2 11:47:37 UTC 2017 - mplus...@suse.com + +- Fix download url + +------------------------------------------------------------------- +Mon May 1 07:32:10 UTC 2017 - devel...@develop7.info + +- update to v0.8.6 + * Support Mercurial 4.2-rc + * Bugfixes +- enable tests back +- source verification added + +------------------------------------------------------------------- Old: ---- hg-git-0.8.5.tar.gz New: ---- hg-git-0.8.6.tar.gz hg-git-0.8.6.tar.gz.asc hg-git.keyring ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ Other differences: ------------------ ++++++ hg-git.spec ++++++ --- /var/tmp/diff_new_pack.xp6ySa/_old 2017-05-03 15:58:17.626877569 +0200 +++ /var/tmp/diff_new_pack.xp6ySa/_new 2017-05-03 15:58:17.630877004 +0200 @@ -1,7 +1,7 @@ # # spec file for package hg-git # -# Copyright (c) 2016 SUSE LINUX GmbH, Nuernberg, Germany. +# Copyright (c) 2017 SUSE LINUX GmbH, Nuernberg, Germany. # # All modifications and additions to the file contributed by third parties # remain the property of their copyright owners, unless otherwise agreed @@ -17,13 +17,15 @@ Name: hg-git -Version: 0.8.5 +Version: 0.8.6 Release: 0 Summary: Mercurial Plugin for Communicating with Git Servers License: GPL-2.0+ Group: Development/Tools/Version Control Url: https://hg-git.github.io -Source0: https://pypi.python.org/packages/source/h/hg-git/hg-git-%{version}.tar.gz +Source0: https://pypi.python.org/packages/c7/15/ec7e1bb6356cb140d5c1c2a2884fcadfd51c0039a6fccb08688c67646eba/hg-git-0.8.6.tar.gz +Source1: https://pypi.python.org/packages/c7/15/ec7e1bb6356cb140d5c1c2a2884fcadfd51c0039a6fccb08688c67646eba/hg-git-0.8.6.tar.gz.asc +Source2: %{name}.keyring BuildRequires: git-daemon BuildRequires: mercurial BuildRequires: netcat-openbsd @@ -52,10 +54,10 @@ python setup.py build %check -# export PYTHONPATH="%{buildroot}%{python_sitelib}" -# pushd tests -# python run-tests.py --verbose --with-hg=%{_bindir}/hg -# popd +export PYTHONPATH="%{buildroot}%{python_sitelib}" +pushd tests +python run-tests.py --verbose --with-hg=%{_bindir}/hg +popd %install python setup.py install --prefix=%{_prefix} --root=%{buildroot} ++++++ hg-git-0.8.5.tar.gz -> hg-git-0.8.6.tar.gz ++++++ diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/hg-git-0.8.5/PKG-INFO new/hg-git-0.8.6/PKG-INFO --- old/hg-git-0.8.5/PKG-INFO 2016-02-02 01:59:49.000000000 +0100 +++ new/hg-git-0.8.6/PKG-INFO 2017-04-19 06:43:10.000000000 +0200 @@ -1,6 +1,6 @@ Metadata-Version: 1.0 Name: hg-git -Version: 0.8.5 +Version: 0.8.6 Summary: push to and pull from a Git repository using Mercurial Home-page: http://hg-git.github.com/ Author: Augie Fackler diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/hg-git-0.8.5/hg_git.egg-info/PKG-INFO new/hg-git-0.8.6/hg_git.egg-info/PKG-INFO --- old/hg-git-0.8.5/hg_git.egg-info/PKG-INFO 2016-02-02 01:59:49.000000000 +0100 +++ new/hg-git-0.8.6/hg_git.egg-info/PKG-INFO 2017-04-19 06:43:09.000000000 +0200 @@ -1,6 +1,6 @@ Metadata-Version: 1.0 Name: hg-git -Version: 0.8.5 +Version: 0.8.6 Summary: push to and pull from a Git repository using Mercurial Home-page: http://hg-git.github.com/ Author: Augie Fackler diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/hg-git-0.8.5/hg_git.egg-info/requires.txt new/hg-git-0.8.6/hg_git.egg-info/requires.txt --- old/hg-git-0.8.5/hg_git.egg-info/requires.txt 2016-02-02 01:59:49.000000000 +0100 +++ new/hg-git-0.8.6/hg_git.egg-info/requires.txt 2017-04-19 06:43:09.000000000 +0200 @@ -1 +1 @@ -dulwich>=0.9.7 \ No newline at end of file +dulwich>=0.9.7 diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/hg-git-0.8.5/hggit/__init__.py new/hg-git-0.8.6/hggit/__init__.py --- old/hg-git-0.8.5/hggit/__init__.py 2016-02-02 01:57:10.000000000 +0100 +++ new/hg-git-0.8.6/hggit/__init__.py 2017-04-19 06:41:08.000000000 +0200 @@ -30,6 +30,7 @@ from bisect import insort from git_handler import GitHandler from mercurial.node import hex +from mercurial.error import LookupError from mercurial.i18n import _ from mercurial import ( bundlerepo, @@ -76,9 +77,10 @@ 'collections', ]) -__version__ = '0.8.5' +__version__ = '0.8.6' -testedwith = '2.8.2 3.0.1 3.1 3.2.2 3.3 3.4 3.5 3.6 3.7' +testedwith = ('2.8.2 2.9.2 3.0.2 3.1.2 3.2.4 3.3.3 3.4.2 3.5.2 3.6.3 3.7.3' + '3.8.4 3.9.2 4.0.2 4.1.3 4.2-rc') buglink = 'https://bitbucket.org/durin42/hg-git/issues' cmdtable = {} @@ -207,7 +209,9 @@ if not isinstance(repo, gitrepo.gitrepo): if (getattr(dirstate, 'rootcache', False) and - (not ignoremod or getattr(ignore, 'readpats', False))): + (not ignoremod or getattr(ignore, 'readpats', False)) and + hgutil.safehasattr(repo, 'join') and + os.path.exists(repo.vfs.join('git'))): # only install our dirstate wrapper if it has a hope of working import gitdirstate if ignoremod: @@ -258,11 +262,11 @@ def git_cleanup(ui, repo): '''clean up Git commit map after history editing''' new_map = [] - for line in repo.opener(GitHandler.map_file): + for line in repo.vfs(GitHandler.map_file): gitsha, hgsha = line.strip().split(' ', 1) if hgsha in repo: new_map.append('%s %s\n' % (gitsha, hgsha)) - f = repo.opener(GitHandler.map_file, 'wb') + f = repo.vfs(GitHandler.map_file, 'wb') map(f.write, new_map) ui.status(_('git commit map cleaned\n')) @@ -379,7 +383,9 @@ def revset_gitnode(repo, subset, x): '''``gitnode(hash)`` - Select changesets that originate in the given Git revision. + Select the changeset that originates in the given Git revision. The hash + may be abbreviated: `gitnode(a5b)` selects the revision whose Git hash + starts with `a5b`. Aborts if multiple changesets match the abbreviation. ''' args = revset.getargs(x, 1, 1, "gitnode takes one argument") rev = revset.getstring(args[0], @@ -391,8 +397,11 @@ gitnode = git.map_git_get(hex(node(r))) if gitnode is None: return False - return rev in [gitnode, gitnode[:12]] - return baseset(r for r in subset if matches(r)) + return gitnode.startswith(rev) + result = baseset(r for r in subset if matches(r)) + if 0 <= len(result) < 2: + return result + raise LookupError(rev, git.map_file, _('ambiguous identifier')) def gitnodekw(**args): """:gitnode: String. The Git changeset identification hash, as a 40 hexadecimal digit string.""" diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/hg-git-0.8.5/hggit/compat.py new/hg-git-0.8.6/hggit/compat.py --- old/hg-git-0.8.5/hggit/compat.py 2015-12-31 21:39:40.000000000 +0100 +++ new/hg-git-0.8.6/hggit/compat.py 2017-03-12 00:49:00.000000000 +0100 @@ -1,3 +1,8 @@ +from mercurial import ( + url, + util as hgutil, +) + try: from mercurial import encoding hfsignoreclean = encoding.hfsignoreclean @@ -22,3 +27,36 @@ for c in _ignore: s = s.replace(c, '') return s + +def passwordmgr(ui, passwddb): + try: + return url.passwordmgr(ui, + hgutil.urlreq.httppasswordmgrwithdefaultrealm()) + except TypeError: + # compat with hg < 3.9 + return url.passwordmgr(ui) + +# dulwich doesn't return the symref where remote HEAD points, so we monkey +# patch it here +from dulwich.errors import GitProtocolError +from dulwich.protocol import extract_capabilities + +def read_pkt_refs(proto): + server_capabilities = None + refs = {} + # Receive refs from server + for pkt in proto.read_pkt_seq(): + (sha, ref) = pkt.rstrip('\n').split(None, 1) + if sha == 'ERR': + raise GitProtocolError(ref) + if server_capabilities is None: + (ref, server_capabilities) = extract_capabilities(ref) + symref = 'symref=HEAD:' + for cap in server_capabilities: + if cap.startswith(symref): + sha = cap.replace(symref, '') + refs[ref] = sha + + if len(refs) == 0: + return None, set([]) + return refs, set(server_capabilities) diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/hg-git-0.8.5/hggit/git2hg.py new/hg-git-0.8.6/hggit/git2hg.py --- old/hg-git-0.8.5/hggit/git2hg.py 2015-12-31 21:39:40.000000000 +0100 +++ new/hg-git-0.8.6/hggit/git2hg.py 2017-03-12 00:49:33.000000000 +0100 @@ -22,10 +22,10 @@ def get_heads(refs): todo = [] seenheads = set() - for sha in refs.itervalues(): + for ref, sha in refs.iteritems(): # refs could contain refs on the server that we haven't pulled down - # the objects for - if sha in git_object_store: + # the objects for; also make sure it's a sha and not a symref + if ref != 'HEAD' and sha in git_object_store: obj = git_object_store[sha] while isinstance(obj, Tag): obj_type, sha = obj.object diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/hg-git-0.8.5/hggit/git_handler.py new/hg-git-0.8.6/hggit/git_handler.py --- old/hg-git-0.8.5/hggit/git_handler.py 2016-01-20 00:12:41.000000000 +0100 +++ new/hg-git-0.8.6/hggit/git_handler.py 2017-04-19 05:21:45.000000000 +0200 @@ -27,6 +27,7 @@ ) import _ssh +import compat import git2hg import hg2git import util @@ -107,7 +108,7 @@ if ui.configbool('git', 'intree'): self.gitdir = self.repo.wjoin('.git') else: - self.gitdir = self.repo.join('git') + self.gitdir = self.repo.vfs.join('git') self.init_author_file() @@ -181,8 +182,8 @@ def load_map(self): map_git_real = {} map_hg_real = {} - if os.path.exists(self.repo.join(self.map_file)): - for line in self.repo.opener(self.map_file): + if os.path.exists(self.repo.vfs.join(self.map_file)): + for line in self.repo.vfs(self.map_file): # format is <40 hex digits> <40 hex digits>\n if len(line) != 82: raise ValueError( @@ -196,7 +197,7 @@ self._map_hg_real = map_hg_real def save_map(self, map_file): - file = self.repo.opener(map_file, 'w+', atomictemp=True) + file = self.repo.vfs(map_file, 'w+', atomictemp=True) map_hg = self._map_hg buf = cStringIO.StringIO() bwrite = buf.write @@ -209,13 +210,13 @@ def load_tags(self): self.tags = {} - if os.path.exists(self.repo.join(self.tags_file)): - for line in self.repo.opener(self.tags_file): + if os.path.exists(self.repo.vfs.join(self.tags_file)): + for line in self.repo.vfs(self.tags_file): sha, name = line.strip().split(' ', 1) self.tags[name] = sha def save_tags(self): - file = self.repo.opener(self.tags_file, 'w+', atomictemp=True) + file = self.repo.vfs(self.tags_file, 'w+', atomictemp=True) for name, sha in sorted(self.tags.iteritems()): if not self.repo.tagtype(name) == 'global': file.write("%s %s\n" % (sha, name)) @@ -260,6 +261,9 @@ refs = self.fetch_pack(remote, heads) remote_name = self.remote_name(remote) + # if remote returns a symref for HEAD, then let's store that + rhead = None + rnode = None oldheads = self.repo.changelog.heads() imported = 0 if refs: @@ -267,6 +271,20 @@ imported = self.import_git_objects(remote_name, filteredrefs) self.import_tags(refs) self.update_hg_bookmarks(refs) + + try: + symref = refs['HEAD'] + if symref.startswith('refs/heads'): + rhead = symref.replace('refs/heads/', '') + + rnode = refs['refs/heads/%s' % rhead] + rnode = self._map_git[rnode] + rnode = self.repo[rnode].node() + except KeyError: + # if there is any error make sure to clear the variables + rhead = None + rnode = None + if remote_name: self.update_remote_branches(remote_name, refs) elif not self.paths: @@ -276,6 +294,15 @@ # "Activate" a tipmost bookmark. bms = self.repo['tip'].bookmarks() + # override the 'tipmost' behavior if we know the remote HEAD + if rnode: + # make sure the bookmark exists; at the point the remote + # branches has already been set up + suffix = self.branch_bookmark_suffix or '' + self.repo._bookmarks[rhead + suffix] = rnode + util.recordbookmarks(self.repo, self.repo._bookmarks) + bms = [rhead + suffix] + if bms: try: bookmarks.activate(self.repo, bms[0]) @@ -375,7 +402,7 @@ return ret def clear(self): - mapfile = self.repo.join(self.map_file) + mapfile = self.repo.vfs.join(self.map_file) if os.path.exists(self.gitdir): for root, dirs, files in os.walk(self.gitdir, topdown=False): for name in files: @@ -410,13 +437,27 @@ # CHANGESET CONVERSION METHODS def export_git_objects(self): + self.ui.note(_("finding hg commits to export\n")) repo = self.repo clnode = repo.changelog.node + nodes = (clnode(n) for n in repo) - export = (repo[node] for node in nodes if not hex(node) in + to_export = (repo[node] for node in nodes if not hex(node) in self._map_hg) - export = [ctx for ctx in export - if ctx.extra().get('hg-git', None) != 'octopus'] + + todo_total = len(repo) - len(self._map_hg) + topic = 'find commits to export' + pos = 0 + unit = 'commits' + + export = [] + for ctx in to_export: + item = hex(ctx.node()) + pos += 1 + repo.ui.progress(topic, pos, item, unit, todo_total) + if ctx.extra().get('hg-git', None) != 'octopus': + export.append(ctx) + total = len(export) if not total: return @@ -444,11 +485,20 @@ exporter = hg2git.IncrementalChangesetExporter( self.repo, pctx, self.git.object_store, gitcommit) + mapsavefreq = self.ui.configint('hggit', 'mapsavefrequency', 0) for i, ctx in enumerate(export): self.ui.progress('exporting', i, total=total) self.export_hg_commit(ctx.node(), exporter) + if mapsavefreq and i % mapsavefreq == 0: + self.ui.debug(_("saving mapfile\n")) + self.save_map(self.map_file) self.ui.progress('exporting', None, total=total) + def set_commiter_from_author(self, commit): + commit.committer = commit.author + commit.commit_time = commit.author_time + commit.commit_timezone = commit.author_timezone + # convert this commit into git objects # go through the manifest, convert all blobs/trees we don't have # write the commit object (with metadata info) @@ -474,25 +524,26 @@ commit.author_timezone = -timezone if 'committer' in extra: - # fixup timezone - (name, timestamp, timezone) = extra['committer'].rsplit(' ', 2) - commit.committer = name - commit.commit_time = timestamp - - # work around a timezone format change - if int(timezone) % 60 != 0: # pragma: no cover - timezone = parse_timezone(timezone) - # Newer versions of Dulwich return a tuple here - if isinstance(timezone, tuple): - timezone, neg_utc = timezone - commit._commit_timezone_neg_utc = neg_utc - else: - timezone = -int(timezone) - commit.commit_timezone = timezone + try: + # fixup timezone + (name, timestamp, timezone) = extra['committer'].rsplit(' ', 2) + commit.committer = name + commit.commit_time = timestamp + + # work around a timezone format change + if int(timezone) % 60 != 0: # pragma: no cover + timezone = parse_timezone(timezone) + # Newer versions of Dulwich return a tuple here + if isinstance(timezone, tuple): + timezone, neg_utc = timezone + commit._commit_timezone_neg_utc = neg_utc + else: + timezone = -int(timezone) + commit.commit_timezone = timezone + except: # extra is essentially user-supplied, we must be careful + self.set_commiter_from_author(commit) else: - commit.committer = commit.author - commit.commit_time = commit.author_time - commit.commit_timezone = commit.author_timezone + self.set_commiter_from_author(commit) commit.parents = [] for parent in self.get_git_parents(ctx): @@ -981,7 +1032,7 @@ for rev in (hex(r) for r in revs): if rev not in all_exportable: raise hgutil.Abort("revision %s cannot be pushed since" - " it doesn't have a ref" % + " it doesn't have a bookmark" % self.repo[rev]) exportable[rev] = all_exportable[rev] return self.get_changed_refs(refs, exportable, force) @@ -1069,7 +1120,7 @@ ctx = self.repo[rev] if not rev_refs: raise hgutil.Abort("revision %s cannot be pushed since" - " it doesn't have a ref" % ctx) + " it doesn't have a bookmark" % ctx) # Check if the tags the server is advertising are annotated tags, # by attempting to retrieve it from the our git repo, and building @@ -1135,6 +1186,10 @@ try: progress = GitProgress(self.ui) f = StringIO.StringIO() + + # monkey patch dulwich's read_pkt_refs so that we can determine on + # clone which bookmark to activate + client.read_pkt_refs = compat.read_pkt_refs ret = localclient.fetch_pack(path, determine_wants, graphwalker, f.write, progress.progress) if(f.pos != 0): @@ -1456,6 +1511,7 @@ gitlinks[oldfile] = None continue if newfile is not None: + self.audit_hg_path(newfile) # new = file files[newfile] = False, newmode, newsha if renames is not None and newfile != oldfile: @@ -1538,6 +1594,18 @@ if names: return names[0] + def audit_hg_path(self, path): + if '.hg' in path.split(os.path.sep): + if self.ui.configbool('git', 'blockdothg', True): + raise hgutil.Abort( + ('Refusing to import problematic path %r' % path), + hint=("Mercurial cannot check out paths inside nested " + + "repositories; if you need to continue, then set " + + "'[git] blockdothg = false' in your hgrc.")) + self.ui.warn(('warning: path %r is within a nested repository, ' + + 'which Mercurial cannot check out.\n') + % path) + # Stolen from hgsubversion def swap_out_encoding(self, new_encoding='UTF-8'): try: @@ -1614,7 +1682,10 @@ uri = uri[4:] if uri.startswith('http://') or uri.startswith('https://'): - auth = urllib2.HTTPBasicAuthHandler(url.passwordmgr(self.ui)) + realm = hgutil.urlreq.httppasswordmgrwithdefaultrealm() + pmgr = compat.passwordmgr(self.ui, realm) + auth = urllib2.HTTPBasicAuthHandler(pmgr) + opener = urllib2.build_opener(auth) ua = 'git/20x6 (hg-git ; uses dulwich and hg ; like git-core)' opener.addheaders = [('User-Agent', ua)] diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/hg-git-0.8.5/hggit/overlay.py new/hg-git-0.8.6/hggit/overlay.py --- old/hg-git-0.8.5/hggit/overlay.py 2015-12-31 21:45:21.000000000 +0100 +++ new/hg-git-0.8.6/hggit/overlay.py 2017-04-19 05:13:41.000000000 +0200 @@ -6,8 +6,11 @@ from mercurial import ( ancestor, + changelog, manifest, + match as matchmod, context, + util, ) from mercurial.node import bin, hex, nullid @@ -97,7 +100,13 @@ self.load() return self._map.get(path, default) - def diff(self, m2, clean=False): + def diff(self, m2, match=None, clean=False): + # Older mercurial clients used diff(m2, clean=False). If a caller failed + # to specify clean as a keyword arg, it might get passed as match here. + if isinstance(match, bool): + clean = match + match = None + self.load() if isinstance(m2, overlaymanifest): m2.load() @@ -111,7 +120,11 @@ # Mercurial <= 3.3 m2flagget = m2._flags.get + if match is None: + match = matchmod.always('', '') for fn, n1 in self.iteritems(): + if not match(fn): + continue fl1 = self._flags.get(fn, '') n2 = m2.get(fn, None) fl2 = m2flagget(fn, '') @@ -124,6 +137,8 @@ for fn, n2 in m2.iteritems(): if fn not in self: + if not match(fn): + continue fl2 = m2flagget(fn, '') diff[fn] = ((None, ''), (n2, fl2)) @@ -132,17 +147,30 @@ def __delitem__(self, path): del self._map[path] -def wrapmanifestdictdiff(orig, self, m2, clean=False): +def wrapmanifestdictdiff(orig, self, m2, match=None, clean=False): '''avoid calling into lazymanifest code if m2 is an overlaymanifest''' + # Older mercurial clients used diff(m2, clean=False). If a caller failed + # to specify clean as a keyword arg, it might get passed as match here. + if isinstance(match, bool): + clean = match + match = None + + kwargs = { + 'clean' : clean + } + # Older versions of mercurial don't support the match arg, so only add it if + # it exists. + if match is not None: + kwargs['match'] = match if isinstance(m2, overlaymanifest): - diff = m2.diff(self, clean=clean) + diff = m2.diff(self, **kwargs) # since we calculated the diff with m2 vs m1, flip it around for fn in diff: c1, c2 = diff[fn] diff[fn] = c2, c1 return diff else: - return orig(self, m2, clean=clean) + return orig(self, m2, **kwargs) class overlayfilectx(object): def __init__(self, repo, path, fileid=None): @@ -307,12 +335,46 @@ def __len__(self): return len(self.repo.handler.repo) + len(self.repo.revmap) -class overlaymanifestlog(overlayrevlog): +class overlayoldmanifestlog(overlayrevlog): def read(self, sha): if sha == nullid: return manifest.manifestdict() return overlaymanifest(self.repo, sha) + def __getitem__(self, sha): + return overlaymanifestctx(self.repo, sha) + +class overlaymanifestrevlog(overlayrevlog): + pass + +class overlaymanifestctx(object): + def __init__(self, repo, node): + self._repo = repo + self._node = node + + def read(self): + return overlaymanifest(self._repo, self._node) + +try: + class overlaymanifestlog(manifest.manifestlog): + def __init__(self, repo): + self._repo = repo + + # Needed for 4.0, since __getitem__ did not redirect to get() in that + # release. + def __getitem__(self, node): + return self.get('', node) + + def get(self, dir, node): + if dir: + raise RuntimeError("hggit doesn't support treemanifests") + if node == nullid: + return manifest.manifestctx() + return overlaymanifestctx(self._repo, node) +except AttributeError: + # manifestlog did not exist prior to 4.0 + pass + class overlaychangelog(overlayrevlog): def read(self, sha): if isinstance(sha, int): @@ -324,12 +386,21 @@ except LookupError: return overlaychangectx(self.repo, sha).totuple() + def changelogrevision(self, noderev): + return changelog._changelogrevision(*self.read(noderev)) + class overlayrepo(object): def __init__(self, handler, commits, refs): self.handler = handler self.changelog = overlaychangelog(self, handler.repo.changelog) - self.manifest = overlaymanifestlog(self, handler.repo.manifest) + if util.safehasattr(handler.repo, 'manifest'): + self.manifest = overlayoldmanifestlog(self, handler.repo.manifest) + # new as of mercurial 3.9+ + self.manifestlog = self.manifest + else: + # no more manifest class as of 4.1 + self.manifestlog = overlaymanifestlog(self) # for incoming -p self.root = handler.repo.root @@ -351,6 +422,10 @@ except (AttributeError, ImportError): pass + def _constructmanifest(self): + return overlaymanifestrevlog(self, + self.handler.repo._constructmanifest()) + def __getitem__(self, n): if n not in self.revmap: return self.handler.repo[n] @@ -396,6 +471,9 @@ def filectx(self, path, fileid=None): return overlayfilectx(self, path, fileid=fileid) + def unfiltered(self): + return self.handler.repo.unfiltered() + def _makemaps(self, commits, refs): baserev = self.handler.repo['tip'].rev() self.revmap = {} diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/hg-git-0.8.5/setup.cfg new/hg-git-0.8.6/setup.cfg --- old/hg-git-0.8.5/setup.cfg 2016-02-02 01:59:49.000000000 +0100 +++ new/hg-git-0.8.6/setup.cfg 2017-04-19 06:43:10.000000000 +0200 @@ -1,5 +1,4 @@ [egg_info] tag_build = tag_date = 0 -tag_svn_revision = 0 diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/hg-git-0.8.5/tests/test-extra.t new/hg-git-0.8.6/tests/test-extra.t --- old/hg-git-0.8.5/tests/test-extra.t 2014-12-30 23:21:25.000000000 +0100 +++ new/hg-git-0.8.6/tests/test-extra.t 2017-03-12 00:49:38.000000000 +0100 @@ -15,7 +15,7 @@ $ cd hgrepo $ hg mv a b $ fn_hg_commit -mb - $ hg up 0 | egrep -v '^\(leaving bookmark master\)$' + $ hg up 0 | egrep -v '^\(leaving bookmark' 1 files updated, 0 files merged, 1 files removed, 0 files unresolved $ touch c $ hg add c @@ -68,7 +68,7 @@ $ hg mv 'c2 => c3' 'c3 => c4' warning: filename contains '>', which is reserved on Windows: 'c3 => c4' $ fn_hg_commit -m 'test filename with arrow 2' - $ hg log --graph --template "{rev} {node} {desc|firstline}\n{join(extras, ' ')}\n\n" -l 3 + $ hg log --graph --template "{rev} {node} {desc|firstline}\n{join(extras, ' ')}\n\n" -l 3 --config "experimental.graphstyle.missing=|" @ 6 bca4ba69a6844c133b069e227dfa043d41e3c197 test filename with arrow 2 | branch=default | diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/hg-git-0.8.5/tests/test-gitignore.t new/hg-git-0.8.6/tests/test-gitignore.t --- old/hg-git-0.8.5/tests/test-gitignore.t 2015-06-01 20:42:50.000000000 +0200 +++ new/hg-git-0.8.6/tests/test-gitignore.t 2016-09-03 03:42:01.000000000 +0200 @@ -5,6 +5,11 @@ $ hg init +We should only read .gitignore files in a hg-git repo (i.e. one with .hg/git +directory) otherwise, a rogue .gitignore could slow down a hg-only repo + + $ mkdir .hg/git + $ touch foo $ touch foobar $ touch bar diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/hg-git-0.8.5/tests/test-hg-author.t new/hg-git-0.8.6/tests/test-hg-author.t --- old/hg-git-0.8.5/tests/test-hg-author.t 2015-03-12 23:50:25.000000000 +0100 +++ new/hg-git-0.8.6/tests/test-hg-author.t 2017-03-12 00:49:38.000000000 +0100 @@ -16,8 +16,7 @@ 1 files updated, 0 files merged, 0 files removed, 0 files unresolved $ cd hgrepo - $ hg co master | egrep -v '^\(activating bookmark master\)$' - 0 files updated, 0 files merged, 0 files removed, 0 files unresolved + $ hg book master $ echo beta > beta $ hg add beta $ fn_hg_commit -u "test" -m 'add beta' diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/hg-git-0.8.5/tests/test-illegal-contents.t new/hg-git-0.8.6/tests/test-illegal-contents.t --- old/hg-git-0.8.5/tests/test-illegal-contents.t 2015-01-27 01:07:54.000000000 +0100 +++ new/hg-git-0.8.6/tests/test-illegal-contents.t 2016-04-18 19:15:27.000000000 +0200 @@ -90,3 +90,28 @@ (If you need to continue, read about CVE-2014-9390 and then set '[git] blockdotgit = false' in your hgrc.) [255] $ cd .. + +Now check a Git repository containing a Mercurial repository, which +you can't check out. + + $ rm -rf hg git nested + $ git init -q git + $ hg init nested + $ mv nested git + $ cd git + $ git add nested + $ fn_git_commit -m 'add a Mercurial repository' + $ cd .. + $ hg clone git hg + importing git objects into hg + abort: Refusing to import problematic path 'nested/.hg/00changelog.i' + (Mercurial cannot check out paths inside nested repositories; if you need to continue, then set '[git] blockdothg = false' in your hgrc.) + [255] + $ hg clone --config git.blockdothg=false git hg + importing git objects into hg + warning: path 'nested/.hg/00changelog.i' is within a nested repository, which Mercurial cannot check out. + warning: path 'nested/.hg/requires' is within a nested repository, which Mercurial cannot check out. + updating to branch default + abort: path 'nested/.hg/00changelog.i' is inside nested repo 'nested' + [255] + $ cd .. diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/hg-git-0.8.5/tests/test-keywords.t new/hg-git-0.8.6/tests/test-keywords.t --- old/hg-git-0.8.5/tests/test-keywords.t 2014-12-30 23:21:25.000000000 +0100 +++ new/hg-git-0.8.6/tests/test-keywords.t 2016-10-09 22:19:31.000000000 +0200 @@ -11,25 +11,37 @@ $ git add beta $ fn_git_commit -m 'add beta' +This commit is called gamma10 so that its hash will have the same initial digit +as commit alpha. This lets us test ambiguous abbreviated identifiers. + + $ echo gamma10 > gamma10 + $ git add gamma10 + $ fn_git_commit -m 'add gamma10' + $ cd .. $ hg clone gitrepo hgrepo | grep -v '^updating' importing git objects into hg - 2 files updated, 0 files merged, 0 files removed, 0 files unresolved + 3 files updated, 0 files merged, 0 files removed, 0 files unresolved $ cd hgrepo $ echo gamma > gamma $ hg add gamma $ hg commit -m 'add gamma' $ hg log --template "{rev} {node} {node|short} {gitnode} {gitnode|short}\n" - 2 168eb1ee8b3c04e6723c9330327b0eec1e36577f 168eb1ee8b3c + 3 965bf7d08d3ac847dd8eb9e72ee0bf547d1a65d9 965bf7d08d3a + 2 8e3f0ecc9aefd4ea2fdf8e2d5299cac548762a1c 8e3f0ecc9aef 7e2a5465ff4e3b992c429bb87a392620a0ac97b7 7e2a5465ff4e 1 7fe02317c63d9ee324d4b5df7c9296085162da1b 7fe02317c63d 9497a4ee62e16ee641860d7677cdb2589ea15554 9497a4ee62e1 0 ff7a2f2d8d7099694ae1e8b03838d40575bebb63 ff7a2f2d8d70 7eeab2ea75ec1ac0ff3d500b5b6f8a3447dd7c03 7eeab2ea75ec $ hg log --template "fromgit {rev}\n" --rev "fromgit()" fromgit 0 fromgit 1 + fromgit 2 $ hg log --template "gitnode_existsA {rev}\n" --rev "gitnode(9497a4ee62e16ee641860d7677cdb2589ea15554)" gitnode_existsA 1 - $ hg log --template "gitnode_existsB {rev}\n" --rev "gitnode(7eeab2ea75ec)" + $ hg log --template "gitnode_existsB {rev}\n" --rev "gitnode(7eeab)" gitnode_existsB 0 + $ hg log --rev "gitnode(7e)" + abort: git-mapfile@7e: ambiguous identifier! + [255] $ hg log --template "gitnode_notexists {rev}\n" --rev "gitnode(1234567890ab)" diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/hg-git-0.8.5/tests/test-push.t new/hg-git-0.8.6/tests/test-push.t --- old/hg-git-0.8.5/tests/test-push.t 2015-12-31 22:07:42.000000000 +0100 +++ new/hg-git-0.8.6/tests/test-push.t 2017-03-12 00:49:38.000000000 +0100 @@ -16,6 +16,7 @@ 1 files updated, 0 files merged, 0 files removed, 0 files unresolved $ cd hgrepo + $ hg bookmark -q master $ echo beta > beta $ hg add beta $ fn_hg_commit -m 'add beta' diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/hg-git-0.8.5/tests/test-renames.t new/hg-git-0.8.6/tests/test-renames.t --- old/hg-git-0.8.5/tests/test-renames.t 2016-01-20 00:13:38.000000000 +0100 +++ new/hg-git-0.8.6/tests/test-renames.t 2017-04-19 05:01:18.000000000 +0200 @@ -90,6 +90,7 @@ $ cd .. $ hg clone -q gitrepo hgrepo $ cd hgrepo + $ hg book master -q $ hg log -p --graph --template "{rev} {node} {desc|firstline}\n{join(extras, ' ')}\n\n" @ 8 a26f94023ab2ea40c9e4c4dbb753c9a4e572fefe remove submodule and rename back | branch=default hg-git-rename-source=git @@ -405,6 +406,7 @@ $ cd .. $ hg clone -q gitrepo hgrepo2 $ cd hgrepo2 + $ hg book master -qf $ hg export master # HG changeset patch # User test @@ -452,3 +454,145 @@ e1348449e0c3a417b086ed60fc13f068d4aa8b26 gamma cc83241f39927232f690d370894960b0d1943a0e beta 938bb65bb322eb4a3558bec4cdc8a680c4d1794c alpha + +Test findcopiesharder + + $ cd $TESTTMP + $ git init -q gitcopyharder + $ cd gitcopyharder + $ cat >> file0 << EOF + > 1 + > 2 + > 3 + > 4 + > 5 + > EOF + $ git add file0 + $ fn_git_commit -m file0 + $ cp file0 file1 + $ git add file1 + $ fn_git_commit -m file1 + $ cp file0 file2 + $ echo 6 >> file2 + $ git add file2 + $ fn_git_commit -m file2 + + $ cd .. + +Clone without findcopiesharder does not find copies from unmodified files + + $ hg clone gitcopyharder hgnocopyharder + importing git objects into hg + updating to branch default + 3 files updated, 0 files merged, 0 files removed, 0 files unresolved + $ hg -R hgnocopyharder export 1::2 + # HG changeset patch + # User test <t...@example.org> + # Date 1167609621 0 + # Mon Jan 01 00:00:21 2007 +0000 + # Node ID 555831c93e2a250e5ba42efad45bf7ba71da13e4 + # Parent b45d023c6842337ffe694663a44aa672d311081c + file1 + + diff --git a/file1 b/file1 + new file mode 100644 + --- /dev/null + +++ b/file1 + @@ -0,0 +1,5 @@ + +1 + +2 + +3 + +4 + +5 + # HG changeset patch + # User test <t...@example.org> + # Date 1167609622 0 + # Mon Jan 01 00:00:22 2007 +0000 + # Node ID ec77ccdbefe023eb9898b0399f84f670c8c0f5fc + # Parent 555831c93e2a250e5ba42efad45bf7ba71da13e4 + file2 + + diff --git a/file2 b/file2 + new file mode 100644 + --- /dev/null + +++ b/file2 + @@ -0,0 +1,6 @@ + +1 + +2 + +3 + +4 + +5 + +6 + +findcopiesharder finds copies from unmodified files if similarity is met + + $ hg --config git.findcopiesharder=true clone gitcopyharder hgcopyharder0 + importing git objects into hg + updating to branch default + 3 files updated, 0 files merged, 0 files removed, 0 files unresolved + $ hg -R hgcopyharder0 export 1::2 + # HG changeset patch + # User test <t...@example.org> + # Date 1167609621 0 + # Mon Jan 01 00:00:21 2007 +0000 + # Node ID cd05a87103eed9d270fc05b62b00f48e174ab960 + # Parent b45d023c6842337ffe694663a44aa672d311081c + file1 + + diff --git a/file0 b/file1 + copy from file0 + copy to file1 + # HG changeset patch + # User test <t...@example.org> + # Date 1167609622 0 + # Mon Jan 01 00:00:22 2007 +0000 + # Node ID 9b30998342729c7357d418bebed7399986cfe643 + # Parent cd05a87103eed9d270fc05b62b00f48e174ab960 + file2 + + diff --git a/file0 b/file2 + copy from file0 + copy to file2 + --- a/file0 + +++ b/file2 + @@ -3,3 +3,4 @@ + 3 + 4 + 5 + +6 + + $ hg --config git.findcopiesharder=true --config git.similarity=95 clone gitcopyharder hgcopyharder1 + importing git objects into hg + updating to branch default + 3 files updated, 0 files merged, 0 files removed, 0 files unresolved + $ hg -R hgcopyharder1 export 1::2 + # HG changeset patch + # User test <t...@example.org> + # Date 1167609621 0 + # Mon Jan 01 00:00:21 2007 +0000 + # Node ID cd05a87103eed9d270fc05b62b00f48e174ab960 + # Parent b45d023c6842337ffe694663a44aa672d311081c + file1 + + diff --git a/file0 b/file1 + copy from file0 + copy to file1 + # HG changeset patch + # User test <t...@example.org> + # Date 1167609622 0 + # Mon Jan 01 00:00:22 2007 +0000 + # Node ID d9d2e8cbf050772be31dccf78851f71dc547d139 + # Parent cd05a87103eed9d270fc05b62b00f48e174ab960 + file2 + + diff --git a/file2 b/file2 + new file mode 100644 + --- /dev/null + +++ b/file2 + @@ -0,0 +1,6 @@ + +1 + +2 + +3 + +4 + +5 + +6 diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/hg-git-0.8.5/tests/test-subrepos.t new/hg-git-0.8.6/tests/test-subrepos.t --- old/hg-git-0.8.5/tests/test-subrepos.t 2015-12-31 21:57:56.000000000 +0100 +++ new/hg-git-0.8.6/tests/test-subrepos.t 2016-09-14 21:59:56.000000000 +0200 @@ -16,11 +16,11 @@ $ git add alpha $ fn_git_commit -m 'add alpha' $ git submodule add ../gitsubrepo subrepo1 - Cloning into 'subrepo1'... + Cloning into '*subrepo1'... (glob) done. $ fn_git_commit -m 'add subrepo1' $ git submodule add ../gitsubrepo xyz/subrepo2 - Cloning into 'xyz/subrepo2'... + Cloning into '*xyz/subrepo2'... (glob) done. $ fn_git_commit -m 'add subrepo2' we are going to push to this repo from our hg clone, ++++++ hg-git.keyring ++++++ pub rsa4096 2013-08-05 [SC] [expires: 2018-08-04] 3A8155163D0E20A530FCB78647A67FFAA346AACE uid [ unknown] Kevin Bullock <kbull...@umn.edu> uid [ unknown] Kevin Bullock <guit...@ringworld.org> uid [ unknown] Kevin Bullock <kbull...@ringworld.org> uid [ unknown] Kevin Bullock <ke...@softwareforgood.com> uid [ unknown] Kevin Bullock <kbullock+mercur...@ringworld.org> sub rsa4096 2013-08-05 [E] [expires: 2018-08-04] -----BEGIN PGP PUBLIC KEY BLOCK----- mQINBFH/ChIBEADEajjD1+fw19RfXYGwuez6W3PL7w1NQ6AsDVyd0rqTwIGv30Z7 sO3jt4I6C39/ZcNWyI4sJOvr0RGp6NaKV+BuL4I1R/cvVpC6eV1swC3iYca1DWIZ pyHgjZt4EylXWCAljAZB85UMELKbklghYO4wMlwzwHmpFM0OasG+amFdpjvZWPWw I6ofi39exrb43+UhDJ070wlvSdrZ7hNUpCjHcEbkdoI8X1SuCB9TmYEcNzxI8pr/ /pAaRUnNwGNeDAnHC5cOWulbOSz7se4EiHtRGATXg83rQucH7XgPJO7tvSWhVXHW ZgOWVblR/5q1q8IKfD+R8ljIcHn04lO0su54D8e+4D0CgVb4XWeF82vnLMYPqoOI 8BM/kYyI5S/Kd4FF2BYU0JqXC4WZJrSOvVbMCSWF64x7R3FMYvsu8kG9/e54mMoo aV1DQeTTidVTBY1/f7XWBnsTCNsTtqfCPWL6cuqpD7gEg24wrT5lepSjmUub6bKd xOYt0M1Ku2byOjDiihqqkBTSAT34n59e8i9abV0i4IB7IeKr6Hvy2gfd68uwg/13 Cuo/tUhRn+3NUQs9BzEqE6Wo3oqGS/zxuND2Wk+WEyORvV4MjbIL7W6gSaRgomm7 63TvkTKGBrx/Srv1LNZVcjQVug45LwjLlBlHNsRJHXlfSdy4SIqnfsoIrwARAQAB tCBLZXZpbiBCdWxsb2NrIDxrYnVsbG9ja0B1bW4uZWR1PokCPgQTAQIAKAUCUf8M zgIbAwUJCWYBgAYLCQgHAwIGFQgCCQoLBBYCAwECHgECF4AACgkQR6Z/+qNGqs6i Lg//Q7WLllLFHaMEzrHnYz6TcztZVOoaU1gDljzYlPnsME4GDyJ1Eh9EE9vTbgfn FGHGMPIs4sgX/O86rV2vLif9x5y2zawi7drIYeffeDWKagWySdCV9aqJMLIUGKBH /eUqqehntuNnK82TuzhWjNn3iGJ+mU77TS+uWcF0xGlILY2Yd1V79Y+97hgqDsPG aBVN96Il/401GIHYWTfTd+Sl82Lcthtq2qNVaqMw9wfyFE4TABDt9wNqIeTRGrtP h23vNckLuIxNCJbyExfKYBlQa9AesDTjxEzKGIoAD2xQnGawBtEpgN/d9PqVb9xx IFNbBwWNGPg13TO3EssSPGwkUxE2Th0YzCA+3+bMahNhc5ZnJYU92LpnCdNo5nWs g7JpxCU3Z21ws8YijRQC4WmZo1YCjPxrHXcR4ROqzMzLKr16AAOmqCucarzI1Z5Y 2GJjqoaCXlGUpvcWb5NamUidtPrUWvJEJkbDbxqTorTk9EedTjVvg9d0vipk9o39 W2oprXBfjLwRwaTbT6nZa5U+wi8YnRnffCRUGvIBRAp9THeSlEQ8V6lEuJ7KbvSa uxTNhTlC0jMwZo90QF1CsM84+pe6hhBB5MLVrdxHsTWE02lCSdr1qctg7722lS3t nQG8QOumjw/FJ21e7g9TA9MZD4/fuiUEODwdV48n+mISnpO0JUtldmluIEJ1bGxv Y2sgPGd1aXRhcmtAcmluZ3dvcmxkLm9yZz6JAj4EEwECACgFAlH/CqYCGwMFCQlm AYAGCwkIBwMCBhUIAgkKCwQWAgMBAh4BAheAAAoJEEemf/qjRqrOB7kQAL4d1vrE GT0M+x4IHbAueHyrhd5ovC5+NfBgVaOtJ9409msymdz7rfCRot6qSwECm0wDJDup I5wqmOTi1t8JT2Hovu4tETBp9qjB6W/gCdXxwWP6wn2jwf4PcZDul4bRhzYBNRJx VECs/i97Re+v4d10tow/v5lCbrgSYL+RcM07QwvmjB7sUait74w9E5Qc+3EL/sK3 SIVlgfU49qjZEKBQhK57MDswLOWHFNfLx4swfOtUEmYnFcvNiVwmEwgBdfXhabX6 UlcpYAJGHoPEw7KBtNJhHAD6UxYomsV+5CSB+VD8toaCuxsWkSiBpv4ud901m1YH aaxCuwCjcQje4gwawMwgLVNYLO97txbetWlCmAAvQfbqGNCG+tMcJsdVaFT2e/3G hMNWO7dKnL3qBmjz+T/o7OCDkolyk/Wdo2xC49KDaH4iamGA2TkGLZLCzUvX4pIg 7mHdw3RngxO3+7BKujgCdQofRRS2p2PNDQfNRz9N1dDWuspFIGUS0Gs0AS64IvKO sGbhnff175eIey7LouW8JpphBVad6/FK76tXLkr5k6LZTSc/MbYomqxSyburcuyK 9FYxYbTWTwAUecnKLSRa2TZdXUTCJ4GSyghA2M95RL8pGTv8pkV5ZFltkU0863Cq P4gCTnzzUdvGSp228lYTw1zkkes9LnWvOBGDtCZLZXZpbiBCdWxsb2NrIDxrYnVs bG9ja0ByaW5nd29ybGQub3JnPokCPgQTAQIAKAUCUf8KEgIbAwUJCWYBgAYLCQgH AwIGFQgCCQoLBBYCAwECHgECF4AACgkQR6Z/+qNGqs6ZmxAAt87+zhW1v213lcD7 PNzJ836pPSXZby3W9NhAfMgWdYUeZ6NFwqfrakoFw5vTWgjmEAJc7Y1hAVXDBZUq ocNNMpEJ8KovFZiGArFfvSuI61joFqZSQVpOaeXkKUiJhKpmKImzACrxqDDKgSyg U++zfhvroh+4O2Fg8i03vxcRIUVa/PbLcuS6TWtYGkjYGJvoTETTSBHqm3aTd76a 3BqJdwNBSzD4tpZUk08OBc5Rcc8b1tXQ6U8YsVuEiF/Q2ozeu3lWBI5iKW2kq2AO 6/0p7YrwR2XeZRWnLYbL7hvIDL5+6cxpNf7oWkn1gmls+SlWOlzMJfnT86YcBC8p cnhjvV5NTYFONkEScsRyoypxIRkX+oGVCq8j7w+5WXgAvnWyMGgyqIRLp2s05NEl hN27nM2I2IdYyxrWop2ghHFYBWJ09VUUMQ/imN4fz2eRw8DCa96++5fJJFKNXVeO m37UvzlsAGQNoq0XqSWAA2NI8Npf5Vw34TzhLErU0oKIaD+Nafnzw0X7LO6sTBKf 6By2eMK6BEedk0iZvsfKoxitBArjZzOEB+xUGYVw9//fnrmqBALb1LURUfK0tAaD jPFO03BHHvHj5AqSfoLYPc+/Mv7SQM5UAjrrOaC2mbtKnVQgy724ChDg19QXgRt9 wO9ZUDlwH8JK1TTkgIEJ6QZ+fYq0KUtldmluIEJ1bGxvY2sgPGtldmluQHNvZnR3 YXJlZm9yZ29vZC5jb20+iQI+BBMBAgAoBQJR/wqWAhsDBQkJZgGABgsJCAcDAgYV CAIJCgsEFgIDAQIeAQIXgAAKCRBHpn/6o0aqzvhxD/0Q+kcNXDCp0aSBuZPzLGcN MQPbfeSOgkJCueWBF0hLrhd2vZKe+8DSZS+GlIIQClWl0bKD+/bfolnilBpsyVrQ nCUtu9wgBNI9ZxtBm8uhCLg+E7QDL4VFiq9Dg0d2KOaP3QenrLVOgns8kR/BjLPi 9xGRZNNQe0KUGta42Rn27NYFX3Hl5Xy+df2N7klQtRnw6evwxY9rdpV6y1V2cBq9 0uR1/siDbiJ2rzdzJWteC07Fo0957jHmmNosUIi8jMnrycXyfoGfqH77FLYt6vpx X2lVJOZlLgcqBcEqVF814E9FPWTegRY8doMV1MXjwAWOtGf2UJN69BVEySCUxRIw A60TGGKZOy0HCOgF+/OskHZUTSUtMTRUPc9rIbUMOrv/InjThfvSHE6YBpgzW0xm OSw68IUiK9ixtrP9VXNnDiwzFZk5DFxDDwQn6ZkH7yNBcnw55ttIgnyraMjSc7zl E2yL2VEh6dwxMH01yzMe5u96SvB/heYRs0iM7e9ADq3hJqrLq+PwiVt3v932O9oI uO9vr761e8gK2mvYp4t/UjhdAStMNU4w93lDolj5fDHPXaYQaXhTgdaP49xv7zya 92TQ85vb9MLIDBfltRBGGdrN1SW60qYnd8+zYvSnHs+vLFNr496jmOYv5I0p7hrK GWNdC/HRxniVSw0MKPInk7QwS2V2aW4gQnVsbG9jayA8a2J1bGxvY2srbWVyY3Vy aWFsQHJpbmd3b3JsZC5vcmc+iQI+BBMBAgAoBQJR/wqFAhsDBQkJZgGABgsJCAcD AgYVCAIJCgsEFgIDAQIeAQIXgAAKCRBHpn/6o0aqzmCxEACha7nLAgbyt9UNgqeX 6sUyIU1Ms8uS4H9lng+ynYQ8bW4j8tiejbbwwleWw9GwaFYw1JmspU1Sa+pDs/aj 6YBZzHt+NW1t3DKEJ18JATs1Pi0ynmMINwCU1tN3bgCq9TQQaJ/OUV67xquDChgt ItZ7D4hM/dBgTOsK48XXPOJA7+wzOXRL1DdweRNDOe2N7DqllKDInrPQLlMUvRB1 o7EUBFZDiDpvn39ioNWiF735nJS+XKzzjIAr5va2MX3VCx17Dm1yVkCGRr4xburJ JvWVkdyzDfihTdZUp7+suleA88ehGuZxNjhmLgyGyhIuxFNaQM4LWOdEFk5opnMc cJ9SXOaET2wwoV0Wv+RMK6785hleTGoibd0xVQPGUZWB6HzPGs9jx4WCPaocpNcK BYqAxxsbi71ctaqIFf8kQdCNgW4W08N+yvLevP6AnLlHJHPkBlo3d6k0KODXx4TM 0vTFmpDE15hjQlV/APsC9BFdna9o/4tZ3o/mnCZrl9FAn+s24cApLfvn+Fu9P9j0 qC0wfaoQYk4LBvOkp6r3adLfXmvjJ7d0hC7XjnvBYSqMJZfdM/g0tsZGwEZGCIs3 bb1Vc7BUwTLabUTrd4paE2R2n9w7QKctKMYhkhxhRtiI0RD4J6USxVpTUI3Vyn/L l4nGt66JJXzsTv1ewCYzlpmPL7kCDQRR/woSARAArTfmbtQazuuqHyM4D6VsvLnC Ht2MDare1L4hPqT33afJBTKJXtMwCGMhx4vq7snBPKovuMIv81ueDNMsgz3tPE/b UKvcJkdJsu1wJkxpqNBG7E877T6kzQlFG3dDm269Ig1q11ujlzLyoJWYDeIGnYoy 9qmAw+PpG7BVut+RTW2zOFJ/6GQt3CyllF1b75H9UvyxRI+QxGfZtyHyYKhNzUxc 08dMZgCNHmHfdBTNxH1kpQMs/1GpHbCzjeV65fw1AzSRR1HeHAW0L+kqL5B3J8WV iwAu0d6loUvQlhr/4w6cwDsuU5ftSe4Yi/mmwx0hXdfscBOOAFrItBoQ+bVQo87Y daJVAFnuXs1ll0s61BXes2mZsHlCUscNkzt0/v8tmuVcWRCKyVZHUuczXFmo8ZwM cf/nsRBbpprxlUNrkx5r3O3z1HRcOF37jWDim9OlL675RodXoyU8ShVVTsBw6Gp3 YaVcIjxuzYXUJ72LTVETw0GYZvXw4pwKaU44nsL06BADbeg2wchoFiva43dhaqXX DLjB0WMO7+3byAAZ3rHtJFy104lTNjZDC/GBJ2VuZOzkx1avL3DbSkwVDtTxe7kD xZ11LgmDzoEVp079k25r1TcEcQJdmSiO9pHmsQ7k9rjzoHWEue2AZUzt2qoDB4r9 4UgQaG9zztsiF0W3jNkAEQEAAYkCJQQYAQIADwUCUf8KEgIbDAUJCWYBgAAKCRBH pn/6o0aqzl2kD/4vLg53w7EwI7AUUTkwvNIV4ju1uNwNYJeYTPqt77QzDWLSzugz JboyzaxAC9wWV89d2UluMMa/991CvnfGBz6cldUuuzX+Pz/DMS9DdiN2M39PIqkz ciXGP5xglILP2hYexBRjiXmTXRWEoQhYzLvGJ4e6bswG0DUPJezSeUpcqeCb5zGP YrHt5mGmQhfam0ppWlRYsCLEpBrQugf+rVVHOWBEbgspbSrJc3oY96H1Rw87ubKi 5THfZKtn8CN7m1w8FDi3Pc592t3llnI2Dk1YUUiZc3N4pw+9EPCmG+ljrzwwa0UU H3Cp/H1ndGUPJ/2xfzQ3Wo1kvJMWAbMiiZQSVk+9COK69EwqWd4bnSLjwnl4bOZ6 dV2TvE5j6N2wJKrZBjpHZ+6OaKMnl9Vd1g/DGCXvo5jP+WpLxsWFRncftG/hLi4/ qINXG3lh2zcx9j51rR+LTDERw4OkoTAtXkJLrW6IA0CLAusLB87eDlzqtbN4Nwst 6ZWtz7PYqLHgqKNWl4gf/1oiLkmaFN/rxEEmBfCl9yPKKICe4sjBca8bxDXD4xBY iaFocuOMo1nhH+xDIqgd5U2vZd33dXb5vcO2jZI/2mtg4bFcZMbSgZkTgVZbwCiH shhkgf0lP6G1slV7uvMpUyMpJ4qTDsUxumc/wGh8RvP+87tLeysPNeI+Tg== =8Y6y -----END PGP PUBLIC KEY BLOCK-----