@@ -5,20 +5,32 @@ pub struct Options {
5
5
pub explain : bool ,
6
6
pub cat_file : bool ,
7
7
pub tree_mode : TreeMode ,
8
+ pub blob_format : BlobFormat ,
8
9
}
9
10
10
11
pub enum TreeMode {
11
12
Raw ,
12
13
Pretty ,
13
14
}
14
15
16
+ #[ derive( Copy , Clone ) ]
17
+ pub enum BlobFormat {
18
+ Git ,
19
+ Worktree ,
20
+ Diff ,
21
+ DiffOrGit ,
22
+ }
23
+
15
24
pub ( crate ) mod function {
16
25
use std:: ffi:: OsString ;
17
26
18
- use anyhow:: Context ;
27
+ use anyhow:: { anyhow, Context } ;
28
+ use gix:: diff:: blob:: ResourceKind ;
29
+ use gix:: filter:: plumbing:: driver:: apply:: Delay ;
19
30
use gix:: revision:: Spec ;
20
31
21
32
use super :: Options ;
33
+ use crate :: repository:: revision:: resolve:: BlobFormat ;
22
34
use crate :: {
23
35
repository:: { revision, revision:: resolve:: TreeMode } ,
24
36
OutputFormat ,
@@ -33,9 +45,26 @@ pub(crate) mod function {
33
45
explain,
34
46
cat_file,
35
47
tree_mode,
48
+ blob_format,
36
49
} : Options ,
37
50
) -> anyhow:: Result < ( ) > {
38
51
repo. object_cache_size_if_unset ( 1024 * 1024 ) ;
52
+ let mut cache = ( !matches ! ( blob_format, BlobFormat :: Git ) )
53
+ . then ( || {
54
+ repo. diff_resource_cache (
55
+ match blob_format {
56
+ BlobFormat :: Git => {
57
+ unreachable ! ( "checked before" )
58
+ }
59
+ BlobFormat :: Worktree | BlobFormat :: Diff => {
60
+ gix:: diff:: blob:: pipeline:: Mode :: ToWorktreeAndBinaryToText
61
+ }
62
+ BlobFormat :: DiffOrGit => gix:: diff:: blob:: pipeline:: Mode :: ToGitUnlessBinaryToTextIsPresent ,
63
+ } ,
64
+ Default :: default ( ) ,
65
+ )
66
+ } )
67
+ . transpose ( ) ?;
39
68
40
69
match format {
41
70
OutputFormat :: Human => {
@@ -46,7 +75,7 @@ pub(crate) mod function {
46
75
let spec = gix:: path:: os_str_into_bstr ( & spec) ?;
47
76
let spec = repo. rev_parse ( spec) ?;
48
77
if cat_file {
49
- return display_object ( spec, tree_mode, out) ;
78
+ return display_object ( & repo , spec, tree_mode, cache . as_mut ( ) . map ( |c| ( blob_format , c ) ) , out) ;
50
79
}
51
80
writeln ! ( out, "{spec}" , spec = spec. detach( ) ) ?;
52
81
}
@@ -73,16 +102,51 @@ pub(crate) mod function {
73
102
Ok ( ( ) )
74
103
}
75
104
76
- fn display_object ( spec : Spec < ' _ > , tree_mode : TreeMode , mut out : impl std:: io:: Write ) -> anyhow:: Result < ( ) > {
105
+ fn display_object (
106
+ repo : & gix:: Repository ,
107
+ spec : Spec < ' _ > ,
108
+ tree_mode : TreeMode ,
109
+ cache : Option < ( BlobFormat , & mut gix:: diff:: blob:: Platform ) > ,
110
+ mut out : impl std:: io:: Write ,
111
+ ) -> anyhow:: Result < ( ) > {
77
112
let id = spec. single ( ) . context ( "rev-spec must resolve to a single object" ) ?;
78
- let object = id. object ( ) ?;
79
- match object . kind {
113
+ let header = id. header ( ) ?;
114
+ match header . kind ( ) {
80
115
gix:: object:: Kind :: Tree if matches ! ( tree_mode, TreeMode :: Pretty ) => {
81
- for entry in object. into_tree ( ) . iter ( ) {
116
+ for entry in id . object ( ) ? . into_tree ( ) . iter ( ) {
82
117
writeln ! ( out, "{}" , entry?) ?;
83
118
}
84
119
}
85
- _ => out. write_all ( & object. data ) ?,
120
+ gix:: object:: Kind :: Blob if cache. is_some ( ) && spec. path_and_mode ( ) . is_some ( ) => {
121
+ let ( path, mode) = spec. path_and_mode ( ) . expect ( "is present" ) ;
122
+ let is_dir = Some ( mode. is_tree ( ) ) ;
123
+ match cache. expect ( "is some" ) {
124
+ ( BlobFormat :: Git , _) => unreachable ! ( "no need for a cache when querying object db" ) ,
125
+ ( BlobFormat :: Worktree , cache) => {
126
+ let platform = cache. attr_stack . at_entry ( path, is_dir, & repo. objects ) ?;
127
+ let object = id. object ( ) ?;
128
+ let mut converted = cache. filter . worktree_filter . convert_to_worktree (
129
+ & object. data ,
130
+ path,
131
+ & mut |_path, attrs| {
132
+ let _ = platform. matching_attributes ( attrs) ;
133
+ } ,
134
+ Delay :: Forbid ,
135
+ ) ?;
136
+ std:: io:: copy ( & mut converted, & mut out) ?;
137
+ }
138
+ ( BlobFormat :: Diff | BlobFormat :: DiffOrGit , cache) => {
139
+ cache. set_resource ( id. detach ( ) , mode. kind ( ) , path, ResourceKind :: OldOrSource , & repo. objects ) ?;
140
+ let resource = cache. resource ( ResourceKind :: OldOrSource ) . expect ( "just set" ) ;
141
+ let data = resource
142
+ . data
143
+ . as_slice ( )
144
+ . ok_or_else ( || anyhow ! ( "Binary data at {} cannot be diffed" , path) ) ?;
145
+ out. write_all ( data) ?;
146
+ }
147
+ }
148
+ }
149
+ _ => out. write_all ( & id. object ( ) ?. data ) ?,
86
150
}
87
151
Ok ( ( ) )
88
152
}
0 commit comments