1
- use bstr:: { BStr , BString } ;
2
-
3
- use crate :: blob:: pipeline:: DriverChoice ;
4
- use crate :: blob:: { pipeline, Pipeline , Platform , ResourceKind } ;
1
+ use crate :: blob:: { pipeline, BuiltinDriver , Pipeline , Platform , ResourceKind } ;
2
+ use bstr:: { BStr , BString , ByteSlice } ;
3
+ use gix_filter:: attributes;
5
4
6
5
/// A stored value representing a resource that participates in a merge.
7
6
#[ derive( Clone , Eq , PartialEq , Ord , PartialOrd , Debug ) ]
@@ -10,8 +9,8 @@ pub(super) struct Resource {
10
9
id : gix_hash:: ObjectId ,
11
10
/// The repository-relative path where the resource lives in the tree.
12
11
rela_path : BString ,
13
- /// The outcome of converting a resource into a diffable format using [Pipeline::convert_to_mergeable()].
14
- conversion : pipeline:: Outcome ,
12
+ /// The outcome of converting a resource into a mergable format using [Pipeline::convert_to_mergeable()].
13
+ data : Option < pipeline:: Data > ,
15
14
/// The kind of the resource we are looking at. Only possible values are `Blob` and `BlobExecutable`.
16
15
mode : gix_object:: tree:: EntryKind ,
17
16
/// A possibly empty buffer, depending on `conversion.data` which may indicate the data is considered binary
@@ -26,14 +25,51 @@ pub struct ResourceRef<'a> {
26
25
pub data : resource:: Data < ' a > ,
27
26
/// The location of the resource, relative to the working tree.
28
27
pub rela_path : & ' a BStr ,
29
- /// Which driver to use according to the resource's configuration.
30
- pub driver_choice : DriverChoice ,
31
28
/// The id of the content as it would be stored in `git`, or `null` if the content doesn't exist anymore at
32
29
/// `rela_path` or if it was never computed. This can happen with content read from the worktree, which
33
30
/// after its 'to-git' conversion never had its hash computed.
34
31
pub id : & ' a gix_hash:: oid ,
35
32
}
36
33
34
+ /// Options for use in a [`Platform`].
35
+ #[ derive( Default , Clone , PartialEq , Eq , Debug , Hash , Ord , PartialOrd ) ]
36
+ pub struct Options {
37
+ /// Define which driver to use by name if the `merge` attribute for a resource is unspecified.
38
+ ///
39
+ /// This is the value of the `merge.default` git configuration.
40
+ pub default_driver : Option < BString > ,
41
+ }
42
+
43
+ /// The selection of the driver to use by a resource obtained with [`Pipeline::convert_to_mergeable()`].
44
+ ///
45
+ /// If available, an index into the `drivers` field to access more diff-related information of the driver for items
46
+ /// at the given path, as previously determined by git-attributes.
47
+ ///
48
+ /// * `merge` is set
49
+ /// - Use the [`BuiltinDriver::Text`]
50
+ /// * `-merge` is unset
51
+ /// - Use the [`BuiltinDriver::Binary`]
52
+ /// * `!merge` is unspecified
53
+ /// - Use [`Options::default_driver`] or [`BuiltinDriver::Text`].
54
+ /// * `merge=name`
55
+ /// - Search for a user-configured or built-in driver called `name`.
56
+ /// - If not found, silently default to [`BuiltinDriver::Text`]
57
+ ///
58
+ /// Note that drivers are queried even if there is no object available.
59
+ #[ derive( Copy , Clone , Eq , PartialEq , Ord , PartialOrd , Debug , Hash ) ]
60
+ pub enum DriverChoice {
61
+ /// Use the given built-in driver to perform the merge.
62
+ BuiltIn ( BuiltinDriver ) ,
63
+ /// Use the user-provided driver program using the index into [the pipelines driver array](Pipeline::drivers().
64
+ Index ( usize ) ,
65
+ }
66
+
67
+ impl Default for DriverChoice {
68
+ fn default ( ) -> Self {
69
+ DriverChoice :: BuiltIn ( Default :: default ( ) )
70
+ }
71
+ }
72
+
37
73
///
38
74
pub mod resource {
39
75
use crate :: blob:: {
@@ -44,11 +80,10 @@ pub mod resource {
44
80
impl < ' a > ResourceRef < ' a > {
45
81
pub ( super ) fn new ( cache : & ' a Resource ) -> Self {
46
82
ResourceRef {
47
- data : cache. conversion . data . map_or ( Data :: Missing , |data| match data {
83
+ data : cache. data . map_or ( Data :: Missing , |data| match data {
48
84
pipeline:: Data :: Buffer => Data :: Buffer ( & cache. buffer ) ,
49
- pipeline:: Data :: Binary { size } => Data :: Binary { size } ,
85
+ pipeline:: Data :: TooLarge { size } => Data :: Binary { size } ,
50
86
} ) ,
51
- driver_choice : cache. conversion . driver ,
52
87
rela_path : cache. rela_path . as_ref ( ) ,
53
88
id : & cache. id ,
54
89
}
@@ -118,7 +153,7 @@ pub mod set_resource {
118
153
119
154
///
120
155
pub mod merge {
121
- use crate :: blob:: pipeline :: DriverChoice ;
156
+ use crate :: blob:: platform :: DriverChoice ;
122
157
use crate :: blob:: platform:: ResourceRef ;
123
158
use crate :: blob:: { builtin_driver, BuiltinDriver , Driver , Resolution } ;
124
159
use bstr:: BString ;
@@ -135,6 +170,8 @@ pub mod merge {
135
170
pub ancestor : ResourceRef < ' parent > ,
136
171
/// The other or their side of the merge operation.
137
172
pub other : ResourceRef < ' parent > ,
173
+ /// Which driver to use according to the resource's configuration.
174
+ pub driver_choice : DriverChoice ,
138
175
}
139
176
140
177
#[ derive( Copy , Clone , Debug , Eq , PartialEq ) ]
@@ -267,9 +304,9 @@ pub mod merge {
267
304
/// Return the configured driver program for use with [`Self::prepare_external_driver()`], or `Err`
268
305
/// with the built-in driver to use instead.
269
306
pub fn configured_driver ( & self ) -> Result < & ' parent Driver , BuiltinDriver > {
270
- match self . current . driver_choice {
307
+ match self . driver_choice {
271
308
DriverChoice :: BuiltIn ( builtin) => Err ( builtin) ,
272
- DriverChoice :: Index ( idx) => self . parent . filter . drivers . get ( idx) . ok_or ( BuiltinDriver :: default ( ) ) ,
309
+ DriverChoice :: Index ( idx) => self . parent . drivers . get ( idx) . ok_or ( BuiltinDriver :: default ( ) ) ,
273
310
}
274
311
}
275
312
}
@@ -299,14 +336,21 @@ pub mod merge {
299
336
300
337
///
301
338
pub mod prepare_merge {
339
+ use crate :: blob:: ResourceKind ;
340
+ use bstr:: BString ;
341
+
302
342
/// The error returned by [Platform::prepare_merge()](super::Platform::prepare_merge_state()).
303
343
#[ derive( Debug , thiserror:: Error ) ]
304
344
#[ allow( missing_docs) ]
305
345
pub enum Error {
306
346
#[ error( "The 'current', 'ancestor' or 'other' resource for the merge operation were not set" ) ]
307
347
UnsetResource ,
308
- #[ error( "Tried to merge 'current' and 'other' where at least one of them is removed" ) ]
309
- CurrentOrOtherRemoved ,
348
+ #[ error( "Failed to obtain attributes for {kind:?} resource at '{rela_path}'" ) ]
349
+ Attributes {
350
+ rela_path : BString ,
351
+ kind : ResourceKind ,
352
+ source : std:: io:: Error ,
353
+ } ,
310
354
}
311
355
}
312
356
@@ -315,18 +359,44 @@ impl Platform {
315
359
/// Create a new instance with a way to `filter` data from the object database and turn it into something that is merge-able.
316
360
/// `filter_mode` decides how to do that specifically.
317
361
/// Use `attr_stack` to access attributes pertaining worktree filters and merge settings.
318
- pub fn new ( filter : Pipeline , filter_mode : pipeline:: Mode , attr_stack : gix_worktree:: Stack ) -> Self {
362
+ /// `drivers` are the list of available merge drivers that individual paths can refer to by means of git attributes.
363
+ /// `options` further configure the operation.
364
+ pub fn new (
365
+ filter : Pipeline ,
366
+ filter_mode : pipeline:: Mode ,
367
+ attr_stack : gix_worktree:: Stack ,
368
+ mut drivers : Vec < super :: Driver > ,
369
+ options : Options ,
370
+ ) -> Self {
371
+ drivers. sort_by ( |a, b| a. name . cmp ( & b. name ) ) ;
319
372
Platform {
373
+ drivers,
320
374
current : None ,
321
375
ancestor : None ,
322
376
other : None ,
323
377
filter,
324
378
filter_mode,
325
379
attr_stack,
380
+ attrs : {
381
+ let mut out = attributes:: search:: Outcome :: default ( ) ;
382
+ out. initialize_with_selection ( & Default :: default ( ) , Some ( "merge" ) ) ;
383
+ out
384
+ } ,
385
+ options,
326
386
}
327
387
}
328
388
}
329
389
390
+ /// Access
391
+ impl Platform {
392
+ /// Return all drivers that this instance was initialized with.
393
+ ///
394
+ /// They are sorted by [`name`](super::Driver::name) to support binary searches.
395
+ pub fn drivers ( & self ) -> & [ super :: Driver ] {
396
+ & self . drivers
397
+ }
398
+ }
399
+
330
400
/// Preparation
331
401
impl Platform {
332
402
/// Store enough information about a resource to eventually use it in a merge, where…
@@ -351,33 +421,62 @@ impl Platform {
351
421
self . set_resource_inner ( id, mode, rela_path, kind, objects)
352
422
}
353
423
354
- /// Returns the resource of the given kind if it was set.
355
- pub fn resource ( & self , kind : ResourceKind ) -> Option < ResourceRef < ' _ > > {
356
- let cache = match kind {
357
- ResourceKind :: CurrentOrOurs => self . current . as_ref ( ) ,
358
- ResourceKind :: CommonAncestorOrBase => self . ancestor . as_ref ( ) ,
359
- ResourceKind :: OtherOrTheirs => self . other . as_ref ( ) ,
360
- } ?;
361
- ResourceRef :: new ( cache) . into ( )
362
- }
363
-
364
424
/// Prepare all state needed for performing a merge, using all [previously set](Self::set_resource()) resources.
365
- pub fn prepare_merge_state ( & self ) -> Result < merge:: State < ' _ > , prepare_merge:: Error > {
425
+ /// Note that no additional validation is performed here to facilitate inspection.
426
+ pub fn prepare_merge_state (
427
+ & mut self ,
428
+ objects : & impl gix_object:: Find ,
429
+ ) -> Result < merge:: State < ' _ > , prepare_merge:: Error > {
366
430
let current = self . current . as_ref ( ) . ok_or ( prepare_merge:: Error :: UnsetResource ) ?;
367
431
let ancestor = self . ancestor . as_ref ( ) . ok_or ( prepare_merge:: Error :: UnsetResource ) ?;
368
432
let other = self . other . as_ref ( ) . ok_or ( prepare_merge:: Error :: UnsetResource ) ?;
369
433
434
+ let entry = self
435
+ . attr_stack
436
+ . at_entry ( current. rela_path . as_bstr ( ) , None , objects)
437
+ . map_err ( |err| prepare_merge:: Error :: Attributes {
438
+ source : err,
439
+ kind : ResourceKind :: CurrentOrOurs ,
440
+ rela_path : current. rela_path . clone ( ) ,
441
+ } ) ?;
442
+ entry. matching_attributes ( & mut self . attrs ) ;
443
+ let attr = self . attrs . iter_selected ( ) . next ( ) . expect ( "pre-initialized with 'diff'" ) ;
444
+ let driver = match attr. assignment . state {
445
+ attributes:: StateRef :: Set => DriverChoice :: BuiltIn ( BuiltinDriver :: Text ) ,
446
+ attributes:: StateRef :: Unset => DriverChoice :: BuiltIn ( BuiltinDriver :: Binary ) ,
447
+ attributes:: StateRef :: Value ( _) | attributes:: StateRef :: Unspecified => {
448
+ let name = match attr. assignment . state {
449
+ attributes:: StateRef :: Value ( name) => Some ( name. as_bstr ( ) ) ,
450
+ attributes:: StateRef :: Unspecified => {
451
+ self . options . default_driver . as_ref ( ) . map ( |name| name. as_bstr ( ) )
452
+ }
453
+ _ => unreachable ! ( "only value and unspecified are possible here" ) ,
454
+ } ;
455
+ name. and_then ( |name| {
456
+ self . drivers
457
+ . binary_search_by ( |d| d. name . as_bstr ( ) . cmp ( name) )
458
+ . ok ( )
459
+ . map ( DriverChoice :: Index )
460
+ . or_else ( || {
461
+ name. to_str ( )
462
+ . ok ( )
463
+ . and_then ( BuiltinDriver :: by_name)
464
+ . map ( DriverChoice :: BuiltIn )
465
+ } )
466
+ } )
467
+ . unwrap_or_default ( )
468
+ }
469
+ } ;
470
+
370
471
let out = merge:: State {
371
472
parent : self ,
473
+ driver_choice : driver,
372
474
current : ResourceRef :: new ( current) ,
373
475
ancestor : ResourceRef :: new ( ancestor) ,
374
476
other : ResourceRef :: new ( other) ,
375
477
} ;
376
478
377
- match ( current. conversion . data , other. conversion . data ) {
378
- ( None , None ) => Err ( prepare_merge:: Error :: CurrentOrOtherRemoved ) ,
379
- ( _, _) => Ok ( out) ,
380
- }
479
+ Ok ( out)
381
480
}
382
481
}
383
482
@@ -430,15 +529,15 @@ impl Platform {
430
529
* storage = Some ( Resource {
431
530
id,
432
531
rela_path : rela_path. to_owned ( ) ,
433
- conversion : out,
532
+ data : out,
434
533
mode,
435
534
buffer : buf_storage,
436
535
} ) ;
437
536
}
438
537
Some ( storage) => {
439
538
storage. id = id;
440
539
storage. rela_path = rela_path. to_owned ( ) ;
441
- storage. conversion = out;
540
+ storage. data = out;
442
541
storage. mode = mode;
443
542
}
444
543
} ;
0 commit comments