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!("");}