Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

added support for share-safe requirement, options #5

Merged
merged 1 commit into from
Oct 1, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
22 changes: 11 additions & 11 deletions Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@ description = """
Mercurial repository changelog parser. It allows to get any revision
with creation date, user, parents, branch and files.
"""
edition = "2018"
edition = "2021"
homepage = "https://github.com/kilork/hg-parser"
keywords = ["hg", "mercurial", "parser"]
license = "GPL-2.0-or-later"
Expand All @@ -14,14 +14,14 @@ version = "0.8.0"
rust-version = "1.78"

[dependencies]
bitflags = {version = "2.5", default-features = false}
byteorder = {version = "1.3", default-features = false}
chrono = {version = "0.4", features = ["clock"], default-features = false}
bitflags = { version = "2.5", default-features = false }
byteorder = { version = "1.3", default-features = false }
chrono = { version = "0.4", features = ["clock"], default-features = false }
flate2 = "1.0"
lazy_static = {version = "1.4", default-features = false}
lru-cache = {version = "0.1", default-features = false}
nom = {version = "7.1", default-features = false, features = ["alloc"]}
ordered-parallel-iterator = {version = "0.2", default-features = false}
rayon = {version = "1.4", default-features = false}
sha-1 = {version = "0.10", default-features = false}
thiserror = "1"
lazy_static = { version = "1.4", default-features = false }
lru-cache = { version = "0.1", default-features = false }
nom = { version = "7.1", default-features = false, features = ["alloc"] }
ordered-parallel-iterator = { version = "0.2", default-features = false }
rayon = { version = "1.4", default-features = false }
sha-1 = { version = "0.10", default-features = false }
thiserror = "1"
16 changes: 9 additions & 7 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -13,14 +13,16 @@ hg-parser = "0.8"

### Use case - Analyse revision log and export to ```git fast-import``` format

```rust#ignore
use hg_parser::{file_content, FileType, ManifestEntryDetails, MercurialRepository, Revision};
```rust, no_run
use std::{
env::args,
io::Write,
path::{Path, PathBuf},
string::ParseError,
time::Instant,
};

use std::env::args;
use std::io::Write;
use std::path::{Path, PathBuf};
use std::string::ParseError;
use std::time::Instant;
use hg_parser::{file_content, FileType, ManifestEntryDetails, MercurialRepository, Revision};

