45 reporelpath = subrepoutil.reporelpath |
45 reporelpath = subrepoutil.reporelpath |
46 subrelpath = subrepoutil.subrelpath |
46 subrelpath = subrepoutil.subrelpath |
47 _abssource = subrepoutil._abssource |
47 _abssource = subrepoutil._abssource |
48 propertycache = util.propertycache |
48 propertycache = util.propertycache |
49 |
49 |
|
50 |
50 def _expandedabspath(path): |
51 def _expandedabspath(path): |
51 ''' |
52 ''' |
52 get a path or url and if it is a path expand it and return an absolute path |
53 get a path or url and if it is a path expand it and return an absolute path |
53 ''' |
54 ''' |
54 expandedpath = util.urllocalpath(util.expandpath(path)) |
55 expandedpath = util.urllocalpath(util.expandpath(path)) |
55 u = util.url(expandedpath) |
56 u = util.url(expandedpath) |
56 if not u.scheme: |
57 if not u.scheme: |
57 path = util.normpath(os.path.abspath(u.path)) |
58 path = util.normpath(os.path.abspath(u.path)) |
58 return path |
59 return path |
59 |
60 |
|
61 |
60 def _getstorehashcachename(remotepath): |
62 def _getstorehashcachename(remotepath): |
61 '''get a unique filename for the store hash cache of a remote repository''' |
63 '''get a unique filename for the store hash cache of a remote repository''' |
62 return node.hex(hashlib.sha1(_expandedabspath(remotepath)).digest())[0:12] |
64 return node.hex(hashlib.sha1(_expandedabspath(remotepath)).digest())[0:12] |
63 |
65 |
|
66 |
64 class SubrepoAbort(error.Abort): |
67 class SubrepoAbort(error.Abort): |
65 """Exception class used to avoid handling a subrepo error more than once""" |
68 """Exception class used to avoid handling a subrepo error more than once""" |
|
69 |
66 def __init__(self, *args, **kw): |
70 def __init__(self, *args, **kw): |
67 self.subrepo = kw.pop(r'subrepo', None) |
71 self.subrepo = kw.pop(r'subrepo', None) |
68 self.cause = kw.pop(r'cause', None) |
72 self.cause = kw.pop(r'cause', None) |
69 error.Abort.__init__(self, *args, **kw) |
73 error.Abort.__init__(self, *args, **kw) |
|
74 |
70 |
75 |
71 def annotatesubrepoerror(func): |
76 def annotatesubrepoerror(func): |
72 def decoratedmethod(self, *args, **kargs): |
77 def decoratedmethod(self, *args, **kargs): |
73 try: |
78 try: |
74 res = func(self, *args, **kargs) |
79 res = func(self, *args, **kargs) |
75 except SubrepoAbort as ex: |
80 except SubrepoAbort as ex: |
76 # This exception has already been handled |
81 # This exception has already been handled |
77 raise ex |
82 raise ex |
78 except error.Abort as ex: |
83 except error.Abort as ex: |
79 subrepo = subrelpath(self) |
84 subrepo = subrelpath(self) |
80 errormsg = (stringutil.forcebytestr(ex) + ' ' |
85 errormsg = ( |
81 + _('(in subrepository "%s")') % subrepo) |
86 stringutil.forcebytestr(ex) |
|
87 + ' ' |
|
88 + _('(in subrepository "%s")') % subrepo |
|
89 ) |
82 # avoid handling this exception by raising a SubrepoAbort exception |
90 # avoid handling this exception by raising a SubrepoAbort exception |
83 raise SubrepoAbort(errormsg, hint=ex.hint, subrepo=subrepo, |
91 raise SubrepoAbort( |
84 cause=sys.exc_info()) |
92 errormsg, hint=ex.hint, subrepo=subrepo, cause=sys.exc_info() |
|
93 ) |
85 return res |
94 return res |
|
95 |
86 return decoratedmethod |
96 return decoratedmethod |
|
97 |
87 |
98 |
88 def _updateprompt(ui, sub, dirty, local, remote): |
99 def _updateprompt(ui, sub, dirty, local, remote): |
89 if dirty: |
100 if dirty: |
90 msg = (_(' subrepository sources for %s differ\n' |
101 msg = _( |
91 'you can use (l)ocal source (%s) or (r)emote source (%s).\n' |
102 ' subrepository sources for %s differ\n' |
92 'what do you want to do?' |
103 'you can use (l)ocal source (%s) or (r)emote source (%s).\n' |
93 '$$ &Local $$ &Remote') |
104 'what do you want to do?' |
94 % (subrelpath(sub), local, remote)) |
105 '$$ &Local $$ &Remote' |
|
106 ) % (subrelpath(sub), local, remote) |
95 else: |
107 else: |
96 msg = (_(' subrepository sources for %s differ (in checked out ' |
108 msg = _( |
97 'version)\n' |
109 ' subrepository sources for %s differ (in checked out ' |
98 'you can use (l)ocal source (%s) or (r)emote source (%s).\n' |
110 'version)\n' |
99 'what do you want to do?' |
111 'you can use (l)ocal source (%s) or (r)emote source (%s).\n' |
100 '$$ &Local $$ &Remote') |
112 'what do you want to do?' |
101 % (subrelpath(sub), local, remote)) |
113 '$$ &Local $$ &Remote' |
|
114 ) % (subrelpath(sub), local, remote) |
102 return ui.promptchoice(msg, 0) |
115 return ui.promptchoice(msg, 0) |
|
116 |
103 |
117 |
104 def _sanitize(ui, vfs, ignore): |
118 def _sanitize(ui, vfs, ignore): |
105 for dirname, dirs, names in vfs.walk(): |
119 for dirname, dirs, names in vfs.walk(): |
106 for i, d in enumerate(dirs): |
120 for i, d in enumerate(dirs): |
107 if d.lower() == ignore: |
121 if d.lower() == ignore: |
109 break |
123 break |
110 if vfs.basename(dirname).lower() != '.hg': |
124 if vfs.basename(dirname).lower() != '.hg': |
111 continue |
125 continue |
112 for f in names: |
126 for f in names: |
113 if f.lower() == 'hgrc': |
127 if f.lower() == 'hgrc': |
114 ui.warn(_("warning: removing potentially hostile 'hgrc' " |
128 ui.warn( |
115 "in '%s'\n") % vfs.join(dirname)) |
129 _( |
|
130 "warning: removing potentially hostile 'hgrc' " |
|
131 "in '%s'\n" |
|
132 ) |
|
133 % vfs.join(dirname) |
|
134 ) |
116 vfs.unlink(vfs.reljoin(dirname, f)) |
135 vfs.unlink(vfs.reljoin(dirname, f)) |
|
136 |
117 |
137 |
118 def _auditsubrepopath(repo, path): |
138 def _auditsubrepopath(repo, path): |
119 # sanity check for potentially unsafe paths such as '~' and '$FOO' |
139 # sanity check for potentially unsafe paths such as '~' and '$FOO' |
120 if path.startswith('~') or '$' in path or util.expandpath(path) != path: |
140 if path.startswith('~') or '$' in path or util.expandpath(path) != path: |
121 raise error.Abort(_('subrepo path contains illegal component: %s') |
141 raise error.Abort( |
122 % path) |
142 _('subrepo path contains illegal component: %s') % path |
|
143 ) |
123 # auditor doesn't check if the path itself is a symlink |
144 # auditor doesn't check if the path itself is a symlink |
124 pathutil.pathauditor(repo.root)(path) |
145 pathutil.pathauditor(repo.root)(path) |
125 if repo.wvfs.islink(path): |
146 if repo.wvfs.islink(path): |
126 raise error.Abort(_("subrepo '%s' traverses symbolic link") % path) |
147 raise error.Abort(_("subrepo '%s' traverses symbolic link") % path) |
|
148 |
127 |
149 |
128 SUBREPO_ALLOWED_DEFAULTS = { |
150 SUBREPO_ALLOWED_DEFAULTS = { |
129 'hg': True, |
151 'hg': True, |
130 'git': False, |
152 'git': False, |
131 'svn': False, |
153 'svn': False, |
132 } |
154 } |
133 |
155 |
|
156 |
134 def _checktype(ui, kind): |
157 def _checktype(ui, kind): |
135 # subrepos.allowed is a master kill switch. If disabled, subrepos are |
158 # subrepos.allowed is a master kill switch. If disabled, subrepos are |
136 # disabled period. |
159 # disabled period. |
137 if not ui.configbool('subrepos', 'allowed', True): |
160 if not ui.configbool('subrepos', 'allowed', True): |
138 raise error.Abort(_('subrepos not enabled'), |
161 raise error.Abort( |
139 hint=_("see 'hg help config.subrepos' for details")) |
162 _('subrepos not enabled'), |
|
163 hint=_("see 'hg help config.subrepos' for details"), |
|
164 ) |
140 |
165 |
141 default = SUBREPO_ALLOWED_DEFAULTS.get(kind, False) |
166 default = SUBREPO_ALLOWED_DEFAULTS.get(kind, False) |
142 if not ui.configbool('subrepos', '%s:allowed' % kind, default): |
167 if not ui.configbool('subrepos', '%s:allowed' % kind, default): |
143 raise error.Abort(_('%s subrepos not allowed') % kind, |
168 raise error.Abort( |
144 hint=_("see 'hg help config.subrepos' for details")) |
169 _('%s subrepos not allowed') % kind, |
|
170 hint=_("see 'hg help config.subrepos' for details"), |
|
171 ) |
145 |
172 |
146 if kind not in types: |
173 if kind not in types: |
147 raise error.Abort(_('unknown subrepo type %s') % kind) |
174 raise error.Abort(_('unknown subrepo type %s') % kind) |
|
175 |
148 |
176 |
149 def subrepo(ctx, path, allowwdir=False, allowcreate=True): |
177 def subrepo(ctx, path, allowwdir=False, allowcreate=True): |
150 """return instance of the right subrepo class for subrepo in path""" |
178 """return instance of the right subrepo class for subrepo in path""" |
151 # subrepo inherently violates our import layering rules |
179 # subrepo inherently violates our import layering rules |
152 # because it wants to make repo objects from deep inside the stack |
180 # because it wants to make repo objects from deep inside the stack |
153 # so we manually delay the circular imports to not break |
181 # so we manually delay the circular imports to not break |
154 # scripts that don't use our demand-loading |
182 # scripts that don't use our demand-loading |
155 global hg |
183 global hg |
156 from . import hg as h |
184 from . import hg as h |
|
185 |
157 hg = h |
186 hg = h |
158 |
187 |
159 repo = ctx.repo() |
188 repo = ctx.repo() |
160 _auditsubrepopath(repo, path) |
189 _auditsubrepopath(repo, path) |
161 state = ctx.substate[path] |
190 state = ctx.substate[path] |
162 _checktype(repo.ui, state[2]) |
191 _checktype(repo.ui, state[2]) |
163 if allowwdir: |
192 if allowwdir: |
164 state = (state[0], ctx.subrev(path), state[2]) |
193 state = (state[0], ctx.subrev(path), state[2]) |
165 return types[state[2]](ctx, path, state[:2], allowcreate) |
194 return types[state[2]](ctx, path, state[:2], allowcreate) |
|
195 |
166 |
196 |
167 def nullsubrepo(ctx, path, pctx): |
197 def nullsubrepo(ctx, path, pctx): |
168 """return an empty subrepo in pctx for the extant subrepo in ctx""" |
198 """return an empty subrepo in pctx for the extant subrepo in ctx""" |
169 # subrepo inherently violates our import layering rules |
199 # subrepo inherently violates our import layering rules |
170 # because it wants to make repo objects from deep inside the stack |
200 # because it wants to make repo objects from deep inside the stack |
171 # so we manually delay the circular imports to not break |
201 # so we manually delay the circular imports to not break |
172 # scripts that don't use our demand-loading |
202 # scripts that don't use our demand-loading |
173 global hg |
203 global hg |
174 from . import hg as h |
204 from . import hg as h |
|
205 |
175 hg = h |
206 hg = h |
176 |
207 |
177 repo = ctx.repo() |
208 repo = ctx.repo() |
178 _auditsubrepopath(repo, path) |
209 _auditsubrepopath(repo, path) |
179 state = ctx.substate[path] |
210 state = ctx.substate[path] |
358 ''' |
392 ''' |
359 |
393 |
360 def forget(self, match, prefix, uipathfn, dryrun, interactive): |
394 def forget(self, match, prefix, uipathfn, dryrun, interactive): |
361 return ([], []) |
395 return ([], []) |
362 |
396 |
363 def removefiles(self, matcher, prefix, uipathfn, after, force, subrepos, |
397 def removefiles( |
364 dryrun, warnings): |
398 self, |
|
399 matcher, |
|
400 prefix, |
|
401 uipathfn, |
|
402 after, |
|
403 force, |
|
404 subrepos, |
|
405 dryrun, |
|
406 warnings, |
|
407 ): |
365 """remove the matched files from the subrepository and the filesystem, |
408 """remove the matched files from the subrepository and the filesystem, |
366 possibly by force and/or after the file has been removed from the |
409 possibly by force and/or after the file has been removed from the |
367 filesystem. Return 0 on success, 1 on any warning. |
410 filesystem. Return 0 on success, 1 on any warning. |
368 """ |
411 """ |
369 warnings.append(_("warning: removefiles not implemented (%s)") |
412 warnings.append( |
370 % self._path) |
413 _("warning: removefiles not implemented (%s)") % self._path |
|
414 ) |
371 return 1 |
415 return 1 |
372 |
416 |
373 def revert(self, substate, *pats, **opts): |
417 def revert(self, substate, *pats, **opts): |
374 self.ui.warn(_('%s: reverting %s subrepos is unsupported\n') |
418 self.ui.warn( |
375 % (substate[0], substate[2])) |
419 _('%s: reverting %s subrepos is unsupported\n') |
|
420 % (substate[0], substate[2]) |
|
421 ) |
376 return [] |
422 return [] |
377 |
423 |
378 def shortid(self, revid): |
424 def shortid(self, revid): |
379 return revid |
425 return revid |
380 |
426 |
409 root = r.wjoin(util.localpath(path)) |
456 root = r.wjoin(util.localpath(path)) |
410 create = allowcreate and not r.wvfs.exists('%s/.hg' % path) |
457 create = allowcreate and not r.wvfs.exists('%s/.hg' % path) |
411 # repository constructor does expand variables in path, which is |
458 # repository constructor does expand variables in path, which is |
412 # unsafe since subrepo path might come from untrusted source. |
459 # unsafe since subrepo path might come from untrusted source. |
413 if os.path.realpath(util.expandpath(root)) != root: |
460 if os.path.realpath(util.expandpath(root)) != root: |
414 raise error.Abort(_('subrepo path contains illegal component: %s') |
461 raise error.Abort( |
415 % path) |
462 _('subrepo path contains illegal component: %s') % path |
|
463 ) |
416 self._repo = hg.repository(r.baseui, root, create=create) |
464 self._repo = hg.repository(r.baseui, root, create=create) |
417 if self._repo.root != root: |
465 if self._repo.root != root: |
418 raise error.ProgrammingError('failed to reject unsafe subrepo ' |
466 raise error.ProgrammingError( |
419 'path: %s (expanded to %s)' |
467 'failed to reject unsafe subrepo ' |
420 % (root, self._repo.root)) |
468 'path: %s (expanded to %s)' % (root, self._repo.root) |
|
469 ) |
421 |
470 |
422 # Propagate the parent's --hidden option |
471 # Propagate the parent's --hidden option |
423 if r is r.unfiltered(): |
472 if r is r.unfiltered(): |
424 self._repo = self._repo.unfiltered() |
473 self._repo = self._repo.unfiltered() |
425 |
474 |
517 |
566 |
518 self._repo.vfs.write('hgrc', util.tonativeeol(''.join(lines))) |
567 self._repo.vfs.write('hgrc', util.tonativeeol(''.join(lines))) |
519 |
568 |
520 @annotatesubrepoerror |
569 @annotatesubrepoerror |
521 def add(self, ui, match, prefix, uipathfn, explicitonly, **opts): |
570 def add(self, ui, match, prefix, uipathfn, explicitonly, **opts): |
522 return cmdutil.add(ui, self._repo, match, prefix, uipathfn, |
571 return cmdutil.add( |
523 explicitonly, **opts) |
572 ui, self._repo, match, prefix, uipathfn, explicitonly, **opts |
|
573 ) |
524 |
574 |
525 @annotatesubrepoerror |
575 @annotatesubrepoerror |
526 def addremove(self, m, prefix, uipathfn, opts): |
576 def addremove(self, m, prefix, uipathfn, opts): |
527 # In the same way as sub directories are processed, once in a subrepo, |
577 # In the same way as sub directories are processed, once in a subrepo, |
528 # always entry any of its subrepos. Don't corrupt the options that will |
578 # always entry any of its subrepos. Don't corrupt the options that will |
533 |
583 |
534 @annotatesubrepoerror |
584 @annotatesubrepoerror |
535 def cat(self, match, fm, fntemplate, prefix, **opts): |
585 def cat(self, match, fm, fntemplate, prefix, **opts): |
536 rev = self._state[1] |
586 rev = self._state[1] |
537 ctx = self._repo[rev] |
587 ctx = self._repo[rev] |
538 return cmdutil.cat(self.ui, self._repo, ctx, match, fm, fntemplate, |
588 return cmdutil.cat( |
539 prefix, **opts) |
589 self.ui, self._repo, ctx, match, fm, fntemplate, prefix, **opts |
|
590 ) |
540 |
591 |
541 @annotatesubrepoerror |
592 @annotatesubrepoerror |
542 def status(self, rev2, **opts): |
593 def status(self, rev2, **opts): |
543 try: |
594 try: |
544 rev1 = self._state[1] |
595 rev1 = self._state[1] |
545 ctx1 = self._repo[rev1] |
596 ctx1 = self._repo[rev1] |
546 ctx2 = self._repo[rev2] |
597 ctx2 = self._repo[rev2] |
547 return self._repo.status(ctx1, ctx2, **opts) |
598 return self._repo.status(ctx1, ctx2, **opts) |
548 except error.RepoLookupError as inst: |
599 except error.RepoLookupError as inst: |
549 self.ui.warn(_('warning: error "%s" in subrepository "%s"\n') |
600 self.ui.warn( |
550 % (inst, subrelpath(self))) |
601 _('warning: error "%s" in subrepository "%s"\n') |
|
602 % (inst, subrelpath(self)) |
|
603 ) |
551 return scmutil.status([], [], [], [], [], [], []) |
604 return scmutil.status([], [], [], [], [], [], []) |
552 |
605 |
553 @annotatesubrepoerror |
606 @annotatesubrepoerror |
554 def diff(self, ui, diffopts, node2, match, prefix, **opts): |
607 def diff(self, ui, diffopts, node2, match, prefix, **opts): |
555 try: |
608 try: |
556 node1 = node.bin(self._state[1]) |
609 node1 = node.bin(self._state[1]) |
557 # We currently expect node2 to come from substate and be |
610 # We currently expect node2 to come from substate and be |
558 # in hex format |
611 # in hex format |
559 if node2 is not None: |
612 if node2 is not None: |
560 node2 = node.bin(node2) |
613 node2 = node.bin(node2) |
561 logcmdutil.diffordiffstat(ui, self._repo, diffopts, node1, node2, |
614 logcmdutil.diffordiffstat( |
562 match, prefix=prefix, listsubrepos=True, |
615 ui, |
563 **opts) |
616 self._repo, |
|
617 diffopts, |
|
618 node1, |
|
619 node2, |
|
620 match, |
|
621 prefix=prefix, |
|
622 listsubrepos=True, |
|
623 **opts |
|
624 ) |
564 except error.RepoLookupError as inst: |
625 except error.RepoLookupError as inst: |
565 self.ui.warn(_('warning: error "%s" in subrepository "%s"\n') |
626 self.ui.warn( |
566 % (inst, subrelpath(self))) |
627 _('warning: error "%s" in subrepository "%s"\n') |
|
628 % (inst, subrelpath(self)) |
|
629 ) |
567 |
630 |
568 @annotatesubrepoerror |
631 @annotatesubrepoerror |
569 def archive(self, archiver, prefix, match=None, decode=True): |
632 def archive(self, archiver, prefix, match=None, decode=True): |
570 self._get(self._state + ('hg',)) |
633 self._get(self._state + ('hg',)) |
571 files = self.files() |
634 files = self.files() |
572 if match: |
635 if match: |
573 files = [f for f in files if match(f)] |
636 files = [f for f in files if match(f)] |
574 rev = self._state[1] |
637 rev = self._state[1] |
575 ctx = self._repo[rev] |
638 ctx = self._repo[rev] |
576 scmutil.prefetchfiles(self._repo, [ctx.rev()], |
639 scmutil.prefetchfiles( |
577 scmutil.matchfiles(self._repo, files)) |
640 self._repo, [ctx.rev()], scmutil.matchfiles(self._repo, files) |
|
641 ) |
578 total = abstractsubrepo.archive(self, archiver, prefix, match) |
642 total = abstractsubrepo.archive(self, archiver, prefix, match) |
579 for subpath in ctx.substate: |
643 for subpath in ctx.substate: |
580 s = subrepo(ctx, subpath, True) |
644 s = subrepo(ctx, subpath, True) |
581 submatch = matchmod.subdirmatcher(subpath, match) |
645 submatch = matchmod.subdirmatcher(subpath, match) |
582 subprefix = prefix + subpath + '/' |
646 subprefix = prefix + subpath + '/' |
583 total += s.archive(archiver, subprefix, submatch, |
647 total += s.archive(archiver, subprefix, submatch, decode) |
584 decode) |
|
585 return total |
648 return total |
586 |
649 |
587 @annotatesubrepoerror |
650 @annotatesubrepoerror |
588 def dirty(self, ignoreupdate=False, missing=False): |
651 def dirty(self, ignoreupdate=False, missing=False): |
589 r = self._state[1] |
652 r = self._state[1] |
590 if r == '' and not ignoreupdate: # no state recorded |
653 if r == '' and not ignoreupdate: # no state recorded |
591 return True |
654 return True |
592 w = self._repo[None] |
655 w = self._repo[None] |
593 if r != w.p1().hex() and not ignoreupdate: |
656 if r != w.p1().hex() and not ignoreupdate: |
594 # different version checked out |
657 # different version checked out |
595 return True |
658 return True |
596 return w.dirty(missing=missing) # working directory changed |
659 return w.dirty(missing=missing) # working directory changed |
597 |
660 |
598 def basestate(self): |
661 def basestate(self): |
599 return self._repo['.'].hex() |
662 return self._repo['.'].hex() |
600 |
663 |
601 def checknested(self, path): |
664 def checknested(self, path): |
647 # relative to the parent's share source. But clone pooling doesn't |
710 # relative to the parent's share source. But clone pooling doesn't |
648 # assemble the repos in a tree, so that can't be consistently done. |
711 # assemble the repos in a tree, so that can't be consistently done. |
649 # A simpler option is for the user to configure clone pooling, and |
712 # A simpler option is for the user to configure clone pooling, and |
650 # work with that. |
713 # work with that. |
651 if parentrepo.shared() and hg.islocal(srcurl): |
714 if parentrepo.shared() and hg.islocal(srcurl): |
652 self.ui.status(_('sharing subrepo %s from %s\n') |
715 self.ui.status( |
653 % (subrelpath(self), srcurl)) |
716 _('sharing subrepo %s from %s\n') |
654 shared = hg.share(self._repo._subparent.baseui, |
717 % (subrelpath(self), srcurl) |
655 getpeer(), self._repo.root, |
718 ) |
656 update=False, bookmarks=False) |
719 shared = hg.share( |
|
720 self._repo._subparent.baseui, |
|
721 getpeer(), |
|
722 self._repo.root, |
|
723 update=False, |
|
724 bookmarks=False, |
|
725 ) |
657 self._repo = shared.local() |
726 self._repo = shared.local() |
658 else: |
727 else: |
659 # TODO: find a common place for this and this code in the |
728 # TODO: find a common place for this and this code in the |
660 # share.py wrap of the clone command. |
729 # share.py wrap of the clone command. |
661 if parentrepo.shared(): |
730 if parentrepo.shared(): |
668 'mode': self.ui.config('share', 'poolnaming'), |
737 'mode': self.ui.config('share', 'poolnaming'), |
669 } |
738 } |
670 else: |
739 else: |
671 shareopts = {} |
740 shareopts = {} |
672 |
741 |
673 self.ui.status(_('cloning subrepo %s from %s\n') |
742 self.ui.status( |
674 % (subrelpath(self), util.hidepassword(srcurl))) |
743 _('cloning subrepo %s from %s\n') |
675 other, cloned = hg.clone(self._repo._subparent.baseui, {}, |
744 % (subrelpath(self), util.hidepassword(srcurl)) |
676 getpeer(), self._repo.root, |
745 ) |
677 update=False, shareopts=shareopts) |
746 other, cloned = hg.clone( |
|
747 self._repo._subparent.baseui, |
|
748 {}, |
|
749 getpeer(), |
|
750 self._repo.root, |
|
751 update=False, |
|
752 shareopts=shareopts, |
|
753 ) |
678 self._repo = cloned.local() |
754 self._repo = cloned.local() |
679 self._initrepo(parentrepo, source, create=True) |
755 self._initrepo(parentrepo, source, create=True) |
680 self._cachestorehash(srcurl) |
756 self._cachestorehash(srcurl) |
681 else: |
757 else: |
682 self.ui.status(_('pulling subrepo %s from %s\n') |
758 self.ui.status( |
683 % (subrelpath(self), util.hidepassword(srcurl))) |
759 _('pulling subrepo %s from %s\n') |
|
760 % (subrelpath(self), util.hidepassword(srcurl)) |
|
761 ) |
684 cleansub = self.storeclean(srcurl) |
762 cleansub = self.storeclean(srcurl) |
685 exchange.pull(self._repo, getpeer()) |
763 exchange.pull(self._repo, getpeer()) |
686 if cleansub: |
764 if cleansub: |
687 # keep the repo clean after pull |
765 # keep the repo clean after pull |
688 self._cachestorehash(srcurl) |
766 self._cachestorehash(srcurl) |
739 newbranch = opts.get('new_branch') |
820 newbranch = opts.get('new_branch') |
740 ssh = opts.get('ssh') |
821 ssh = opts.get('ssh') |
741 |
822 |
742 # push subrepos depth-first for coherent ordering |
823 # push subrepos depth-first for coherent ordering |
743 c = self._repo['.'] |
824 c = self._repo['.'] |
744 subs = c.substate # only repos that are committed |
825 subs = c.substate # only repos that are committed |
745 for s in sorted(subs): |
826 for s in sorted(subs): |
746 if c.sub(s).push(opts) == 0: |
827 if c.sub(s).push(opts) == 0: |
747 return False |
828 return False |
748 |
829 |
749 dsturl = _abssource(self._repo, True) |
830 dsturl = _abssource(self._repo, True) |
750 if not force: |
831 if not force: |
751 if self.storeclean(dsturl): |
832 if self.storeclean(dsturl): |
752 self.ui.status( |
833 self.ui.status( |
753 _('no changes made to subrepo %s since last push to %s\n') |
834 _('no changes made to subrepo %s since last push to %s\n') |
754 % (subrelpath(self), util.hidepassword(dsturl))) |
835 % (subrelpath(self), util.hidepassword(dsturl)) |
|
836 ) |
755 return None |
837 return None |
756 self.ui.status(_('pushing subrepo %s to %s\n') % |
838 self.ui.status( |
757 (subrelpath(self), util.hidepassword(dsturl))) |
839 _('pushing subrepo %s to %s\n') |
|
840 % (subrelpath(self), util.hidepassword(dsturl)) |
|
841 ) |
758 other = hg.peer(self._repo, {'ssh': ssh}, dsturl) |
842 other = hg.peer(self._repo, {'ssh': ssh}, dsturl) |
759 res = exchange.push(self._repo, other, force, newbranch=newbranch) |
843 res = exchange.push(self._repo, other, force, newbranch=newbranch) |
760 |
844 |
761 # the repo is now clean |
845 # the repo is now clean |
762 self._cachestorehash(dsturl) |
846 self._cachestorehash(dsturl) |
823 try: |
907 try: |
824 sm = sub.matchfileset(expr, badfn=badfn) |
908 sm = sub.matchfileset(expr, badfn=badfn) |
825 pm = matchmod.prefixdirmatcher(subpath, sm, badfn=badfn) |
909 pm = matchmod.prefixdirmatcher(subpath, sm, badfn=badfn) |
826 matchers.append(pm) |
910 matchers.append(pm) |
827 except error.LookupError: |
911 except error.LookupError: |
828 self.ui.status(_("skipping missing subrepository: %s\n") |
912 self.ui.status( |
829 % self.wvfs.reljoin(reporelpath(self), subpath)) |
913 _("skipping missing subrepository: %s\n") |
|
914 % self.wvfs.reljoin(reporelpath(self), subpath) |
|
915 ) |
830 if len(matchers) == 1: |
916 if len(matchers) == 1: |
831 return matchers[0] |
917 return matchers[0] |
832 return matchmod.unionmatcher(matchers) |
918 return matchmod.unionmatcher(matchers) |
833 |
919 |
834 def walk(self, match): |
920 def walk(self, match): |
835 ctx = self._repo[None] |
921 ctx = self._repo[None] |
836 return ctx.walk(match) |
922 return ctx.walk(match) |
837 |
923 |
838 @annotatesubrepoerror |
924 @annotatesubrepoerror |
839 def forget(self, match, prefix, uipathfn, dryrun, interactive): |
925 def forget(self, match, prefix, uipathfn, dryrun, interactive): |
840 return cmdutil.forget(self.ui, self._repo, match, prefix, uipathfn, |
926 return cmdutil.forget( |
841 True, dryrun=dryrun, interactive=interactive) |
927 self.ui, |
842 |
928 self._repo, |
843 @annotatesubrepoerror |
929 match, |
844 def removefiles(self, matcher, prefix, uipathfn, after, force, subrepos, |
930 prefix, |
845 dryrun, warnings): |
931 uipathfn, |
846 return cmdutil.remove(self.ui, self._repo, matcher, prefix, uipathfn, |
932 True, |
847 after, force, subrepos, dryrun) |
933 dryrun=dryrun, |
|
934 interactive=interactive, |
|
935 ) |
|
936 |
|
937 @annotatesubrepoerror |
|
938 def removefiles( |
|
939 self, |
|
940 matcher, |
|
941 prefix, |
|
942 uipathfn, |
|
943 after, |
|
944 force, |
|
945 subrepos, |
|
946 dryrun, |
|
947 warnings, |
|
948 ): |
|
949 return cmdutil.remove( |
|
950 self.ui, |
|
951 self._repo, |
|
952 matcher, |
|
953 prefix, |
|
954 uipathfn, |
|
955 after, |
|
956 force, |
|
957 subrepos, |
|
958 dryrun, |
|
959 ) |
848 |
960 |
849 @annotatesubrepoerror |
961 @annotatesubrepoerror |
850 def revert(self, substate, *pats, **opts): |
962 def revert(self, substate, *pats, **opts): |
851 # reverting a subrepo is a 2 step process: |
963 # reverting a subrepo is a 2 step process: |
852 # 1. if the no_backup is not set, revert all modified |
964 # 1. if the no_backup is not set, revert all modified |
927 """return path to this subrepository as seen from outermost repository |
1044 """return path to this subrepository as seen from outermost repository |
928 """ |
1045 """ |
929 # Keep consistent dir separators by avoiding vfs.join(self._path) |
1046 # Keep consistent dir separators by avoiding vfs.join(self._path) |
930 return reporelpath(self._repo) |
1047 return reporelpath(self._repo) |
931 |
1048 |
|
1049 |
932 class svnsubrepo(abstractsubrepo): |
1050 class svnsubrepo(abstractsubrepo): |
933 def __init__(self, ctx, path, state, allowcreate): |
1051 def __init__(self, ctx, path, state, allowcreate): |
934 super(svnsubrepo, self).__init__(ctx, path) |
1052 super(svnsubrepo, self).__init__(ctx, path) |
935 self._state = state |
1053 self._state = state |
936 self._exe = procutil.findexe('svn') |
1054 self._exe = procutil.findexe('svn') |
937 if not self._exe: |
1055 if not self._exe: |
938 raise error.Abort(_("'svn' executable not found for subrepo '%s'") |
1056 raise error.Abort( |
939 % self._path) |
1057 _("'svn' executable not found for subrepo '%s'") % self._path |
|
1058 ) |
940 |
1059 |
941 def _svncommand(self, commands, filename='', failok=False): |
1060 def _svncommand(self, commands, filename='', failok=False): |
942 cmd = [self._exe] |
1061 cmd = [self._exe] |
943 extrakw = {} |
1062 extrakw = {} |
944 if not self.ui.interactive(): |
1063 if not self.ui.interactive(): |
951 # --non-interactive. |
1070 # --non-interactive. |
952 if commands[0] in ('update', 'checkout', 'commit'): |
1071 if commands[0] in ('update', 'checkout', 'commit'): |
953 cmd.append('--non-interactive') |
1072 cmd.append('--non-interactive') |
954 cmd.extend(commands) |
1073 cmd.extend(commands) |
955 if filename is not None: |
1074 if filename is not None: |
956 path = self.wvfs.reljoin(self._ctx.repo().origroot, |
1075 path = self.wvfs.reljoin( |
957 self._path, filename) |
1076 self._ctx.repo().origroot, self._path, filename |
|
1077 ) |
958 cmd.append(path) |
1078 cmd.append(path) |
959 env = dict(encoding.environ) |
1079 env = dict(encoding.environ) |
960 # Avoid localized output, preserve current locale for everything else. |
1080 # Avoid localized output, preserve current locale for everything else. |
961 lc_all = env.get('LC_ALL') |
1081 lc_all = env.get('LC_ALL') |
962 if lc_all: |
1082 if lc_all: |
963 env['LANG'] = lc_all |
1083 env['LANG'] = lc_all |
964 del env['LC_ALL'] |
1084 del env['LC_ALL'] |
965 env['LC_MESSAGES'] = 'C' |
1085 env['LC_MESSAGES'] = 'C' |
966 p = subprocess.Popen(pycompat.rapply(procutil.tonativestr, cmd), |
1086 p = subprocess.Popen( |
967 bufsize=-1, close_fds=procutil.closefds, |
1087 pycompat.rapply(procutil.tonativestr, cmd), |
968 stdout=subprocess.PIPE, stderr=subprocess.PIPE, |
1088 bufsize=-1, |
969 env=procutil.tonativeenv(env), **extrakw) |
1089 close_fds=procutil.closefds, |
|
1090 stdout=subprocess.PIPE, |
|
1091 stderr=subprocess.PIPE, |
|
1092 env=procutil.tonativeenv(env), |
|
1093 **extrakw |
|
1094 ) |
970 stdout, stderr = map(util.fromnativeeol, p.communicate()) |
1095 stdout, stderr = map(util.fromnativeeol, p.communicate()) |
971 stderr = stderr.strip() |
1096 stderr = stderr.strip() |
972 if not failok: |
1097 if not failok: |
973 if p.returncode: |
1098 if p.returncode: |
974 raise error.Abort(stderr or 'exited with code %d' |
1099 raise error.Abort( |
975 % p.returncode) |
1100 stderr or 'exited with code %d' % p.returncode |
|
1101 ) |
976 if stderr: |
1102 if stderr: |
977 self.ui.warn(stderr + '\n') |
1103 self.ui.warn(stderr + '\n') |
978 return stdout, stderr |
1104 return stdout, stderr |
979 |
1105 |
980 @propertycache |
1106 @propertycache |
1177 out, err = self._gitnodir(['--version']) |
1314 out, err = self._gitnodir(['--version']) |
1178 except OSError as e: |
1315 except OSError as e: |
1179 genericerror = _("error executing git for subrepo '%s': %s") |
1316 genericerror = _("error executing git for subrepo '%s': %s") |
1180 notfoundhint = _("check git is installed and in your PATH") |
1317 notfoundhint = _("check git is installed and in your PATH") |
1181 if e.errno != errno.ENOENT: |
1318 if e.errno != errno.ENOENT: |
1182 raise error.Abort(genericerror % ( |
1319 raise error.Abort( |
1183 self._path, encoding.strtolocal(e.strerror))) |
1320 genericerror % (self._path, encoding.strtolocal(e.strerror)) |
|
1321 ) |
1184 elif pycompat.iswindows: |
1322 elif pycompat.iswindows: |
1185 try: |
1323 try: |
1186 self._gitexecutable = 'git.cmd' |
1324 self._gitexecutable = 'git.cmd' |
1187 out, err = self._gitnodir(['--version']) |
1325 out, err = self._gitnodir(['--version']) |
1188 except OSError as e2: |
1326 except OSError as e2: |
1189 if e2.errno == errno.ENOENT: |
1327 if e2.errno == errno.ENOENT: |
1190 raise error.Abort(_("couldn't find 'git' or 'git.cmd'" |
1328 raise error.Abort( |
1191 " for subrepo '%s'") % self._path, |
1329 _( |
1192 hint=notfoundhint) |
1330 "couldn't find 'git' or 'git.cmd'" |
|
1331 " for subrepo '%s'" |
|
1332 ) |
|
1333 % self._path, |
|
1334 hint=notfoundhint, |
|
1335 ) |
1193 else: |
1336 else: |
1194 raise error.Abort(genericerror % (self._path, |
1337 raise error.Abort( |
1195 encoding.strtolocal(e2.strerror))) |
1338 genericerror |
|
1339 % (self._path, encoding.strtolocal(e2.strerror)) |
|
1340 ) |
1196 else: |
1341 else: |
1197 raise error.Abort(_("couldn't find git for subrepo '%s'") |
1342 raise error.Abort( |
1198 % self._path, hint=notfoundhint) |
1343 _("couldn't find git for subrepo '%s'") % self._path, |
|
1344 hint=notfoundhint, |
|
1345 ) |
1199 versionstatus = self._checkversion(out) |
1346 versionstatus = self._checkversion(out) |
1200 if versionstatus == 'unknown': |
1347 if versionstatus == 'unknown': |
1201 self.ui.warn(_('cannot retrieve git version\n')) |
1348 self.ui.warn(_('cannot retrieve git version\n')) |
1202 elif versionstatus == 'abort': |
1349 elif versionstatus == 'abort': |
1203 raise error.Abort(_('git subrepo requires at least 1.6.0 or later')) |
1350 raise error.Abort(_('git subrepo requires at least 1.6.0 or later')) |
1254 |
1401 |
1255 def _gitcommand(self, commands, env=None, stream=False): |
1402 def _gitcommand(self, commands, env=None, stream=False): |
1256 return self._gitdir(commands, env=env, stream=stream)[0] |
1403 return self._gitdir(commands, env=env, stream=stream)[0] |
1257 |
1404 |
1258 def _gitdir(self, commands, env=None, stream=False): |
1405 def _gitdir(self, commands, env=None, stream=False): |
1259 return self._gitnodir(commands, env=env, stream=stream, |
1406 return self._gitnodir( |
1260 cwd=self._abspath) |
1407 commands, env=env, stream=stream, cwd=self._abspath |
|
1408 ) |
1261 |
1409 |
1262 def _gitnodir(self, commands, env=None, stream=False, cwd=None): |
1410 def _gitnodir(self, commands, env=None, stream=False, cwd=None): |
1263 """Calls the git command |
1411 """Calls the git command |
1264 |
1412 |
1265 The methods tries to call the git command. versions prior to 1.6.0 |
1413 The methods tries to call the git command. versions prior to 1.6.0 |
1280 errpipe = open(os.devnull, 'w') |
1428 errpipe = open(os.devnull, 'w') |
1281 if self.ui._colormode and len(commands) and commands[0] == "diff": |
1429 if self.ui._colormode and len(commands) and commands[0] == "diff": |
1282 # insert the argument in the front, |
1430 # insert the argument in the front, |
1283 # the end of git diff arguments is used for paths |
1431 # the end of git diff arguments is used for paths |
1284 commands.insert(1, '--color') |
1432 commands.insert(1, '--color') |
1285 p = subprocess.Popen(pycompat.rapply(procutil.tonativestr, |
1433 p = subprocess.Popen( |
1286 [self._gitexecutable] + commands), |
1434 pycompat.rapply( |
1287 bufsize=-1, |
1435 procutil.tonativestr, [self._gitexecutable] + commands |
1288 cwd=pycompat.rapply(procutil.tonativestr, cwd), |
1436 ), |
1289 env=procutil.tonativeenv(env), |
1437 bufsize=-1, |
1290 close_fds=procutil.closefds, |
1438 cwd=pycompat.rapply(procutil.tonativestr, cwd), |
1291 stdout=subprocess.PIPE, stderr=errpipe) |
1439 env=procutil.tonativeenv(env), |
|
1440 close_fds=procutil.closefds, |
|
1441 stdout=subprocess.PIPE, |
|
1442 stderr=errpipe, |
|
1443 ) |
1292 if stream: |
1444 if stream: |
1293 return p.stdout, None |
1445 return p.stdout, None |
1294 |
1446 |
1295 retdata = p.stdout.read().strip() |
1447 retdata = p.stdout.read().strip() |
1296 # wait for the child to exit to avoid race condition. |
1448 # wait for the child to exit to avoid race condition. |
1347 a map from git branch to revision |
1501 a map from git branch to revision |
1348 a map from revision to branches''' |
1502 a map from revision to branches''' |
1349 branch2rev = {} |
1503 branch2rev = {} |
1350 rev2branch = {} |
1504 rev2branch = {} |
1351 |
1505 |
1352 out = self._gitcommand(['for-each-ref', '--format', |
1506 out = self._gitcommand( |
1353 '%(objectname) %(refname)']) |
1507 ['for-each-ref', '--format', '%(objectname) %(refname)'] |
|
1508 ) |
1354 for line in out.split('\n'): |
1509 for line in out.split('\n'): |
1355 revision, ref = line.split(' ') |
1510 revision, ref = line.split(' ') |
1356 if (not ref.startswith('refs/heads/') and |
1511 if not ref.startswith('refs/heads/') and not ref.startswith( |
1357 not ref.startswith('refs/remotes/')): |
1512 'refs/remotes/' |
|
1513 ): |
1358 continue |
1514 continue |
1359 if ref.startswith('refs/remotes/') and ref.endswith('/HEAD'): |
1515 if ref.startswith('refs/remotes/') and ref.endswith('/HEAD'): |
1360 continue # ignore remote/HEAD redirects |
1516 continue # ignore remote/HEAD redirects |
1361 branch2rev[ref] = revision |
1517 branch2rev[ref] = revision |
1362 rev2branch.setdefault(revision, []).append(ref) |
1518 rev2branch.setdefault(revision, []).append(ref) |
1363 return branch2rev, rev2branch |
1519 return branch2rev, rev2branch |
1364 |
1520 |
1365 def _gittracking(self, branches): |
1521 def _gittracking(self, branches): |
1390 if self._gitmissing(): |
1547 if self._gitmissing(): |
1391 # SEC: check for safe ssh url |
1548 # SEC: check for safe ssh url |
1392 util.checksafessh(source) |
1549 util.checksafessh(source) |
1393 |
1550 |
1394 source = self._abssource(source) |
1551 source = self._abssource(source) |
1395 self.ui.status(_('cloning subrepo %s from %s\n') % |
1552 self.ui.status( |
1396 (self._relpath, source)) |
1553 _('cloning subrepo %s from %s\n') % (self._relpath, source) |
|
1554 ) |
1397 self._gitnodir(['clone', source, self._abspath]) |
1555 self._gitnodir(['clone', source, self._abspath]) |
1398 if self._githavelocally(revision): |
1556 if self._githavelocally(revision): |
1399 return |
1557 return |
1400 self.ui.status(_('pulling subrepo %s from %s\n') % |
1558 self.ui.status( |
1401 (self._relpath, self._gitremote('origin'))) |
1559 _('pulling subrepo %s from %s\n') |
|
1560 % (self._relpath, self._gitremote('origin')) |
|
1561 ) |
1402 # try only origin: the originally cloned repo |
1562 # try only origin: the originally cloned repo |
1403 self._gitcommand(['fetch']) |
1563 self._gitcommand(['fetch']) |
1404 if not self._githavelocally(revision): |
1564 if not self._githavelocally(revision): |
1405 raise error.Abort(_('revision %s does not exist in subrepository ' |
1565 raise error.Abort( |
1406 '"%s"\n') % (revision, self._relpath)) |
1566 _('revision %s does not exist in subrepository ' '"%s"\n') |
|
1567 % (revision, self._relpath) |
|
1568 ) |
1407 |
1569 |
1408 @annotatesubrepoerror |
1570 @annotatesubrepoerror |
1409 def dirty(self, ignoreupdate=False, missing=False): |
1571 def dirty(self, ignoreupdate=False, missing=False): |
1410 if self._gitmissing(): |
1572 if self._gitmissing(): |
1411 return self._state[1] != '' |
1573 return self._state[1] != '' |
1534 self._gitupdatestat() |
1700 self._gitupdatestat() |
1535 out, code = self._gitdir(['diff-index', '--quiet', 'HEAD']) |
1701 out, code = self._gitdir(['diff-index', '--quiet', 'HEAD']) |
1536 |
1702 |
1537 def mergefunc(): |
1703 def mergefunc(): |
1538 if base == revision: |
1704 if base == revision: |
1539 self.get(state) # fast forward merge |
1705 self.get(state) # fast forward merge |
1540 elif base != self._state[1]: |
1706 elif base != self._state[1]: |
1541 self._gitcommand(['merge', '--no-commit', revision]) |
1707 self._gitcommand(['merge', '--no-commit', revision]) |
1542 _sanitize(self.ui, self.wvfs, '.git') |
1708 _sanitize(self.ui, self.wvfs, '.git') |
1543 |
1709 |
1544 if self.dirty(): |
1710 if self.dirty(): |
1545 if self._gitstate() != revision: |
1711 if self._gitstate() != revision: |
1546 dirty = self._gitstate() == self._state[1] or code != 0 |
1712 dirty = self._gitstate() == self._state[1] or code != 0 |
1547 if _updateprompt(self.ui, self, dirty, |
1713 if _updateprompt( |
1548 self._state[1][:7], revision[:7]): |
1714 self.ui, self, dirty, self._state[1][:7], revision[:7] |
|
1715 ): |
1549 mergefunc() |
1716 mergefunc() |
1550 else: |
1717 else: |
1551 mergefunc() |
1718 mergefunc() |
1552 |
1719 |
1553 @annotatesubrepoerror |
1720 @annotatesubrepoerror |
1575 |
1742 |
1576 current = self._gitcurrentbranch() |
1743 current = self._gitcurrentbranch() |
1577 if current: |
1744 if current: |
1578 # determine if the current branch is even useful |
1745 # determine if the current branch is even useful |
1579 if not self._gitisancestor(self._state[1], current): |
1746 if not self._gitisancestor(self._state[1], current): |
1580 self.ui.warn(_('unrelated git branch checked out ' |
1747 self.ui.warn( |
1581 'in subrepository "%s"\n') % self._relpath) |
1748 _( |
|
1749 'unrelated git branch checked out ' |
|
1750 'in subrepository "%s"\n' |
|
1751 ) |
|
1752 % self._relpath |
|
1753 ) |
1582 return False |
1754 return False |
1583 self.ui.status(_('pushing branch %s of subrepository "%s"\n') % |
1755 self.ui.status( |
1584 (current.split('/', 2)[2], self._relpath)) |
1756 _('pushing branch %s of subrepository "%s"\n') |
|
1757 % (current.split('/', 2)[2], self._relpath) |
|
1758 ) |
1585 ret = self._gitdir(cmd + ['origin', current]) |
1759 ret = self._gitdir(cmd + ['origin', current]) |
1586 return ret[1] == 0 |
1760 return ret[1] == 0 |
1587 else: |
1761 else: |
1588 self.ui.warn(_('no branch checked out in subrepository "%s"\n' |
1762 self.ui.warn( |
1589 'cannot push revision %s\n') % |
1763 _( |
1590 (self._relpath, self._state[1])) |
1764 'no branch checked out in subrepository "%s"\n' |
|
1765 'cannot push revision %s\n' |
|
1766 ) |
|
1767 % (self._relpath, self._state[1]) |
|
1768 ) |
1591 return False |
1769 return False |
1592 |
1770 |
1593 @annotatesubrepoerror |
1771 @annotatesubrepoerror |
1594 def add(self, ui, match, prefix, uipathfn, explicitonly, **opts): |
1772 def add(self, ui, match, prefix, uipathfn, explicitonly, **opts): |
1595 if self._gitmissing(): |
1773 if self._gitmissing(): |
1679 total += 1 |
1860 total += 1 |
1680 progress.increment() |
1861 progress.increment() |
1681 progress.complete() |
1862 progress.complete() |
1682 return total |
1863 return total |
1683 |
1864 |
1684 |
|
1685 @annotatesubrepoerror |
1865 @annotatesubrepoerror |
1686 def cat(self, match, fm, fntemplate, prefix, **opts): |
1866 def cat(self, match, fm, fntemplate, prefix, **opts): |
1687 rev = self._state[1] |
1867 rev = self._state[1] |
1688 if match.anypats(): |
1868 if match.anypats(): |
1689 return 1 #No support for include/exclude yet |
1869 return 1 # No support for include/exclude yet |
1690 |
1870 |
1691 if not match.files(): |
1871 if not match.files(): |
1692 return 1 |
1872 return 1 |
1693 |
1873 |
1694 # TODO: add support for non-plain formatter (see cmdutil.cat()) |
1874 # TODO: add support for non-plain formatter (see cmdutil.cat()) |
1695 for f in match.files(): |
1875 for f in match.files(): |
1696 output = self._gitcommand(["show", "%s:%s" % (rev, f)]) |
1876 output = self._gitcommand(["show", "%s:%s" % (rev, f)]) |
1697 fp = cmdutil.makefileobj(self._ctx, fntemplate, |
1877 fp = cmdutil.makefileobj( |
1698 pathname=self.wvfs.reljoin(prefix, f)) |
1878 self._ctx, fntemplate, pathname=self.wvfs.reljoin(prefix, f) |
|
1879 ) |
1699 fp.write(output) |
1880 fp.write(output) |
1700 fp.close() |
1881 fp.close() |
1701 return 0 |
1882 return 0 |
1702 |
|
1703 |
1883 |
1704 @annotatesubrepoerror |
1884 @annotatesubrepoerror |
1705 def status(self, rev2, **opts): |
1885 def status(self, rev2, **opts): |
1706 rev1 = self._state[1] |
1886 rev1 = self._state[1] |
1707 if self._gitmissing() or not rev1: |
1887 if self._gitmissing() or not rev1: |
1763 out = self._gitcommand(['ls-files']) |
1943 out = self._gitcommand(['ls-files']) |
1764 for f in out.split('\n'): |
1944 for f in out.split('\n'): |
1765 if not f in changedfiles: |
1945 if not f in changedfiles: |
1766 clean.append(f) |
1946 clean.append(f) |
1767 |
1947 |
1768 return scmutil.status(modified, added, removed, deleted, |
1948 return scmutil.status( |
1769 unknown, ignored, clean) |
1949 modified, added, removed, deleted, unknown, ignored, clean |
|
1950 ) |
1770 |
1951 |
1771 @annotatesubrepoerror |
1952 @annotatesubrepoerror |
1772 def diff(self, ui, diffopts, node2, match, prefix, **opts): |
1953 def diff(self, ui, diffopts, node2, match, prefix, **opts): |
1773 node1 = self._state[1] |
1954 node1 = self._state[1] |
1774 cmd = ['diff', '--no-renames'] |
1955 cmd = ['diff', '--no-renames'] |
1777 else: |
1958 else: |
1778 # for Git, this also implies '-p' |
1959 # for Git, this also implies '-p' |
1779 cmd.append('-U%d' % diffopts.context) |
1960 cmd.append('-U%d' % diffopts.context) |
1780 |
1961 |
1781 if diffopts.noprefix: |
1962 if diffopts.noprefix: |
1782 cmd.extend(['--src-prefix=%s/' % prefix, |
1963 cmd.extend( |
1783 '--dst-prefix=%s/' % prefix]) |
1964 ['--src-prefix=%s/' % prefix, '--dst-prefix=%s/' % prefix] |
|
1965 ) |
1784 else: |
1966 else: |
1785 cmd.extend(['--src-prefix=a/%s/' % prefix, |
1967 cmd.extend( |
1786 '--dst-prefix=b/%s/' % prefix]) |
1968 ['--src-prefix=a/%s/' % prefix, '--dst-prefix=b/%s/' % prefix] |
|
1969 ) |
1787 |
1970 |
1788 if diffopts.ignorews: |
1971 if diffopts.ignorews: |
1789 cmd.append('--ignore-all-space') |
1972 cmd.append('--ignore-all-space') |
1790 if diffopts.ignorewsamount: |
1973 if diffopts.ignorewsamount: |
1791 cmd.append('--ignore-space-change') |
1974 cmd.append('--ignore-space-change') |
1792 if (self._gitversion(self._gitcommand(['--version'])) >= (1, 8, 4) |
1975 if ( |
1793 and diffopts.ignoreblanklines): |
1976 self._gitversion(self._gitcommand(['--version'])) >= (1, 8, 4) |
|
1977 and diffopts.ignoreblanklines |
|
1978 ): |
1794 cmd.append('--ignore-blank-lines') |
1979 cmd.append('--ignore-blank-lines') |
1795 |
1980 |
1796 cmd.append(node1) |
1981 cmd.append(node1) |
1797 if node2: |
1982 if node2: |
1798 cmd.append(node2) |
1983 cmd.append(node2) |
1818 names = status.modified |
2003 names = status.modified |
1819 for name in names: |
2004 for name in names: |
1820 # backuppath() expects a path relative to the parent repo (the |
2005 # backuppath() expects a path relative to the parent repo (the |
1821 # repo that ui.origbackuppath is relative to) |
2006 # repo that ui.origbackuppath is relative to) |
1822 parentname = os.path.join(self._path, name) |
2007 parentname = os.path.join(self._path, name) |
1823 bakname = scmutil.backuppath(self.ui, self._subparent, |
2008 bakname = scmutil.backuppath( |
1824 parentname) |
2009 self.ui, self._subparent, parentname |
1825 self.ui.note(_('saving current version of %s as %s\n') % |
2010 ) |
1826 (name, os.path.relpath(bakname))) |
2011 self.ui.note( |
|
2012 _('saving current version of %s as %s\n') |
|
2013 % (name, os.path.relpath(bakname)) |
|
2014 ) |
1827 util.rename(self.wvfs.join(name), bakname) |
2015 util.rename(self.wvfs.join(name), bakname) |
1828 |
2016 |
1829 if not opts.get(r'dry_run'): |
2017 if not opts.get(r'dry_run'): |
1830 self.get(substate, overwrite=True) |
2018 self.get(substate, overwrite=True) |
1831 return [] |
2019 return [] |
1832 |
2020 |
1833 def shortid(self, revid): |
2021 def shortid(self, revid): |
1834 return revid[:7] |
2022 return revid[:7] |
|
2023 |
1835 |
2024 |
1836 types = { |
2025 types = { |
1837 'hg': hgsubrepo, |
2026 'hg': hgsubrepo, |
1838 'svn': svnsubrepo, |
2027 'svn': svnsubrepo, |
1839 'git': gitsubrepo, |
2028 'git': gitsubrepo, |
1840 } |
2029 } |