+byr-fogtix

This commit is contained in:
Alain Zscheile 2022-10-15 21:54:53 +02:00
parent a574fe6993
commit c2a0aba3a5
7 changed files with 949 additions and 7 deletions

438
Cargo.lock generated
View file

@ -8,6 +8,29 @@ version = "0.0.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "ec8ad6edb4840b78c5c3d88de606b22252d552b55f3a4699fbb10fc070ec3049"
[[package]]
name = "arrayref"
version = "0.3.6"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "a4c527152e37cf757a3f78aae5a06fbeefdb07ccc535c980a3208ee3060dd544"
[[package]]
name = "arrayvec"
version = "0.7.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "8da52d66c7071e2e3fa2a1e5c6d088fec47b593032b254f5e980de8ea54454d6"
[[package]]
name = "atty"
version = "0.2.14"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "d9b39be18770d11421cdb1b9947a45dd3f37e93092cbf377614828a319d5fee8"
dependencies = [
"hermit-abi",
"libc",
"winapi",
]
[[package]]
name = "base64"
version = "0.20.0-alpha.1"
@ -20,17 +43,54 @@ version = "1.3.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "bef38d45163c2f1dde094a7dfd33ccf595c92905c8f8f4fdc18d06fb1037718a"
[[package]]
name = "blake3"
version = "1.3.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "a08e53fc5a564bb15bfe6fae56bd71522205f1f91893f9c0116edad6496c183f"
dependencies = [
"arrayref",
"arrayvec",
"cc",
"cfg-if 1.0.0",
"constant_time_eq",
"digest",
]
[[package]]
name = "block-buffer"
version = "0.10.3"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "69cce20737498f97b993470a6e536b8523f0af7892a4f928cceb1ac5e52ebe7e"
dependencies = [
"generic-array",
]
[[package]]
name = "byr-core"
version = "0.1.0"
dependencies = [
"cap-std",
"cap-tempfile",
"fs2",
"tracing",
"yzb64",
"zstd",
]
[[package]]
name = "byr-fogtix"
version = "0.1.0"
dependencies = [
"blake3",
"byr-core",
"cap-std",
"clap",
"fogtix-vm",
"indicatif",
"yzb64",
]
[[package]]
name = "cap-primitives"
version = "0.26.1"
@ -62,6 +122,18 @@ dependencies = [
"rustix",
]
[[package]]
name = "cap-tempfile"
version = "0.26.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "c29f533e17e7a53e60c3a76d049bc8aea4f4800bd40df85a9a0376e0a59c48b7"
dependencies = [
"cap-std",
"rand",
"rustix",
"uuid",
]
[[package]]
name = "cc"
version = "1.0.73"
@ -71,12 +143,102 @@ dependencies = [
"jobserver",
]
[[package]]
name = "cfg-if"
version = "0.1.10"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "4785bdd1c96b2a846b2bd7cc02e86b6b3dbf14e7e53446c4f54c92a361040822"
[[package]]
name = "cfg-if"
version = "1.0.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "baf1de4339761588bc0619e3cbc0120ee582ebb74b53b4efbf79117bd2da40fd"
[[package]]
name = "clap"
version = "4.0.15"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "6bf8832993da70a4c6d13c581f4463c2bdda27b9bf1c5498dc4365543abe6d6f"
dependencies = [
"atty",
"bitflags",
"clap_derive",
"clap_lex",
"once_cell",
"strsim",
"termcolor",
]
[[package]]
name = "clap_derive"
version = "4.0.13"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "c42f169caba89a7d512b5418b09864543eeb4d497416c917d7137863bd2076ad"
dependencies = [
"heck",
"proc-macro-error",
"proc-macro2",
"quote",
"syn",
]
[[package]]
name = "clap_lex"
version = "0.3.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "0d4198f73e42b4936b35b5bb248d81d2b595ecb170da0bac7655c54eedfa8da8"
dependencies = [
"os_str_bytes",
]
[[package]]
name = "console"
version = "0.15.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "c050367d967ced717c04b65d8c619d863ef9292ce0c5760028655a2fb298718c"
dependencies = [
"encode_unicode",
"lazy_static",
"libc",
"terminal_size",
"unicode-width",
"winapi",
]
[[package]]
name = "constant_time_eq"
version = "0.1.5"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "245097e9a4535ee1e3e3931fcfcd55a796a44c643e8596ff6566d68f09b87bbc"
[[package]]
name = "crypto-common"
version = "0.1.6"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "1bfb12502f3fc46cca1bb51ac28df9d618d813cdc3d2f25b9fe775a34af26bb3"
dependencies = [
"generic-array",
"typenum",
]
[[package]]
name = "digest"
version = "0.10.5"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "adfbc57365a37acbd2ebf2b64d7e69bb766e2fea813521ed536f5d0520dcf86c"
dependencies = [
"block-buffer",
"crypto-common",
"subtle",
]
[[package]]
name = "encode_unicode"
version = "0.3.6"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "a357d28ed41a50f9c765dbfe56cbc04a64e53e5fc58ba79fbc34c10ef3df831f"
[[package]]
name = "errno"
version = "0.2.8"
@ -98,6 +260,24 @@ dependencies = [
"libc",
]
[[package]]
name = "fogtix-bytecode"
version = "0.0.0"
source = "git+https://git.exozy.me/zseri/fogtix.git#b889f626abafc7d230788a2cb4527e9e349850c2"
dependencies = [
"int-enum",
]
[[package]]
name = "fogtix-vm"
version = "0.0.0"
source = "git+https://git.exozy.me/zseri/fogtix.git#b889f626abafc7d230788a2cb4527e9e349850c2"
dependencies = [
"fogtix-bytecode",
"thiserror",
"tracing",
]
[[package]]
name = "fs-set-times"
version = "0.17.1"
@ -119,6 +299,76 @@ dependencies = [
"winapi",
]
[[package]]
name = "generic-array"
version = "0.14.6"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "bff49e947297f3312447abdca79f45f4738097cc82b06e72054d2223f601f1b9"
dependencies = [
"typenum",
"version_check",
]
[[package]]
name = "getrandom"
version = "0.2.7"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "4eb1a864a501629691edf6c15a593b7a51eebaa1e8468e9ddc623de7c9b58ec6"
dependencies = [
"cfg-if 1.0.0",
"libc",
"wasi",
]
[[package]]
name = "heck"
version = "0.4.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "2540771e65fc8cb83cd6e8a237f70c319bd5c29f78ed1084ba5d50eeac86f7f9"
[[package]]
name = "hermit-abi"
version = "0.1.19"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "62b467343b94ba476dcb2500d242dadbb39557df889310ac77c5d99100aaac33"
dependencies = [
"libc",
]
[[package]]
name = "indicatif"
version = "0.17.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "bfddc9561e8baf264e0e45e197fd7696320026eb10a8180340debc27b18f535b"
dependencies = [
"console",
"number_prefix",
"unicode-width",
]
[[package]]
name = "int-enum"
version = "0.4.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "2b1428b2b1abe959e6eedb0a17d0ab12f6ba20e1106cc29fc4874e3ba393c177"
dependencies = [
"cfg-if 0.1.10",
"int-enum-impl",
]
[[package]]
name = "int-enum-impl"
version = "0.4.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "a2c3cecaad8ca1a5020843500c696de2b9a07b63b624ddeef91f85f9bafb3671"
dependencies = [
"cfg-if 0.1.10",
"proc-macro-crate",
"proc-macro2",
"quote",
"syn",
]
[[package]]
name = "io-extras"
version = "0.15.0"
@ -156,6 +406,12 @@ dependencies = [
"libc",
]
[[package]]
name = "lazy_static"
version = "1.4.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "e2abad23fbc42b3700f2f279844dc832adb2b2eb069b2df918f455c4e18cc646"
[[package]]
name = "libc"
version = "0.2.135"
@ -174,18 +430,69 @@ version = "0.3.4"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "4facc753ae494aeb6e3c22f839b158aebd4f9270f55cd3c79906c45476c47ab4"
[[package]]
name = "number_prefix"
version = "0.4.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "830b246a0e5f20af87141b25c173cd1b609bd7779a4617d6ec582abaf90870f3"
[[package]]
name = "once_cell"
version = "1.15.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "e82dad04139b71a90c080c8463fe0dc7902db5192d939bd0950f074d014339e1"
[[package]]
name = "os_str_bytes"
version = "6.3.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "9ff7415e9ae3fff1225851df9e0d9e4e5479f947619774677a63572e55e80eff"
[[package]]
name = "pin-project-lite"
version = "0.2.9"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "e0a7ae3ac2f1173085d398531c705756c94a4c56843785df85a60c1a0afac116"
[[package]]
name = "ppv-lite86"
version = "0.2.16"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "eb9f9e6e233e5c4a35559a617bf40a4ec447db2e84c20b55a6f83167b7e57872"
[[package]]
name = "proc-macro-crate"
version = "0.1.5"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "1d6ea3c4595b96363c13943497db34af4460fb474a95c43f4446ad341b8c9785"
dependencies = [
"toml",
]
[[package]]
name = "proc-macro-error"
version = "1.0.4"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "da25490ff9892aab3fcf7c36f08cfb902dd3e71ca0f9f9517bea02a73a5ce38c"
dependencies = [
"proc-macro-error-attr",
"proc-macro2",
"quote",
"syn",
"version_check",
]
[[package]]
name = "proc-macro-error-attr"
version = "1.0.4"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "a1be40180e52ecc98ad80b184934baf3d0d29f979574e439af5a55274b35f869"
dependencies = [
"proc-macro2",
"quote",
"version_check",
]
[[package]]
name = "proc-macro2"
version = "1.0.47"
@ -204,6 +511,36 @@ dependencies = [
"proc-macro2",
]
[[package]]
name = "rand"
version = "0.8.5"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "34af8d1a0e25924bc5b7c43c079c942339d8f0a8b57c39049bef581b46327404"
dependencies = [
"libc",
"rand_chacha",
"rand_core",
]
[[package]]
name = "rand_chacha"
version = "0.3.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "e6c10a63a0fa32252be49d21e7709d4d4baf8d231c2dbce1eaa8141b9b127d88"
dependencies = [
"ppv-lite86",
"rand_core",
]
[[package]]
name = "rand_core"
version = "0.6.4"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "ec0be4795e2f6a28069bec0b5ff3e2ac9bafc99e6a9a7dc3547996c5c816922c"
dependencies = [
"getrandom",
]
[[package]]
name = "rustix"
version = "0.35.11"
@ -220,6 +557,24 @@ dependencies = [
"windows-sys",
]
[[package]]
name = "serde"
version = "1.0.145"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "728eb6351430bccb993660dfffc5a72f91ccc1295abaa8ce19b27ebe4f75568b"
[[package]]
name = "strsim"
version = "0.10.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "73473c0e59e6d5812c5dfe2a064a6444949f089e20eec9a2e5506596494e4623"
[[package]]
name = "subtle"
version = "2.4.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "6bdef32e8150c2a081110b42772ffe7d7c9032b606bc226c8260fd97e0976601"
[[package]]
name = "syn"
version = "1.0.102"
@ -231,13 +586,61 @@ dependencies = [
"unicode-ident",
]
[[package]]
name = "termcolor"
version = "1.1.3"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "bab24d30b911b2376f3a13cc2cd443142f0c81dda04c118693e35b3835757755"
dependencies = [
"winapi-util",
]
[[package]]
name = "terminal_size"
version = "0.1.17"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "633c1a546cee861a1a6d0dc69ebeca693bf4296661ba7852b9d21d159e0506df"
dependencies = [
"libc",
"winapi",
]
[[package]]
name = "thiserror"
version = "1.0.37"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "10deb33631e3c9018b9baf9dcbbc4f737320d2b576bac10f6aefa048fa407e3e"
dependencies = [
"thiserror-impl",
]
[[package]]
name = "thiserror-impl"
version = "1.0.37"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "982d17546b47146b28f7c22e3d08465f6b8903d0ea13c1660d9d84a6e7adcdbb"
dependencies = [
"proc-macro2",
"quote",
"syn",
]
[[package]]
name = "toml"
version = "0.5.9"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "8d82e1a7758622a465f8cee077614c73484dac5b836c02ff6a40d5d1010324d7"
dependencies = [
"serde",
]
[[package]]
name = "tracing"
version = "0.1.37"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "8ce8c33a8d48bd45d624a6e523445fd21ec13d3653cd51f681abf67418f54eb8"
dependencies = [
"cfg-if",
"cfg-if 1.0.0",
"pin-project-lite",
"tracing-attributes",
"tracing-core",
@ -263,12 +666,45 @@ dependencies = [
"once_cell",
]
[[package]]
name = "typenum"
version = "1.15.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "dcf81ac59edc17cc8697ff311e8f5ef2d99fcbd9817b34cec66f90b6c3dfd987"
[[package]]
name = "unicode-ident"
version = "1.0.5"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "6ceab39d59e4c9499d4e5a8ee0e2735b891bb7308ac83dfb4e80cad195c9f6f3"
[[package]]
name = "unicode-width"
version = "0.1.10"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "c0edd1e5b14653f783770bce4a4dabb4a5108a5370a5f5d8cfe8710c361f6c8b"
[[package]]
name = "uuid"
version = "1.2.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "feb41e78f93363bb2df8b0e86a2ca30eed7806ea16ea0c790d757cf93f79be83"
dependencies = [
"getrandom",
]
[[package]]
name = "version_check"
version = "0.9.4"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "49874b5167b65d7193b8aba1567f5c7d93d001cafc34600cee003eda787e483f"
[[package]]
name = "wasi"
version = "0.11.0+wasi-snapshot-preview1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "9c8d87e72b64a3b4db28d11ce29237c246188f4f51057d65a7eab63b7987e423"
[[package]]
name = "winapi"
version = "0.3.9"

View file

@ -6,6 +6,7 @@ license = "Apache-2.0"
[dependencies]
cap-std = "0.26"
cap-tempfile = "0.26"
fs2 = "0.4"
tracing = "0.1"
yzb64 = "0.1"

View file

@ -1,8 +1,6 @@
use core::fmt;
use std::io::{Read, Result as IoResult, Write};
/// Note that the first entry has a special meaning, it is the anchor hash
/// a changelist may also be empty in degraded cases (e.g. in a root snapshot)
#[derive(Clone, Default)]
pub struct ChangeList(pub Vec<crate::ChangeHash>);

View file

@ -1,5 +1,5 @@
use cap_std::fs::Dir;
use std::io::{Read, Result as IoResult, Write};
use std::io::{Error as IoError, ErrorKind as IoEk, Read, Result as IoResult, Write};
mod traits;
pub use traits::{Event, FlowData};
@ -40,6 +40,12 @@ fn yzb64_file_name(h: &ChangeHash) -> [u8; 43] {
buf
}
#[allow(dead_code)]
pub struct MassChangesGet {
cd: Dir,
l: RepoLock,
}
impl Changes {
pub fn insert(&self, h: &ChangeHash, contents: &[u8]) -> IoResult<bool> {
let buf = yzb64_file_name(h);
@ -70,9 +76,35 @@ impl Changes {
dcd.read_to_end(&mut buf2)?;
Ok(buf2)
}
pub fn massget(&self) -> IoResult<MassChangesGet> {
let l = RepoLock::lock_read(&self.0, ".lock")?;
Ok(MassChangesGet {
cd: self.0.try_clone()?,
l,
})
}
}
pub struct Snapshots(Dir);
impl MassChangesGet {
pub fn get(&self, h: &ChangeHash) -> IoResult<Vec<u8>> {
let buf = yzb64_file_name(h);
let buf = std::str::from_utf8(&buf).unwrap();
let mut dcd = zstd::stream::read::Decoder::new(self.cd.open(buf)?)?;
let mut buf2 = Vec::new();
dcd.read_to_end(&mut buf2)?;
Ok(buf2)
}
pub fn try_clone(&self) -> IoResult<Self> {
let l = RepoLock::lock_read(&self.cd, ".lock")?;
Ok(MassChangesGet {
cd: self.cd.try_clone()?,
l,
})
}
}
pub struct Snapshots(pub Dir);
impl Snapshots {
pub fn insert_thin(&self, name: &str, contents: &ThinSnapshot) -> IoResult<bool> {
@ -85,6 +117,20 @@ impl Snapshots {
Ok(true)
}
pub fn update_thin<R>(
&self,
name: &str,
mut tf: impl FnMut(&mut ThinSnapshot) -> IoResult<R>,
) -> IoResult<R> {
let _l = RepoLock::lock_write(&self.0, ".lock");
let mut snap = ThinSnapshot::read_from_stream(self.0.open(name)?)?;
let res = tf(&mut snap)?;
let mut tmpf = cap_tempfile::TempFile::new(&self.0)?;
snap.write_to_stream(&mut tmpf)?;
tmpf.replace(name)?;
Ok(res)
}
pub fn remove(&self, name: &str) -> IoResult<()> {
let _l = RepoLock::lock_write(&self.0, ".lock");
self.0.remove_file(name)
@ -95,4 +141,18 @@ impl Snapshots {
let f = self.0.open(name)?;
ThinSnapshot::read_from_stream(f)
}
pub fn fork(&self, old: &str, new: &str) -> IoResult<()> {
let _l = RepoLock::lock_write(&self.0, ".lock");
if self.0.exists(new) {
return Err(IoError::new(
IoEk::AlreadyExists,
"fork target already exists",
));
}
let mut src = self.0.open(old)?.into_std();
let mut trg = self.0.create(new)?.into_std();
std::io::copy(&mut src, &mut trg)?;
Ok(())
}
}

View file

@ -1,4 +1,4 @@
use cap_std::fs::{Dir, OpenOptions};
use cap_std::fs::Dir;
use fs2::FileExt;
use std::fs::File;
use std::io::Result as IoResult;
@ -21,7 +21,7 @@ impl RepoLock {
}
pub fn lock_write(d: &Dir, nam: &str) -> IoResult<RepoLock> {
let f = d.open_with(nam, OpenOptions::new().write(true))?.into_std();
let f = d.create(nam)?.into_std();
f.lock_exclusive()?;
Ok(RepoLock(f))
}

View file

@ -0,0 +1,20 @@
[package]
name = "byr-fogtix"
version = "0.1.0"
edition = "2021"
[dependencies]
cap-std = "0.26"
indicatif = "0.17"
blake3 = "1.3.1"
yzb64 = "0.1"
[dependencies.byr-core]
path = "../byr-core"
[dependencies.clap]
version = "4.0"
features = ["derive"]
[dependencies.fogtix-vm]
git = "https://git.exozy.me/zseri/fogtix.git"

View file

@ -0,0 +1,427 @@
use byr_core::{Event, ThinSnapshot};
use std::io::Result as IoResult;
#[derive(clap::Parser)]
#[command(version)]
struct Args {
#[arg(short = 'C')]
repo: String,
#[command(subcommand)]
command: Command,
}
#[derive(clap::Subcommand)]
enum Command {
Init {
/// the empty snapshot to create
#[arg(short)]
snapshot: String,
},
Remove {
/// the snapshot to remove
#[arg(short)]
snapshot: String,
},
Snapshot {
/// the snapshot to anchor this snapshot on
#[arg(short)]
anchor: String,
/// the snapshot to create
#[arg(short)]
snapshot: String,
},
Fork {
/// the snapshot to clone
#[arg(short)]
orig: String,
/// the snapshot to create
#[arg(short)]
snapshot: String,
},
Commit {
/// the snapshot to edit
#[arg(short)]
snapshot: String,
/// the bytecode file containing the current to-be-applied change
#[arg(short)]
bytecode_file: String,
},
Merge {
/// the snapshot to edit
#[arg(short)]
snapshot: String,
/// the snapshot to inject
#[arg(short)]
augment: String,
},
}
#[derive(PartialEq, Eq, PartialOrd)]
struct BytecodeWrapper<'a>(&'a [u8]);
impl Event for BytecodeWrapper<'_> {
type Data = Vec<u64>;
type Err = fogtix_vm::Error;
fn run(&self, data: &mut Vec<u64>) -> Result<(), fogtix_vm::Error> {
let mut p = fogtix_vm::Process {
stack: core::mem::take(data),
callstack: Vec::new(),
m: self.0,
instrp: 0,
};
p.run(None)
}
}
fn data_deser(din: &[u8]) -> IoResult<Vec<u64>> {
let mut dit = din.chunks_exact(8);
let data = (&mut dit)
.map(|i| u64::from_be_bytes(i.try_into().unwrap()))
.collect();
if !dit.remainder().is_empty() {
return Err(std::io::Error::new(
std::io::ErrorKind::InvalidData,
"invalid attached snapshot data",
));
}
Ok(data)
}
fn data_ser(din: Vec<u64>, dout: &mut Vec<u8>) {
dout.extend(din.into_iter().flat_map(|i| i.to_be_bytes()));
}
fn main() {
let args = <Args as clap::Parser>::parse();
std::fs::create_dir_all(&args.repo).expect("unable to create repository");
let repo = byr_core::Repository(
cap_std::fs::Dir::open_ambient_dir(&args.repo, cap_std::ambient_authority())
.expect("unable to open repository"),
);
match args.command {
Command::Init { snapshot } => {
let snapshots = repo.snapshots().unwrap();
if !snapshots
.insert_thin(
&snapshot,
&ThinSnapshot {
meta: [0u8; 256],
changelist: Default::default(),
data: Vec::new(),
},
)
.expect("unable to write snapshot")
{
eprintln!("ERROR: snapshot already exists");
std::process::exit(1);
}
}
Command::Snapshot { anchor, snapshot } => {
if anchor.len() > 256 {
eprintln!("ERROR: anchor name too long");
std::process::exit(1);
}
let snapshots = repo.snapshots().unwrap();
let anchor_data = snapshots.get_thin(&anchor).unwrap();
let mut meta = [0u8; 256];
meta[..anchor.len()].copy_from_slice(anchor.as_bytes());
if !snapshots
.insert_thin(
&snapshot,
&ThinSnapshot {
meta,
changelist: Default::default(),
data: anchor_data.data,
},
)
.expect("unable to write snapshot")
{
eprintln!("ERROR: snapshot already exists");
std::process::exit(1);
}
}
Command::Fork { orig, snapshot } => {
let snapshots = repo.snapshots().unwrap();
snapshots.fork(&orig, &snapshot).unwrap();
}
Command::Remove { snapshot } => {
let snapshots = repo.snapshots().unwrap();
snapshots.remove(&snapshot).unwrap();
}
Command::Commit {
snapshot,
bytecode_file,
} => {
let snapshots = repo.snapshots().unwrap();
let changes = repo.changes().unwrap();
let bytecode = std::fs::read(&bytecode_file).expect("unable to read bytecode file");
let hash = {
let mut hshr = blake3::Hasher::new();
hshr.update(&bytecode);
*hshr.finalize().as_bytes()
};
changes
.insert(&hash, &bytecode[..])
.expect("unable to insert change");
snapshots
.update_thin(&snapshot, |snap| {
snap.changelist.0.push(hash);
let mut data = data_deser(&snap.data)?;
snap.data.clear();
let olddata = data.clone();
BytecodeWrapper(&bytecode[..]).run(&mut data).map_err(|e| {
std::io::Error::new(std::io::ErrorKind::InvalidInput, e.to_string())
})?;
if olddata == data {
return Err(std::io::Error::new(
std::io::ErrorKind::InvalidData,
"change is a NOP",
));
}
data_ser(data, &mut snap.data);
Ok(())
})
.expect("unable to update snapshot");
}
Command::Merge { snapshot, augment } => {
let snapshots = repo.snapshots().unwrap();
let changes = repo.changes().unwrap();
let changes = changes
.massget()
.expect("unable to acquire changes dir read lock");
let mut b = snapshots
.get_thin(&augment)
.expect("unable to get augmenting snapshot");
b.data.clear();
b.data.shrink_to_fit();
snapshots
.update_thin(&snapshot, |snap| {
// 0. base snapshot -> base data
if snap.meta != b.meta {
return Err(std::io::Error::new(
std::io::ErrorKind::InvalidData,
"unable to merge snapshot with different anchors",
));
}
snap.data.clear();
snap.data.shrink_to_fit();
// retrieve base data; manually because `update_thin` holds the lock already
let mut data = {
let sn = snapshots.0.open(core::str::from_utf8(&snap.meta).map_err(
|_e| {
std::io::Error::new(
std::io::ErrorKind::InvalidData,
"unable to parse anchor",
)
},
)?)?;
data_deser(&byr_core::ThinSnapshot::read_from_stream(sn)?.data)?
};
let mprgs = indicatif::MultiProgress::new();
use indicatif::ProgressBar;
// 1. apply (largest) common leading subsequence
let pbarA = ProgressBar::new(snap.changelist.0.len().try_into().unwrap());
pbarA.set_prefix("S");
let mut ait = snap.changelist.0.iter().peekable();
let pbarB = ProgressBar::new(b.changelist.0.len().try_into().unwrap());
pbarA.set_prefix("U");
let mut bit = b.changelist.0.iter().peekable();
mprgs.add(pbarA.clone());
mprgs.add(pbarB.clone());
loop {
let (ap, bp) = match (ait.peek(), bit.peek()) {
(Some(ap), Some(bp)) => (ap, bp),
(_, _) => break,
};
if ap == bp {
let bytecode = changes.get(ap)?;
BytecodeWrapper(&bytecode[..]).run(&mut data).map_err(|e| {
std::io::Error::new(std::io::ErrorKind::InvalidInput, e.to_string())
})?;
pbarA.inc(1);
pbarB.inc(1);
ait.next();
bit.next();
} else {
break;
}
}
// 2. check the three different ways of merging the command sequences.
#[derive(Clone, Copy, Debug)]
enum X {
A(usize),
B(usize),
}
let restA = ait
.clone()
.enumerate()
.map(|(n, &i)| (X::A(n), i))
.collect::<Vec<_>>();
let restB = bit
.clone()
.enumerate()
.map(|(n, &i)| (X::B(n), i))
.collect::<Vec<_>>();
// this just relies on the fact that any remaining duplicates between A and B are idempotent
// TODO: compute common elements between restA & restB, and handle them specifically (dedup)
let appAB = restA
.iter()
.chain(restB.iter())
.copied()
.collect::<Vec<_>>();
let appBA = restB
.into_iter()
.chain(restA.into_iter())
.collect::<Vec<_>>();
let appMX = {
let mut mx = Vec::new();
// time for cursed merge-sort
while let (Some(ap), Some(bp)) = (ait.peek(), bit.peek()) {
use core::cmp::Ordering;
match ap.cmp(bp) {
Ordering::Less => {
mx.push(ait.next().unwrap());
pbarA.inc(1);
}
Ordering::Greater => {
mx.push(bit.next().unwrap());
pbarB.inc(1);
}
Ordering::Equal => {
mx.push(ait.next().unwrap());
pbarA.inc(1);
let _ = bit.next();
pbarB.inc(1);
}
}
}
// handle rest (either ait or bit should already be empty here)
mx.extend(ait);
pbarA.finish_and_clear();
mx.extend(bit);
pbarB.finish_and_clear();
mx
};
// run them...
let (data1, data2) = (data.clone(), data.clone());
let (changes1, changes2) = (changes.try_clone()?, changes.try_clone()?);
fn run_chain(
mut data: Vec<u64>,
chain: Vec<(X, [u8; 32])>,
changes: byr_core::MassChangesGet,
pbar: ProgressBar,
) -> IoResult<Vec<u64>> {
for (idx, i) in pbar.wrap_iter(chain.into_iter()) {
let mut p = fogtix_vm::Process {
stack: core::mem::take(&mut data),
callstack: Vec::new(),
m: &changes.get(&i)?,
instrp: 0,
};
p.run(None).map_err(|e| {
std::io::Error::new(
std::io::ErrorKind::InvalidInput,
format!("{:?}:{:?}", idx, e),
)
})?;
data = p.stack;
}
Ok(data)
}
let (pA, pB) = (
ProgressBar::new(appAB.len().try_into().unwrap()).with_prefix("s|aug"),
ProgressBar::new(appBA.len().try_into().unwrap()).with_prefix("aug|s"),
);
mprgs.add(pA.clone());
mprgs.add(pB.clone());
let tA = std::thread::spawn(move || run_chain(data1, appAB, changes1, pA));
let tB = std::thread::spawn(move || run_chain(data2, appBA, changes2, pB));
let pMX =
ProgressBar::new(appMX.len().try_into().unwrap()).with_prefix("s<m>aug");
mprgs.add(pMX.clone());
for (idx, i) in pMX.wrap_iter(appMX.into_iter()).enumerate() {
let mut p = fogtix_vm::Process {
stack: core::mem::take(&mut data),
callstack: Vec::new(),
m: &changes.get(i)?,
instrp: 0,
};
p.run(None).map_err(|e| {
std::io::Error::new(
std::io::ErrorKind::InvalidInput,
format!(
"{}:{}:{:?}",
idx,
yzb64::base64::display::Base64Display::from(
i,
&*yzb64::B64_ENGINE
),
e
),
)
})?;
data = p.stack;
}
let rA = tA.join().expect("s|aug thread failed")?;
let rB = tB.join().expect("aug|s thread failed")?;
let mut succ = true;
if rA != rB {
let _ = mprgs
.println("ERROR: the diverging parts don't commute with each other!");
succ = false;
}
if rA != data {
let _ = mprgs.println(
"ERROR: the merged version and s|aug have mismatching results!",
);
succ = false;
}
if rB != data {
let _ = mprgs.println(
"ERROR: the merged version and aug|s have mismatching results!",
);
succ = false;
}
if !succ {
return Err(std::io::Error::new(
std::io::ErrorKind::InvalidData,
"merging failed".to_string(),
));
}
data_ser(data, &mut snap.data);
Ok(())
})
.expect("unable to update snapshot");
}
}
}