gix_merge/blob/platform/
prepare_merge.rs1use crate::blob::builtin_driver::text::Conflict;
2use crate::blob::platform::{merge, DriverChoice, ResourceRef};
3use crate::blob::{BuiltinDriver, Platform, PlatformRef, ResourceKind};
4use bstr::{BStr, BString, ByteSlice};
5use gix_filter::attributes;
6use std::num::NonZeroU8;
7use std::str::FromStr;
8
9#[derive(Debug, thiserror::Error)]
11#[allow(missing_docs)]
12pub enum Error {
13 #[error("The 'current', 'ancestor' or 'other' resource for the merge operation were not set")]
14 UnsetResource,
15 #[error("Failed to obtain attributes for {kind:?} resource at '{rela_path}'")]
16 Attributes {
17 rela_path: BString,
18 kind: ResourceKind,
19 source: std::io::Error,
20 },
21}
22
23impl Platform {
25 pub fn prepare_merge(
34 &mut self,
35 objects: &impl gix_object::Find,
36 mut options: merge::Options,
37 ) -> Result<PlatformRef<'_>, Error> {
38 let current = self.current.as_ref().ok_or(Error::UnsetResource)?;
39 let ancestor = self.ancestor.as_ref().ok_or(Error::UnsetResource)?;
40 let other = self.other.as_ref().ok_or(Error::UnsetResource)?;
41
42 let entry = self
43 .attr_stack
44 .at_entry(current.rela_path.as_bstr(), None, objects)
45 .map_err(|err| Error::Attributes {
46 source: err,
47 kind: ResourceKind::CurrentOrOurs,
48 rela_path: current.rela_path.clone(),
49 })?;
50 entry.matching_attributes(&mut self.attrs);
51 let mut attrs = self.attrs.iter_selected();
52 let merge_attr = attrs.next().expect("pre-initialized with 'merge'");
53 let marker_size_attr = attrs.next().expect("pre-initialized with 'conflict-marker-size'");
54 let mut driver = match merge_attr.assignment.state {
55 attributes::StateRef::Set => DriverChoice::BuiltIn(BuiltinDriver::Text),
56 attributes::StateRef::Unset => DriverChoice::BuiltIn(BuiltinDriver::Binary),
57 attributes::StateRef::Value(_) | attributes::StateRef::Unspecified => {
58 let name = match merge_attr.assignment.state {
59 attributes::StateRef::Value(name) => Some(name.as_bstr()),
60 attributes::StateRef::Unspecified => {
61 self.options.default_driver.as_ref().map(|name| name.as_bstr())
62 }
63 _ => unreachable!("only value and unspecified are possible here"),
64 };
65 self.find_driver_by_name(name)
66 }
67 };
68 if let attributes::StateRef::Value(value) = marker_size_attr.assignment.state {
69 if let Some(value) = u8::from_str(value.as_bstr().to_str_lossy().as_ref())
70 .ok()
71 .and_then(NonZeroU8::new)
72 {
73 match &mut options.text.conflict {
74 Conflict::Keep { marker_size, .. } => *marker_size = value,
75 Conflict::ResolveWithOurs | Conflict::ResolveWithTheirs | Conflict::ResolveWithUnion => {}
76 }
77 }
78 }
79 if let Some(recursive_driver_name) = match driver {
80 DriverChoice::Index(idx) => self.drivers.get(idx),
81 _ => None,
82 }
83 .and_then(|driver| driver.recursive.as_deref())
84 .filter(|_| options.is_virtual_ancestor)
85 {
86 driver = self.find_driver_by_name(Some(recursive_driver_name.as_bstr()));
87 options.resolve_binary_with = Some(crate::blob::builtin_driver::binary::ResolveWith::Ours);
88 }
89
90 let out = PlatformRef {
91 parent: self,
92 driver,
93 current: ResourceRef::new(current),
94 ancestor: ResourceRef::new(ancestor),
95 other: ResourceRef::new(other),
96 options,
97 };
98 Ok(out)
99 }
100
101 fn find_driver_by_name(&self, name: Option<&BStr>) -> DriverChoice {
102 name.and_then(|name| {
103 self.drivers
104 .binary_search_by(|d| d.name.as_bstr().cmp(name))
105 .ok()
106 .map(DriverChoice::Index)
107 .or_else(|| {
108 name.to_str()
109 .ok()
110 .and_then(BuiltinDriver::by_name)
111 .map(DriverChoice::BuiltIn)
112 })
113 })
114 .unwrap_or_default()
115 }
116}