solano 1.31.4 → 1.31.5

Sign up to get free protection for your applications and to get access to all the features.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA1:
3
- metadata.gz: 75363fbe9126412f3896b76d5f8121c7a510fa5b
4
- data.tar.gz: b86dbb2b56d4f5180f02875c2ef45cd250b5fae5
3
+ metadata.gz: 61b3f855cb149d12d8205a6c24c8cc53ccfc5892
4
+ data.tar.gz: 6039e124ea7231a430c7efff23b400d5743bcbdc
5
5
  SHA512:
6
- metadata.gz: 88dd0eac4e2e08d07cc42ea287be7acec5f3a567360ed47f3dff23dc100c3e83b7a38868929e47aae6d302a71ef81f37c0606f6d5c94c21dda0ab98a83dcb8a5
7
- data.tar.gz: 8f1cdc7b4477d2c6b8aa15f77e3d61bca3940fcd7ca7ee98cc704eaff8bde9db511b3040cd3e4d3317768218f9f08ddfa16f86e111591873b59cc72bcf55a5b3
6
+ metadata.gz: eb120b4f808d2200f5144266dbb573a8aa2fe698ffb35d072e14a46130eadd8f668b3ea84cd66396c0e1bf8badf9610e1e913fc544af3e3c0573ffad9017003e
7
+ data.tar.gz: eb58fc5b38b1af3bf683e0fc373ca92125a580e5f53f3f3ded4bce0fa462bf6d23ff715902abd69c359428b9d88d8393f70dfba1eec1191247fa12f7f114d4f9
@@ -67,7 +67,6 @@ module Solano
67
67
  require 'solano/cli/commands/config'
68
68
  require 'solano/cli/commands/describe'
69
69
  require 'solano/cli/commands/web'
70
- require 'solano/cli/commands/hg'
71
70
  require 'solano/cli/commands/server'
72
71
  require 'solano/cli/commands/support'
73
72
 
File without changes
@@ -1,5 +1,5 @@
1
- # Copyright (c) 2011-2016 Solano Labs All Rights Reserved
1
+ # Copyright (c) 2011-2017 Solano Labs All Rights Reserved
2
2
 
3
3
  module Solano
4
- VERSION = "1.31.4"
4
+ VERSION = "1.31.5"
5
5
  end
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: solano
3
3
  version: !ruby/object:Gem::Version
4
- version: 1.31.4
4
+ version: 1.31.5
5
5
  platform: ruby
6
6
  authors:
7
7
  - Solano Labs
8
8
  autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
- date: 2017-08-29 00:00:00.000000000 Z
11
+ date: 2017-09-14 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: thor
@@ -353,7 +353,6 @@ files:
353
353
  - lib/solano/cli/commands/describe.rb
354
354
  - lib/solano/cli/commands/find_failing.rb
355
355
  - lib/solano/cli/commands/heroku.rb
356
- - lib/solano/cli/commands/hg.rb
357
356
  - lib/solano/cli/commands/keys.rb
358
357
  - lib/solano/cli/commands/login.rb
359
358
  - lib/solano/cli/commands/logout.rb
@@ -386,7 +385,7 @@ files:
386
385
  - lib/solano/scm/scm_stub.rb
387
386
  - lib/solano/scm/url.rb
388
387
  - lib/solano/script.rb
389
- - lib/solano/script/git-remote-hg
388
+ - lib/solano/script/.gitkeep
390
389
  - lib/solano/ssh.rb
391
390
  - lib/solano/util.rb
392
391
  - lib/solano/version.rb
