Converting to the new patch format "online"

[?]
Jun 3, 2021, 10:09 AM
SMMBFECLGSUKRZW5YPOQPOQCOY2CH2OTZXBSZ3KG2N3J3HQZ5PSAC

Dependencies

  • [2] RRCSHAYZ Formatting
  • [3] EEBKW7VT Keys and identities
  • [4] PSKXR4QE Do not load the entire change in memory in log
  • [5] CCLLB7OI Upgrading to Sanakirja 0.15 + version bump
  • [6] SLJ3OHD4 unrecord: show list of changes if none were given as arguments
  • [7] 3S6LU2U5 abstract out FileMetadata (de)serialistion
  • [8] CIEUBH46 Fixing an index-out-of-bounds error when serialising bad changes
  • [9] CCFJ7VO3 Renaming "Record" to "Hunk" in the changes
  • [10] 6YMDOZIB Refactoring apply
  • [11] SXEYMYF7 Fixing the bad changes in history (unfortunately, by rebooting).
  • [12] VO5OQW4W Removing anyhow in libpijul
  • [13] YN63NUZO Sanakirja 1.0
  • [14] I24UEJQL Various post-fire fixes
  • [15] QL6K2ZM3 Tags
  • [16] AAXP2534 Tags: completing the subcommand
  • [17] 5OGOE4VW Store the current channel in the pristine
  • [18] TFPETWTV Add config options for patch message templates
  • [19] UNZXTNSJ Change text format: order dependencies in the order they were on the channel at record time
  • [20] ZRUPLBBT Colours in diff and change: separating concerns and dependencies
  • [21] ZSF3YFZT encoded file deletion
  • [22] SE4RJYBZ No pager on Windows (really not)
  • [*] L4JXJHWX pijul/*: reorganize imports and remove extern crate

Change contents

  • replacement in pijul/src/commands/tag.rs at line 158
    [3.720][3.720:757]()
    authors.push(a.to_string());
    [3.720]
    [3.757]
    authors.push(a.to_string().into());
  • replacement in pijul/src/commands/tag.rs at line 163
    [3.1002][3.1002:1034]()
    authors.push(k.key)
    [3.1002]
    [3.1034]
    authors.push(k.key.into())
  • replacement in pijul/src/commands/record.rs at line 221
    [3.2140][3.2140:2177]()
    authors.push(a.clone());
    [3.2140]
    [3.2177]
    authors.push(a.clone().into());
  • replacement in pijul/src/commands/record.rs at line 226
    [3.2438][3.2438:2474]()
    authors.push(k.key)
    [3.2438]
    [3.2474]
    authors.push(k.key.into())
    } else {
    bail!("No identity configured yet. Please use `pijul key` to create one")
  • replacement in pijul/src/commands/mod.rs at line 188
    [4.4328][4.4328:4369]()
    write!(v, "{}", a).unwrap();
    [4.4328]
    [4.4369]
    write!(v, "{}", a.name).unwrap();
  • edit in pijul/src/commands/mod.rs at line 217
    [4.5215]
    [4.5215]
    }
    use serde_derive::*;
    #[derive(Debug, Serialize, Deserialize)]
    pub struct Identity {
    public_key: libpijul::key::PublicKey,
    name: String,
    #[serde(default, skip_serializing_if = "String::is_empty")]
    origin: String,
    #[serde(default, skip_serializing_if = "Option::is_none")]
    email: Option<String>,
  • edit in pijul/src/commands/log.rs at line 1
    [4.134376]
    [24.2043]
    use std::collections::hash_map::Entry;
    use std::collections::HashMap;
  • edit in pijul/src/commands/log.rs at line 56
    [4.135743]
    [4.19446]
    let mut authors = HashMap::new();
    let mut id_path = if let Some(mut dir) = crate::config::global_config_dir() {
    dir.push("identities");
    Some(dir)
    } else {
    None
    };
  • replacement in pijul/src/commands/log.rs at line 70
    [4.135936][4.55:122]()
    writeln!(stdout, "Author: {:?}", header.authors)?;
    [4.135936]
    [4.122]
    write!(stdout, "Author: ")?;
    let mut is_first = true;
    for auth in header.authors.into_iter() {
    let auth = match authors.entry(auth.name) {
    Entry::Occupied(e) => e.into_mut(),
    Entry::Vacant(e) => {
    let mut id = None;
    if let Some(ref mut p) = id_path {
    p.push(e.key());
    if let Ok(f) = std::fs::File::open(&p) {
    if let Ok(id_) =
    serde_json::from_reader::<_, super::Identity>(f)
    {
    id = Some(id_)
    }
    }
    p.pop();
    }
    if let Some(id) = id {
    e.insert(id.name)
    } else {
    let k = e.key().to_string();
    e.insert(k)
    }
    }
    };
    if is_first {
    is_first = false;
    write!(stdout, "{}", auth)?;
    } else {
    write!(stdout, ", {}", auth)?;
    }
    }
    writeln!(stdout)?;
  • replacement in pijul/src/commands/key.rs at line 17
    [3.2839][3.2839:2856]()
    Generate {},
    [3.2839]
    [3.2856]
    Generate {
    #[clap(long = "email")]
    email: Option<String>,
    name: String,
    },
  • replacement in pijul/src/commands/key.rs at line 27
    [3.2956][3.2956:3003]()
    Some(SubCommand::Generate {}) => {
    [3.2956]
    [3.3003]
    Some(SubCommand::Generate { email, name }) => {
  • edit in pijul/src/commands/key.rs at line 29
    [3.3064]
    [3.3064]
    std::fs::create_dir_all(&dir)?;
  • edit in pijul/src/commands/key.rs at line 51
    [3.4058][3.4058:4059]()
  • edit in pijul/src/commands/key.rs at line 54
    [3.4218]
    [3.4218]
  • replacement in pijul/src/commands/key.rs at line 58
    [3.4383][3.4383:4459]()
    serde_json::to_writer_pretty(&mut f, &k.public_key())?;
    [3.4383]
    [3.4459]
    let pk = k.public_key();
    serde_json::to_writer_pretty(&mut f, &pk)?;
    f.write_all(b"\n")?;
    dir.pop();
    dir.push("identities");
    std::fs::create_dir_all(&dir)?;
    dir.push(&pk.key);
    debug!("creating file {:?}", dir);
    let mut f = std::fs::File::create(&dir)?;
    serde_json::to_writer_pretty(
    &mut f,
    &super::Identity {
    public_key: pk,
    origin: String::new(),
    name,
    email,
    },
    )?;
  • replacement in libpijul/src/tag.rs at line 82
    [4.8017][4.8017:8045]()
    pub const VERSION: u64 = 5;
    [4.8017]
    [4.8045]
    pub const VERSION: u64 = 7;
    pub const VERSION_NOENC: u64 = 5;
  • edit in libpijul/src/key.rs at line 36
    [3.5852]
    [3.5852]
    #[serde(default, skip_serializing_if = "Option::is_none")]
  • edit in libpijul/src/key.rs at line 114
    [3.7937]
    [3.7937]
    let secret = ed25519_dalek::SecretKey::from_bytes(&key).unwrap();
  • replacement in libpijul/src/key.rs at line 116
    [3.7961][3.7961:8029]()
    key: ed25519_dalek::Keypair::from_bytes(&key).unwrap(),
    [3.7961]
    [3.8029]
    key: ed25519_dalek::Keypair {
    public: (&secret).into(),
    secret,
    },
  • edit in libpijul/src/key.rs at line 363
    [3.16320]
    [3.16320]
    }
    #[derive(Clone, Copy)]
    pub struct SerializedKey {
    pub(crate) t: u8,
    k: K,
    }
    impl From<ed25519_dalek::PublicKey> for SerializedKey {
    fn from(k: ed25519_dalek::PublicKey) -> Self {
    SerializedKey {
    t: 0,
    k: K {
    ed25519: k.as_bytes().clone(),
    },
    }
    }
    }
    impl From<SerializedKey> for ed25519_dalek::PublicKey {
    fn from(k: SerializedKey) -> Self {
    assert_eq!(k.t, 0);
    unsafe { ed25519_dalek::PublicKey::from_bytes(&k.k.ed25519).unwrap() }
    }
  • edit in libpijul/src/key.rs at line 388
    [3.16322]
    #[derive(Clone, Copy)]
    pub(crate) union K {
    ed25519: [u8; 32],
    }
  • replacement in libpijul/src/changestore/mod.rs at line 101
    [2.4033][4.2460:2503](),[4.2460][4.2460:2503]()
    bincode::deserialize(buf).unwrap()
    [2.4033]
    [4.2503]
    if let Ok(m) = bincode::deserialize(buf) {
    m
    } else {
    let (a, b) = buf.split_at(2);
    use byteorder::ByteOrder;
    FileMetadata {
    metadata: InodeMetadata(byteorder::BigEndian::read_u16(a)),
    basename: std::str::from_utf8(b).unwrap(),
    encoding: None,
    }
    }
  • edit in libpijul/src/change.rs at line 17
    [4.36178]
    [4.36178]
    mod noenc;
  • replacement in libpijul/src/change.rs at line 22
    [4.36226][4.36226:36280]()
    #[error("Version mismatch")]
    VersionMismatch,
    [4.36226]
    [4.36280]
    #[error("Version mismatch: got {}", got)]
    VersionMismatch { got: u64 },
  • replacement in libpijul/src/change.rs at line 113
    [4.833227][3.16387:16417]()
    pub authors: Vec<String>,
    [4.833227]
    [4.834123]
    pub authors: Vec<Author>,
    }
    #[derive(Debug, Serialize, Deserialize, Clone, PartialEq, Eq, Default)]
    pub struct Author {
    pub name: String,
    #[serde(default)]
    pub full_name: Option<String>,
    #[serde(default)]
    pub email: Option<String>,
    }
    impl From<String> for Author {
    fn from(name: String) -> Author {
    Author {
    name,
    ..Author::default()
    }
    }
  • replacement in libpijul/src/change.rs at line 146
    [4.834452][4.834452:834484]()
    pub struct LocalChange<Local> {
    [4.834452]
    [4.834484]
    pub struct LocalChange<Hunk> {
  • replacement in libpijul/src/change.rs at line 148
    [4.834510][4.834510:834541]()
    pub hashed: Hashed<Local>,
    [4.834510]
    [4.834541]
    pub hashed: Hashed<Hunk>,
  • replacement in libpijul/src/change.rs at line 155
    [4.834670][4.834670:834749]()
    impl std::ops::Deref for LocalChange<Local> {
    type Target = Hashed<Local>;
    [4.834670]
    [4.834749]
    impl std::ops::Deref for LocalChange<Hunk<Option<Hash>, Local>> {
    type Target = Hashed<Hunk<Option<Hash>, Local>>;
  • replacement in libpijul/src/change.rs at line 162
    [4.834818][4.834818:834867]()
    impl std::ops::DerefMut for LocalChange<Local> {
    [4.834818]
    [4.834867]
    impl std::ops::DerefMut for LocalChange<Hunk<Option<Hash>, Local>> {
  • replacement in libpijul/src/change.rs at line 168
    [4.834952][4.138043:138096](),[4.138096][3.16464:16492]()
    // Beware of change the version, tags also use that.
    pub const VERSION: u64 = 5;
    [4.834952]
    [4.834980]
    // Beware of changes in the version, tags also use that.
    pub const VERSION: u64 = 6;
    pub const VERSION_NOENC: u64 = 4;
  • replacement in libpijul/src/change.rs at line 173
    [4.835040][4.835040:835067]()
    pub struct Hashed<Local> {
    [4.835040]
    [4.835067]
    pub struct Hashed<Hunk> {
  • replacement in libpijul/src/change.rs at line 185
    [4.835524][4.2773:2822]()
    pub changes: Vec<Hunk<Option<Hash>, Local>>,
    [4.835524]
    [4.835575]
    pub changes: Vec<Hunk>,
  • replacement in libpijul/src/change.rs at line 191
    [4.835735][4.835735:835773]()
    pub type Change = LocalChange<Local>;
    [4.835735]
    [4.835773]
    pub type Change = LocalChange<Hunk<Option<Hash>, Local>>;
  • replacement in libpijul/src/change.rs at line 1204
    [4.867084][4.867084:867109]()
    impl<L> LocalChange<L> {
    [4.867084]
    [4.867109]
    impl LocalChange<Hunk<Option<Hash>, Local>> {
  • replacement in libpijul/src/change.rs at line 1211
    [4.867256][4.8393:8438]()
    changes: Vec<Hunk<Option<Hash>, L>>,
    [4.867256]
    [4.867303]
    changes: Vec<Hunk<Option<Hash>, Local>>,
  • replacement in libpijul/src/change.rs at line 1290
    [4.869721][4.869721:869757](),[4.869757][4.37256:37310]()
    if off.version != VERSION {
    return Err(ChangeError::VersionMismatch);
    [4.869721]
    [4.869812]
    if off.version != VERSION && off.version != VERSION_NOENC {
    return Err(ChangeError::VersionMismatch { got: off.version });
  • replacement in libpijul/src/change.rs at line 1352
    [4.871982][4.37475:37529]()
    return Err(ChangeError::VersionMismatch);
    [4.871982]
    [4.872037]
    return Err(ChangeError::VersionMismatch {
    got: offsets.version,
    });
  • replacement in libpijul/src/change.rs at line 1377
    [4.872818][4.872818:872884]()
    let hashed: Hashed<Local> = bincode::deserialize(&buf_)?;
    [4.872818]
    [4.872884]
    let hashed: Hashed<Hunk<Option<Hash>, Local>> = bincode::deserialize(&buf_)?;
  • replacement in libpijul/src/change.rs at line 1408
    [4.874114][4.874114:874154](),[4.874154][4.37754:37808]()
    if offsets.version != VERSION {
    return Err(ChangeError::VersionMismatch);
    [4.874114]
    [4.874209]
    if offsets.version == VERSION_NOENC {
    return Self::deserialize_noenc(offsets, r, hash);
    } else if offsets.version != VERSION {
    return Err(ChangeError::VersionMismatch {
    got: offsets.version,
    });
  • replacement in libpijul/src/change.rs at line 1420
    [4.874394][4.874394:874432]()
    let hashed: Hashed<Local> = {
    [4.874394]
    [4.874432]
    let hashed: Hashed<Hunk<Option<Hash>, Local>> = {
  • replacement in libpijul/src/change.rs at line 1446
    [4.875516][3.16550:16598]()
    Some(serde_json::from_slice(&out)?)
    [4.875516]
    [4.875562]
    debug!("parsing unhashed: {:?}", std::str::from_utf8(&out));
    serde_json::from_slice(&out).ok()
  • replacement in libpijul/src/change/text_changes.rs at line 38
    [4.38731][4.38731:38757]()
    impl LocalChange<Local> {
    [4.38731]
    [4.38757]
    impl LocalChange<Hunk<Option<Hash>, Local>> {
  • file addition: noenc.rs (----------)
    [4.931000]
    use super::{Atom, Change, ChangeError, Hashed, Local, LocalChange, Offsets};
    use crate::pristine::Hasher;
    use crate::Hash;
    #[derive(Debug, PartialEq, Eq, Clone, Serialize, Deserialize)]
    pub enum Hunk<Hash, Local> {
    FileMove {
    del: Atom<Hash>,
    add: Atom<Hash>,
    path: String,
    },
    FileDel {
    del: Atom<Hash>,
    contents: Option<Atom<Hash>>,
    path: String,
    },
    FileUndel {
    undel: Atom<Hash>,
    contents: Option<Atom<Hash>>,
    path: String,
    },
    FileAdd {
    add_name: Atom<Hash>,
    add_inode: Atom<Hash>,
    contents: Option<Atom<Hash>>,
    path: String,
    },
    SolveNameConflict {
    name: Atom<Hash>,
    path: String,
    },
    UnsolveNameConflict {
    name: Atom<Hash>,
    path: String,
    },
    Edit {
    change: Atom<Hash>,
    local: Local,
    },
    Replacement {
    change: Atom<Hash>,
    replacement: Atom<Hash>,
    local: Local,
    },
    SolveOrderConflict {
    change: Atom<Hash>,
    local: Local,
    },
    UnsolveOrderConflict {
    change: Atom<Hash>,
    local: Local,
    },
    ResurrectZombies {
    change: Atom<Hash>,
    local: Local,
    },
    }
    impl<H, L> From<Hunk<H, L>> for super::Hunk<H, L> {
    fn from(h: Hunk<H, L>) -> Self {
    match h {
    Hunk::FileMove { del, add, path } => super::Hunk::FileMove { del, add, path },
    Hunk::FileDel {
    del,
    contents,
    path,
    } => super::Hunk::FileDel {
    del,
    contents,
    path,
    encoding: None,
    },
    Hunk::FileUndel {
    undel,
    contents,
    path,
    } => super::Hunk::FileUndel {
    undel,
    contents,
    path,
    encoding: None,
    },
    Hunk::FileAdd {
    add_name,
    add_inode,
    contents,
    path,
    } => super::Hunk::FileAdd {
    add_name,
    add_inode,
    contents,
    path,
    encoding: None,
    },
    Hunk::SolveNameConflict { name, path } => super::Hunk::SolveNameConflict { name, path },
    Hunk::UnsolveNameConflict { name, path } => {
    super::Hunk::UnsolveNameConflict { name, path }
    }
    Hunk::Edit { change, local } => super::Hunk::Edit {
    change,
    local,
    encoding: None,
    },
    Hunk::Replacement {
    change,
    replacement,
    local,
    } => super::Hunk::Replacement {
    change,
    replacement,
    local,
    encoding: None,
    },
    Hunk::SolveOrderConflict { change, local } => {
    super::Hunk::SolveOrderConflict { change, local }
    }
    Hunk::UnsolveOrderConflict { change, local } => {
    super::Hunk::UnsolveOrderConflict { change, local }
    }
    Hunk::ResurrectZombies { change, local } => super::Hunk::ResurrectZombies {
    change,
    local,
    encoding: None,
    },
    }
    }
    }
    impl Change {
    /// Deserialise a change from the file given as input `file`.
    #[cfg(feature = "zstd")]
    pub(super) fn deserialize_noenc(
    offsets: Offsets,
    mut r: std::fs::File,
    hash: Option<&Hash>,
    ) -> Result<Self, ChangeError> {
    use std::io::Read;
    debug!("offsets = {:?}", offsets);
    let mut buf = vec![0u8; (offsets.unhashed_off - Self::OFFSETS_SIZE) as usize];
    r.read_exact(&mut buf)?;
    let hashed: Hashed<Hunk<Option<Hash>, Local>> = {
    let mut s = zstd_seekable::Seekable::init_buf(&buf[..])?;
    let mut out = vec![0u8; offsets.hashed_len as usize];
    s.decompress(&mut out[..], 0)?;
    let mut hasher = Hasher::default();
    hasher.update(&out);
    let computed_hash = hasher.finish();
    if let Some(hash) = hash {
    if &computed_hash != hash {
    return Err(super::ChangeError::ChangeHashMismatch {
    claimed: *hash,
    computed: computed_hash,
    });
    }
    }
    bincode::deserialize_from(&out[..])?
    };
    buf.clear();
    buf.resize((offsets.contents_off - offsets.unhashed_off) as usize, 0);
    let unhashed = if buf.is_empty() {
    None
    } else {
    r.read_exact(&mut buf)?;
    let mut s = zstd_seekable::Seekable::init_buf(&buf[..])?;
    let mut out = vec![0u8; offsets.unhashed_len as usize];
    s.decompress(&mut out[..], 0)?;
    serde_json::from_slice(&out).ok()
    };
    debug!("unhashed = {:?}", unhashed);
    buf.clear();
    buf.resize((offsets.total - offsets.contents_off) as usize, 0);
    let contents = if r.read_exact(&mut buf).is_ok() {
    let mut s = zstd_seekable::Seekable::init_buf(&buf[..])?;
    let mut contents = vec![0u8; offsets.contents_len as usize];
    s.decompress(&mut contents[..], 0)?;
    contents
    } else {
    Vec::new()
    };
    debug!("contents = {:?}", contents);
    Ok(LocalChange {
    offsets,
    hashed: hashed.into(),
    unhashed,
    contents,
    })
    }
    }
    impl From<Hashed<Hunk<Option<Hash>, Local>>> for Hashed<super::Hunk<Option<Hash>, Local>> {
    fn from(hashed: Hashed<Hunk<Option<Hash>, Local>>) -> Self {
    Hashed {
    contents_hash: hashed.contents_hash,
    dependencies: hashed.dependencies,
    extra_known: hashed.extra_known,
    header: hashed.header,
    metadata: hashed.metadata,
    version: hashed.version,
    changes: hashed.changes.into_iter().map(|x| x.into()).collect(),
    }
    }
    }
  • replacement in libpijul/src/change/change_file.rs at line 7
    [4.90296][4.90296:90323]()
    hashed: Hashed<Local>,
    [4.90296]
    [4.90323]
    hashed: Hashed<Hunk<Option<Hash>, Local>>,
  • replacement in libpijul/src/change/change_file.rs at line 46
    [4.91337][4.91337:91431]()
    if offsets.version != VERSION {
    return Err(ChangeError::VersionMismatch);
    [4.91337]
    [4.91431]
    if offsets.version != VERSION && offsets.version != VERSION_NOENC {
    return Err(ChangeError::VersionMismatch {
    got: offsets.version,
    });
  • replacement in libpijul/src/change/change_file.rs at line 56
    [4.91638][4.91638:91676]()
    let hashed: Hashed<Local> = {
    [4.91638]
    [4.91676]
    let hashed: Hashed<Hunk<Option<Hash>, Local>> = if offsets.version == VERSION {
  • edit in libpijul/src/change/change_file.rs at line 59
    [4.91783]
    [4.91783]
    debug!("deserialize current version {:?}", buf2.len());
  • edit in libpijul/src/change/change_file.rs at line 61
    [4.91824]
    [4.91824]
    } else {
    assert_eq!(offsets.version, VERSION_NOENC);
    let mut s = zstd_seekable::Seekable::init_buf(&buf)?;
    s.decompress(&mut buf2, 0)?;
    debug!("deserialize noenc {:?}", buf2.len());
    let h: Hashed<noenc::Hunk<Option<Hash>, Local>> = bincode::deserialize(&buf2)?;
    h.into()
  • replacement in libpijul/src/change/change_file.rs at line 78
    [4.92195][4.92195:92242]()
    Some(toml::de::from_slice(&buf2)?)
    [4.92195]
    [4.92242]
    debug!("parsing unhashed: {:?}", std::str::from_utf8(&buf2));
    serde_json::from_slice(&buf2).ok()
  • replacement in libpijul/src/change/change_file.rs at line 115
    [4.93237][4.93237:93282]()
    pub fn hashed(&self) -> &Hashed<Local> {
    [4.93237]
    [4.93282]
    pub fn hashed(&self) -> &Hashed<Hunk<Option<Hash>, Local>> {