git-remote-hg 1.0.3__tar.gz → 1.0.5__tar.gz

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -1,13 +1,12 @@
1
- Metadata-Version: 2.1
1
+ Metadata-Version: 2.4
2
2
  Name: git-remote-hg
3
- Version: 1.0.3
3
+ Version: 1.0.5
4
4
  Summary: access hg repositories as git remotes
5
5
  Home-page: http://github.com/mnauw/git-remote-hg
6
6
  Author: Mark Nauwelaerts
7
7
  Author-email: mnauw@users.sourceforge.net
8
8
  License: GPLv2
9
9
  Keywords: git hg mercurial
10
- Platform: UNKNOWN
11
10
  Classifier: Programming Language :: Python
12
11
  Classifier: Programming Language :: Python :: 2
13
12
  Classifier: Programming Language :: Python :: 2.7
@@ -18,6 +17,15 @@ Classifier: License :: OSI Approved :: GNU General Public License v2 (GPLv2)
18
17
  Classifier: Development Status :: 5 - Production/Stable
19
18
  Classifier: Intended Audience :: Developers
20
19
  License-File: LICENSE
20
+ Dynamic: author
21
+ Dynamic: author-email
22
+ Dynamic: classifier
23
+ Dynamic: description
24
+ Dynamic: home-page
25
+ Dynamic: keywords
26
+ Dynamic: license
27
+ Dynamic: license-file
28
+ Dynamic: summary
21
29
 
22
30
 
23
31
  'git-remote-hg' is a gitremote protocol helper for Mercurial.
@@ -25,5 +33,3 @@ It allows you to clone, fetch and push to and from Mercurial repositories as if
25
33
  they were Git ones using a hg::some-url URL.
26
34
 
27
35
  See the homepage for much more explanation.
28
-
29
-
@@ -5,6 +5,11 @@
5
5
 
6
6
  from mercurial import hg, ui, commands, util
7
7
  from mercurial import context, subrepo
8
+ try:
9
+ # hg >= 5.8
10
+ from mercurial.utils import urlutil
11
+ except ImportError:
12
+ from mercurial import util as urlutil
8
13
 
9
14
  import re
10
15
  import sys
@@ -51,7 +56,13 @@ if sys.version_info[0] == 3:
51
56
  stdout = sys.stdout.buffer
52
57
  stderr = sys.stderr.buffer
53
58
  getcwd = os.getcwdb
54
- getenv = os.getenvb if os.supports_bytes_environ else os.getenv
59
+ @staticmethod
60
+ def getenvb(val, default):
61
+ result = os.getenv(val.decode(), default.decode() if hasattr(default, 'decode') else default)
62
+ # if result is a string, get bytes instead
63
+ result = result.encode() if hasattr(result, 'encode') else result
64
+ return result
65
+ getenv = os.getenvb if os.supports_bytes_environ else getenvb
55
66
  else:
56
67
  class compat(basecompat):
57
68
  # life was simple in those days ...
@@ -86,11 +97,27 @@ def debug(msg, *args):
86
97
  def log(msg, *args):
87
98
  logger.log(logging.LOG, msg, *args)
88
99
 
100
+ # new style way to import a source file
101
+ def _imp_load_source(module_name, file_path):
102
+ import importlib.util
103
+ loader = importlib.machinery.SourceFileLoader(module_name, file_path)
104
+ spec = importlib.util.spec_from_loader(module_name, loader)
105
+ module = importlib.util.module_from_spec(spec)
106
+ sys.modules[module_name] = module
107
+ spec.loader.exec_module(module)
108
+ return module
109
+
89
110
  def import_sibling(mod, filename):
90
- import imp
91
111
  mydir = os.path.dirname(__file__)
92
112
  sys.dont_write_bytecode = True
93
- return imp.load_source(mod, os.path.join(mydir, filename))
113
+ vi = sys.version_info
114
+ ff = os.path.join(mydir, filename)
115
+ if vi.major >= 3 and vi.minor >= 5:
116
+ return _imp_load_source(mod, ff)
117
+ else:
118
+ import imp
119
+ return imp.load_source(mod, ff)
120
+
94
121
 
95
122
  class GitHgRepo:
96
123
 
@@ -135,7 +162,7 @@ class GitHgRepo:
135
162
  process = self.start_cmd(args, **kwargs)
136
163
  output = process.communicate()[0]
137
164
  if check and process.returncode != 0:
138
- die(b'command failed: %s' % b' '.join([compat.to_b(a) for a in cmd]))
165
+ die(b'git command failed: %s' % b' '.join([compat.to_b(a) for a in args]))
139
166
  return output
140
167
 
141
168
  def get_config(self, config, getall=False):
@@ -216,9 +243,12 @@ class GitHgRepo:
216
243
  warn(b'failed to find local hg for remote %s' % (r))
