Details
Details
- Reviewers
Alphare - Group Reviewers
hg-reviewers - Commits
- rHG68a15b5a7e58: rust: Replace DirstatePackError with HgError
Diff Detail
Diff Detail
- Repository
- rHG Mercurial
- Branch
- default
- Lint
No Linters Available - Unit
No Unit Test Coverage
Alphare |
hg-reviewers |
No Linters Available |
No Unit Test Coverage |
Path | Packages | |||
---|---|---|---|---|
M | rust/hg-core/src/dirstate/parsers.rs (24 lines) | |||
M | rust/hg-core/src/lib.rs (15 lines) | |||
M | rust/hg-cpython/src/parsers.rs (18 lines) |
Commit | Parents | Author | Summary | Date |
---|---|---|---|---|
fae0c8053fb9 | d09510b9d837 | Simon Sapin | Jan 27 2021, 7:41 AM |
Status | Author | Revision | |
---|---|---|---|
Closed | SimonSapin | ||
Closed | SimonSapin | ||
Closed | SimonSapin | ||
Closed | SimonSapin | ||
Closed | SimonSapin | ||
Closed | SimonSapin | ||
Closed | SimonSapin | ||
Closed | SimonSapin | ||
Closed | SimonSapin | ||
Closed | SimonSapin | ||
Closed | SimonSapin | ||
Closed | SimonSapin | ||
Closed | SimonSapin | ||
Closed | SimonSapin | ||
Closed | SimonSapin | ||
Closed | SimonSapin | ||
Closed | SimonSapin | ||
Closed | SimonSapin | ||
Closed | SimonSapin | ||
Closed | SimonSapin |
// Copyright 2019 Raphaël Gomès <rgomes@octobus.net> | // Copyright 2019 Raphaël Gomès <rgomes@octobus.net> | ||||
// | // | ||||
// This software may be used and distributed according to the terms of the | // This software may be used and distributed according to the terms of the | ||||
// GNU General Public License version 2 or any later version. | // GNU General Public License version 2 or any later version. | ||||
use crate::errors::HgError; | |||||
use crate::utils::hg_path::HgPath; | use crate::utils::hg_path::HgPath; | ||||
use crate::{ | use crate::{ | ||||
dirstate::{CopyMap, EntryState, StateMap}, | dirstate::{CopyMap, EntryState, StateMap}, | ||||
DirstateEntry, DirstatePackError, DirstateParents, DirstateParseError, | DirstateEntry, DirstateParents, DirstateParseError, | ||||
}; | }; | ||||
use byteorder::{BigEndian, ReadBytesExt, WriteBytesExt}; | use byteorder::{BigEndian, ReadBytesExt, WriteBytesExt}; | ||||
use micro_timer::timed; | use micro_timer::timed; | ||||
use std::convert::{TryFrom, TryInto}; | use std::convert::{TryFrom, TryInto}; | ||||
use std::io::Cursor; | use std::io::Cursor; | ||||
use std::time::Duration; | use std::time::Duration; | ||||
/// Parents are stored in the dirstate as byte hashes. | /// Parents are stored in the dirstate as byte hashes. | ||||
/// `now` is the duration in seconds since the Unix epoch | /// `now` is the duration in seconds since the Unix epoch | ||||
#[cfg(not(feature = "dirstate-tree"))] | #[cfg(not(feature = "dirstate-tree"))] | ||||
pub fn pack_dirstate( | pub fn pack_dirstate( | ||||
state_map: &mut StateMap, | state_map: &mut StateMap, | ||||
copy_map: &CopyMap, | copy_map: &CopyMap, | ||||
parents: DirstateParents, | parents: DirstateParents, | ||||
now: Duration, | now: Duration, | ||||
) -> Result<Vec<u8>, DirstatePackError> { | ) -> Result<Vec<u8>, HgError> { | ||||
// TODO move away from i32 before 2038. | // TODO move away from i32 before 2038. | ||||
let now: i32 = now.as_secs().try_into().expect("time overflow"); | let now: i32 = now.as_secs().try_into().expect("time overflow"); | ||||
let expected_size: usize = state_map | let expected_size: usize = state_map | ||||
.iter() | .iter() | ||||
.map(|(filename, _)| { | .map(|(filename, _)| { | ||||
let mut length = MIN_ENTRY_SIZE + filename.len(); | let mut length = MIN_ENTRY_SIZE + filename.len(); | ||||
if let Some(copy) = copy_map.get(filename) { | if let Some(copy) = copy_map.get(filename) { | ||||
}; | }; | ||||
} | } | ||||
let mut new_filename = new_filename.into_vec(); | let mut new_filename = new_filename.into_vec(); | ||||
if let Some(copy) = copy_map.get(filename) { | if let Some(copy) = copy_map.get(filename) { | ||||
new_filename.push(b'\0'); | new_filename.push(b'\0'); | ||||
new_filename.extend(copy.bytes()); | new_filename.extend(copy.bytes()); | ||||
} | } | ||||
packed.write_u8(entry.state.into())?; | // Unwrapping because `impl std::io::Write for Vec<u8>` never errors | ||||
packed.write_i32::<BigEndian>(entry.mode)?; | packed.write_u8(entry.state.into()).unwrap(); | ||||
packed.write_i32::<BigEndian>(entry.size)?; | packed.write_i32::<BigEndian>(entry.mode).unwrap(); | ||||
packed.write_i32::<BigEndian>(new_mtime)?; | packed.write_i32::<BigEndian>(entry.size).unwrap(); | ||||
packed.write_i32::<BigEndian>(new_filename.len() as i32)?; | packed.write_i32::<BigEndian>(new_mtime).unwrap(); | ||||
packed | |||||
.write_i32::<BigEndian>(new_filename.len() as i32) | |||||
.unwrap(); | |||||
packed.extend(new_filename) | packed.extend(new_filename) | ||||
} | } | ||||
if packed.len() != expected_size { | if packed.len() != expected_size { | ||||
return Err(DirstatePackError::BadSize(expected_size, packed.len())); | return Err(HgError::CorruptedRepository(format!( | ||||
"bad dirstate size: {} != {}", | |||||
expected_size, | |||||
packed.len() | |||||
))); | |||||
} | } | ||||
Ok(packed) | Ok(packed) | ||||
} | } | ||||
/// `now` is the duration in seconds since the Unix epoch | /// `now` is the duration in seconds since the Unix epoch | ||||
#[cfg(feature = "dirstate-tree")] | #[cfg(feature = "dirstate-tree")] | ||||
pub fn pack_dirstate( | pub fn pack_dirstate( | ||||
state_map: &mut StateMap, | state_map: &mut StateMap, |
Overflow => "Overflow in dirstate.".to_string(), | Overflow => "Overflow in dirstate.".to_string(), | ||||
CorruptedEntry(e) => format!("Corrupted entry: {:?}.", e), | CorruptedEntry(e) => format!("Corrupted entry: {:?}.", e), | ||||
Damaged => "Dirstate appears to be damaged.".to_string(), | Damaged => "Dirstate appears to be damaged.".to_string(), | ||||
} | } | ||||
} | } | ||||
} | } | ||||
#[derive(Debug, PartialEq)] | #[derive(Debug, PartialEq)] | ||||
pub enum DirstatePackError { | |||||
CorruptedEntry(String), | |||||
CorruptedParent, | |||||
BadSize(usize, usize), | |||||
} | |||||
impl From<std::io::Error> for DirstatePackError { | |||||
fn from(e: std::io::Error) -> Self { | |||||
DirstatePackError::CorruptedEntry(e.to_string()) | |||||
} | |||||
} | |||||
#[derive(Debug, PartialEq)] | |||||
pub enum DirstateMapError { | pub enum DirstateMapError { | ||||
PathNotFound(HgPathBuf), | PathNotFound(HgPathBuf), | ||||
EmptyPath, | EmptyPath, | ||||
InvalidPath(HgPathError), | InvalidPath(HgPathError), | ||||
} | } | ||||
impl ToString for DirstateMapError { | impl ToString for DirstateMapError { | ||||
fn to_string(&self) -> String { | fn to_string(&self) -> String { | ||||
match self { | match self { | ||||
DirstateMapError::PathNotFound(_) => { | DirstateMapError::PathNotFound(_) => { | ||||
"expected a value, found none".to_string() | "expected a value, found none".to_string() | ||||
} | } | ||||
DirstateMapError::EmptyPath => "Overflow in dirstate.".to_string(), | DirstateMapError::EmptyPath => "Overflow in dirstate.".to_string(), | ||||
DirstateMapError::InvalidPath(e) => e.to_string(), | DirstateMapError::InvalidPath(e) => e.to_string(), | ||||
} | } | ||||
} | } | ||||
} | } | ||||
#[derive(Debug, derive_more::From)] | #[derive(Debug, derive_more::From)] | ||||
pub enum DirstateError { | pub enum DirstateError { | ||||
Parse(DirstateParseError), | Parse(DirstateParseError), | ||||
Pack(DirstatePackError), | |||||
Map(DirstateMapError), | Map(DirstateMapError), | ||||
IO(std::io::Error), | IO(std::io::Error), | ||||
Common(errors::HgError), | |||||
} | } | ||||
#[derive(Debug, derive_more::From)] | #[derive(Debug, derive_more::From)] | ||||
pub enum PatternError { | pub enum PatternError { | ||||
#[from] | #[from] | ||||
Path(HgPathError), | Path(HgPathError), | ||||
UnsupportedSyntax(String), | UnsupportedSyntax(String), | ||||
UnsupportedSyntaxInFile(String, String, usize), | UnsupportedSyntaxInFile(String, String, usize), |
//! | //! | ||||
//! From Python, this will be seen as `mercurial.rustext.parsers` | //! From Python, this will be seen as `mercurial.rustext.parsers` | ||||
use cpython::{ | use cpython::{ | ||||
exc, PyBytes, PyDict, PyErr, PyInt, PyModule, PyResult, PyTuple, Python, | exc, PyBytes, PyDict, PyErr, PyInt, PyModule, PyResult, PyTuple, Python, | ||||
PythonObject, ToPyObject, | PythonObject, ToPyObject, | ||||
}; | }; | ||||
use hg::{ | use hg::{ | ||||
pack_dirstate, parse_dirstate, utils::hg_path::HgPathBuf, DirstateEntry, | pack_dirstate, parse_dirstate, utils::hg_path::HgPathBuf, DirstateEntry, | ||||
DirstatePackError, DirstateParents, DirstateParseError, FastHashMap, | DirstateParents, DirstateParseError, FastHashMap, PARENT_SIZE, | ||||
PARENT_SIZE, | |||||
}; | }; | ||||
use std::convert::TryInto; | use std::convert::TryInto; | ||||
use crate::dirstate::{extract_dirstate, make_dirstate_tuple}; | use crate::dirstate::{extract_dirstate, make_dirstate_tuple}; | ||||
use std::time::Duration; | use std::time::Duration; | ||||
fn parse_dirstate_wrapper( | fn parse_dirstate_wrapper( | ||||
py: Python, | py: Python, | ||||
dmap.set_item( | dmap.set_item( | ||||
py, | py, | ||||
PyBytes::new(py, filename.as_bytes()), | PyBytes::new(py, filename.as_bytes()), | ||||
make_dirstate_tuple(py, &entry)?, | make_dirstate_tuple(py, &entry)?, | ||||
)?; | )?; | ||||
} | } | ||||
Ok(PyBytes::new(py, &packed)) | Ok(PyBytes::new(py, &packed)) | ||||
} | } | ||||
Err(error) => Err(PyErr::new::<exc::ValueError, _>( | Err(error) => { | ||||
py, | Err(PyErr::new::<exc::ValueError, _>(py, error.to_string())) | ||||
match error { | |||||
DirstatePackError::CorruptedParent => { | |||||
"expected a 20-byte hash".to_string() | |||||
} | |||||
DirstatePackError::CorruptedEntry(e) => e, | |||||
DirstatePackError::BadSize(expected, actual) => { | |||||
format!("bad dirstate size: {} != {}", actual, expected) | |||||
} | } | ||||
}, | |||||
)), | |||||
} | } | ||||
} | } | ||||
/// Create the module, with `__package__` given from parent | /// Create the module, with `__package__` given from parent | ||||
pub fn init_parsers_module(py: Python, package: &str) -> PyResult<PyModule> { | pub fn init_parsers_module(py: Python, package: &str) -> PyResult<PyModule> { | ||||
let dotted_name = &format!("{}.parsers", package); | let dotted_name = &format!("{}.parsers", package); | ||||
let m = PyModule::new(py, dotted_name)?; | let m = PyModule::new(py, dotted_name)?; | ||||