fn main() -> Result<(), Error> {
let path: PathBuf = args().nth(1).expect("path not provided").parse()?;
Expand Down
14 changes: 8 additions & 6 deletions examples/git-fast-import.rs
Original file line number Diff line number Diff line change
@@ -1,10 +1,12 @@
use hg_parser::{file_content, FileType, ManifestEntryDetails, MercurialRepository, Revision};
use std::{
env::args,
io::Write,
path::{Path, PathBuf},
string::ParseError,
time::Instant,
};

use std::env::args;
use std::io::Write;
use std::path::{Path, PathBuf};
use std::string::ParseError;
use std::time::Instant;
use hg_parser::{file_content, FileType, ManifestEntryDetails, MercurialRepository, Revision};

fn main() -> Result<(), Error> {
let path: PathBuf = args().nth(1).expect("path not provided").parse()?;
Expand Down
4 changes: 3 additions & 1 deletion src/error.rs
Original file line number Diff line number Diff line change
@@ -1,3 +1,5 @@
use crate::types::RepositoryRequire;

#[derive(Debug, thiserror::Error)]
pub enum ErrorKind {
/// Parser failed.
Expand All @@ -20,7 +22,7 @@ pub enum ErrorKind {
InvalidDateTime(String),
/// Requirement in ``.hg/requires`` is not supported.
#[error("unknown requirement {0}")]
UnknownRequirement(String),
UnknownRequirement(RepositoryRequire),
/// Manifest issue.
#[error("manifest issue {0}")]
Manifest(String),
Expand Down
41 changes: 33 additions & 8 deletions src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -22,16 +22,23 @@ mod revisionlog;
mod types;

use cache::{Cachable, Cache};
pub use changeset::*;
pub use error::ErrorKind;
use manifest::Manifest;
use path::{fncache_fsencode, simple_fsencode, MPath, MPathElement};
use revisionlog::RevisionLog;
use types::{MercurialTag, NodeHash, RepositoryRequire};

pub use changeset::*;
pub use error::ErrorKind;
pub use manifest::{FileType, ManifestEntry, ManifestEntryDetails};
pub use types::{Revision, RevisionRange};

/// Options for mercurial repository.
#[derive(Default)]
pub struct MercurialRepositoryOptions {
/// Threat unknown requirements as warnings.
pub ignore_unknown_requirements: bool,
}

#[derive(Debug)]
/// Mercurial repository. Top-level structure for access to change sets and tags.
pub struct MercurialRepository {
Expand All @@ -44,9 +51,17 @@ pub struct MercurialRepository {
impl MercurialRepository {
/// Opens `MercurialRepository` at `root_path`.
pub fn open<P: AsRef<Path>>(root_path: P) -> Result<MercurialRepository, ErrorKind> {
Self::open_with_options(root_path, Default::default())
}

/// Opens `MercurialRepository` at `root_path` with options.
pub fn open_with_options<P: AsRef<Path>>(
root_path: P,
options: MercurialRepositoryOptions,
) -> Result<MercurialRepository, ErrorKind> {
let base = root_path.as_ref().join(".hg");

let requires = MercurialRepository::load_requires(&base)?;
let requires = MercurialRepository::load_requires(&base, &options)?;

let store = base.join("store");

Expand Down Expand Up @@ -142,13 +157,23 @@ impl MercurialRepository {

fn load_requires<P: AsRef<Path>>(
path: P,
) -> Result<HashSet<RepositoryRequire>, std::io::Error> {
options: &MercurialRepositoryOptions,
) -> Result<HashSet<RepositoryRequire>, ErrorKind> {
let requires_path = path.as_ref().join("requires");
let file = File::open(requires_path)?;
Ok(BufReader::new(file)
.lines()
.map(|x| x.unwrap().parse().expect("could not parse requirement"))
.collect())
let lines = BufReader::new(file).lines().map_while(Result::ok);
if options.ignore_unknown_requirements {
lines
.map(|x| match x.parse() {
Err(ErrorKind::UnknownRequirement(r)) => Ok(r),
other => other,
})
.collect()
} else {
Ok(lines
.map(|x| x.parse().expect("could not parse requirement"))
.collect())
}
}

fn fsencode_path(&self, elements: &[MPathElement]) -> PathBuf {
Expand Down
51 changes: 39 additions & 12 deletions src/types.rs
Original file line number Diff line number Diff line change
@@ -1,23 +1,24 @@
use std::{
fmt::{self, Debug, Display},
fmt::{self, Display},
ops::{Add, Range, Sub},
rc::Rc,
str::FromStr,
sync::Arc,
};

/// Repository requires flags.
/// Repositories contain a file (``.hg/requires``) containing a list of
/// features/capabilities that are *required* for clients to interface
/// with the repository.
use super::error::ErrorKind;
use bitflags::bitflags;
use chrono::{
DateTime as ChronoDateTime, FixedOffset, Local, LocalResult, NaiveDateTime, TimeZone,
};
use sha1::{Digest, Sha1};
#[derive(Debug, Copy, Clone, Eq, PartialEq, Hash)]
pub(crate) enum RepositoryRequire {

/// Repository requires flags.
/// Repositories contain a file (``.hg/requires``) containing a list of
/// features/capabilities that are *required* for clients to interface
/// with the repository.
#[derive(Debug, Clone, Eq, PartialEq, Hash)]
pub enum RepositoryRequire {
/// When present, revlogs are version 1 (**RevlogNG**).
Revlogv1,
/// The **store** repository layout is used.
Expand Down Expand Up @@ -45,6 +46,10 @@ pub(crate) enum RepositoryRequire {
TreeManifest,
/// The working directory is sparse (only contains a subset of files).
ExpSparse,
/// Safe behaviour for all shares that access a repository.
ShareSafe,
/// Unknown requirement.
Unknown(String),
}

impl FromStr for RepositoryRequire {
Expand All @@ -64,7 +69,29 @@ impl FromStr for RepositoryRequire {
"manifestv2" => Ok(Manifestv2),
"treemanifest" => Ok(TreeManifest),
"exp-sparse" => Ok(ExpSparse),
other => Err(ErrorKind::UnknownRequirement(other.into())),
"share-safe" => Ok(ShareSafe),
other => Err(ErrorKind::UnknownRequirement(Self::Unknown(other.into()))),
}
}
}

impl std::fmt::Display for RepositoryRequire {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
use RepositoryRequire::*;
match self {
Revlogv1 => "revlogv1".fmt(f),
Store => "store".fmt(f),
FnCache => "fncache".fmt(f),
Shared => "shared".fmt(f),
RelShared => "relshared".fmt(f),
DotEncode => "dotencode".fmt(f),
ParentDelta => "parentdelta".fmt(f),
GeneralDelta => "generaldelta".fmt(f),
Manifestv2 => "manifestv2".fmt(f),
TreeManifest => "treemanifest".fmt(f),
ExpSparse => "exp-sparse".fmt(f),
ShareSafe => "share-safe".fmt(f),
Unknown(s) => s.fmt(f),
}
}
}
Expand All @@ -81,7 +108,7 @@ impl Revision {

/// Return an open ended iterator from index.
pub fn range(self) -> RevisionRange {
RevisionRange(self.0, std::u32::MAX)
RevisionRange(self.0, u32::MAX)
}
}

Expand Down Expand Up @@ -221,13 +248,13 @@ impl AsRef<[u8]> for NodeHash {
}
}

impl Display for NodeHash {
impl std::fmt::Display for NodeHash {
fn fmt(&self, fmt: &mut fmt::Formatter) -> fmt::Result {
Display::fmt(&self.to_hex(), fmt)
}
}

impl Debug for NodeHash {
impl std::fmt::Debug for NodeHash {
fn fmt(&self, fmt: &mut fmt::Formatter) -> fmt::Result {
write!(fmt, "NodeHash({})", self)
}
Expand Down Expand Up @@ -303,7 +330,7 @@ impl Fragment {
}
}

impl Debug for Fragment {
impl std::fmt::Debug for Fragment {
fn fmt(&self, fmt: &mut fmt::Formatter) -> fmt::Result {
write!(
fmt,
Expand Down
2 changes: 1 addition & 1 deletion templates/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,7 @@ hg-parser = "0.8"

### Use case - Analyse revision log and export to ```git fast-import``` format

{{ codeblock "rust#ignore" ( read_to_str "examples/git-fast-import.rs" ) }}
{{ codeblock "rust, no_run" ( read_to_str "examples/git-fast-import.rs" ) }}

## Implementation details

Expand Down