217
244
  continue
218
245
  else:
246
+ npath = os.path.abspath(hg_path)
247
+ # use relative path if possible
248
+ if check_version(4, 2):
249
+ npath = os.path.join(b'..', b'..', b'..', b'.hg')
219
250
  # make sure the shared path is always up-to-date
220
- util.writefile(os.path.join(local_hg, b'sharedpath'),
221
- os.path.abspath(hg_path))
251
+ util.writefile(os.path.join(local_hg, b'sharedpath'), npath)
222
252
  self.hg_repos[r] = os.path.join(local_path)
223
253
 
224
254
  log('%s determined hg_repos %s', self.identity(), self.hg_repos)
@@ -308,11 +338,11 @@ class GitHgRepo:
308
338
  if not kind in (b'hg', b'git'):
309
339
  warn('skipping unsupported subrepo type %s' % kind)
310
340
  continue
311
- if not util.url(src).isabs():
341
+ if not urlutil.url(src).isabs():
312
342
  parent = self.get_hg_repo_url(remote)
313
343
  if not parent:
314
344
  die(b'could not determine repo url of %s' % remote)
315
- parent = util.url(parent)
345
+ parent = urlutil.url(parent)
316
346
  parent.path = posixpath.join(parent.path or b'', src)
317
347
  parent.path = posixpath.normpath(parent.path)
318
348
  src = bytes(parent)
@@ -544,6 +574,43 @@ class GcCommand(SubCommand):
544
574
  gm.store()
545
575
 
546
576
 
577
+ class MapFileCommand(SubCommand):
578
+
579
+ def argumentparser(self):
580
+ usage = '%%(prog)s %s [options] <remote>' % (self.subcommand)
581
+ p = argparse.ArgumentParser(usage=usage)
582
+ p.add_argument('--output', required=True,
583
+ help='mapfile to write')
584
+ p.epilog = textwrap.dedent("""\
585
+ Writes a so-called git-mapfile, as used internally by hg-git.
586
+ This files consists of lines of format `<githexsha> <hghexsha>`.
587
+
588
+ As such, the result could be used to coax hg-git in some manner.
589
+ However, as git-remote-hg and hg-git may (likely) produce different
590
+ commits (either git or hg), mixed use of both tools is not recommended.
591
+ """)
592
+ return p
593
+
594
+ def do(self, options, args):
595
+ remotehg = import_sibling('remotehg', 'git-remote-hg')
596
+
597
+ if not args or len(args) != 1:
598
+ self.usage('expect 1 remote')
599
+
600
+ remote = args[0]
601
+ hgpath = remotehg.select_marks_dir(remote, self.githgrepo.gitdir, False)
602
+ puts(b"Loading hg marks ...")
603
+ hgm = remotehg.Marks(os.path.join(hgpath, b'marks-hg'), None)
604
+ puts(b"Loading git marks ...")
605
+ gm = GitMarks(os.path.join(hgpath, b'marks-git'))
606
+ puts(b"Writing mapfile ...")
607
+ with open(options.output, 'wb') as f:
608
+ for c, m in gm.marks.items():
609
+ hgc = hgm.rev_marks.get(m, None)
610
+ if hgc:
611
+ f.write(b'%s %s\n' % (c, hgc))
612
+
613
+
547
614
  class SubRepoCommand(SubCommand):
548
615
 
549
616
  def writestate(repo, state):
@@ -910,6 +977,7 @@ def get_subcommands():
910
977
  b'repo': RepoCommand,
911
978
  b'gc': GcCommand,
912
979
  b'sub': SubRepoCommand,
980
+ b'mapfile': MapFileCommand,
913
981
  b'help' : HelpCommand
914
982
  }
915
983
  # add remote named subcommands
@@ -932,6 +1000,7 @@ def do_usage():
932
1000
  gc \t perform maintenance and consistency cleanup on repo tracking marks
933
1001
  sub \t manage subrepos
934
1002
  repo \t show local hg repo backing a remote
1003
+ mapfile \t dump a hg-git git-mapfile
935
1004
 
936
1005
  If the subcommand is the name of a remote hg repo, then any remaining arguments
937
1006
  are considered a "hg command", e.g. hg heads, or thg, and it is then executed
@@ -86,7 +86,13 @@ if sys.version_info[0] == 3:
86
86
  stdout = sys.stdout.buffer
87
87
  stderr = sys.stderr.buffer
88
88
  getcwd = os.getcwdb
89
- getenv = os.getenvb if os.supports_bytes_environ else os.getenv
89
+ @staticmethod
90
+ def getenvb(val, default):
91
+ result = os.getenv(val.decode(), default.decode() if hasattr(default, 'decode') else default)
92
+ # if result is a string, get bytes instead
93
+ result = result.encode() if hasattr(result, 'encode') else result
94
+ return result
95
+ getenv = os.getenvb if os.supports_bytes_environ else getenvb
90
96
  urlparse = urllib.parse.urlparse
