FIIUZR4LJOB5DPB4CBMPJHMO7C5Q4ZINUVM52UK6SIM5WM7R7ZLAC
D467LQZ62MTKWYPTMRBYTTR63CZDCE5WGBIGLQMSWAQYPHC3XITAC
OZUZ5H6DJUXJ2MEHQK6FQ7LTSPUHHGZSFZ3SPBV26A2KBE4TQKQQC
ATRA7XTTN62JZQOI7A4JI3Z7L3XVTAEEW2U4AX6UQKEQ6USOXQDQC
YNZMKRJDWYOQ3R3XHA2G47YG2SDI7FT7AEXH3OLB3BJGB6ALTRQAC
RVRUZGHUCMZO2UAXMT5NVJM62XK3B3TZWXZFWZKKGIX6RI7LPLCQC
TQBJZLD7Q223IFEBR7SU4FJWPWQWVBCSRPYYYEHXNSDM6DC7UWRAC
W7HZ5VFMEFVJIPYZJXOSMWTQ7DOZOOHT4QZTMDCT63AKIWB3TCZQC
UFSP7C7B2ERFJ2XVVVNXGZRXUEMFSMRABC5YXXLK6ONMFG6QBNHAC
#[derive(Debug, Clone)]
pub struct StateMismatch {
got: libpijul::Merkle,
want: libpijul::Merkle,
}
impl fmt::Display for StateMismatch {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
write!(
f,
"state mismatch: got {:?}, want {:?}",
self.got, self.want
)
}
}
impl Error for StateMismatch {}
}
pub fn new_sandbox(&mut self) -> Result<Sandbox, Box<dyn Error>> {
let change_store =
libpijul::changestore::filesystem::FileSystem::from_root(&Path::new(&self.path), 256);
let txn = self.pristine.arc_txn_begin()?;
let channel = txn.write().open_or_create_channel("pijul-export-sandbox")?;
return Ok(Sandbox {
change_store,
txn,
channel,
});
}
}
// A Sandbox has a temporary channel for applying changes and getting the
// contents of the affected files.
pub struct Sandbox {
change_store: libpijul::changestore::filesystem::FileSystem,
txn: libpijul::pristine::ArcTxn<libpijul::pristine::sanakirja::MutTxn<()>>,
channel: libpijul::pristine::ChannelRef<libpijul::pristine::sanakirja::MutTxn<()>>,
}
impl Sandbox {
pub fn add_change(&mut self, change: &Change) -> Result<(), Box<dyn Error>> {
let (_, new_state) = self.txn.write().apply_change(
&self.change_store,
&mut *self.channel.write(),
&change.hash,
)?;
if new_state != change.state {
return Err(Box::new(StateMismatch {
got: new_state,
want: change.state,
}));
}
return Ok(());
}
pub fn get_files(&mut self) -> Result<Vec<File>, Box<dyn Error>> {
let fs = FileSet {
files: Arc::new(Mutex::new(Vec::new())),
};
libpijul::output::output_repository_no_pending(
&fs,
&self.change_store,
&self.txn,
&self.channel,
"",
false,
None,
1,
0,
)?;
let mut files: Vec<File> = Vec::new();
let mut file_writers = match fs.files.lock() {
Ok(fw) => fw,
Err(err) => panic!("mutex error: {}", err),
};
for f in file_writers.drain(..) {
files.push(File {
name: f.name,
content: Arc::try_unwrap(f.content).unwrap().into_inner()?,
});
}
return Ok(files);
#[derive(Clone)]
pub struct FileWriter {
pub name: String,
pub content: Arc<Mutex<Vec<u8>>>,
}
impl std::io::Write for FileWriter {
fn write(&mut self, b: &[u8]) -> Result<usize, std::io::Error> {
match self.content.lock() {
Ok(mut c) => c.write(b),
Err(e) => panic!("{}", e),
}
}
fn flush(&mut self) -> Result<(), std::io::Error> {
Ok(())
}
}
#[derive(Clone)]
struct FileSet {
pub files: Arc<Mutex<Vec<FileWriter>>>,
}
#[derive(Debug, Clone)]
enum FileSetError {
RemoveNotImplemented(String),
RenameNotImplemented(String, String),
ReadNotImplemented,
MutexPoison,
}
impl Error for FileSetError {}
impl fmt::Display for FileSetError {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
match self {
FileSetError::RemoveNotImplemented(p) => {
write!(f, "not implemented: remove_path({})", p)
}
FileSetError::RenameNotImplemented(old, new) => {
write!(f, "not implemented: rename({}, {})", old, new)
}
FileSetError::ReadNotImplemented => write!(f, "not implemented: WorkingCopyRead"),
FileSetError::MutexPoison => write!(f, "poisoned mutex"),
}
}
}
impl WorkingCopyRead for FileSet {
type Error = FileSetError;
fn file_metadata(&self, _file: &str) -> Result<InodeMetadata, Self::Error> {
Err(FileSetError::ReadNotImplemented)
}
fn read_file(&self, _file: &str, _buffer: &mut Vec<u8>) -> Result<(), Self::Error> {
Err(FileSetError::ReadNotImplemented)
}
fn modified_time(&self, _file: &str) -> Result<std::time::SystemTime, Self::Error> {
Err(FileSetError::ReadNotImplemented)
}
}
impl WorkingCopy for FileSet {
type Writer = FileWriter;
fn create_dir_all(&self, _file: &str) -> Result<(), Self::Error> {
Ok(())
}
fn remove_path(&self, path: &str, _rec: bool) -> Result<(), Self::Error> {
Err(FileSetError::RemoveNotImplemented(path.to_string()))
}
fn rename(&self, old: &str, new: &str) -> Result<(), Self::Error> {
Err(FileSetError::RenameNotImplemented(
old.to_string(),
new.to_string(),
))
}
fn set_permissions(&self, _file: &str, _permissions: u16) -> Result<(), Self::Error> {
Ok(())
}
fn write_file(&self, file: &str, _: libpijul::Inode) -> Result<Self::Writer, Self::Error> {
let f = FileWriter {
name: file.to_string(),
content: Arc::new(Mutex::new(Vec::new())),
};
match self.files.lock() {
Ok(mut v) => v.push(f.clone()),
Err(_err) => return Err(FileSetError::MutexPoison),
}
return Ok(f);
}
}
pub fn write_commit(&mut self, c: &Change, parent: Option<libpijul::Merkle>, files: &Vec<File>) {
let mut file_marks = Vec::new();
for f in files {
self.max_blob_mark += 1;
let blob_mark = self.max_blob_mark;
file_marks.push(blob_mark);
println!("blob");
println!("mark :{}", blob_mark);
println!("data {}", f.content.len());
std::io::stdout().write_all(&f.content).unwrap();
println!("");
}