Skip to content

Commit a0802db

Browse files
committed
version 0.7.0: dep updates, use arc<[u8]>, added example
1 parent d630940 commit a0802db

11 files changed

+478
-319
lines changed

.gitignore

-1
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,4 @@
11
/target
22
**/*.rs.bk
33
Cargo.lock
4-
/examples/**
54
check_export.sh

Cargo.toml

+15-16
Original file line numberDiff line numberDiff line change
@@ -1,27 +1,26 @@
11
[package]
2-
name = "hg-parser"
3-
version = "0.6.0"
4-
authors = ["Alexander Korolev <[email protected]>"]
2+
authors = ["Alexander Korolev <[email protected]>"]
53
description = """
64
Mercurial repository changelog parser. It allows to get any revision
75
with creation date, user, parents, branch and files.
86
"""
97
edition = "2018"
10-
license = "GPL-2.0-or-later"
11-
readme = "README.md"
128
homepage = "https://github.com/kilork/hg-parser"
13-
repository = "https://github.com/kilork/hg-parser"
149
keywords = ["hg", "mercurial", "parser"]
10+
license = "GPL-2.0-or-later"
11+
name = "hg-parser"
12+
repository = "https://github.com/kilork/hg-parser"
13+
version = "0.7.0"
1514

1615
[dependencies]
17-
nom = "4.2"
16+
bitflags = {version = "2.5", default-features = false}
17+
byteorder = {version = "1.3", default-features = false}
18+
chrono = {version = "0.4", features = ["clock"], default-features = false}
1819
flate2 = "1.0"
19-
bitflags = { version = "1.2", default-features = false }
20-
byteorder = { version = "1.3", default-features = false }
21-
chrono = { version = "0.4", features = ["clock"], default-features = false }
22-
lazy_static = { version = "1.4", default-features = false }
23-
sha-1 = { version = "0.9", default-features = false }
24-
rayon = { version = "1.4", default-features = false }
25-
ordered-parallel-iterator = { version = "0.1", default-features = false }
26-
failure = "0.1"
27-
lru-cache = { version = "0.1", default-features = false }
20+
lazy_static = {version = "1.4", default-features = false}
21+
lru-cache = {version = "0.1", default-features = false}
22+
nom = {version = "7.1", default-features = false, features = ["alloc"]}
23+
ordered-parallel-iterator = {version = "0.1", default-features = false}
24+
rayon = {version = "1.4", default-features = false}
25+
sha-1 = {version = "0.10", default-features = false}
26+
thiserror = "1"

examples/git-fast-import.rs

+151
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,151 @@
1+
use hg_parser::{file_content, FileType, ManifestEntryDetails, MercurialRepository, Revision};
2+
3+
use std::env::args;
4+
use std::io::Write;
5+
use std::path::{Path, PathBuf};
6+
use std::string::ParseError;
7+
use std::time::Instant;
8+
9+
fn main() -> Result<(), Error> {
10+
let path: PathBuf = args().nth(1).expect("path not provided").parse()?;
11+
export_repo(path)
12+
}
13+
14+
fn export_repo<P: AsRef<Path>>(path: P) -> Result<(), Error> {
15+
let start = Instant::now();
16+
let repo = MercurialRepository::open(path)?;
17+
18+
let stdout = std::io::stdout();
19+
let mut writer = stdout.lock();
20+
21+
for changeset in &repo {
22+
let revision = changeset.revision;
23+
eprintln!("rev: {:?}", revision);
24+
25+
let header = &changeset.header;
26+
let mut branch = None;
27+
let mut closed = false;
28+
for (key, value) in &header.extra {
29+
if key == b"branch" {
30+
branch = Some(value.as_slice());
31+
}
32+
33+
if key == b"close" && value == b"1" {
34+
closed = true;
35+
}
36+
}
37+
38+
let mut branch: Vec<_> = branch.unwrap_or_else(|| b"master").into();
39+
for b in branch.iter_mut() {
40+
if *b == b' ' {
41+
*b = b'-';
42+
}
43+
}
44+
45+
let user = String::from_utf8_lossy(&header.user);
46+
let desc = String::from_utf8_lossy(&header.comment);
47+
48+
let time = header.time.timestamp_secs();
49+
let timezone = header.time.tz_offset_secs();
50+
let tz = format!("{:+03}{:02}", -timezone / 3600, ((-timezone % 3600) / 60));
51+
52+
write!(writer, "reset refs/heads/")?;
53+
writer.write_all(&mut branch)?;
54+
write!(writer, "\ncommit refs/heads/")?;
55+
writer.write_all(&mut branch)?;
56+
writeln!(writer, "\nmark :{}", mark(revision))?;
57+
58+
writeln!(writer, "author {} {} {}", user, time, tz)?;
59+
writeln!(writer, "committer {} {} {}", user, time, tz)?;
60+
writeln!(writer, "data {}", desc.len() + 1)?;
61+
writeln!(writer, "{}\n", desc)?;
62+
63+
match (header.p1, header.p2) {
64+
(Some(p1), Some(p2)) => {
65+
writeln!(writer, "from :{}", mark(p1))?;
66+
writeln!(writer, "merge :{}", mark(p2))?;
67+
}
68+
(Some(p), None) | (None, Some(p)) => {
69+
writeln!(writer, "from :{}", mark(p))?;
70+
}
71+
_ => (),
72+
}
73+
74+
for mut file in changeset.files {
75+
match (file.data, file.manifest_entry) {
76+
(None, None) => {
77+
write!(writer, "D ")?;
78+
writer.write_all(&mut file.path)?;
79+
writeln!(writer)?;
80+
}
81+
(Some(data), Some(manifest_entry)) => {
82+
write!(
83+
writer,
84+
"M {} inline ",
85+
match manifest_entry.details {
86+
ManifestEntryDetails::File(FileType::Symlink) => "120000",
87+
ManifestEntryDetails::File(FileType::Executable) => "100755",
88+
ManifestEntryDetails::Tree
89+
| ManifestEntryDetails::File(FileType::Regular) => "100644",
90+
}
91+
)?;
92+
writer.write_all(&mut file.path)?;
93+
let data = file_content(&data);
94+
writeln!(writer, "\ndata {}", data.len())?;
95+
writer.write_all(&data[..])?;
96+
}
97+
_ => panic!("Wrong file data!"),
98+
}
99+
}
100+
101+
if closed {
102+
write!(writer, "reset refs/tags/archive/")?;
103+
writer.write_all(&mut branch)?;
104+
writeln!(writer, "\nfrom :{}\n", mark(revision))?;
105+
106+
write!(writer, "reset refs/heads/")?;
107+
writer.write_all(&mut branch)?;
108+
writeln!(writer, "\nfrom 0000000000000000000000000000000000000000\n")?;
109+
}
110+
}
111+
112+
for (rev, tag) in repo.tags().unwrap() {
113+
eprintln!("export tag {}", tag.name);
114+
writeln!(writer, "reset refs/tags/{}", tag.name).unwrap();
115+
writeln!(writer, "from :{}", mark(rev)).unwrap();
116+
writeln!(writer).unwrap();
117+
}
118+
119+
eprintln!("Done. Elapsed: {:?}", start.elapsed());
120+
Ok(())
121+
}
122+
123+
fn mark<R: Into<Revision>>(rev: R) -> usize {
124+
(rev.into() + 1).0 as usize
125+
}
126+
127+
#[derive(Debug)]
128+
#[allow(dead_code)]
129+
enum Error {
130+
MercurialRepoException(hg_parser::ErrorKind),
131+
Parse(ParseError),
132+
IO(std::io::Error),
133+
}
134+
135+
impl From<ParseError> for Error {
136+
fn from(value: ParseError) -> Self {
137+
Error::Parse(value)
138+
}
139+
}
140+
141+
impl From<std::io::Error> for Error {
142+
fn from(value: std::io::Error) -> Self {
143+
Error::IO(value)
144+
}
145+
}
146+
147+
impl From<hg_parser::ErrorKind> for Error {
148+
fn from(value: hg_parser::ErrorKind) -> Self {
149+
Error::MercurialRepoException(value)
150+
}
151+
}

src/cache.rs

+6-6
Original file line numberDiff line numberDiff line change
@@ -5,36 +5,36 @@ use lru_cache::LruCache;
55
use crate::types::NodeHash;
66

77
pub struct Cache {
8-
inner: Mutex<LruCache<NodeHash, CacheEntry<Vec<u8>>>>,
8+
inner: Mutex<LruCache<NodeHash, CacheEntry<[u8]>>>,
99
}
1010

11-
impl Cachable<NodeHash, Vec<u8>> for Cache {
11+
impl Cachable<NodeHash, [u8]> for Cache {
1212
fn new(capacity: usize) -> Self {
1313
Self {
1414
inner: Mutex::new(LruCache::new(capacity)),
1515
}
1616
}
1717

18-
fn put(&self, key: NodeHash, value: Arc<Vec<u8>>) -> Arc<Vec<u8>> {
18+
fn put(&self, key: NodeHash, value: Arc<[u8]>) -> Arc<[u8]> {
1919
self.inner
2020
.lock()
2121
.unwrap()
2222
.insert(key, CacheEntry::Normal(value.clone()));
2323
value
2424
}
2525

26-
fn get(&self, key: &NodeHash) -> Option<Arc<Vec<u8>>> {
26+
fn get(&self, key: &NodeHash) -> Option<Arc<[u8]>> {
2727
self.inner.lock().unwrap().get_mut(key).map(|x| match x {
2828
CacheEntry::Normal(x) => x.clone(),
2929
})
3030
}
3131
}
3232

33-
pub enum CacheEntry<K> {
33+
pub enum CacheEntry<K: ?Sized> {
3434
Normal(Arc<K>),
3535
}
3636

37-
pub trait Cachable<K, V> {
37+
pub trait Cachable<K, V: ?Sized> {
3838
fn new(capacity: usize) -> Self;
3939
fn get(&self, key: &K) -> Option<Arc<V>>;
4040
fn put(&self, key: K, value: Arc<V>) -> Arc<V>;

src/changeset.rs

+7-4
Original file line numberDiff line numberDiff line change
@@ -1,11 +1,14 @@
1-
use crate::error::ErrorKind;
2-
use crate::manifest::ManifestEntry;
3-
use crate::types::{DateTime, NodeHash, Revision, RevisionLogEntry};
41
use std::collections::HashMap;
52
use std::fmt::Debug;
63
use std::sync::Arc;
74
use std::{fmt, str};
85

6+
use crate::{
7+
error::ErrorKind,
8+
manifest::ManifestEntry,
9+
types::{DateTime, NodeHash, Revision, RevisionLogEntry},
10+
};
11+
912
/// Changeset's header.
1013
pub struct ChangesetHeader {
1114
/// Parent 1.
@@ -182,7 +185,7 @@ pub struct ChangesetFile {
182185
/// Path.
183186
pub path: Vec<u8>,
184187
/// Data of file, `None` - file was deleted, otherwise it was added or modified.
185-
pub data: Option<Arc<Vec<u8>>>,
188+
pub data: Option<Arc<[u8]>>,
186189
/// Meta information, `None` - file was deleted, otherwise it was added or modified.
187190
pub manifest_entry: Option<ManifestEntry>,
188191
}

src/error.rs

+12-20
Original file line numberDiff line numberDiff line change
@@ -1,41 +1,33 @@
1-
use failure::Fail;
2-
3-
#[derive(Debug, Fail)]
1+
#[derive(Debug, thiserror::Error)]
42
pub enum ErrorKind {
53
/// Parser failed.
6-
#[fail(display = "parser failed")]
4+
#[error("parser failed")]
75
Parser,
86
/// Cannot convert from Utf-8.
9-
#[fail(display = "cannot convert from Utf-8 {}", _0)]
7+
#[error("cannot convert from Utf-8 {0}")]
108
FromUtf8(std::str::Utf8Error),
119
/// IO error.
12-
#[fail(display = "IO error {}", _0)]
13-
IO(std::io::Error),
10+
#[error("IO error {0}")]
11+
IO(#[from] std::io::Error),
1412
/// Invalid path.
15-
#[fail(display = "Invalid path {}", _0)]
13+
#[error("Invalid path {0}")]
1614
InvalidPath(String),
1715
/// RevisionLog load failure.
18-
#[fail(display = "revision log load failure {}", _0)]
16+
#[error("revision log load failure {0}")]
1917
RevisionLogFailure(String),
2018
/// Cannot convert date/time.
21-
#[fail(display = "invalid date time {}", _0)]
19+
#[error("invalid date time {0}")]
2220
InvalidDateTime(String),
2321
/// Requirement in ``.hg/requires`` is not supported.
24-
#[fail(display = "unknown requirement {}", _0)]
22+
#[error("unknown requirement {0}")]
2523
UnknownRequirement(String),
2624
/// Manifest issue.
27-
#[fail(display = "manifest issue {}", _0)]
25+
#[error("manifest issue {0}")]
2826
Manifest(String),
2927
}
3028

31-
impl From<std::io::Error> for ErrorKind {
32-
fn from(value: std::io::Error) -> Self {
33-
ErrorKind::IO(value)
34-
}
35-
}
36-
37-
impl From<nom::Err<&[u8]>> for ErrorKind {
38-
fn from(_value: nom::Err<&[u8]>) -> Self {
29+
impl From<nom::Err<nom::error::Error<&[u8]>>> for ErrorKind {
30+
fn from(_value: nom::Err<nom::error::Error<&[u8]>>) -> Self {
3931
ErrorKind::Parser
4032
}
4133
}

0 commit comments

Comments
 (0)