91
97
  urljoin = urllib.parse.urljoin
92
98
  else:
@@ -116,6 +122,27 @@ else:
116
122
  urlparse = staticmethod(_urlparse)
117
123
  urljoin = staticmethod(_urljoin)
118
124
 
125
+ # new style way to import a source file
126
+ def _imp_load_source(module_name, file_path):
127
+ import importlib.util
128
+ loader = importlib.machinery.SourceFileLoader(module_name, file_path)
129
+ spec = importlib.util.spec_from_loader(module_name, loader)
130
+ module = importlib.util.module_from_spec(spec)
131
+ sys.modules[module_name] = module
132
+ spec.loader.exec_module(module)
133
+ return module
134
+
135
+ def import_sibling(mod, filename):
136
+ mydir = os.path.dirname(__file__)
137
+ sys.dont_write_bytecode = True
138
+ vi = sys.version_info
139
+ ff = os.path.join(mydir, filename)
140
+ if vi.major >= 3 and vi.minor >= 5:
141
+ return _imp_load_source(mod, ff)
142
+ else:
143
+ import imp
144
+ return imp.load_source(mod, ff)
145
+
119
146
  #
120
147
  # If you want to see Mercurial revisions as Git commit notes:
121
148
  # git config core.notesRef refs/notes/hg
@@ -141,11 +168,11 @@ else:
141
168
  # Commits are modified to preserve hg information and allow bidirectionality.
142
169
  #
143
170
 
144
- NAME_RE = re.compile(b'^([^<>]+)')
145
- AUTHOR_RE = re.compile(b'^([^<>]+?)? ?[<>]([^<>]*)(?:$|>)')
171
+ NAME_RE = re.compile(br'^([^<>]+)')
172
+ AUTHOR_RE = re.compile(br'^([^<>]+?)? ?[<>]([^<>]*)(?:$|>)')
146
173
  EMAIL_RE = re.compile(br'([^ \t<>]+@[^ \t<>]+)')
147
- AUTHOR_HG_RE = re.compile(b'^(.*?) ?<(.*?)(?:>(.*))?$')
148
- RAW_AUTHOR_RE = re.compile(b'^(\w+) (?:(.+)? )?<(.*)> (\d+) ([+-]\d+)')
174
+ AUTHOR_HG_RE = re.compile(br'^(.*?) ?<(.*?)(?:>(.*))?$')
175
+ RAW_AUTHOR_RE = re.compile(br'^(\w+) (?:(.+)? )?<(.*)> (\d+) ([+-]\d+)')
149
176
 
150
177
  VERSION = 2
151
178
 
@@ -153,6 +180,9 @@ def die(msg):
153
180
  compat.stderr.write(b'ERROR: %s\n' % compat.to_b(msg, 'utf-8'))
154
181
  sys.exit(1)
155
182
 
183
+ def debug(*args):
184
+ compat.stderr.write(b'DEBUG: %s\n' % compat.to_b(repr(args)))
185
+
156
186
  def warn(msg):
157
187
  compat.stderr.write(b'WARNING: %s\n' % compat.to_b(msg, 'utf-8'))
158
188
  compat.stderr.flush()
@@ -231,27 +261,17 @@ def get_rev_hg(commit):
231
261
 
232
262
  class Marks:
233
263
 
234
- def __init__(self, path, repo):
264
+ def __init__(self, path, _repo=None):
235
265
  self.path = path
236
- self.repo = repo
237
266
  self.clear()
238
267
  self.load()
239
268
 
240
- if self.version < VERSION:
241
- if self.version == 1:
242
- self.upgrade_one()
243
-
244
- # upgraded?
245
- if self.version < VERSION:
246
- self.clear()
247
- self.version = VERSION
248
-
249
269
  def clear(self):
250
270
  self.tips = {}
251
271
  self.marks = {}
252
272
  self.rev_marks = {}
253
273
  self.last_mark = 0
254
- self.version = 0
274
+ self.version = VERSION
255
275
  self.last_note = 0
256
276
 
257
277
  def load(self):
@@ -267,20 +287,12 @@ class Marks:
267
287
  self.tips = []
268
288
  self.marks = marks
269
289
  self.last_mark = tmp['last-mark']
270
- self.version = tmp.get('version', 1)
290
+ self.version = tmp['version']
271
291
  self.last_note = 0
272
292
 
273
293
  for rev, mark in compat.iteritems(self.marks):
274
294
  self.rev_marks[mark] = rev
275
295
 
