WIP
This commit is contained in:
@@ -7,7 +7,7 @@ license = "AGPL-3.0-or-later"
|
||||
|
||||
[dependencies]
|
||||
error-chain = "0.12.2"
|
||||
serde = "1.0.106"
|
||||
serde = { version = "1.0.106", features = ["derive"] }
|
||||
toml = "0.5.6"
|
||||
uuid = { version = "0.8.1", features = ["serde", "v4"] }
|
||||
tempfile = "3.1.0"
|
||||
|
||||
@@ -52,5 +52,15 @@ error_chain! {
|
||||
description("Mismatching object size")
|
||||
display("Mismatching object size: expected {}, got {}.", actual, expected)
|
||||
}
|
||||
|
||||
UnsupportedFileType {
|
||||
description("Unsupported file type")
|
||||
display("Unsupported file type.")
|
||||
}
|
||||
|
||||
InvalidPath(path: PathBuf) {
|
||||
description("Invalid path")
|
||||
display("Invalid path: {:?}.", path)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -21,8 +21,8 @@ pub mod object;
|
||||
pub mod repository;
|
||||
|
||||
|
||||
pub const NAME: &'static str = env!("CARGO_PKG_NAME");
|
||||
pub const VERSION: &'static str = env!("CARGO_PKG_VERSION");
|
||||
pub const NAME: &str = env!("CARGO_PKG_NAME");
|
||||
pub const VERSION: &str = env!("CARGO_PKG_VERSION");
|
||||
|
||||
|
||||
pub use error::{Error, Result, ErrorKind};
|
||||
|
||||
@@ -14,7 +14,162 @@
|
||||
// along with cdb. If not, see <https://www.gnu.org/licenses/>.
|
||||
|
||||
|
||||
use std::path::{Path};
|
||||
use std::fs::Metadata;
|
||||
use std::os::unix::fs::MetadataExt;
|
||||
|
||||
use crate::core::error::*;
|
||||
use crate::{ObjectId};
|
||||
|
||||
|
||||
pub type ObjectType = [u8; 4];
|
||||
|
||||
pub const OTYPE_BLOB: &ObjectType = b"blob";
|
||||
pub const OTYPE_TREE: &ObjectType = b"tree";
|
||||
|
||||
pub fn object_type_from_metadata(md: &Metadata) -> Result<ObjectType> {
|
||||
if md.is_file() {
|
||||
Ok(*OTYPE_BLOB)
|
||||
}
|
||||
else if md.is_dir() {
|
||||
Ok(*OTYPE_TREE)
|
||||
}
|
||||
else {
|
||||
Err(ErrorKind::UnsupportedFileType.into())
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
enum PermissionsFlag {
|
||||
Read = 0x04,
|
||||
Write = 0x02,
|
||||
Execute = 0x01,
|
||||
}
|
||||
|
||||
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
|
||||
pub struct Permissions {
|
||||
flags: u8,
|
||||
}
|
||||
|
||||
impl Default for Permissions {
|
||||
fn default() -> Permissions {
|
||||
Permissions { flags: 0 }
|
||||
}
|
||||
}
|
||||
|
||||
impl Permissions {
|
||||
pub fn read_only() -> Permissions {
|
||||
*Self::default().set_read(true)
|
||||
}
|
||||
|
||||
pub fn read_write() -> Permissions {
|
||||
*Self::read_only().set_write(true)
|
||||
}
|
||||
|
||||
pub fn read_execute() -> Permissions {
|
||||
*Self::read_only().set_execute(true)
|
||||
}
|
||||
|
||||
pub fn read_write_execute() -> Permissions {
|
||||
*Self::read_write().set_execute(true)
|
||||
}
|
||||
|
||||
pub fn from_unix_mode(mode: u32) -> Permissions {
|
||||
*Self::default()
|
||||
.set_read(mode & 0o400 != 0)
|
||||
.set_write(mode & 0o200 != 0)
|
||||
.set_execute(mode & 0o100 != 0)
|
||||
}
|
||||
|
||||
pub fn is_read(&self) -> bool {
|
||||
self.test_flag(PermissionsFlag::Read)
|
||||
}
|
||||
|
||||
pub fn is_write(&self) -> bool {
|
||||
self.test_flag(PermissionsFlag::Write)
|
||||
}
|
||||
|
||||
pub fn is_execute(&self) -> bool {
|
||||
self.test_flag(PermissionsFlag::Execute)
|
||||
}
|
||||
|
||||
pub fn set_read(&mut self, read: bool) -> &mut Self {
|
||||
self.set_flag(PermissionsFlag::Read, read)
|
||||
}
|
||||
|
||||
pub fn set_write(&mut self, write: bool) -> &mut Self {
|
||||
self.set_flag(PermissionsFlag::Write, write)
|
||||
}
|
||||
|
||||
pub fn set_execute(&mut self, execute: bool) -> &mut Self {
|
||||
self.set_flag(PermissionsFlag::Execute, execute)
|
||||
}
|
||||
|
||||
fn test_flag(&self, flag: PermissionsFlag) -> bool {
|
||||
(self.flags & flag as u8) != 0
|
||||
}
|
||||
|
||||
fn set_flag(&mut self, flag: PermissionsFlag, value: bool) -> &mut Self {
|
||||
if value { self.flags |= flag as u8; }
|
||||
else { self.flags &= !(flag as u8); }
|
||||
self
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
pub struct TreeItem {
|
||||
otype: ObjectType,
|
||||
oid: ObjectId,
|
||||
modification_time: i64,
|
||||
permissions: Permissions,
|
||||
name: String,
|
||||
}
|
||||
|
||||
impl TreeItem {
|
||||
pub fn new(otype: &ObjectType, oid: &ObjectId, name: &str) -> TreeItem {
|
||||
TreeItem {
|
||||
otype: *otype,
|
||||
oid: oid.clone(),
|
||||
modification_time: 0,
|
||||
permissions: Permissions::read_write_execute(),
|
||||
name: name.into(),
|
||||
}
|
||||
}
|
||||
|
||||
pub fn from_file_path_and_id(file_path: &Path, oid: &ObjectId) -> Result<TreeItem> {
|
||||
let md = file_path.symlink_metadata()?;
|
||||
Ok(TreeItem {
|
||||
otype: object_type_from_metadata(&md)?,
|
||||
oid: oid.clone(),
|
||||
modification_time: md.mtime(),
|
||||
permissions: Permissions::from_unix_mode(md.mode()),
|
||||
name: file_path.file_name()
|
||||
.and_then(|n| n.to_str())
|
||||
.ok_or_else(|| ErrorKind::InvalidPath(file_path.into()))?
|
||||
.into(),
|
||||
})
|
||||
}
|
||||
|
||||
pub fn object_type(&self) -> ObjectType {
|
||||
self.otype
|
||||
}
|
||||
|
||||
pub fn object_id(&self) -> &ObjectId {
|
||||
&self.oid
|
||||
}
|
||||
|
||||
pub fn modification_time(&self) -> i64 {
|
||||
self.modification_time
|
||||
}
|
||||
|
||||
pub fn permissions(&self) -> &Permissions {
|
||||
&self.permissions
|
||||
}
|
||||
|
||||
pub fn name(&self) -> &str {
|
||||
&self.name
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
pub type TreeObject = Vec<TreeItem>;
|
||||
|
||||
@@ -15,13 +15,14 @@
|
||||
|
||||
|
||||
use std::fmt;
|
||||
use std::str::{FromStr};
|
||||
|
||||
use super::error::*;
|
||||
|
||||
|
||||
/// A unique identifier for an object.
|
||||
///
|
||||
/// This is the handle used to referenc an Object. This is an opaque type that uniquely identify an
|
||||
/// This is the handle used to reference an Object. This is an opaque type that uniquely identify an
|
||||
/// object. It can be compared to another ObjectId, be hashed and that's about it.
|
||||
#[derive(Clone, PartialEq, Eq, PartialOrd, Ord, Hash)]
|
||||
pub struct ObjectId {
|
||||
@@ -35,8 +36,13 @@ impl ObjectId {
|
||||
id: id.into(),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
pub fn from_str(id_str: &str) -> Result<ObjectId> {
|
||||
|
||||
impl FromStr for ObjectId {
|
||||
type Err = Error;
|
||||
|
||||
fn from_str(id_str: &str) -> Result<ObjectId> {
|
||||
if id_str.len() % 2 != 0 {
|
||||
return Err(ErrorKind::InvalidObjectIdSize.into());
|
||||
}
|
||||
@@ -78,6 +84,8 @@ impl fmt::Debug for ObjectId {
|
||||
|
||||
#[cfg(test)]
|
||||
mod tests {
|
||||
use std::str::{FromStr};
|
||||
|
||||
use super::ObjectId;
|
||||
|
||||
#[test]
|
||||
|
||||
@@ -26,7 +26,7 @@ use super::config::{Config, RepositoryConfig};
|
||||
use crate::simple_db::SimpleDb;
|
||||
|
||||
|
||||
const CONFIG_FILENAME: &'static str = ".bsv";
|
||||
const CONFIG_FILENAME: &str = ".bsv";
|
||||
|
||||
|
||||
#[derive(Debug)]
|
||||
@@ -42,7 +42,7 @@ impl Repository {
|
||||
bail!(ErrorKind::NonEmptyDirectory(path.into()))
|
||||
}
|
||||
|
||||
if device_name.len() == 0 {
|
||||
if device_name.is_empty() {
|
||||
bail!("Device name must not be empty.")
|
||||
}
|
||||
|
||||
@@ -74,7 +74,7 @@ impl Repository {
|
||||
|
||||
Ok(Repository {
|
||||
config: Rc::clone(&config),
|
||||
db: SimpleDb::new(path.into())?,
|
||||
db: SimpleDb::new(path)?,
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
@@ -16,6 +16,7 @@
|
||||
|
||||
#[macro_use]
|
||||
extern crate error_chain;
|
||||
extern crate serde;
|
||||
|
||||
|
||||
pub mod core;
|
||||
|
||||
@@ -129,6 +129,8 @@ impl SimpleDb {
|
||||
|
||||
#[cfg(test)]
|
||||
mod tests {
|
||||
use std::str::{FromStr};
|
||||
|
||||
use super::ObjectId;
|
||||
use super::SimpleDb;
|
||||
|
||||
@@ -14,11 +14,11 @@
|
||||
// along with cdb. If not, see <https://www.gnu.org/licenses/>.
|
||||
|
||||
|
||||
pub mod simple_db;
|
||||
pub mod db;
|
||||
pub mod object;
|
||||
|
||||
|
||||
pub use simple_db::SimpleDb;
|
||||
pub use db::SimpleDb;
|
||||
pub use object::{
|
||||
ObjectReader,
|
||||
};
|
||||
|
||||
@@ -185,6 +185,8 @@ impl<T: Read + Seek> WriteAsObject for T {
|
||||
|
||||
#[cfg(test)]
|
||||
mod tests {
|
||||
use std::str::{FromStr};
|
||||
|
||||
use crate::core::OTYPE_BLOB;
|
||||
|
||||
use super::*;
|
||||
|
||||
@@ -18,6 +18,7 @@ extern crate tempfile;
|
||||
extern crate libbsv;
|
||||
|
||||
|
||||
use std::str::{FromStr};
|
||||
use std::path::{PathBuf};
|
||||
use std::io::{Cursor, Read};
|
||||
use std::fs::{create_dir_all, write};
|
||||
|
||||
Reference in New Issue
Block a user