annotate rust/hg-core/src/revlog/changelog.rs @ 51725:bbe59cc5d2e1

rust-changelog: accessing the index The `Index` object is currently the one providing all DAG related algorithms, starting with simple ancestors iteration up to more advanced ones (ranges, common ancestors…). From pure Rust code, there was no way to access the changelog index for a given `Repository`, probably because `rhg` does not use any such algorithm yet.
author Georges Racinet <georges.racinet@cloudcrane.io>
date Mon, 22 Jul 2024 18:20:29 +0200
parents ec7171748350
children 69b804c8e09e
Ignore whitespace changes - Everywhere: Within whitespace: At end of lines:
rev   line source
51391
a96ed440450e hg-core: implement timestamp line parsing
Arun Kulshreshtha <akulshreshtha@janestreet.com>
parents: 51369
diff changeset
1 use std::ascii::escape_default;
a96ed440450e hg-core: implement timestamp line parsing
Arun Kulshreshtha <akulshreshtha@janestreet.com>
parents: 51369
diff changeset
2 use std::borrow::Cow;
a96ed440450e hg-core: implement timestamp line parsing
Arun Kulshreshtha <akulshreshtha@janestreet.com>
parents: 51369
diff changeset
3 use std::collections::BTreeMap;
a96ed440450e hg-core: implement timestamp line parsing
Arun Kulshreshtha <akulshreshtha@janestreet.com>
parents: 51369
diff changeset
4 use std::fmt::{Debug, Formatter};
a96ed440450e hg-core: implement timestamp line parsing
Arun Kulshreshtha <akulshreshtha@janestreet.com>
parents: 51369
diff changeset
5 use std::{iter, str};
a96ed440450e hg-core: implement timestamp line parsing
Arun Kulshreshtha <akulshreshtha@janestreet.com>
parents: 51369
diff changeset
6
a96ed440450e hg-core: implement timestamp line parsing
Arun Kulshreshtha <akulshreshtha@janestreet.com>
parents: 51369
diff changeset
7 use chrono::{DateTime, FixedOffset, NaiveDateTime};
a96ed440450e hg-core: implement timestamp line parsing
Arun Kulshreshtha <akulshreshtha@janestreet.com>
parents: 51369
diff changeset
8 use itertools::{Either, Itertools};
a96ed440450e hg-core: implement timestamp line parsing
Arun Kulshreshtha <akulshreshtha@janestreet.com>
parents: 51369
diff changeset
9
46443
43d63979a75e rust: use HgError in RevlogError and Vfs
Simon Sapin <simon.sapin@octobus.net>
parents: 46433
diff changeset
10 use crate::errors::HgError;
51725
bbe59cc5d2e1 rust-changelog: accessing the index
Georges Racinet <georges.racinet@cloudcrane.io>
parents: 51707
diff changeset
11 use crate::revlog::Index;
50747
9865af7191d2 rust-changelog: removed now useless early conditional for NULL_REVISION
Georges Racinet <georges.racinet@octobus.net>
parents: 50746
diff changeset
12 use crate::revlog::Revision;
46744
b1f2c2b336ec rhg: `cat` command: print error messages for missing files
Simon Sapin <simon.sapin@octobus.net>
parents: 46443
diff changeset
13 use crate::revlog::{Node, NodePrefix};
49937
750409505286 rust-clippy: merge "revlog" module definition and struct implementation
Raphaël Gomès <rgomes@octobus.net>
parents: 49930
diff changeset
14 use crate::revlog::{Revlog, RevlogEntry, RevlogError};
49064
95da3e99cbd8 rust-changelog: start parsing changeset data
Martin von Zweigbergk <martinvonz@google.com>
parents: 49063
diff changeset
15 use crate::utils::hg_path::HgPath;
49090
a5ef50becea8 rust-revlog: make `Changelog` and `ManifestLog` unaware of `Repo`
Martin von Zweigbergk <martinvonz@google.com>
parents: 49089
diff changeset
16 use crate::vfs::Vfs;
51191
13f58ce70299 rust-revlog: teach the revlog opening code to read the repo options
Raphaël Gomès <rgomes@octobus.net>
parents: 50978
diff changeset
17 use crate::{Graph, GraphError, RevlogOpenOptions, UncheckedRevision};
45532
c2317b7624fd hg-core: add `Changlog` a specialized `Revlog`
Antoine Cezar <antoine.cezar@octobus.net>
parents:
diff changeset
18
50409
b47a9316050a rust-changelog: made doc-comments more consistent
Georges Racinet <georges.racinet@octobus.net>
parents: 49937
diff changeset
19 /// A specialized `Revlog` to work with changelog data format.
45532
c2317b7624fd hg-core: add `Changlog` a specialized `Revlog`
Antoine Cezar <antoine.cezar@octobus.net>
parents:
diff changeset
20 pub struct Changelog {
c2317b7624fd hg-core: add `Changlog` a specialized `Revlog`
Antoine Cezar <antoine.cezar@octobus.net>
parents:
diff changeset
21 /// The generic `revlog` format.
46433
4b381dbbf8b7 rhg: centralize parsing of `--rev` CLI arguments
Simon Sapin <simon.sapin@octobus.net>
parents: 46431
diff changeset
22 pub(crate) revlog: Revlog,
45532
c2317b7624fd hg-core: add `Changlog` a specialized `Revlog`
Antoine Cezar <antoine.cezar@octobus.net>
parents:
diff changeset
23 }
c2317b7624fd hg-core: add `Changlog` a specialized `Revlog`
Antoine Cezar <antoine.cezar@octobus.net>
parents:
diff changeset
24
c2317b7624fd hg-core: add `Changlog` a specialized `Revlog`
Antoine Cezar <antoine.cezar@octobus.net>
parents:
diff changeset
25 impl Changelog {
c2317b7624fd hg-core: add `Changlog` a specialized `Revlog`
Antoine Cezar <antoine.cezar@octobus.net>
parents:
diff changeset
26 /// Open the `changelog` of a repository given by its root.
51191
13f58ce70299 rust-revlog: teach the revlog opening code to read the repo options
Raphaël Gomès <rgomes@octobus.net>
parents: 50978
diff changeset
27 pub fn open(
13f58ce70299 rust-revlog: teach the revlog opening code to read the repo options
Raphaël Gomès <rgomes@octobus.net>
parents: 50978
diff changeset
28 store_vfs: &Vfs,
13f58ce70299 rust-revlog: teach the revlog opening code to read the repo options
Raphaël Gomès <rgomes@octobus.net>
parents: 50978
diff changeset
29 options: RevlogOpenOptions,
13f58ce70299 rust-revlog: teach the revlog opening code to read the repo options
Raphaël Gomès <rgomes@octobus.net>
parents: 50978
diff changeset
30 ) -> Result<Self, HgError> {
13f58ce70299 rust-revlog: teach the revlog opening code to read the repo options
Raphaël Gomès <rgomes@octobus.net>
parents: 50978
diff changeset
31 let revlog = Revlog::open(store_vfs, "00changelog.i", None, options)?;
45532
c2317b7624fd hg-core: add `Changlog` a specialized `Revlog`
Antoine Cezar <antoine.cezar@octobus.net>
parents:
diff changeset
32 Ok(Self { revlog })
c2317b7624fd hg-core: add `Changlog` a specialized `Revlog`
Antoine Cezar <antoine.cezar@octobus.net>
parents:
diff changeset
33 }
c2317b7624fd hg-core: add `Changlog` a specialized `Revlog`
Antoine Cezar <antoine.cezar@octobus.net>
parents:
diff changeset
34
50409
b47a9316050a rust-changelog: made doc-comments more consistent
Georges Racinet <georges.racinet@octobus.net>
parents: 49937
diff changeset
35 /// Return the `ChangelogRevisionData` for the given node ID.
47969
87e3f878e65f rust: Rename get_node methods to data_for_node, get_rev to data_for_rev
Simon Sapin <simon.sapin@octobus.net>
parents: 47968
diff changeset
36 pub fn data_for_node(
45532
c2317b7624fd hg-core: add `Changlog` a specialized `Revlog`
Antoine Cezar <antoine.cezar@octobus.net>
parents:
diff changeset
37 &self,
46431
645ee7225fab rust: Make NodePrefix allocation-free and Copy, remove NodePrefixRef
Simon Sapin <simon.sapin@octobus.net>
parents: 46167
diff changeset
38 node: NodePrefix,
48540
20d0d896183e rhg: Rename some revlog-related types and methods
Simon Sapin <simon.sapin@octobus.net>
parents: 48198
diff changeset
39 ) -> Result<ChangelogRevisionData, RevlogError> {
47968
6f579618ea7b rust: Rename the `Revlog::get_node_rev` method to `rev_from_node`
Simon Sapin <simon.sapin@octobus.net>
parents: 47967
diff changeset
40 let rev = self.revlog.rev_from_node(node)?;
50977
1928b770e3e7 rust: use the new `UncheckedRevision` everywhere applicable
Raphaël Gomès <rgomes@octobus.net>
parents: 50747
diff changeset
41 self.entry_for_checked_rev(rev)?.data()
45532
c2317b7624fd hg-core: add `Changlog` a specialized `Revlog`
Antoine Cezar <antoine.cezar@octobus.net>
parents:
diff changeset
42 }
c2317b7624fd hg-core: add `Changlog` a specialized `Revlog`
Antoine Cezar <antoine.cezar@octobus.net>
parents:
diff changeset
43
50411
841b13e6e84c rust-changelog: introducing an intermediate `ChangelogEntry`
Georges Racinet <georges.racinet@octobus.net>
parents: 50410
diff changeset
44 /// Return the [`ChangelogEntry`] for the given revision number.
49065
5d205e476057 rust-revlog: add methods for getting parent revs and entries
Martin von Zweigbergk <martinvonz@google.com>
parents: 49064
diff changeset
45 pub fn entry_for_rev(
5d205e476057 rust-revlog: add methods for getting parent revs and entries
Martin von Zweigbergk <martinvonz@google.com>
parents: 49064
diff changeset
46 &self,
50977
1928b770e3e7 rust: use the new `UncheckedRevision` everywhere applicable
Raphaël Gomès <rgomes@octobus.net>
parents: 50747
diff changeset
47 rev: UncheckedRevision,
1928b770e3e7 rust: use the new `UncheckedRevision` everywhere applicable
Raphaël Gomès <rgomes@octobus.net>
parents: 50747
diff changeset
48 ) -> Result<ChangelogEntry, RevlogError> {
1928b770e3e7 rust: use the new `UncheckedRevision` everywhere applicable
Raphaël Gomès <rgomes@octobus.net>
parents: 50747
diff changeset
49 let revlog_entry = self.revlog.get_entry(rev)?;
1928b770e3e7 rust: use the new `UncheckedRevision` everywhere applicable
Raphaël Gomès <rgomes@octobus.net>
parents: 50747
diff changeset
50 Ok(ChangelogEntry { revlog_entry })
1928b770e3e7 rust: use the new `UncheckedRevision` everywhere applicable
Raphaël Gomès <rgomes@octobus.net>
parents: 50747
diff changeset
51 }
1928b770e3e7 rust: use the new `UncheckedRevision` everywhere applicable
Raphaël Gomès <rgomes@octobus.net>
parents: 50747
diff changeset
52
1928b770e3e7 rust: use the new `UncheckedRevision` everywhere applicable
Raphaël Gomès <rgomes@octobus.net>
parents: 50747
diff changeset
53 /// Same as [`Self::entry_for_rev`] for checked revisions.
1928b770e3e7 rust: use the new `UncheckedRevision` everywhere applicable
Raphaël Gomès <rgomes@octobus.net>
parents: 50747
diff changeset
54 fn entry_for_checked_rev(
1928b770e3e7 rust: use the new `UncheckedRevision` everywhere applicable
Raphaël Gomès <rgomes@octobus.net>
parents: 50747
diff changeset
55 &self,
49065
5d205e476057 rust-revlog: add methods for getting parent revs and entries
Martin von Zweigbergk <martinvonz@google.com>
parents: 49064
diff changeset
56 rev: Revision,
50411
841b13e6e84c rust-changelog: introducing an intermediate `ChangelogEntry`
Georges Racinet <georges.racinet@octobus.net>
parents: 50410
diff changeset
57 ) -> Result<ChangelogEntry, RevlogError> {
50977
1928b770e3e7 rust: use the new `UncheckedRevision` everywhere applicable
Raphaël Gomès <rgomes@octobus.net>
parents: 50747
diff changeset
58 let revlog_entry = self.revlog.get_entry_for_checked_rev(rev)?;
50411
841b13e6e84c rust-changelog: introducing an intermediate `ChangelogEntry`
Georges Racinet <georges.racinet@octobus.net>
parents: 50410
diff changeset
59 Ok(ChangelogEntry { revlog_entry })
49065
5d205e476057 rust-revlog: add methods for getting parent revs and entries
Martin von Zweigbergk <martinvonz@google.com>
parents: 49064
diff changeset
60 }
5d205e476057 rust-revlog: add methods for getting parent revs and entries
Martin von Zweigbergk <martinvonz@google.com>
parents: 49064
diff changeset
61
50409
b47a9316050a rust-changelog: made doc-comments more consistent
Georges Racinet <georges.racinet@octobus.net>
parents: 49937
diff changeset
62 /// Return the [`ChangelogRevisionData`] for the given revision number.
50411
841b13e6e84c rust-changelog: introducing an intermediate `ChangelogEntry`
Georges Racinet <georges.racinet@octobus.net>
parents: 50410
diff changeset
63 ///
841b13e6e84c rust-changelog: introducing an intermediate `ChangelogEntry`
Georges Racinet <georges.racinet@octobus.net>
parents: 50410
diff changeset
64 /// This is a useful shortcut in case the caller does not need the
841b13e6e84c rust-changelog: introducing an intermediate `ChangelogEntry`
Georges Racinet <georges.racinet@octobus.net>
parents: 50410
diff changeset
65 /// generic revlog information (parents, hashes etc). Otherwise
841b13e6e84c rust-changelog: introducing an intermediate `ChangelogEntry`
Georges Racinet <georges.racinet@octobus.net>
parents: 50410
diff changeset
66 /// consider taking a [`ChangelogEntry`] with
841b13e6e84c rust-changelog: introducing an intermediate `ChangelogEntry`
Georges Racinet <georges.racinet@octobus.net>
parents: 50410
diff changeset
67 /// [entry_for_rev](`Self::entry_for_rev`) and doing everything from there.
47969
87e3f878e65f rust: Rename get_node methods to data_for_node, get_rev to data_for_rev
Simon Sapin <simon.sapin@octobus.net>
parents: 47968
diff changeset
68 pub fn data_for_rev(
45532
c2317b7624fd hg-core: add `Changlog` a specialized `Revlog`
Antoine Cezar <antoine.cezar@octobus.net>
parents:
diff changeset
69 &self,
50977
1928b770e3e7 rust: use the new `UncheckedRevision` everywhere applicable
Raphaël Gomès <rgomes@octobus.net>
parents: 50747
diff changeset
70 rev: UncheckedRevision,
48540
20d0d896183e rhg: Rename some revlog-related types and methods
Simon Sapin <simon.sapin@octobus.net>
parents: 48198
diff changeset
71 ) -> Result<ChangelogRevisionData, RevlogError> {
50411
841b13e6e84c rust-changelog: introducing an intermediate `ChangelogEntry`
Georges Racinet <georges.racinet@octobus.net>
parents: 50410
diff changeset
72 self.entry_for_rev(rev)?.data()
45532
c2317b7624fd hg-core: add `Changlog` a specialized `Revlog`
Antoine Cezar <antoine.cezar@octobus.net>
parents:
diff changeset
73 }
46744
b1f2c2b336ec rhg: `cat` command: print error messages for missing files
Simon Sapin <simon.sapin@octobus.net>
parents: 46443
diff changeset
74
50977
1928b770e3e7 rust: use the new `UncheckedRevision` everywhere applicable
Raphaël Gomès <rgomes@octobus.net>
parents: 50747
diff changeset
75 pub fn node_from_rev(&self, rev: UncheckedRevision) -> Option<&Node> {
47967
6c653d9d41b8 rust: Make private the `index` field of the `Revlog` struct
Simon Sapin <simon.sapin@octobus.net>
parents: 47964
diff changeset
76 self.revlog.node_from_rev(rev)
46744
b1f2c2b336ec rhg: `cat` command: print error messages for missing files
Simon Sapin <simon.sapin@octobus.net>
parents: 46443
diff changeset
77 }
49065
5d205e476057 rust-revlog: add methods for getting parent revs and entries
Martin von Zweigbergk <martinvonz@google.com>
parents: 49064
diff changeset
78
5d205e476057 rust-revlog: add methods for getting parent revs and entries
Martin von Zweigbergk <martinvonz@google.com>
parents: 49064
diff changeset
79 pub fn rev_from_node(
5d205e476057 rust-revlog: add methods for getting parent revs and entries
Martin von Zweigbergk <martinvonz@google.com>
parents: 49064
diff changeset
80 &self,
5d205e476057 rust-revlog: add methods for getting parent revs and entries
Martin von Zweigbergk <martinvonz@google.com>
parents: 49064
diff changeset
81 node: NodePrefix,
5d205e476057 rust-revlog: add methods for getting parent revs and entries
Martin von Zweigbergk <martinvonz@google.com>
parents: 49064
diff changeset
82 ) -> Result<Revision, RevlogError> {
5d205e476057 rust-revlog: add methods for getting parent revs and entries
Martin von Zweigbergk <martinvonz@google.com>
parents: 49064
diff changeset
83 self.revlog.rev_from_node(node)
5d205e476057 rust-revlog: add methods for getting parent revs and entries
Martin von Zweigbergk <martinvonz@google.com>
parents: 49064
diff changeset
84 }
51725
bbe59cc5d2e1 rust-changelog: accessing the index
Georges Racinet <georges.racinet@cloudcrane.io>
parents: 51707
diff changeset
85
bbe59cc5d2e1 rust-changelog: accessing the index
Georges Racinet <georges.racinet@cloudcrane.io>
parents: 51707
diff changeset
86 pub fn get_index(&self) -> &Index {
bbe59cc5d2e1 rust-changelog: accessing the index
Georges Racinet <georges.racinet@cloudcrane.io>
parents: 51707
diff changeset
87 &self.revlog.index
bbe59cc5d2e1 rust-changelog: accessing the index
Georges Racinet <georges.racinet@cloudcrane.io>
parents: 51707
diff changeset
88 }
45532
c2317b7624fd hg-core: add `Changlog` a specialized `Revlog`
Antoine Cezar <antoine.cezar@octobus.net>
parents:
diff changeset
89 }
c2317b7624fd hg-core: add `Changlog` a specialized `Revlog`
Antoine Cezar <antoine.cezar@octobus.net>
parents:
diff changeset
90
50978
27e773aa607d rust: implement the `Graph` trait for all revlogs
Raphaël Gomès <rgomes@octobus.net>
parents: 50977
diff changeset
91 impl Graph for Changelog {
27e773aa607d rust: implement the `Graph` trait for all revlogs
Raphaël Gomès <rgomes@octobus.net>
parents: 50977
diff changeset
92 fn parents(&self, rev: Revision) -> Result<[Revision; 2], GraphError> {
27e773aa607d rust: implement the `Graph` trait for all revlogs
Raphaël Gomès <rgomes@octobus.net>
parents: 50977
diff changeset
93 self.revlog.parents(rev)
27e773aa607d rust: implement the `Graph` trait for all revlogs
Raphaël Gomès <rgomes@octobus.net>
parents: 50977
diff changeset
94 }
27e773aa607d rust: implement the `Graph` trait for all revlogs
Raphaël Gomès <rgomes@octobus.net>
parents: 50977
diff changeset
95 }
27e773aa607d rust: implement the `Graph` trait for all revlogs
Raphaël Gomès <rgomes@octobus.net>
parents: 50977
diff changeset
96
50411
841b13e6e84c rust-changelog: introducing an intermediate `ChangelogEntry`
Georges Racinet <georges.racinet@octobus.net>
parents: 50410
diff changeset
97 /// A specialized `RevlogEntry` for `changelog` data format
841b13e6e84c rust-changelog: introducing an intermediate `ChangelogEntry`
Georges Racinet <georges.racinet@octobus.net>
parents: 50410
diff changeset
98 ///
841b13e6e84c rust-changelog: introducing an intermediate `ChangelogEntry`
Georges Racinet <georges.racinet@octobus.net>
parents: 50410
diff changeset
99 /// This is a `RevlogEntry` with the added semantics that the associated
841b13e6e84c rust-changelog: introducing an intermediate `ChangelogEntry`
Georges Racinet <georges.racinet@octobus.net>
parents: 50410
diff changeset
100 /// data should meet the requirements for `changelog`, materialized by
841b13e6e84c rust-changelog: introducing an intermediate `ChangelogEntry`
Georges Racinet <georges.racinet@octobus.net>
parents: 50410
diff changeset
101 /// the fact that `data()` constructs a `ChangelogRevisionData`.
841b13e6e84c rust-changelog: introducing an intermediate `ChangelogEntry`
Georges Racinet <georges.racinet@octobus.net>
parents: 50410
diff changeset
102 /// In case that promise would be broken, the `data` method returns an error.
841b13e6e84c rust-changelog: introducing an intermediate `ChangelogEntry`
Georges Racinet <georges.racinet@octobus.net>
parents: 50410
diff changeset
103 #[derive(Clone)]
841b13e6e84c rust-changelog: introducing an intermediate `ChangelogEntry`
Georges Racinet <georges.racinet@octobus.net>
parents: 50410
diff changeset
104 pub struct ChangelogEntry<'changelog> {
841b13e6e84c rust-changelog: introducing an intermediate `ChangelogEntry`
Georges Racinet <georges.racinet@octobus.net>
parents: 50410
diff changeset
105 /// Same data, as a generic `RevlogEntry`.
841b13e6e84c rust-changelog: introducing an intermediate `ChangelogEntry`
Georges Racinet <georges.racinet@octobus.net>
parents: 50410
diff changeset
106 pub(crate) revlog_entry: RevlogEntry<'changelog>,
841b13e6e84c rust-changelog: introducing an intermediate `ChangelogEntry`
Georges Racinet <georges.racinet@octobus.net>
parents: 50410
diff changeset
107 }
841b13e6e84c rust-changelog: introducing an intermediate `ChangelogEntry`
Georges Racinet <georges.racinet@octobus.net>
parents: 50410
diff changeset
108
841b13e6e84c rust-changelog: introducing an intermediate `ChangelogEntry`
Georges Racinet <georges.racinet@octobus.net>
parents: 50410
diff changeset
109 impl<'changelog> ChangelogEntry<'changelog> {
841b13e6e84c rust-changelog: introducing an intermediate `ChangelogEntry`
Georges Racinet <georges.racinet@octobus.net>
parents: 50410
diff changeset
110 pub fn data<'a>(
841b13e6e84c rust-changelog: introducing an intermediate `ChangelogEntry`
Georges Racinet <georges.racinet@octobus.net>
parents: 50410
diff changeset
111 &'a self,
841b13e6e84c rust-changelog: introducing an intermediate `ChangelogEntry`
Georges Racinet <georges.racinet@octobus.net>
parents: 50410
diff changeset
112 ) -> Result<ChangelogRevisionData<'changelog>, RevlogError> {
841b13e6e84c rust-changelog: introducing an intermediate `ChangelogEntry`
Georges Racinet <georges.racinet@octobus.net>
parents: 50410
diff changeset
113 let bytes = self.revlog_entry.data()?;
841b13e6e84c rust-changelog: introducing an intermediate `ChangelogEntry`
Georges Racinet <georges.racinet@octobus.net>
parents: 50410
diff changeset
114 if bytes.is_empty() {
841b13e6e84c rust-changelog: introducing an intermediate `ChangelogEntry`
Georges Racinet <georges.racinet@octobus.net>
parents: 50410
diff changeset
115 Ok(ChangelogRevisionData::null())
841b13e6e84c rust-changelog: introducing an intermediate `ChangelogEntry`
Georges Racinet <georges.racinet@octobus.net>
parents: 50410
diff changeset
116 } else {
841b13e6e84c rust-changelog: introducing an intermediate `ChangelogEntry`
Georges Racinet <georges.racinet@octobus.net>
parents: 50410
diff changeset
117 Ok(ChangelogRevisionData::new(bytes).map_err(|err| {
841b13e6e84c rust-changelog: introducing an intermediate `ChangelogEntry`
Georges Racinet <georges.racinet@octobus.net>
parents: 50410
diff changeset
118 RevlogError::Other(HgError::CorruptedRepository(format!(
841b13e6e84c rust-changelog: introducing an intermediate `ChangelogEntry`
Georges Racinet <georges.racinet@octobus.net>
parents: 50410
diff changeset
119 "Invalid changelog data for revision {}: {:?}",
841b13e6e84c rust-changelog: introducing an intermediate `ChangelogEntry`
Georges Racinet <georges.racinet@octobus.net>
parents: 50410
diff changeset
120 self.revlog_entry.revision(),
841b13e6e84c rust-changelog: introducing an intermediate `ChangelogEntry`
Georges Racinet <georges.racinet@octobus.net>
parents: 50410
diff changeset
121 err
841b13e6e84c rust-changelog: introducing an intermediate `ChangelogEntry`
Georges Racinet <georges.racinet@octobus.net>
parents: 50410
diff changeset
122 )))
841b13e6e84c rust-changelog: introducing an intermediate `ChangelogEntry`
Georges Racinet <georges.racinet@octobus.net>
parents: 50410
diff changeset
123 })?)
841b13e6e84c rust-changelog: introducing an intermediate `ChangelogEntry`
Georges Racinet <georges.racinet@octobus.net>
parents: 50410
diff changeset
124 }
841b13e6e84c rust-changelog: introducing an intermediate `ChangelogEntry`
Georges Racinet <georges.racinet@octobus.net>
parents: 50410
diff changeset
125 }
841b13e6e84c rust-changelog: introducing an intermediate `ChangelogEntry`
Georges Racinet <georges.racinet@octobus.net>
parents: 50410
diff changeset
126
841b13e6e84c rust-changelog: introducing an intermediate `ChangelogEntry`
Georges Racinet <georges.racinet@octobus.net>
parents: 50410
diff changeset
127 /// Obtain a reference to the underlying `RevlogEntry`.
841b13e6e84c rust-changelog: introducing an intermediate `ChangelogEntry`
Georges Racinet <georges.racinet@octobus.net>
parents: 50410
diff changeset
128 ///
841b13e6e84c rust-changelog: introducing an intermediate `ChangelogEntry`
Georges Racinet <georges.racinet@octobus.net>
parents: 50410
diff changeset
129 /// This allows the caller to access the information that is common
841b13e6e84c rust-changelog: introducing an intermediate `ChangelogEntry`
Georges Racinet <georges.racinet@octobus.net>
parents: 50410
diff changeset
130 /// to all revlog entries: revision number, node id, parent revisions etc.
841b13e6e84c rust-changelog: introducing an intermediate `ChangelogEntry`
Georges Racinet <georges.racinet@octobus.net>
parents: 50410
diff changeset
131 pub fn as_revlog_entry(&self) -> &RevlogEntry {
841b13e6e84c rust-changelog: introducing an intermediate `ChangelogEntry`
Georges Racinet <georges.racinet@octobus.net>
parents: 50410
diff changeset
132 &self.revlog_entry
841b13e6e84c rust-changelog: introducing an intermediate `ChangelogEntry`
Georges Racinet <georges.racinet@octobus.net>
parents: 50410
diff changeset
133 }
50414
071a6c1d291e rust-changelog: introduce ChangelogEntry parent entries accessors
Georges Racinet <georges.racinet@octobus.net>
parents: 50411
diff changeset
134
071a6c1d291e rust-changelog: introduce ChangelogEntry parent entries accessors
Georges Racinet <georges.racinet@octobus.net>
parents: 50411
diff changeset
135 pub fn p1_entry(&self) -> Result<Option<ChangelogEntry>, RevlogError> {
071a6c1d291e rust-changelog: introduce ChangelogEntry parent entries accessors
Georges Racinet <georges.racinet@octobus.net>
parents: 50411
diff changeset
136 Ok(self
071a6c1d291e rust-changelog: introduce ChangelogEntry parent entries accessors
Georges Racinet <georges.racinet@octobus.net>
parents: 50411
diff changeset
137 .revlog_entry
071a6c1d291e rust-changelog: introduce ChangelogEntry parent entries accessors
Georges Racinet <georges.racinet@octobus.net>
parents: 50411
diff changeset
138 .p1_entry()?
071a6c1d291e rust-changelog: introduce ChangelogEntry parent entries accessors
Georges Racinet <georges.racinet@octobus.net>
parents: 50411
diff changeset
139 .map(|revlog_entry| Self { revlog_entry }))
071a6c1d291e rust-changelog: introduce ChangelogEntry parent entries accessors
Georges Racinet <georges.racinet@octobus.net>
parents: 50411
diff changeset
140 }
071a6c1d291e rust-changelog: introduce ChangelogEntry parent entries accessors
Georges Racinet <georges.racinet@octobus.net>
parents: 50411
diff changeset
141
071a6c1d291e rust-changelog: introduce ChangelogEntry parent entries accessors
Georges Racinet <georges.racinet@octobus.net>
parents: 50411
diff changeset
142 pub fn p2_entry(&self) -> Result<Option<ChangelogEntry>, RevlogError> {
071a6c1d291e rust-changelog: introduce ChangelogEntry parent entries accessors
Georges Racinet <georges.racinet@octobus.net>
parents: 50411
diff changeset
143 Ok(self
071a6c1d291e rust-changelog: introduce ChangelogEntry parent entries accessors
Georges Racinet <georges.racinet@octobus.net>
parents: 50411
diff changeset
144 .revlog_entry
071a6c1d291e rust-changelog: introduce ChangelogEntry parent entries accessors
Georges Racinet <georges.racinet@octobus.net>
parents: 50411
diff changeset
145 .p2_entry()?
071a6c1d291e rust-changelog: introduce ChangelogEntry parent entries accessors
Georges Racinet <georges.racinet@octobus.net>
parents: 50411
diff changeset
146 .map(|revlog_entry| Self { revlog_entry }))
071a6c1d291e rust-changelog: introduce ChangelogEntry parent entries accessors
Georges Racinet <georges.racinet@octobus.net>
parents: 50411
diff changeset
147 }
50411
841b13e6e84c rust-changelog: introducing an intermediate `ChangelogEntry`
Georges Racinet <georges.racinet@octobus.net>
parents: 50410
diff changeset
148 }
841b13e6e84c rust-changelog: introducing an intermediate `ChangelogEntry`
Georges Racinet <georges.racinet@octobus.net>
parents: 50410
diff changeset
149
45532
c2317b7624fd hg-core: add `Changlog` a specialized `Revlog`
Antoine Cezar <antoine.cezar@octobus.net>
parents:
diff changeset
150 /// `Changelog` entry which knows how to interpret the `changelog` data bytes.
49064
95da3e99cbd8 rust-changelog: start parsing changeset data
Martin von Zweigbergk <martinvonz@google.com>
parents: 49063
diff changeset
151 #[derive(PartialEq)]
49096
07ec9f4f24bf changelog: avoid copying changeset data into `ChangesetRevisionData`
Martin von Zweigbergk <martinvonz@google.com>
parents: 49090
diff changeset
152 pub struct ChangelogRevisionData<'changelog> {
45532
c2317b7624fd hg-core: add `Changlog` a specialized `Revlog`
Antoine Cezar <antoine.cezar@octobus.net>
parents:
diff changeset
153 /// The data bytes of the `changelog` entry.
49096
07ec9f4f24bf changelog: avoid copying changeset data into `ChangesetRevisionData`
Martin von Zweigbergk <martinvonz@google.com>
parents: 49090
diff changeset
154 bytes: Cow<'changelog, [u8]>,
49064
95da3e99cbd8 rust-changelog: start parsing changeset data
Martin von Zweigbergk <martinvonz@google.com>
parents: 49063
diff changeset
155 /// The end offset for the hex manifest (not including the newline)
95da3e99cbd8 rust-changelog: start parsing changeset data
Martin von Zweigbergk <martinvonz@google.com>
parents: 49063
diff changeset
156 manifest_end: usize,
95da3e99cbd8 rust-changelog: start parsing changeset data
Martin von Zweigbergk <martinvonz@google.com>
parents: 49063
diff changeset
157 /// The end offset for the user+email (not including the newline)
95da3e99cbd8 rust-changelog: start parsing changeset data
Martin von Zweigbergk <martinvonz@google.com>
parents: 49063
diff changeset
158 user_end: usize,
95da3e99cbd8 rust-changelog: start parsing changeset data
Martin von Zweigbergk <martinvonz@google.com>
parents: 49063
diff changeset
159 /// The end offset for the timestamp+timezone+extras (not including the
95da3e99cbd8 rust-changelog: start parsing changeset data
Martin von Zweigbergk <martinvonz@google.com>
parents: 49063
diff changeset
160 /// newline)
95da3e99cbd8 rust-changelog: start parsing changeset data
Martin von Zweigbergk <martinvonz@google.com>
parents: 49063
diff changeset
161 timestamp_end: usize,
95da3e99cbd8 rust-changelog: start parsing changeset data
Martin von Zweigbergk <martinvonz@google.com>
parents: 49063
diff changeset
162 /// The end offset for the file list (not including the newline)
95da3e99cbd8 rust-changelog: start parsing changeset data
Martin von Zweigbergk <martinvonz@google.com>
parents: 49063
diff changeset
163 files_end: usize,
45532
c2317b7624fd hg-core: add `Changlog` a specialized `Revlog`
Antoine Cezar <antoine.cezar@octobus.net>
parents:
diff changeset
164 }
c2317b7624fd hg-core: add `Changlog` a specialized `Revlog`
Antoine Cezar <antoine.cezar@octobus.net>
parents:
diff changeset
165
49096
07ec9f4f24bf changelog: avoid copying changeset data into `ChangesetRevisionData`
Martin von Zweigbergk <martinvonz@google.com>
parents: 49090
diff changeset
166 impl<'changelog> ChangelogRevisionData<'changelog> {
07ec9f4f24bf changelog: avoid copying changeset data into `ChangesetRevisionData`
Martin von Zweigbergk <martinvonz@google.com>
parents: 49090
diff changeset
167 fn new(bytes: Cow<'changelog, [u8]>) -> Result<Self, HgError> {
49064
95da3e99cbd8 rust-changelog: start parsing changeset data
Martin von Zweigbergk <martinvonz@google.com>
parents: 49063
diff changeset
168 let mut line_iter = bytes.split(|b| b == &b'\n');
95da3e99cbd8 rust-changelog: start parsing changeset data
Martin von Zweigbergk <martinvonz@google.com>
parents: 49063
diff changeset
169 let manifest_end = line_iter
95da3e99cbd8 rust-changelog: start parsing changeset data
Martin von Zweigbergk <martinvonz@google.com>
parents: 49063
diff changeset
170 .next()
95da3e99cbd8 rust-changelog: start parsing changeset data
Martin von Zweigbergk <martinvonz@google.com>
parents: 49063
diff changeset
171 .expect("Empty iterator from split()?")
95da3e99cbd8 rust-changelog: start parsing changeset data
Martin von Zweigbergk <martinvonz@google.com>
parents: 49063
diff changeset
172 .len();
95da3e99cbd8 rust-changelog: start parsing changeset data
Martin von Zweigbergk <martinvonz@google.com>
parents: 49063
diff changeset
173 let user_slice = line_iter.next().ok_or_else(|| {
95da3e99cbd8 rust-changelog: start parsing changeset data
Martin von Zweigbergk <martinvonz@google.com>
parents: 49063
diff changeset
174 HgError::corrupted("Changeset data truncated after manifest line")
95da3e99cbd8 rust-changelog: start parsing changeset data
Martin von Zweigbergk <martinvonz@google.com>
parents: 49063
diff changeset
175 })?;
95da3e99cbd8 rust-changelog: start parsing changeset data
Martin von Zweigbergk <martinvonz@google.com>
parents: 49063
diff changeset
176 let user_end = manifest_end + 1 + user_slice.len();
95da3e99cbd8 rust-changelog: start parsing changeset data
Martin von Zweigbergk <martinvonz@google.com>
parents: 49063
diff changeset
177 let timestamp_slice = line_iter.next().ok_or_else(|| {
95da3e99cbd8 rust-changelog: start parsing changeset data
Martin von Zweigbergk <martinvonz@google.com>
parents: 49063
diff changeset
178 HgError::corrupted("Changeset data truncated after user line")
95da3e99cbd8 rust-changelog: start parsing changeset data
Martin von Zweigbergk <martinvonz@google.com>
parents: 49063
diff changeset
179 })?;
95da3e99cbd8 rust-changelog: start parsing changeset data
Martin von Zweigbergk <martinvonz@google.com>
parents: 49063
diff changeset
180 let timestamp_end = user_end + 1 + timestamp_slice.len();
95da3e99cbd8 rust-changelog: start parsing changeset data
Martin von Zweigbergk <martinvonz@google.com>
parents: 49063
diff changeset
181 let mut files_end = timestamp_end + 1;
95da3e99cbd8 rust-changelog: start parsing changeset data
Martin von Zweigbergk <martinvonz@google.com>
parents: 49063
diff changeset
182 loop {
95da3e99cbd8 rust-changelog: start parsing changeset data
Martin von Zweigbergk <martinvonz@google.com>
parents: 49063
diff changeset
183 let line = line_iter.next().ok_or_else(|| {
95da3e99cbd8 rust-changelog: start parsing changeset data
Martin von Zweigbergk <martinvonz@google.com>
parents: 49063
diff changeset
184 HgError::corrupted("Changeset data truncated in files list")
95da3e99cbd8 rust-changelog: start parsing changeset data
Martin von Zweigbergk <martinvonz@google.com>
parents: 49063
diff changeset
185 })?;
95da3e99cbd8 rust-changelog: start parsing changeset data
Martin von Zweigbergk <martinvonz@google.com>
parents: 49063
diff changeset
186 if line.is_empty() {
95da3e99cbd8 rust-changelog: start parsing changeset data
Martin von Zweigbergk <martinvonz@google.com>
parents: 49063
diff changeset
187 if files_end == bytes.len() {
95da3e99cbd8 rust-changelog: start parsing changeset data
Martin von Zweigbergk <martinvonz@google.com>
parents: 49063
diff changeset
188 // The list of files ended with a single newline (there
95da3e99cbd8 rust-changelog: start parsing changeset data
Martin von Zweigbergk <martinvonz@google.com>
parents: 49063
diff changeset
189 // should be two)
95da3e99cbd8 rust-changelog: start parsing changeset data
Martin von Zweigbergk <martinvonz@google.com>
parents: 49063
diff changeset
190 return Err(HgError::corrupted(
95da3e99cbd8 rust-changelog: start parsing changeset data
Martin von Zweigbergk <martinvonz@google.com>
parents: 49063
diff changeset
191 "Changeset data truncated after files list",
95da3e99cbd8 rust-changelog: start parsing changeset data
Martin von Zweigbergk <martinvonz@google.com>
parents: 49063
diff changeset
192 ));
95da3e99cbd8 rust-changelog: start parsing changeset data
Martin von Zweigbergk <martinvonz@google.com>
parents: 49063
diff changeset
193 }
95da3e99cbd8 rust-changelog: start parsing changeset data
Martin von Zweigbergk <martinvonz@google.com>
parents: 49063
diff changeset
194 files_end -= 1;
95da3e99cbd8 rust-changelog: start parsing changeset data
Martin von Zweigbergk <martinvonz@google.com>
parents: 49063
diff changeset
195 break;
95da3e99cbd8 rust-changelog: start parsing changeset data
Martin von Zweigbergk <martinvonz@google.com>
parents: 49063
diff changeset
196 }
95da3e99cbd8 rust-changelog: start parsing changeset data
Martin von Zweigbergk <martinvonz@google.com>
parents: 49063
diff changeset
197 files_end += line.len() + 1;
95da3e99cbd8 rust-changelog: start parsing changeset data
Martin von Zweigbergk <martinvonz@google.com>
parents: 49063
diff changeset
198 }
95da3e99cbd8 rust-changelog: start parsing changeset data
Martin von Zweigbergk <martinvonz@google.com>
parents: 49063
diff changeset
199
95da3e99cbd8 rust-changelog: start parsing changeset data
Martin von Zweigbergk <martinvonz@google.com>
parents: 49063
diff changeset
200 Ok(Self {
95da3e99cbd8 rust-changelog: start parsing changeset data
Martin von Zweigbergk <martinvonz@google.com>
parents: 49063
diff changeset
201 bytes,
95da3e99cbd8 rust-changelog: start parsing changeset data
Martin von Zweigbergk <martinvonz@google.com>
parents: 49063
diff changeset
202 manifest_end,
95da3e99cbd8 rust-changelog: start parsing changeset data
Martin von Zweigbergk <martinvonz@google.com>
parents: 49063
diff changeset
203 user_end,
95da3e99cbd8 rust-changelog: start parsing changeset data
Martin von Zweigbergk <martinvonz@google.com>
parents: 49063
diff changeset
204 timestamp_end,
95da3e99cbd8 rust-changelog: start parsing changeset data
Martin von Zweigbergk <martinvonz@google.com>
parents: 49063
diff changeset
205 files_end,
95da3e99cbd8 rust-changelog: start parsing changeset data
Martin von Zweigbergk <martinvonz@google.com>
parents: 49063
diff changeset
206 })
49063
cc132255261b rust-changelog: remove special parsing of empty changelog data for null rev
Martin von Zweigbergk <martinvonz@google.com>
parents: 49062
diff changeset
207 }
cc132255261b rust-changelog: remove special parsing of empty changelog data for null rev
Martin von Zweigbergk <martinvonz@google.com>
parents: 49062
diff changeset
208
cc132255261b rust-changelog: remove special parsing of empty changelog data for null rev
Martin von Zweigbergk <martinvonz@google.com>
parents: 49062
diff changeset
209 fn null() -> Self {
49096
07ec9f4f24bf changelog: avoid copying changeset data into `ChangesetRevisionData`
Martin von Zweigbergk <martinvonz@google.com>
parents: 49090
diff changeset
210 Self::new(Cow::Borrowed(
07ec9f4f24bf changelog: avoid copying changeset data into `ChangesetRevisionData`
Martin von Zweigbergk <martinvonz@google.com>
parents: 49090
diff changeset
211 b"0000000000000000000000000000000000000000\n\n0 0\n\n",
07ec9f4f24bf changelog: avoid copying changeset data into `ChangesetRevisionData`
Martin von Zweigbergk <martinvonz@google.com>
parents: 49090
diff changeset
212 ))
49064
95da3e99cbd8 rust-changelog: start parsing changeset data
Martin von Zweigbergk <martinvonz@google.com>
parents: 49063
diff changeset
213 .unwrap()
49063
cc132255261b rust-changelog: remove special parsing of empty changelog data for null rev
Martin von Zweigbergk <martinvonz@google.com>
parents: 49062
diff changeset
214 }
cc132255261b rust-changelog: remove special parsing of empty changelog data for null rev
Martin von Zweigbergk <martinvonz@google.com>
parents: 49062
diff changeset
215
45532
c2317b7624fd hg-core: add `Changlog` a specialized `Revlog`
Antoine Cezar <antoine.cezar@octobus.net>
parents:
diff changeset
216 /// Return an iterator over the lines of the entry.
c2317b7624fd hg-core: add `Changlog` a specialized `Revlog`
Antoine Cezar <antoine.cezar@octobus.net>
parents:
diff changeset
217 pub fn lines(&self) -> impl Iterator<Item = &[u8]> {
49062
fb82b5cb8301 rust-changelog: don't skip empty lines when iterating over changeset lines
Martin von Zweigbergk <martinvonz@google.com>
parents: 48541
diff changeset
218 self.bytes.split(|b| b == &b'\n')
45532
c2317b7624fd hg-core: add `Changlog` a specialized `Revlog`
Antoine Cezar <antoine.cezar@octobus.net>
parents:
diff changeset
219 }
c2317b7624fd hg-core: add `Changlog` a specialized `Revlog`
Antoine Cezar <antoine.cezar@octobus.net>
parents:
diff changeset
220
c2317b7624fd hg-core: add `Changlog` a specialized `Revlog`
Antoine Cezar <antoine.cezar@octobus.net>
parents:
diff changeset
221 /// Return the node id of the `manifest` referenced by this `changelog`
c2317b7624fd hg-core: add `Changlog` a specialized `Revlog`
Antoine Cezar <antoine.cezar@octobus.net>
parents:
diff changeset
222 /// entry.
47964
796206e74b10 rhg: Reuse manifest when checking status of multiple ambiguous files
Simon Sapin <simon.sapin@octobus.net>
parents: 47963
diff changeset
223 pub fn manifest_node(&self) -> Result<Node, HgError> {
49064
95da3e99cbd8 rust-changelog: start parsing changeset data
Martin von Zweigbergk <martinvonz@google.com>
parents: 49063
diff changeset
224 let manifest_node_hex = &self.bytes[..self.manifest_end];
49063
cc132255261b rust-changelog: remove special parsing of empty changelog data for null rev
Martin von Zweigbergk <martinvonz@google.com>
parents: 49062
diff changeset
225 Node::from_hex_for_repo(manifest_node_hex)
45532
c2317b7624fd hg-core: add `Changlog` a specialized `Revlog`
Antoine Cezar <antoine.cezar@octobus.net>
parents:
diff changeset
226 }
49064
95da3e99cbd8 rust-changelog: start parsing changeset data
Martin von Zweigbergk <martinvonz@google.com>
parents: 49063
diff changeset
227
95da3e99cbd8 rust-changelog: start parsing changeset data
Martin von Zweigbergk <martinvonz@google.com>
parents: 49063
diff changeset
228 /// The full user string (usually a name followed by an email enclosed in
95da3e99cbd8 rust-changelog: start parsing changeset data
Martin von Zweigbergk <martinvonz@google.com>
parents: 49063
diff changeset
229 /// angle brackets)
95da3e99cbd8 rust-changelog: start parsing changeset data
Martin von Zweigbergk <martinvonz@google.com>
parents: 49063
diff changeset
230 pub fn user(&self) -> &[u8] {
95da3e99cbd8 rust-changelog: start parsing changeset data
Martin von Zweigbergk <martinvonz@google.com>
parents: 49063
diff changeset
231 &self.bytes[self.manifest_end + 1..self.user_end]
95da3e99cbd8 rust-changelog: start parsing changeset data
Martin von Zweigbergk <martinvonz@google.com>
parents: 49063
diff changeset
232 }
95da3e99cbd8 rust-changelog: start parsing changeset data
Martin von Zweigbergk <martinvonz@google.com>
parents: 49063
diff changeset
233
95da3e99cbd8 rust-changelog: start parsing changeset data
Martin von Zweigbergk <martinvonz@google.com>
parents: 49063
diff changeset
234 /// The full timestamp line (timestamp in seconds, offset in seconds, and
95da3e99cbd8 rust-changelog: start parsing changeset data
Martin von Zweigbergk <martinvonz@google.com>
parents: 49063
diff changeset
235 /// possibly extras)
95da3e99cbd8 rust-changelog: start parsing changeset data
Martin von Zweigbergk <martinvonz@google.com>
parents: 49063
diff changeset
236 // TODO: We should expose this in a more useful way
95da3e99cbd8 rust-changelog: start parsing changeset data
Martin von Zweigbergk <martinvonz@google.com>
parents: 49063
diff changeset
237 pub fn timestamp_line(&self) -> &[u8] {
95da3e99cbd8 rust-changelog: start parsing changeset data
Martin von Zweigbergk <martinvonz@google.com>
parents: 49063
diff changeset
238 &self.bytes[self.user_end + 1..self.timestamp_end]
95da3e99cbd8 rust-changelog: start parsing changeset data
Martin von Zweigbergk <martinvonz@google.com>
parents: 49063
diff changeset
239 }
95da3e99cbd8 rust-changelog: start parsing changeset data
Martin von Zweigbergk <martinvonz@google.com>
parents: 49063
diff changeset
240
51393
6603a1448f18 hg-core: separate timestamp and extra methods
Arun Kulshreshtha <akulshreshtha@janestreet.com>
parents: 51391
diff changeset
241 /// Parsed timestamp.
6603a1448f18 hg-core: separate timestamp and extra methods
Arun Kulshreshtha <akulshreshtha@janestreet.com>
parents: 51391
diff changeset
242 pub fn timestamp(&self) -> Result<DateTime<FixedOffset>, HgError> {
6603a1448f18 hg-core: separate timestamp and extra methods
Arun Kulshreshtha <akulshreshtha@janestreet.com>
parents: 51391
diff changeset
243 parse_timestamp(self.timestamp_line())
6603a1448f18 hg-core: separate timestamp and extra methods
Arun Kulshreshtha <akulshreshtha@janestreet.com>
parents: 51391
diff changeset
244 }
6603a1448f18 hg-core: separate timestamp and extra methods
Arun Kulshreshtha <akulshreshtha@janestreet.com>
parents: 51391
diff changeset
245
6603a1448f18 hg-core: separate timestamp and extra methods
Arun Kulshreshtha <akulshreshtha@janestreet.com>
parents: 51391
diff changeset
246 /// Optional commit extras.
6603a1448f18 hg-core: separate timestamp and extra methods
Arun Kulshreshtha <akulshreshtha@janestreet.com>
parents: 51391
diff changeset
247 pub fn extra(&self) -> Result<BTreeMap<String, Vec<u8>>, HgError> {
6603a1448f18 hg-core: separate timestamp and extra methods
Arun Kulshreshtha <akulshreshtha@janestreet.com>
parents: 51391
diff changeset
248 parse_timestamp_line_extra(self.timestamp_line())
51391
a96ed440450e hg-core: implement timestamp line parsing
Arun Kulshreshtha <akulshreshtha@janestreet.com>
parents: 51369
diff changeset
249 }
a96ed440450e hg-core: implement timestamp line parsing
Arun Kulshreshtha <akulshreshtha@janestreet.com>
parents: 51369
diff changeset
250
49064
95da3e99cbd8 rust-changelog: start parsing changeset data
Martin von Zweigbergk <martinvonz@google.com>
parents: 49063
diff changeset
251 /// The files changed in this revision.
95da3e99cbd8 rust-changelog: start parsing changeset data
Martin von Zweigbergk <martinvonz@google.com>
parents: 49063
diff changeset
252 pub fn files(&self) -> impl Iterator<Item = &HgPath> {
51363
d626e5e7bbbe rust-changelog: don't panic on empty file lists
Arun Kulshreshtha <akulshreshtha@janestreet.com>
parents: 50978
diff changeset
253 if self.timestamp_end == self.files_end {
d626e5e7bbbe rust-changelog: don't panic on empty file lists
Arun Kulshreshtha <akulshreshtha@janestreet.com>
parents: 50978
diff changeset
254 Either::Left(iter::empty())
d626e5e7bbbe rust-changelog: don't panic on empty file lists
Arun Kulshreshtha <akulshreshtha@janestreet.com>
parents: 50978
diff changeset
255 } else {
d626e5e7bbbe rust-changelog: don't panic on empty file lists
Arun Kulshreshtha <akulshreshtha@janestreet.com>
parents: 50978
diff changeset
256 Either::Right(
d626e5e7bbbe rust-changelog: don't panic on empty file lists
Arun Kulshreshtha <akulshreshtha@janestreet.com>
parents: 50978
diff changeset
257 self.bytes[self.timestamp_end + 1..self.files_end]
d626e5e7bbbe rust-changelog: don't panic on empty file lists
Arun Kulshreshtha <akulshreshtha@janestreet.com>
parents: 50978
diff changeset
258 .split(|b| b == &b'\n')
d626e5e7bbbe rust-changelog: don't panic on empty file lists
Arun Kulshreshtha <akulshreshtha@janestreet.com>
parents: 50978
diff changeset
259 .map(HgPath::new),
d626e5e7bbbe rust-changelog: don't panic on empty file lists
Arun Kulshreshtha <akulshreshtha@janestreet.com>
parents: 50978
diff changeset
260 )
d626e5e7bbbe rust-changelog: don't panic on empty file lists
Arun Kulshreshtha <akulshreshtha@janestreet.com>
parents: 50978
diff changeset
261 }
49064
95da3e99cbd8 rust-changelog: start parsing changeset data
Martin von Zweigbergk <martinvonz@google.com>
parents: 49063
diff changeset
262 }
95da3e99cbd8 rust-changelog: start parsing changeset data
Martin von Zweigbergk <martinvonz@google.com>
parents: 49063
diff changeset
263
95da3e99cbd8 rust-changelog: start parsing changeset data
Martin von Zweigbergk <martinvonz@google.com>
parents: 49063
diff changeset
264 /// The change description.
95da3e99cbd8 rust-changelog: start parsing changeset data
Martin von Zweigbergk <martinvonz@google.com>
parents: 49063
diff changeset
265 pub fn description(&self) -> &[u8] {
95da3e99cbd8 rust-changelog: start parsing changeset data
Martin von Zweigbergk <martinvonz@google.com>
parents: 49063
diff changeset
266 &self.bytes[self.files_end + 2..]
95da3e99cbd8 rust-changelog: start parsing changeset data
Martin von Zweigbergk <martinvonz@google.com>
parents: 49063
diff changeset
267 }
45532
c2317b7624fd hg-core: add `Changlog` a specialized `Revlog`
Antoine Cezar <antoine.cezar@octobus.net>
parents:
diff changeset
268 }
49064
95da3e99cbd8 rust-changelog: start parsing changeset data
Martin von Zweigbergk <martinvonz@google.com>
parents: 49063
diff changeset
269
49096
07ec9f4f24bf changelog: avoid copying changeset data into `ChangesetRevisionData`
Martin von Zweigbergk <martinvonz@google.com>
parents: 49090
diff changeset
270 impl Debug for ChangelogRevisionData<'_> {
49064
95da3e99cbd8 rust-changelog: start parsing changeset data
Martin von Zweigbergk <martinvonz@google.com>
parents: 49063
diff changeset
271 fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result {
95da3e99cbd8 rust-changelog: start parsing changeset data
Martin von Zweigbergk <martinvonz@google.com>
parents: 49063
diff changeset
272 f.debug_struct("ChangelogRevisionData")
95da3e99cbd8 rust-changelog: start parsing changeset data
Martin von Zweigbergk <martinvonz@google.com>
parents: 49063
diff changeset
273 .field("bytes", &debug_bytes(&self.bytes))
95da3e99cbd8 rust-changelog: start parsing changeset data
Martin von Zweigbergk <martinvonz@google.com>
parents: 49063
diff changeset
274 .field("manifest", &debug_bytes(&self.bytes[..self.manifest_end]))
95da3e99cbd8 rust-changelog: start parsing changeset data
Martin von Zweigbergk <martinvonz@google.com>
parents: 49063
diff changeset
275 .field(
95da3e99cbd8 rust-changelog: start parsing changeset data
Martin von Zweigbergk <martinvonz@google.com>
parents: 49063
diff changeset
276 "user",
95da3e99cbd8 rust-changelog: start parsing changeset data
Martin von Zweigbergk <martinvonz@google.com>
parents: 49063
diff changeset
277 &debug_bytes(
95da3e99cbd8 rust-changelog: start parsing changeset data
Martin von Zweigbergk <martinvonz@google.com>
parents: 49063
diff changeset
278 &self.bytes[self.manifest_end + 1..self.user_end],
95da3e99cbd8 rust-changelog: start parsing changeset data
Martin von Zweigbergk <martinvonz@google.com>
parents: 49063
diff changeset
279 ),
95da3e99cbd8 rust-changelog: start parsing changeset data
Martin von Zweigbergk <martinvonz@google.com>
parents: 49063
diff changeset
280 )
95da3e99cbd8 rust-changelog: start parsing changeset data
Martin von Zweigbergk <martinvonz@google.com>
parents: 49063
diff changeset
281 .field(
95da3e99cbd8 rust-changelog: start parsing changeset data
Martin von Zweigbergk <martinvonz@google.com>
parents: 49063
diff changeset
282 "timestamp",
95da3e99cbd8 rust-changelog: start parsing changeset data
Martin von Zweigbergk <martinvonz@google.com>
parents: 49063
diff changeset
283 &debug_bytes(
95da3e99cbd8 rust-changelog: start parsing changeset data
Martin von Zweigbergk <martinvonz@google.com>
parents: 49063
diff changeset
284 &self.bytes[self.user_end + 1..self.timestamp_end],
95da3e99cbd8 rust-changelog: start parsing changeset data
Martin von Zweigbergk <martinvonz@google.com>
parents: 49063
diff changeset
285 ),
95da3e99cbd8 rust-changelog: start parsing changeset data
Martin von Zweigbergk <martinvonz@google.com>
parents: 49063
diff changeset
286 )
95da3e99cbd8 rust-changelog: start parsing changeset data
Martin von Zweigbergk <martinvonz@google.com>
parents: 49063
diff changeset
287 .field(
95da3e99cbd8 rust-changelog: start parsing changeset data
Martin von Zweigbergk <martinvonz@google.com>
parents: 49063
diff changeset
288 "files",
95da3e99cbd8 rust-changelog: start parsing changeset data
Martin von Zweigbergk <martinvonz@google.com>
parents: 49063
diff changeset
289 &debug_bytes(
95da3e99cbd8 rust-changelog: start parsing changeset data
Martin von Zweigbergk <martinvonz@google.com>
parents: 49063
diff changeset
290 &self.bytes[self.timestamp_end + 1..self.files_end],
95da3e99cbd8 rust-changelog: start parsing changeset data
Martin von Zweigbergk <martinvonz@google.com>
parents: 49063
diff changeset
291 ),
95da3e99cbd8 rust-changelog: start parsing changeset data
Martin von Zweigbergk <martinvonz@google.com>
parents: 49063
diff changeset
292 )
95da3e99cbd8 rust-changelog: start parsing changeset data
Martin von Zweigbergk <martinvonz@google.com>
parents: 49063
diff changeset
293 .field(
95da3e99cbd8 rust-changelog: start parsing changeset data
Martin von Zweigbergk <martinvonz@google.com>
parents: 49063
diff changeset
294 "description",
95da3e99cbd8 rust-changelog: start parsing changeset data
Martin von Zweigbergk <martinvonz@google.com>
parents: 49063
diff changeset
295 &debug_bytes(&self.bytes[self.files_end + 2..]),
95da3e99cbd8 rust-changelog: start parsing changeset data
Martin von Zweigbergk <martinvonz@google.com>
parents: 49063
diff changeset
296 )
95da3e99cbd8 rust-changelog: start parsing changeset data
Martin von Zweigbergk <martinvonz@google.com>
parents: 49063
diff changeset
297 .finish()
95da3e99cbd8 rust-changelog: start parsing changeset data
Martin von Zweigbergk <martinvonz@google.com>
parents: 49063
diff changeset
298 }
95da3e99cbd8 rust-changelog: start parsing changeset data
Martin von Zweigbergk <martinvonz@google.com>
parents: 49063
diff changeset
299 }
95da3e99cbd8 rust-changelog: start parsing changeset data
Martin von Zweigbergk <martinvonz@google.com>
parents: 49063
diff changeset
300
95da3e99cbd8 rust-changelog: start parsing changeset data
Martin von Zweigbergk <martinvonz@google.com>
parents: 49063
diff changeset
301 fn debug_bytes(bytes: &[u8]) -> String {
95da3e99cbd8 rust-changelog: start parsing changeset data
Martin von Zweigbergk <martinvonz@google.com>
parents: 49063
diff changeset
302 String::from_utf8_lossy(
95da3e99cbd8 rust-changelog: start parsing changeset data
Martin von Zweigbergk <martinvonz@google.com>
parents: 49063
diff changeset
303 &bytes.iter().flat_map(|b| escape_default(*b)).collect_vec(),
95da3e99cbd8 rust-changelog: start parsing changeset data
Martin von Zweigbergk <martinvonz@google.com>
parents: 49063
diff changeset
304 )
95da3e99cbd8 rust-changelog: start parsing changeset data
Martin von Zweigbergk <martinvonz@google.com>
parents: 49063
diff changeset
305 .to_string()
95da3e99cbd8 rust-changelog: start parsing changeset data
Martin von Zweigbergk <martinvonz@google.com>
parents: 49063
diff changeset
306 }
95da3e99cbd8 rust-changelog: start parsing changeset data
Martin von Zweigbergk <martinvonz@google.com>
parents: 49063
diff changeset
307
51393
6603a1448f18 hg-core: separate timestamp and extra methods
Arun Kulshreshtha <akulshreshtha@janestreet.com>
parents: 51391
diff changeset
308 /// Parse the raw bytes of the timestamp line from a changelog entry.
6603a1448f18 hg-core: separate timestamp and extra methods
Arun Kulshreshtha <akulshreshtha@janestreet.com>
parents: 51391
diff changeset
309 ///
6603a1448f18 hg-core: separate timestamp and extra methods
Arun Kulshreshtha <akulshreshtha@janestreet.com>
parents: 51391
diff changeset
310 /// According to the documentation in `hg help dates` and the
6603a1448f18 hg-core: separate timestamp and extra methods
Arun Kulshreshtha <akulshreshtha@janestreet.com>
parents: 51391
diff changeset
311 /// implementation in `changelog.py`, the format of the timestamp line
6603a1448f18 hg-core: separate timestamp and extra methods
Arun Kulshreshtha <akulshreshtha@janestreet.com>
parents: 51391
diff changeset
312 /// is `time tz extra\n` where:
6603a1448f18 hg-core: separate timestamp and extra methods
Arun Kulshreshtha <akulshreshtha@janestreet.com>
parents: 51391
diff changeset
313 ///
6603a1448f18 hg-core: separate timestamp and extra methods
Arun Kulshreshtha <akulshreshtha@janestreet.com>
parents: 51391
diff changeset
314 /// - `time` is an ASCII-encoded signed int or float denoting a UTC timestamp
6603a1448f18 hg-core: separate timestamp and extra methods
Arun Kulshreshtha <akulshreshtha@janestreet.com>
parents: 51391
diff changeset
315 /// as seconds since the UNIX epoch.
6603a1448f18 hg-core: separate timestamp and extra methods
Arun Kulshreshtha <akulshreshtha@janestreet.com>
parents: 51391
diff changeset
316 ///
6603a1448f18 hg-core: separate timestamp and extra methods
Arun Kulshreshtha <akulshreshtha@janestreet.com>
parents: 51391
diff changeset
317 /// - `tz` is the timezone offset as an ASCII-encoded signed integer denoting
6603a1448f18 hg-core: separate timestamp and extra methods
Arun Kulshreshtha <akulshreshtha@janestreet.com>
parents: 51391
diff changeset
318 /// seconds WEST of UTC (so negative for timezones east of UTC, which is the
6603a1448f18 hg-core: separate timestamp and extra methods
Arun Kulshreshtha <akulshreshtha@janestreet.com>
parents: 51391
diff changeset
319 /// opposite of the sign in ISO 8601 timestamps).
6603a1448f18 hg-core: separate timestamp and extra methods
Arun Kulshreshtha <akulshreshtha@janestreet.com>
parents: 51391
diff changeset
320 ///
6603a1448f18 hg-core: separate timestamp and extra methods
Arun Kulshreshtha <akulshreshtha@janestreet.com>
parents: 51391
diff changeset
321 /// - `extra` is an optional set of NUL-delimited key-value pairs, with the key
6603a1448f18 hg-core: separate timestamp and extra methods
Arun Kulshreshtha <akulshreshtha@janestreet.com>
parents: 51391
diff changeset
322 /// and value in each pair separated by an ASCII colon. Keys are limited to
6603a1448f18 hg-core: separate timestamp and extra methods
Arun Kulshreshtha <akulshreshtha@janestreet.com>
parents: 51391
diff changeset
323 /// ASCII letters, digits, hyphens, and underscores, whereas values can be
6603a1448f18 hg-core: separate timestamp and extra methods
Arun Kulshreshtha <akulshreshtha@janestreet.com>
parents: 51391
diff changeset
324 /// arbitrary bytes.
6603a1448f18 hg-core: separate timestamp and extra methods
Arun Kulshreshtha <akulshreshtha@janestreet.com>
parents: 51391
diff changeset
325 fn parse_timestamp(
6603a1448f18 hg-core: separate timestamp and extra methods
Arun Kulshreshtha <akulshreshtha@janestreet.com>
parents: 51391
diff changeset
326 timestamp_line: &[u8],
6603a1448f18 hg-core: separate timestamp and extra methods
Arun Kulshreshtha <akulshreshtha@janestreet.com>
parents: 51391
diff changeset
327 ) -> Result<DateTime<FixedOffset>, HgError> {
6603a1448f18 hg-core: separate timestamp and extra methods
Arun Kulshreshtha <akulshreshtha@janestreet.com>
parents: 51391
diff changeset
328 let mut parts = timestamp_line.splitn(3, |c| *c == b' ');
51391
a96ed440450e hg-core: implement timestamp line parsing
Arun Kulshreshtha <akulshreshtha@janestreet.com>
parents: 51369
diff changeset
329
51393
6603a1448f18 hg-core: separate timestamp and extra methods
Arun Kulshreshtha <akulshreshtha@janestreet.com>
parents: 51391
diff changeset
330 let timestamp_bytes = parts
6603a1448f18 hg-core: separate timestamp and extra methods
Arun Kulshreshtha <akulshreshtha@janestreet.com>
parents: 51391
diff changeset
331 .next()
6603a1448f18 hg-core: separate timestamp and extra methods
Arun Kulshreshtha <akulshreshtha@janestreet.com>
parents: 51391
diff changeset
332 .ok_or_else(|| HgError::corrupted("missing timestamp"))?;
6603a1448f18 hg-core: separate timestamp and extra methods
Arun Kulshreshtha <akulshreshtha@janestreet.com>
parents: 51391
diff changeset
333 let timestamp_str = str::from_utf8(timestamp_bytes).map_err(|e| {
6603a1448f18 hg-core: separate timestamp and extra methods
Arun Kulshreshtha <akulshreshtha@janestreet.com>
parents: 51391
diff changeset
334 HgError::corrupted(format!("timestamp is not valid UTF-8: {e}"))
6603a1448f18 hg-core: separate timestamp and extra methods
Arun Kulshreshtha <akulshreshtha@janestreet.com>
parents: 51391
diff changeset
335 })?;
6603a1448f18 hg-core: separate timestamp and extra methods
Arun Kulshreshtha <akulshreshtha@janestreet.com>
parents: 51391
diff changeset
336 let timestamp_utc = timestamp_str
6603a1448f18 hg-core: separate timestamp and extra methods
Arun Kulshreshtha <akulshreshtha@janestreet.com>
parents: 51391
diff changeset
337 .parse()
6603a1448f18 hg-core: separate timestamp and extra methods
Arun Kulshreshtha <akulshreshtha@janestreet.com>
parents: 51391
diff changeset
338 .map_err(|e| {
6603a1448f18 hg-core: separate timestamp and extra methods
Arun Kulshreshtha <akulshreshtha@janestreet.com>
parents: 51391
diff changeset
339 HgError::corrupted(format!("failed to parse timestamp: {e}"))
6603a1448f18 hg-core: separate timestamp and extra methods
Arun Kulshreshtha <akulshreshtha@janestreet.com>
parents: 51391
diff changeset
340 })
6603a1448f18 hg-core: separate timestamp and extra methods
Arun Kulshreshtha <akulshreshtha@janestreet.com>
parents: 51391
diff changeset
341 .and_then(|secs| {
6603a1448f18 hg-core: separate timestamp and extra methods
Arun Kulshreshtha <akulshreshtha@janestreet.com>
parents: 51391
diff changeset
342 NaiveDateTime::from_timestamp_opt(secs, 0).ok_or_else(|| {
6603a1448f18 hg-core: separate timestamp and extra methods
Arun Kulshreshtha <akulshreshtha@janestreet.com>
parents: 51391
diff changeset
343 HgError::corrupted(format!(
6603a1448f18 hg-core: separate timestamp and extra methods
Arun Kulshreshtha <akulshreshtha@janestreet.com>
parents: 51391
diff changeset
344 "integer timestamp out of valid range: {secs}"
6603a1448f18 hg-core: separate timestamp and extra methods
Arun Kulshreshtha <akulshreshtha@janestreet.com>
parents: 51391
diff changeset
345 ))
51391
a96ed440450e hg-core: implement timestamp line parsing
Arun Kulshreshtha <akulshreshtha@janestreet.com>
parents: 51369
diff changeset
346 })
51393
6603a1448f18 hg-core: separate timestamp and extra methods
Arun Kulshreshtha <akulshreshtha@janestreet.com>
parents: 51391
diff changeset
347 })
6603a1448f18 hg-core: separate timestamp and extra methods
Arun Kulshreshtha <akulshreshtha@janestreet.com>
parents: 51391
diff changeset
348 // Attempt to parse the timestamp as a float if we can't parse
6603a1448f18 hg-core: separate timestamp and extra methods
Arun Kulshreshtha <akulshreshtha@janestreet.com>
parents: 51391
diff changeset
349 // it as an int. It doesn't seem like float timestamps are actually
6603a1448f18 hg-core: separate timestamp and extra methods
Arun Kulshreshtha <akulshreshtha@janestreet.com>
parents: 51391
diff changeset
350 // used in practice, but the Python code supports them.
6603a1448f18 hg-core: separate timestamp and extra methods
Arun Kulshreshtha <akulshreshtha@janestreet.com>
parents: 51391
diff changeset
351 .or_else(|_| parse_float_timestamp(timestamp_str))?;
51391
a96ed440450e hg-core: implement timestamp line parsing
Arun Kulshreshtha <akulshreshtha@janestreet.com>
parents: 51369
diff changeset
352
51393
6603a1448f18 hg-core: separate timestamp and extra methods
Arun Kulshreshtha <akulshreshtha@janestreet.com>
parents: 51391
diff changeset
353 let timezone_bytes = parts
6603a1448f18 hg-core: separate timestamp and extra methods
Arun Kulshreshtha <akulshreshtha@janestreet.com>
parents: 51391
diff changeset
354 .next()
6603a1448f18 hg-core: separate timestamp and extra methods
Arun Kulshreshtha <akulshreshtha@janestreet.com>
parents: 51391
diff changeset
355 .ok_or_else(|| HgError::corrupted("missing timezone"))?;
6603a1448f18 hg-core: separate timestamp and extra methods
Arun Kulshreshtha <akulshreshtha@janestreet.com>
parents: 51391
diff changeset
356 let timezone_secs: i32 = str::from_utf8(timezone_bytes)
6603a1448f18 hg-core: separate timestamp and extra methods
Arun Kulshreshtha <akulshreshtha@janestreet.com>
parents: 51391
diff changeset
357 .map_err(|e| {
6603a1448f18 hg-core: separate timestamp and extra methods
Arun Kulshreshtha <akulshreshtha@janestreet.com>
parents: 51391
diff changeset
358 HgError::corrupted(format!("timezone is not valid UTF-8: {e}"))
6603a1448f18 hg-core: separate timestamp and extra methods
Arun Kulshreshtha <akulshreshtha@janestreet.com>
parents: 51391
diff changeset
359 })?
6603a1448f18 hg-core: separate timestamp and extra methods
Arun Kulshreshtha <akulshreshtha@janestreet.com>
parents: 51391
diff changeset
360 .parse()
6603a1448f18 hg-core: separate timestamp and extra methods
Arun Kulshreshtha <akulshreshtha@janestreet.com>
parents: 51391
diff changeset
361 .map_err(|e| {
6603a1448f18 hg-core: separate timestamp and extra methods
Arun Kulshreshtha <akulshreshtha@janestreet.com>
parents: 51391
diff changeset
362 HgError::corrupted(format!("timezone is not an integer: {e}"))
6603a1448f18 hg-core: separate timestamp and extra methods
Arun Kulshreshtha <akulshreshtha@janestreet.com>
parents: 51391
diff changeset
363 })?;
6603a1448f18 hg-core: separate timestamp and extra methods
Arun Kulshreshtha <akulshreshtha@janestreet.com>
parents: 51391
diff changeset
364 let timezone = FixedOffset::west_opt(timezone_secs)
6603a1448f18 hg-core: separate timestamp and extra methods
Arun Kulshreshtha <akulshreshtha@janestreet.com>
parents: 51391
diff changeset
365 .ok_or_else(|| HgError::corrupted("timezone offset out of bounds"))?;
51391
a96ed440450e hg-core: implement timestamp line parsing
Arun Kulshreshtha <akulshreshtha@janestreet.com>
parents: 51369
diff changeset
366
51393
6603a1448f18 hg-core: separate timestamp and extra methods
Arun Kulshreshtha <akulshreshtha@janestreet.com>
parents: 51391
diff changeset
367 Ok(DateTime::from_naive_utc_and_offset(timestamp_utc, timezone))
51391
a96ed440450e hg-core: implement timestamp line parsing
Arun Kulshreshtha <akulshreshtha@janestreet.com>
parents: 51369
diff changeset
368 }
a96ed440450e hg-core: implement timestamp line parsing
Arun Kulshreshtha <akulshreshtha@janestreet.com>
parents: 51369
diff changeset
369
a96ed440450e hg-core: implement timestamp line parsing
Arun Kulshreshtha <akulshreshtha@janestreet.com>
parents: 51369
diff changeset
370 /// Attempt to parse the given string as floating-point timestamp, and
a96ed440450e hg-core: implement timestamp line parsing
Arun Kulshreshtha <akulshreshtha@janestreet.com>
parents: 51369
diff changeset
371 /// convert the result into a `chrono::NaiveDateTime`.
a96ed440450e hg-core: implement timestamp line parsing
Arun Kulshreshtha <akulshreshtha@janestreet.com>
parents: 51369
diff changeset
372 fn parse_float_timestamp(
a96ed440450e hg-core: implement timestamp line parsing
Arun Kulshreshtha <akulshreshtha@janestreet.com>
parents: 51369
diff changeset
373 timestamp_str: &str,
a96ed440450e hg-core: implement timestamp line parsing
Arun Kulshreshtha <akulshreshtha@janestreet.com>
parents: 51369
diff changeset
374 ) -> Result<NaiveDateTime, HgError> {
a96ed440450e hg-core: implement timestamp line parsing
Arun Kulshreshtha <akulshreshtha@janestreet.com>
parents: 51369
diff changeset
375 let timestamp = timestamp_str.parse::<f64>().map_err(|e| {
a96ed440450e hg-core: implement timestamp line parsing
Arun Kulshreshtha <akulshreshtha@janestreet.com>
parents: 51369
diff changeset
376 HgError::corrupted(format!("failed to parse timestamp: {e}"))
a96ed440450e hg-core: implement timestamp line parsing
Arun Kulshreshtha <akulshreshtha@janestreet.com>
parents: 51369
diff changeset
377 })?;
a96ed440450e hg-core: implement timestamp line parsing
Arun Kulshreshtha <akulshreshtha@janestreet.com>
parents: 51369
diff changeset
378
a96ed440450e hg-core: implement timestamp line parsing
Arun Kulshreshtha <akulshreshtha@janestreet.com>
parents: 51369
diff changeset
379 // To construct a `NaiveDateTime` we'll need to convert the float
a96ed440450e hg-core: implement timestamp line parsing
Arun Kulshreshtha <akulshreshtha@janestreet.com>
parents: 51369
diff changeset
380 // into signed integer seconds and unsigned integer nanoseconds.
a96ed440450e hg-core: implement timestamp line parsing
Arun Kulshreshtha <akulshreshtha@janestreet.com>
parents: 51369
diff changeset
381 let mut secs = timestamp.trunc() as i64;
a96ed440450e hg-core: implement timestamp line parsing
Arun Kulshreshtha <akulshreshtha@janestreet.com>
parents: 51369
diff changeset
382 let mut subsecs = timestamp.fract();
a96ed440450e hg-core: implement timestamp line parsing
Arun Kulshreshtha <akulshreshtha@janestreet.com>
parents: 51369
diff changeset
383
a96ed440450e hg-core: implement timestamp line parsing
Arun Kulshreshtha <akulshreshtha@janestreet.com>
parents: 51369
diff changeset
384 // If the timestamp is negative, we need to express the fractional
a96ed440450e hg-core: implement timestamp line parsing
Arun Kulshreshtha <akulshreshtha@janestreet.com>
parents: 51369
diff changeset
385 // component as positive nanoseconds since the previous second.
a96ed440450e hg-core: implement timestamp line parsing
Arun Kulshreshtha <akulshreshtha@janestreet.com>
parents: 51369
diff changeset
386 if timestamp < 0.0 {
a96ed440450e hg-core: implement timestamp line parsing
Arun Kulshreshtha <akulshreshtha@janestreet.com>
parents: 51369
diff changeset
387 secs -= 1;
a96ed440450e hg-core: implement timestamp line parsing
Arun Kulshreshtha <akulshreshtha@janestreet.com>
parents: 51369
diff changeset
388 subsecs += 1.0;
a96ed440450e hg-core: implement timestamp line parsing
Arun Kulshreshtha <akulshreshtha@janestreet.com>
parents: 51369
diff changeset
389 }
a96ed440450e hg-core: implement timestamp line parsing
Arun Kulshreshtha <akulshreshtha@janestreet.com>
parents: 51369
diff changeset
390
a96ed440450e hg-core: implement timestamp line parsing
Arun Kulshreshtha <akulshreshtha@janestreet.com>
parents: 51369
diff changeset
391 // This cast should be safe because the fractional component is
a96ed440450e hg-core: implement timestamp line parsing
Arun Kulshreshtha <akulshreshtha@janestreet.com>
parents: 51369
diff changeset
392 // by definition less than 1.0, so this value should not exceed
a96ed440450e hg-core: implement timestamp line parsing
Arun Kulshreshtha <akulshreshtha@janestreet.com>
parents: 51369
diff changeset
393 // 1 billion, which is representable as an f64 without loss of
a96ed440450e hg-core: implement timestamp line parsing
Arun Kulshreshtha <akulshreshtha@janestreet.com>
parents: 51369
diff changeset
394 // precision and should fit into a u32 without overflowing.
a96ed440450e hg-core: implement timestamp line parsing
Arun Kulshreshtha <akulshreshtha@janestreet.com>
parents: 51369
diff changeset
395 //
a96ed440450e hg-core: implement timestamp line parsing
Arun Kulshreshtha <akulshreshtha@janestreet.com>
parents: 51369
diff changeset
396 // (Any loss of precision in the fractional component will have
a96ed440450e hg-core: implement timestamp line parsing
Arun Kulshreshtha <akulshreshtha@janestreet.com>
parents: 51369
diff changeset
397 // already happened at the time of initial parsing; in general,
a96ed440450e hg-core: implement timestamp line parsing
Arun Kulshreshtha <akulshreshtha@janestreet.com>
parents: 51369
diff changeset
398 // f64s are insufficiently precise to provide nanosecond-level
a96ed440450e hg-core: implement timestamp line parsing
Arun Kulshreshtha <akulshreshtha@janestreet.com>
parents: 51369
diff changeset
399 // precision with present-day timestamps.)
a96ed440450e hg-core: implement timestamp line parsing
Arun Kulshreshtha <akulshreshtha@janestreet.com>
parents: 51369
diff changeset
400 let nsecs = (subsecs * 1_000_000_000.0) as u32;
a96ed440450e hg-core: implement timestamp line parsing
Arun Kulshreshtha <akulshreshtha@janestreet.com>
parents: 51369
diff changeset
401
a96ed440450e hg-core: implement timestamp line parsing
Arun Kulshreshtha <akulshreshtha@janestreet.com>
parents: 51369
diff changeset
402 NaiveDateTime::from_timestamp_opt(secs, nsecs).ok_or_else(|| {
a96ed440450e hg-core: implement timestamp line parsing
Arun Kulshreshtha <akulshreshtha@janestreet.com>
parents: 51369
diff changeset
403 HgError::corrupted(format!(
a96ed440450e hg-core: implement timestamp line parsing
Arun Kulshreshtha <akulshreshtha@janestreet.com>
parents: 51369
diff changeset
404 "float timestamp out of valid range: {timestamp}"
a96ed440450e hg-core: implement timestamp line parsing
Arun Kulshreshtha <akulshreshtha@janestreet.com>
parents: 51369
diff changeset
405 ))
a96ed440450e hg-core: implement timestamp line parsing
Arun Kulshreshtha <akulshreshtha@janestreet.com>
parents: 51369
diff changeset
406 })
a96ed440450e hg-core: implement timestamp line parsing
Arun Kulshreshtha <akulshreshtha@janestreet.com>
parents: 51369
diff changeset
407 }
a96ed440450e hg-core: implement timestamp line parsing
Arun Kulshreshtha <akulshreshtha@janestreet.com>
parents: 51369
diff changeset
408
51393
6603a1448f18 hg-core: separate timestamp and extra methods
Arun Kulshreshtha <akulshreshtha@janestreet.com>
parents: 51391
diff changeset
409 /// Decode changeset extra fields.
51391
a96ed440450e hg-core: implement timestamp line parsing
Arun Kulshreshtha <akulshreshtha@janestreet.com>
parents: 51369
diff changeset
410 ///
a96ed440450e hg-core: implement timestamp line parsing
Arun Kulshreshtha <akulshreshtha@janestreet.com>
parents: 51369
diff changeset
411 /// Extras are null-delimited key-value pairs where the key consists of ASCII
a96ed440450e hg-core: implement timestamp line parsing
Arun Kulshreshtha <akulshreshtha@janestreet.com>
parents: 51369
diff changeset
412 /// alphanumeric characters plus hyphens and underscores, and the value can
a96ed440450e hg-core: implement timestamp line parsing
Arun Kulshreshtha <akulshreshtha@janestreet.com>
parents: 51369
diff changeset
413 /// contain arbitrary bytes.
51393
6603a1448f18 hg-core: separate timestamp and extra methods
Arun Kulshreshtha <akulshreshtha@janestreet.com>
parents: 51391
diff changeset
414 fn decode_extra(extra: &[u8]) -> Result<BTreeMap<String, Vec<u8>>, HgError> {
51391
a96ed440450e hg-core: implement timestamp line parsing
Arun Kulshreshtha <akulshreshtha@janestreet.com>
parents: 51369
diff changeset
415 extra
a96ed440450e hg-core: implement timestamp line parsing
Arun Kulshreshtha <akulshreshtha@janestreet.com>
parents: 51369
diff changeset
416 .split(|c| *c == b'\0')
a96ed440450e hg-core: implement timestamp line parsing
Arun Kulshreshtha <akulshreshtha@janestreet.com>
parents: 51369
diff changeset
417 .map(|pair| {
a96ed440450e hg-core: implement timestamp line parsing
Arun Kulshreshtha <akulshreshtha@janestreet.com>
parents: 51369
diff changeset
418 let pair = unescape_extra(pair);
a96ed440450e hg-core: implement timestamp line parsing
Arun Kulshreshtha <akulshreshtha@janestreet.com>
parents: 51369
diff changeset
419 let mut iter = pair.splitn(2, |c| *c == b':');
a96ed440450e hg-core: implement timestamp line parsing
Arun Kulshreshtha <akulshreshtha@janestreet.com>
parents: 51369
diff changeset
420
a96ed440450e hg-core: implement timestamp line parsing
Arun Kulshreshtha <akulshreshtha@janestreet.com>
parents: 51369
diff changeset
421 let key_bytes =
a96ed440450e hg-core: implement timestamp line parsing
Arun Kulshreshtha <akulshreshtha@janestreet.com>
parents: 51369
diff changeset
422 iter.next().filter(|k| !k.is_empty()).ok_or_else(|| {
a96ed440450e hg-core: implement timestamp line parsing
Arun Kulshreshtha <akulshreshtha@janestreet.com>
parents: 51369
diff changeset
423 HgError::corrupted("empty key in changeset extras")
a96ed440450e hg-core: implement timestamp line parsing
Arun Kulshreshtha <akulshreshtha@janestreet.com>
parents: 51369
diff changeset
424 })?;
a96ed440450e hg-core: implement timestamp line parsing
Arun Kulshreshtha <akulshreshtha@janestreet.com>
parents: 51369
diff changeset
425
a96ed440450e hg-core: implement timestamp line parsing
Arun Kulshreshtha <akulshreshtha@janestreet.com>
parents: 51369
diff changeset
426 let key = str::from_utf8(key_bytes)
a96ed440450e hg-core: implement timestamp line parsing
Arun Kulshreshtha <akulshreshtha@janestreet.com>
parents: 51369
diff changeset
427 .ok()
a96ed440450e hg-core: implement timestamp line parsing
Arun Kulshreshtha <akulshreshtha@janestreet.com>
parents: 51369
diff changeset
428 .filter(|k| {
a96ed440450e hg-core: implement timestamp line parsing
Arun Kulshreshtha <akulshreshtha@janestreet.com>
parents: 51369
diff changeset
429 k.chars().all(|c| {
a96ed440450e hg-core: implement timestamp line parsing
Arun Kulshreshtha <akulshreshtha@janestreet.com>
parents: 51369
diff changeset
430 c.is_ascii_alphanumeric() || c == '_' || c == '-'
a96ed440450e hg-core: implement timestamp line parsing
Arun Kulshreshtha <akulshreshtha@janestreet.com>
parents: 51369
diff changeset
431 })
a96ed440450e hg-core: implement timestamp line parsing
Arun Kulshreshtha <akulshreshtha@janestreet.com>
parents: 51369
diff changeset
432 })
a96ed440450e hg-core: implement timestamp line parsing
Arun Kulshreshtha <akulshreshtha@janestreet.com>
parents: 51369
diff changeset
433 .ok_or_else(|| {
a96ed440450e hg-core: implement timestamp line parsing
Arun Kulshreshtha <akulshreshtha@janestreet.com>
parents: 51369
diff changeset
434 let key = String::from_utf8_lossy(key_bytes);
a96ed440450e hg-core: implement timestamp line parsing
Arun Kulshreshtha <akulshreshtha@janestreet.com>
parents: 51369
diff changeset
435 HgError::corrupted(format!(
a96ed440450e hg-core: implement timestamp line parsing
Arun Kulshreshtha <akulshreshtha@janestreet.com>
parents: 51369
diff changeset
436 "invalid key in changeset extras: {key}",
a96ed440450e hg-core: implement timestamp line parsing
Arun Kulshreshtha <akulshreshtha@janestreet.com>
parents: 51369
diff changeset
437 ))
a96ed440450e hg-core: implement timestamp line parsing
Arun Kulshreshtha <akulshreshtha@janestreet.com>
parents: 51369
diff changeset
438 })?
a96ed440450e hg-core: implement timestamp line parsing
Arun Kulshreshtha <akulshreshtha@janestreet.com>
parents: 51369
diff changeset
439 .to_string();
a96ed440450e hg-core: implement timestamp line parsing
Arun Kulshreshtha <akulshreshtha@janestreet.com>
parents: 51369
diff changeset
440
a96ed440450e hg-core: implement timestamp line parsing
Arun Kulshreshtha <akulshreshtha@janestreet.com>
parents: 51369
diff changeset
441 let value = iter.next().map(Into::into).ok_or_else(|| {
a96ed440450e hg-core: implement timestamp line parsing
Arun Kulshreshtha <akulshreshtha@janestreet.com>
parents: 51369
diff changeset
442 HgError::corrupted(format!(
a96ed440450e hg-core: implement timestamp line parsing
Arun Kulshreshtha <akulshreshtha@janestreet.com>
parents: 51369
diff changeset
443 "missing value for changeset extra: {key}"
a96ed440450e hg-core: implement timestamp line parsing
Arun Kulshreshtha <akulshreshtha@janestreet.com>
parents: 51369
diff changeset
444 ))
a96ed440450e hg-core: implement timestamp line parsing
Arun Kulshreshtha <akulshreshtha@janestreet.com>
parents: 51369
diff changeset
445 })?;
a96ed440450e hg-core: implement timestamp line parsing
Arun Kulshreshtha <akulshreshtha@janestreet.com>
parents: 51369
diff changeset
446
a96ed440450e hg-core: implement timestamp line parsing
Arun Kulshreshtha <akulshreshtha@janestreet.com>
parents: 51369
diff changeset
447 Ok((key, value))
a96ed440450e hg-core: implement timestamp line parsing
Arun Kulshreshtha <akulshreshtha@janestreet.com>
parents: 51369
diff changeset
448 })
a96ed440450e hg-core: implement timestamp line parsing
Arun Kulshreshtha <akulshreshtha@janestreet.com>
parents: 51369
diff changeset
449 .collect()
a96ed440450e hg-core: implement timestamp line parsing
Arun Kulshreshtha <akulshreshtha@janestreet.com>
parents: 51369
diff changeset
450 }
a96ed440450e hg-core: implement timestamp line parsing
Arun Kulshreshtha <akulshreshtha@janestreet.com>
parents: 51369
diff changeset
451
51393
6603a1448f18 hg-core: separate timestamp and extra methods
Arun Kulshreshtha <akulshreshtha@janestreet.com>
parents: 51391
diff changeset
452 /// Parse the extra fields from a changeset's timestamp line.
6603a1448f18 hg-core: separate timestamp and extra methods
Arun Kulshreshtha <akulshreshtha@janestreet.com>
parents: 51391
diff changeset
453 fn parse_timestamp_line_extra(
6603a1448f18 hg-core: separate timestamp and extra methods
Arun Kulshreshtha <akulshreshtha@janestreet.com>
parents: 51391
diff changeset
454 timestamp_line: &[u8],
6603a1448f18 hg-core: separate timestamp and extra methods
Arun Kulshreshtha <akulshreshtha@janestreet.com>
parents: 51391
diff changeset
455 ) -> Result<BTreeMap<String, Vec<u8>>, HgError> {
6603a1448f18 hg-core: separate timestamp and extra methods
Arun Kulshreshtha <akulshreshtha@janestreet.com>
parents: 51391
diff changeset
456 Ok(timestamp_line
6603a1448f18 hg-core: separate timestamp and extra methods
Arun Kulshreshtha <akulshreshtha@janestreet.com>
parents: 51391
diff changeset
457 .splitn(3, |c| *c == b' ')
6603a1448f18 hg-core: separate timestamp and extra methods
Arun Kulshreshtha <akulshreshtha@janestreet.com>
parents: 51391
diff changeset
458 .nth(2)
6603a1448f18 hg-core: separate timestamp and extra methods
Arun Kulshreshtha <akulshreshtha@janestreet.com>
parents: 51391
diff changeset
459 .map(decode_extra)
6603a1448f18 hg-core: separate timestamp and extra methods
Arun Kulshreshtha <akulshreshtha@janestreet.com>
parents: 51391
diff changeset
460 .transpose()?
6603a1448f18 hg-core: separate timestamp and extra methods
Arun Kulshreshtha <akulshreshtha@janestreet.com>
parents: 51391
diff changeset
461 .unwrap_or_default())
6603a1448f18 hg-core: separate timestamp and extra methods
Arun Kulshreshtha <akulshreshtha@janestreet.com>
parents: 51391
diff changeset
462 }
6603a1448f18 hg-core: separate timestamp and extra methods
Arun Kulshreshtha <akulshreshtha@janestreet.com>
parents: 51391
diff changeset
463
51391
a96ed440450e hg-core: implement timestamp line parsing
Arun Kulshreshtha <akulshreshtha@janestreet.com>
parents: 51369
diff changeset
464 /// Decode Mercurial's escaping for changelog extras.
a96ed440450e hg-core: implement timestamp line parsing
Arun Kulshreshtha <akulshreshtha@janestreet.com>
parents: 51369
diff changeset
465 ///
a96ed440450e hg-core: implement timestamp line parsing
Arun Kulshreshtha <akulshreshtha@janestreet.com>
parents: 51369
diff changeset
466 /// The `_string_escape` function in `changelog.py` only escapes 4 characters
a96ed440450e hg-core: implement timestamp line parsing
Arun Kulshreshtha <akulshreshtha@janestreet.com>
parents: 51369
diff changeset
467 /// (null, backslash, newline, and carriage return) so we only decode those.
a96ed440450e hg-core: implement timestamp line parsing
Arun Kulshreshtha <akulshreshtha@janestreet.com>
parents: 51369
diff changeset
468 ///
a96ed440450e hg-core: implement timestamp line parsing
Arun Kulshreshtha <akulshreshtha@janestreet.com>
parents: 51369
diff changeset
469 /// The Python code also includes a workaround for decoding escaped nuls
a96ed440450e hg-core: implement timestamp line parsing
Arun Kulshreshtha <akulshreshtha@janestreet.com>
parents: 51369
diff changeset
470 /// that are followed by an ASCII octal digit, since Python's built-in
a96ed440450e hg-core: implement timestamp line parsing
Arun Kulshreshtha <akulshreshtha@janestreet.com>
parents: 51369
diff changeset
471 /// `string_escape` codec will interpret that as an escaped octal byte value.
a96ed440450e hg-core: implement timestamp line parsing
Arun Kulshreshtha <akulshreshtha@janestreet.com>
parents: 51369
diff changeset
472 /// That workaround is omitted here since we don't support decoding octal.
a96ed440450e hg-core: implement timestamp line parsing
Arun Kulshreshtha <akulshreshtha@janestreet.com>
parents: 51369
diff changeset
473 fn unescape_extra(bytes: &[u8]) -> Vec<u8> {
a96ed440450e hg-core: implement timestamp line parsing
Arun Kulshreshtha <akulshreshtha@janestreet.com>
parents: 51369
diff changeset
474 let mut output = Vec::with_capacity(bytes.len());
a96ed440450e hg-core: implement timestamp line parsing
Arun Kulshreshtha <akulshreshtha@janestreet.com>
parents: 51369
diff changeset
475 let mut input = bytes.iter().copied();
a96ed440450e hg-core: implement timestamp line parsing
Arun Kulshreshtha <akulshreshtha@janestreet.com>
parents: 51369
diff changeset
476
a96ed440450e hg-core: implement timestamp line parsing
Arun Kulshreshtha <akulshreshtha@janestreet.com>
parents: 51369
diff changeset
477 while let Some(c) = input.next() {
a96ed440450e hg-core: implement timestamp line parsing
Arun Kulshreshtha <akulshreshtha@janestreet.com>
parents: 51369
diff changeset
478 if c != b'\\' {
a96ed440450e hg-core: implement timestamp line parsing
Arun Kulshreshtha <akulshreshtha@janestreet.com>
parents: 51369
diff changeset
479 output.push(c);
a96ed440450e hg-core: implement timestamp line parsing
Arun Kulshreshtha <akulshreshtha@janestreet.com>
parents: 51369
diff changeset
480 continue;
a96ed440450e hg-core: implement timestamp line parsing
Arun Kulshreshtha <akulshreshtha@janestreet.com>
parents: 51369
diff changeset
481 }
a96ed440450e hg-core: implement timestamp line parsing
Arun Kulshreshtha <akulshreshtha@janestreet.com>
parents: 51369
diff changeset
482
a96ed440450e hg-core: implement timestamp line parsing
Arun Kulshreshtha <akulshreshtha@janestreet.com>
parents: 51369
diff changeset
483 match input.next() {
a96ed440450e hg-core: implement timestamp line parsing
Arun Kulshreshtha <akulshreshtha@janestreet.com>
parents: 51369
diff changeset
484 Some(b'0') => output.push(b'\0'),
a96ed440450e hg-core: implement timestamp line parsing
Arun Kulshreshtha <akulshreshtha@janestreet.com>
parents: 51369
diff changeset
485 Some(b'\\') => output.push(b'\\'),
a96ed440450e hg-core: implement timestamp line parsing
Arun Kulshreshtha <akulshreshtha@janestreet.com>
parents: 51369
diff changeset
486 Some(b'n') => output.push(b'\n'),
a96ed440450e hg-core: implement timestamp line parsing
Arun Kulshreshtha <akulshreshtha@janestreet.com>
parents: 51369
diff changeset
487 Some(b'r') => output.push(b'\r'),
a96ed440450e hg-core: implement timestamp line parsing
Arun Kulshreshtha <akulshreshtha@janestreet.com>
parents: 51369
diff changeset
488 // The following cases should never occur in theory because any
a96ed440450e hg-core: implement timestamp line parsing
Arun Kulshreshtha <akulshreshtha@janestreet.com>
parents: 51369
diff changeset
489 // backslashes in the original input should have been escaped
a96ed440450e hg-core: implement timestamp line parsing
Arun Kulshreshtha <akulshreshtha@janestreet.com>
parents: 51369
diff changeset
490 // with another backslash, so it should not be possible to
a96ed440450e hg-core: implement timestamp line parsing
Arun Kulshreshtha <akulshreshtha@janestreet.com>
parents: 51369
diff changeset
491 // observe an escape sequence other than the 4 above.
a96ed440450e hg-core: implement timestamp line parsing
Arun Kulshreshtha <akulshreshtha@janestreet.com>
parents: 51369
diff changeset
492 Some(c) => output.extend_from_slice(&[b'\\', c]),
a96ed440450e hg-core: implement timestamp line parsing
Arun Kulshreshtha <akulshreshtha@janestreet.com>
parents: 51369
diff changeset
493 None => output.push(b'\\'),
a96ed440450e hg-core: implement timestamp line parsing
Arun Kulshreshtha <akulshreshtha@janestreet.com>
parents: 51369
diff changeset
494 }
a96ed440450e hg-core: implement timestamp line parsing
Arun Kulshreshtha <akulshreshtha@janestreet.com>
parents: 51369
diff changeset
495 }
a96ed440450e hg-core: implement timestamp line parsing
Arun Kulshreshtha <akulshreshtha@janestreet.com>
parents: 51369
diff changeset
496
a96ed440450e hg-core: implement timestamp line parsing
Arun Kulshreshtha <akulshreshtha@janestreet.com>
parents: 51369
diff changeset
497 output
a96ed440450e hg-core: implement timestamp line parsing
Arun Kulshreshtha <akulshreshtha@janestreet.com>
parents: 51369
diff changeset
498 }
a96ed440450e hg-core: implement timestamp line parsing
Arun Kulshreshtha <akulshreshtha@janestreet.com>
parents: 51369
diff changeset
499
49064
95da3e99cbd8 rust-changelog: start parsing changeset data
Martin von Zweigbergk <martinvonz@google.com>
parents: 49063
diff changeset
500 #[cfg(test)]
95da3e99cbd8 rust-changelog: start parsing changeset data
Martin von Zweigbergk <martinvonz@google.com>
parents: 49063
diff changeset
501 mod tests {
95da3e99cbd8 rust-changelog: start parsing changeset data
Martin von Zweigbergk <martinvonz@google.com>
parents: 49063
diff changeset
502 use super::*;
50410
b5dd6d6d6fa6 rust-changelog: added a test for `NULL_REVISION` special case
Georges Racinet <georges.racinet@octobus.net>
parents: 50409
diff changeset
503 use crate::vfs::Vfs;
b5dd6d6d6fa6 rust-changelog: added a test for `NULL_REVISION` special case
Georges Racinet <georges.racinet@octobus.net>
parents: 50409
diff changeset
504 use crate::NULL_REVISION;
49064
95da3e99cbd8 rust-changelog: start parsing changeset data
Martin von Zweigbergk <martinvonz@google.com>
parents: 49063
diff changeset
505 use pretty_assertions::assert_eq;
95da3e99cbd8 rust-changelog: start parsing changeset data
Martin von Zweigbergk <martinvonz@google.com>
parents: 49063
diff changeset
506
95da3e99cbd8 rust-changelog: start parsing changeset data
Martin von Zweigbergk <martinvonz@google.com>
parents: 49063
diff changeset
507 #[test]
95da3e99cbd8 rust-changelog: start parsing changeset data
Martin von Zweigbergk <martinvonz@google.com>
parents: 49063
diff changeset
508 fn test_create_changelogrevisiondata_invalid() {
95da3e99cbd8 rust-changelog: start parsing changeset data
Martin von Zweigbergk <martinvonz@google.com>
parents: 49063
diff changeset
509 // Completely empty
49096
07ec9f4f24bf changelog: avoid copying changeset data into `ChangesetRevisionData`
Martin von Zweigbergk <martinvonz@google.com>
parents: 49090
diff changeset
510 assert!(ChangelogRevisionData::new(Cow::Borrowed(b"abcd")).is_err());
49064
95da3e99cbd8 rust-changelog: start parsing changeset data
Martin von Zweigbergk <martinvonz@google.com>
parents: 49063
diff changeset
511 // No newline after manifest
49096
07ec9f4f24bf changelog: avoid copying changeset data into `ChangesetRevisionData`
Martin von Zweigbergk <martinvonz@google.com>
parents: 49090
diff changeset
512 assert!(ChangelogRevisionData::new(Cow::Borrowed(b"abcd")).is_err());
49064
95da3e99cbd8 rust-changelog: start parsing changeset data
Martin von Zweigbergk <martinvonz@google.com>
parents: 49063
diff changeset
513 // No newline after user
49096
07ec9f4f24bf changelog: avoid copying changeset data into `ChangesetRevisionData`
Martin von Zweigbergk <martinvonz@google.com>
parents: 49090
diff changeset
514 assert!(ChangelogRevisionData::new(Cow::Borrowed(b"abcd\n")).is_err());
49064
95da3e99cbd8 rust-changelog: start parsing changeset data
Martin von Zweigbergk <martinvonz@google.com>
parents: 49063
diff changeset
515 // No newline after timestamp
49096
07ec9f4f24bf changelog: avoid copying changeset data into `ChangesetRevisionData`
Martin von Zweigbergk <martinvonz@google.com>
parents: 49090
diff changeset
516 assert!(
07ec9f4f24bf changelog: avoid copying changeset data into `ChangesetRevisionData`
Martin von Zweigbergk <martinvonz@google.com>
parents: 49090
diff changeset
517 ChangelogRevisionData::new(Cow::Borrowed(b"abcd\n\n0 0")).is_err()
07ec9f4f24bf changelog: avoid copying changeset data into `ChangesetRevisionData`
Martin von Zweigbergk <martinvonz@google.com>
parents: 49090
diff changeset
518 );
49064
95da3e99cbd8 rust-changelog: start parsing changeset data
Martin von Zweigbergk <martinvonz@google.com>
parents: 49063
diff changeset
519 // Missing newline after files
49096
07ec9f4f24bf changelog: avoid copying changeset data into `ChangesetRevisionData`
Martin von Zweigbergk <martinvonz@google.com>
parents: 49090
diff changeset
520 assert!(ChangelogRevisionData::new(Cow::Borrowed(
07ec9f4f24bf changelog: avoid copying changeset data into `ChangesetRevisionData`
Martin von Zweigbergk <martinvonz@google.com>
parents: 49090
diff changeset
521 b"abcd\n\n0 0\nfile1\nfile2"
07ec9f4f24bf changelog: avoid copying changeset data into `ChangesetRevisionData`
Martin von Zweigbergk <martinvonz@google.com>
parents: 49090
diff changeset
522 ))
49064
95da3e99cbd8 rust-changelog: start parsing changeset data
Martin von Zweigbergk <martinvonz@google.com>
parents: 49063
diff changeset
523 .is_err(),);
95da3e99cbd8 rust-changelog: start parsing changeset data
Martin von Zweigbergk <martinvonz@google.com>
parents: 49063
diff changeset
524 // Only one newline after files
49096
07ec9f4f24bf changelog: avoid copying changeset data into `ChangesetRevisionData`
Martin von Zweigbergk <martinvonz@google.com>
parents: 49090
diff changeset
525 assert!(ChangelogRevisionData::new(Cow::Borrowed(
07ec9f4f24bf changelog: avoid copying changeset data into `ChangesetRevisionData`
Martin von Zweigbergk <martinvonz@google.com>
parents: 49090
diff changeset
526 b"abcd\n\n0 0\nfile1\nfile2\n"
07ec9f4f24bf changelog: avoid copying changeset data into `ChangesetRevisionData`
Martin von Zweigbergk <martinvonz@google.com>
parents: 49090
diff changeset
527 ))
49064
95da3e99cbd8 rust-changelog: start parsing changeset data
Martin von Zweigbergk <martinvonz@google.com>
parents: 49063
diff changeset
528 .is_err(),);
95da3e99cbd8 rust-changelog: start parsing changeset data
Martin von Zweigbergk <martinvonz@google.com>
parents: 49063
diff changeset
529 }
95da3e99cbd8 rust-changelog: start parsing changeset data
Martin von Zweigbergk <martinvonz@google.com>
parents: 49063
diff changeset
530
95da3e99cbd8 rust-changelog: start parsing changeset data
Martin von Zweigbergk <martinvonz@google.com>
parents: 49063
diff changeset
531 #[test]
95da3e99cbd8 rust-changelog: start parsing changeset data
Martin von Zweigbergk <martinvonz@google.com>
parents: 49063
diff changeset
532 fn test_create_changelogrevisiondata() {
49096
07ec9f4f24bf changelog: avoid copying changeset data into `ChangesetRevisionData`
Martin von Zweigbergk <martinvonz@google.com>
parents: 49090
diff changeset
533 let data = ChangelogRevisionData::new(Cow::Borrowed(
49064
95da3e99cbd8 rust-changelog: start parsing changeset data
Martin von Zweigbergk <martinvonz@google.com>
parents: 49063
diff changeset
534 b"0123456789abcdef0123456789abcdef01234567
95da3e99cbd8 rust-changelog: start parsing changeset data
Martin von Zweigbergk <martinvonz@google.com>
parents: 49063
diff changeset
535 Some One <someone@example.com>
95da3e99cbd8 rust-changelog: start parsing changeset data
Martin von Zweigbergk <martinvonz@google.com>
parents: 49063
diff changeset
536 0 0
95da3e99cbd8 rust-changelog: start parsing changeset data
Martin von Zweigbergk <martinvonz@google.com>
parents: 49063
diff changeset
537 file1
95da3e99cbd8 rust-changelog: start parsing changeset data
Martin von Zweigbergk <martinvonz@google.com>
parents: 49063
diff changeset
538 file2
95da3e99cbd8 rust-changelog: start parsing changeset data
Martin von Zweigbergk <martinvonz@google.com>
parents: 49063
diff changeset
539
95da3e99cbd8 rust-changelog: start parsing changeset data
Martin von Zweigbergk <martinvonz@google.com>
parents: 49063
diff changeset
540 some
95da3e99cbd8 rust-changelog: start parsing changeset data
Martin von Zweigbergk <martinvonz@google.com>
parents: 49063
diff changeset
541 commit
49096
07ec9f4f24bf changelog: avoid copying changeset data into `ChangesetRevisionData`
Martin von Zweigbergk <martinvonz@google.com>
parents: 49090
diff changeset
542 message",
07ec9f4f24bf changelog: avoid copying changeset data into `ChangesetRevisionData`
Martin von Zweigbergk <martinvonz@google.com>
parents: 49090
diff changeset
543 ))
49064
95da3e99cbd8 rust-changelog: start parsing changeset data
Martin von Zweigbergk <martinvonz@google.com>
parents: 49063
diff changeset
544 .unwrap();
95da3e99cbd8 rust-changelog: start parsing changeset data
Martin von Zweigbergk <martinvonz@google.com>
parents: 49063
diff changeset
545 assert_eq!(
95da3e99cbd8 rust-changelog: start parsing changeset data
Martin von Zweigbergk <martinvonz@google.com>
parents: 49063
diff changeset
546 data.manifest_node().unwrap(),
95da3e99cbd8 rust-changelog: start parsing changeset data
Martin von Zweigbergk <martinvonz@google.com>
parents: 49063
diff changeset
547 Node::from_hex("0123456789abcdef0123456789abcdef01234567")
95da3e99cbd8 rust-changelog: start parsing changeset data
Martin von Zweigbergk <martinvonz@google.com>
parents: 49063
diff changeset
548 .unwrap()
95da3e99cbd8 rust-changelog: start parsing changeset data
Martin von Zweigbergk <martinvonz@google.com>
parents: 49063
diff changeset
549 );
95da3e99cbd8 rust-changelog: start parsing changeset data
Martin von Zweigbergk <martinvonz@google.com>
parents: 49063
diff changeset
550 assert_eq!(data.user(), b"Some One <someone@example.com>");
95da3e99cbd8 rust-changelog: start parsing changeset data
Martin von Zweigbergk <martinvonz@google.com>
parents: 49063
diff changeset
551 assert_eq!(data.timestamp_line(), b"0 0");
95da3e99cbd8 rust-changelog: start parsing changeset data
Martin von Zweigbergk <martinvonz@google.com>
parents: 49063
diff changeset
552 assert_eq!(
95da3e99cbd8 rust-changelog: start parsing changeset data
Martin von Zweigbergk <martinvonz@google.com>
parents: 49063
diff changeset
553 data.files().collect_vec(),
95da3e99cbd8 rust-changelog: start parsing changeset data
Martin von Zweigbergk <martinvonz@google.com>
parents: 49063
diff changeset
554 vec![HgPath::new("file1"), HgPath::new("file2")]
95da3e99cbd8 rust-changelog: start parsing changeset data
Martin von Zweigbergk <martinvonz@google.com>
parents: 49063
diff changeset
555 );
95da3e99cbd8 rust-changelog: start parsing changeset data
Martin von Zweigbergk <martinvonz@google.com>
parents: 49063
diff changeset
556 assert_eq!(data.description(), b"some\ncommit\nmessage");
95da3e99cbd8 rust-changelog: start parsing changeset data
Martin von Zweigbergk <martinvonz@google.com>
parents: 49063
diff changeset
557 }
50410
b5dd6d6d6fa6 rust-changelog: added a test for `NULL_REVISION` special case
Georges Racinet <georges.racinet@octobus.net>
parents: 50409
diff changeset
558
b5dd6d6d6fa6 rust-changelog: added a test for `NULL_REVISION` special case
Georges Racinet <georges.racinet@octobus.net>
parents: 50409
diff changeset
559 #[test]
b5dd6d6d6fa6 rust-changelog: added a test for `NULL_REVISION` special case
Georges Racinet <georges.racinet@octobus.net>
parents: 50409
diff changeset
560 fn test_data_from_rev_null() -> Result<(), RevlogError> {
b5dd6d6d6fa6 rust-changelog: added a test for `NULL_REVISION` special case
Georges Racinet <georges.racinet@octobus.net>
parents: 50409
diff changeset
561 // an empty revlog will be enough for this case
b5dd6d6d6fa6 rust-changelog: added a test for `NULL_REVISION` special case
Georges Racinet <georges.racinet@octobus.net>
parents: 50409
diff changeset
562 let temp = tempfile::tempdir().unwrap();
b5dd6d6d6fa6 rust-changelog: added a test for `NULL_REVISION` special case
Georges Racinet <georges.racinet@octobus.net>
parents: 50409
diff changeset
563 let vfs = Vfs { base: temp.path() };
b5dd6d6d6fa6 rust-changelog: added a test for `NULL_REVISION` special case
Georges Racinet <georges.racinet@octobus.net>
parents: 50409
diff changeset
564 std::fs::write(temp.path().join("foo.i"), b"").unwrap();
51191
13f58ce70299 rust-revlog: teach the revlog opening code to read the repo options
Raphaël Gomès <rgomes@octobus.net>
parents: 50978
diff changeset
565 let revlog =
13f58ce70299 rust-revlog: teach the revlog opening code to read the repo options
Raphaël Gomès <rgomes@octobus.net>
parents: 50978
diff changeset
566 Revlog::open(&vfs, "foo.i", None, RevlogOpenOptions::new())
13f58ce70299 rust-revlog: teach the revlog opening code to read the repo options
Raphaël Gomès <rgomes@octobus.net>
parents: 50978
diff changeset
567 .unwrap();
50410
b5dd6d6d6fa6 rust-changelog: added a test for `NULL_REVISION` special case
Georges Racinet <georges.racinet@octobus.net>
parents: 50409
diff changeset
568
b5dd6d6d6fa6 rust-changelog: added a test for `NULL_REVISION` special case
Georges Racinet <georges.racinet@octobus.net>
parents: 50409
diff changeset
569 let changelog = Changelog { revlog };
b5dd6d6d6fa6 rust-changelog: added a test for `NULL_REVISION` special case
Georges Racinet <georges.racinet@octobus.net>
parents: 50409
diff changeset
570 assert_eq!(
50977
1928b770e3e7 rust: use the new `UncheckedRevision` everywhere applicable
Raphaël Gomès <rgomes@octobus.net>
parents: 50747
diff changeset
571 changelog.data_for_rev(NULL_REVISION.into())?,
50410
b5dd6d6d6fa6 rust-changelog: added a test for `NULL_REVISION` special case
Georges Racinet <georges.racinet@octobus.net>
parents: 50409
diff changeset
572 ChangelogRevisionData::null()
b5dd6d6d6fa6 rust-changelog: added a test for `NULL_REVISION` special case
Georges Racinet <georges.racinet@octobus.net>
parents: 50409
diff changeset
573 );
50746
124c44b5cfad rust-revlog: fix RevlogEntry.data() for NULL_REVISION
Georges Racinet <georges.racinet@octobus.net>
parents: 50414
diff changeset
574 // same with the intermediate entry object
124c44b5cfad rust-revlog: fix RevlogEntry.data() for NULL_REVISION
Georges Racinet <georges.racinet@octobus.net>
parents: 50414
diff changeset
575 assert_eq!(
50977
1928b770e3e7 rust: use the new `UncheckedRevision` everywhere applicable
Raphaël Gomès <rgomes@octobus.net>
parents: 50747
diff changeset
576 changelog.entry_for_rev(NULL_REVISION.into())?.data()?,
50746
124c44b5cfad rust-revlog: fix RevlogEntry.data() for NULL_REVISION
Georges Racinet <georges.racinet@octobus.net>
parents: 50414
diff changeset
577 ChangelogRevisionData::null()
124c44b5cfad rust-revlog: fix RevlogEntry.data() for NULL_REVISION
Georges Racinet <georges.racinet@octobus.net>
parents: 50414
diff changeset
578 );
50410
b5dd6d6d6fa6 rust-changelog: added a test for `NULL_REVISION` special case
Georges Racinet <georges.racinet@octobus.net>
parents: 50409
diff changeset
579 Ok(())
b5dd6d6d6fa6 rust-changelog: added a test for `NULL_REVISION` special case
Georges Racinet <georges.racinet@octobus.net>
parents: 50409
diff changeset
580 }
51363
d626e5e7bbbe rust-changelog: don't panic on empty file lists
Arun Kulshreshtha <akulshreshtha@janestreet.com>
parents: 50978
diff changeset
581
d626e5e7bbbe rust-changelog: don't panic on empty file lists
Arun Kulshreshtha <akulshreshtha@janestreet.com>
parents: 50978
diff changeset
582 #[test]
d626e5e7bbbe rust-changelog: don't panic on empty file lists
Arun Kulshreshtha <akulshreshtha@janestreet.com>
parents: 50978
diff changeset
583 fn test_empty_files_list() {
d626e5e7bbbe rust-changelog: don't panic on empty file lists
Arun Kulshreshtha <akulshreshtha@janestreet.com>
parents: 50978
diff changeset
584 assert!(ChangelogRevisionData::null()
d626e5e7bbbe rust-changelog: don't panic on empty file lists
Arun Kulshreshtha <akulshreshtha@janestreet.com>
parents: 50978
diff changeset
585 .files()
d626e5e7bbbe rust-changelog: don't panic on empty file lists
Arun Kulshreshtha <akulshreshtha@janestreet.com>
parents: 50978
diff changeset
586 .collect_vec()
d626e5e7bbbe rust-changelog: don't panic on empty file lists
Arun Kulshreshtha <akulshreshtha@janestreet.com>
parents: 50978
diff changeset
587 .is_empty());
d626e5e7bbbe rust-changelog: don't panic on empty file lists
Arun Kulshreshtha <akulshreshtha@janestreet.com>
parents: 50978
diff changeset
588 }
51391
a96ed440450e hg-core: implement timestamp line parsing
Arun Kulshreshtha <akulshreshtha@janestreet.com>
parents: 51369
diff changeset
589
a96ed440450e hg-core: implement timestamp line parsing
Arun Kulshreshtha <akulshreshtha@janestreet.com>
parents: 51369
diff changeset
590 #[test]
a96ed440450e hg-core: implement timestamp line parsing
Arun Kulshreshtha <akulshreshtha@janestreet.com>
parents: 51369
diff changeset
591 fn test_unescape_basic() {
a96ed440450e hg-core: implement timestamp line parsing
Arun Kulshreshtha <akulshreshtha@janestreet.com>
parents: 51369
diff changeset
592 // '\0', '\\', '\n', and '\r' are correctly unescaped.
a96ed440450e hg-core: implement timestamp line parsing
Arun Kulshreshtha <akulshreshtha@janestreet.com>
parents: 51369
diff changeset
593 let expected = b"AAA\0BBB\\CCC\nDDD\rEEE";
a96ed440450e hg-core: implement timestamp line parsing
Arun Kulshreshtha <akulshreshtha@janestreet.com>
parents: 51369
diff changeset
594 let escaped = br"AAA\0BBB\\CCC\nDDD\rEEE";
a96ed440450e hg-core: implement timestamp line parsing
Arun Kulshreshtha <akulshreshtha@janestreet.com>
parents: 51369
diff changeset
595 let unescaped = unescape_extra(escaped);
a96ed440450e hg-core: implement timestamp line parsing
Arun Kulshreshtha <akulshreshtha@janestreet.com>
parents: 51369
diff changeset
596 assert_eq!(&expected[..], &unescaped[..]);
a96ed440450e hg-core: implement timestamp line parsing
Arun Kulshreshtha <akulshreshtha@janestreet.com>
parents: 51369
diff changeset
597 }
a96ed440450e hg-core: implement timestamp line parsing
Arun Kulshreshtha <akulshreshtha@janestreet.com>
parents: 51369
diff changeset
598
a96ed440450e hg-core: implement timestamp line parsing
Arun Kulshreshtha <akulshreshtha@janestreet.com>
parents: 51369
diff changeset
599 #[test]
a96ed440450e hg-core: implement timestamp line parsing
Arun Kulshreshtha <akulshreshtha@janestreet.com>
parents: 51369
diff changeset
600 fn test_unescape_unsupported_sequence() {
a96ed440450e hg-core: implement timestamp line parsing
Arun Kulshreshtha <akulshreshtha@janestreet.com>
parents: 51369
diff changeset
601 // Other escape sequences are left unaltered.
a96ed440450e hg-core: implement timestamp line parsing
Arun Kulshreshtha <akulshreshtha@janestreet.com>
parents: 51369
diff changeset
602 for c in 0u8..255 {
a96ed440450e hg-core: implement timestamp line parsing
Arun Kulshreshtha <akulshreshtha@janestreet.com>
parents: 51369
diff changeset
603 match c {
a96ed440450e hg-core: implement timestamp line parsing
Arun Kulshreshtha <akulshreshtha@janestreet.com>
parents: 51369
diff changeset
604 b'0' | b'\\' | b'n' | b'r' => continue,
a96ed440450e hg-core: implement timestamp line parsing
Arun Kulshreshtha <akulshreshtha@janestreet.com>
parents: 51369
diff changeset
605 c => {
a96ed440450e hg-core: implement timestamp line parsing
Arun Kulshreshtha <akulshreshtha@janestreet.com>
parents: 51369
diff changeset
606 let expected = &[b'\\', c][..];
a96ed440450e hg-core: implement timestamp line parsing
Arun Kulshreshtha <akulshreshtha@janestreet.com>
parents: 51369
diff changeset
607 let unescaped = unescape_extra(expected);
a96ed440450e hg-core: implement timestamp line parsing
Arun Kulshreshtha <akulshreshtha@janestreet.com>
parents: 51369
diff changeset
608 assert_eq!(expected, &unescaped[..]);
a96ed440450e hg-core: implement timestamp line parsing
Arun Kulshreshtha <akulshreshtha@janestreet.com>
parents: 51369
diff changeset
609 }
a96ed440450e hg-core: implement timestamp line parsing
Arun Kulshreshtha <akulshreshtha@janestreet.com>
parents: 51369
diff changeset
610 }
a96ed440450e hg-core: implement timestamp line parsing
Arun Kulshreshtha <akulshreshtha@janestreet.com>
parents: 51369
diff changeset
611 }
a96ed440450e hg-core: implement timestamp line parsing
Arun Kulshreshtha <akulshreshtha@janestreet.com>
parents: 51369
diff changeset
612 }
a96ed440450e hg-core: implement timestamp line parsing
Arun Kulshreshtha <akulshreshtha@janestreet.com>
parents: 51369
diff changeset
613
a96ed440450e hg-core: implement timestamp line parsing
Arun Kulshreshtha <akulshreshtha@janestreet.com>
parents: 51369
diff changeset
614 #[test]
a96ed440450e hg-core: implement timestamp line parsing
Arun Kulshreshtha <akulshreshtha@janestreet.com>
parents: 51369
diff changeset
615 fn test_unescape_trailing_backslash() {
a96ed440450e hg-core: implement timestamp line parsing
Arun Kulshreshtha <akulshreshtha@janestreet.com>
parents: 51369
diff changeset
616 // Trailing backslashes are OK.
a96ed440450e hg-core: implement timestamp line parsing
Arun Kulshreshtha <akulshreshtha@janestreet.com>
parents: 51369
diff changeset
617 let expected = br"hi\";
a96ed440450e hg-core: implement timestamp line parsing
Arun Kulshreshtha <akulshreshtha@janestreet.com>
parents: 51369
diff changeset
618 let unescaped = unescape_extra(expected);
a96ed440450e hg-core: implement timestamp line parsing
Arun Kulshreshtha <akulshreshtha@janestreet.com>
parents: 51369
diff changeset
619 assert_eq!(&expected[..], &unescaped[..]);
a96ed440450e hg-core: implement timestamp line parsing
Arun Kulshreshtha <akulshreshtha@janestreet.com>
parents: 51369
diff changeset
620 }
a96ed440450e hg-core: implement timestamp line parsing
Arun Kulshreshtha <akulshreshtha@janestreet.com>
parents: 51369
diff changeset
621
a96ed440450e hg-core: implement timestamp line parsing
Arun Kulshreshtha <akulshreshtha@janestreet.com>
parents: 51369
diff changeset
622 #[test]
a96ed440450e hg-core: implement timestamp line parsing
Arun Kulshreshtha <akulshreshtha@janestreet.com>
parents: 51369
diff changeset
623 fn test_unescape_nul_followed_by_octal() {
a96ed440450e hg-core: implement timestamp line parsing
Arun Kulshreshtha <akulshreshtha@janestreet.com>
parents: 51369
diff changeset
624 // Escaped NUL chars followed by octal digits are decoded correctly.
51707
ec7171748350 rust: apply clippy lints
Raphaël Gomès <rgomes@octobus.net>
parents: 51700
diff changeset
625 let expected = b"\x0012";
51391
a96ed440450e hg-core: implement timestamp line parsing
Arun Kulshreshtha <akulshreshtha@janestreet.com>
parents: 51369
diff changeset
626 let escaped = br"\012";
a96ed440450e hg-core: implement timestamp line parsing
Arun Kulshreshtha <akulshreshtha@janestreet.com>
parents: 51369
diff changeset
627 let unescaped = unescape_extra(escaped);
a96ed440450e hg-core: implement timestamp line parsing
Arun Kulshreshtha <akulshreshtha@janestreet.com>
parents: 51369
diff changeset
628 assert_eq!(&expected[..], &unescaped[..]);
a96ed440450e hg-core: implement timestamp line parsing
Arun Kulshreshtha <akulshreshtha@janestreet.com>
parents: 51369
diff changeset
629 }
a96ed440450e hg-core: implement timestamp line parsing
Arun Kulshreshtha <akulshreshtha@janestreet.com>
parents: 51369
diff changeset
630
a96ed440450e hg-core: implement timestamp line parsing
Arun Kulshreshtha <akulshreshtha@janestreet.com>
parents: 51369
diff changeset
631 #[test]
a96ed440450e hg-core: implement timestamp line parsing
Arun Kulshreshtha <akulshreshtha@janestreet.com>
parents: 51369
diff changeset
632 fn test_parse_float_timestamp() {
a96ed440450e hg-core: implement timestamp line parsing
Arun Kulshreshtha <akulshreshtha@janestreet.com>
parents: 51369
diff changeset
633 let test_cases = [
a96ed440450e hg-core: implement timestamp line parsing
Arun Kulshreshtha <akulshreshtha@janestreet.com>
parents: 51369
diff changeset
634 // Zero should map to the UNIX epoch.
a96ed440450e hg-core: implement timestamp line parsing
Arun Kulshreshtha <akulshreshtha@janestreet.com>
parents: 51369
diff changeset
635 ("0.0", "1970-01-01 00:00:00"),
a96ed440450e hg-core: implement timestamp line parsing
Arun Kulshreshtha <akulshreshtha@janestreet.com>
parents: 51369
diff changeset
636 // Negative zero should be the same as positive zero.
a96ed440450e hg-core: implement timestamp line parsing
Arun Kulshreshtha <akulshreshtha@janestreet.com>
parents: 51369
diff changeset
637 ("-0.0", "1970-01-01 00:00:00"),
a96ed440450e hg-core: implement timestamp line parsing
Arun Kulshreshtha <akulshreshtha@janestreet.com>
parents: 51369
diff changeset
638 // Values without fractional components should work like integers.
a96ed440450e hg-core: implement timestamp line parsing
Arun Kulshreshtha <akulshreshtha@janestreet.com>
parents: 51369
diff changeset
639 // (Assuming the timestamp is within the limits of f64 precision.)
a96ed440450e hg-core: implement timestamp line parsing
Arun Kulshreshtha <akulshreshtha@janestreet.com>
parents: 51369
diff changeset
640 ("1115154970.0", "2005-05-03 21:16:10"),
a96ed440450e hg-core: implement timestamp line parsing
Arun Kulshreshtha <akulshreshtha@janestreet.com>
parents: 51369
diff changeset
641 // We expect some loss of precision in the fractional component
a96ed440450e hg-core: implement timestamp line parsing
Arun Kulshreshtha <akulshreshtha@janestreet.com>
parents: 51369
diff changeset
642 // when parsing arbitrary floating-point values.
a96ed440450e hg-core: implement timestamp line parsing
Arun Kulshreshtha <akulshreshtha@janestreet.com>
parents: 51369
diff changeset
643 ("1115154970.123456789", "2005-05-03 21:16:10.123456716"),
a96ed440450e hg-core: implement timestamp line parsing
Arun Kulshreshtha <akulshreshtha@janestreet.com>
parents: 51369
diff changeset
644 // But representable f64 values should parse losslessly.
a96ed440450e hg-core: implement timestamp line parsing
Arun Kulshreshtha <akulshreshtha@janestreet.com>
parents: 51369
diff changeset
645 ("1115154970.123456716", "2005-05-03 21:16:10.123456716"),
a96ed440450e hg-core: implement timestamp line parsing
Arun Kulshreshtha <akulshreshtha@janestreet.com>
parents: 51369
diff changeset
646 // Negative fractional components are subtracted from the epoch.
a96ed440450e hg-core: implement timestamp line parsing
Arun Kulshreshtha <akulshreshtha@janestreet.com>
parents: 51369
diff changeset
647 ("-1.333", "1969-12-31 23:59:58.667"),
a96ed440450e hg-core: implement timestamp line parsing
Arun Kulshreshtha <akulshreshtha@janestreet.com>
parents: 51369
diff changeset
648 ];
a96ed440450e hg-core: implement timestamp line parsing
Arun Kulshreshtha <akulshreshtha@janestreet.com>
parents: 51369
diff changeset
649
a96ed440450e hg-core: implement timestamp line parsing
Arun Kulshreshtha <akulshreshtha@janestreet.com>
parents: 51369
diff changeset
650 for (input, expected) in test_cases {
a96ed440450e hg-core: implement timestamp line parsing
Arun Kulshreshtha <akulshreshtha@janestreet.com>
parents: 51369
diff changeset
651 let res = parse_float_timestamp(input).unwrap().to_string();
a96ed440450e hg-core: implement timestamp line parsing
Arun Kulshreshtha <akulshreshtha@janestreet.com>
parents: 51369
diff changeset
652 assert_eq!(res, expected);
a96ed440450e hg-core: implement timestamp line parsing
Arun Kulshreshtha <akulshreshtha@janestreet.com>
parents: 51369
diff changeset
653 }
a96ed440450e hg-core: implement timestamp line parsing
Arun Kulshreshtha <akulshreshtha@janestreet.com>
parents: 51369
diff changeset
654 }
a96ed440450e hg-core: implement timestamp line parsing
Arun Kulshreshtha <akulshreshtha@janestreet.com>
parents: 51369
diff changeset
655
a96ed440450e hg-core: implement timestamp line parsing
Arun Kulshreshtha <akulshreshtha@janestreet.com>
parents: 51369
diff changeset
656 fn escape_extra(bytes: &[u8]) -> Vec<u8> {
a96ed440450e hg-core: implement timestamp line parsing
Arun Kulshreshtha <akulshreshtha@janestreet.com>
parents: 51369
diff changeset
657 let mut output = Vec::with_capacity(bytes.len());
a96ed440450e hg-core: implement timestamp line parsing
Arun Kulshreshtha <akulshreshtha@janestreet.com>
parents: 51369
diff changeset
658
a96ed440450e hg-core: implement timestamp line parsing
Arun Kulshreshtha <akulshreshtha@janestreet.com>
parents: 51369
diff changeset
659 for c in bytes.iter().copied() {
a96ed440450e hg-core: implement timestamp line parsing
Arun Kulshreshtha <akulshreshtha@janestreet.com>
parents: 51369
diff changeset
660 output.extend_from_slice(match c {
a96ed440450e hg-core: implement timestamp line parsing
Arun Kulshreshtha <akulshreshtha@janestreet.com>
parents: 51369
diff changeset
661 b'\0' => &b"\\0"[..],
a96ed440450e hg-core: implement timestamp line parsing
Arun Kulshreshtha <akulshreshtha@janestreet.com>
parents: 51369
diff changeset
662 b'\\' => &b"\\\\"[..],
a96ed440450e hg-core: implement timestamp line parsing
Arun Kulshreshtha <akulshreshtha@janestreet.com>
parents: 51369
diff changeset
663 b'\n' => &b"\\n"[..],
a96ed440450e hg-core: implement timestamp line parsing
Arun Kulshreshtha <akulshreshtha@janestreet.com>
parents: 51369
diff changeset
664 b'\r' => &b"\\r"[..],
a96ed440450e hg-core: implement timestamp line parsing
Arun Kulshreshtha <akulshreshtha@janestreet.com>
parents: 51369
diff changeset
665 _ => {
a96ed440450e hg-core: implement timestamp line parsing
Arun Kulshreshtha <akulshreshtha@janestreet.com>
parents: 51369
diff changeset
666 output.push(c);
a96ed440450e hg-core: implement timestamp line parsing
Arun Kulshreshtha <akulshreshtha@janestreet.com>
parents: 51369
diff changeset
667 continue;
a96ed440450e hg-core: implement timestamp line parsing
Arun Kulshreshtha <akulshreshtha@janestreet.com>
parents: 51369
diff changeset
668 }
a96ed440450e hg-core: implement timestamp line parsing
Arun Kulshreshtha <akulshreshtha@janestreet.com>
parents: 51369
diff changeset
669 });
a96ed440450e hg-core: implement timestamp line parsing
Arun Kulshreshtha <akulshreshtha@janestreet.com>
parents: 51369
diff changeset
670 }
a96ed440450e hg-core: implement timestamp line parsing
Arun Kulshreshtha <akulshreshtha@janestreet.com>
parents: 51369
diff changeset
671
a96ed440450e hg-core: implement timestamp line parsing
Arun Kulshreshtha <akulshreshtha@janestreet.com>
parents: 51369
diff changeset
672 output
a96ed440450e hg-core: implement timestamp line parsing
Arun Kulshreshtha <akulshreshtha@janestreet.com>
parents: 51369
diff changeset
673 }
a96ed440450e hg-core: implement timestamp line parsing
Arun Kulshreshtha <akulshreshtha@janestreet.com>
parents: 51369
diff changeset
674
a96ed440450e hg-core: implement timestamp line parsing
Arun Kulshreshtha <akulshreshtha@janestreet.com>
parents: 51369
diff changeset
675 fn encode_extra<K, V>(pairs: impl IntoIterator<Item = (K, V)>) -> Vec<u8>
a96ed440450e hg-core: implement timestamp line parsing
Arun Kulshreshtha <akulshreshtha@janestreet.com>
parents: 51369
diff changeset
676 where
a96ed440450e hg-core: implement timestamp line parsing
Arun Kulshreshtha <akulshreshtha@janestreet.com>
parents: 51369
diff changeset
677 K: AsRef<[u8]>,
a96ed440450e hg-core: implement timestamp line parsing
Arun Kulshreshtha <akulshreshtha@janestreet.com>
parents: 51369
diff changeset
678 V: AsRef<[u8]>,
a96ed440450e hg-core: implement timestamp line parsing
Arun Kulshreshtha <akulshreshtha@janestreet.com>
parents: 51369
diff changeset
679 {
a96ed440450e hg-core: implement timestamp line parsing
Arun Kulshreshtha <akulshreshtha@janestreet.com>
parents: 51369
diff changeset
680 let extras = pairs.into_iter().map(|(k, v)| {
a96ed440450e hg-core: implement timestamp line parsing
Arun Kulshreshtha <akulshreshtha@janestreet.com>
parents: 51369
diff changeset
681 escape_extra(&[k.as_ref(), b":", v.as_ref()].concat())
a96ed440450e hg-core: implement timestamp line parsing
Arun Kulshreshtha <akulshreshtha@janestreet.com>
parents: 51369
diff changeset
682 });
a96ed440450e hg-core: implement timestamp line parsing
Arun Kulshreshtha <akulshreshtha@janestreet.com>
parents: 51369
diff changeset
683 // Use fully-qualified syntax to avoid a future naming conflict with
a96ed440450e hg-core: implement timestamp line parsing
Arun Kulshreshtha <akulshreshtha@janestreet.com>
parents: 51369
diff changeset
684 // the standard library: https://github.com/rust-lang/rust/issues/79524
a96ed440450e hg-core: implement timestamp line parsing
Arun Kulshreshtha <akulshreshtha@janestreet.com>
parents: 51369
diff changeset
685 Itertools::intersperse(extras, b"\0".to_vec()).concat()
a96ed440450e hg-core: implement timestamp line parsing
Arun Kulshreshtha <akulshreshtha@janestreet.com>
parents: 51369
diff changeset
686 }
a96ed440450e hg-core: implement timestamp line parsing
Arun Kulshreshtha <akulshreshtha@janestreet.com>
parents: 51369
diff changeset
687
a96ed440450e hg-core: implement timestamp line parsing
Arun Kulshreshtha <akulshreshtha@janestreet.com>
parents: 51369
diff changeset
688 #[test]
51393
6603a1448f18 hg-core: separate timestamp and extra methods
Arun Kulshreshtha <akulshreshtha@janestreet.com>
parents: 51391
diff changeset
689 fn test_decode_extra() {
51391
a96ed440450e hg-core: implement timestamp line parsing
Arun Kulshreshtha <akulshreshtha@janestreet.com>
parents: 51369
diff changeset
690 let extra = [
a96ed440450e hg-core: implement timestamp line parsing
Arun Kulshreshtha <akulshreshtha@janestreet.com>
parents: 51369
diff changeset
691 ("branch".into(), b"default".to_vec()),
a96ed440450e hg-core: implement timestamp line parsing
Arun Kulshreshtha <akulshreshtha@janestreet.com>
parents: 51369
diff changeset
692 ("key-with-hyphens".into(), b"value1".to_vec()),
a96ed440450e hg-core: implement timestamp line parsing
Arun Kulshreshtha <akulshreshtha@janestreet.com>
parents: 51369
diff changeset
693 ("key_with_underscores".into(), b"value2".to_vec()),
a96ed440450e hg-core: implement timestamp line parsing
Arun Kulshreshtha <akulshreshtha@janestreet.com>
parents: 51369
diff changeset
694 ("empty-value".into(), b"".to_vec()),
a96ed440450e hg-core: implement timestamp line parsing
Arun Kulshreshtha <akulshreshtha@janestreet.com>
parents: 51369
diff changeset
695 ("binary-value".into(), (0u8..=255).collect::<Vec<_>>()),
a96ed440450e hg-core: implement timestamp line parsing
Arun Kulshreshtha <akulshreshtha@janestreet.com>
parents: 51369
diff changeset
696 ]
a96ed440450e hg-core: implement timestamp line parsing
Arun Kulshreshtha <akulshreshtha@janestreet.com>
parents: 51369
diff changeset
697 .into_iter()
a96ed440450e hg-core: implement timestamp line parsing
Arun Kulshreshtha <akulshreshtha@janestreet.com>
parents: 51369
diff changeset
698 .collect::<BTreeMap<String, Vec<u8>>>();
a96ed440450e hg-core: implement timestamp line parsing
Arun Kulshreshtha <akulshreshtha@janestreet.com>
parents: 51369
diff changeset
699
a96ed440450e hg-core: implement timestamp line parsing
Arun Kulshreshtha <akulshreshtha@janestreet.com>
parents: 51369
diff changeset
700 let encoded = encode_extra(&extra);
51393
6603a1448f18 hg-core: separate timestamp and extra methods
Arun Kulshreshtha <akulshreshtha@janestreet.com>
parents: 51391
diff changeset
701 let decoded = decode_extra(&encoded).unwrap();
51391
a96ed440450e hg-core: implement timestamp line parsing
Arun Kulshreshtha <akulshreshtha@janestreet.com>
parents: 51369
diff changeset
702
51393
6603a1448f18 hg-core: separate timestamp and extra methods
Arun Kulshreshtha <akulshreshtha@janestreet.com>
parents: 51391
diff changeset
703 assert_eq!(extra, decoded);
51391
a96ed440450e hg-core: implement timestamp line parsing
Arun Kulshreshtha <akulshreshtha@janestreet.com>
parents: 51369
diff changeset
704 }
a96ed440450e hg-core: implement timestamp line parsing
Arun Kulshreshtha <akulshreshtha@janestreet.com>
parents: 51369
diff changeset
705
a96ed440450e hg-core: implement timestamp line parsing
Arun Kulshreshtha <akulshreshtha@janestreet.com>
parents: 51369
diff changeset
706 #[test]
a96ed440450e hg-core: implement timestamp line parsing
Arun Kulshreshtha <akulshreshtha@janestreet.com>
parents: 51369
diff changeset
707 fn test_corrupt_extra() {
a96ed440450e hg-core: implement timestamp line parsing
Arun Kulshreshtha <akulshreshtha@janestreet.com>
parents: 51369
diff changeset
708 let test_cases = [
a96ed440450e hg-core: implement timestamp line parsing
Arun Kulshreshtha <akulshreshtha@janestreet.com>
parents: 51369
diff changeset
709 (&b""[..], "empty input"),
a96ed440450e hg-core: implement timestamp line parsing
Arun Kulshreshtha <akulshreshtha@janestreet.com>
parents: 51369
diff changeset
710 (&b"\0"[..], "unexpected null byte"),
a96ed440450e hg-core: implement timestamp line parsing
Arun Kulshreshtha <akulshreshtha@janestreet.com>
parents: 51369
diff changeset
711 (&b":empty-key"[..], "empty key"),
a96ed440450e hg-core: implement timestamp line parsing
Arun Kulshreshtha <akulshreshtha@janestreet.com>
parents: 51369
diff changeset
712 (&b"\0leading-null:"[..], "leading null"),
a96ed440450e hg-core: implement timestamp line parsing
Arun Kulshreshtha <akulshreshtha@janestreet.com>
parents: 51369
diff changeset
713 (&b"trailing-null:\0"[..], "trailing null"),
a96ed440450e hg-core: implement timestamp line parsing
Arun Kulshreshtha <akulshreshtha@janestreet.com>
parents: 51369
diff changeset
714 (&b"missing-value"[..], "missing value"),
a96ed440450e hg-core: implement timestamp line parsing
Arun Kulshreshtha <akulshreshtha@janestreet.com>
parents: 51369
diff changeset
715 (&b"$!@# non-alphanum-key:"[..], "non-alphanumeric key"),
a96ed440450e hg-core: implement timestamp line parsing
Arun Kulshreshtha <akulshreshtha@janestreet.com>
parents: 51369
diff changeset
716 (&b"\xF0\x9F\xA6\x80 non-ascii-key:"[..], "non-ASCII key"),
a96ed440450e hg-core: implement timestamp line parsing
Arun Kulshreshtha <akulshreshtha@janestreet.com>
parents: 51369
diff changeset
717 ];
a96ed440450e hg-core: implement timestamp line parsing
Arun Kulshreshtha <akulshreshtha@janestreet.com>
parents: 51369
diff changeset
718
a96ed440450e hg-core: implement timestamp line parsing
Arun Kulshreshtha <akulshreshtha@janestreet.com>
parents: 51369
diff changeset
719 for (extra, msg) in test_cases {
a96ed440450e hg-core: implement timestamp line parsing
Arun Kulshreshtha <akulshreshtha@janestreet.com>
parents: 51369
diff changeset
720 assert!(
51707
ec7171748350 rust: apply clippy lints
Raphaël Gomès <rgomes@octobus.net>
parents: 51700
diff changeset
721 decode_extra(extra).is_err(),
51391
a96ed440450e hg-core: implement timestamp line parsing
Arun Kulshreshtha <akulshreshtha@janestreet.com>
parents: 51369
diff changeset
722 "corrupt extra should have failed to parse: {}",
a96ed440450e hg-core: implement timestamp line parsing
Arun Kulshreshtha <akulshreshtha@janestreet.com>
parents: 51369
diff changeset
723 msg
a96ed440450e hg-core: implement timestamp line parsing
Arun Kulshreshtha <akulshreshtha@janestreet.com>
parents: 51369
diff changeset
724 );
a96ed440450e hg-core: implement timestamp line parsing
Arun Kulshreshtha <akulshreshtha@janestreet.com>
parents: 51369
diff changeset
725 }
a96ed440450e hg-core: implement timestamp line parsing
Arun Kulshreshtha <akulshreshtha@janestreet.com>
parents: 51369
diff changeset
726 }
a96ed440450e hg-core: implement timestamp line parsing
Arun Kulshreshtha <akulshreshtha@janestreet.com>
parents: 51369
diff changeset
727
a96ed440450e hg-core: implement timestamp line parsing
Arun Kulshreshtha <akulshreshtha@janestreet.com>
parents: 51369
diff changeset
728 #[test]
a96ed440450e hg-core: implement timestamp line parsing
Arun Kulshreshtha <akulshreshtha@janestreet.com>
parents: 51369
diff changeset
729 fn test_parse_timestamp_line() {
a96ed440450e hg-core: implement timestamp line parsing
Arun Kulshreshtha <akulshreshtha@janestreet.com>
parents: 51369
diff changeset
730 let extra = [
a96ed440450e hg-core: implement timestamp line parsing
Arun Kulshreshtha <akulshreshtha@janestreet.com>
parents: 51369
diff changeset
731 ("branch".into(), b"default".to_vec()),
a96ed440450e hg-core: implement timestamp line parsing
Arun Kulshreshtha <akulshreshtha@janestreet.com>
parents: 51369
diff changeset
732 ("key-with-hyphens".into(), b"value1".to_vec()),
a96ed440450e hg-core: implement timestamp line parsing
Arun Kulshreshtha <akulshreshtha@janestreet.com>
parents: 51369
diff changeset
733 ("key_with_underscores".into(), b"value2".to_vec()),
a96ed440450e hg-core: implement timestamp line parsing
Arun Kulshreshtha <akulshreshtha@janestreet.com>
parents: 51369
diff changeset
734 ("empty-value".into(), b"".to_vec()),
a96ed440450e hg-core: implement timestamp line parsing
Arun Kulshreshtha <akulshreshtha@janestreet.com>
parents: 51369
diff changeset
735 ("binary-value".into(), (0u8..=255).collect::<Vec<_>>()),
a96ed440450e hg-core: implement timestamp line parsing
Arun Kulshreshtha <akulshreshtha@janestreet.com>
parents: 51369
diff changeset
736 ]
a96ed440450e hg-core: implement timestamp line parsing
Arun Kulshreshtha <akulshreshtha@janestreet.com>
parents: 51369
diff changeset
737 .into_iter()
a96ed440450e hg-core: implement timestamp line parsing
Arun Kulshreshtha <akulshreshtha@janestreet.com>
parents: 51369
diff changeset
738 .collect::<BTreeMap<String, Vec<u8>>>();
a96ed440450e hg-core: implement timestamp line parsing
Arun Kulshreshtha <akulshreshtha@janestreet.com>
parents: 51369
diff changeset
739
a96ed440450e hg-core: implement timestamp line parsing
Arun Kulshreshtha <akulshreshtha@janestreet.com>
parents: 51369
diff changeset
740 let mut line: Vec<u8> = b"1115154970 28800 ".to_vec();
a96ed440450e hg-core: implement timestamp line parsing
Arun Kulshreshtha <akulshreshtha@janestreet.com>
parents: 51369
diff changeset
741 line.extend_from_slice(&encode_extra(&extra));
a96ed440450e hg-core: implement timestamp line parsing
Arun Kulshreshtha <akulshreshtha@janestreet.com>
parents: 51369
diff changeset
742
51393
6603a1448f18 hg-core: separate timestamp and extra methods
Arun Kulshreshtha <akulshreshtha@janestreet.com>
parents: 51391
diff changeset
743 let timestamp = parse_timestamp(&line).unwrap();
6603a1448f18 hg-core: separate timestamp and extra methods
Arun Kulshreshtha <akulshreshtha@janestreet.com>
parents: 51391
diff changeset
744 assert_eq!(&timestamp.to_rfc3339(), "2005-05-03T13:16:10-08:00");
51391
a96ed440450e hg-core: implement timestamp line parsing
Arun Kulshreshtha <akulshreshtha@janestreet.com>
parents: 51369
diff changeset
745
51393
6603a1448f18 hg-core: separate timestamp and extra methods
Arun Kulshreshtha <akulshreshtha@janestreet.com>
parents: 51391
diff changeset
746 let parsed_extra = parse_timestamp_line_extra(&line).unwrap();
6603a1448f18 hg-core: separate timestamp and extra methods
Arun Kulshreshtha <akulshreshtha@janestreet.com>
parents: 51391
diff changeset
747 assert_eq!(extra, parsed_extra);
51391
a96ed440450e hg-core: implement timestamp line parsing
Arun Kulshreshtha <akulshreshtha@janestreet.com>
parents: 51369
diff changeset
748 }
49064
95da3e99cbd8 rust-changelog: start parsing changeset data
Martin von Zweigbergk <martinvonz@google.com>
parents: 49063
diff changeset
749 }