276
- def upgrade_one(self):
277
- def get_id(rev):
278
- return hghex(self.repo.changelog.node(int(rev)))
279
- self.tips = dict((name, get_id(rev)) for name, rev in compat.iteritems(self.tips))
280
- self.marks = dict((get_id(rev), mark) for rev, mark in compat.iteritems(self.marks))
281
- self.rev_marks = dict((mark, get_id(rev)) for mark, rev in compat.iteritems(self.rev_marks))
282
- self.version = 2
283
-
284
296
  def dict(self):
285
297
  return { 'tips': self.tips, 'marks': self.marks,
286
298
  'last-mark': self.last_mark, 'version': self.version,
@@ -383,7 +395,7 @@ class Parser:
383
395
  return None
384
396
  _, name, email, date, tz = m.groups()
385
397
  if name and b'ext:' in name:
386
- m = re.match(b'^(.+?) ext:\((.+)\)$', name)
398
+ m = re.match(br'^(.+?) ext:\((.+)\)$', name)
387
399
  if m:
388
400
  name = m.group(1)
389
401
  ex = compat.urlunquote(m.group(2))
@@ -402,40 +414,38 @@ class Parser:
402
414
  return (user, int(date), hgtz(tz))
403
415
 
404
416
  def fix_file_path(path):
405
- def posix_path(path):
406
- if os.sep == '/':
407
- return path
408
- # even Git for Windows expects forward
409
- return path.replace(compat.to_b(os.sep), b'/')
410
- # also converts forward slash to backwards slash on Win
411
417
  path = os.path.normpath(path)
412
- if not os.path.isabs(path):
413
- return posix_path(path)
414
- return posix_path(os.path.relpath(path, b'/'))
415
-
416
- def export_files(files):
417
- final = []
418
- for f in files:
419
- fid = node.hex(f.filenode())
420
-
421
- if fid in filenodes:
422
- mark = filenodes[fid]
423
- else:
424
- mark = marks.next_mark()
425
- filenodes[fid] = mark
426
- d = f.data()
427
-
428
- puts(b"blob")
429
- puts(b"mark :%u" % mark)
430
- puts(b"data %d" % len(d))
431
- puts(d)
418
+ if os.path.isabs(path):
419
+ path = os.path.relpath(path, b'/')
420
+ if os.sep == '/':
421
+ return path
422
+ # even Git for Windows expects forward
423
+ return path.replace(compat.to_b(os.sep), b'/')
424
+
425
+ def export_file(ctx, fname):
426
+ f = ctx.filectx(fname)
427
+ fid = node.hex(f.filenode())
428
+
429
+ if fid in filenodes:
430
+ mark = filenodes[fid]
431
+ else:
432
+ mark = marks.next_mark()
433
+ filenodes[fid] = mark
434
+ d = f.data()
432
435
 
433
- path = fix_file_path(f.path())
434
- final.append((gitmode(f.flags()), mark, path))
436
+ puts(b"blob")
437
+ puts(b"mark :%u" % mark)
438
+ puts(b"data %d" % len(d))
439
+ puts(f.data())
435
440
 
436
- return final
441
+ path = fixup_path_to_git(fix_file_path(f.path()))
442
+ return (gitmode(f.flags()), mark, path)
437
443
 
438
444
  def get_filechanges(repo, ctx, parent):
445
+ if hasattr(parent, 'status'):
446
+ stat = parent.status(ctx)
447
+ return stat.modified + stat.added, stat.removed
448
+
439
449
  modified = set()
440
450
  added = set()
441
451
  removed = set()
@@ -477,7 +487,7 @@ def fixup_user_git(user):
477
487
  def fixup_user_hg(user):
478
488
  def sanitize(name):
479
489
  # stole this from hg-git
480
- return re.sub(b'[<>\n]', b'?', name.lstrip(b'< ').rstrip(b'> '))
490
+ return re.sub(br'[<>\n]', b'?', name.lstrip(b'< ').rstrip(b'> '))
481
491
 
482
492
  m = AUTHOR_HG_RE.match(user)
483
493
  if m:
@@ -508,6 +518,51 @@ def fixup_user(user):
508
518
 
509
519
  return b'%s <%s>' % (name, mail)
510
520
 
521
+ # (recent) git fast-import does not accept .git or .gitmodule component names
522
+ # (anywhere, case-insensitive)
523
+ # in any case, surprising things may happen, so add some front-end replacement magic;
524
+ # transform of (hg) .git(0 or more suffix) to (git) .git(1 or more suffix)
525
+ # (likewise so for any invalid git keyword)
526
+ def fixup_dotfile_path(path, suffix, add):
527
+ def subst(part):
528
+ if (not part) or part[0] != ord(b'.'):
529
+ return part
530
+ for prefix in (b'.git', b'.gitmodules'):
531
+ pl = len(prefix)
532
+ tail = len(part) - pl
533
+ if tail < 0:
534
+ continue
535
+ if part[0:pl].lower() == prefix and part[pl:] == suffix * tail:
536
+ if add:
537
+ return part + suffix
538
+ elif tail == 0:
539
+ # .git should not occur in git space
540
+ # so complain
541
+ if pl == 3:
542
+ die('invalid path component %s' % part)
543
+ else:
544
+ # but .gitmodules might
545
+ # leave as-is, it is handled/ignored elsewhere
546
+ return part
547
+ else:
548
+ return part[0:-1]
549
+ return part
550
+ # quick optimization check;
551
+ if (not path) or (path[0] != ord(b'.') and path.find(b'/.') < 0):
552
+ return path
553
+ sep = b'/'
554
+ return sep.join((subst(part) for part in path.split(sep)))
555
+
556
+ def fixup_path_to_git(path):
557
+ if not dotfile_suffix:
558
+ return path
559
+ return fixup_dotfile_path(path, dotfile_suffix, True)
560
+
561
+ def fixup_path_from_git(path):
562
+ if not dotfile_suffix:
563
+ return path
564
+ return fixup_dotfile_path(path, dotfile_suffix, False)
565
+
511
566
  def updatebookmarks(repo, peer):
512
567
  remotemarks = peer.listkeys(b'bookmarks')
513
568
 
@@ -579,18 +634,6 @@ def get_repo(url, alias):
579
634
  else:
580
635
  shared_path = os.path.join(gitdir, b'hg')
581
636
 
582
- # check and upgrade old organization
583
- hg_path = os.path.join(shared_path, b'.hg')
584
- if os.path.exists(shared_path) and not os.path.exists(hg_path):
585
- repos = os.listdir(shared_path)
586
- for x in repos:
587
- local_hg = os.path.join(shared_path, x, b'clone', b'.hg')
588
- if not os.path.exists(local_hg):
589
- continue
590
- if not os.path.exists(hg_path):
591
- shutil.move(local_hg, hg_path)
592
- shutil.rmtree(os.path.join(shared_path, x, b'clone'))
593
-
594
637
  # setup shared repo (if not there)
595
638
  try:
596
639
  hg.peer(myui, {}, shared_path, create=True)
@@ -601,8 +644,13 @@ def get_repo(url, alias):
601
644
  os.makedirs(dirname)
602
645
 
603
646
  local_path = os.path.join(dirname, b'clone')
647
+ kwargs = {}
648
+ hg_path = os.path.join(shared_path, b'.hg')
649
+ if check_version(4, 2):
650
+ kwargs = {'relative': True}
651
+ hg_path = os.path.join(b'..', b'..', b'..', b'.hg')
604
652
  if not os.path.exists(local_path):
605
- hg.share(myui, shared_path, local_path, update=False)
653
+ hg.share(myui, shared_path, local_path, update=False, **kwargs)
606
654
  else:
607
655
  # make sure the shared path is always up-to-date
608
656
  util.writefile(os.path.join(local_path, b'.hg', b'sharedpath'), hg_path)
@@ -711,11 +759,16 @@ def export_ref(repo, name, kind, head):
711
759
  if rename:
712
760
  renames.append((rename[0], f))
713
761
 
762
+ # NOTE no longer used in hg-git, a HG:rename extra header is used
714
763
  for e in renames:
715
764
  extra_msg += b"rename : %s => %s\n" % e
716
765
 
717
766
  for key, value in compat.iteritems(extra):
718
- if key in (b'author', b'committer', b'encoding', b'message', b'branch', b'hg-git'):
767
+ if key in (b'author', b'committer', b'encoding', b'message', b'branch', b'hg-git', b'transplant_source'):
768
+ continue
769
+ elif key == b'hg-git-rename-source' and value == b'git':
770
+ # extra data that hg-git might put there unconditionally
771
+ # or that we put in there to be compatible
719
772
  continue
720
773
  else:
721
774
  extra_msg += b"extra : %s : %s\n" % (key, compat.urlquote(value))
@@ -726,7 +779,7 @@ def export_ref(repo, name, kind, head):
726
779
  if len(parents) == 0:
727
780
  puts(b'reset %s/%s' % (prefix, ename))
728
781
 
729
- modified_final = export_files(c.filectx(f) for f in modified)
782
+ modified_final = [export_file(c, fname) for fname in modified]
730
783
 
731
784
  puts(b"commit %s/%s" % (prefix, ename))
732
785
  puts(b"mark :%d" % (marks.get_mark(c.hex())))
@@ -741,7 +794,7 @@ def export_ref(repo, name, kind, head):
741
794
  puts(b"merge :%u" % (rev_to_mark(parents[1])))
742
795
 
743
796
  for f in removed:
744
- puts(b"D %s" % (fix_file_path(f)))
797
+ puts(b"D %s" % fixup_path_to_git(fix_file_path(f)))
745
798
  for f in modified_final:
746
799
  puts(b"M %s :%u %s" % f)
747
800
  puts()
@@ -839,8 +892,11 @@ def do_list(parser, branchmap):
839
892
 
840
893
  for branch, heads in compat.iteritems(branchmap):
841
894
  # only open heads
842
- heads = [h for h in heads if b'close' not in repo.changelog.read(h)[5]]
843
- if heads:
895
+ try:
896
+ heads = [h for h in heads if b'close' not in repo.changelog.read(h)[5]]
897
+ if heads:
898
+ branches[branch] = heads
899
+ except error.LookupError:
844
900
  branches[branch] = heads
845
901
 
846
902
  list_head(repo, cur)
@@ -1031,6 +1087,7 @@ def parse_commit(parser):
1031
1087
  else:
1032
1088
  die(b'Unknown file command: %s' % line)
1033
1089
  path = c_style_unescape(path)
1090
+ path = fixup_path_from_git(path)
1034
1091
  files[path] = files.get(path, {})
1035
1092
  files[path].update(f)
1036
1093
 
@@ -1135,10 +1192,20 @@ def parse_commit(parser):
1135
1192
  extra[b'branch'] = hgref(branch)
1136
1193
 
1137
1194
  if mode == 'hg':
1195
+ # add some extra that hg-git adds (almost) unconditionally
1196
+ # see also https://foss.heptapod.net/mercurial/hg-git/-/merge_requests/211
1197
+ # NOTE it could be changed to another value below
1198
+ # actually, it is *almost* unconditionally, and only done if the commit
1199
+ # is deduced to originate in git. However, the latter is based on
1200
+ # presence/absence of HG markers in commit "extra headers".
1201
+ # The latter can not be handled here, and so this can not be correctly
1202
+ # reproduced.
1203
+ # extra[b'hg-git-rename-source'] = b'git'
1138
1204
  i = data.find(b'\n--HG--\n')
1139
1205
  if i >= 0:
1140
1206
  tmp = data[i + len(b'\n--HG--\n'):].strip()
1141
1207
  for k, v in [e.split(b' : ', 1) for e in tmp.split(b'\n')]:
1208
+ # NOTE no longer used in hg-git, a HG:rename extra header is used
1142
1209
  if k == b'rename':
1143
1210
  old, new = v.split(b' => ', 1)
1144
1211
  files[new]['rename'] = old
@@ -1326,7 +1393,10 @@ def checkheads(repo, remote, p_revs, force):
1326
1393
  def push_unsafe(repo, remote, p_revs, force):
1327
1394
 
1328
1395
  fci = discovery.findcommonincoming
1329
- commoninc = fci(repo, remote, force=force)
1396
+ if check_version(4, 5):
1397
+ commoninc = fci(repo, remote, force=force, ancestorsof=list(p_revs))
1398
+ else:
1399
+ commoninc = fci(repo, remote, force=force)
1330
1400
  common, _, remoteheads = commoninc
1331
1401
  fco = discovery.findcommonoutgoing
1332
1402
  outgoing = fco(repo, remote, onlyheads=list(p_revs), commoninc=commoninc, force=force)
@@ -1357,12 +1427,6 @@ def push_unsafe(repo, remote, p_revs, force):
1357
1427
  else:
1358
1428
  ret = remote.addchangegroup(cg, b'push', repo.url())
1359
1429
 
1360
- phases = remote.listkeys(b'phases')
1361
- if phases:
1362
- for head in p_revs:
1363
- # update to public
1364
- remote.pushkey(b'phases', hghex(head), b'1', b'0')
1365
-
1366
1430
  return ret
1367
1431
 
1368
1432
  def push(repo, remote, p_revs, force):
@@ -1397,6 +1461,7 @@ def do_push_hg(parser):
1397
1461
  global parsed_refs, parsed_tags
1398
1462
  p_bmarks = []
1399
1463
  p_revs = {}
1464
+ ok_refs = []
1400
1465
 
1401
1466
  parsed_refs = {}
1402
1467
  parsed_tags = {}
@@ -1443,7 +1508,7 @@ def do_push_hg(parser):
1443
1508
  continue
1444
1509
 
1445
1510
  p_revs[bnode] = ref
1446
- puts(b"ok %s" % ref)
1511
+ ok_refs.append(ref)
1447
1512
  elif ref.startswith(b'refs/heads/'):
1448
1513
  bmark = ref[len(b'refs/heads/'):]
1449
1514
  new = node
@@ -1453,14 +1518,14 @@ def do_push_hg(parser):
1453
1518
  puts(b"ok %s up to date" % ref)
1454
1519
  continue
1455
1520
 
1456
- puts(b"ok %s" % ref)
1521
+ ok_refs.append(ref)
1457
1522
  if not bookmark_is_fake(bmark, parser.repo._bookmarks):
1458
1523
  p_bmarks.append((ref, bmark, old, new))
1459
1524
 
1460
1525
  p_revs[bnode] = ref
1461
1526
  elif ref.startswith(b'refs/tags/'):
1462
1527
  if dry_run:
1463
- puts(b"ok %s" % ref)
1528
+ ok_refs.append(ref)
1464
1529
  continue
1465
1530
  tag = ref[len(b'refs/tags/'):]
1466
1531
  tag = hgref(tag)
@@ -1487,14 +1552,15 @@ def do_push_hg(parser):
1487
1552
  fp.write(b'%s %s\n' % (node, tag))
1488
1553
  fp.close()
1489
1554
  p_revs[bnode] = ref
1490
- puts(b"ok %s" % ref)
1555
+ ok_refs.append(ref)
1491
1556
  else:
1492
1557
  # transport-helper/fast-export bugs
1493
1558
  continue
1494
1559
 
1495
1560
  if dry_run:
1496
- if peer:
1497
- checkheads(parser.repo, peer, p_revs, force_push)
1561
+ if not peer or checkheads(parser.repo, peer, p_revs, force_push):
1562
+ for ref in ok_refs:
1563
+ puts(b"ok %s" % ref)
1498
1564
  return
1499
1565
 
1500
1566
  success = True
@@ -1515,12 +1581,18 @@ def do_push_hg(parser):
1515
1581
  if not peer.pushkey(b'bookmarks', bmark, old, new):
1516
1582
  success = False
1517
1583
  puts(b"error %s" % ref)
1584
+ ok_refs.remove(ref)
1518
1585
  else:
1519
1586
  # update local bookmarks
1520
1587
  for ref, bmark, old, new in p_bmarks:
1521
1588
  if not bookmarks.pushbookmark(parser.repo, bmark, old, new):
1522
1589
  success = False
1523
1590
  puts(b"error %s" % ref)
1591
+ ok_refs.remove(ref)
1592
+
1593
+ # update rest of the refs
1594
+ for ref in ok_refs:
1595
+ puts(b"ok %s" % ref)
1524
1596
 
1525
1597
  return success
1526
1598
 
@@ -1604,10 +1676,7 @@ def do_push_refspec(parser, refspec, revs):
1604
1676
  tmpfastexport = open(os.path.join(marksdir, b'git-fast-export-%d' % (os.getpid())), 'w+b')
1605
1677
  subprocess.check_call(cmd, stdin=None, stdout=tmpfastexport)
1606
1678
  try:
1607
- import imp
1608
- sys.dont_write_bytecode = True
1609
- ctx.hghelper = imp.load_source('hghelper', \
1610
- os.path.join(os.path.dirname(__file__), 'git-hg-helper'))
1679
+ ctx.hghelper = import_sibling('hghelper', 'git-hg-helper')
1611
1680
  ctx.hghelper.init_git(gitdir)
1612
1681
  ctx.gitmarks = ctx.hghelper.GitMarks(tmpmarks)
1613
1682
  # let processing know it should not bother pushing if not requested
@@ -1729,8 +1798,7 @@ def fix_path(alias, repo, orig_url):
1729
1798
  url = compat.urlparse(orig_url, b'file')
1730
1799
  if url.scheme != b'file' or os.path.isabs(os.path.expanduser(url.path)):
1731
1800
  return
1732
- abs_url = compat.urljoin(b"%s/" % compat.getcwd(), orig_url)
1733
- cmd = ['git', 'config', b'remote.%s.url' % alias, b"hg::%s" % abs_url]
1801
+ cmd = ['git', 'config', b'remote.%s.url' % alias, b"hg::%s" % os.path.abspath(orig_url)]
1734
1802
  subprocess.call(cmd)
1735
1803
 
1736
1804
  def select_private_refs(alias):
@@ -1845,6 +1913,7 @@ def main(args):
1845
1913
  global capability_push
1846
1914
  global remove_username_quotes
1847
1915
  global marksdir
1916
+ global dotfile_suffix
1848
1917
 
1849
1918
  marks = None
1850
1919
  is_tmp = False
@@ -1864,6 +1933,7 @@ def main(args):
1864
1933
  track_branches = get_config_bool('remote-hg.track-branches', True)
1865
1934
  capability_push = get_config_bool('remote-hg.capability-push', True)
1866
1935
  remove_username_quotes = get_config_bool('remote-hg.remove-username-quotes', True)
1936
+ dotfile_suffix = get_config('remote-hg.dotfile-suffix').strip() or b'_'
1867
1937
  force_push = False
1868
1938
 
1869
1939
  if hg_git_compat:
@@ -1908,7 +1978,7 @@ def main(args):
1908
1978
  fix_path(alias, peer or repo, url)
1909
1979
 
1910
1980
  marks_path = os.path.join(marksdir, b'marks-hg')
1911
- marks = Marks(marks_path, repo)
1981
+ marks = Marks(marks_path)
1912
1982
 
1913
1983
  if sys.platform == 'win32':
1914
1984
  import msvcrt
@@ -1,13 +1,12 @@
1
- Metadata-Version: 2.1
1
+ Metadata-Version: 2.4
2
2
  Name: git-remote-hg
3
- Version: 1.0.3
3
+ Version: 1.0.5
4
4
  Summary: access hg repositories as git remotes
5
5
  Home-page: http://github.com/mnauw/git-remote-hg
6
6
  Author: Mark Nauwelaerts
7
7
  Author-email: mnauw@users.sourceforge.net
8
8
  License: GPLv2
9
9
  Keywords: git hg mercurial
10
- Platform: UNKNOWN
11
10
  Classifier: Programming Language :: Python
12
11
  Classifier: Programming Language :: Python :: 2
13
12
  Classifier: Programming Language :: Python :: 2.7
@@ -18,6 +17,15 @@ Classifier: License :: OSI Approved :: GNU General Public License v2 (GPLv2)
18
17
  Classifier: Development Status :: 5 - Production/Stable
19
18
  Classifier: Intended Audience :: Developers
20
19
  License-File: LICENSE
20
+ Dynamic: author
21
+ Dynamic: author-email
22
+ Dynamic: classifier
23
+ Dynamic: description
24
+ Dynamic: home-page
25
+ Dynamic: keywords
26
+ Dynamic: license
27
+ Dynamic: license-file
28
+ Dynamic: summary
21
29
 
22
30
 
23
31
  'git-remote-hg' is a gitremote protocol helper for Mercurial.
@@ -25,5 +33,3 @@ It allows you to clone, fetch and push to and from Mercurial repositories as if
25
33
  they were Git ones using a hg::some-url URL.
26
34
 
27
35
  See the homepage for much more explanation.
28
-
29
-
@@ -1,8 +1,10 @@
1
1
  LICENSE
2
2
  git-hg-helper
3
3
  git-remote-hg
4
+ setup.cfg
4
5
  setup.py
5
6
  git_remote_hg.egg-info/PKG-INFO
6
7
  git_remote_hg.egg-info/SOURCES.txt
7
8
  git_remote_hg.egg-info/dependency_links.txt
8
- git_remote_hg.egg-info/top_level.txt
9
+ git_remote_hg.egg-info/top_level.txt
10
+ p3/bin/activate_this.py
@@ -0,0 +1,34 @@
1
+ """By using execfile(this_file, dict(__file__=this_file)) you will
2
+ activate this virtualenv environment.
3
+
4
+ This can be used when you must use an existing Python interpreter, not
5
+ the virtualenv bin/python
6
+ """
7
+
8
+ try:
9
+ __file__
10
+ except NameError:
11
+ raise AssertionError(
12
+ "You must run this like execfile('path/to/activate_this.py', dict(__file__='path/to/activate_this.py'))")
13
+ import sys
14
+ import os
15
+
16
+ old_os_path = os.environ.get('PATH', '')
17
+ os.environ['PATH'] = os.path.dirname(os.path.abspath(__file__)) + os.pathsep + old_os_path
18
+ base = os.path.dirname(os.path.dirname(os.path.abspath(__file__)))
19
+ if sys.platform == 'win32':
20
+ site_packages = os.path.join(base, 'Lib', 'site-packages')
21
+ else:
22
+ site_packages = os.path.join(base, 'lib', 'python%s' % sys.version[:3], 'site-packages')
23
+ prev_sys_path = list(sys.path)
24
+ import site
25
+ site.addsitedir(site_packages)
26
+ sys.real_prefix = sys.prefix
27
+ sys.prefix = base
28
+ # Move the added items to the front of the path:
29
+ new_sys_path = []
30
+ for item in list(sys.path):
31
+ if item not in prev_sys_path:
32
+ new_sys_path.append(item)
33
+ sys.path.remove(item)
34
+ sys.path[:0] = new_sys_path
@@ -0,0 +1,9 @@
1
+ [flake8]
2
+ ignore = E126, E127, E128, E401, E402, E741, E301, E302, E305, W503, W504
3
+ max-line-length = 140
4
+ max-complexity = 100
5
+
6
+ [egg_info]
7
+ tag_build =
8
+ tag_date = 0
9
+
@@ -3,7 +3,7 @@
3
3
  import setuptools
4
4
 
5
5
  # strip leading v
6
- version = 'v1.0.3'[1:]
6
+ version = 'v1.0.5'[1:]
7
7
 
8
8
  # check for released version
9
9
  assert (len(version) > 0)
@@ -1,4 +0,0 @@
1
- [egg_info]
2
- tag_build =
3
- tag_date = 0
4
-
File without changes