90 lines · 3.2 KB · Rust
RawDownload
use std::ops::Range; use bstr::{ByteSlice, ByteVec}; use crate::clear_and_set_capacity; /// Undo identifiers like `$Id:<hexsha>$` to `$Id$` in `src` and write to `buf`. Newlines between dollars are ignored./// Return `true` if `buf` was written or `false` if `src` was left unaltered (as there was nothing to do).pub fn undo(src: &[u8], buf: &mut Vec<u8>) -> Result<bool, std::collections::TryReserveError> {    fn find_range(input: &[u8]) -> Option<Range<usize>> {        let mut ofs = 0;        loop {            let mut cursor = input.get(ofs..)?;            let start = cursor.find(b"$Id:")?;            cursor = cursor.get((start + 4)..)?;            let maybe_end = cursor.find_byteset(b"$\n")?;            if cursor[maybe_end] == b'\n' {                ofs += start + 4 + maybe_end + 1;                continue;            } else {                return Some((ofs + start)..(ofs + start + 4 + maybe_end + 1));            }        }    }     let mut ofs = 0;    let mut initialized = false;    while let Some(range) = find_range(&src[ofs..]) {        if !initialized {            clear_and_set_capacity(buf, src.len())?;            initialized = true;        }        buf.push_str(&src[ofs..][..range.start]);        buf.push_str(b"$Id$");        ofs += range.end;    }    if initialized {        buf.push_str(&src[ofs..]);    }    Ok(initialized)} ///pub mod apply {    /// The error produced by [`super::apply()`].    #[derive(Debug, thiserror::Error)]    #[expect(missing_docs)]    pub enum Error {        #[error("Could not allocate buffer")]        OutOfMemory(#[from] std::collections::TryReserveError),        #[error("Could not hash blob")]        Hasher(#[from] gix_hash::hasher::Error),    }} /// Substitute all occurrences of `$Id$` with `$Id: <hexsha-of-input>$` if present in `src` and write all changes to `buf`,/// with `object_hash` being used accordingly. Return `true` if `buf` was written to or `false` if no change was made/// (as there was nothing to do).////// ### Deviation////// `Git` also tries to cleanup 'stray' substituted `$Id: <hex>$`, but we don't do that, sticking exactly to what ought to be done./// The respective code is up to 16 years old and one might assume that `git` by now handles checking and checkout filters correctly.pub fn apply(src: &[u8], object_hash: gix_hash::Kind, buf: &mut Vec<u8>) -> Result<bool, apply::Error> {    const HASH_LEN: usize = ": ".len() + gix_hash::Kind::longest().len_in_hex();    let mut id = None;    let mut ofs = 0;    while let Some(pos) = src[ofs..].find(b"$Id$") {        let id = match id {            None => {                let new_id = gix_object::compute_hash(object_hash, gix_object::Kind::Blob, src)?;                id = new_id.into();                clear_and_set_capacity(buf, src.len() + HASH_LEN)?; // pre-allocate for one ID                new_id            }            Some(id) => id.to_owned(),        };         buf.push_str(&src[ofs..][..pos + 3]);        buf.push_str(b": ");        id.write_hex_to(&mut *buf).expect("writes to memory always work");        buf.push(b'$');         ofs += pos + 4;    }    if id.is_some() {        buf.push_str(&src[ofs..]);    }    Ok(id.is_some())}