D11653: chistedit: rename a confusingly named variable
martinvonz created this revision. Herald added a reviewer: durin42. Herald added a reviewer: hg-reviewers. Herald added a subscriber: mercurial-patches. REVISION SUMMARY I would expect `ctxs` contain instances of some class from the `context` module but it actually contains instances of `histeditrule`. REPOSITORY rHG Mercurial BRANCH default REVISION DETAIL https://phab.mercurial-scm.org/D11653 AFFECTED FILES hgext/histedit.py CHANGE DETAILS diff --git a/hgext/histedit.py b/hgext/histedit.py --- a/hgext/histedit.py +++ b/hgext/histedit.py @@ -1716,11 +1716,11 @@ _(b'%s is not an ancestor of working directory') % short(root) ) -ctxs = [] +rules = [] for i, r in enumerate(revs): -ctxs.append(histeditrule(ui, repo[r], i)) +rules.append(histeditrule(ui, repo[r], i)) with util.with_lc_ctype(): -rc = curses.wrapper(functools.partial(_chisteditmain, repo, ctxs)) +rc = curses.wrapper(functools.partial(_chisteditmain, repo, rules)) curses.echo() curses.endwin() if rc is False: To: martinvonz, durin42, #hg-reviewers Cc: mercurial-patches, mercurial-devel ___ Mercurial-devel mailing list Mercurial-devel@mercurial-scm.org https://www.mercurial-scm.org/mailman/listinfo/mercurial-devel
D11652: chistedit: remove some local variable and access state on self instead
martinvonz created this revision. Herald added a reviewer: durin42. Herald added a reviewer: hg-reviewers. Herald added a subscriber: mercurial-patches. REVISION SUMMARY Now that we've replaced the state dict by a class, some of the local variables that just do `foo = self.foo` seem unnecessary. REPOSITORY rHG Mercurial BRANCH default REVISION DETAIL https://phab.mercurial-scm.org/D11652 AFFECTED FILES hgext/histedit.py CHANGE DETAILS diff --git a/hgext/histedit.py b/hgext/histedit.py --- a/hgext/histedit.py +++ b/hgext/histedit.py @@ -1256,9 +1256,7 @@ def render_commit(self, win): """Renders the commit window that shows the log of the current selected commit""" -pos = self.pos -rules = self.rules -rule = rules[pos] +rule = self.rules[self.pos] ctx = rule.ctx win.box() @@ -1345,19 +1343,16 @@ } def render_rules(self, rulesscr): -rules = self.rules -pos = self.pos -selected = self.selected start = self.modes[MODE_RULES][b'line_offset'] -conflicts = [r.ctx for r in rules if r.conflicts] +conflicts = [r.ctx for r in self.rules if r.conflicts] if len(conflicts) > 0: line = b"potential conflict in %s" % b','.join( map(pycompat.bytestr, conflicts) ) addln(rulesscr, -1, 0, line, curses.color_pair(COLOR_WARN)) -for y, rule in enumerate(rules[start:]): +for y, rule in enumerate(self.rules[start:]): if y >= self.page_height: break if len(rule.conflicts) > 0: @@ -1365,10 +1360,10 @@ else: rulesscr.addstr(y, 0, b" ", curses.COLOR_BLACK) -if y + start == selected: +if y + start == self.selected: rollcolor = COLOR_ROLL_SELECTED addln(rulesscr, y, 2, rule, curses.color_pair(COLOR_SELECTED)) -elif y + start == pos: +elif y + start == self.pos: rollcolor = COLOR_ROLL_CURRENT addln( rulesscr, @@ -1424,9 +1419,7 @@ This takes the current state and based on the current character input from the user we change the state. """ -selected = self.selected oldpos = self.pos -rules = self.rules if ch in (curses.KEY_RESIZE, b"KEY_RESIZE"): return E_RESIZE @@ -1442,26 +1435,26 @@ if action is None: return if action in (b'down', b'move-down'): -newpos = min(oldpos + 1, len(rules) - 1) +newpos = min(oldpos + 1, len(self.rules) - 1) self.move_cursor(oldpos, newpos) -if selected is not None or action == b'move-down': +if self.selected is not None or action == b'move-down': self.swap(oldpos, newpos) elif action in (b'up', b'move-up'): newpos = max(0, oldpos - 1) self.move_cursor(oldpos, newpos) -if selected is not None or action == b'move-up': +if self.selected is not None or action == b'move-up': self.swap(oldpos, newpos) elif action == b'next-action': self.cycle_action(oldpos, next=True) elif action == b'prev-action': self.cycle_action(oldpos, next=False) elif action == b'select': -selected = oldpos if selected is None else None -self.make_selection(selected) -elif action == b'goto' and int(ch) < len(rules) and len(rules) <= 10: -newrule = next((r for r in rules if r.origpos == int(ch))) +self.selected = oldpos if self.selected is None else None +self.make_selection(self.selected) +elif action == b'goto' and int(ch) < len(self.rules) <= 10: +newrule = next((r for r in self.rules if r.origpos == int(ch))) self.move_cursor(oldpos, newrule.pos) -if selected is not None: +if self.selected is not None: self.swap(oldpos, newrule.pos) elif action.startswith(b'action-'): self.change_action(oldpos, action[7:]) @@ -1549,16 +1542,14 @@ def change_action(self, pos, action): """Change the action state on the given position to the new action""" -rules = self.rules -assert 0 <= pos < len(rules) -rules[pos].action = action +assert 0 <= pos < len(self.rules) +self.rules[pos].action = action def cycle_action(self, pos, next=False): """Changes the action state the next or the previous action from the action list""" -rules = self.rules -assert 0 <= pos < len(rules) -current = rules[pos].action +assert 0 <= pos < len(self.rules) +current = self.rules[pos].action assert current in KEY_LIST To: martinvonz,
mercurial-devel | Failed pipeline for branch/default | caafdc0d
Pipeline #27697 has failed! Project: mercurial-devel ( https://foss.heptapod.net/mercurial/mercurial-devel ) Branch: branch/default ( https://foss.heptapod.net/mercurial/mercurial-devel/-/commits/branch/default ) Commit: caafdc0d ( https://foss.heptapod.net/mercurial/mercurial-devel/-/commit/caafdc0d059d9a8ea4f3871ff06bbfdae3ef738a ) Commit Message: rhg: handle null changelog and manifest revisio... Commit Author: Arseniy Alekseyev Pipeline #27697 ( https://foss.heptapod.net/mercurial/mercurial-devel/-/pipelines/27697 ) triggered by Administrator ( https://foss.heptapod.net/root ) had 9 failed jobs. Job #253018 ( https://foss.heptapod.net/mercurial/mercurial-devel/-/jobs/253018/raw ) Stage: tests Name: test-py2-chg Job #253011 ( https://foss.heptapod.net/mercurial/mercurial-devel/-/jobs/253011/raw ) Stage: tests Name: test-py2 Job #253020 ( https://foss.heptapod.net/mercurial/mercurial-devel/-/jobs/253020/raw ) Stage: tests Name: check-pytype-py3 Job #253015 ( https://foss.heptapod.net/mercurial/mercurial-devel/-/jobs/253015/raw ) Stage: tests Name: test-py2-rust Job #253013 ( https://foss.heptapod.net/mercurial/mercurial-devel/-/jobs/253013/raw ) Stage: tests Name: test-py2-pure Job #253017 ( https://foss.heptapod.net/mercurial/mercurial-devel/-/jobs/253017/raw ) Stage: tests Name: test-py3-rhg Job #253007 ( https://foss.heptapod.net/mercurial/mercurial-devel/-/jobs/253007/raw ) Stage: tests Name: checks-py2 Job #253009 ( https://foss.heptapod.net/mercurial/mercurial-devel/-/jobs/253009/raw ) Stage: tests Name: rust-cargo-test-py2 Job #253010 ( https://foss.heptapod.net/mercurial/mercurial-devel/-/jobs/253010/raw ) Stage: tests Name: rust-cargo-test-py3 -- You're receiving this email because of your account on foss.heptapod.net. ___ Mercurial-devel mailing list Mercurial-devel@mercurial-scm.org https://www.mercurial-scm.org/mailman/listinfo/mercurial-devel
mercurial@48187: 20 new changesets
20 new changesets in mercurial: https://www.mercurial-scm.org/repo/hg/rev/df3021c1f093 changeset: 48168:df3021c1f093 user:Pulkit Goyal <7895pul...@gmail.com> date:Mon Jul 19 04:11:08 2021 +0530 summary: largefiles: pass current transaction to `lfdirstate.write()` https://www.mercurial-scm.org/repo/hg/rev/1e98f9b5bc71 changeset: 48169:1e98f9b5bc71 user:Pulkit Goyal <7895pul...@gmail.com> date:Mon Jul 19 04:12:14 2021 +0530 summary: largefiles: add tr backup for largefilesdirstate https://www.mercurial-scm.org/repo/hg/rev/941fbaab5aff changeset: 48170:941fbaab5aff user:Pulkit Goyal <7895pul...@gmail.com> date:Mon Jul 19 04:13:50 2021 +0530 summary: largefiles: partially undo 61e526585b20e2ff15f19497d0451d18fea02db8 and child https://www.mercurial-scm.org/repo/hg/rev/64b8676f11bb changeset: 48171:64b8676f11bb user:Pulkit Goyal <7895pul...@gmail.com> date:Thu Jun 24 14:23:11 2021 +0530 summary: rhg: fallback if tweakdefaults or statuscopies is enabled with status https://www.mercurial-scm.org/repo/hg/rev/08c8cd2527bc changeset: 48172:08c8cd2527bc user:Arseniy Alekseyev date:Tue Oct 05 16:09:20 2021 +0100 summary: rhg: in rhg cat cli, fix the long name of the --rev flag https://www.mercurial-scm.org/repo/hg/rev/1d70fb83ff4a changeset: 48173:1d70fb83ff4a user:Sushil khanchi date:Wed Oct 06 13:32:07 2021 +0530 summary: hg: let extensions call the func without populating opts keys https://www.mercurial-scm.org/repo/hg/rev/9ecf802b06e0 changeset: 48174:9ecf802b06e0 user:Pulkit Goyal <7895pul...@gmail.com> date:Tue Oct 05 18:02:22 2021 +0530 summary: rhg: refactor function to relativize paths in utils https://www.mercurial-scm.org/repo/hg/rev/707c58880cd0 changeset: 48175:707c58880cd0 user:Pulkit Goyal <7895pul...@gmail.com> date:Tue Oct 05 18:10:04 2021 +0530 summary: rhg: add relative paths support in `rhg status` https://www.mercurial-scm.org/repo/hg/rev/38deb65d4441 changeset: 48176:38deb65d4441 user:Pulkit Goyal <7895pul...@gmail.com> date:Fri Jun 25 15:00:08 2021 +0530 summary: rhg: add ui.plain() and check it before showing relative paths in status https://www.mercurial-scm.org/repo/hg/rev/066cdec8f74f changeset: 48177:066cdec8f74f user:Danny Hooper date:Thu Sep 02 14:07:55 2021 -0700 summary: fix: add test to demonstrate how many times tools are executed https://www.mercurial-scm.org/repo/hg/rev/f12a19d03d2c changeset: 48178:f12a19d03d2c user:Danny Hooper date:Thu Sep 02 14:08:45 2021 -0700 summary: fix: reduce number of tool executions https://www.mercurial-scm.org/repo/hg/rev/67d14d4e036c changeset: 48179:67d14d4e036c user:Matt Harbison date:Sun Sep 19 01:23:16 2021 -0400 summary: exewrapper: find the proper python3X.dll in the registry https://www.mercurial-scm.org/repo/hg/rev/f78d8b8c46d7 changeset: 48180:f78d8b8c46d7 user:Matt Harbison date:Sun Sep 19 01:36:37 2021 -0400 summary: setup: stop packaging python3.dll and python3X.dll in the wheel distribution https://www.mercurial-scm.org/repo/hg/rev/c95f6c2d1f4e changeset: 48181:c95f6c2d1f4e user:Matt Harbison date:Sun Oct 03 20:11:42 2021 -0400 summary: packaging: update the certifi dependency https://www.mercurial-scm.org/repo/hg/rev/01c3dd208c75 changeset: 48182:01c3dd208c75 user:Simon Sapin date:Fri Oct 08 11:06:03 2021 +0200 summary: rust: Make the hg-cpython crate default to Python 3 https://www.mercurial-scm.org/repo/hg/rev/eb8092f9304f changeset: 48183:eb8092f9304f user:Simon Sapin date:Mon Oct 11 17:31:27 2021 +0200 summary: dirstate-v2: Use "byte sequence" in docs https://www.mercurial-scm.org/repo/hg/rev/8fae2cc6ee86 changeset: 48184:8fae2cc6ee86 user:Martin von Zweigbergk date:Fri Oct 08 13:34:33 2021 -0700 summary: dispatch: don't change error status if flushing stdio fails https://www.mercurial-scm.org/repo/hg/rev/2f2107c01dee changeset: 48185:2f2107c01dee user:Martin von Zweigbergk date:Fri Oct 08 13:36:02 2021 -0700 summary: dispatch: ignore failure to flush ui https://www.mercurial-scm.org/repo/hg/rev/6edc8800dbc3 changeset: 48186:6edc8800dbc3 user:Martin von Zweigbergk date:Tue Mar 02 09:33:25 2021 -0800 summary: dispatch: use detailed exit code 250 for keyboard interrupt https://www.mercurial-scm.org/repo/hg/rev/b669e40fbbd6 changeset: 48187:b669e40fbbd6 bookmark:@ tag: tip user:Raphaël Gomès date:Wed Sep 08 10:47:10 2021 +0200 summary: help: update help text for debug-repair-issue6528 -- Repository URL: https://www.mercurial-scm.org/repo/hg ___ Mercurial-devel mailing list Mercurial-devel@mercurial-scm.org
mercurial-devel | Failed pipeline for branch/default | 1f38a623
Pipeline #27691 has failed! Project: mercurial-devel ( https://foss.heptapod.net/mercurial/mercurial-devel ) Branch: branch/default ( https://foss.heptapod.net/mercurial/mercurial-devel/-/commits/branch/default ) Commit: 1f38a623 ( https://foss.heptapod.net/mercurial/mercurial-devel/-/commit/1f38a6234134e30fc2e330acd64253bc22a52ab8 ) Commit Message: dirstate-v2: Name a constant in the Rust implem... Commit Author: Simon Sapin ( https://foss.heptapod.net/SimonSapin ) Pipeline #27691 ( https://foss.heptapod.net/mercurial/mercurial-devel/-/pipelines/27691 ) triggered by Administrator ( https://foss.heptapod.net/root ) had 5 failed jobs. Job #252961 ( https://foss.heptapod.net/mercurial/mercurial-devel/-/jobs/252961/raw ) Stage: tests Name: test-py2-rust Job #252964 ( https://foss.heptapod.net/mercurial/mercurial-devel/-/jobs/252964/raw ) Stage: tests Name: test-py2-chg Job #252957 ( https://foss.heptapod.net/mercurial/mercurial-devel/-/jobs/252957/raw ) Stage: tests Name: test-py2 Job #252959 ( https://foss.heptapod.net/mercurial/mercurial-devel/-/jobs/252959/raw ) Stage: tests Name: test-py2-pure Job #252953 ( https://foss.heptapod.net/mercurial/mercurial-devel/-/jobs/252953/raw ) Stage: tests Name: checks-py2 -- You're receiving this email because of your account on foss.heptapod.net. ___ Mercurial-devel mailing list Mercurial-devel@mercurial-scm.org https://www.mercurial-scm.org/mailman/listinfo/mercurial-devel
D11651: rhg: do not fail when the repo is empty
aalekseyev created this revision. Herald added a reviewer: hg-reviewers. Herald added a subscriber: mercurial-patches. REPOSITORY rHG Mercurial BRANCH default REVISION DETAIL https://phab.mercurial-scm.org/D11651 AFFECTED FILES rust/hg-core/src/revlog/revlog.rs rust/hg-core/src/vfs.rs tests/test-empty-manifest-index.t CHANGE DETAILS diff --git a/tests/test-empty-manifest-index.t b/tests/test-empty-manifest-index.t --- a/tests/test-empty-manifest-index.t +++ b/tests/test-empty-manifest-index.t @@ -1,23 +1,27 @@ -Create a repo such that the changelog entry refers to a null manifest node: +Test null revisions (node , aka rev -1) +in various circumstances. + +Make an empty repo: $ hg init a $ cd a - $ hg log - $ touch x - $ hg add x - $ hg commit -m "init" - $ hg rm x - $ hg commit -q --amend - $ wc -c < .hg/store/00manifest.i - 0 - -Make sure that the manifest can be read (and is empty): - - $ hg --config rhg.on-unsupported=abort files -r . + $ hg files -r + [1] + $ hg files -r . [1] -Test a null changelog rev, too: +Add an empty commit (this makes the changelog refer to a null manifest node): + + + $ hg commit -m "init" --config ui.allowemptycommit=true - $ hg --config rhg.on-unsupported=abort files -r + $ hg files -r . [1] + +Strip that empty commit (this makes the changelog file empty, as opposed to missing): + + $ hg --config 'extensions.strip=' strip . > /dev/null + + $ hg files -r . + [1] diff --git a/rust/hg-core/src/vfs.rs b/rust/hg-core/src/vfs.rs --- a/rust/hg-core/src/vfs.rs +++ b/rust/hg-core/src/vfs.rs @@ -9,6 +9,8 @@ pub(crate) base: &'a Path, } +struct FileNotFound(std::io::Error, PathBuf); + impl Vfs<'_> { pub fn join(, relative_path: impl AsRef) -> PathBuf { self.base.join(relative_path) @@ -22,16 +24,41 @@ std::fs::read().when_reading_file() } +fn mmap_open_gen( +, +relative_path: impl AsRef, +) -> Result, HgError> { +let path = self.join(relative_path); +let file = match std::fs::File::open() { +Err(err) => { +if let ErrorKind::NotFound = err.kind() { +return Ok(Err(FileNotFound(err, path))); +}; +return (Err(err)).when_reading_file(); +} +Ok(file) => file, +}; +// TODO: what are the safety requirements here? +let mmap = unsafe { MmapOptions::new().map() } +.when_reading_file()?; +Ok(Ok(mmap)) +} + +pub fn mmap_open_opt( +, +relative_path: impl AsRef, +) -> Result, HgError> { +self.mmap_open_gen(relative_path).map(|res| res.ok()) +} + pub fn mmap_open( , relative_path: impl AsRef, ) -> Result { -let path = self.base.join(relative_path); -let file = std::fs::File::open().when_reading_file()?; -// TODO: what are the safety requirements here? -let mmap = unsafe { MmapOptions::new().map() } -.when_reading_file()?; -Ok(mmap) +match self.mmap_open_gen(relative_path)? { +Err(FileNotFound(err, path)) => Err(err).when_reading_file(), +Ok(res) => Ok(res), +} } pub fn rename( diff --git a/rust/hg-core/src/revlog/revlog.rs b/rust/hg-core/src/revlog/revlog.rs --- a/rust/hg-core/src/revlog/revlog.rs +++ b/rust/hg-core/src/revlog/revlog.rs @@ -70,15 +70,21 @@ data_path: Option<>, ) -> Result { let index_path = index_path.as_ref(); -let index_mmap = repo.store_vfs().mmap_open(_path)?; +let index = { +match repo.store_vfs().mmap_open_opt(_path)? { +None => Index::new(Box::new(vec![])), +Some(index_mmap) => { +let version = get_version(_mmap)?; +if version != 1 { +// A proper new version should have had a repo/store requirement. +return Err(HgError::corrupted("corrupted revlog")); +} -let version = get_version(_mmap)?; -if version != 1 { -// A proper new version should have had a repo/store requirement. -return Err(HgError::corrupted("corrupted revlog")); -} - -let index = Index::new(Box::new(index_mmap))?; +let index = Index::new(Box::new(index_mmap))?; +Ok(index) +} +} +}?; let default_data_path = index_path.with_extension("d"); To: aalekseyev, #hg-reviewers Cc: mercurial-patches, mercurial-devel ___ Mercurial-devel mailing list Mercurial-devel@mercurial-scm.org https://www.mercurial-scm.org/mailman/listinfo/mercurial-devel
mercurial-devel | Failed pipeline for branch/default | c2e9d0eb
Pipeline #27692 has failed! Project: mercurial-devel ( https://foss.heptapod.net/mercurial/mercurial-devel ) Branch: branch/default ( https://foss.heptapod.net/mercurial/mercurial-devel/-/commits/branch/default ) Commit: c2e9d0eb ( https://foss.heptapod.net/mercurial/mercurial-devel/-/commit/c2e9d0eb8db8e736216484880164389ce053e092 ) Commit Message: rust: update the rust-cpython crate to 0.7.0 T... Commit Author: Simon Sapin ( https://foss.heptapod.net/SimonSapin ) Pipeline #27692 ( https://foss.heptapod.net/mercurial/mercurial-devel/-/pipelines/27692 ) triggered by Administrator ( https://foss.heptapod.net/root ) had 5 failed jobs. Job #252981 ( https://foss.heptapod.net/mercurial/mercurial-devel/-/jobs/252981/raw ) Stage: tests Name: test-py2-chg Job #252974 ( https://foss.heptapod.net/mercurial/mercurial-devel/-/jobs/252974/raw ) Stage: tests Name: test-py2 Job #252976 ( https://foss.heptapod.net/mercurial/mercurial-devel/-/jobs/252976/raw ) Stage: tests Name: test-py2-pure Job #252978 ( https://foss.heptapod.net/mercurial/mercurial-devel/-/jobs/252978/raw ) Stage: tests Name: test-py2-rust Job #252970 ( https://foss.heptapod.net/mercurial/mercurial-devel/-/jobs/252970/raw ) Stage: tests Name: checks-py2 -- You're receiving this email because of your account on foss.heptapod.net. ___ Mercurial-devel mailing list Mercurial-devel@mercurial-scm.org https://www.mercurial-scm.org/mailman/listinfo/mercurial-devel
mercurial-devel | Failed pipeline for branch/default | 506123a0
Pipeline #27690 has failed! Project: mercurial-devel ( https://foss.heptapod.net/mercurial/mercurial-devel ) Branch: branch/default ( https://foss.heptapod.net/mercurial/mercurial-devel/-/commits/branch/default ) Commit: 506123a0 ( https://foss.heptapod.net/mercurial/mercurial-devel/-/commit/506123a0cd7e969a9f39413369e82582a560d66a ) Commit Message: dirstate-v2: Replace the 32-bit `mode` field wi... Commit Author: Simon Sapin ( https://foss.heptapod.net/SimonSapin ) Pipeline #27690 ( https://foss.heptapod.net/mercurial/mercurial-devel/-/pipelines/27690 ) triggered by Administrator ( https://foss.heptapod.net/root ) had 5 failed jobs. Job #252947 ( https://foss.heptapod.net/mercurial/mercurial-devel/-/jobs/252947/raw ) Stage: tests Name: test-py2-chg Job #252944 ( https://foss.heptapod.net/mercurial/mercurial-devel/-/jobs/252944/raw ) Stage: tests Name: test-py2-rust Job #252940 ( https://foss.heptapod.net/mercurial/mercurial-devel/-/jobs/252940/raw ) Stage: tests Name: test-py2 Job #252942 ( https://foss.heptapod.net/mercurial/mercurial-devel/-/jobs/252942/raw ) Stage: tests Name: test-py2-pure Job #252936 ( https://foss.heptapod.net/mercurial/mercurial-devel/-/jobs/252936/raw ) Stage: tests Name: checks-py2 -- You're receiving this email because of your account on foss.heptapod.net. ___ Mercurial-devel mailing list Mercurial-devel@mercurial-scm.org https://www.mercurial-scm.org/mailman/listinfo/mercurial-devel
D11650: rhg: handle null changelog and manifest revisions
aalekseyev created this revision. Herald added a reviewer: hg-reviewers. Herald added a subscriber: mercurial-patches. REPOSITORY rHG Mercurial BRANCH default REVISION DETAIL https://phab.mercurial-scm.org/D11650 AFFECTED FILES rust/hg-core/src/revlog/changelog.rs rust/hg-core/src/revlog/index.rs rust/hg-core/src/revlog/revlog.rs tests/test-empty-manifest-index.t CHANGE DETAILS diff --git a/tests/test-empty-manifest-index.t b/tests/test-empty-manifest-index.t new file mode 100644 --- /dev/null +++ b/tests/test-empty-manifest-index.t @@ -0,0 +1,23 @@ +Create a repo such that the changelog entry refers to a null manifest node: + + $ hg init a + $ cd a + $ hg log + $ touch x + $ hg add x + $ hg commit -m "init" + $ hg rm x + $ hg commit -q --amend + + $ wc -c < .hg/store/00manifest.i + 0 + +Make sure that the manifest can be read (and is empty): + + $ hg --config rhg.on-unsupported=abort files -r . + [1] + +Test a null changelog rev, too: + + $ hg --config rhg.on-unsupported=abort files -r + [1] diff --git a/rust/hg-core/src/revlog/revlog.rs b/rust/hg-core/src/revlog/revlog.rs --- a/rust/hg-core/src/revlog/revlog.rs +++ b/rust/hg-core/src/revlog/revlog.rs @@ -72,7 +72,7 @@ let index_path = index_path.as_ref(); let index_mmap = repo.store_vfs().mmap_open(_path)?; -let version = get_version(_mmap); +let version = get_version(_mmap)?; if version != 1 { // A proper new version should have had a repo/store requirement. return Err(HgError::corrupted("corrupted revlog")); @@ -179,6 +179,9 @@ /// snapshot to rebuild the final data. #[timed] pub fn get_rev_data(, rev: Revision) -> Result, RevlogError> { +if rev == NULL_REVISION { +return Ok(vec![]); +}; // Todo return -> Cow let mut entry = self.get_entry(rev)?; let mut delta_chain = vec![]; @@ -371,8 +374,16 @@ } /// Format version of the revlog. -pub fn get_version(index_bytes: &[u8]) -> u16 { -BigEndian::read_u16(_bytes[2..=3]) +pub fn get_version(index_bytes: &[u8]) -> Result { +if index_bytes.len() == 0 { +return Ok(1); +}; +if index_bytes.len() < 4 { +return Err(HgError::corrupted( +"corrupted revlog: can't read the index format header", +)); +}; +Ok(BigEndian::read_u16(_bytes[2..=3])) } /// Calculate the hash of a revision given its data and its parents. diff --git a/rust/hg-core/src/revlog/index.rs b/rust/hg-core/src/revlog/index.rs --- a/rust/hg-core/src/revlog/index.rs +++ b/rust/hg-core/src/revlog/index.rs @@ -208,6 +208,9 @@ /// Value of the inline flag. pub fn is_inline(index_bytes: &[u8]) -> bool { +if index_bytes.len() < 4 { +return true; +} match _bytes[0..=1] { [0, 0] | [0, 2] => false, _ => true, diff --git a/rust/hg-core/src/revlog/changelog.rs b/rust/hg-core/src/revlog/changelog.rs --- a/rust/hg-core/src/revlog/changelog.rs +++ b/rust/hg-core/src/revlog/changelog.rs @@ -1,5 +1,6 @@ use crate::errors::HgError; use crate::repo::Repo; +use crate::revlog::node::NULL_NODE; use crate::revlog::revlog::{Revlog, RevlogError}; use crate::revlog::Revision; use crate::revlog::{Node, NodePrefix}; @@ -58,10 +59,9 @@ /// Return the node id of the `manifest` referenced by this `changelog` /// entry. pub fn manifest_node() -> Result { -Node::from_hex_for_repo( -self.lines() -.next() -.ok_or_else(|| HgError::corrupted("empty changelog entry"))?, -) +match self.lines().next() { +None => Ok(NULL_NODE), +Some(x) => Node::from_hex_for_repo(x), +} } } To: aalekseyev, #hg-reviewers Cc: mercurial-patches, mercurial-devel ___ Mercurial-devel mailing list Mercurial-devel@mercurial-scm.org https://www.mercurial-scm.org/mailman/listinfo/mercurial-devel
D11649: chistedit: move changeview() onto state class
martinvonz created this revision. Herald added a reviewer: durin42. Herald added a reviewer: hg-reviewers. Herald added a subscriber: mercurial-patches. REPOSITORY rHG Mercurial BRANCH default REVISION DETAIL https://phab.mercurial-scm.org/D11649 AFFECTED FILES hgext/histedit.py CHANGE DETAILS diff --git a/hgext/histedit.py b/hgext/histedit.py --- a/hgext/histedit.py +++ b/hgext/histedit.py @@ -1193,23 +1193,6 @@ return self.conflicts -# EVENTS === -def changeview(state, delta, unit): -"""Change the region of whatever is being viewed (a patch or the list of -changesets). 'delta' is an amount (+/- 1) and 'unit' is 'page' or 'line'.""" -mode, _ = state.mode -if mode != MODE_PATCH: -return -mode_state = state.modes[mode] -num_lines = len(mode_state[b'patchcontents']) -page_height = state.page_height -unit = page_height if unit == b'page' else 1 -num_pages = 1 + (num_lines - 1) // page_height -max_offset = (num_pages - 1) * page_height -newline = mode_state[b'line_offset'] + delta * unit -mode_state[b'line_offset'] = max(0, min(max_offset, newline)) - - def makecommands(rules): """Returns a list of commands consumable by histedit --commands based on our list of rules""" @@ -1586,6 +1569,21 @@ index -= 1 self.change_action(pos, KEY_LIST[index % len(KEY_LIST)]) +def change_view(self, delta, unit): +"""Change the region of whatever is being viewed (a patch or the list of +changesets). 'delta' is an amount (+/- 1) and 'unit' is 'page' or 'line'.""" +mode, _ = self.mode +if mode != MODE_PATCH: +return +mode_state = self.modes[mode] +num_lines = len(mode_state[b'patchcontents']) +page_height = self.page_height +unit = page_height if unit == b'page' else 1 +num_pages = 1 + (num_lines - 1) // page_height +max_offset = (num_pages - 1) * page_height +newline = mode_state[b'line_offset'] + delta * unit +mode_state[b'line_offset'] = max(0, min(max_offset, newline)) + def _chisteditmain(repo, rules, stdscr): try: @@ -1657,13 +1655,13 @@ if e in (E_PAGEDOWN, E_PAGEUP, E_LINEDOWN, E_LINEUP): if e == E_PAGEDOWN: -changeview(state, +1, b'page') +state.change_view(+1, b'page') elif e == E_PAGEUP: -changeview(state, -1, b'page') +state.change_view(-1, b'page') elif e == E_LINEDOWN: -changeview(state, +1, b'line') +state.change_view(+1, b'line') elif e == E_LINEUP: -changeview(state, -1, b'line') +state.change_view(-1, b'line') # start rendering commitwin.erase() To: martinvonz, durin42, #hg-reviewers Cc: mercurial-patches, mercurial-devel ___ Mercurial-devel mailing list Mercurial-devel@mercurial-scm.org https://www.mercurial-scm.org/mailman/listinfo/mercurial-devel
D11648: chistedit: move cycleaction() onto state class
martinvonz created this revision. Herald added a reviewer: durin42. Herald added a reviewer: hg-reviewers. Herald added a subscriber: mercurial-patches. REPOSITORY rHG Mercurial BRANCH default REVISION DETAIL https://phab.mercurial-scm.org/D11648 AFFECTED FILES hgext/histedit.py CHANGE DETAILS diff --git a/hgext/histedit.py b/hgext/histedit.py --- a/hgext/histedit.py +++ b/hgext/histedit.py @@ -1194,23 +1194,6 @@ # EVENTS === -def cycleaction(state, pos, next=False): -"""Changes the action state the next or the previous action from -the action list""" -rules = state.rules -assert 0 <= pos < len(rules) -current = rules[pos].action - -assert current in KEY_LIST - -index = KEY_LIST.index(current) -if next: -index += 1 -else: -index -= 1 -state.change_action(pos, KEY_LIST[index % len(KEY_LIST)]) - - def changeview(state, delta, unit): """Change the region of whatever is being viewed (a patch or the list of changesets). 'delta' is an amount (+/- 1) and 'unit' is 'page' or 'line'.""" @@ -1486,9 +1469,9 @@ if selected is not None or action == b'move-up': self.swap(oldpos, newpos) elif action == b'next-action': -cycleaction(self, oldpos, next=True) +self.cycle_action(oldpos, next=True) elif action == b'prev-action': -cycleaction(self, oldpos, next=False) +self.cycle_action(oldpos, next=False) elif action == b'select': selected = oldpos if selected is None else None self.make_selection(selected) @@ -1587,6 +1570,22 @@ assert 0 <= pos < len(rules) rules[pos].action = action +def cycle_action(self, pos, next=False): +"""Changes the action state the next or the previous action from +the action list""" +rules = self.rules +assert 0 <= pos < len(rules) +current = rules[pos].action + +assert current in KEY_LIST + +index = KEY_LIST.index(current) +if next: +index += 1 +else: +index -= 1 +self.change_action(pos, KEY_LIST[index % len(KEY_LIST)]) + def _chisteditmain(repo, rules, stdscr): try: To: martinvonz, durin42, #hg-reviewers Cc: mercurial-patches, mercurial-devel ___ Mercurial-devel mailing list Mercurial-devel@mercurial-scm.org https://www.mercurial-scm.org/mailman/listinfo/mercurial-devel
D11647: chistedit: move changeaction() onto state class
martinvonz created this revision. Herald added a reviewer: durin42. Herald added a reviewer: hg-reviewers. Herald added a subscriber: mercurial-patches. REPOSITORY rHG Mercurial BRANCH default REVISION DETAIL https://phab.mercurial-scm.org/D11647 AFFECTED FILES hgext/histedit.py CHANGE DETAILS diff --git a/hgext/histedit.py b/hgext/histedit.py --- a/hgext/histedit.py +++ b/hgext/histedit.py @@ -1194,13 +1194,6 @@ # EVENTS === -def changeaction(state, pos, action): -"""Change the action state on the given position to the new action""" -rules = state.rules -assert 0 <= pos < len(rules) -rules[pos].action = action - - def cycleaction(state, pos, next=False): """Changes the action state the next or the previous action from the action list""" @@ -1215,7 +1208,7 @@ index += 1 else: index -= 1 -changeaction(state, pos, KEY_LIST[index % len(KEY_LIST)]) +state.change_action(pos, KEY_LIST[index % len(KEY_LIST)]) def changeview(state, delta, unit): @@ -1505,7 +1498,7 @@ if selected is not None: self.swap(oldpos, newrule.pos) elif action.startswith(b'action-'): -changeaction(self, oldpos, action[7:]) +self.change_action(oldpos, action[7:]) elif action == b'showpatch': self.change_mode(MODE_PATCH if curmode != MODE_PATCH else prevmode) elif action == b'help': @@ -1588,6 +1581,12 @@ if self.selected: self.make_selection(newpos) +def change_action(self, pos, action): +"""Change the action state on the given position to the new action""" +rules = self.rules +assert 0 <= pos < len(rules) +rules[pos].action = action + def _chisteditmain(repo, rules, stdscr): try: To: martinvonz, durin42, #hg-reviewers Cc: mercurial-patches, mercurial-devel ___ Mercurial-devel mailing list Mercurial-devel@mercurial-scm.org https://www.mercurial-scm.org/mailman/listinfo/mercurial-devel
D11646: chistedit: move swap() onto state class
martinvonz created this revision. Herald added a reviewer: durin42. Herald added a reviewer: hg-reviewers. Herald added a subscriber: mercurial-patches. REPOSITORY rHG Mercurial BRANCH default REVISION DETAIL https://phab.mercurial-scm.org/D11646 AFFECTED FILES hgext/histedit.py CHANGE DETAILS diff --git a/hgext/histedit.py b/hgext/histedit.py --- a/hgext/histedit.py +++ b/hgext/histedit.py @@ -1194,29 +1194,6 @@ # EVENTS === -def swap(state, oldpos, newpos): -"""Swap two positions and calculate necessary conflicts in -O(|newpos-oldpos|) time""" - -rules = state.rules -assert 0 <= oldpos < len(rules) and 0 <= newpos < len(rules) - -rules[oldpos], rules[newpos] = rules[newpos], rules[oldpos] - -# TODO: swap should not know about histeditrule's internals -rules[newpos].pos = newpos -rules[oldpos].pos = oldpos - -start = min(oldpos, newpos) -end = max(oldpos, newpos) -for r in pycompat.xrange(start, end + 1): -rules[newpos].checkconflicts(rules[r]) -rules[oldpos].checkconflicts(rules[r]) - -if state.selected: -state.make_selection(newpos) - - def changeaction(state, pos, action): """Change the action state on the given position to the new action""" rules = state.rules @@ -1509,12 +1486,12 @@ newpos = min(oldpos + 1, len(rules) - 1) self.move_cursor(oldpos, newpos) if selected is not None or action == b'move-down': -swap(self, oldpos, newpos) +self.swap(oldpos, newpos) elif action in (b'up', b'move-up'): newpos = max(0, oldpos - 1) self.move_cursor(oldpos, newpos) if selected is not None or action == b'move-up': -swap(self, oldpos, newpos) +self.swap(oldpos, newpos) elif action == b'next-action': cycleaction(self, oldpos, next=True) elif action == b'prev-action': @@ -1526,7 +1503,7 @@ newrule = next((r for r in rules if r.origpos == int(ch))) self.move_cursor(oldpos, newrule.pos) if selected is not None: -swap(self, oldpos, newrule.pos) +self.swap(oldpos, newrule.pos) elif action.startswith(b'action-'): changeaction(self, oldpos, action[7:]) elif action == b'showpatch': @@ -1589,6 +1566,28 @@ def make_selection(self, pos): self.selected = pos +def swap(self, oldpos, newpos): +"""Swap two positions and calculate necessary conflicts in +O(|newpos-oldpos|) time""" + +rules = self.rules +assert 0 <= oldpos < len(rules) and 0 <= newpos < len(rules) + +rules[oldpos], rules[newpos] = rules[newpos], rules[oldpos] + +# TODO: swap should not know about histeditrule's internals +rules[newpos].pos = newpos +rules[oldpos].pos = oldpos + +start = min(oldpos, newpos) +end = max(oldpos, newpos) +for r in pycompat.xrange(start, end + 1): +rules[newpos].checkconflicts(rules[r]) +rules[oldpos].checkconflicts(rules[r]) + +if self.selected: +self.make_selection(newpos) + def _chisteditmain(repo, rules, stdscr): try: To: martinvonz, durin42, #hg-reviewers Cc: mercurial-patches, mercurial-devel ___ Mercurial-devel mailing list Mercurial-devel@mercurial-scm.org https://www.mercurial-scm.org/mailman/listinfo/mercurial-devel
D11645: chistedit: move makeselection() onto state class
martinvonz created this revision. Herald added a reviewer: durin42. Herald added a reviewer: hg-reviewers. Herald added a subscriber: mercurial-patches. REPOSITORY rHG Mercurial BRANCH default REVISION DETAIL https://phab.mercurial-scm.org/D11645 AFFECTED FILES hgext/histedit.py CHANGE DETAILS diff --git a/hgext/histedit.py b/hgext/histedit.py --- a/hgext/histedit.py +++ b/hgext/histedit.py @@ -1194,10 +1194,6 @@ # EVENTS === -def makeselection(state, pos): -state.selected = pos - - def swap(state, oldpos, newpos): """Swap two positions and calculate necessary conflicts in O(|newpos-oldpos|) time""" @@ -1218,7 +1214,7 @@ rules[oldpos].checkconflicts(rules[r]) if state.selected: -makeselection(state, newpos) +state.make_selection(newpos) def changeaction(state, pos, action): @@ -1525,7 +1521,7 @@ cycleaction(self, oldpos, next=False) elif action == b'select': selected = oldpos if selected is None else None -makeselection(self, selected) +self.make_selection(selected) elif action == b'goto' and int(ch) < len(rules) and len(rules) <= 10: newrule = next((r for r in rules if r.origpos == int(ch))) self.move_cursor(oldpos, newrule.pos) @@ -1590,6 +1586,9 @@ if mode == MODE_PATCH: self.modes[MODE_PATCH][b'patchcontents'] = self.patch_contents() +def make_selection(self, pos): +self.selected = pos + def _chisteditmain(repo, rules, stdscr): try: To: martinvonz, durin42, #hg-reviewers Cc: mercurial-patches, mercurial-devel ___ Mercurial-devel mailing list Mercurial-devel@mercurial-scm.org https://www.mercurial-scm.org/mailman/listinfo/mercurial-devel
D11644: chistedit: move changemode() onto state class
martinvonz created this revision. Herald added a reviewer: durin42. Herald added a reviewer: hg-reviewers. Herald added a subscriber: mercurial-patches. REPOSITORY rHG Mercurial BRANCH default REVISION DETAIL https://phab.mercurial-scm.org/D11644 AFFECTED FILES hgext/histedit.py CHANGE DETAILS diff --git a/hgext/histedit.py b/hgext/histedit.py --- a/hgext/histedit.py +++ b/hgext/histedit.py @@ -1194,13 +1194,6 @@ # EVENTS === -def changemode(state, mode): -curmode, _ = state.mode -state.mode = (mode, curmode) -if mode == MODE_PATCH: -state.modes[MODE_PATCH][b'patchcontents'] = state.patch_contents() - - def makeselection(state, pos): state.selected = pos @@ -1541,9 +1534,9 @@ elif action.startswith(b'action-'): changeaction(self, oldpos, action[7:]) elif action == b'showpatch': -changemode(self, MODE_PATCH if curmode != MODE_PATCH else prevmode) +self.change_mode(MODE_PATCH if curmode != MODE_PATCH else prevmode) elif action == b'help': -changemode(self, MODE_HELP if curmode != MODE_HELP else prevmode) +self.change_mode(MODE_HELP if curmode != MODE_HELP else prevmode) elif action == b'quit': return E_QUIT elif action == b'histedit': @@ -1591,6 +1584,12 @@ # Reset the patch view region to the top of the new patch. self.modes[MODE_PATCH][b'line_offset'] = 0 +def change_mode(self, mode): +curmode, _ = self.mode +self.mode = (mode, curmode) +if mode == MODE_PATCH: +self.modes[MODE_PATCH][b'patchcontents'] = self.patch_contents() + def _chisteditmain(repo, rules, stdscr): try: @@ -1633,7 +1632,7 @@ while True: oldmode, unused = state.mode if oldmode == MODE_INIT: -changemode(state, MODE_RULES) +state.change_mode(MODE_RULES) e = state.event(ch) if e == E_QUIT: To: martinvonz, durin42, #hg-reviewers Cc: mercurial-patches, mercurial-devel ___ Mercurial-devel mailing list Mercurial-devel@mercurial-scm.org https://www.mercurial-scm.org/mailman/listinfo/mercurial-devel
D11643: chistedit: move movecursor() onto state class
martinvonz created this revision. Herald added a reviewer: durin42. Herald added a reviewer: hg-reviewers. Herald added a subscriber: mercurial-patches. REPOSITORY rHG Mercurial BRANCH default REVISION DETAIL https://phab.mercurial-scm.org/D11643 AFFECTED FILES hgext/histedit.py CHANGE DETAILS diff --git a/hgext/histedit.py b/hgext/histedit.py --- a/hgext/histedit.py +++ b/hgext/histedit.py @@ -1194,26 +1194,6 @@ # EVENTS === -def movecursor(state, oldpos, newpos): -"""Change the rule/changeset that the cursor is pointing to, regardless of -current mode (you can switch between patches from the view patch window).""" -state.pos = newpos - -mode, _ = state.mode -if mode == MODE_RULES: -# Scroll through the list by updating the view for MODE_RULES, so that -# even if we are not currently viewing the rules, switching back will -# result in the cursor's rule being visible. -modestate = state.modes[MODE_RULES] -if newpos < modestate[b'line_offset']: -modestate[b'line_offset'] = newpos -elif newpos > modestate[b'line_offset'] + state.page_height - 1: -modestate[b'line_offset'] = newpos - state.page_height + 1 - -# Reset the patch view region to the top of the new patch. -state.modes[MODE_PATCH][b'line_offset'] = 0 - - def changemode(state, mode): curmode, _ = state.mode state.mode = (mode, curmode) @@ -1538,12 +1518,12 @@ return if action in (b'down', b'move-down'): newpos = min(oldpos + 1, len(rules) - 1) -movecursor(self, oldpos, newpos) +self.move_cursor(oldpos, newpos) if selected is not None or action == b'move-down': swap(self, oldpos, newpos) elif action in (b'up', b'move-up'): newpos = max(0, oldpos - 1) -movecursor(self, oldpos, newpos) +self.move_cursor(oldpos, newpos) if selected is not None or action == b'move-up': swap(self, oldpos, newpos) elif action == b'next-action': @@ -1555,7 +1535,7 @@ makeselection(self, selected) elif action == b'goto' and int(ch) < len(rules) and len(rules) <= 10: newrule = next((r for r in rules if r.origpos == int(ch))) -movecursor(self, oldpos, newrule.pos) +self.move_cursor(oldpos, newrule.pos) if selected is not None: swap(self, oldpos, newrule.pos) elif action.startswith(b'action-'): @@ -1592,6 +1572,25 @@ displayer.close() return displayer.hunk[rule.ctx.rev()].splitlines() +def move_cursor(self, oldpos, newpos): +"""Change the rule/changeset that the cursor is pointing to, regardless of +current mode (you can switch between patches from the view patch window).""" +self.pos = newpos + +mode, _ = self.mode +if mode == MODE_RULES: +# Scroll through the list by updating the view for MODE_RULES, so that +# even if we are not currently viewing the rules, switching back will +# result in the cursor's rule being visible. +modestate = self.modes[MODE_RULES] +if newpos < modestate[b'line_offset']: +modestate[b'line_offset'] = newpos +elif newpos > modestate[b'line_offset'] + self.page_height - 1: +modestate[b'line_offset'] = newpos - self.page_height + 1 + +# Reset the patch view region to the top of the new patch. +self.modes[MODE_PATCH][b'line_offset'] = 0 + def _chisteditmain(repo, rules, stdscr): try: @@ -1652,7 +1651,7 @@ if curmode != oldmode: state.page_height = sizes[b'main'][0] # Adjust the view to fit the current screen size. -movecursor(state, state.pos, state.pos) +state.move_cursor(state.pos, state.pos) # Pack the windows against the top, each pane spread across the # full width of the screen. To: martinvonz, durin42, #hg-reviewers Cc: mercurial-patches, mercurial-devel ___ Mercurial-devel mailing list Mercurial-devel@mercurial-scm.org https://www.mercurial-scm.org/mailman/listinfo/mercurial-devel
D11642: chistedit: move patchcontents() onto state class
martinvonz created this revision. Herald added a reviewer: durin42. Herald added a reviewer: hg-reviewers. Herald added a subscriber: mercurial-patches. REPOSITORY rHG Mercurial BRANCH default REVISION DETAIL https://phab.mercurial-scm.org/D11642 AFFECTED FILES hgext/histedit.py CHANGE DETAILS diff --git a/hgext/histedit.py b/hgext/histedit.py --- a/hgext/histedit.py +++ b/hgext/histedit.py @@ -1218,7 +1218,7 @@ curmode, _ = state.mode state.mode = (mode, curmode) if mode == MODE_PATCH: -state.modes[MODE_PATCH][b'patchcontents'] = patchcontents(state) +state.modes[MODE_PATCH][b'patchcontents'] = state.patch_contents() def makeselection(state, pos): @@ -1325,19 +1325,6 @@ return line[: n - 2] + b' >' -def patchcontents(state): -repo = state.repo -rule = state.rules[state.pos] -displayer = logcmdutil.changesetdisplayer( -repo.ui, repo, {b"patch": True, b"template": b"status"}, buffered=True -) -overrides = {(b'ui', b'verbose'): True} -with repo.ui.configoverride(overrides, source=b'histedit'): -displayer.show(rule.ctx) -displayer.close() -return displayer.hunk[rule.ctx.rev()].splitlines() - - class _chistedit_state(object): def __init__( self, @@ -1590,6 +1577,21 @@ elif action == b'line-up': return E_LINEUP +def patch_contents(self): +repo = self.repo +rule = self.rules[self.pos] +displayer = logcmdutil.changesetdisplayer( +repo.ui, +repo, +{b"patch": True, b"template": b"status"}, +buffered=True, +) +overrides = {(b'ui', b'verbose'): True} +with repo.ui.configoverride(overrides, source=b'histedit'): +displayer.show(rule.ctx) +displayer.close() +return displayer.hunk[rule.ctx.rev()].splitlines() + def _chisteditmain(repo, rules, stdscr): try: To: martinvonz, durin42, #hg-reviewers Cc: mercurial-patches, mercurial-devel ___ Mercurial-devel mailing list Mercurial-devel@mercurial-scm.org https://www.mercurial-scm.org/mailman/listinfo/mercurial-devel
D11641: chistedit: move event() onto state class
martinvonz created this revision. Herald added a reviewer: durin42. Herald added a reviewer: hg-reviewers. Herald added a subscriber: mercurial-patches. REPOSITORY rHG Mercurial BRANCH default REVISION DETAIL https://phab.mercurial-scm.org/D11641 AFFECTED FILES hgext/histedit.py CHANGE DETAILS diff --git a/hgext/histedit.py b/hgext/histedit.py --- a/hgext/histedit.py +++ b/hgext/histedit.py @@ -1288,71 +1288,6 @@ mode_state[b'line_offset'] = max(0, min(max_offset, newline)) -def event(state, ch): -"""Change state based on the current character input - -This takes the current state and based on the current character input from -the user we change the state. -""" -selected = state.selected -oldpos = state.pos -rules = state.rules - -if ch in (curses.KEY_RESIZE, b"KEY_RESIZE"): -return E_RESIZE - -lookup_ch = ch -if ch is not None and b'0' <= ch <= b'9': -lookup_ch = b'0' - -curmode, prevmode = state.mode -action = KEYTABLE[curmode].get( -lookup_ch, KEYTABLE[b'global'].get(lookup_ch) -) -if action is None: -return -if action in (b'down', b'move-down'): -newpos = min(oldpos + 1, len(rules) - 1) -movecursor(state, oldpos, newpos) -if selected is not None or action == b'move-down': -swap(state, oldpos, newpos) -elif action in (b'up', b'move-up'): -newpos = max(0, oldpos - 1) -movecursor(state, oldpos, newpos) -if selected is not None or action == b'move-up': -swap(state, oldpos, newpos) -elif action == b'next-action': -cycleaction(state, oldpos, next=True) -elif action == b'prev-action': -cycleaction(state, oldpos, next=False) -elif action == b'select': -selected = oldpos if selected is None else None -makeselection(state, selected) -elif action == b'goto' and int(ch) < len(rules) and len(rules) <= 10: -newrule = next((r for r in rules if r.origpos == int(ch))) -movecursor(state, oldpos, newrule.pos) -if selected is not None: -swap(state, oldpos, newrule.pos) -elif action.startswith(b'action-'): -changeaction(state, oldpos, action[7:]) -elif action == b'showpatch': -changemode(state, MODE_PATCH if curmode != MODE_PATCH else prevmode) -elif action == b'help': -changemode(state, MODE_HELP if curmode != MODE_HELP else prevmode) -elif action == b'quit': -return E_QUIT -elif action == b'histedit': -return E_HISTEDIT -elif action == b'page-down': -return E_PAGEDOWN -elif action == b'page-up': -return E_PAGEUP -elif action == b'line-down': -return E_LINEDOWN -elif action == b'line-up': -return E_LINEUP - - def makecommands(rules): """Returns a list of commands consumable by histedit --commands based on our list of rules""" @@ -1591,6 +1526,70 @@ content = self.modes[MODE_PATCH][b'patchcontents'] self.render_string(win, content[start:], diffcolors=True) +def event(self, ch): +"""Change state based on the current character input + +This takes the current state and based on the current character input from +the user we change the state. +""" +selected = self.selected +oldpos = self.pos +rules = self.rules + +if ch in (curses.KEY_RESIZE, b"KEY_RESIZE"): +return E_RESIZE + +lookup_ch = ch +if ch is not None and b'0' <= ch <= b'9': +lookup_ch = b'0' + +curmode, prevmode = self.mode +action = KEYTABLE[curmode].get( +lookup_ch, KEYTABLE[b'global'].get(lookup_ch) +) +if action is None: +return +if action in (b'down', b'move-down'): +newpos = min(oldpos + 1, len(rules) - 1) +movecursor(self, oldpos, newpos) +if selected is not None or action == b'move-down': +swap(self, oldpos, newpos) +elif action in (b'up', b'move-up'): +newpos = max(0, oldpos - 1) +movecursor(self, oldpos, newpos) +if selected is not None or action == b'move-up': +swap(self, oldpos, newpos) +elif action == b'next-action': +cycleaction(self, oldpos, next=True) +elif action == b'prev-action': +cycleaction(self, oldpos, next=False) +elif action == b'select': +selected = oldpos if selected is None else None +makeselection(self, selected) +elif action == b'goto' and int(ch) < len(rules) and len(rules) <= 10: +newrule = next((r for r in rules if r.origpos == int(ch))) +movecursor(self, oldpos, newrule.pos) +if selected is not None: +swap(self, oldpos, newrule.pos) +elif action.startswith(b'action-'): +changeaction(self, oldpos,
D11640: chistedit: move renderpatch() and dependencies onto state class
martinvonz created this revision. Herald added a reviewer: durin42. Herald added a reviewer: hg-reviewers. Herald added a subscriber: mercurial-patches. REPOSITORY rHG Mercurial BRANCH default REVISION DETAIL https://phab.mercurial-scm.org/D11640 AFFECTED FILES hgext/histedit.py CHANGE DETAILS diff --git a/hgext/histedit.py b/hgext/histedit.py --- a/hgext/histedit.py +++ b/hgext/histedit.py @@ -1564,6 +1564,33 @@ rulesscr.noutrefresh() +def render_string(self, win, output, diffcolors=False): +maxy, maxx = win.getmaxyx() +length = min(maxy - 1, len(output)) +for y in range(0, length): +line = output[y] +if diffcolors: +if line and line[0] == b'+': +win.addstr( +y, 0, line, curses.color_pair(COLOR_DIFF_ADD_LINE) +) +elif line and line[0] == b'-': +win.addstr( +y, 0, line, curses.color_pair(COLOR_DIFF_DEL_LINE) +) +elif line.startswith(b'@@ '): +win.addstr(y, 0, line, curses.color_pair(COLOR_DIFF_OFFSET)) +else: +win.addstr(y, 0, line) +else: +win.addstr(y, 0, line) +win.noutrefresh() + +def render_patch(self, win): +start = self.modes[MODE_PATCH][b'line_offset'] +content = self.modes[MODE_PATCH][b'patchcontents'] +self.render_string(win, content[start:], diffcolors=True) + def _chisteditmain(repo, rules, stdscr): try: @@ -1592,33 +1619,6 @@ except curses.error: pass -def renderstring(win, state, output, diffcolors=False): -maxy, maxx = win.getmaxyx() -length = min(maxy - 1, len(output)) -for y in range(0, length): -line = output[y] -if diffcolors: -if line and line[0] == b'+': -win.addstr( -y, 0, line, curses.color_pair(COLOR_DIFF_ADD_LINE) -) -elif line and line[0] == b'-': -win.addstr( -y, 0, line, curses.color_pair(COLOR_DIFF_DEL_LINE) -) -elif line.startswith(b'@@ '): -win.addstr(y, 0, line, curses.color_pair(COLOR_DIFF_OFFSET)) -else: -win.addstr(y, 0, line) -else: -win.addstr(y, 0, line) -win.noutrefresh() - -def renderpatch(win, state): -start = state.modes[MODE_PATCH][b'line_offset'] -content = state.modes[MODE_PATCH][b'patchcontents'] -renderstring(win, state, content[start:], diffcolors=True) - def drawvertwin(size, y, x): win = curses.newwin(size[0], size[1], y, x) y += size[0] @@ -1675,9 +1675,9 @@ helpwin.erase() mainwin.erase() if curmode == MODE_PATCH: -renderpatch(mainwin, state) +state.render_patch(mainwin) elif curmode == MODE_HELP: -renderstring(mainwin, state, __doc__.strip().splitlines()) +state.render_string(mainwin, __doc__.strip().splitlines()) else: state.render_rules(mainwin) state.render_commit(commitwin) To: martinvonz, durin42, #hg-reviewers Cc: mercurial-patches, mercurial-devel ___ Mercurial-devel mailing list Mercurial-devel@mercurial-scm.org https://www.mercurial-scm.org/mailman/listinfo/mercurial-devel
D11639: chistedit: move renderrules() onto state class
martinvonz created this revision. Herald added a reviewer: durin42. Herald added a reviewer: hg-reviewers. Herald added a subscriber: mercurial-patches. REPOSITORY rHG Mercurial BRANCH default REVISION DETAIL https://phab.mercurial-scm.org/D11639 AFFECTED FILES hgext/histedit.py CHANGE DETAILS diff --git a/hgext/histedit.py b/hgext/histedit.py --- a/hgext/histedit.py +++ b/hgext/histedit.py @@ -1517,39 +1517,11 @@ b'main': (mainlen, maxx), } - -def _chisteditmain(repo, rules, stdscr): -try: -curses.use_default_colors() -except curses.error: -pass - -# initialize color pattern -curses.init_pair(COLOR_HELP, curses.COLOR_WHITE, curses.COLOR_BLUE) -curses.init_pair(COLOR_SELECTED, curses.COLOR_BLACK, curses.COLOR_WHITE) -curses.init_pair(COLOR_WARN, curses.COLOR_BLACK, curses.COLOR_YELLOW) -curses.init_pair(COLOR_OK, curses.COLOR_BLACK, curses.COLOR_GREEN) -curses.init_pair(COLOR_CURRENT, curses.COLOR_WHITE, curses.COLOR_MAGENTA) -curses.init_pair(COLOR_DIFF_ADD_LINE, curses.COLOR_GREEN, -1) -curses.init_pair(COLOR_DIFF_DEL_LINE, curses.COLOR_RED, -1) -curses.init_pair(COLOR_DIFF_OFFSET, curses.COLOR_MAGENTA, -1) -curses.init_pair(COLOR_ROLL, curses.COLOR_RED, -1) -curses.init_pair( -COLOR_ROLL_CURRENT, curses.COLOR_BLACK, curses.COLOR_MAGENTA -) -curses.init_pair(COLOR_ROLL_SELECTED, curses.COLOR_RED, curses.COLOR_WHITE) - -# don't display the cursor -try: -curses.curs_set(0) -except curses.error: -pass - -def renderrules(rulesscr, state): -rules = state.rules -pos = state.pos -selected = state.selected -start = state.modes[MODE_RULES][b'line_offset'] +def render_rules(self, rulesscr): +rules = self.rules +pos = self.pos +selected = self.selected +start = self.modes[MODE_RULES][b'line_offset'] conflicts = [r.ctx for r in rules if r.conflicts] if len(conflicts) > 0: @@ -1559,7 +1531,7 @@ addln(rulesscr, -1, 0, line, curses.color_pair(COLOR_WARN)) for y, rule in enumerate(rules[start:]): -if y >= state.page_height: +if y >= self.page_height: break if len(rule.conflicts) > 0: rulesscr.addstr(y, 0, b" ", curses.color_pair(COLOR_WARN)) @@ -1592,6 +1564,34 @@ rulesscr.noutrefresh() + +def _chisteditmain(repo, rules, stdscr): +try: +curses.use_default_colors() +except curses.error: +pass + +# initialize color pattern +curses.init_pair(COLOR_HELP, curses.COLOR_WHITE, curses.COLOR_BLUE) +curses.init_pair(COLOR_SELECTED, curses.COLOR_BLACK, curses.COLOR_WHITE) +curses.init_pair(COLOR_WARN, curses.COLOR_BLACK, curses.COLOR_YELLOW) +curses.init_pair(COLOR_OK, curses.COLOR_BLACK, curses.COLOR_GREEN) +curses.init_pair(COLOR_CURRENT, curses.COLOR_WHITE, curses.COLOR_MAGENTA) +curses.init_pair(COLOR_DIFF_ADD_LINE, curses.COLOR_GREEN, -1) +curses.init_pair(COLOR_DIFF_DEL_LINE, curses.COLOR_RED, -1) +curses.init_pair(COLOR_DIFF_OFFSET, curses.COLOR_MAGENTA, -1) +curses.init_pair(COLOR_ROLL, curses.COLOR_RED, -1) +curses.init_pair( +COLOR_ROLL_CURRENT, curses.COLOR_BLACK, curses.COLOR_MAGENTA +) +curses.init_pair(COLOR_ROLL_SELECTED, curses.COLOR_RED, curses.COLOR_WHITE) + +# don't display the cursor +try: +curses.curs_set(0) +except curses.error: +pass + def renderstring(win, state, output, diffcolors=False): maxy, maxx = win.getmaxyx() length = min(maxy - 1, len(output)) @@ -1679,7 +1679,7 @@ elif curmode == MODE_HELP: renderstring(mainwin, state, __doc__.strip().splitlines()) else: -renderrules(mainwin, state) +state.render_rules(mainwin) state.render_commit(commitwin) state.render_help(helpwin) curses.doupdate() To: martinvonz, durin42, #hg-reviewers Cc: mercurial-patches, mercurial-devel ___ Mercurial-devel mailing list Mercurial-devel@mercurial-scm.org https://www.mercurial-scm.org/mailman/listinfo/mercurial-devel
D11638: chistedit: move layout() and dependencies onto state class
martinvonz created this revision. Herald added a reviewer: durin42. Herald added a reviewer: hg-reviewers. Herald added a subscriber: mercurial-patches. REPOSITORY rHG Mercurial BRANCH default REVISION DETAIL https://phab.mercurial-scm.org/D11638 AFFECTED FILES hgext/histedit.py CHANGE DETAILS diff --git a/hgext/histedit.py b/hgext/histedit.py --- a/hgext/histedit.py +++ b/hgext/histedit.py @@ -1408,9 +1408,11 @@ self, repo, rules, +stdscr, ): self.repo = repo self.rules = rules +self.stdscr = stdscr self.pos = 0 self.selected = None self.mode = (MODE_INIT, MODE_INIT) @@ -1475,6 +1477,46 @@ win.addstr(y, 1, conflictstr[:length]) win.noutrefresh() +def helplines(self): +if self.mode[0] == MODE_PATCH: +help = b"""\ +?: help, k/up: line up, j/down: line down, v: stop viewing patch +pgup: prev page, space/pgdn: next page, c: commit, q: abort +""" +else: +help = b"""\ +?: help, k/up: move up, j/down: move down, space: select, v: view patch +d: drop, e: edit, f: fold, m: mess, p: pick, r: roll +pgup/K: move patch up, pgdn/J: move patch down, c: commit, q: abort +""" +return help.splitlines() + +def render_help(self, win): +maxy, maxx = win.getmaxyx() +for y, line in enumerate(self.helplines()): +if y >= maxy: +break +addln(win, y, 0, line, curses.color_pair(COLOR_HELP)) +win.noutrefresh() + +def layout(self): +maxy, maxx = self.stdscr.getmaxyx() +helplen = len(self.helplines()) +mainlen = maxy - helplen - 12 +if mainlen < 1: +raise error.Abort( +_(b"terminal dimensions %d by %d too small for curses histedit") +% (maxy, maxx), +hint=_( +b"enlarge your terminal or use --config ui.interface=text" +), +) +return { +b'commit': (12, maxx), +b'help': (helplen, maxx), +b'main': (mainlen, maxx), +} + def _chisteditmain(repo, rules, stdscr): try: @@ -1503,29 +1545,6 @@ except curses.error: pass -def helplines(mode): -if mode == MODE_PATCH: -help = b"""\ -?: help, k/up: line up, j/down: line down, v: stop viewing patch -pgup: prev page, space/pgdn: next page, c: commit, q: abort -""" -else: -help = b"""\ -?: help, k/up: move up, j/down: move down, space: select, v: view patch -d: drop, e: edit, f: fold, m: mess, p: pick, r: roll -pgup/K: move patch up, pgdn/J: move patch down, c: commit, q: abort -""" -return help.splitlines() - -def renderhelp(win, state): -maxy, maxx = win.getmaxyx() -mode, _ = state.mode -for y, line in enumerate(helplines(mode)): -if y >= maxy: -break -addln(win, y, 0, line, curses.color_pair(COLOR_HELP)) -win.noutrefresh() - def renderrules(rulesscr, state): rules = state.rules pos = state.pos @@ -1600,30 +1619,12 @@ content = state.modes[MODE_PATCH][b'patchcontents'] renderstring(win, state, content[start:], diffcolors=True) -def layout(mode): -maxy, maxx = stdscr.getmaxyx() -helplen = len(helplines(mode)) -mainlen = maxy - helplen - 12 -if mainlen < 1: -raise error.Abort( -_(b"terminal dimensions %d by %d too small for curses histedit") -% (maxy, maxx), -hint=_( -b"enlarge your terminal or use --config ui.interface=text" -), -) -return { -b'commit': (12, maxx), -b'help': (helplen, maxx), -b'main': (mainlen, maxx), -} - def drawvertwin(size, y, x): win = curses.newwin(size[0], size[1], y, x) y += size[0] return win, y, x -state = _chistedit_state(repo, rules) +state = _chistedit_state(repo, rules, stdscr) # eventloop ch = None @@ -1645,8 +1646,8 @@ if size != stdscr.getmaxyx(): curses.resizeterm(*size) +sizes = state.layout() curmode, unused = state.mode -sizes = layout(curmode) if curmode != oldmode: state.page_height = sizes[b'main'][0] # Adjust the view to fit the current screen size. @@ -1680,7 +1681,7 @@ else: renderrules(mainwin, state) state.render_commit(commitwin) -renderhelp(helpwin, state) +state.render_help(helpwin) curses.doupdate() # done rendering ch = encoding.strtolocal(stdscr.getkey()) To: martinvonz, durin42, #hg-reviewers Cc: mercurial-patches, mercurial-devel
D11637: chistedit: move rendercommit() onto state class
martinvonz created this revision. Herald added a reviewer: durin42. Herald added a reviewer: hg-reviewers. Herald added a subscriber: mercurial-patches. REPOSITORY rHG Mercurial BRANCH default REVISION DETAIL https://phab.mercurial-scm.org/D11637 AFFECTED FILES hgext/histedit.py CHANGE DETAILS diff --git a/hgext/histedit.py b/hgext/histedit.py --- a/hgext/histedit.py +++ b/hgext/histedit.py @@ -1424,39 +1424,11 @@ }, } - -def _chisteditmain(repo, rules, stdscr): -try: -curses.use_default_colors() -except curses.error: -pass - -# initialize color pattern -curses.init_pair(COLOR_HELP, curses.COLOR_WHITE, curses.COLOR_BLUE) -curses.init_pair(COLOR_SELECTED, curses.COLOR_BLACK, curses.COLOR_WHITE) -curses.init_pair(COLOR_WARN, curses.COLOR_BLACK, curses.COLOR_YELLOW) -curses.init_pair(COLOR_OK, curses.COLOR_BLACK, curses.COLOR_GREEN) -curses.init_pair(COLOR_CURRENT, curses.COLOR_WHITE, curses.COLOR_MAGENTA) -curses.init_pair(COLOR_DIFF_ADD_LINE, curses.COLOR_GREEN, -1) -curses.init_pair(COLOR_DIFF_DEL_LINE, curses.COLOR_RED, -1) -curses.init_pair(COLOR_DIFF_OFFSET, curses.COLOR_MAGENTA, -1) -curses.init_pair(COLOR_ROLL, curses.COLOR_RED, -1) -curses.init_pair( -COLOR_ROLL_CURRENT, curses.COLOR_BLACK, curses.COLOR_MAGENTA -) -curses.init_pair(COLOR_ROLL_SELECTED, curses.COLOR_RED, curses.COLOR_WHITE) - -# don't display the cursor -try: -curses.curs_set(0) -except curses.error: -pass - -def rendercommit(win, state): +def render_commit(self, win): """Renders the commit window that shows the log of the current selected commit""" -pos = state.pos -rules = state.rules +pos = self.pos +rules = self.rules rule = rules[pos] ctx = rule.ctx @@ -1471,7 +1443,7 @@ line = b"user: %s" % ctx.user() win.addstr(2, 1, line[:length]) -bms = repo.nodebookmarks(ctx.node()) +bms = self.repo.nodebookmarks(ctx.node()) line = b"bookmark: %s" % b' '.join(bms) win.addstr(3, 1, line[:length]) @@ -1503,6 +1475,34 @@ win.addstr(y, 1, conflictstr[:length]) win.noutrefresh() + +def _chisteditmain(repo, rules, stdscr): +try: +curses.use_default_colors() +except curses.error: +pass + +# initialize color pattern +curses.init_pair(COLOR_HELP, curses.COLOR_WHITE, curses.COLOR_BLUE) +curses.init_pair(COLOR_SELECTED, curses.COLOR_BLACK, curses.COLOR_WHITE) +curses.init_pair(COLOR_WARN, curses.COLOR_BLACK, curses.COLOR_YELLOW) +curses.init_pair(COLOR_OK, curses.COLOR_BLACK, curses.COLOR_GREEN) +curses.init_pair(COLOR_CURRENT, curses.COLOR_WHITE, curses.COLOR_MAGENTA) +curses.init_pair(COLOR_DIFF_ADD_LINE, curses.COLOR_GREEN, -1) +curses.init_pair(COLOR_DIFF_DEL_LINE, curses.COLOR_RED, -1) +curses.init_pair(COLOR_DIFF_OFFSET, curses.COLOR_MAGENTA, -1) +curses.init_pair(COLOR_ROLL, curses.COLOR_RED, -1) +curses.init_pair( +COLOR_ROLL_CURRENT, curses.COLOR_BLACK, curses.COLOR_MAGENTA +) +curses.init_pair(COLOR_ROLL_SELECTED, curses.COLOR_RED, curses.COLOR_WHITE) + +# don't display the cursor +try: +curses.curs_set(0) +except curses.error: +pass + def helplines(mode): if mode == MODE_PATCH: help = b"""\ @@ -1679,7 +1679,7 @@ renderstring(mainwin, state, __doc__.strip().splitlines()) else: renderrules(mainwin, state) -rendercommit(commitwin, state) +state.render_commit(commitwin) renderhelp(helpwin, state) curses.doupdate() # done rendering To: martinvonz, durin42, #hg-reviewers Cc: mercurial-patches, mercurial-devel ___ Mercurial-devel mailing list Mercurial-devel@mercurial-scm.org https://www.mercurial-scm.org/mailman/listinfo/mercurial-devel
D11636: chistedit: move view state from a dict to a custom class
martinvonz created this revision. Herald added a reviewer: durin42. Herald added a reviewer: hg-reviewers. Herald added a subscriber: mercurial-patches. REPOSITORY rHG Mercurial BRANCH default REVISION DETAIL https://phab.mercurial-scm.org/D11636 AFFECTED FILES hgext/histedit.py CHANGE DETAILS diff --git a/hgext/histedit.py b/hgext/histedit.py --- a/hgext/histedit.py +++ b/hgext/histedit.py @@ -1197,39 +1197,39 @@ def movecursor(state, oldpos, newpos): """Change the rule/changeset that the cursor is pointing to, regardless of current mode (you can switch between patches from the view patch window).""" -state[b'pos'] = newpos - -mode, _ = state[b'mode'] +state.pos = newpos + +mode, _ = state.mode if mode == MODE_RULES: # Scroll through the list by updating the view for MODE_RULES, so that # even if we are not currently viewing the rules, switching back will # result in the cursor's rule being visible. -modestate = state[b'modes'][MODE_RULES] +modestate = state.modes[MODE_RULES] if newpos < modestate[b'line_offset']: modestate[b'line_offset'] = newpos -elif newpos > modestate[b'line_offset'] + state[b'page_height'] - 1: -modestate[b'line_offset'] = newpos - state[b'page_height'] + 1 +elif newpos > modestate[b'line_offset'] + state.page_height - 1: +modestate[b'line_offset'] = newpos - state.page_height + 1 # Reset the patch view region to the top of the new patch. -state[b'modes'][MODE_PATCH][b'line_offset'] = 0 +state.modes[MODE_PATCH][b'line_offset'] = 0 def changemode(state, mode): -curmode, _ = state[b'mode'] -state[b'mode'] = (mode, curmode) +curmode, _ = state.mode +state.mode = (mode, curmode) if mode == MODE_PATCH: -state[b'modes'][MODE_PATCH][b'patchcontents'] = patchcontents(state) +state.modes[MODE_PATCH][b'patchcontents'] = patchcontents(state) def makeselection(state, pos): -state[b'selected'] = pos +state.selected = pos def swap(state, oldpos, newpos): """Swap two positions and calculate necessary conflicts in O(|newpos-oldpos|) time""" -rules = state[b'rules'] +rules = state.rules assert 0 <= oldpos < len(rules) and 0 <= newpos < len(rules) rules[oldpos], rules[newpos] = rules[newpos], rules[oldpos] @@ -1244,13 +1244,13 @@ rules[newpos].checkconflicts(rules[r]) rules[oldpos].checkconflicts(rules[r]) -if state[b'selected']: +if state.selected: makeselection(state, newpos) def changeaction(state, pos, action): """Change the action state on the given position to the new action""" -rules = state[b'rules'] +rules = state.rules assert 0 <= pos < len(rules) rules[pos].action = action @@ -1258,7 +1258,7 @@ def cycleaction(state, pos, next=False): """Changes the action state the next or the previous action from the action list""" -rules = state[b'rules'] +rules = state.rules assert 0 <= pos < len(rules) current = rules[pos].action @@ -1275,12 +1275,12 @@ def changeview(state, delta, unit): """Change the region of whatever is being viewed (a patch or the list of changesets). 'delta' is an amount (+/- 1) and 'unit' is 'page' or 'line'.""" -mode, _ = state[b'mode'] +mode, _ = state.mode if mode != MODE_PATCH: return -mode_state = state[b'modes'][mode] +mode_state = state.modes[mode] num_lines = len(mode_state[b'patchcontents']) -page_height = state[b'page_height'] +page_height = state.page_height unit = page_height if unit == b'page' else 1 num_pages = 1 + (num_lines - 1) // page_height max_offset = (num_pages - 1) * page_height @@ -1294,9 +1294,9 @@ This takes the current state and based on the current character input from the user we change the state. """ -selected = state[b'selected'] -oldpos = state[b'pos'] -rules = state[b'rules'] +selected = state.selected +oldpos = state.pos +rules = state.rules if ch in (curses.KEY_RESIZE, b"KEY_RESIZE"): return E_RESIZE @@ -1305,7 +1305,7 @@ if ch is not None and b'0' <= ch <= b'9': lookup_ch = b'0' -curmode, prevmode = state[b'mode'] +curmode, prevmode = state.mode action = KEYTABLE[curmode].get( lookup_ch, KEYTABLE[b'global'].get(lookup_ch) ) @@ -1391,8 +1391,8 @@ def patchcontents(state): -repo = state[b'repo'] -rule = state[b'rules'][state[b'pos']] +repo = state.repo +rule = state.rules[state.pos] displayer = logcmdutil.changesetdisplayer( repo.ui, repo, {b"patch": True, b"template": b"status"}, buffered=True ) @@ -1403,6 +1403,28 @@ return displayer.hunk[rule.ctx.rev()].splitlines() +class _chistedit_state(object): +def __init__( +self, +repo, +rules, +): +
D11633: dirstate-v2: Truncate directory mtimes to 31 bits of seconds
SimonSapin created this revision. Herald added a reviewer: hg-reviewers. Herald added a subscriber: mercurial-patches. REVISION SUMMARY … instead of 64 bits, while keeping the sub-second presision. This brings the size of one timestamp from 12 bytes to 8 bytes. 31 bits is chosen instead of 32 because that’s already what happens for the mtime of files and symlinks, because dirstate-v1 uses negative i32 values as markers. Later we’ll add sub-second precision for file/symlink mtimes, making their dirstate-v2 representation the same as for directories. REPOSITORY rHG Mercurial BRANCH default REVISION DETAIL https://phab.mercurial-scm.org/D11633 AFFECTED FILES mercurial/helptext/internals/dirstate-v2.txt rust/hg-core/src/dirstate/entry.rs rust/hg-core/src/dirstate_tree/dirstate_map.rs rust/hg-core/src/dirstate_tree/on_disk.rs rust/hg-core/src/dirstate_tree/status.rs CHANGE DETAILS diff --git a/rust/hg-core/src/dirstate_tree/status.rs b/rust/hg-core/src/dirstate_tree/status.rs --- a/rust/hg-core/src/dirstate_tree/status.rs +++ b/rust/hg-core/src/dirstate_tree/status.rs @@ -1,4 +1,4 @@ -use crate::dirstate::entry::Timestamp; +use crate::dirstate::entry::TruncatedTimestamp; use crate::dirstate::status::IgnoreFnType; use crate::dirstate_tree::dirstate_map::BorrowedPath; use crate::dirstate_tree::dirstate_map::ChildNodesRef; @@ -126,7 +126,8 @@ matcher: &'a (dyn Matcher + Sync), ignore_fn: IgnoreFnType<'a>, outcome: Mutex>, -new_cachable_directories: Mutex, Timestamp)>>, +new_cachable_directories: +Mutex, TruncatedTimestamp)>>, outated_cached_directories: Mutex>>, /// Whether ignore files like `.hgignore` have changed since the previous @@ -165,7 +166,7 @@ dirstate_node: <'tree, 'on_disk>, ) -> Result<(), DirstateV2ParseError> { if self.ignore_patterns_have_changed == Some(true) -&& dirstate_node.cached_directory_mtime().is_some() +&& dirstate_node.cached_directory_mtime()?.is_some() { self.outated_cached_directories.lock().unwrap().push( dirstate_node @@ -182,7 +183,7 @@ fn can_skip_fs_readdir( , directory_metadata: Option<::fs::Metadata>, -cached_directory_mtime: Option, +cached_directory_mtime: Option, ) -> bool { if !self.options.list_unknown && !self.options.list_ignored { // All states that we care about listing have corresponding @@ -199,8 +200,9 @@ // directory eligible for `read_dir` caching. if let Some(meta) = directory_metadata { if let Ok(current_mtime) = meta.modified() { -let current_mtime = Timestamp::from(current_mtime); -if current_mtime == cached_mtime { +let truncated = +TruncatedTimestamp::from(current_mtime); +if truncated.very_likely_equal(_mtime) { // The mtime of that directory has not changed // since then, which means that the results of // `read_dir` should also be unchanged. @@ -222,7 +224,7 @@ directory_hg_path: <'tree, 'on_disk>, directory_fs_path: , directory_metadata: Option<::fs::Metadata>, -cached_directory_mtime: Option, +cached_directory_mtime: Option, is_at_repo_root: bool, ) -> Result { if self.can_skip_fs_readdir(directory_metadata, cached_directory_mtime) @@ -363,7 +365,7 @@ hg_path, fs_path, Some(fs_metadata), -dirstate_node.cached_directory_mtime(), +dirstate_node.cached_directory_mtime()?, is_at_repo_root, )?; self.maybe_save_directory_mtime( @@ -466,16 +468,22 @@ // // We deem this scenario (unlike the previous one) to be // unlikely enough in practice. -let timestamp = directory_mtime.into(); -let cached = dirstate_node.cached_directory_mtime(); -if cached != Some(timestamp) { +let truncated = TruncatedTimestamp::from(directory_mtime); +let is_up_to_date = if let Some(cached) = +dirstate_node.cached_directory_mtime()? +{ +cached.very_likely_equal() +} else { +false +}; +if !is_up_to_date { let hg_path = dirstate_node .full_path_borrowed(self.dmap.on_disk)? .detach_from_tree(); self.new_cachable_directories
D11635: dirstate-v2: Replace the 32-bit `mode` field with two bits
SimonSapin created this revision. Herald added a reviewer: hg-reviewers. Herald added a subscriber: mercurial-patches. REVISION SUMMARY Previously we stored the entire value from `stat_result.st_mode`, like dirstate-v1 does. However only the executable permission and type of file (only symbolic links and normal files are supported) are relevant to Mecurial. So replace this field with two bits in the existing bitfield byte. For now the unused space is left as padding, as it will be used for something else soon. REPOSITORY rHG Mercurial BRANCH default REVISION DETAIL https://phab.mercurial-scm.org/D11635 AFFECTED FILES mercurial/helptext/internals/dirstate-v2.txt rust/Cargo.lock rust/hg-core/Cargo.toml rust/hg-core/src/dirstate_tree/on_disk.rs rust/hg-cpython/Cargo.toml CHANGE DETAILS diff --git a/rust/hg-cpython/Cargo.toml b/rust/hg-cpython/Cargo.toml --- a/rust/hg-cpython/Cargo.toml +++ b/rust/hg-cpython/Cargo.toml @@ -23,7 +23,7 @@ [dependencies] crossbeam-channel = "0.4" hg-core = { path = "../hg-core"} -libc = '*' +libc = "0.2" log = "0.4.8" env_logger = "0.7.1" stable_deref_trait = "1.2.0" diff --git a/rust/hg-core/src/dirstate_tree/on_disk.rs b/rust/hg-core/src/dirstate_tree/on_disk.rs --- a/rust/hg-core/src/dirstate_tree/on_disk.rs +++ b/rust/hg-core/src/dirstate_tree/on_disk.rs @@ -107,13 +107,15 @@ const P2_INFO = 1 << 2; const HAS_MODE_AND_SIZE = 1 << 3; const HAS_MTIME = 1 << 4; +const MODE_EXEC_PERM = 1 << 5; +const MODE_IS_SYMLINK = 1 << 7; } } #[derive(BytesCast, Copy, Clone, Debug)] #[repr(C)] struct Entry { -mode: U32Be, +_padding: U32Be, size: U32Be, mtime: U32Be, } @@ -332,13 +334,27 @@ ) } +fn synthesize_unix_mode() -> u32 { +let file_type = if self.flags.contains(Flags::MODE_IS_SYMLINK) { +libc::S_IFLNK +} else { +libc::S_IFREG +}; +let permisions = if self.flags.contains(Flags::MODE_EXEC_PERM) { +0o755 +} else { +0o644 +}; +file_type | permisions +} + fn assume_entry() -> DirstateEntry { // TODO: convert through raw bits instead? let wdir_tracked = self.flags.contains(Flags::WDIR_TRACKED); let p1_tracked = self.flags.contains(Flags::P1_TRACKED); let p2_info = self.flags.contains(Flags::P2_INFO); let mode_size = if self.flags.contains(Flags::HAS_MODE_AND_SIZE) { -Some((self.data.mode.into(), self.data.size.into())) +Some((self.synthesize_unix_mode(), self.data.size.into())) } else { None }; @@ -400,13 +416,15 @@ flags.set(Flags::WDIR_TRACKED, wdir_tracked); flags.set(Flags::P1_TRACKED, p1_tracked); flags.set(Flags::P2_INFO, p2_info); -let (mode, size, mtime); +let (size, mtime); if let Some((m, s)) = mode_size_opt { -mode = m; +let exec_perm = m & libc::S_IXUSR != 0; +let is_symlink = m & libc::S_IFMT == libc::S_IFLNK; +flags.set(Flags::MODE_EXEC_PERM, exec_perm); +flags.set(Flags::MODE_IS_SYMLINK, is_symlink); size = s; flags.insert(Flags::HAS_MODE_AND_SIZE) } else { -mode = 0; size = 0; } if let Some(m) = mtime_opt { @@ -416,7 +434,7 @@ mtime = 0; } let raw_entry = Entry { -mode: mode.into(), +_padding: 0.into(), size: size.into(), mtime: mtime.into(), }; @@ -600,7 +618,7 @@ dirstate_map::NodeData::None => ( Flags::empty(), Entry { -mode: 0.into(), +_padding: 0.into(), size: 0.into(), mtime: 0.into(), }, diff --git a/rust/hg-core/Cargo.toml b/rust/hg-core/Cargo.toml --- a/rust/hg-core/Cargo.toml +++ b/rust/hg-core/Cargo.toml @@ -17,6 +17,7 @@ im-rc = "15.0.*" itertools = "0.9" lazy_static = "1.4.0" +libc = "0.2" rand = "0.7.3" rand_pcg = "0.2.1" rand_distr = "0.2.2" diff --git a/rust/Cargo.lock b/rust/Cargo.lock --- a/rust/Cargo.lock +++ b/rust/Cargo.lock @@ -1,5 +1,7 @@ # This file is automatically @generated by Cargo. # It is not intended for manual editing. +version = 3 + [[package]] name = "adler" version = "0.2.3" @@ -386,6 +388,7 @@ "im-rc", "itertools", "lazy_static", + "libc", "log", "memmap2", "micro-timer", diff --git a/mercurial/helptext/internals/dirstate-v2.txt b/mercurial/helptext/internals/dirstate-v2.txt --- a/mercurial/helptext/internals/dirstate-v2.txt +++ b/mercurial/helptext/internals/dirstate-v2.txt @@ -380,6 +380,9 @@ P2_INFO = 1 << 2 HAS_MODE_AND_SIZE = 1 << 3
D11632: dirstate-v2: Separate Rust structs for Timestamp and PackedTimestamp
SimonSapin created this revision. Herald added a reviewer: hg-reviewers. Herald added a subscriber: mercurial-patches. REVISION SUMMARY PackedTimestamp is now exclusively for dirstate-v2 serialization purpose. It contains unaligned big-endian integers. Timestamp is used everywhere else and contains native Rust integers. REPOSITORY rHG Mercurial BRANCH default REVISION DETAIL https://phab.mercurial-scm.org/D11632 AFFECTED FILES rust/hg-core/src/dirstate/entry.rs rust/hg-core/src/dirstate_tree/dirstate_map.rs rust/hg-core/src/dirstate_tree/on_disk.rs rust/hg-core/src/dirstate_tree/status.rs CHANGE DETAILS diff --git a/rust/hg-core/src/dirstate_tree/status.rs b/rust/hg-core/src/dirstate_tree/status.rs --- a/rust/hg-core/src/dirstate_tree/status.rs +++ b/rust/hg-core/src/dirstate_tree/status.rs @@ -1,3 +1,4 @@ +use crate::dirstate::entry::Timestamp; use crate::dirstate::status::IgnoreFnType; use crate::dirstate_tree::dirstate_map::BorrowedPath; use crate::dirstate_tree::dirstate_map::ChildNodesRef; @@ -5,7 +6,6 @@ use crate::dirstate_tree::dirstate_map::NodeData; use crate::dirstate_tree::dirstate_map::NodeRef; use crate::dirstate_tree::on_disk::DirstateV2ParseError; -use crate::dirstate_tree::on_disk::Timestamp; use crate::matchers::get_ignore_function; use crate::matchers::Matcher; use crate::utils::files::get_bytes_from_os_string; @@ -182,7 +182,7 @@ fn can_skip_fs_readdir( , directory_metadata: Option<::fs::Metadata>, -cached_directory_mtime: Option<>, +cached_directory_mtime: Option, ) -> bool { if !self.options.list_unknown && !self.options.list_ignored { // All states that we care about listing have corresponding @@ -200,7 +200,7 @@ if let Some(meta) = directory_metadata { if let Ok(current_mtime) = meta.modified() { let current_mtime = Timestamp::from(current_mtime); -if current_mtime == *cached_mtime { +if current_mtime == cached_mtime { // The mtime of that directory has not changed // since then, which means that the results of // `read_dir` should also be unchanged. @@ -222,7 +222,7 @@ directory_hg_path: <'tree, 'on_disk>, directory_fs_path: , directory_metadata: Option<::fs::Metadata>, -cached_directory_mtime: Option<>, +cached_directory_mtime: Option, is_at_repo_root: bool, ) -> Result { if self.can_skip_fs_readdir(directory_metadata, cached_directory_mtime) @@ -468,7 +468,7 @@ // unlikely enough in practice. let timestamp = directory_mtime.into(); let cached = dirstate_node.cached_directory_mtime(); -if cached != Some() { +if cached != Some(timestamp) { let hg_path = dirstate_node .full_path_borrowed(self.dmap.on_disk)? .detach_from_tree(); diff --git a/rust/hg-core/src/dirstate_tree/on_disk.rs b/rust/hg-core/src/dirstate_tree/on_disk.rs --- a/rust/hg-core/src/dirstate_tree/on_disk.rs +++ b/rust/hg-core/src/dirstate_tree/on_disk.rs @@ -2,6 +2,7 @@ //! //! See `mercurial/helptext/internals/dirstate-v2.txt` +use crate::dirstate::Timestamp; use crate::dirstate_tree::dirstate_map::{self, DirstateMap, NodeRef}; use crate::dirstate_tree::path_with_basename::WithBasename; use crate::errors::HgError; @@ -15,7 +16,6 @@ use format_bytes::format_bytes; use std::borrow::Cow; use std::convert::{TryFrom, TryInto}; -use std::time::{SystemTime, UNIX_EPOCH}; /// Added at the start of `.hg/dirstate` when the "v2" format is used. /// This a redundant sanity check more than an actual "magic number" since @@ -119,9 +119,9 @@ } /// Duration since the Unix epoch -#[derive(BytesCast, Copy, Clone, PartialEq)] +#[derive(BytesCast, Copy, Clone)] #[repr(C)] -pub(super) struct Timestamp { +struct PackedTimestamp { seconds: I64Be, /// In `0 .. 1_000_000_000`. @@ -316,14 +316,14 @@ ) -> Result { if self.has_entry() { Ok(dirstate_map::NodeData::Entry(self.assume_entry())) -} else if let Some() = self.cached_directory_mtime() { +} else if let Some(mtime) = self.cached_directory_mtime() { Ok(dirstate_map::NodeData::CachedDirectory { mtime }) } else { Ok(dirstate_map::NodeData::None) } } -pub(super) fn cached_directory_mtime() -> Option<> { +pub(super) fn cached_directory_mtime() -> Option { if self.flags.contains(Flags::HAS_MTIME) && !self.has_entry() { Some(self.data.as_timestamp()) } else { @@ -423,58 +423,23 @@ } fn from_timestamp(timestamp: Timestamp) -> Self { +let packed = PackedTimestamp { +
D11634: dirstate-v2: Store unsigned integers inside DirstateEntry
SimonSapin created this revision. Herald added a reviewer: hg-reviewers. Herald added a subscriber: mercurial-patches. REVISION SUMMARY The negative marker values are not used anymore. REPOSITORY rHG Mercurial BRANCH default REVISION DETAIL https://phab.mercurial-scm.org/D11634 AFFECTED FILES rust/hg-core/src/dirstate/entry.rs rust/hg-core/src/dirstate_tree/on_disk.rs rust/hg-cpython/src/dirstate/item.rs CHANGE DETAILS diff --git a/rust/hg-cpython/src/dirstate/item.rs b/rust/hg-cpython/src/dirstate/item.rs --- a/rust/hg-cpython/src/dirstate/item.rs +++ b/rust/hg-cpython/src/dirstate/item.rs @@ -21,7 +21,7 @@ p2_info: bool = false, has_meaningful_data: bool = true, has_meaningful_mtime: bool = true, -parentfiledata: Option<(i32, i32, i32)> = None, +parentfiledata: Option<(u32, u32, u32)> = None, ) -> PyResult { let mut mode_size_opt = None; @@ -145,9 +145,9 @@ def set_clean( , -mode: i32, -size: i32, -mtime: i32, +mode: u32, +size: u32, +mtime: u32, ) -> PyResult { self.update(py, |entry| entry.set_clean(mode, size, mtime)); Ok(PyNone) diff --git a/rust/hg-core/src/dirstate_tree/on_disk.rs b/rust/hg-core/src/dirstate_tree/on_disk.rs --- a/rust/hg-core/src/dirstate_tree/on_disk.rs +++ b/rust/hg-core/src/dirstate_tree/on_disk.rs @@ -11,7 +11,7 @@ use crate::DirstateError; use crate::DirstateParents; use bitflags::bitflags; -use bytes_cast::unaligned::{I32Be, U16Be, U32Be}; +use bytes_cast::unaligned::{U16Be, U32Be}; use bytes_cast::BytesCast; use format_bytes::format_bytes; use std::borrow::Cow; @@ -113,9 +113,9 @@ #[derive(BytesCast, Copy, Clone, Debug)] #[repr(C)] struct Entry { -mode: I32Be, -size: I32Be, -mtime: I32Be, +mode: U32Be, +size: U32Be, +mtime: U32Be, } /// Duration since the Unix epoch diff --git a/rust/hg-core/src/dirstate/entry.rs b/rust/hg-core/src/dirstate/entry.rs --- a/rust/hg-core/src/dirstate/entry.rs +++ b/rust/hg-core/src/dirstate/entry.rs @@ -18,8 +18,8 @@ #[derive(Debug, PartialEq, Copy, Clone)] pub struct DirstateEntry { pub(crate) flags: Flags, -mode_size: Option<(i32, i32)>, -mtime: Option, +mode_size: Option<(u32, u32)>, +mtime: Option, } bitflags! { @@ -153,9 +153,17 @@ wdir_tracked: bool, p1_tracked: bool, p2_info: bool, -mode_size: Option<(i32, i32)>, -mtime: Option, +mode_size: Option<(u32, u32)>, +mtime: Option, ) -> Self { +if let Some((mode, size)) = mode_size { +// TODO: return an error for out of range values? +assert!(mode & !RANGE_MASK_31BIT == 0); +assert!(size & !RANGE_MASK_31BIT == 0); +} +if let Some(mtime) = mtime { +assert!(mtime & !RANGE_MASK_31BIT == 0); +} let mut flags = Flags::empty(); flags.set(Flags::WDIR_TRACKED, wdir_tracked); flags.set(Flags::P1_TRACKED, p1_tracked); @@ -189,12 +197,19 @@ mtime: None, } } else if mtime == MTIME_UNSET { +// TODO: return an error for negative values? +let mode = u32::try_from(mode).unwrap(); +let size = u32::try_from(size).unwrap(); Self { flags: Flags::WDIR_TRACKED | Flags::P1_TRACKED, mode_size: Some((mode, size)), mtime: None, } } else { +// TODO: return an error for negative values? +let mode = u32::try_from(mode).unwrap(); +let size = u32::try_from(size).unwrap(); +let mtime = u32::try_from(mtime).unwrap(); Self { flags: Flags::WDIR_TRACKED | Flags::P1_TRACKED, mode_size: Some((mode, size)), @@ -282,7 +297,7 @@ /// Returns `(wdir_tracked, p1_tracked, p2_info, mode_size, mtime)` pub(crate) fn v2_data( , -) -> (bool, bool, bool, Option<(i32, i32)>, Option) { +) -> (bool, bool, bool, Option<(u32, u32)>, Option) { if !self.any_tracked() { // TODO: return an Option instead? panic!("Accessing v1_state of an untracked DirstateEntry") @@ -316,7 +331,7 @@ fn v1_mode() -> i32 { if let Some((mode, _size)) = self.mode_size { -mode +i32::try_from(mode).unwrap() } else { 0 } @@ -338,7 +353,7 @@ } else if self.added() { SIZE_NON_NORMAL } else if let Some((_mode, size)) = self.mode_size { -size +i32::try_from(size).unwrap() } else { SIZE_NON_NORMAL } @@ -355,8 +370,10 @@ MTIME_UNSET } else if
D11631: dirstate-v2: Only convert from SystemTime to Timestamp and not back
SimonSapin created this revision. Herald added a reviewer: hg-reviewers. Herald added a subscriber: mercurial-patches. REVISION SUMMARY Converting from Timestamp back to SystemTime was only used for equality comparison, but this can also be done on Timestamp values. REPOSITORY rHG Mercurial BRANCH default REVISION DETAIL https://phab.mercurial-scm.org/D11631 AFFECTED FILES rust/hg-core/src/dirstate_tree/on_disk.rs rust/hg-core/src/dirstate_tree/status.rs CHANGE DETAILS diff --git a/rust/hg-core/src/dirstate_tree/status.rs b/rust/hg-core/src/dirstate_tree/status.rs --- a/rust/hg-core/src/dirstate_tree/status.rs +++ b/rust/hg-core/src/dirstate_tree/status.rs @@ -199,7 +199,8 @@ // directory eligible for `read_dir` caching. if let Some(meta) = directory_metadata { if let Ok(current_mtime) = meta.modified() { -if current_mtime == cached_mtime.into() { +let current_mtime = Timestamp::from(current_mtime); +if current_mtime == *cached_mtime { // The mtime of that directory has not changed // since then, which means that the results of // `read_dir` should also be unchanged. diff --git a/rust/hg-core/src/dirstate_tree/on_disk.rs b/rust/hg-core/src/dirstate_tree/on_disk.rs --- a/rust/hg-core/src/dirstate_tree/on_disk.rs +++ b/rust/hg-core/src/dirstate_tree/on_disk.rs @@ -15,7 +15,7 @@ use format_bytes::format_bytes; use std::borrow::Cow; use std::convert::{TryFrom, TryInto}; -use std::time::{Duration, SystemTime, UNIX_EPOCH}; +use std::time::{SystemTime, UNIX_EPOCH}; /// Added at the start of `.hg/dirstate` when the "v2" format is used. /// This a redundant sanity check more than an actual "magic number" since @@ -462,18 +462,6 @@ } } -impl From<&'_ Timestamp> for SystemTime { -fn from(timestamp: &'_ Timestamp) -> Self { -let secs = timestamp.seconds.get(); -let nanos = timestamp.nanoseconds.get(); -if secs >= 0 { -UNIX_EPOCH + Duration::new(secs as u64, nanos) -} else { -UNIX_EPOCH - Duration::new((-secs) as u64, nanos) -} -} -} - fn read_hg_path( on_disk: &[u8], slice: PathSlice, To: SimonSapin, #hg-reviewers Cc: mercurial-patches, mercurial-devel ___ Mercurial-devel mailing list Mercurial-devel@mercurial-scm.org https://www.mercurial-scm.org/mailman/listinfo/mercurial-devel
D11630: rust: update the rust-cpython crate to 0.7.0
SimonSapin created this revision. Herald added a reviewer: hg-reviewers. Herald added a subscriber: mercurial-patches. REVISION SUMMARY This notably brings support for Python 3.10, and includes the panic message when propagating a Rust panic as a Python exception. https://github.com/dgrunwald/rust-cpython/blob/master/CHANGELOG.md#070---2021-10-09 REPOSITORY rHG Mercurial BRANCH default REVISION DETAIL https://phab.mercurial-scm.org/D11630 AFFECTED FILES rust/Cargo.lock rust/hg-cpython/Cargo.toml CHANGE DETAILS diff --git a/rust/hg-cpython/Cargo.toml b/rust/hg-cpython/Cargo.toml --- a/rust/hg-cpython/Cargo.toml +++ b/rust/hg-cpython/Cargo.toml @@ -21,13 +21,10 @@ python3-bin = ["cpython/python3-sys"] [dependencies] +cpython = { version = "0.7.0", default-features = false } crossbeam-channel = "0.4" hg-core = { path = "../hg-core"} libc = '*' log = "0.4.8" env_logger = "0.7.1" stable_deref_trait = "1.2.0" - -[dependencies.cpython] -version = "0.6.0" -default-features = false diff --git a/rust/Cargo.lock b/rust/Cargo.lock --- a/rust/Cargo.lock +++ b/rust/Cargo.lock @@ -1,5 +1,7 @@ # This file is automatically @generated by Cargo. # It is not intended for manual editing. +version = 3 + [[package]] name = "adler" version = "0.2.3" @@ -157,9 +159,9 @@ [[package]] name = "cpython" -version = "0.6.0" +version = "0.7.0" source = "registry+https://github.com/rust-lang/crates.io-index; -checksum = "8094679a4e9bfc8035572162624bc800eda35b5f9eff2537b9cd9aacc3d9782e" +checksum = "b7d46ba8ace7f3a1d204ac5060a706d0a68de6b42eafb6a586cc08bebcffe664" dependencies = [ "libc", "num-traits", @@ -652,9 +654,9 @@ [[package]] name = "python27-sys" -version = "0.6.0" +version = "0.7.0" source = "registry+https://github.com/rust-lang/crates.io-index; -checksum = "5826ddbc5366eb0b0492040fdc25bf50bb49092c192bd45e80fb7a24dc6832ab" +checksum = "94670354e264300dde81a5864cbb6bfc9d56ac3dcf3a278c32cb52f816f4dfd1" dependencies = [ "libc", "regex", @@ -662,9 +664,9 @@ [[package]] name = "python3-sys" -version = "0.6.0" +version = "0.7.0" source = "registry+https://github.com/rust-lang/crates.io-index; -checksum = "b78af21b29594951a47fc3dac9b9eff0a3f077dec2f780ee943ae16a668f3b6a" +checksum = "b18b32e64c103d5045f44644d7d65336f7a0521f6fde673240a9ecceb77e" dependencies = [ "libc", "regex", To: SimonSapin, #hg-reviewers Cc: mercurial-patches, mercurial-devel ___ Mercurial-devel mailing list Mercurial-devel@mercurial-scm.org https://www.mercurial-scm.org/mailman/listinfo/mercurial-devel
D11629: dirstate-v2: Change the representation of negative directory mtime
SimonSapin created this revision. Herald added a reviewer: hg-reviewers. Herald added a subscriber: mercurial-patches. REVISION SUMMARY Change it from how I previously thought C’s `timespec` works to how it actually works. The previous behavior was also buggy for timestamps strictly before the epoch but less than one second away from it, because two’s complement does not distinguish negative zero from positive zero. REPOSITORY rHG Mercurial BRANCH default REVISION DETAIL https://phab.mercurial-scm.org/D11629 AFFECTED FILES mercurial/helptext/internals/dirstate-v2.txt rust/hg-core/src/dirstate_tree/on_disk.rs CHANGE DETAILS diff --git a/rust/hg-core/src/dirstate_tree/on_disk.rs b/rust/hg-core/src/dirstate_tree/on_disk.rs --- a/rust/hg-core/src/dirstate_tree/on_disk.rs +++ b/rust/hg-core/src/dirstate_tree/on_disk.rs @@ -126,8 +126,7 @@ /// In `0 .. 1_000_000_000`. /// -/// This timestamp is later or earlier than `(seconds, 0)` by this many -/// nanoseconds, if `seconds` is non-negative or negative, respectively. +/// This timestamp is after `(seconds, 0)` by this many nanoseconds. nanoseconds: U32Be, } @@ -444,15 +443,33 @@ } } +const NSEC_PER_SEC: u32 = 1_000_000_000; + impl From for Timestamp { fn from(system_time: SystemTime) -> Self { +// On Unix, `SystemTime` is a wrapper for the `timespec` C struct: +// https://www.gnu.org/software/libc/manual/html_node/Time-Types.html#index-struct-timespec +// We want to effectively access its fields, but the Rust standard +// library does not expose them. The best we can do is: let (secs, nanos) = match system_time.duration_since(UNIX_EPOCH) { Ok(duration) => { (duration.as_secs() as i64, duration.subsec_nanos()) } Err(error) => { +// `system_time` is before `UNIX_EPOCH`. +// We need to undo this algorithm: +// https://github.com/rust-lang/rust/blob/6bed1f0bc3cc50c10aab26d5f94b16a00776b8a5/library/std/src/sys/unix/time.rs#L40-L41 let negative = error.duration(); -(-(negative.as_secs() as i64), negative.subsec_nanos()) +let negative_secs = negative.as_secs() as i64; +let negative_nanos = negative.subsec_nanos(); +if negative_nanos == 0 { +(-negative_secs, 0) +} else { +// For example if `system_time` was 4.3 seconds before +// the Unix epoch we get a Duration that represents +// `(-4, -0.3)` but we want `(-5, +0.7)`: +(-1 - negative_secs, NSEC_PER_SEC - negative_nanos) +} } }; Timestamp { @@ -466,10 +483,17 @@ fn from(timestamp: &'_ Timestamp) -> Self { let secs = timestamp.seconds.get(); let nanos = timestamp.nanoseconds.get(); -if secs >= 0 { +if secs < 0 { +let (s_to_subtract, ns_to_subtract) = if nanos == 0 { +(-secs, 0) +} else { +// Example: `(-5, +0.7)` → `(-4, -0.3)` +// See `impl From for Timestamp` above +(1 - secs, NSEC_PER_SEC - nanos) +}; +UNIX_EPOCH - Duration::new(s_to_subtract as u64, ns_to_subtract) +} else { UNIX_EPOCH + Duration::new(secs as u64, nanos) -} else { -UNIX_EPOCH - Duration::new((-secs) as u64, nanos) } } } diff --git a/mercurial/helptext/internals/dirstate-v2.txt b/mercurial/helptext/internals/dirstate-v2.txt --- a/mercurial/helptext/internals/dirstate-v2.txt +++ b/mercurial/helptext/internals/dirstate-v2.txt @@ -443,20 +443,19 @@ If an untracked node `HAS_MTIME` *set*, what follows is the modification time of a directory - represented with separated second and sub-second components - since the Unix epoch: + represented similarly to the C `timespec` struct: * Offset 31: -The number of seconds as a signed (two’s complement) 64-bit integer. +The number of seconds elapsed since the Unix epoch, +as a signed (two’s complement) 64-bit integer. * Offset 39: -The number of nanoseconds as 32-bit integer. +The number of nanoseconds elapsed since +the instant specified by the previous field alone, +as 32-bit integer. Always greater than or equal to zero, and strictly less than a billion. Increasing this component makes the modification time -go forward or backward in time dependening -on the sign of the integral seconds components. -(Note: this is buggy because there is no negative zero integer, -but will be changed soon.) +go forward in time regardless of the sign of the seconds component. The presence of a directory modification time means that at some point, this path in the working directory