@@ -1,48 +0,0 @@
1
- # Copyright (c) 2012-2015 Solano Labs All Rights Reserved
2
-
3
- require 'fileutils'
4
-
5
- module Solano
6
- class SolanoCli < Thor
7
- desc "hg:mirror", "Construct local hg -> git mirror"
8
- method_option :noop, :type => :boolean, :default => false
9
- method_option :force, :type => :boolean, :default => false
10
- define_method "hg:mirror" do |*args|
11
- solano_setup({:repo => true, :deprecated => true})
12
-
13
- if @scm.scm_name != 'hg' then
14
- exit_failure("Current repository does not appear to be using Mercurial")
15
- end
16
-
17
- if @scm.origin_url.nil? then
18
- exit_failure("Missing default path; please set default path in hgrc")
19
- end
20
-
21
- if File.exists?(@scm.mirror_path) then
22
- if !options[:force] then
23
- exit_failure("Mirror already exists; use --force to recreate")
24
- end
25
- if options[:noop] then
26
- exit_failure("Running in no-op mode; not removing existing mirror")
27
- end
28
- FileUtils.rm_rf(@scm.mirror_path)
29
- end
30
-
31
- FileUtils.mkdir_p(@scm.mirror_path)
32
-
33
- Solano::Scripts.prepend_script_path
34
-
35
- clone_command = "git clone hg::#{@scm.root} #{@scm.mirror_path}"
36
- # origin_command = "cd #{@scm.mirror_path} && git remote set-url origin #{@scm.origin_url}"
37
-
38
- if options[:noop] then
39
- puts "export PATH=#{ENV['PATH']}"
40
- puts clone_command
41
- # puts origin_command
42
- else
43
- Kernel.system(clone_command)
44
- # Kernel.system(origin_command)
45
- end
46
- end
47
- end
48
- end
@@ -1,1258 +0,0 @@
1
- #!/usr/bin/env python
2
- #
3
- # Copyright (c) 2012 Felipe Contreras
4
- #
5
-
6
- # Inspired by Rocco Rutte's hg-fast-export
7
-
8
- # Just copy to your ~/bin, or anywhere in your $PATH.
9
- # Then you can clone with:
10
- # git clone hg::/path/to/mercurial/repo/
11
- #
12
- # For remote repositories a local clone is stored in
13
- # "$GIT_DIR/hg/origin/clone/.hg/".
14
-
15
- from mercurial import hg, ui, bookmarks, context, encoding, node, error, extensions, discovery, util
16
-
17
- import re
18
- import sys
19
- import os
20
- import json
21
- import shutil
22
- import subprocess
23
- import urllib
24
- import atexit
25
- import urlparse, hashlib
26
- import time as ptime
27
-
28
- #
29
- # If you want to see Mercurial revisions as Git commit notes:
30
- # git config core.notesRef refs/notes/hg
31
- #
32
- # If you are not in hg-git-compat mode and want to disable the tracking of
33
- # named branches:
34
- # git config --global remote-hg.track-branches false
35
- #
36
- # If you want the equivalent of hg's clone/pull--insecure option:
37
- # git config --global remote-hg.insecure true
38
- #
39
- # If you want to switch to hg-git compatibility mode:
40
- # git config --global remote-hg.hg-git-compat true
41
- #
42
- # git:
43
- # Sensible defaults for git.
44
- # hg bookmarks are exported as git branches, hg branches are prefixed
45
- # with 'branches/', HEAD is a special case.
46
- #
47
- # hg:
48
- # Emulate hg-git.
49
- # Only hg bookmarks are exported as git branches.
50
- # Commits are modified to preserve hg information and allow bidirectionality.
51
- #
52
-
53
- NAME_RE = re.compile('^([^<>]+)')
54
- AUTHOR_RE = re.compile('^([^<>]+?)? ?[<>]([^<>]*)(?:$|>)')
55
- EMAIL_RE = re.compile(r'([^ \t<>]+@[^ \t<>]+)')
56
- AUTHOR_HG_RE = re.compile('^(.*?) ?<(.*?)(?:>(.+)?)?$')
57
- RAW_AUTHOR_RE = re.compile('^(\w+) (?:(.+)? )?<(.*)> (\d+) ([+-]\d+)')
58
-
59
- VERSION = 2
60
-
61
- def die(msg, *args):
62
- sys.stderr.write('ERROR: %s\n' % (msg % args))
63
- sys.exit(1)
64
-
65
- def warn(msg, *args):
66
- sys.stderr.write('WARNING: %s\n' % (msg % args))
67
-
68
- def gitmode(flags):
69
- return 'l' in flags and '120000' or 'x' in flags and '100755' or '100644'
70
-
71
- def gittz(tz):
72
- return '%+03d%02d' % (-tz / 3600, -tz % 3600 / 60)
73
-
74
- def hgmode(mode):
75
- m = { '100755': 'x', '120000': 'l' }
76
- return m.get(mode, '')
77
-
78
- def hghex(n):
79
- return node.hex(n)
80
-
81
- def hgbin(n):
82
- return node.bin(n)
83
-
84
- def hgref(ref):
85
- return ref.replace('___', ' ')
86
-
87
- def gitref(ref):
88
- return ref.replace(' ', '___')
89
-
90
- def check_version(*check):
91
- if not hg_version:
92
- return True
93
- return hg_version >= check
94
-
95
- def get_config(config):
96
- cmd = ['git', 'config', '--get', config]
97
- process = subprocess.Popen(cmd, stdout=subprocess.PIPE)
98
- output, _ = process.communicate()
99
- return output
100
-
101
- def get_config_bool(config, default=False):
102
- value = get_config(config).rstrip('\n')
103
- if value == "true":
104
- return True
105
- elif value == "false":
106
- return False
107
- else:
108
- return default
109
-
110
- class Marks:
111
-
112
- def __init__(self, path, repo):
113
- self.path = path
114
- self.repo = repo
115
- self.clear()
116
- self.load()
117
-
118
- if self.version < VERSION:
119
- if self.version == 1:
120
- self.upgrade_one()
121
-
122
- # upgraded?
123
- if self.version < VERSION:
124
- self.clear()
125
- self.version = VERSION
126
-
127
- def clear(self):
128
- self.tips = {}
129
- self.marks = {}
130
- self.rev_marks = {}
131
- self.last_mark = 0
132
- self.version = 0
133
- self.last_note = 0
134
-
135
- def load(self):
136
- if not os.path.exists(self.path):
137
- return
138
-
139
- tmp = json.load(open(self.path))
140
-
141
- self.tips = tmp['tips']
142
- self.marks = tmp['marks']
143
- self.last_mark = tmp['last-mark']
144
- self.version = tmp.get('version', 1)
145
- self.last_note = tmp.get('last-note', 0)
146
-
147
- for rev, mark in self.marks.iteritems():
148
- self.rev_marks[mark] = rev
149
-
150
- def upgrade_one(self):
151
- def get_id(rev):
152
- return hghex(self.repo.changelog.node(int(rev)))
153
- self.tips = dict((name, get_id(rev)) for name, rev in self.tips.iteritems())
154
- self.marks = dict((get_id(rev), mark) for rev, mark in self.marks.iteritems())
155
- self.rev_marks = dict((mark, get_id(rev)) for mark, rev in self.rev_marks.iteritems())
156
- self.version = 2
157
-
158
- def dict(self):
159
- return { 'tips': self.tips, 'marks': self.marks, 'last-mark' : self.last_mark, 'version' : self.version, 'last-note' : self.last_note }
160
-
161
- def store(self):
162
- json.dump(self.dict(), open(self.path, 'w'))
163
-
164
- def __str__(self):
165
- return str(self.dict())
166
-
167
- def from_rev(self, rev):
168
- return self.marks[rev]
169
-
170
- def to_rev(self, mark):
171
- return str(self.rev_marks[mark])
172
-
173
- def next_mark(self):
174
- self.last_mark += 1
175
- return self.last_mark
176
-
177
- def get_mark(self, rev):
178
- self.last_mark += 1
179
- self.marks[rev] = self.last_mark
180
- return self.last_mark
181
-
182
- def new_mark(self, rev, mark):
183
- self.marks[rev] = mark
184
- self.rev_marks[mark] = rev
185
- self.last_mark = mark
186
-
187
- def is_marked(self, rev):
188
- return rev in self.marks
189
-
190
- def get_tip(self, branch):
191
- return str(self.tips[branch])
192
-
193
- def set_tip(self, branch, tip):
194
- self.tips[branch] = tip
195
-
196
- class Parser:
197
-
198
- def __init__(self, repo):
199
- self.repo = repo
200
- self.line = self.get_line()
201
-
202
- def get_line(self):
203
- return sys.stdin.readline().strip()
204
-
205
- def __getitem__(self, i):
206
- return self.line.split()[i]
207
-
208
- def check(self, word):
209
- return self.line.startswith(word)
210
-
211
- def each_block(self, separator):
212
- while self.line != separator:
213
- yield self.line
214
- self.line = self.get_line()
215
-
216
- def __iter__(self):
217
- return self.each_block('')
218
-
219
- def next(self):
220
- self.line = self.get_line()
221
- if self.line == 'done':
222
- self.line = None
223
-
224
- def get_mark(self):
225
- i = self.line.index(':') + 1
226
- return int(self.line[i:])
227
-
228
- def get_data(self):
229
- if not self.check('data'):
230
- return None
231
- i = self.line.index(' ') + 1
232
- size = int(self.line[i:])
233
- return sys.stdin.read(size)
234
-
235
- def get_author(self):
236
- ex = None
237
- m = RAW_AUTHOR_RE.match(self.line)
238
- if not m:
239
- return None
240
- _, name, email, date, tz = m.groups()
241
- if name and 'ext:' in name:
242
- m = re.match('^(.+?) ext:\((.+)\)$', name)
243
- if m:
244
- name = m.group(1)
245
- ex = urllib.unquote(m.group(2))
246
-
247
- if email != bad_mail:
248
- if name:
249
- user = '%s <%s>' % (name, email)
250
- else:
251
- user = '<%s>' % (email)
252
- else:
253
- user = name
254
-
255
- if ex:
256
- user += ex
257
-
258
- tz = int(tz)
259
- tz = ((tz / 100) * 3600) + ((tz % 100) * 60)
260
- return (user, int(date), -tz)
261
-
262
- def fix_file_path(path):
263
- path = os.path.normpath(path)
264
- if not os.path.isabs(path):
265
- return path
266
- return os.path.relpath(path, '/')
267
-
268
- def export_files(files):
269
- final = []
270
- for f in files:
271
- fid = node.hex(f.filenode())
272
-
273
- if fid in filenodes:
274
- mark = filenodes[fid]
275
- else:
276
- mark = marks.next_mark()
277
- filenodes[fid] = mark
278
- d = f.data()
279
-
280
- print "blob"
281
- print "mark :%u" % mark
282
- print "data %d" % len(d)
283
- print d
284
-
285
- path = fix_file_path(f.path())
286
- final.append((gitmode(f.flags()), mark, path))
287
-
288
- return final
289
-
290
- def get_filechanges(repo, ctx, parent):
291
- modified = set()
292
- added = set()
293
- removed = set()
294
-
295
- # load earliest manifest first for caching reasons
296
- prev = parent.manifest().copy()
297
- cur = ctx.manifest()
298
-
299
- for fn in cur:
300
- if fn in prev:
301
- if (cur.flags(fn) != prev.flags(fn) or cur[fn] != prev[fn]):
302
- modified.add(fn)
303
- del prev[fn]
304
- else:
305
- added.add(fn)
306
- removed |= set(prev.keys())
307
-
308
- return added | modified, removed
309
-
310
- def fixup_user_git(user):
311
- name = mail = None
312
- user = user.replace('"', '')
313
- m = AUTHOR_RE.match(user)
314
- if m:
315
- name = m.group(1)
316
- mail = m.group(2).strip()
317
- else:
318
- m = EMAIL_RE.match(user)
319
- if m:
320
- mail = m.group(1)
321
- else:
322
- m = NAME_RE.match(user)
323
- if m:
324
- name = m.group(1).strip()
325
- return (name, mail)
326
-
327
- def fixup_user_hg(user):
328
- def sanitize(name):
329
- # stole this from hg-git
330
- return re.sub('[<>\n]', '?', name.lstrip('< ').rstrip('> '))
331
-
332
- m = AUTHOR_HG_RE.match(user)
333
- if m:
334
- name = sanitize(m.group(1))
335
- mail = sanitize(m.group(2))
336
- ex = m.group(3)
337
- if ex:
338
- name += ' ext:(' + urllib.quote(ex) + ')'
339
- else:
340
- name = sanitize(user)
341
- if '@' in user:
342
- mail = name
343
- else:
344
- mail = None
345
-
346
- return (name, mail)
347
-
348
- def fixup_user(user):
349
- if mode == 'git':
350
- name, mail = fixup_user_git(user)
351
- else:
352
- name, mail = fixup_user_hg(user)
353
-
354
- if not name:
355
- name = bad_name
356
- if not mail:
357
- mail = bad_mail
358
-
359
- return '%s <%s>' % (name, mail)
360
-
361
- def updatebookmarks(repo, peer):
362
- remotemarks = peer.listkeys('bookmarks')
363
- localmarks = repo._bookmarks
364
-
365
- if not remotemarks:
366
- return
367
-
368
- for k, v in remotemarks.iteritems():
369
- localmarks[k] = hgbin(v)
370
-
371
- if hasattr(localmarks, 'write'):
372
- localmarks.write()
373
- else:
374
- bookmarks.write(repo)
375
-
376
- def get_repo(url, alias):
377
- global peer
378
-
379
- myui = ui.ui()
380
- myui.setconfig('ui', 'interactive', 'off')
381
- myui.fout = sys.stderr
382
-
383
- if get_config_bool('remote-hg.insecure'):
384
- myui.setconfig('web', 'cacerts', '')
385
-
386
- extensions.loadall(myui)
387
-
388
- if hg.islocal(url) and not os.environ.get('GIT_REMOTE_HG_TEST_REMOTE'):
389
- repo = hg.repository(myui, url)
390
- if not os.path.exists(dirname):
391
- os.makedirs(dirname)
392
- else:
393
- shared_path = os.path.join(gitdir, 'hg')
394
-
395
- # check and upgrade old organization
396
- hg_path = os.path.join(shared_path, '.hg')
397
- if os.path.exists(shared_path) and not os.path.exists(hg_path):
398
- repos = os.listdir(shared_path)
399
- for x in repos:
400
- local_hg = os.path.join(shared_path, x, 'clone', '.hg')
401
- if not os.path.exists(local_hg):
402
- continue
403
- if not os.path.exists(hg_path):
404
- shutil.move(local_hg, hg_path)
405
- shutil.rmtree(os.path.join(shared_path, x, 'clone'))
406
-
407
- # setup shared repo (if not there)
408
- try:
409
- hg.peer(myui, {}, shared_path, create=True)
410
- except error.RepoError:
411
- pass
412
-
413
- if not os.path.exists(dirname):
414
- os.makedirs(dirname)
415
-
416
- local_path = os.path.join(dirname, 'clone')
417
- if not os.path.exists(local_path):
418
- hg.share(myui, shared_path, local_path, update=False)
419
- else:
420
- # make sure the shared path is always up-to-date
421
- util.writefile(os.path.join(local_path, '.hg', 'sharedpath'), hg_path)
422
-
423
- repo = hg.repository(myui, local_path)
424
- try:
425
- peer = hg.peer(myui, {}, url)
426
- except:
427
- die('Repository error')
428
- repo.pull(peer, heads=None, force=True)
429
-
430
- updatebookmarks(repo, peer)
431
-
432
- return repo
433
-
434
- def rev_to_mark(rev):
435
- return marks.from_rev(rev.hex())
436
-
437
- def mark_to_rev(mark):
438
- return marks.to_rev(mark)
439
-
440
- def export_ref(repo, name, kind, head):
441
- ename = '%s/%s' % (kind, name)
442
- try:
443
- tip = marks.get_tip(ename)
444
- tip = repo[tip].rev()
445
- except:
446
- tip = 0
447
-
448
- revs = xrange(tip, head.rev() + 1)
449
- total = len(revs)
450
-
451
- for rev in revs:
452
-
453
- c = repo[rev]
454
- node = c.node()
455
-
456
- if marks.is_marked(c.hex()):
457
- continue
458
-
459
- (manifest, user, (time, tz), files, desc, extra) = repo.changelog.read(node)
460
- rev_branch = extra['branch']
461
-
462
- author = "%s %d %s" % (fixup_user(user), time, gittz(tz))
463
- if 'committer' in extra:
464
- user, time, tz = extra['committer'].rsplit(' ', 2)
465
- committer = "%s %s %s" % (user, time, gittz(int(tz)))
466
- else:
467
- committer = author
468
-
469
- parents = [repo[p] for p in repo.changelog.parentrevs(rev) if p >= 0]
470
-
471
- if len(parents) == 0:
472
- modified = c.manifest().keys()
473
- removed = []
474
- else:
475
- modified, removed = get_filechanges(repo, c, parents[0])
476
-
477
- desc += '\n'
478
-
479
- if mode == 'hg':
480
- extra_msg = ''
481
-
482
- if rev_branch != 'default':
483
- extra_msg += 'branch : %s\n' % rev_branch
484
-
485
- renames = []
486
- for f in c.files():
487
- if f not in c.manifest():
488
- continue
489
- rename = c.filectx(f).renamed()
490
- if rename:
491
- renames.append((rename[0], f))
492
-
493
- for e in renames:
494
- extra_msg += "rename : %s => %s\n" % e
495
-
496
- for key, value in extra.iteritems():
497
- if key in ('author', 'committer', 'encoding', 'message', 'branch', 'hg-git'):
498
- continue
499
- else:
500
- extra_msg += "extra : %s : %s\n" % (key, urllib.quote(value))
501
-
502
- if extra_msg:
503
- desc += '\n--HG--\n' + extra_msg
504
-
505
- if len(parents) == 0 and rev:
506
- print 'reset %s/%s' % (prefix, ename)
507
-
508
- modified_final = export_files(c.filectx(f) for f in modified)
509
-
510
- print "commit %s/%s" % (prefix, ename)
511
- print "mark :%d" % (marks.get_mark(c.hex()))
512
- print "author %s" % (author)
513
- print "committer %s" % (committer)
514
- print "data %d" % (len(desc))
515
- print desc
516
-
517
- if len(parents) > 0:
518
- print "from :%s" % (rev_to_mark(parents[0]))
519
- if len(parents) > 1:
520
- print "merge :%s" % (rev_to_mark(parents[1]))
521
-
522
- for f in removed:
523
- print "D %s" % (fix_file_path(f))
524
- for f in modified_final:
525
- print "M %s :%u %s" % f
526
- print
527
-
528
- progress = (rev - tip)
529
- if (progress % 100 == 0):
530
- print "progress revision %d '%s' (%d/%d)" % (rev, name, progress, total)
531
-
532
- # make sure the ref is updated
533
- print "reset %s/%s" % (prefix, ename)
534
- print "from :%u" % rev_to_mark(head)
535
- print
536
-
537
- pending_revs = set(revs) - notes
538
- if pending_revs:
539
- note_mark = marks.next_mark()
540
- ref = "refs/notes/hg"
541
-
542
- print "commit %s" % ref
543
- print "mark :%d" % (note_mark)
544
- print "committer remote-hg <> %d %s" % (ptime.time(), gittz(ptime.timezone))
545
- desc = "Notes for %s\n" % (name)
546
- print "data %d" % (len(desc))
547
- print desc
548
- if marks.last_note:
549
- print "from :%u" % marks.last_note
550
-
551
- for rev in pending_revs:
552
- notes.add(rev)
553
- c = repo[rev]
554
- print "N inline :%u" % rev_to_mark(c)
555
- msg = c.hex()
556
- print "data %d" % (len(msg))
557
- print msg
558
- print
559
-
560
- marks.last_note = note_mark
561
-
562
- marks.set_tip(ename, head.hex())
563
-
564
- def export_tag(repo, tag):
565
- export_ref(repo, tag, 'tags', repo[hgref(tag)])
566
-
567
- def export_bookmark(repo, bmark):
568
- head = bmarks[hgref(bmark)]
569
- export_ref(repo, bmark, 'bookmarks', head)
570
-
571
- def export_branch(repo, branch):
572
- tip = get_branch_tip(repo, branch)
573
- head = repo[tip]
574
- export_ref(repo, branch, 'branches', head)
575
-
576
- def export_head(repo):
577
- export_ref(repo, g_head[0], 'bookmarks', g_head[1])
578
-
579
- def do_capabilities(parser):
580
- print "import"
581
- print "export"
582
- print "refspec refs/heads/branches/*:%s/branches/*" % prefix
583
- print "refspec refs/heads/*:%s/bookmarks/*" % prefix
584
- print "refspec refs/tags/*:%s/tags/*" % prefix
585
-
586
- path = os.path.join(dirname, 'marks-git')
587
-
588
- if os.path.exists(path):
589
- print "*import-marks %s" % path
590
- print "*export-marks %s" % path
591
- print "option"
592
-
593
- print
594
-
595
- def branch_tip(branch):
596
- return branches[branch][-1]
597
-
598
- def get_branch_tip(repo, branch):
599
- heads = branches.get(hgref(branch), None)
600
- if not heads:
601
- return None
602
-
603
- # verify there's only one head
604
- if (len(heads) > 1):
605
- warn("Branch '%s' has more than one head, consider merging" % branch)
606
- return branch_tip(hgref(branch))
607
-
608
- return heads[0]
609
-
610
- def list_head(repo, cur):
611
- global g_head, fake_bmark
612
-
613
- if 'default' not in branches:
614
- # empty repo
615
- return
616
-
617
- node = repo[branch_tip('default')]
618
- head = 'master' if not 'master' in bmarks else 'default'
619
- fake_bmark = head
620
- bmarks[head] = node
621
-
622
- head = gitref(head)
623
- print "@refs/heads/%s HEAD" % head
624
- g_head = (head, node)
625
-
626
- def do_list(parser):
627
- repo = parser.repo
628
- for bmark, node in bookmarks.listbookmarks(repo).iteritems():
629
- bmarks[bmark] = repo[node]
630
-
631
- cur = repo.dirstate.branch()
632
- orig = peer if peer else repo
633
-
634
- for branch, heads in orig.branchmap().iteritems():
635
- # only open heads
636
- heads = [h for h in heads if 'close' not in repo.changelog.read(h)[5]]
637
- if heads:
638
- branches[branch] = heads
639
-
640
- list_head(repo, cur)
641
-
642
- if track_branches:
643
- for branch in branches:
644
- print "? refs/heads/branches/%s" % gitref(branch)
645
-
646
- for bmark in bmarks:
647
- if bmarks[bmark].hex() == '0000000000000000000000000000000000000000':
648
- warn("Ignoring invalid bookmark '%s'", bmark)
649
- else:
650
- print "? refs/heads/%s" % gitref(bmark)
651
-
652
- for tag, node in repo.tagslist():
653
- if tag == 'tip':
654
- continue
655
- print "? refs/tags/%s" % gitref(tag)
656
-
657
- print
658
-
659
- def do_import(parser):
660
- repo = parser.repo
661
-
662
- path = os.path.join(dirname, 'marks-git')
663
-
664
- print "feature done"
665
- if os.path.exists(path):
666
- print "feature import-marks=%s" % path
667
- print "feature export-marks=%s" % path
668
- print "feature force"
669
- sys.stdout.flush()
670
-
671
- tmp = encoding.encoding
672
- encoding.encoding = 'utf-8'
673
-
674
- # lets get all the import lines
675
- while parser.check('import'):
676
- ref = parser[1]
677
-
678
- if (ref == 'HEAD'):
679
- export_head(repo)
680
- elif ref.startswith('refs/heads/branches/'):
681
- branch = ref[len('refs/heads/branches/'):]
682
- export_branch(repo, branch)
683
- elif ref.startswith('refs/heads/'):
684
- bmark = ref[len('refs/heads/'):]
685
- export_bookmark(repo, bmark)
686
- elif ref.startswith('refs/tags/'):
687
- tag = ref[len('refs/tags/'):]
688
- export_tag(repo, tag)
689
-
690
- parser.next()
691
-
692
- encoding.encoding = tmp
693
-
694
- print 'done'
695
-
696
- def parse_blob(parser):
697
- parser.next()
698
- mark = parser.get_mark()
699
- parser.next()
700
- data = parser.get_data()
701
- blob_marks[mark] = data
702
- parser.next()
703
-
704
- def get_merge_files(repo, p1, p2, files):
705
- for e in repo[p1].files():
706
- if e not in files:
707
- if e not in repo[p1].manifest():
708
- continue
709
- f = { 'ctx' : repo[p1][e] }
710
- files[e] = f
711
-
712
- def c_style_unescape(string):
713
- if string[0] == string[-1] == '"':
714
- return string.decode('string-escape')[1:-1]
715
- return string
716
-
717
- def parse_commit(parser):
718
- from_mark = merge_mark = None
719
-
720
- ref = parser[1]
721
- parser.next()
722
-
723
- commit_mark = parser.get_mark()
724
- parser.next()
725
- author = parser.get_author()
726
- parser.next()
727
- committer = parser.get_author()
728
- parser.next()
729
- data = parser.get_data()
730
- parser.next()
731
- if parser.check('from'):
732
- from_mark = parser.get_mark()
733
- parser.next()
734
- if parser.check('merge'):
735
- merge_mark = parser.get_mark()
736
- parser.next()
737
- if parser.check('merge'):
738
- die('octopus merges are not supported yet')
739
-
740
- # fast-export adds an extra newline
741
- if data[-1] == '\n':
742
- data = data[:-1]
743
-
744
- files = {}
745
-
746
- for line in parser:
747
- if parser.check('M'):
748
- t, m, mark_ref, path = line.split(' ', 3)
749
- mark = int(mark_ref[1:])
750
- f = { 'mode' : hgmode(m), 'data' : blob_marks[mark] }
751
- elif parser.check('D'):
752
- t, path = line.split(' ', 1)
753
- f = { 'deleted' : True }
754
- else:
755
- die('Unknown file command: %s' % line)
756
- path = c_style_unescape(path)
757
- files[path] = f
758
-
759
- # only export the commits if we are on an internal proxy repo
760
- if dry_run and not peer:
761
- parsed_refs[ref] = None
762
- return
763
-
764
- def getfilectx(repo, memctx, f):
765
- of = files[f]
766
- if 'deleted' in of:
767
- raise IOError
768
- if 'ctx' in of:
769
- return of['ctx']
770
- is_exec = of['mode'] == 'x'
771
- is_link = of['mode'] == 'l'
772
- rename = of.get('rename', None)
773
- return context.memfilectx(f, of['data'],
774
- is_link, is_exec, rename)
775
-
776
- repo = parser.repo
777
-
778
- user, date, tz = author
779
- extra = {}
780
-
781
- if committer != author:
782
- extra['committer'] = "%s %u %u" % committer
783
-
784
- if from_mark:
785
- p1 = mark_to_rev(from_mark)
786
- else:
787
- p1 = '0' * 40
788
-
789
- if merge_mark:
790
- p2 = mark_to_rev(merge_mark)
791
- else:
792
- p2 = '0' * 40
793
-
794
- #
795
- # If files changed from any of the parents, hg wants to know, but in git if
796
- # nothing changed from the first parent, nothing changed.
797
- #
798
- if merge_mark:
799
- get_merge_files(repo, p1, p2, files)
800
-
801
- # Check if the ref is supposed to be a named branch
802
- if ref.startswith('refs/heads/branches/'):
803
- branch = ref[len('refs/heads/branches/'):]
804
- extra['branch'] = hgref(branch)
805
-
806
- if mode == 'hg':
807
- i = data.find('\n--HG--\n')
808
- if i >= 0:
809
- tmp = data[i + len('\n--HG--\n'):].strip()
810
- for k, v in [e.split(' : ', 1) for e in tmp.split('\n')]:
811
- if k == 'rename':
812
- old, new = v.split(' => ', 1)
813
- files[new]['rename'] = old
814
- elif k == 'branch':
815
- extra[k] = v
816
- elif k == 'extra':
817
- ek, ev = v.split(' : ', 1)
818
- extra[ek] = urllib.unquote(ev)
819
- data = data[:i]
820
-
821
- ctx = context.memctx(repo, (p1, p2), data,
822
- files.keys(), getfilectx,
823
- user, (date, tz), extra)
824
-
825
- tmp = encoding.encoding
826
- encoding.encoding = 'utf-8'
827
-
828
- node = hghex(repo.commitctx(ctx))
829
-
830
- encoding.encoding = tmp
831
-
832
- parsed_refs[ref] = node
833
- marks.new_mark(node, commit_mark)
834
-
835
- def parse_reset(parser):
836
- ref = parser[1]
837
- parser.next()
838
- # ugh
839
- if parser.check('commit'):
840
- parse_commit(parser)
841
- return
842
- if not parser.check('from'):
843
- return
844
- from_mark = parser.get_mark()
845
- parser.next()
846
-
847
- try:
848
- rev = mark_to_rev(from_mark)
849
- except KeyError:
850
- rev = None
851
- parsed_refs[ref] = rev
852
-
853
- def parse_tag(parser):
854
- name = parser[1]
855
- parser.next()
856
- from_mark = parser.get_mark()
857
- parser.next()
858
- tagger = parser.get_author()
859
- parser.next()
860
- data = parser.get_data()
861
- parser.next()
862
-
863
- parsed_tags[name] = (tagger, data)
864
-
865
- def write_tag(repo, tag, node, msg, author):
866
- branch = repo[node].branch()
867
- tip = branch_tip(branch)
868
- tip = repo[tip]
869
-
870
- def getfilectx(repo, memctx, f):
871
- try:
872
- fctx = tip.filectx(f)
873
- data = fctx.data()
874
- except error.ManifestLookupError:
875
- data = ""
876
- content = data + "%s %s\n" % (node, tag)
877
- return context.memfilectx(f, content, False, False, None)
878
-
879
- p1 = tip.hex()
880
- p2 = '0' * 40
881
- if author:
882
- user, date, tz = author
883
- date_tz = (date, tz)
884
- else:
885
- cmd = ['git', 'var', 'GIT_COMMITTER_IDENT']
886
- process = subprocess.Popen(cmd, stdout=subprocess.PIPE)
887
- output, _ = process.communicate()
888
- m = re.match('^.* <.*>', output)
889
- if m:
890
- user = m.group(0)
891
- else:
892
- user = repo.ui.username()
893
- date_tz = None
894
-
895
- ctx = context.memctx(repo, (p1, p2), msg,
896
- ['.hgtags'], getfilectx,
897
- user, date_tz, {'branch' : branch})
898
-
899
- tmp = encoding.encoding
900
- encoding.encoding = 'utf-8'
901
-
902
- tagnode = repo.commitctx(ctx)
903
-
904
- encoding.encoding = tmp
905
-
906
- return (tagnode, branch)
907
-
908
- def checkheads_bmark(repo, ref, ctx):
909
- bmark = ref[len('refs/heads/'):]
910
- if not bmark in bmarks:
911
- # new bmark
912
- return True
913
-
914
- ctx_old = bmarks[bmark]
915
- ctx_new = ctx
916
- if not repo.changelog.descendant(ctx_old.rev(), ctx_new.rev()):
917
- if force_push:
918
- print "ok %s forced update" % ref
919
- else:
920
- print "error %s non-fast forward" % ref
921
- return False
922
-
923
- return True
924
-
925
- def checkheads(repo, remote, p_revs):
926
-
927
- remotemap = remote.branchmap()
928
- if not remotemap:
929
- # empty repo
930
- return True
931
-
932
- new = {}
933
- ret = True
934
-
935
- for node, ref in p_revs.iteritems():
936
- ctx = repo[node]
937
- branch = ctx.branch()
938
- if not branch in remotemap:
939
- # new branch
940
- continue
941
- if not ref.startswith('refs/heads/branches'):
942
- if ref.startswith('refs/heads/'):
943
- if not checkheads_bmark(repo, ref, ctx):
944
- ret = False
945
-
946
- # only check branches
947
- continue
948
- new.setdefault(branch, []).append(ctx.rev())
949
-
950
- for branch, heads in new.iteritems():
951
- old = [repo.changelog.rev(x) for x in remotemap[branch]]
952
- for rev in heads:
953
- if check_version(2, 3):
954
- ancestors = repo.changelog.ancestors([rev], stoprev=min(old))
955
- else:
956
- ancestors = repo.changelog.ancestors(rev)
957
- found = False
958
-
959
- for x in old:
960
- if x in ancestors:
961
- found = True
962
- break
963
-
964
- if found:
965
- continue
966
-
967
- node = repo.changelog.node(rev)
968
- ref = p_revs[node]
969
- if force_push:
970
- print "ok %s forced update" % ref
971
- else:
972
- print "error %s non-fast forward" % ref
973
- ret = False
974
-
975
- return ret
976
-
977
- def push_unsafe(repo, remote, parsed_refs, p_revs):
978
-
979
- force = force_push
980
-
981
- fci = discovery.findcommonincoming
982
- commoninc = fci(repo, remote, force=force)
983
- common, _, remoteheads = commoninc
984
-
985
- if not checkheads(repo, remote, p_revs):
986
- return None
987
-
988
- cg = repo.getbundle('push', heads=list(p_revs), common=common)
989
-
990
- unbundle = remote.capable('unbundle')
991
- if unbundle:
992
- if force:
993
- remoteheads = ['force']
994
- return remote.unbundle(cg, remoteheads, 'push')
995
- else:
996
- return remote.addchangegroup(cg, 'push', repo.url())
997
-
998
- def push(repo, remote, parsed_refs, p_revs):
999
- if hasattr(remote, 'canpush') and not remote.canpush():
1000
- print "error cannot push"
1001
-
1002
- if not p_revs:
1003
- # nothing to push
1004
- return
1005
-
1006
- lock = None
1007
- unbundle = remote.capable('unbundle')
1008
- if not unbundle:
1009
- lock = remote.lock()
1010
- try:
1011
- ret = push_unsafe(repo, remote, parsed_refs, p_revs)
1012
- finally:
1013
- if lock is not None:
1014
- lock.release()
1015
-
1016
- return ret
1017
-
1018
- def check_tip(ref, kind, name, heads):
1019
- try:
1020
- ename = '%s/%s' % (kind, name)
1021
- tip = marks.get_tip(ename)
1022
- except KeyError:
1023
- return True
1024
- else:
1025
- return tip in heads
1026
-
1027
- def do_export(parser):
1028
- p_bmarks = []
1029
- p_revs = {}
1030
-
1031
- parser.next()
1032
-
1033
- for line in parser.each_block('done'):
1034
- if parser.check('blob'):
1035
- parse_blob(parser)
1036
- elif parser.check('commit'):
1037
- parse_commit(parser)
1038
- elif parser.check('reset'):
1039
- parse_reset(parser)
1040
- elif parser.check('tag'):
1041
- parse_tag(parser)
1042
- elif parser.check('feature'):
1043
- pass
1044
- else:
1045
- die('unhandled export command: %s' % line)
1046
-
1047
- need_fetch = False
1048
-
1049
- for ref, node in parsed_refs.iteritems():
1050
- bnode = hgbin(node) if node else None
1051
- if ref.startswith('refs/heads/branches'):
1052
- branch = ref[len('refs/heads/branches/'):]
1053
- if branch in branches and bnode in branches[branch]:
1054
- # up to date
1055
- continue
1056
-
1057
- if peer:
1058
- remotemap = peer.branchmap()
1059
- if remotemap and branch in remotemap:
1060
- heads = [hghex(e) for e in remotemap[branch]]
1061
- if not check_tip(ref, 'branches', branch, heads):
1062
- print "error %s fetch first" % ref
1063
- need_fetch = True
1064
- continue
1065
-
1066
- p_revs[bnode] = ref
1067
- print "ok %s" % ref
1068
- elif ref.startswith('refs/heads/'):
1069
- bmark = ref[len('refs/heads/'):]
1070
- new = node
1071
- old = bmarks[bmark].hex() if bmark in bmarks else ''
1072
-
1073
- if old == new:
1074
- continue
1075
-
1076
- print "ok %s" % ref
1077
- if bmark != fake_bmark and \
1078
- not (bmark == 'master' and bmark not in parser.repo._bookmarks):
1079
- p_bmarks.append((ref, bmark, old, new))
1080
-
1081
- if peer:
1082
- remote_old = peer.listkeys('bookmarks').get(bmark)
1083
- if remote_old:
1084
- if not check_tip(ref, 'bookmarks', bmark, remote_old):
1085
- print "error %s fetch first" % ref
1086
- need_fetch = True
1087
- continue
1088
-
1089
- p_revs[bnode] = ref
1090
- elif ref.startswith('refs/tags/'):
1091
- if dry_run:
1092
- print "ok %s" % ref
1093
- continue
1094
- tag = ref[len('refs/tags/'):]
1095
- tag = hgref(tag)
1096
- author, msg = parsed_tags.get(tag, (None, None))
1097
- if mode == 'git':
1098
- if not msg:
1099
- msg = 'Added tag %s for changeset %s' % (tag, node[:12])
1100
- tagnode, branch = write_tag(parser.repo, tag, node, msg, author)
1101
- p_revs[tagnode] = 'refs/heads/branches/' + gitref(branch)
1102
- else:
1103
- fp = parser.repo.opener('localtags', 'a')
1104
- fp.write('%s %s\n' % (node, tag))
1105
- fp.close()
1106
- p_revs[bnode] = ref
1107
- print "ok %s" % ref
1108
- else:
1109
- # transport-helper/fast-export bugs
1110
- continue
1111
-
1112
- if need_fetch:
1113
- print
1114
- return
1115
-
1116
- if dry_run:
1117
- if peer and not force_push:
1118
- checkheads(parser.repo, peer, p_revs)
1119
- print
1120
- return
1121
-
1122
- if peer:
1123
- if not push(parser.repo, peer, parsed_refs, p_revs):
1124
- # do not update bookmarks
1125
- print
1126
- return
1127
-
1128
- # update remote bookmarks
1129
- remote_bmarks = peer.listkeys('bookmarks')
1130
- for ref, bmark, old, new in p_bmarks:
1131
- if force_push:
1132
- old = remote_bmarks.get(bmark, '')
1133
- if not peer.pushkey('bookmarks', bmark, old, new):
1134
- print "error %s" % ref
1135
- else:
1136
- # update local bookmarks
1137
- for ref, bmark, old, new in p_bmarks:
1138
- if not bookmarks.pushbookmark(parser.repo, bmark, old, new):
1139
- print "error %s" % ref
1140
-
1141
- print
1142
-
1143
- def do_option(parser):
1144
- global dry_run, force_push
1145
- _, key, value = parser.line.split(' ')
1146
- if key == 'dry-run':
1147
- dry_run = (value == 'true')
1148
- print 'ok'
1149
- elif key == 'force':
1150
- force_push = (value == 'true')
1151
- print 'ok'
1152
- else:
1153
- print 'unsupported'
1154
-
1155
- def fix_path(alias, repo, orig_url):
1156
- url = urlparse.urlparse(orig_url, 'file')
1157
- if url.scheme != 'file' or os.path.isabs(os.path.expanduser(url.path)):
1158
- return
1159
- abs_url = urlparse.urljoin("%s/" % os.getcwd(), orig_url)
1160
- cmd = ['git', 'config', 'remote.%s.url' % alias, "hg::%s" % abs_url]
1161
- subprocess.call(cmd)
1162
-
1163
- def main(args):
1164
- global prefix, gitdir, dirname, branches, bmarks
1165
- global marks, blob_marks, parsed_refs
1166
- global peer, mode, bad_mail, bad_name
1167
- global track_branches, force_push, is_tmp
1168
- global parsed_tags
1169
- global filenodes
1170
- global fake_bmark, hg_version
1171
- global dry_run
1172
- global notes, alias
1173
-
1174
- marks = None
1175
- is_tmp = False
1176
- gitdir = os.environ.get('GIT_DIR', None)
1177
-
1178
- if len(args) < 3:
1179
- die('Not enough arguments.')
1180
-
1181
- if not gitdir:
1182
- die('GIT_DIR not set')
1183
-
1184
- alias = args[1]
1185
- url = args[2]
1186
- peer = None
1187
-
1188
- hg_git_compat = get_config_bool('remote-hg.hg-git-compat')
1189
- track_branches = get_config_bool('remote-hg.track-branches', True)
1190
- force_push = False
1191
-
1192
- if hg_git_compat:
1193
- mode = 'hg'
1194
- bad_mail = 'none@none'
1195
- bad_name = ''
1196
- else:
1197
- mode = 'git'
1198
- bad_mail = 'unknown'
1199
- bad_name = 'Unknown'
1200
-
1201
- if alias[4:] == url:
1202
- is_tmp = True
1203
- alias = hashlib.sha1(alias).hexdigest()
1204
-
1205
- dirname = os.path.join(gitdir, 'hg', alias)
1206
- branches = {}
1207
- bmarks = {}
1208
- blob_marks = {}
1209
- parsed_refs = {}
1210
- parsed_tags = {}
1211
- filenodes = {}
1212
- fake_bmark = None
1213
- try:
1214
- hg_version = tuple(int(e) for e in util.version().split('.'))
1215
- except:
1216
- hg_version = None
1217
- dry_run = False
1218
- notes = set()
1219
-
1220
- repo = get_repo(url, alias)
1221
- prefix = 'refs/hg/%s' % alias
1222
-
1223
- if not is_tmp:
1224
- fix_path(alias, peer or repo, url)
1225
-
1226
- marks_path = os.path.join(dirname, 'marks-hg')
1227
- marks = Marks(marks_path, repo)
1228
-
1229
- if sys.platform == 'win32':
1230
- import msvcrt
1231
- msvcrt.setmode(sys.stdout.fileno(), os.O_BINARY)
1232
-
1233
- parser = Parser(repo)
1234
- for line in parser:
1235
- if parser.check('capabilities'):
1236
- do_capabilities(parser)
1237
- elif parser.check('list'):
1238
- do_list(parser)
1239
- elif parser.check('import'):
1240
- do_import(parser)
1241
- elif parser.check('export'):
1242
- do_export(parser)
1243
- elif parser.check('option'):
1244
- do_option(parser)
1245
- else:
1246
- die('unhandled command: %s' % line)
1247
- sys.stdout.flush()
1248
-
1249
- def bye():
1250
- if not marks:
1251
- return
1252
- if not is_tmp:
1253
- marks.store()
1254
- else:
1255
- shutil.rmtree(dirname)
1256
-
1257
- atexit.register(bye)
1258
- sys.exit(main(sys.argv))