Re: Switching to a date-based version scheme?
On Thu, 11 Jan 2018 22:21:50 -0800 Gregory Szorcwrote: > Mercurial's version numbers (currently 4.4, soon to be 4.5) mean little to > nothing. Mercurial's existing .. version scheme > doesn't honor semantic versioning in the traditional sense. API guarantees > are that each quarterly X.Y release generally maintains API compatibility > within the release but there are no guarantees between quarterly releases. > The component of the version scheme is incremented when > would hit 10 - not when there is a major API change. (This is an arbitrary > decision since it is technically possible to have version components with > an absolute value >=10.) > > To the typical user who isn't intimately familiar with Mercurial's > versioning and release strategy, the existing versioning scheme means > little to nothing. > > A typical user does care about something: whether their Mercurial is up to > date. > > One way of determining if something is up to date is asking "how old is it?" FWIW, here are my thoughts about putting date of release into version. First, let's consider something that's still active, but not doing time-based release plan. If a typical user looks at something like TeX 3.1415926, which was last released in January 2014 (let's say they somehow knew that), how would that help them, what would they think? "There has to be an update by now, it's been 4 years already", right? No, it's actually the latest TeX release. So the assumption that some period of time (now - releasedate) means there's an update available only works if that user is, well, at least somewhat familiar with Mercurial's release strategy. 18.2.0 may look like it was released in February 2018, but what does 18.2.1 look like? Was it released February 1st? What about 18.2.2, how old is it? Would users need to know and remember our versioning scheme to tell that offhand? And if we do YY.M (18.2, 18.3, 18.4) instead, that will completely obfuscate if a version is a feature release or a bug-fix release. I think at least package maintainers care about that. Also, users may not realize that 18.2.0 means it was released in February 2018 at all, unless they also, for example, look at previous versions... or look it up on our site. In fact, why not just look at our site to see how old their version is, and, of course, if there's an update available. Even Wikipedia has this information. ___ Mercurial-devel mailing list Mercurial-devel@mercurial-scm.org https://www.mercurial-scm.org/mailman/listinfo/mercurial-devel
D1795: py3: use pycompat.bytestr() instead of str()
yuja added inline comments. INLINE COMMENTS > subrepo.py:392 > if source.isabs(): > -return str(source) > +return pycompat.bytestr(source) > source.path = posixpath.normpath(source.path) bytes() > subrepo.py:399 > parent.path = posixpath.normpath(parent.path) > -return str(parent) > +return pycompat.bytestr(parent) > else: # recursion reached top repo bytes() > verify.py:110 > +self.warn(_(" (expected %s)") % " ".join > + (map(pycompat.bytestr, linkrevs))) > lr = None # can't be trusted '%d', perhaps. REPOSITORY rHG Mercurial REVISION DETAIL https://phab.mercurial-scm.org/D1795 To: pulkit, #hg-reviewers, durin42 Cc: yuja, mercurial-devel ___ Mercurial-devel mailing list Mercurial-devel@mercurial-scm.org https://www.mercurial-scm.org/mailman/listinfo/mercurial-devel
D1851: visibilty: fix a comment introduced before which is not up-to-date
This revision was automatically updated to reflect the committed changes. Closed by commit rHG49e073ea09d6: visibilty: fix a comment introduced before which is not up-to-date (authored by lothiraldan, committed by ). REPOSITORY rHG Mercurial CHANGES SINCE LAST UPDATE https://phab.mercurial-scm.org/D1851?vs=4800=4804 REVISION DETAIL https://phab.mercurial-scm.org/D1851 AFFECTED FILES mercurial/context.py CHANGE DETAILS diff --git a/mercurial/context.py b/mercurial/context.py --- a/mercurial/context.py +++ b/mercurial/context.py @@ -439,8 +439,8 @@ unfilteredrepo = repo.unfiltered() ctx = unfilteredrepo[changeid] -# If the changeset is obsolete, enrich the hint with the reason that -# made this changeset not visible +# If the changeset is obsolete, enrich the message with the reason +# that made this changeset not visible if ctx.obsolete(): reason = obsutil._getfilteredreason(unfilteredrepo, ctx) msg = _("hidden revision '%s' %s") % (changeid, reason) To: lothiraldan, #hg-reviewers, yuja Cc: mercurial-devel ___ Mercurial-devel mailing list Mercurial-devel@mercurial-scm.org https://www.mercurial-scm.org/mailman/listinfo/mercurial-devel
D1853: visiblity: pass a normal repo to _getfilteredreason
This revision was automatically updated to reflect the committed changes. Closed by commit rHGea9bd35529f2: visiblity: pass a normal repo to _getfilteredreason (authored by lothiraldan, committed by ). REPOSITORY rHG Mercurial CHANGES SINCE LAST UPDATE https://phab.mercurial-scm.org/D1853?vs=4802=4806 REVISION DETAIL https://phab.mercurial-scm.org/D1853 AFFECTED FILES mercurial/context.py mercurial/obsutil.py CHANGE DETAILS diff --git a/mercurial/obsutil.py b/mercurial/obsutil.py --- a/mercurial/obsutil.py +++ b/mercurial/obsutil.py @@ -875,10 +875,10 @@ "%d more"), } -def _getfilteredreason(unfilteredrepo, changeid, ctx): +def _getfilteredreason(repo, changeid, ctx): """return a human-friendly string on why a obsolete changeset is hidden """ -successors = successorssets(unfilteredrepo, ctx.node()) +successors = successorssets(repo, ctx.node()) fate = _getobsfate(successors) # Be more precise in case the revision is superseded diff --git a/mercurial/context.py b/mercurial/context.py --- a/mercurial/context.py +++ b/mercurial/context.py @@ -442,7 +442,7 @@ # If the changeset is obsolete, enrich the message with the reason # that made this changeset not visible if ctx.obsolete(): -msg = obsutil._getfilteredreason(unfilteredrepo, changeid, ctx) +msg = obsutil._getfilteredreason(repo, changeid, ctx) else: msg = _("hidden revision '%s'") % changeid To: lothiraldan, #hg-reviewers, yuja Cc: mercurial-devel ___ Mercurial-devel mailing list Mercurial-devel@mercurial-scm.org https://www.mercurial-scm.org/mailman/listinfo/mercurial-devel
D1851: visibilty: fix a comment introduced before which is not up-to-date
lothiraldan created this revision. Herald added a subscriber: mercurial-devel. Herald added a reviewer: hg-reviewers. REVISION SUMMARY https://phab.mercurial-scm.org/rHG265cd9e19d26dd7f684f660b6c267b45427284e8 introduced a comment in _filterederror that was not updated with the latest iterations of the patch, fix the comment. REPOSITORY rHG Mercurial REVISION DETAIL https://phab.mercurial-scm.org/D1851 AFFECTED FILES mercurial/context.py CHANGE DETAILS diff --git a/mercurial/context.py b/mercurial/context.py --- a/mercurial/context.py +++ b/mercurial/context.py @@ -439,8 +439,8 @@ unfilteredrepo = repo.unfiltered() ctx = unfilteredrepo[changeid] -# If the changeset is obsolete, enrich the hint with the reason that -# made this changeset not visible +# If the changeset is obsolete, enrich the message with the reason +# that made this changeset not visible if ctx.obsolete(): reason = obsutil._getfilteredreason(unfilteredrepo, ctx) msg = _("hidden revision '%s' %s") % (changeid, reason) To: lothiraldan, #hg-reviewers Cc: mercurial-devel ___ Mercurial-devel mailing list Mercurial-devel@mercurial-scm.org https://www.mercurial-scm.org/mailman/listinfo/mercurial-devel
D1852: visibility: make the filtered message translatable
lothiraldan created this revision. Herald added a subscriber: mercurial-devel. Herald added a reviewer: hg-reviewers. REVISION SUMMARY Introduce a filtered message table to ease translation of these messages. REPOSITORY rHG Mercurial REVISION DETAIL https://phab.mercurial-scm.org/D1852 AFFECTED FILES mercurial/context.py mercurial/obsutil.py CHANGE DETAILS diff --git a/mercurial/obsutil.py b/mercurial/obsutil.py --- a/mercurial/obsutil.py +++ b/mercurial/obsutil.py @@ -865,33 +865,42 @@ return "".join(line) -def _getfilteredreason(unfilteredrepo, ctx): + +filteredmsgtable = { +"pruned": _("hidden revision '%s' is pruned"), +"diverged": _("hidden revision '%s' has diverged"), +"superseded": _("hidden revision '%s' was rewritten as: %s"), +"superseded_split": _("hidden revision '%s' was split as: %s"), +"superseded_split_several": _("hidden revision '%s' was split as: %s and " + "%d more"), +} + +def _getfilteredreason(unfilteredrepo, changeid, ctx): """return a human-friendly string on why a obsolete changeset is hidden """ successors = successorssets(unfilteredrepo, ctx.node()) fate = _getobsfate(successors) # Be more precise in case the revision is superseded if fate == 'pruned': -reason = _('is pruned') +return filteredmsgtable['pruned'] % changeid elif fate == 'diverged': -reason = _('has diverged') +return filteredmsgtable['diverged'] % changeid elif fate == 'superseded': -reason = _("was rewritten as: %s") % nodemod.short(successors[0][0]) +single_successor = nodemod.short(successors[0][0]) +return filteredmsgtable['superseded'] % (changeid, single_successor) elif fate == 'superseded_split': succs = [] for node_id in successors[0]: succs.append(nodemod.short(node_id)) if len(succs) <= 2: -reason = _("was split as: %s") % ", ".join(succs) +fmtsuccs = ', '.join(succs) +return filteredmsgtable['superseded_split'] % (changeid, fmtsuccs) else: -firstsuccessors = ", ".join(succs[:2]) +firstsuccessors = ', '.join(succs[:2]) remainingnumber = len(succs) - 2 -args = (firstsuccessors, remainingnumber) -successorsmsg = _("%s and %d more") % args -reason = _("was split as: %s") % successorsmsg - -return reason +args = (changeid, firstsuccessors, remainingnumber) +return filteredmsgtable['superseded_split_several'] % args diff --git a/mercurial/context.py b/mercurial/context.py --- a/mercurial/context.py +++ b/mercurial/context.py @@ -442,8 +442,7 @@ # If the changeset is obsolete, enrich the message with the reason # that made this changeset not visible if ctx.obsolete(): -reason = obsutil._getfilteredreason(unfilteredrepo, ctx) -msg = _("hidden revision '%s' %s") % (changeid, reason) +msg = obsutil._getfilteredreason(unfilteredrepo, changeid, ctx) else: msg = _("hidden revision '%s'") % changeid To: lothiraldan, #hg-reviewers Cc: mercurial-devel ___ Mercurial-devel mailing list Mercurial-devel@mercurial-scm.org https://www.mercurial-scm.org/mailman/listinfo/mercurial-devel
Re: [PATCH 2 of 2 V2] filterlang: add a small language to filter files
On Thu, 11 Jan 2018 11:13:57 -0500, Matt Harbison wrote: > > > On Jan 11, 2018, at 10:16 AM, Yuya Nishiharawrote: > > > >> On Thu, 11 Jan 2018 00:17:39 -0500, Matt Harbison wrote: > >> # HG changeset patch > >> # User Matt Harbison > >> # Date 1515641014 18000 > >> # Wed Jan 10 22:23:34 2018 -0500 > >> # Node ID 548e748cb3f4eea0aedb36a2b2e9fe3b77ffb263 > >> # Parent 962b2bdd70d094ce4bf9a8135495788166b04510 > >> filterlang: add a small language to filter files > > > >> I also made the 'always' token a > >> predicate for consistency, and introduced 'never' to improve readability. > > > > Perhaps '**' or '.' could be an "always" symbol given patterns are relative > > to the repository root in filterlang. > > I’m thinking ahead to a tracked file that could be converted to this > language, and trying to make it readable. This construct seems weird to me: > > **.c = !** Ah, okay. always()/never() or all()/none() makes sense there. I slightly prefer all()/none() as fileset is the language for set operations, and we have all() in revset. > >> diff --git a/mercurial/filterlang.py b/mercurial/filterlang.py > >> new file mode 100644 > >> --- /dev/null > >> +++ b/mercurial/filterlang.py > >> @@ -0,0 +1,73 @@ > >> +# filterlang.py - a simple language to select files > > > > The module name seems too generic. > > minifileset.py, ufileset.py, etc. or merge these functions into fileset.py? > > minifileset.py I guess? My concern with putting it in fileset.py is how to > enforce the boundary clearly. Seems fine. > >> +def _compile(tree): > >> +op = tree[0] > >> +if op in ('symbol', 'string'): > >> +name = fileset.getstring(tree, 'invalid file pattern') > >> +op = name[0] > >> +if op == '*': # file extension test, ex. "*.tar.gz" > >> +return lambda n, s: n.endswith(name[1:]) > > > > Better to make sure no metacharacters in name[1:]. > > Aren’t meta characters allowed in a string, so as to not block certain file > names? Does this mean symbol and string have to be handled separately? I meant '*.*' shouldn't be translated to n.endswith('.*'), for example. > >> +elif op in ['or', 'and']: > >> +funcs = [_compile(t) for t in tree[1:]] > >> +summary = {'or': any, 'and': all}[op] > >> +return lambda n, s: summary(f(n, s) for f in funcs) > > > > IIRC, ('or'/'and', x, y) isn't flattened in fileset.py, so the tree would > > have > > exactly 2 operands. > > fileset.andset() calls getset(), which checks the arg, but maybe that’s an > artifact of other uses. That's probably for "()", an empty group. Here I meant any()/all() always takes a list of two elements. Just for the record, that isn't a problem. ___ Mercurial-devel mailing list Mercurial-devel@mercurial-scm.org https://www.mercurial-scm.org/mailman/listinfo/mercurial-devel
Re: [PATCH 2 of 2 V2] filterlang: add a small language to filter files
On Thu, 11 Jan 2018 21:07:10 -0500, Matt Harbison wrote: > On Thu, 11 Jan 2018 11:13:57 -0500, Matt Harbison> wrote: > >> Perhaps this could be 'path:'. > > I ended up needing to add this to avoid a parse error. The "*fileset*" > tests run, but I'm not sure if this should be allowed for normal > filesets. The '/' operator works because it is in the globchars string. > > diff --git a/mercurial/fileset.py b/mercurial/fileset.py > --- a/mercurial/fileset.py > +++ b/mercurial/fileset.py > @@ -72,13 +72,13 @@ > pos += 1 > else: > raise error.ParseError(_("unterminated string"), s) > -elif c.isalnum() or c in globchars or ord(c) > 127: > +elif c.isalnum() or c in globchars or ord(c) > 127 or c == ':': Yep, ':' is reserved. We could instead add ':' operator to separate matcher kind and pat, but I'm not sure which will be better. For now, we need quotes, ":". ___ Mercurial-devel mailing list Mercurial-devel@mercurial-scm.org https://www.mercurial-scm.org/mailman/listinfo/mercurial-devel
D1852: visibility: make the filtered message translatable
yuja added a comment. Queued, thanks. FWIW, it might be good idea to move `context._filterederror()` to obsutil.py because context.py is painfully big. REPOSITORY rHG Mercurial REVISION DETAIL https://phab.mercurial-scm.org/D1852 To: lothiraldan, #hg-reviewers, yuja Cc: mercurial-devel ___ Mercurial-devel mailing list Mercurial-devel@mercurial-scm.org https://www.mercurial-scm.org/mailman/listinfo/mercurial-devel
D1813: bookmarks: add bookmarks to hidden revs if directaccess config is set
pulkit updated this revision to Diff 4803. REPOSITORY rHG Mercurial CHANGES SINCE LAST UPDATE https://phab.mercurial-scm.org/D1813?vs=4754=4803 REVISION DETAIL https://phab.mercurial-scm.org/D1813 AFFECTED FILES mercurial/bookmarks.py tests/test-directaccess.t tests/test-log.t tests/test-obsolete.t tests/test-rebase-obsolete.t CHANGE DETAILS diff --git a/tests/test-rebase-obsolete.t b/tests/test-rebase-obsolete.t --- a/tests/test-rebase-obsolete.t +++ b/tests/test-rebase-obsolete.t @@ -1496,6 +1496,7 @@ $ hg log -r . # working dir is at rev 3 (successor of 2) 3:be1832deae9a b (no-eol) $ hg book -r 2 mybook --hidden # rev 2 has a bookmark on it now + bookmarking hidden changeset 1e9a3c00cbe9 $ hg up 2 && hg log -r . # working dir is at rev 2 again 0 files updated, 0 files merged, 1 files removed, 0 files unresolved 2:1e9a3c00cbe9 b (rewritten using rebase as 3:be1832deae9a) (no-eol) diff --git a/tests/test-obsolete.t b/tests/test-obsolete.t --- a/tests/test-obsolete.t +++ b/tests/test-obsolete.t @@ -1333,6 +1333,7 @@ $ echo "hello" > b $ hg commit --amend -m "message" $ hg book bookb -r 13bedc178fce --hidden + bookmarking hidden changeset 13bedc178fce $ hg log -r 13bedc178fce 4:13bedc178fce (draft *obsolete*) [ bookb] add b [rewritten using amend as 5:a9b1f8652753] $ hg book -d bookb diff --git a/tests/test-log.t b/tests/test-log.t --- a/tests/test-log.t +++ b/tests/test-log.t @@ -1851,14 +1851,16 @@ bookmarks prevent a changeset being hidden $ hg bookmark --hidden -r 1 X + bookmarking hidden changeset a765632148dc $ hg log --template '{rev}:{node}\n' 1:a765632148dc55d38c35c4f247c618701886cb2f 0:9f758d63dcde62d547ebfb08e1e7ee96535f2b05 $ hg bookmark -d X divergent bookmarks are not hidden $ hg bookmark --hidden -r 1 X@foo + bookmarking hidden changeset a765632148dc $ hg log --template '{rev}:{node}\n' 1:a765632148dc55d38c35c4f247c618701886cb2f 0:9f758d63dcde62d547ebfb08e1e7ee96535f2b05 diff --git a/tests/test-directaccess.t b/tests/test-directaccess.t --- a/tests/test-directaccess.t +++ b/tests/test-directaccess.t @@ -186,3 +186,11 @@ abort: hidden revision '2' was rewritten as: 2443a0e66469! (use --hidden to access hidden revisions) [255] + +Setting a bookmark will make that changeset unhidden, so this should come in end + + $ hg bookmarks -r 28ad74 book + bookmarking hidden changeset 28ad74487de9 + + $ hg bookmarks + book 2:28ad74487de9 diff --git a/mercurial/bookmarks.py b/mercurial/bookmarks.py --- a/mercurial/bookmarks.py +++ b/mercurial/bookmarks.py @@ -830,6 +830,7 @@ cur = repo.changectx('.').node() newact = None changes = [] +hiddenrevs = set() for mark in names: mark = checkformat(repo, mark) if newact is None: @@ -839,10 +840,17 @@ return tgt = cur if rev: -tgt = scmutil.revsingle(repo, rev).node() +repo = scmutil.unhidehashlikerevs(repo, [rev], 'nowarn') +ctx = scmutil.revsingle(repo, rev) +if ctx.hidden(): +hiddenrevs.add(ctx.hex()[:12]) +tgt = ctx.node() for bm in marks.checkconflict(mark, force, tgt): changes.append((bm, None)) changes.append((mark, tgt)) +if hiddenrevs: +repo.ui.warn(_("bookmarking hidden changeset %s\n") % \ + (', '.join(hiddenrevs))) marks.applychanges(repo, tr, changes) if not inactive and cur == marks[newact] and not rev: activate(repo, newact) To: pulkit, #hg-reviewers, yuja Cc: yuja, mercurial-devel ___ Mercurial-devel mailing list Mercurial-devel@mercurial-scm.org https://www.mercurial-scm.org/mailman/listinfo/mercurial-devel
D1853: visiblity: pass a normal repo to _getfilteredreason
lothiraldan created this revision. Herald added a subscriber: mercurial-devel. Herald added a reviewer: hg-reviewers. REVISION SUMMARY There is no reason to pass an unfiltered-repo to _getfilteredreason and successorssets, so use a normal repo instead. REPOSITORY rHG Mercurial REVISION DETAIL https://phab.mercurial-scm.org/D1853 AFFECTED FILES mercurial/context.py mercurial/obsutil.py CHANGE DETAILS diff --git a/mercurial/obsutil.py b/mercurial/obsutil.py --- a/mercurial/obsutil.py +++ b/mercurial/obsutil.py @@ -875,10 +875,10 @@ "%d more"), } -def _getfilteredreason(unfilteredrepo, changeid, ctx): +def _getfilteredreason(repo, changeid, ctx): """return a human-friendly string on why a obsolete changeset is hidden """ -successors = successorssets(unfilteredrepo, ctx.node()) +successors = successorssets(repo, ctx.node()) fate = _getobsfate(successors) # Be more precise in case the revision is superseded diff --git a/mercurial/context.py b/mercurial/context.py --- a/mercurial/context.py +++ b/mercurial/context.py @@ -442,7 +442,7 @@ # If the changeset is obsolete, enrich the message with the reason # that made this changeset not visible if ctx.obsolete(): -msg = obsutil._getfilteredreason(unfilteredrepo, changeid, ctx) +msg = obsutil._getfilteredreason(repo, changeid, ctx) else: msg = _("hidden revision '%s'") % changeid To: lothiraldan, #hg-reviewers Cc: mercurial-devel ___ Mercurial-devel mailing list Mercurial-devel@mercurial-scm.org https://www.mercurial-scm.org/mailman/listinfo/mercurial-devel
D1795: py3: use pycompat.bytestr() instead of str()
pulkit added a comment. In https://phab.mercurial-scm.org/D1795#31282, @yuja wrote: > `bytes()` or `"%d"` is preferred. Can you send a follow up? I am not sure which one needs to be changed. REPOSITORY rHG Mercurial REVISION DETAIL https://phab.mercurial-scm.org/D1795 To: pulkit, #hg-reviewers, durin42 Cc: yuja, mercurial-devel ___ Mercurial-devel mailing list Mercurial-devel@mercurial-scm.org https://www.mercurial-scm.org/mailman/listinfo/mercurial-devel
D1694: debugcommands: replace opts.get('foo') by opts['foo']
yuja added a comment. In https://phab.mercurial-scm.org/D1694#31044, @durin42 wrote: > I think it's probably okay for debug commands, those are pretty rare to use as a function aren't they? Yeah, it's okay, but why do we apply a different rule to debug commands? If we take this, I'd rather replace `.get()` by `[]` everywhere to blame third-party tools which don't pass all options. REPOSITORY rHG Mercurial REVISION DETAIL https://phab.mercurial-scm.org/D1694 To: martinvonz, #hg-reviewers Cc: durin42, yuja, mercurial-devel ___ Mercurial-devel mailing list Mercurial-devel@mercurial-scm.org https://www.mercurial-scm.org/mailman/listinfo/mercurial-devel
D1852: visibility: make the filtered message translatable
This revision was automatically updated to reflect the committed changes. Closed by commit rHG0e0daf46a30c: visibility: make the filtered message translatable (authored by lothiraldan, committed by ). REPOSITORY rHG Mercurial CHANGES SINCE LAST UPDATE https://phab.mercurial-scm.org/D1852?vs=4801=4805 REVISION DETAIL https://phab.mercurial-scm.org/D1852 AFFECTED FILES mercurial/context.py mercurial/obsutil.py CHANGE DETAILS diff --git a/mercurial/obsutil.py b/mercurial/obsutil.py --- a/mercurial/obsutil.py +++ b/mercurial/obsutil.py @@ -865,33 +865,42 @@ return "".join(line) -def _getfilteredreason(unfilteredrepo, ctx): + +filteredmsgtable = { +"pruned": _("hidden revision '%s' is pruned"), +"diverged": _("hidden revision '%s' has diverged"), +"superseded": _("hidden revision '%s' was rewritten as: %s"), +"superseded_split": _("hidden revision '%s' was split as: %s"), +"superseded_split_several": _("hidden revision '%s' was split as: %s and " + "%d more"), +} + +def _getfilteredreason(unfilteredrepo, changeid, ctx): """return a human-friendly string on why a obsolete changeset is hidden """ successors = successorssets(unfilteredrepo, ctx.node()) fate = _getobsfate(successors) # Be more precise in case the revision is superseded if fate == 'pruned': -reason = _('is pruned') +return filteredmsgtable['pruned'] % changeid elif fate == 'diverged': -reason = _('has diverged') +return filteredmsgtable['diverged'] % changeid elif fate == 'superseded': -reason = _("was rewritten as: %s") % nodemod.short(successors[0][0]) +single_successor = nodemod.short(successors[0][0]) +return filteredmsgtable['superseded'] % (changeid, single_successor) elif fate == 'superseded_split': succs = [] for node_id in successors[0]: succs.append(nodemod.short(node_id)) if len(succs) <= 2: -reason = _("was split as: %s") % ", ".join(succs) +fmtsuccs = ', '.join(succs) +return filteredmsgtable['superseded_split'] % (changeid, fmtsuccs) else: -firstsuccessors = ", ".join(succs[:2]) +firstsuccessors = ', '.join(succs[:2]) remainingnumber = len(succs) - 2 -args = (firstsuccessors, remainingnumber) -successorsmsg = _("%s and %d more") % args -reason = _("was split as: %s") % successorsmsg - -return reason +args = (changeid, firstsuccessors, remainingnumber) +return filteredmsgtable['superseded_split_several'] % args diff --git a/mercurial/context.py b/mercurial/context.py --- a/mercurial/context.py +++ b/mercurial/context.py @@ -442,8 +442,7 @@ # If the changeset is obsolete, enrich the message with the reason # that made this changeset not visible if ctx.obsolete(): -reason = obsutil._getfilteredreason(unfilteredrepo, ctx) -msg = _("hidden revision '%s' %s") % (changeid, reason) +msg = obsutil._getfilteredreason(unfilteredrepo, changeid, ctx) else: msg = _("hidden revision '%s'") % changeid To: lothiraldan, #hg-reviewers, yuja Cc: mercurial-devel ___ Mercurial-devel mailing list Mercurial-devel@mercurial-scm.org https://www.mercurial-scm.org/mailman/listinfo/mercurial-devel
[PATCH 2 of 2] rust: convert Unix path to CString transparently
# HG changeset patch # User Yuya Nishihara# Date 1515763122 -32400 # Fri Jan 12 22:18:42 2018 +0900 # Node ID 4ca3b26ca272cf8c24b34deee8bc2530a8eccada # Parent 44289d889542a3c559c424fa1f2d85cb7e16 rust: convert Unix path to CString transparently On Unix, path is just a sequence of bytes. We shouldn't convert it to UTF-8 string. diff --git a/rust/hgcli/src/main.rs b/rust/hgcli/src/main.rs --- a/rust/hgcli/src/main.rs +++ b/rust/hgcli/src/main.rs @@ -16,7 +16,7 @@ use std::env; use std::path::PathBuf; use std::ffi::{CString, OsStr}; #[cfg(target_family = "unix")] -use std::os::unix::ffi::OsStringExt; +use std::os::unix::ffi::{OsStrExt, OsStringExt}; #[derive(Debug)] struct Environment { @@ -62,6 +62,14 @@ fn get_environment() -> Environment { } } +// On UNIX, platform string is just bytes and should not contain NUL. +#[cfg(target_family = "unix")] +fn cstring_from_os>(s: T) -> CString { +CString::new(s.as_ref().as_bytes()).unwrap() +} + +// TODO convert to ANSI characters? +#[cfg(target_family = "windows")] fn cstring_from_os>(s: T) -> CString { CString::new(s.as_ref().to_str().unwrap()).unwrap() } ___ Mercurial-devel mailing list Mercurial-devel@mercurial-scm.org https://www.mercurial-scm.org/mailman/listinfo/mercurial-devel
[PATCH 1 of 2] rust: extract function to convert Path to platform CString
# HG changeset patch # User Yuya Nishihara# Date 1515762574 -32400 # Fri Jan 12 22:09:34 2018 +0900 # Node ID 44289d889542a3c559c424fa1f2d85cb7e16 # Parent ea9bd35529f231c438630071119a309ba84dcc77 rust: extract function to convert Path to platform CString It can be better on Unix. diff --git a/rust/hgcli/src/main.rs b/rust/hgcli/src/main.rs --- a/rust/hgcli/src/main.rs +++ b/rust/hgcli/src/main.rs @@ -14,7 +14,7 @@ use libc::{c_char, c_int}; use std::env; use std::path::PathBuf; -use std::ffi::CString; +use std::ffi::{CString, OsStr}; #[cfg(target_family = "unix")] use std::os::unix::ffi::OsStringExt; @@ -62,6 +62,10 @@ fn get_environment() -> Environment { } } +fn cstring_from_os>(s: T) -> CString { +CString::new(s.as_ref().to_str().unwrap()).unwrap() +} + // On UNIX, argv starts as an array of char*. So it is easy to convert // to C strings. #[cfg(target_family = "unix")] @@ -86,9 +90,7 @@ fn args_to_cstrings() -> Vec { } fn set_python_home(env: ) { -let raw = CString::new(env.python_home.to_str().unwrap()) -.unwrap() -.into_raw(); +let raw = cstring_from_os(_home).into_raw(); unsafe { python27_sys::Py_SetPythonHome(raw); } @@ -133,9 +135,7 @@ fn run() -> Result<(), i32> { // Python files. Apparently we could define our own ``Py_GetPath()`` // implementation. But this may require statically linking Python, which is // not desirable. -let program_name = CString::new(env.python_exe.to_str().unwrap()) -.unwrap() -.as_ptr(); +let program_name = cstring_from_os(_exe).as_ptr(); unsafe { python27_sys::Py_SetProgramName(program_name as *mut i8); } ___ Mercurial-devel mailing list Mercurial-devel@mercurial-scm.org https://www.mercurial-scm.org/mailman/listinfo/mercurial-devel
D1855: explicitly kill server processes
joerg.sonnenberger created this revision. Herald added a subscriber: mercurial-devel. Herald added a reviewer: hg-reviewers. REPOSITORY rHG Mercurial REVISION DETAIL https://phab.mercurial-scm.org/D1855 AFFECTED FILES tests/test-pull-r.t CHANGE DETAILS diff --git a/tests/test-pull-r.t b/tests/test-pull-r.t --- a/tests/test-pull-r.t +++ b/tests/test-pull-r.t @@ -144,3 +144,4 @@ $ cd .. + $ killdaemons.py To: joerg.sonnenberger, #hg-reviewers Cc: mercurial-devel ___ Mercurial-devel mailing list Mercurial-devel@mercurial-scm.org https://www.mercurial-scm.org/mailman/listinfo/mercurial-devel
D1856: wireproto: server-side support for pullbundles
joerg.sonnenberger created this revision. Herald added a subscriber: mercurial-devel. Herald added a reviewer: hg-reviewers. REVISION SUMMARY Pullbundles are similar to clonebundles, but served as normal inline bundle streams. They are almost transparent to the client -- the only visible effect is that the client might get less changes than what it asked for, i.e. not all requested head revisions are provided. The missing client-side logic is to retry a pull in that case. REPOSITORY rHG Mercurial REVISION DETAIL https://phab.mercurial-scm.org/D1856 AFFECTED FILES mercurial/configitems.py mercurial/help/config.txt mercurial/wireproto.py tests/test-pull-r.t CHANGE DETAILS diff --git a/tests/test-pull-r.t b/tests/test-pull-r.t --- a/tests/test-pull-r.t +++ b/tests/test-pull-r.t @@ -145,3 +145,59 @@ $ cd .. $ killdaemons.py + +Test pullbundle functionality + + $ cd repo + $ cat < .hg/hgrc + > [server] + > pullbundle = True + > EOF + $ hg bundle --base null -r 0 .hg/0.hg + 1 changesets found + $ hg bundle --base 0 -r 1 .hg/1.hg + 1 changesets found + $ hg bundle --base 1 -r 2 .hg/2.hg + 1 changesets found + $ cat < .hg/pullbundles.manifest + > 2.hg heads=effea6de0384e684f44435651cb7bd70b8735bd4 base=bbd179dfa0a71671c253b3ae0aa1513b60d199fa + > 1.hg heads=ed1b79f46b9a29f5a6efa59cf12fcfca43bead5a base=bbd179dfa0a71671c253b3ae0aa1513b60d199fa + > 0.hg heads=bbd179dfa0a71671c253b3ae0aa1513b60d199fa + > EOF + $ hg serve --debug -p $HGPORT2 --pid-file=../repo.pid > ../repo-server.txt 2>&1 & + $ while ! grep listening ../repo-server.txt > /dev/null; do sleep 1; done + $ cat ../repo.pid >> $DAEMON_PIDS + $ cd .. + $ hg clone -r 0 http://localhost:$HGPORT2/ repo.pullbundle + adding changesets + adding manifests + adding file changes + added 1 changesets with 1 changes to 1 files + new changesets bbd179dfa0a7 + updating to branch default + 1 files updated, 0 files merged, 0 files removed, 0 files unresolved + $ cd repo.pullbundle + $ hg pull -r 1 + pulling from http://localhost:$HGPORT2/ + searching for changes + adding changesets + adding manifests + adding file changes + added 1 changesets with 1 changes to 1 files + new changesets ed1b79f46b9a + (run 'hg update' to get a working copy) + $ hg pull -r 2 + pulling from http://localhost:$HGPORT2/ + searching for changes + adding changesets + adding manifests + adding file changes + added 1 changesets with 1 changes to 1 files (+1 heads) + new changesets effea6de0384 + (run 'hg heads' to see heads, 'hg merge' to merge) + $ cd .. + $ killdaemons.py + $ grep 'sending pullbundle ' repo-server.txt + sending pullbundle "0.hg" + sending pullbundle "1.hg" + sending pullbundle "2.hg" diff --git a/mercurial/wireproto.py b/mercurial/wireproto.py --- a/mercurial/wireproto.py +++ b/mercurial/wireproto.py @@ -831,6 +831,65 @@ opts = options('debugwireargs', ['three', 'four'], others) return repo.debugwireargs(one, two, **pycompat.strkwargs(opts)) +def find_pullbundle(repo, opts, clheads, heads, common): +def decodehexstring(s): +return set([h.decode('hex') for h in s.split(':')]) + +def hasdescendant(ancestor, revs): +# Quick path for exact match +if ancestor in revs: +return True +for rev in revs: +if repo.changelog.isancestor(ancestor, rev): +return True +return False +def hasancestor(descendant, revs): +if descendant in revs: +return True +for rev in revs: +if repo.changelog.isancestor(rev, descendant): +return True +return False + +manifest = repo.vfs.tryread('pullbundles.manifest') +res = exchange.parseclonebundlesmanifest(repo, manifest) +res = exchange.filterclonebundleentries(repo, res) +for entry in res: +if 'heads' in entry: +try: +bundle_heads = decodehexstring(entry['heads']) +except TypeError: +# Bad heads entry +continue +if len(bundle_heads) > len(heads): +# Client wants less heads than the bundle contains +continue +if bundle_heads.issubset(common): +continue # Nothing new +if all(hasdescendant(rev, common) for rev in bundle_heads): +continue # Still nothing new +if any(not hasdescendant(rev, heads) for rev in bundle_heads): +continue +if 'bases' in entry: +try: +bundle_bases = decodehexstring(entry['bases']) +except TypeError: +# Bad bases entry +continue +if len(bundle_bases) < len(common): +# Client is missing a revision the bundle requires +continue +if all(hasdescendant(rev, common) for rev in bundle_bases): +continue +path =
D1850: hgweb: when no agreement on compression can be found, fail for v2
indygreg requested changes to this revision. indygreg added a comment. This revision now requires changes to proceed. We're not using the `Accept*` HTTP headers, so the use of HTTP `406` is not appropriate. See https://tools.ietf.org/html/rfc7231#section-6.5.6. I believe if you scour the mailing list or even the commit messages, you'll find text explaining why we explicitly chose to not use the `Accept` headers for protocol negotiation. I do think I'm OK with aborting the request if the client request is "malformed." Although it's a BC break and needs to be called out as such. Since we already shipped forgiving code, others may insist we keep the existing behavior. They have a point. REPOSITORY rHG Mercurial REVISION DETAIL https://phab.mercurial-scm.org/D1850 To: joerg.sonnenberger, #hg-reviewers, indygreg Cc: indygreg, mercurial-devel ___ Mercurial-devel mailing list Mercurial-devel@mercurial-scm.org https://www.mercurial-scm.org/mailman/listinfo/mercurial-devel
[PATCH 1 of 2 V3] fileset: split the logic for matching a size expression to a separate method
# HG changeset patch # User Matt Harbison# Date 1515641708 18000 # Wed Jan 10 22:35:08 2018 -0500 # Node ID 2201fc4fd6d3d9dda72459c6642c16acbe6fc0a4 # Parent 24b5106e3e1e265cb60258b314ae2b774610de81 fileset: split the logic for matching a size expression to a separate method This will be used in the next patch to build a simple filtering language, but where we won't have an mctx. diff --git a/mercurial/fileset.py b/mercurial/fileset.py --- a/mercurial/fileset.py +++ b/mercurial/fileset.py @@ -344,6 +344,35 @@ except ValueError: raise error.ParseError(_("couldn't parse size: %s") % s) +def sizematcher(x): +"""Return a function(size) -> bool from the ``size()`` expression""" + +# i18n: "size" is a keyword +expr = getstring(x, _("size requires an expression")).strip() +if '-' in expr: # do we have a range? +a, b = expr.split('-', 1) +a = util.sizetoint(a) +b = util.sizetoint(b) +return lambda x: x >= a and x <= b +elif expr.startswith("<="): +a = util.sizetoint(expr[2:]) +return lambda x: x <= a +elif expr.startswith("<"): +a = util.sizetoint(expr[1:]) +return lambda x: x < a +elif expr.startswith(">="): +a = util.sizetoint(expr[2:]) +return lambda x: x >= a +elif expr.startswith(">"): +a = util.sizetoint(expr[1:]) +return lambda x: x > a +elif expr[0].isdigit or expr[0] == '.': +a = util.sizetoint(expr) +b = _sizetomax(expr) +return lambda x: x >= a and x <= b +else: +raise error.ParseError(_("couldn't parse size: %s") % expr) + @predicate('size(expression)', callexisting=True) def size(mctx, x): """File size matches the given expression. Examples: @@ -353,33 +382,7 @@ - size('>= .5MB') - files at least 524288 bytes - size('4k - 1MB') - files from 4096 bytes to 1048576 bytes """ - -# i18n: "size" is a keyword -expr = getstring(x, _("size requires an expression")).strip() -if '-' in expr: # do we have a range? -a, b = expr.split('-', 1) -a = util.sizetoint(a) -b = util.sizetoint(b) -m = lambda x: x >= a and x <= b -elif expr.startswith("<="): -a = util.sizetoint(expr[2:]) -m = lambda x: x <= a -elif expr.startswith("<"): -a = util.sizetoint(expr[1:]) -m = lambda x: x < a -elif expr.startswith(">="): -a = util.sizetoint(expr[2:]) -m = lambda x: x >= a -elif expr.startswith(">"): -a = util.sizetoint(expr[1:]) -m = lambda x: x > a -elif expr[0].isdigit or expr[0] == '.': -a = util.sizetoint(expr) -b = _sizetomax(expr) -m = lambda x: x >= a and x <= b -else: -raise error.ParseError(_("couldn't parse size: %s") % expr) - +m = sizematcher(x) return [f for f in mctx.existing() if m(mctx.ctx[f].size())] @predicate('encoding(name)', callexisting=True) ___ Mercurial-devel mailing list Mercurial-devel@mercurial-scm.org https://www.mercurial-scm.org/mailman/listinfo/mercurial-devel
[PATCH 1 of 2] fileset: make it robust for bad function calls
# HG changeset patch # User Yuya Nishihara# Date 1515823657 -32400 # Sat Jan 13 15:07:37 2018 +0900 # Node ID 7a283960200aedf4461273ebc0c90f6f677c4a59 # Parent 706aa203b3961372f359df16214b4c10bc8a66fa fileset: make it robust for bad function calls Before, it could crash or show cryptic message. diff --git a/mercurial/fileset.py b/mercurial/fileset.py --- a/mercurial/fileset.py +++ b/mercurial/fileset.py @@ -99,6 +99,11 @@ def parse(expr): raise error.ParseError(_("invalid token"), pos) return tree +def getsymbol(x): +if x and x[0] == 'symbol': +return x[1] +raise error.ParseError(_('not a symbol')) + def getstring(x, err): if x and (x[0] == 'string' or x[0] == 'symbol'): return x[1] @@ -225,8 +230,8 @@ def clean(mctx, x): return [f for f in mctx.subset if f in s] def func(mctx, a, b): -if a[0] == 'symbol' and a[1] in symbols: -funcname = a[1] +funcname = getsymbol(a) +if funcname in symbols: enabled = mctx._existingenabled mctx._existingenabled = funcname in _existingcallers try: @@ -237,7 +242,7 @@ def func(mctx, a, b): keep = lambda fn: getattr(fn, '__doc__', None) is not None syms = [s for (s, fn) in symbols.items() if keep(fn)] -raise error.UnknownIdentifier(a[1], syms) +raise error.UnknownIdentifier(funcname, syms) def getlist(x): if not x: diff --git a/mercurial/minifileset.py b/mercurial/minifileset.py --- a/mercurial/minifileset.py +++ b/mercurial/minifileset.py @@ -56,9 +56,8 @@ def _compile(tree): 'size': lambda n, s: fileset.sizematcher(tree[2])(s), } -x = tree[1] -name = x[1] -if x[0] == 'symbol' and name in symbols: +name = fileset.getsymbol(tree[1]) +if name in symbols: return symbols[name] raise error.UnknownIdentifier(name, symbols.keys()) diff --git a/tests/test-fileset.t b/tests/test-fileset.t --- a/tests/test-fileset.t +++ b/tests/test-fileset.t @@ -53,6 +53,22 @@ Test operators and basic patterns hg: parse error: invalid \x escape [255] +Test invalid syntax + + $ fileset -v '"added"()' + (func +(string 'added') +None) + hg: parse error: not a symbol + [255] + $ fileset -v '()()' + (func +(group + None) +None) + hg: parse error: not a symbol + [255] + Test files status $ rm a1 ___ Mercurial-devel mailing list Mercurial-devel@mercurial-scm.org https://www.mercurial-scm.org/mailman/listinfo/mercurial-devel
[PATCH 2 of 2] fileset: do not crash by unary negate operation
# HG changeset patch # User Yuya Nishihara# Date 1515824009 -32400 # Sat Jan 13 15:13:29 2018 +0900 # Node ID ae8b3e1707597343265e2d2cbc99a665942a76df # Parent 7a283960200aedf4461273ebc0c90f6f677c4a59 fileset: do not crash by unary negate operation Backported from minifileset.py. diff --git a/mercurial/fileset.py b/mercurial/fileset.py --- a/mercurial/fileset.py +++ b/mercurial/fileset.py @@ -136,6 +136,9 @@ def minusset(mctx, x, y): yl = set(getset(mctx, y)) return [f for f in xl if f not in yl] +def negateset(mctx, x): +raise error.ParseError(_("can't use negate operator in this context")) + def listset(mctx, a, b): raise error.ParseError(_("can't use a list in this context"), hint=_('see hg help "filesets.x or y"')) @@ -523,6 +526,7 @@ methods = { 'and': andset, 'or': orset, 'minus': minusset, +'negate': negateset, 'list': listset, 'group': getset, 'not': notset, diff --git a/tests/test-fileset.t b/tests/test-fileset.t --- a/tests/test-fileset.t +++ b/tests/test-fileset.t @@ -68,6 +68,17 @@ Test invalid syntax None) hg: parse error: not a symbol [255] + $ fileset -v -- '-x' + (negate +(symbol 'x')) + hg: parse error: can't use negate operator in this context + [255] + $ fileset -v -- '-()' + (negate +(group + None)) + hg: parse error: can't use negate operator in this context + [255] Test files status ___ Mercurial-devel mailing list Mercurial-devel@mercurial-scm.org https://www.mercurial-scm.org/mailman/listinfo/mercurial-devel
D1855: explicitly kill server processes
This revision was automatically updated to reflect the committed changes. Closed by commit rHG5bda7bd29688: explicitly kill server processes (authored by joerg.sonnenberger, committed by ). REPOSITORY rHG Mercurial CHANGES SINCE LAST UPDATE https://phab.mercurial-scm.org/D1855?vs=4809=4814 REVISION DETAIL https://phab.mercurial-scm.org/D1855 AFFECTED FILES tests/test-pull-r.t CHANGE DETAILS diff --git a/tests/test-pull-r.t b/tests/test-pull-r.t --- a/tests/test-pull-r.t +++ b/tests/test-pull-r.t @@ -144,3 +144,4 @@ $ cd .. + $ killdaemons.py To: joerg.sonnenberger, #hg-reviewers, indygreg Cc: mercurial-devel ___ Mercurial-devel mailing list Mercurial-devel@mercurial-scm.org https://www.mercurial-scm.org/mailman/listinfo/mercurial-devel
[PATCH 2 of 2 V3] fileset: add a lightweight file filtering language
# HG changeset patch # User Matt Harbison# Date 1515641014 18000 # Wed Jan 10 22:23:34 2018 -0500 # Node ID b66e906f11f758eb3b3b0f5bc56cf66229f343b7 # Parent 2201fc4fd6d3d9dda72459c6642c16acbe6fc0a4 fileset: add a lightweight file filtering language This patch was inspired by one that Jun Wu authored for the fb-experimental repo, to avoid using matcher for efficiency[1]. We want a way to specify what files will be converted to LFS at commit time. And per discussion, we also want to specify what files to skip, text diff, or merge in another config option. The current `lfs.threshold` config option could not satisfy complex needs. I'm putting it in a core package because Augie floated the idea of also using it for narrow and sparse. Yuya suggested farming out to fileset.parse(), which added support for more symbols. The only fileset element not supported here is 'negate'. (List isn't supported by filesets either.) I also changed the 'always' token to the 'all()' predicate for consistency, and introduced 'none()' to improve readability in a future tracked file based config. The extension operator was changed from '.' to '**', to match how recursive path globs are specified. Finally, I changed the path matcher from '/' to 'path:' at Yuya's suggestion, for consistency with matcher. Unfortunately, ':' is currently reserved in filesets, so this has to be quoted to be processed as a string instead of a symbol[2]. We should probably revisit that, because it's seriously ugly. But it's only used by an experimental extension, and I think using a file based config for LFS may drive some more tweaks, so I'm settling for this for now. I reserved all of the glob characters in fileset except '.' and '_' for the extension test because those are likely valid extension characters. Sample filter settings: all()# everything size(">20MB")# larger than 20MB !**.txt # except for .txt files **.zip | **.tar.gz | **.7z # some types of compressed files "path:bin" # files under "bin" in the project root [1] https://www.mercurial-scm.org/pipermail/mercurial-devel/2017-December/109387.html [2] https://www.mercurial-scm.org/pipermail/mercurial-devel/2018-January/109729.html diff --git a/mercurial/minifileset.py b/mercurial/minifileset.py new file mode 100644 --- /dev/null +++ b/mercurial/minifileset.py @@ -0,0 +1,94 @@ +# minifileset.py - a simple language to select files +# +# Copyright 2017 Facebook, Inc. +# +# This software may be used and distributed according to the terms of the +# GNU General Public License version 2 or any later version. + +from __future__ import absolute_import + +from .i18n import _ +from . import ( +error, +fileset, +util, +) + +def _compile(tree): +if not tree: +raise error.ParseError(_("missing argument")) +op = tree[0] +if op == 'symbol': +name = fileset.getstring(tree, _('invalid file pattern')) +if name.startswith('**'): # file extension test, ex. "**.tar.gz" +ext = name[2:] +for c in ext: +if c in '*{}[]?/\\': +raise error.ParseError(_('reserved character: %s') % c) +return lambda n, s: n.endswith(ext) +else: +raise error.ParseError(_('invalid symbol: %s') % name) +elif op == 'or': +func1 = _compile(tree[1]) +func2 = _compile(tree[2]) +return lambda n, s: func1(n, s) or func2(n, s) +elif op == 'and': +func1 = _compile(tree[1]) +func2 = _compile(tree[2]) +return lambda n, s: func1(n, s) and func2(n, s) +elif op == 'not': +return lambda n, s: not _compile(tree[1])(n, s) +elif op == 'group': +return _compile(tree[1]) +elif op == 'func': +symbols = { +'all': lambda n, s: True, +'none': lambda n, s: False, +'size': lambda n, s: fileset.sizematcher(tree[2])(s), +} + +x = tree[1] +name = x[1] +if x[0] == 'symbol' and name in symbols: +return symbols[name] + +raise error.UnknownIdentifier(name, symbols.keys()) +elif op == 'minus': # equivalent to 'x and not y' +func1 = _compile(tree[1]) +func2 = _compile(tree[2]) +return lambda n, s: func1(n, s) and not func2(n, s) +elif op == 'negate': +raise error.ParseError(_("can't use negate operator in this context")) +elif op == 'string': +# TODO: teach fileset about 'path:', so that this can be a symbol and +# not require quoting. +name = fileset.getstring(tree, _('invalid path literal')) +if name.startswith('path:'): # directory or full path test +p = name[5:] # prefix +pl = len(p) +f = lambda n, s: n.startswith(p) and (len(n) == pl or n[pl] == '/') +return f +raise
D1855: explicitly kill server processes
yuja added a comment. Just for the record, explicit killdaemon isn't needed unless you want to do something (e.g. checking server logs) after that. Daemons are kill by the test runner. REPOSITORY rHG Mercurial REVISION DETAIL https://phab.mercurial-scm.org/D1855 To: joerg.sonnenberger, #hg-reviewers, indygreg Cc: yuja, mercurial-devel ___ Mercurial-devel mailing list Mercurial-devel@mercurial-scm.org https://www.mercurial-scm.org/mailman/listinfo/mercurial-devel
D1854: py3: use bytes instead of pycompat.bytestr
This revision was automatically updated to reflect the committed changes. Closed by commit rHG991f0be9dc39: py3: use bytes instead of pycompat.bytestr (authored by pulkit, committed by ). REPOSITORY rHG Mercurial CHANGES SINCE LAST UPDATE https://phab.mercurial-scm.org/D1854?vs=4808=4815 REVISION DETAIL https://phab.mercurial-scm.org/D1854 AFFECTED FILES mercurial/subrepo.py CHANGE DETAILS diff --git a/mercurial/subrepo.py b/mercurial/subrepo.py --- a/mercurial/subrepo.py +++ b/mercurial/subrepo.py @@ -389,14 +389,14 @@ if util.safehasattr(repo, '_subparent'): source = util.url(repo._subsource) if source.isabs(): -return pycompat.bytestr(source) +return bytes(source) source.path = posixpath.normpath(source.path) parent = _abssource(repo._subparent, push, abort=False) if parent: parent = util.url(util.pconvert(parent)) parent.path = posixpath.join(parent.path or '', source.path) parent.path = posixpath.normpath(parent.path) -return pycompat.bytestr(parent) +return bytes(parent) else: # recursion reached top repo if util.safehasattr(repo, '_subtoppath'): return repo._subtoppath To: pulkit, #hg-reviewers, yuja Cc: mercurial-devel ___ Mercurial-devel mailing list Mercurial-devel@mercurial-scm.org https://www.mercurial-scm.org/mailman/listinfo/mercurial-devel
[PATCH 1 of 7] share: use context manager or utility function to write file
# HG changeset patch # User Yuya Nishihara# Date 1515817396 -32400 # Sat Jan 13 13:23:16 2018 +0900 # Node ID 2eeaf96c20fce19c8edccf4936aceee4ce651de9 # Parent 991f0be9dc39c402d63a4a8f19cde052095c4689 share: use context manager or utility function to write file diff --git a/mercurial/hg.py b/mercurial/hg.py --- a/mercurial/hg.py +++ b/mercurial/hg.py @@ -307,16 +307,13 @@ def postshare(sourcerepo, destrepo, book """ default = defaultpath or sourcerepo.ui.config('paths', 'default') if default: -fp = destrepo.vfs("hgrc", "w", text=True) -fp.write("[paths]\n") -fp.write("default = %s\n" % default) -fp.close() +with destrepo.vfs("hgrc", "w", text=True) as fp: +fp.write("[paths]\n") +fp.write("default = %s\n" % default) with destrepo.wlock(): if bookmarks: -fp = destrepo.vfs('shared', 'w') -fp.write(sharedbookmarks + '\n') -fp.close() +destrepo.vfs.write('shared', sharedbookmarks + '\n') def _postshareupdate(repo, update, checkout=None): """Maybe perform a working directory update after a shared repo is created. ___ Mercurial-devel mailing list Mercurial-devel@mercurial-scm.org https://www.mercurial-scm.org/mailman/listinfo/mercurial-devel
[PATCH 4 of 7] share: convert EOL of hgrc before writing to bytes IO
# HG changeset patch # User Yuya Nishihara# Date 1515817887 -32400 # Sat Jan 13 13:31:27 2018 +0900 # Node ID c4ecde5fbf1e40f0c918c9b4f6c1215b2cbebb7c # Parent 41f5fc043698f6c8ff042ebb7d380f76a68a006b share: convert EOL of hgrc before writing to bytes IO Text IO is useless on Python 3 as it must be a unicode stream. diff --git a/mercurial/hg.py b/mercurial/hg.py --- a/mercurial/hg.py +++ b/mercurial/hg.py @@ -307,9 +307,9 @@ def postshare(sourcerepo, destrepo, book """ default = defaultpath or sourcerepo.ui.config('paths', 'default') if default: -with destrepo.vfs("hgrc", "w", text=True) as fp: -fp.write("[paths]\n") -fp.write("default = %s\n" % default) +template = ('[paths]\n' +'default = %s\n') +destrepo.vfs.write('hgrc', util.tonativeeol(template % default)) with destrepo.wlock(): if bookmarks: ___ Mercurial-devel mailing list Mercurial-devel@mercurial-scm.org https://www.mercurial-scm.org/mailman/listinfo/mercurial-devel
[PATCH 6 of 7] lfs: convert EOL of hgrc before appending to bytes IO
# HG changeset patch # User Yuya Nishihara# Date 1515818471 -32400 # Sat Jan 13 13:41:11 2018 +0900 # Node ID 2a43867d18dfedd0708a6dfb87ab2fc80e5c # Parent 6f68aa0c4c0aa59dd651e81e813c1a11e4761889 lfs: convert EOL of hgrc before appending to bytes IO Text IO is useless on Python 3 as it must be a unicode stream. diff --git a/hgext/lfs/wrapper.py b/hgext/lfs/wrapper.py --- a/hgext/lfs/wrapper.py +++ b/hgext/lfs/wrapper.py @@ -197,8 +197,8 @@ def convertsink(orig, sink): self.repo._writerequirements() # Permanently enable lfs locally -with self.repo.vfs('hgrc', 'a', text=True) as fp: -fp.write('\n[extensions]\nlfs=\n') +self.repo.vfs.append( +'hgrc', util.tonativeeol('\n[extensions]\nlfs=\n')) return node @@ -232,8 +232,8 @@ def hgclone(orig, ui, opts, *args, **kwa # If lfs is required for this repo, permanently enable it locally if 'lfs' in repo.requirements: -with repo.vfs('hgrc', 'a', text=True) as fp: -fp.write('\n[extensions]\nlfs=\n') +repo.vfs.append('hgrc', +util.tonativeeol('\n[extensions]\nlfs=\n')) return result @@ -242,8 +242,7 @@ def hgpostshare(orig, sourcerepo, destre # If lfs is required for this repo, permanently enable it locally if 'lfs' in destrepo.requirements: -with destrepo.vfs('hgrc', 'a', text=True) as fp: -fp.write('\n[extensions]\nlfs=\n') +destrepo.vfs.append('hgrc', util.tonativeeol('\n[extensions]\nlfs=\n')) def _canskipupload(repo): # if remotestore is a null store, upload is a no-op and can be skipped ___ Mercurial-devel mailing list Mercurial-devel@mercurial-scm.org https://www.mercurial-scm.org/mailman/listinfo/mercurial-devel
[PATCH 7 of 7] vfs: drop text mode flag (API)
# HG changeset patch # User Yuya Nishihara# Date 1515818830 -32400 # Sat Jan 13 13:47:10 2018 +0900 # Node ID 1cd98d602f7a3d4dac3b1327278a29d50c2c0a3c # Parent 2a43867d18dfedd0708a6dfb87ab2fc80e5c vfs: drop text mode flag (API) It's useless on Python 3. .. api:: ``text=False|True`` option is dropped from the vfs interface because of Python 3 compatibility issue. Use ``util.tonativeeol/fromnativeeol()`` to convert EOL manually. diff --git a/mercurial/vfs.py b/mercurial/vfs.py --- a/mercurial/vfs.py +++ b/mercurial/vfs.py @@ -170,9 +170,9 @@ class abstractvfs(object): def mkdir(self, path=None): return os.mkdir(self.join(path)) -def mkstemp(self, suffix='', prefix='tmp', dir=None, text=False): +def mkstemp(self, suffix='', prefix='tmp', dir=None): fd, name = tempfile.mkstemp(suffix=suffix, prefix=prefix, -dir=self.join(dir), text=text) +dir=self.join(dir)) dname, fname = util.split(name) if dir: return fd, os.path.join(dir, fname) @@ -333,9 +333,8 @@ class vfs(abstractvfs): return os.chmod(name, self.createmode & 0o666) -def __call__(self, path, mode="r", text=False, atomictemp=False, - notindexed=False, backgroundclose=False, checkambig=False, - auditpath=True): +def __call__(self, path, mode="r", atomictemp=False, notindexed=False, + backgroundclose=False, checkambig=False, auditpath=True): '''Open ``path`` file, which is relative to vfs root. Newly created directories are marked as "not to be indexed by @@ -373,7 +372,7 @@ class vfs(abstractvfs): self.audit(path, mode=mode) f = self.join(path) -if not text and "b" not in mode: +if "b" not in mode: mode += "b" # for that other OS nlink = -1 ___ Mercurial-devel mailing list Mercurial-devel@mercurial-scm.org https://www.mercurial-scm.org/mailman/listinfo/mercurial-devel
[PATCH 2 of 7] clone: use utility function to write hgrc
# HG changeset patch # User Yuya Nishihara# Date 1515817457 -32400 # Sat Jan 13 13:24:17 2018 +0900 # Node ID f5558d75ef44a2db64131b4e5bca98102542f13b # Parent 2eeaf96c20fce19c8edccf4936aceee4ce651de9 clone: use utility function to write hgrc diff --git a/mercurial/hg.py b/mercurial/hg.py --- a/mercurial/hg.py +++ b/mercurial/hg.py @@ -681,13 +681,10 @@ def clone(ui, peeropts, source, dest=Non destrepo = destpeer.local() if destrepo: template = uimod.samplehgrcs['cloned'] -fp = destrepo.vfs("hgrc", "wb") u = util.url(abspath) u.passwd = None defaulturl = bytes(u) -fp.write(util.tonativeeol(template % defaulturl)) -fp.close() - +destrepo.vfs.write('hgrc', util.tonativeeol(template % defaulturl)) destrepo.ui.setconfig('paths', 'default', defaulturl, 'clone') if ui.configbool('experimental', 'remotenames'): ___ Mercurial-devel mailing list Mercurial-devel@mercurial-scm.org https://www.mercurial-scm.org/mailman/listinfo/mercurial-devel
[PATCH 3 of 7] subrepo: convert EOL of hgrc before writing to bytes IO
# HG changeset patch # User Yuya Nishihara# Date 1515817692 -32400 # Sat Jan 13 13:28:12 2018 +0900 # Node ID 41f5fc043698f6c8ff042ebb7d380f76a68a006b # Parent f5558d75ef44a2db64131b4e5bca98102542f13b subrepo: convert EOL of hgrc before writing to bytes IO Follows up f2f0a777b2e2. Text IO is useless on Python 3 as it must be a unicode stream. diff --git a/mercurial/subrepo.py b/mercurial/subrepo.py --- a/mercurial/subrepo.py +++ b/mercurial/subrepo.py @@ -841,11 +841,7 @@ class hgsubrepo(abstractsubrepo): if defpath != defpushpath: addpathconfig('default-push', defpushpath) -fp = self._repo.vfs("hgrc", "wb", text=True) -try: -fp.write(''.join(lines)) -finally: -fp.close() +self._repo.vfs.write('hgrc', util.tonativeeol(''.join(lines))) @annotatesubrepoerror def add(self, ui, match, prefix, explicitonly, **opts): ___ Mercurial-devel mailing list Mercurial-devel@mercurial-scm.org https://www.mercurial-scm.org/mailman/listinfo/mercurial-devel
[PATCH 5 of 7] largefiles: convert EOL of hgrc before appending to bytes IO
# HG changeset patch # User Yuya Nishihara# Date 1515818035 -32400 # Sat Jan 13 13:33:55 2018 +0900 # Node ID 6f68aa0c4c0aa59dd651e81e813c1a11e4761889 # Parent c4ecde5fbf1e40f0c918c9b4f6c1215b2cbebb7c largefiles: convert EOL of hgrc before appending to bytes IO Text IO is useless on Python 3 as it must be a unicode stream. diff --git a/hgext/largefiles/overrides.py b/hgext/largefiles/overrides.py --- a/hgext/largefiles/overrides.py +++ b/hgext/largefiles/overrides.py @@ -888,8 +888,8 @@ def hgclone(orig, ui, opts, *args, **kwa # If largefiles is required for this repo, permanently enable it locally if 'largefiles' in repo.requirements: -with repo.vfs('hgrc', 'a', text=True) as fp: -fp.write('\n[extensions]\nlargefiles=\n') +repo.vfs.append('hgrc', +util.tonativeeol('\n[extensions]\nlargefiles=\n')) # Caching is implicitly limited to 'rev' option, since the dest repo was # truncated at that point. The user may expect a download count with @@ -907,8 +907,8 @@ def hgpostshare(orig, sourcerepo, destre # If largefiles is required for this repo, permanently enable it locally if 'largefiles' in destrepo.requirements: -with destrepo.vfs('hgrc', 'a+', text=True) as fp: -fp.write('\n[extensions]\nlargefiles=\n') +destrepo.vfs.append('hgrc', +util.tonativeeol('\n[extensions]\nlargefiles=\n')) def overriderebase(orig, ui, repo, **opts): if not util.safehasattr(repo, '_largefilesenabled'): ___ Mercurial-devel mailing list Mercurial-devel@mercurial-scm.org https://www.mercurial-scm.org/mailman/listinfo/mercurial-devel
[PATCH] lfs: drop deprecated remote store config options
# HG changeset patch # User Matt Harbison# Date 1515816818 18000 # Fri Jan 12 23:13:38 2018 -0500 # Node ID a461399d0ac31e3c4ebc8dee10ea0ac46843fa07 # Parent b66e906f11f758eb3b3b0f5bc56cf66229f343b7 lfs: drop deprecated remote store config options The last of these were removed from fb-experimental in 86884a51e9aa, and we might as well clean this up before the freeze. diff --git a/hgext/lfs/__init__.py b/hgext/lfs/__init__.py --- a/hgext/lfs/__init__.py +++ b/hgext/lfs/__init__.py @@ -71,7 +71,7 @@ ) configitem('lfs', 'url', -default=configitem.dynamicdefault, +default=None, ) configitem('lfs', 'usercache', default=None, @@ -82,18 +82,6 @@ configitem('lfs', 'retry', default=5, ) -# Deprecated -configitem('lfs', 'remotestore', -default=None, -) -# Deprecated -configitem('lfs', 'dummy', -default=None, -) -# Deprecated -configitem('lfs', 'git-lfs', -default=None, -) cmdtable = {} command = registrar.command(cmdtable) diff --git a/hgext/lfs/blobstore.py b/hgext/lfs/blobstore.py --- a/hgext/lfs/blobstore.py +++ b/hgext/lfs/blobstore.py @@ -445,22 +445,7 @@ def remote(repo): """remotestore factory. return a store in _storemap depending on config""" -defaulturl = '' - -# convert deprecated configs to the new url. TODO: remove this if other -# places are migrated to the new url config. -# deprecated config: lfs.remotestore -deprecatedstore = repo.ui.config('lfs', 'remotestore') -if deprecatedstore == 'dummy': -# deprecated config: lfs.remotepath -defaulturl = 'file://' + repo.ui.config('lfs', 'remotepath') -elif deprecatedstore == 'git-lfs': -# deprecated config: lfs.remoteurl -defaulturl = repo.ui.config('lfs', 'remoteurl') -elif deprecatedstore == 'null': -defaulturl = 'null://' - -url = util.url(repo.ui.config('lfs', 'url', defaulturl)) +url = util.url(repo.ui.config('lfs', 'url') or '') scheme = url.scheme if scheme not in _storemap: raise error.Abort(_('lfs: unknown url scheme: %s') % scheme) ___ Mercurial-devel mailing list Mercurial-devel@mercurial-scm.org https://www.mercurial-scm.org/mailman/listinfo/mercurial-devel
Re: [PATCH] lfs: drop deprecated remote store config options
On Fri, 12 Jan 2018 23:28:41 -0500, Matt Harbison wrote: > # HG changeset patch > # User Matt Harbison> # Date 1515816818 18000 > # Fri Jan 12 23:13:38 2018 -0500 > # Node ID a461399d0ac31e3c4ebc8dee10ea0ac46843fa07 > # Parent b66e906f11f758eb3b3b0f5bc56cf66229f343b7 > lfs: drop deprecated remote store config options Queued, thanks. ___ Mercurial-devel mailing list Mercurial-devel@mercurial-scm.org https://www.mercurial-scm.org/mailman/listinfo/mercurial-devel
Re: [PATCH 2 of 2 V3] fileset: add a lightweight file filtering language
On Fri, 12 Jan 2018 22:21:59 -0500, Matt Harbison wrote: > # HG changeset patch > # User Matt Harbison> # Date 1515641014 18000 > # Wed Jan 10 22:23:34 2018 -0500 > # Node ID b66e906f11f758eb3b3b0f5bc56cf66229f343b7 > # Parent 2201fc4fd6d3d9dda72459c6642c16acbe6fc0a4 > fileset: add a lightweight file filtering language Also queued, thanks. > +def _compile(tree): > +if not tree: > +raise error.ParseError(_("missing argument")) > +op = tree[0] > +if op == 'symbol': > +name = fileset.getstring(tree, _('invalid file pattern')) > +if name.startswith('**'): # file extension test, ex. "**.tar.gz" > +ext = name[2:] > +for c in ext: > +if c in '*{}[]?/\\': > +raise error.ParseError(_('reserved character: %s') % c) > +return lambda n, s: n.endswith(ext) > +else: > +raise error.ParseError(_('invalid symbol: %s') % name) > +elif op == 'string': > +# TODO: teach fileset about 'path:', so that this can be a symbol and > +# not require quoting. > +name = fileset.getstring(tree, _('invalid path literal')) > +if name.startswith('path:'): # directory or full path test > +p = name[5:] # prefix > +pl = len(p) > +f = lambda n, s: n.startswith(p) and (len(n) == pl or n[pl] == > '/') > +return f > +raise error.ParseError(_("invalid string"), > + hint=_('paths must be prefixed with "path:"')) I've moved op == 'string' next to 'symbol' as they'll have to be merged later. ___ Mercurial-devel mailing list Mercurial-devel@mercurial-scm.org https://www.mercurial-scm.org/mailman/listinfo/mercurial-devel
[PATCH 2 of 2] lfs: migrate most file filtering from threshold to custom filter
# HG changeset patch # User Matt Harbison# Date 1514706889 18000 # Sun Dec 31 02:54:49 2017 -0500 # Node ID 66976f55793cced57929dedc8993204be340c717 # Parent 868cc63bfe9d7d7f5b40bc8cd70175cf1a608a95 lfs: migrate most file filtering from threshold to custom filter Migrate `lfs.threshold` to more powerful `lfs.filter` added by D4990618 so people can specify what files to be stored in LFS with more flexibility. This patch was authored by Jun Wu for the fb-experimental repo, to avoid using matcher for efficiency[1]. All I've changed here is to register the new 'lfs.track' default so that the tests run cleanly, and adapt the subsequent language changes. Migrating the remaining uses of 'lfs.threshold' can be done separately since there's a fallback in place. [1] https://www.mercurial-scm.org/pipermail/mercurial-devel/2017-December/109388.html diff --git a/hgext/lfs/__init__.py b/hgext/lfs/__init__.py --- a/hgext/lfs/__init__.py +++ b/hgext/lfs/__init__.py @@ -19,8 +19,23 @@ # (default: unset) url = https://example.com/lfs -# size of a file to make it use LFS -threshold = 10M +# Which files to track in LFS. Path tests are "**.extname" for file +# extensions, and "path:under/some/directory" for path prefix. Both +# are relative to the repository root, and the latter must be quoted. +# File size can be tested with the "size()" fileset, and tests can be +# joined with fileset operators. (See "hg help filesets.operators".) +# +# Some examples: +# - all() # everything +# - none() # nothing +# - size(">20MB") # larger than 20MB +# - !**.txt # anything not a *.txt file +# - **.zip | **.tar.gz | **.7z # some types of compressed files +# - "path:bin" # files under "bin" in the project root +# - (**.php & size(">2MB")) | (**.js & size(">5MB")) | **.tar.gz +# | ("path:bin" & !"path:/bin/README") | size(">1GB") +# (default: none()) +track = size(">10M") # how many times to retry before giving up on transferring an object retry = 5 @@ -43,6 +58,7 @@ filelog, hg, localrepo, +minifileset, node, registrar, revlog, @@ -76,9 +92,13 @@ configitem('lfs', 'usercache', default=None, ) +# Deprecated configitem('lfs', 'threshold', default=None, ) +configitem('lfs', 'track', +default='none()', +) configitem('lfs', 'retry', default=5, ) @@ -100,9 +120,14 @@ if not repo.local(): return -threshold = repo.ui.configbytes('lfs', 'threshold') +trackspec = repo.ui.config('lfs', 'track') -repo.svfs.options['lfsthreshold'] = threshold +# deprecated config: lfs.threshold +threshold = repo.ui.configbytes('lfs', 'threshold') +if threshold: +trackspec = "(%s) | size('>%s')" % (trackspec, threshold) + +repo.svfs.options['lfstrack'] = minifileset.compile(trackspec) repo.svfs.lfslocalblobstore = blobstore.local(repo) repo.svfs.lfsremoteblobstore = blobstore.remote(repo) diff --git a/hgext/lfs/wrapper.py b/hgext/lfs/wrapper.py --- a/hgext/lfs/wrapper.py +++ b/hgext/lfs/wrapper.py @@ -123,14 +123,14 @@ def filelogaddrevision(orig, self, text, transaction, link, p1, p2, cachedelta=None, node=None, flags=revlog.REVIDX_DEFAULT_FLAGS, **kwds): -threshold = self.opener.options['lfsthreshold'] textlen = len(text) # exclude hg rename meta from file size meta, offset = filelog.parsemeta(text) if offset: textlen -= offset -if threshold and textlen > threshold: +lfstrack = self.opener.options['lfstrack'] +if lfstrack(self.filename, textlen): flags |= revlog.REVIDX_EXTSTORED return orig(self, text, transaction, link, p1, p2, cachedelta=cachedelta, diff --git a/tests/test-lfs-test-server.t b/tests/test-lfs-test-server.t --- a/tests/test-lfs-test-server.t +++ b/tests/test-lfs-test-server.t @@ -30,7 +30,7 @@ > lfs= > [lfs] > url=http://foo:bar@$LFS_HOST/ - > threshold=1 + > track=all() > EOF $ hg init repo1 diff --git a/tests/test-lfs.t b/tests/test-lfs.t --- a/tests/test-lfs.t +++ b/tests/test-lfs.t @@ -4,6 +4,7 @@ > [extensions] > lfs= > [lfs] + > # Test deprecated config > threshold=1000B > EOF @@ -140,7 +141,7 @@ $ cd repo3 $ cat >> .hg/hgrc << EOF > [lfs] - > threshold=10B + > track=size(">10B") > EOF $ echo LONGER-THAN-TEN-BYTES-WILL-TRIGGER-LFS > large @@ -203,7 +204,7 @@ $ cd repo6 $ cat >> .hg/hgrc << EOF > [lfs] - > threshold=30B + > track=size(">30B") > EOF $ echo LARGE-BECAUSE-IT-IS-MORE-THAN-30-BYTES > large @@ -239,7 +240,7 @@ $ cd repo8 $ cat >> .hg/hgrc << EOF > [lfs] - > threshold=10B + > track=size(">10B") > EOF $ echo THIS-IS-LFS-BECAUSE-10-BYTES > a1 @@ -320,7 +321,7 @@ $ cd repo9
[PATCH 1 of 2] test-lfs: bump the number on test repo11 and higher
# HG changeset patch # User Matt Harbison# Date 1514742456 18000 # Sun Dec 31 12:47:36 2017 -0500 # Node ID 868cc63bfe9d7d7f5b40bc8cd70175cf1a608a95 # Parent 706aa203b3961372f359df16214b4c10bc8a66fa test-lfs: bump the number on test repo11 and higher This will allow a Facebook patch that creates 'repo11' to be imported without breaking a bunch of tests, or requiring edits on the fly. diff --git a/tests/test-lfs.t b/tests/test-lfs.t --- a/tests/test-lfs.t +++ b/tests/test-lfs.t @@ -489,8 +489,8 @@ # Test fctx.cmp fastpath - diff without LFS blobs - $ hg init repo11 - $ cd repo11 + $ hg init repo12 + $ cd repo12 $ cat >> .hg/hgrc < [lfs] > threshold=1 @@ -520,8 +520,8 @@ $ cd .. - $ hg clone repo11 repo12 --noupdate - $ cd repo12 + $ hg clone repo12 repo13 --noupdate + $ cd repo13 $ hg log --removed -p a -T '{desc}\n' --config diff.nobinary=1 --git 2 diff --git a/a b/a @@ -590,37 +590,37 @@ repo: repo9 repo: repo10 -repo12 doesn't have any cached lfs files and its source never pushed its +repo13 doesn't have any cached lfs files and its source never pushed its files. Therefore, the files don't exist in the remote store. Use the files in the user cache. - $ test -d $TESTTMP/repo12/.hg/store/lfs/objects + $ test -d $TESTTMP/repo13/.hg/store/lfs/objects [1] - $ hg --config extensions.share= share repo12 repo13 + $ hg --config extensions.share= share repo13 repo14 updating working directory 1 files updated, 0 files merged, 0 files removed, 0 files unresolved - $ hg -R repo13 -q verify + $ hg -R repo14 -q verify - $ hg clone repo12 repo14 + $ hg clone repo13 repo15 updating to branch default 1 files updated, 0 files merged, 0 files removed, 0 files unresolved - $ hg -R repo14 -q verify + $ hg -R repo15 -q verify If the source repo doesn't have the blob (maybe it was pulled or cloned with --noupdate), the blob is still accessible via the global cache to send to the remote store. - $ rm -rf $TESTTMP/repo14/.hg/store/lfs - $ hg init repo15 - $ hg -R repo14 push repo15 - pushing to repo15 + $ rm -rf $TESTTMP/repo15/.hg/store/lfs + $ hg init repo16 + $ hg -R repo15 push repo16 + pushing to repo16 searching for changes adding changesets adding manifests adding file changes added 3 changesets with 2 changes to 1 files - $ hg -R repo14 -q verify + $ hg -R repo15 -q verify Test damaged file scenarios. (This also damages the usercache because of the hardlinks.) ___ Mercurial-devel mailing list Mercurial-devel@mercurial-scm.org https://www.mercurial-scm.org/mailman/listinfo/mercurial-devel
D1857: pull: re-run discovery and pullbundle2 if server didn't send all heads
joerg.sonnenberger added a comment. This is a proof-of-concept. There is an interaction with obsoletion that I am still trying to understand (and fix). REPOSITORY rHG Mercurial REVISION DETAIL https://phab.mercurial-scm.org/D1857 To: joerg.sonnenberger, #hg-reviewers Cc: mercurial-devel ___ Mercurial-devel mailing list Mercurial-devel@mercurial-scm.org https://www.mercurial-scm.org/mailman/listinfo/mercurial-devel
D1857: pull: re-run discovery and pullbundle2 if server didn't send all heads
joerg.sonnenberger updated this revision to Diff 4813. REPOSITORY rHG Mercurial CHANGES SINCE LAST UPDATE https://phab.mercurial-scm.org/D1857?vs=4812=4813 REVISION DETAIL https://phab.mercurial-scm.org/D1857 AFFECTED FILES mercurial/exchange.py tests/test-pull-r.t CHANGE DETAILS diff --git a/tests/test-pull-r.t b/tests/test-pull-r.t --- a/tests/test-pull-r.t +++ b/tests/test-pull-r.t @@ -201,3 +201,40 @@ sending pullbundle "0.hg" sending pullbundle "1.hg" sending pullbundle "2.hg" + +Test pullbundle functionality for incremental pulls + + $ cd repo + $ hg serve --debug -p $HGPORT2 --pid-file=../repo.pid > ../repo-server.txt 2>&1 & + $ while ! grep listening ../repo-server.txt > /dev/null; do sleep 1; done + $ cat ../repo.pid >> $DAEMON_PIDS + $ cd .. + $ hg clone http://localhost:$HGPORT2/ repo.pullbundle2 + requesting all changes + adding changesets + adding manifests + adding file changes + added 1 changesets with 1 changes to 1 files + searching for changes + adding changesets + adding manifests + adding file changes + added 1 changesets with 1 changes to 1 files + searching for changes + adding changesets + adding manifests + adding file changes + added 1 changesets with 1 changes to 1 files (+1 heads) + searching for changes + adding changesets + adding manifests + adding file changes + added 1 changesets with 1 changes to 1 files + new changesets bbd179dfa0a7:66e3ba28d0d7 + updating to branch default + 3 files updated, 0 files merged, 0 files removed, 0 files unresolved + $ killdaemons.py + $ grep 'sending pullbundle ' repo-server.txt + sending pullbundle "0.hg" + sending pullbundle "2.hg" + sending pullbundle "1.hg" diff --git a/mercurial/exchange.py b/mercurial/exchange.py --- a/mercurial/exchange.py +++ b/mercurial/exchange.py @@ -1351,9 +1351,16 @@ # before discovery to avoid extra work. _maybeapplyclonebundle(pullop) streamclone.maybeperformlegacystreamclone(pullop) -_pulldiscovery(pullop) -if pullop.canusebundle2: +while True: +_pulldiscovery(pullop) +if not pullop.canusebundle2: +break _pullbundle2(pullop) +if not pullop.cgresult or not pullop.rheads: +break +unficl = repo.unfiltered().changelog +if all(unficl.hasnode(n) for n in pullop.rheads): +break _pullchangeset(pullop) _pullphase(pullop) _pullbookmarks(pullop) To: joerg.sonnenberger, #hg-reviewers Cc: mercurial-devel ___ Mercurial-devel mailing list Mercurial-devel@mercurial-scm.org https://www.mercurial-scm.org/mailman/listinfo/mercurial-devel
D1856: wireproto: server-side support for pullbundles
joerg.sonnenberger updated this revision to Diff 4811. REPOSITORY rHG Mercurial CHANGES SINCE LAST UPDATE https://phab.mercurial-scm.org/D1856?vs=4810=4811 REVISION DETAIL https://phab.mercurial-scm.org/D1856 AFFECTED FILES mercurial/configitems.py mercurial/help/config.txt mercurial/wireproto.py tests/test-pull-r.t CHANGE DETAILS diff --git a/tests/test-pull-r.t b/tests/test-pull-r.t --- a/tests/test-pull-r.t +++ b/tests/test-pull-r.t @@ -145,3 +145,59 @@ $ cd .. $ killdaemons.py + +Test pullbundle functionality + + $ cd repo + $ cat < .hg/hgrc + > [server] + > pullbundle = True + > EOF + $ hg bundle --base null -r 0 .hg/0.hg + 1 changesets found + $ hg bundle --base 0 -r 1 .hg/1.hg + 1 changesets found + $ hg bundle --base 1 -r 2 .hg/2.hg + 1 changesets found + $ cat < .hg/pullbundles.manifest + > 2.hg heads=effea6de0384e684f44435651cb7bd70b8735bd4 bases=bbd179dfa0a71671c253b3ae0aa1513b60d199fa + > 1.hg heads=ed1b79f46b9a29f5a6efa59cf12fcfca43bead5a bases=bbd179dfa0a71671c253b3ae0aa1513b60d199fa + > 0.hg heads=bbd179dfa0a71671c253b3ae0aa1513b60d199fa + > EOF + $ hg serve --debug -p $HGPORT2 --pid-file=../repo.pid > ../repo-server.txt 2>&1 & + $ while ! grep listening ../repo-server.txt > /dev/null; do sleep 1; done + $ cat ../repo.pid >> $DAEMON_PIDS + $ cd .. + $ hg clone -r 0 http://localhost:$HGPORT2/ repo.pullbundle + adding changesets + adding manifests + adding file changes + added 1 changesets with 1 changes to 1 files + new changesets bbd179dfa0a7 + updating to branch default + 1 files updated, 0 files merged, 0 files removed, 0 files unresolved + $ cd repo.pullbundle + $ hg pull -r 1 + pulling from http://localhost:$HGPORT2/ + searching for changes + adding changesets + adding manifests + adding file changes + added 1 changesets with 1 changes to 1 files + new changesets ed1b79f46b9a + (run 'hg update' to get a working copy) + $ hg pull -r 2 + pulling from http://localhost:$HGPORT2/ + searching for changes + adding changesets + adding manifests + adding file changes + added 1 changesets with 1 changes to 1 files (+1 heads) + new changesets effea6de0384 + (run 'hg heads' to see heads, 'hg merge' to merge) + $ cd .. + $ killdaemons.py + $ grep 'sending pullbundle ' repo-server.txt + sending pullbundle "0.hg" + sending pullbundle "1.hg" + sending pullbundle "2.hg" diff --git a/mercurial/wireproto.py b/mercurial/wireproto.py --- a/mercurial/wireproto.py +++ b/mercurial/wireproto.py @@ -831,6 +831,65 @@ opts = options('debugwireargs', ['three', 'four'], others) return repo.debugwireargs(one, two, **pycompat.strkwargs(opts)) +def find_pullbundle(repo, opts, clheads, heads, common): +def decodehexstring(s): +return set([h.decode('hex') for h in s.split(':')]) + +def hasdescendant(ancestor, revs): +# Quick path for exact match +if ancestor in revs: +return True +for rev in revs: +if repo.changelog.isancestor(ancestor, rev): +return True +return False +def hasancestor(descendant, revs): +if descendant in revs: +return True +for rev in revs: +if repo.changelog.isancestor(rev, descendant): +return True +return False + +manifest = repo.vfs.tryread('pullbundles.manifest') +res = exchange.parseclonebundlesmanifest(repo, manifest) +res = exchange.filterclonebundleentries(repo, res) +for entry in res: +if 'heads' in entry: +try: +bundle_heads = decodehexstring(entry['heads']) +except TypeError: +# Bad heads entry +continue +if len(bundle_heads) > len(heads): +# Client wants less heads than the bundle contains +continue +if bundle_heads.issubset(common): +continue # Nothing new +if all(hasdescendant(rev, common) for rev in bundle_heads): +continue # Still nothing new +if any(not hasdescendant(rev, heads) for rev in bundle_heads): +continue +if 'bases' in entry: +try: +bundle_bases = decodehexstring(entry['bases']) +except TypeError: +# Bad bases entry +continue +if len(bundle_bases) > len(common): +# Client is missing a revision the bundle requires +continue +if not all(hasdescendant(rev, common) for rev in bundle_bases): +continue +path = entry['URL'] +repo.ui.debug('sending pullbundle "%s"\n' % path) +try: +return repo.vfs.open(path) +except IOError: +repo.ui.debug('pullbundle "%s" not accessible\n' % path) +continue +return None + @wireprotocommand('getbundle', '*') def getbundle(repo, proto, others): opts =
D1857: pull: re-run discovery and pullbundle2 if server didn't send all heads
joerg.sonnenberger created this revision. Herald added a subscriber: mercurial-devel. Herald added a reviewer: hg-reviewers. REPOSITORY rHG Mercurial REVISION DETAIL https://phab.mercurial-scm.org/D1857 AFFECTED FILES mercurial/exchange.py tests/test-pull-r.t CHANGE DETAILS diff --git a/tests/test-pull-r.t b/tests/test-pull-r.t --- a/tests/test-pull-r.t +++ b/tests/test-pull-r.t @@ -201,3 +201,40 @@ sending pullbundle "0.hg" sending pullbundle "1.hg" sending pullbundle "2.hg" + +Test pullbundle functionality for incremental pulls + + $ cd repo + $ hg serve --debug -p $HGPORT2 --pid-file=../repo.pid > ../repo-server.txt 2>&1 & + $ while ! grep listening ../repo-server.txt > /dev/null; do sleep 1; done + $ cat ../repo.pid >> $DAEMON_PIDS + $ cd .. + $ hg clone http://localhost:$HGPORT2/ repo.pullbundle2 + requesting all changes + adding changesets + adding manifests + adding file changes + added 1 changesets with 1 changes to 1 files + searching for changes + adding changesets + adding manifests + adding file changes + added 1 changesets with 1 changes to 1 files + searching for changes + adding changesets + adding manifests + adding file changes + added 1 changesets with 1 changes to 1 files (+1 heads) + searching for changes + adding changesets + adding manifests + adding file changes + added 1 changesets with 1 changes to 1 files + new changesets bbd179dfa0a7:66e3ba28d0d7 + updating to branch default + 3 files updated, 0 files merged, 0 files removed, 0 files unresolved + $ killdaemons.py + $ grep 'sending pullbundle ' repo-server.txt + sending pullbundle "0.hg" + sending pullbundle "2.hg" + sending pullbundle "1.hg" diff --git a/mercurial/exchange.py b/mercurial/exchange.py --- a/mercurial/exchange.py +++ b/mercurial/exchange.py @@ -1351,9 +1351,15 @@ # before discovery to avoid extra work. _maybeapplyclonebundle(pullop) streamclone.maybeperformlegacystreamclone(pullop) -_pulldiscovery(pullop) -if pullop.canusebundle2: +while True: +_pulldiscovery(pullop) +if not pullop.canusebundle2: +break _pullbundle2(pullop) +if not pullop.cgresult or not pullop.rheads: +break +if all(repo.changelog.hasnode(n) for n in pullop.rheads): +break _pullchangeset(pullop) _pullphase(pullop) _pullbookmarks(pullop) To: joerg.sonnenberger, #hg-reviewers Cc: mercurial-devel ___ Mercurial-devel mailing list Mercurial-devel@mercurial-scm.org https://www.mercurial-scm.org/mailman/listinfo/mercurial-devel
D1850: hgweb: when no agreement on compression can be found, fail for v2
joerg.sonnenberger created this revision. Herald added a subscriber: mercurial-devel. Herald added a reviewer: hg-reviewers. REVISION SUMMARY When the client supports v2 responses, the fallback to the legacy response is undesirable. If the zlib is acceptable for the client, it should have said so in first place. REPOSITORY rHG Mercurial REVISION DETAIL https://phab.mercurial-scm.org/D1850 AFFECTED FILES mercurial/hgweb/common.py mercurial/hgweb/protocol.py tests/test-http-protocol.t CHANGE DETAILS diff --git a/tests/test-http-protocol.t b/tests/test-http-protocol.t --- a/tests/test-http-protocol.t +++ b/tests/test-http-protocol.t @@ -78,14 +78,15 @@ server: * (glob) transfer-encoding: chunked -Requesting a compression format that server doesn't support results will fall back to 0.1 +Server should fail when it can't agree with client on a compression format $ get-with-headers.py --hgproto '0.2 comp=aa' --headeronly $LOCALIP:$HGPORT '?cmd=getbundle=e93700bd72895c5addab234c56d4024b487a362f=' - - 200 Script output follows + 406 No common compression format + content-length: 31 content-type: application/mercurial-0.1 date: * (glob) server: * (glob) - transfer-encoding: chunked + [1] #if zstd zstd is used if available diff --git a/mercurial/hgweb/protocol.py b/mercurial/hgweb/protocol.py --- a/mercurial/hgweb/protocol.py +++ b/mercurial/hgweb/protocol.py @@ -11,6 +11,8 @@ import struct from .common import ( +ErrorResponse, +HTTP_NOT_ACCEPTABLE, HTTP_OK, ) @@ -140,8 +142,8 @@ return HGTYPE2, engine, opts -# No mutually supported compression format. Fall back to the -# legacy protocol. +raise ErrorResponse(HTTP_NOT_ACCEPTABLE, +'No common compression format') # Don't allow untrusted settings because disabling compression or # setting a very high compression level could lead to flooding diff --git a/mercurial/hgweb/common.py b/mercurial/hgweb/common.py --- a/mercurial/hgweb/common.py +++ b/mercurial/hgweb/common.py @@ -28,6 +28,7 @@ HTTP_FORBIDDEN = 403 HTTP_NOT_FOUND = 404 HTTP_METHOD_NOT_ALLOWED = 405 +HTTP_NOT_ACCEPTABLE = 406 HTTP_SERVER_ERROR = 500 To: joerg.sonnenberger, #hg-reviewers Cc: mercurial-devel ___ Mercurial-devel mailing list Mercurial-devel@mercurial-scm.org https://www.mercurial-scm.org/mailman/listinfo/mercurial-devel
D1813: bookmarks: add bookmarks to hidden revs if directaccess config is set
yuja added a comment. Queued, thanks. INLINE COMMENTS > bookmarks.py:853 > +repo.ui.warn(_("bookmarking hidden changeset %s\n") % \ > + (', '.join(hiddenrevs))) > marks.applychanges(repo, tr, changes) FYI, it loops over bookmark names with the same `rev`, so `hiddenrevs` would have at most one element, and the second `unhidehashlikerevs()` call would be unnecessary. REPOSITORY rHG Mercurial REVISION DETAIL https://phab.mercurial-scm.org/D1813 To: pulkit, #hg-reviewers, yuja Cc: yuja, mercurial-devel ___ Mercurial-devel mailing list Mercurial-devel@mercurial-scm.org https://www.mercurial-scm.org/mailman/listinfo/mercurial-devel
D1795: py3: use pycompat.bytestr() instead of str()
pulkit added inline comments. INLINE COMMENTS > yuja wrote in verify.py:110 > '%d', perhaps. Looks like we cannot use "%d" here as None can be possible value also and test-treemanifest.t has tests with None as a part of output. REPOSITORY rHG Mercurial REVISION DETAIL https://phab.mercurial-scm.org/D1795 To: pulkit, #hg-reviewers, durin42 Cc: yuja, mercurial-devel ___ Mercurial-devel mailing list Mercurial-devel@mercurial-scm.org https://www.mercurial-scm.org/mailman/listinfo/mercurial-devel
D1813: bookmarks: add bookmarks to hidden revs if directaccess config is set
This revision was automatically updated to reflect the committed changes. Closed by commit rHG53c0526b6484: bookmarks: add bookmarks to hidden revs if directaccess config is set (authored by pulkit, committed by ). CHANGED PRIOR TO COMMIT https://phab.mercurial-scm.org/D1813?vs=4803=4807#toc REPOSITORY rHG Mercurial CHANGES SINCE LAST UPDATE https://phab.mercurial-scm.org/D1813?vs=4803=4807 REVISION DETAIL https://phab.mercurial-scm.org/D1813 AFFECTED FILES mercurial/bookmarks.py tests/test-directaccess.t tests/test-log.t tests/test-obsolete.t tests/test-rebase-obsolete.t CHANGE DETAILS diff --git a/tests/test-rebase-obsolete.t b/tests/test-rebase-obsolete.t --- a/tests/test-rebase-obsolete.t +++ b/tests/test-rebase-obsolete.t @@ -1496,6 +1496,7 @@ $ hg log -r . # working dir is at rev 3 (successor of 2) 3:be1832deae9a b (no-eol) $ hg book -r 2 mybook --hidden # rev 2 has a bookmark on it now + bookmarking hidden changeset 1e9a3c00cbe9 $ hg up 2 && hg log -r . # working dir is at rev 2 again 0 files updated, 0 files merged, 1 files removed, 0 files unresolved 2:1e9a3c00cbe9 b (rewritten using rebase as 3:be1832deae9a) (no-eol) diff --git a/tests/test-obsolete.t b/tests/test-obsolete.t --- a/tests/test-obsolete.t +++ b/tests/test-obsolete.t @@ -1333,6 +1333,7 @@ $ echo "hello" > b $ hg commit --amend -m "message" $ hg book bookb -r 13bedc178fce --hidden + bookmarking hidden changeset 13bedc178fce $ hg log -r 13bedc178fce 4:13bedc178fce (draft *obsolete*) [ bookb] add b [rewritten using amend as 5:a9b1f8652753] $ hg book -d bookb diff --git a/tests/test-log.t b/tests/test-log.t --- a/tests/test-log.t +++ b/tests/test-log.t @@ -1851,14 +1851,16 @@ bookmarks prevent a changeset being hidden $ hg bookmark --hidden -r 1 X + bookmarking hidden changeset a765632148dc $ hg log --template '{rev}:{node}\n' 1:a765632148dc55d38c35c4f247c618701886cb2f 0:9f758d63dcde62d547ebfb08e1e7ee96535f2b05 $ hg bookmark -d X divergent bookmarks are not hidden $ hg bookmark --hidden -r 1 X@foo + bookmarking hidden changeset a765632148dc $ hg log --template '{rev}:{node}\n' 1:a765632148dc55d38c35c4f247c618701886cb2f 0:9f758d63dcde62d547ebfb08e1e7ee96535f2b05 diff --git a/tests/test-directaccess.t b/tests/test-directaccess.t --- a/tests/test-directaccess.t +++ b/tests/test-directaccess.t @@ -186,3 +186,11 @@ abort: hidden revision '2' was rewritten as: 2443a0e66469! (use --hidden to access hidden revisions) [255] + +Setting a bookmark will make that changeset unhidden, so this should come in end + + $ hg bookmarks -r 28ad74 book + bookmarking hidden changeset 28ad74487de9 + + $ hg bookmarks + book 2:28ad74487de9 diff --git a/mercurial/bookmarks.py b/mercurial/bookmarks.py --- a/mercurial/bookmarks.py +++ b/mercurial/bookmarks.py @@ -830,6 +830,7 @@ cur = repo.changectx('.').node() newact = None changes = [] +hiddenrevs = set() for mark in names: mark = checkformat(repo, mark) if newact is None: @@ -839,10 +840,17 @@ return tgt = cur if rev: -tgt = scmutil.revsingle(repo, rev).node() +repo = scmutil.unhidehashlikerevs(repo, [rev], 'nowarn') +ctx = scmutil.revsingle(repo, rev) +if ctx.hidden(): +hiddenrevs.add(ctx.hex()[:12]) +tgt = ctx.node() for bm in marks.checkconflict(mark, force, tgt): changes.append((bm, None)) changes.append((mark, tgt)) +if hiddenrevs: +repo.ui.warn(_("bookmarking hidden changeset %s\n") % + ', '.join(hiddenrevs)) marks.applychanges(repo, tr, changes) if not inactive and cur == marks[newact] and not rev: activate(repo, newact) To: pulkit, #hg-reviewers, yuja Cc: yuja, mercurial-devel ___ Mercurial-devel mailing list Mercurial-devel@mercurial-scm.org https://www.mercurial-scm.org/mailman/listinfo/mercurial-devel
D1795: py3: use pycompat.bytestr() instead of str()
yuja added inline comments. INLINE COMMENTS > pulkit wrote in verify.py:110 > Looks like we cannot use "%d" here as None can be possible value also and > test-treemanifest.t has tests with None as a part of output. Ugh, it smells, but let's just leave it for now. REPOSITORY rHG Mercurial REVISION DETAIL https://phab.mercurial-scm.org/D1795 To: pulkit, #hg-reviewers, durin42 Cc: yuja, mercurial-devel ___ Mercurial-devel mailing list Mercurial-devel@mercurial-scm.org https://www.mercurial-scm.org/mailman/listinfo/mercurial-devel
D1854: py3: use bytes instead of pycompat.bytestr
pulkit created this revision. Herald added a subscriber: mercurial-devel. Herald added a reviewer: hg-reviewers. REVISION SUMMARY Follow up for https://phab.mercurial-scm.org/D1795. REPOSITORY rHG Mercurial REVISION DETAIL https://phab.mercurial-scm.org/D1854 AFFECTED FILES mercurial/subrepo.py CHANGE DETAILS diff --git a/mercurial/subrepo.py b/mercurial/subrepo.py --- a/mercurial/subrepo.py +++ b/mercurial/subrepo.py @@ -389,14 +389,14 @@ if util.safehasattr(repo, '_subparent'): source = util.url(repo._subsource) if source.isabs(): -return pycompat.bytestr(source) +return bytes(source) source.path = posixpath.normpath(source.path) parent = _abssource(repo._subparent, push, abort=False) if parent: parent = util.url(util.pconvert(parent)) parent.path = posixpath.join(parent.path or '', source.path) parent.path = posixpath.normpath(parent.path) -return pycompat.bytestr(parent) +return bytes(parent) else: # recursion reached top repo if util.safehasattr(repo, '_subtoppath'): return repo._subtoppath To: pulkit, #hg-reviewers Cc: mercurial-devel ___ Mercurial-devel mailing list Mercurial-devel@mercurial-scm.org https://www.mercurial-scm.org/mailman/listinfo/mercurial-devel