gix_merge/blob/platform/set_resource.rs
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103
use bstr::{BStr, BString};
use crate::blob::platform::Resource;
use crate::blob::{pipeline, Platform, ResourceKind};
/// The error returned by [Platform::set_resource](Platform::set_resource).
#[derive(Debug, thiserror::Error)]
#[allow(missing_docs)]
pub enum Error {
#[error("Can only diff blobs, not {mode:?}")]
InvalidMode { mode: gix_object::tree::EntryKind },
#[error("Failed to read {kind:?} worktree data from '{rela_path}'")]
Io {
rela_path: BString,
kind: ResourceKind,
source: std::io::Error,
},
#[error("Failed to obtain attributes for {kind:?} resource at '{rela_path}'")]
Attributes {
rela_path: BString,
kind: ResourceKind,
source: std::io::Error,
},
#[error(transparent)]
ConvertToMergeable(#[from] pipeline::convert_to_mergeable::Error),
}
/// Preparation
impl Platform {
/// Store enough information about a resource to eventually use it in a merge, where…
///
/// * `id` is the hash of the resource. If it [is null](gix_hash::ObjectId::is_null()), it should either
/// be a resource in the worktree, or it's considered a non-existing, deleted object.
/// If an `id` is known, as the hash of the object as (would) be stored in `git`, then it should be provided
/// for completeness. Note that it's not expected to be in `objects` if `rela_path` is set and a worktree-root
/// is available for `kind`.
/// * `mode` is the kind of object (only blobs and executables are allowed)
/// * `rela_path` is the relative path as seen from the (work)tree root.
/// * `kind` identifies the side of the merge this resource will be used for.
/// * `objects` provides access to the object database in case the resource can't be read from a worktree.
pub fn set_resource(
&mut self,
id: gix_hash::ObjectId,
mode: gix_object::tree::EntryKind,
rela_path: &BStr,
kind: ResourceKind,
objects: &impl gix_object::FindObjectOrHeader,
) -> Result<(), Error> {
if !matches!(
mode,
gix_object::tree::EntryKind::Blob | gix_object::tree::EntryKind::BlobExecutable
) {
return Err(Error::InvalidMode { mode });
}
let entry = self
.attr_stack
.at_entry(rela_path, None, objects)
.map_err(|err| Error::Attributes {
source: err,
kind,
rela_path: rela_path.to_owned(),
})?;
let storage = match kind {
ResourceKind::OtherOrTheirs => &mut self.other,
ResourceKind::CommonAncestorOrBase => &mut self.ancestor,
ResourceKind::CurrentOrOurs => &mut self.current,
};
let mut buf_storage = Vec::new();
let out = self.filter.convert_to_mergeable(
&id,
mode,
rela_path,
kind,
&mut |_, out| {
let _ = entry.matching_attributes(out);
},
objects,
self.filter_mode,
storage.as_mut().map_or(&mut buf_storage, |s| &mut s.buffer),
)?;
match storage {
None => {
*storage = Some(Resource {
id,
rela_path: rela_path.to_owned(),
data: out,
mode,
buffer: buf_storage,
});
}
Some(storage) => {
storage.id = id;
storage.rela_path = rela_path.to_owned();
storage.data = out;
storage.mode = mode;
}
};
Ok(())
}
}