fce44ae9 Andy McCall 1 month ago ↶
1
2
94084087 Andy McCall 1 month ago ↶
3
use super :: format:: { author_name, deps_line, deps_of, plural, short_id, short_meta_id, signature_line, signature_mark, subject_of, when} ;
fce44ae9 Andy McCall 1 month ago ↶
4
use super :: open;
135212de Andy McCall 1 month ago ↶
5
use super :: ui;
fce44ae9 Andy McCall 1 month ago ↶
6
use anyhow:: Result;
94084087 Andy McCall 1 month ago ↶
7
use oxy_core:: objects:: ChangeKind;
fce44ae9 Andy McCall 1 month ago ↶
8
use oxy_core:: repo:: { render_change, ChangeStatus, Repo} ;
9
use std:: path:: PathBuf;
10
11
pub fn init ( path : Option< PathBuf> ) -> Result< i32 > {
12
let path = path.unwrap_or ( std:: env:: current_dir( ) ? ) ;
13
let repo = Repo:: init( & path) ? ;
94084087 Andy McCall 1 month ago ↶
14
println! ( " {} oxy repository in {} " , ui:: done( " Initialized" ) , ui:: path( repo.root ( ) .display ( ) ) ) ;
15
println! ( " {} " , ui:: kv( " bookmark" , ui:: bookmark( & repo.config.bookmark) ) ) ;
16
println! ( " {} " , ui:: kv( " author" , format! ( " {} <{} >" , ui:: author( & repo.config.author_name) , repo.config.author_email) ) ) ;
fce44ae9 Andy McCall 1 month ago ↶
17
Ok ( 0 )
18
}
19
20
fn status_tag ( s : ChangeStatus) -> & 'static str {
21
match s {
22
ChangeStatus:: Added => " A" ,
23
ChangeStatus:: Modified => " M" ,
24
ChangeStatus:: Removed => " D" ,
6e723b81 Andy McCall 1 month ago ↶
25
ChangeStatus:: Renamed => " R" ,
fce44ae9 Andy McCall 1 month ago ↶
26
ChangeStatus:: ModeChanged => " X" ,
27
ChangeStatus:: ConflictEdited => " C!" ,
6e723b81 Andy McCall 1 month ago ↶
28
ChangeStatus:: Resolved => " V" ,
fce44ae9 Andy McCall 1 month ago ↶
29
}
30
}
31
50a046e4 Andy McCall 1 month ago ↶
32
pub fn status ( json : bool ) -> Result< i32 > {
fce44ae9 Andy McCall 1 month ago ↶
33
let repo = open ( ) ? ;
135212de Andy McCall 1 month ago ↶
34
let sp = ui:: spinner( " Snapshotting the working copy…" ) ;
fce44ae9 Andy McCall 1 month ago ↶
35
let snap = repo.snapshot ( " oxy status" ) ? ;
36
let heads = repo.bookmark_heads ( ) ? ;
135212de Andy McCall 1 month ago ↶
37
sp.clear ( ) ;
50a046e4 Andy McCall 1 month ago ↶
38
if json {
39
println! ( " {} " , repo.status_json ( & snap) ? ) ;
40
return Ok ( if snap.base_snapshot.is_conflicted ( ) { 2 } else { 0 } ) ;
41
}
135212de Andy McCall 1 month ago ↶
42
println! (
94084087 Andy McCall 1 month ago ↶
43
" {} {} {} working copy {} {} {} " ,
44
ui:: dim( " On" ) ,
45
ui:: bookmark( & repo.config.bookmark) ,
46
ui:: sep( ) ,
135212de Andy McCall 1 month ago ↶
47
ui:: id( snap.wc.change_id.short ( 8 ) ) ,
94084087 Andy McCall 1 month ago ↶
48
ui:: sep( ) ,
49
ui:: dim( plural ( heads.len ( ) , " head" ) )
135212de Andy McCall 1 month ago ↶
50
) ;
fce44ae9 Andy McCall 1 month ago ↶
51
if snap.statuses.is_empty ( ) {
94084087 Andy McCall 1 month ago ↶
52
println! ( " {} {} " , ui:: ok( ui:: glyph( " ✔" , " *" ) ) , ui:: dim( " nothing to commit, working copy clean" ) ) ;
53
} else {
54
println! ( ) ;
55
for s in & snap.statuses {
56
println! ( " {} {} " , ui:: status_mark( status_tag ( s.status) ) , ui:: path( & s.path) ) ;
57
}
fce44ae9 Andy McCall 1 month ago ↶
58
}
59
if ! snap.base_snapshot.is_conflicted ( ) {
60
return Ok ( 0 ) ;
61
}
135212de Andy McCall 1 month ago ↶
62
println! ( ) ;
94084087 Andy McCall 1 month ago ↶
63
println! ( " {} {} " , ui:: section( ui:: err( " Conflicts" ) ) , ui:: dim( " edit the marked files, or the .oxy-conflict-N candidates, then commit" ) ) ;
fce44ae9 Andy McCall 1 month ago ↶
64
for c in & snap.base_snapshot.tree.conflicts {
94084087 Andy McCall 1 month ago ↶
65
println! ( " {} tree: {c:?} " , ui:: err( ui:: glyph( " ✱" , " !" ) ) ) ;
fce44ae9 Andy McCall 1 month ago ↶
66
}
67
for ( p, f) in & snap.base_snapshot.files {
68
if f.is_conflicted ( ) {
69
let state = match snap.statuses.iter ( ) .find ( | s | s.path = = * p ) .map ( | s | s.status ) {
94084087 Andy McCall 1 month ago ↶
70
Some ( ChangeStatus:: Resolved) => ui:: ok( format! ( " {} resolved in working copy" , ui:: glyph( " ✔" , " *" ) ) ) ,
71
Some ( ChangeStatus:: ConflictEdited) => ui:: warn( format! ( " {} markers remain" , ui:: glyph( " ‼" , " !" ) ) ) ,
72
_ => ui:: err( format! ( " {} unresolved" , ui:: glyph( " ✱" , " !" ) ) ) ,
fce44ae9 Andy McCall 1 month ago ↶
73
} ;
135212de Andy McCall 1 month ago ↶
74
println! ( " {} {state} " , ui:: path( p) ) ;
fce44ae9 Andy McCall 1 month ago ↶
75
}
76
}
77
Ok ( 2 )
78
}
79
80
pub fn commit ( message : & str , depends_on : & [String]) -> Result< i32 > {
81
let repo = open ( ) ? ;
82
let mut deps = Vec :: new( ) ;
83
for d in depends_on {
84
deps.push ( repo.resolve_change ( d) ? ) ;
85
}
135212de Andy McCall 1 month ago ↶
86
let sp = ui:: spinner( " Committing…" ) ;
fce44ae9 Andy McCall 1 month ago ↶
87
let h = repo.commit ( message, & deps) ? ;
88
let c = repo.store ( ) .get_change ( & h) ? ;
94084087 Andy McCall 1 month ago ↶
89
sp.done ( & format! ( " {} {} {} {} " , ui:: done( " Committed" ) , ui:: id( short_id ( & c) ) , ui:: hash( format! ( " #{} " , h.short ( 12 ) ) ) , ui:: subject( subject_of ( message) ) ) ) ;
fce44ae9 Andy McCall 1 month ago ↶
90
Ok ( 0 )
91
}
92
94084087 Andy McCall 1 month ago ↶
93
94
95
96
pub fn log ( limit : Option< usize > , verbose : bool ) -> Result< i32 > {
fce44ae9 Andy McCall 1 month ago ↶
97
let repo = open ( ) ? ;
94084087 Andy McCall 1 month ago ↶
98
let snap = repo.snapshot ( " oxy log" ) ? ;
99
let conflicted = snap.base_snapshot.is_conflicted ( ) ;
100
let entries = repo.log ( ) ? ;
101
let total = entries.len ( ) ;
102
let shown = limit.unwrap_or ( total) .min ( total) ;
103
let rail = ui:: rail( ) ;
104
for ( i, e) in entries.iter ( ) .take ( shown) .enumerate ( ) {
fce44ae9 Andy McCall 1 month ago ↶
105
let c = & e.change;
94084087 Andy McCall 1 month ago ↶
106
let bullet = ui:: log_bullet( e.is_working_copy, e.is_head, e.is_working_copy & & conflicted) ;
107
let mut labels = Vec :: new( ) ;
fce44ae9 Andy McCall 1 month ago ↶
108
if e.is_working_copy {
94084087 Andy McCall 1 month ago ↶
109
labels.push ( ui:: warn( " working copy" ) ) ;
fce44ae9 Andy McCall 1 month ago ↶
110
}
94084087 Andy McCall 1 month ago ↶
111
if c.kind = = ChangeKind:: Resolution {
112
labels.push ( ui:: warn( " resolution" ) ) ;
fce44ae9 Andy McCall 1 month ago ↶
113
}
94084087 Andy McCall 1 month ago ↶
114
let labels = if labels.is_empty ( ) { String :: new( ) } else { format! ( " {} {} {} " , ui:: dim( " (" ) , labels.join ( ui:: dim( " , " ) .as_str ( ) ) , ui:: dim( " )" ) ) } ;
115
let subject = if e.is_working_copy & & c.message.is_empty ( ) {
116
ui:: dim( if snap.statuses.is_empty ( ) { " (clean)" } else { " (uncommitted changes)" } )
117
} else {
118
ui:: subject( subject_of ( & c.message) )
119
} ;
120
println! ( " {bullet} {} {labels} {subject} " , ui:: id( short_meta_id ( c) ) ) ;
121
let meta = format! (
122
" {} {} {} {} {} {} {} " ,
123
ui:: hash( format! ( " #{} " , e.hash.short ( 12 ) ) ) ,
124
ui:: sep( ) ,
125
ui:: author( author_name ( & repo, c) ) ,
126
ui:: sep( ) ,
127
ui:: dim( ui:: ago( c.hlc.wall_ms) ) ,
128
ui:: sep( ) ,
129
if e.is_working_copy { ui:: dim( " not yet committed" ) } else { signature_mark ( & repo, & e.hash) ? }
130
) ;
131
println! ( " {rail} {meta} " ) ;
132
if verbose {
133
if ! e.is_working_copy {
134
println! ( " {rail} {} " , ui:: dim( format! ( " {} {} " , when ( c.hlc.wall_ms) , signature_line ( & repo, & e.hash) ? ) ) ) ;
135
}
136
if ! c.deps.is_empty ( ) {
137
println! ( " {rail} {} {} " , ui:: dim( ui:: glyph( " ↳" , " ->" ) ) , ui:: dim( deps_of ( & c.deps) ) ) ;
138
}
139
let body: Vec< & str > = c.message.lines ( ) .skip ( 1 ) .skip_while ( | l | l.trim ( ) .is_empty ( ) ) .collect ( ) ;
140
if ! body.is_empty ( ) {
141
println! ( " {rail} " ) ;
142
for line in body {
143
println! ( " {rail} {line} " ) ;
144
}
145
}
fce44ae9 Andy McCall 1 month ago ↶
146
}
94084087 Andy McCall 1 month ago ↶
147
if i + 1 < shown {
148
println! ( " {rail} " ) ;
fce44ae9 Andy McCall 1 month ago ↶
149
}
150
}
94084087 Andy McCall 1 month ago ↶
151
if shown < total {
152
println! ( " {} " , ui:: dim( format! ( " {} {} more; pass -n to see them" , ui:: glyph( " …" , " ..." ) , total - shown) ) ) ;
153
}
fce44ae9 Andy McCall 1 month ago ↶
154
Ok ( 0 )
155
}
156
157
pub fn diff ( ) -> Result< i32 > {
158
let repo = open ( ) ? ;
159
let snap = repo.snapshot ( " oxy diff" ) ? ;
160
print! ( " {} " , render_change ( & snap.wc, & snap.base, & snap.base_snapshot) ) ;
161
Ok ( 0 )
162
}
163
164
pub fn show ( change : & str ) -> Result< i32 > {
165
let repo = open ( ) ? ;
166
repo.snapshot ( " oxy show" ) ? ;
167
let h = repo.resolve_change ( change) ? ;
168
let c = repo.store ( ) .get_change ( & h) ? ;
94084087 Andy McCall 1 month ago ↶
169
println! ( " {} {} {} " , ui:: section( " change" ) , ui:: id( short_id ( & c) ) , ui:: hash( format! ( " #{h} " ) ) ) ;
170
println! ( " {} " , ui:: kv( " kind" , format! ( " {:?} " , c.kind) .to_lowercase ( ) ) ) ;
171
println! ( " {} " , ui:: kv( " author" , ui:: author( author_name ( & repo, & oxy_core:: state:: ChangeMeta:: of( & c) ) ) ) ) ;
172
println! ( " {} " , ui:: kv( " date" , format! ( " {} {} " , when ( c.hlc.wall_ms) , ui:: dim( format! ( " ({} )" , ui:: ago( c.hlc.wall_ms) ) ) ) ) ) ;
173
println! ( " {} " , ui:: kv( " deps" , ui:: dim( deps_line ( & c) ) ) ) ;
174
println! ( " {} " , ui:: kv( " sig" , signature_line ( & repo, & h) ? ) ) ;
175
println! ( ) ;
176
for line in ( if c.message.is_empty ( ) { " (no description)" } else { & c.message } ) .lines ( ) {
177
println! ( " {line} " ) ;
178
}
179
println! ( ) ;
fce44ae9 Andy McCall 1 month ago ↶
180
print! ( " {} " , repo.describe_change ( & h) ? ) ;
181
Ok ( 0 )
182
}
183
184
pub fn checkout ( changes : & [String], discard : bool ) -> Result< i32 > {
185
let repo = open ( ) ? ;
186
let heads = if changes.is_empty ( ) {
187
repo.bookmark_heads ( ) ?
188
} else {
132b884b Andy McCall 1 month ago ↶
189
let mut heads = Vec :: new( ) ;
190
for c in changes {
191
heads.extend ( repo.resolve_heads ( c) ? ) ;
192
}
193
heads
fce44ae9 Andy McCall 1 month ago ↶
194
} ;
195
let spec = if changes.is_empty ( ) { repo.config.bookmark.clone ( ) } else { changes.join ( " " ) } ;
135212de Andy McCall 1 month ago ↶
196
let sp = ui:: spinner( & format! ( " Checking out {spec} …" ) ) ;
fce44ae9 Andy McCall 1 month ago ↶
197
let r = repo.checkout ( & heads, discard, & format! ( " oxy checkout {spec} " ) ) ? ;
94084087 Andy McCall 1 month ago ↶
198
sp.done ( & format! ( " {} on {} : {} written, {} removed" , ui:: done( " Working copy" ) , ui:: bookmark( & spec) , plural ( r.written, " file" ) , r.removed) ) ;
fce44ae9 Andy McCall 1 month ago ↶
199
if r.conflicted {
94084087 Andy McCall 1 month ago ↶
200
println! ( " {} {} " , ui:: caution( ) , ui:: warn( " this state has conflicts; see oxy status" ) ) ;
fce44ae9 Andy McCall 1 month ago ↶
201
}
202
Ok ( 0 )
203
}
204
205
pub fn resolve ( ) -> Result< i32 > {
206
let repo = open ( ) ? ;
207
let snap = repo.snapshot ( " oxy resolve" ) ? ;
208
if ! snap.base_snapshot.is_conflicted ( ) {
209
println! ( " The working copy's base has no conflicts." ) ;
210
return Ok ( 0 ) ;
211
}
212
let mut remaining = 0 ;
213
for ( p, f) in & snap.base_snapshot.files {
214
if ! f.is_conflicted ( ) {
215
continue ;
216
}
217
match snap.statuses.iter ( ) .find ( | s | s.path = = * p ) .map ( | s | s.status ) {
218
Some ( ChangeStatus:: Resolved) => println! ( " resolved {p} " ) ,
219
Some ( ChangeStatus:: ConflictEdited) => {
220
remaining + = 1 ;
221
println! ( " markers {p} " ) ;
222
}
223
_ => {
224
remaining + = 1 ;
225
println! ( " unresolved {p} " ) ;
226
}
227
}
228
}
229
for c in & snap.base_snapshot.tree.conflicts {
230
remaining + = 1 ;
231
println! ( " tree {c:?} " ) ;
232
}
233
if remaining = = 0 {
234
println! ( " All conflicts are resolved; `oxy commit` will record the resolution." ) ;
235
Ok ( 0 )
236
} else {
237
Ok ( 2 )
238
}
239
}
240
241
pub fn undo ( ) -> Result< i32 > {
242
let repo = open ( ) ? ;
243
let op = repo.undo ( ) ? ;
94084087 Andy McCall 1 month ago ↶
244
println! ( " {} now at: {} " , ui:: done( " Undone;" ) , ui:: dim( & op.command) ) ;
fce44ae9 Andy McCall 1 month ago ↶
245
Ok ( 0 )
246
}
247
248
pub fn op_log ( ) -> Result< i32 > {
249
let repo = open ( ) ? ;
250
for ( i, ( r, op) ) in repo.op_log ( ) ? .into_iter ( ) .enumerate ( ) {
94084087 Andy McCall 1 month ago ↶
251
let bullet = if i = = 0 { ui:: ok( ui:: glyph( " ●" , " @" ) ) } else { ui:: dim( ui:: glyph( " ○" , " o" ) ) } ;
252
let cmd = subject_of ( & op.command) .split ( " \\ n" ) .next ( ) .unwrap_or ( " " ) ;
253
println! ( " {bullet} {} {} {} {} " , ui:: hash( r.short ( 12 ) ) , ui:: sep( ) , ui:: dim( format! ( " {:<16}" , ui:: ago( op.hlc.wall_ms) ) ) , if i = = 0 { ui:: subject( cmd) } else { cmd.to_string ( ) } ) ;
fce44ae9 Andy McCall 1 month ago ↶
254
}
255
Ok ( 0 )
256
}
d02e545d Andy McCall 1 month ago ↶
257
ba160f60 Andy McCall 1 month ago ↶
258
pub fn gc ( now : bool ) -> Result< i32 > {
d02e545d Andy McCall 1 month ago ↶
259
let repo = open ( ) ? ;
135212de Andy McCall 1 month ago ↶
260
let sp = ui:: spinner( " Packing and pruning…" ) ;
ba160f60 Andy McCall 1 month ago ↶
261
let r = repo.gc ( now) ? ;
135212de Andy McCall 1 month ago ↶
262
sp.clear ( ) ;
ba160f60 Andy McCall 1 month ago ↶
263
if r.packed.objects > 0 {
d02e545d Andy McCall 1 month ago ↶
264
println! (
ba160f60 Andy McCall 1 month ago ↶
265
" Packed {} : {} bytes -> {} bytes ({:.0} %)." ,
266
plural ( r.packed.objects, " loose object" ) ,
267
r.packed.raw_bytes,
268
r.packed.packed_bytes,
269
100. 0 * r.packed.packed_bytes as f64 / r.packed.raw_bytes.max ( 1 ) as f64
d02e545d Andy McCall 1 month ago ↶
270
) ;
271
}
135212de Andy McCall 1 month ago ↶
272
println! ( " {} reachable; pruned {} ({} bytes){} {} ; {} present." ,
ba160f60 Andy McCall 1 month ago ↶
273
plural ( r.reachable, " object" ) ,
274
plural ( r.pruned.objects, " unreachable object" ) ,
275
r.pruned.bytes,
276
if r.pruned.deferred > 0 { format! ( " ; {} deferred by the grace period (use --now)" , plural ( r.pruned.deferred, " object" ) ) } else { String :: new( ) } ,
135212de Andy McCall 1 month ago ↶
277
if r.merged_packs > 0 { format! ( " ; merged {} into one" , plural ( r.merged_packs, " pack" ) ) } else { String :: new( ) } ,
ba160f60 Andy McCall 1 month ago ↶
278
plural ( repo.store ( ) .pack_count ( ) , " pack" )
279
) ;
d02e545d Andy McCall 1 month ago ↶
280
Ok ( 0 )
281
}
614541c3 Andy McCall 1 month ago ↶
282
283
284
fn current_head ( repo : & Repo) -> Result< oxy_core:: hash:: ChangeHash> {
285
let snap = repo.snapshot ( " oxy" ) ? ;
286
let base = snap.base.maximal ( & snap.wc.deps) ;
287
match base.as_slice ( ) {
288
[ h] => Ok ( * h) ,
289
_ => anyhow:: bail! ( " the working copy sits on {} heads; name the change explicitly" , base.len ( ) ) ,
290
}
291
}
292
293
pub fn describe ( message : & str , change : Option< & str > ) -> Result< i32 > {
294
let repo = open ( ) ? ;
295
let h = match change {
296
Some ( c) => repo.resolve_change ( c) ? ,
297
None => current_head ( & repo) ? ,
298
} ;
299
let new = repo.describe ( & h, message) ? ;
300
let c = repo.store ( ) .get_change ( & new) ? ;
94084087 Andy McCall 1 month ago ↶
301
println! ( " {} {} {} {} " , ui:: done( " Described" ) , ui:: id( short_id ( & c) ) , ui:: hash( format! ( " #{} " , new.short ( 12 ) ) ) , ui:: subject( subject_of ( message) ) ) ;
614541c3 Andy McCall 1 month ago ↶
302
Ok ( 0 )
303
}
304
23b217d7 Andy McCall 1 month ago ↶
305
pub fn amend ( message : Option< & str > , into : Option< & str > ) -> Result< i32 > {
614541c3 Andy McCall 1 month ago ↶
306
let repo = open ( ) ? ;
23b217d7 Andy McCall 1 month ago ↶
307
let new = match into {
308
Some ( spec) => {
309
let target = repo.resolve_change ( spec) ? ;
310
repo.amend_into ( & target, message) ?
311
}
312
None => repo.amend ( message) ? ,
313
} ;
614541c3 Andy McCall 1 month ago ↶
314
let c = repo.store ( ) .get_change ( & new) ? ;
94084087 Andy McCall 1 month ago ↶
315
println! ( " {} {} {} {} " , ui:: done( " Amended" ) , ui:: id( short_id ( & c) ) , ui:: hash( format! ( " #{} " , new.short ( 12 ) ) ) , ui:: subject( subject_of ( & c.message) ) ) ;
614541c3 Andy McCall 1 month ago ↶
316
Ok ( 0 )
317
}
318
319
pub fn abandon ( change : & str ) -> Result< i32 > {
320
let repo = open ( ) ? ;
321
let h = repo.resolve_change ( change) ? ;
322
let c = repo.store ( ) .get_change ( & h) ? ;
6706bdcf Andy McCall 1 month ago ↶
323
let notes = repo.abandon ( & h) ? ;
94084087 Andy McCall 1 month ago ↶
324
println! ( " {} {} {} {} " , ui:: done( " Abandoned" ) , ui:: id( short_id ( & c) ) , ui:: hash( format! ( " #{} " , h.short ( 12 ) ) ) , ui:: dim( " its content remains on disk as uncommitted work if the working copy sat on it" ) ) ;
6706bdcf Andy McCall 1 month ago ↶
325
for n in notes {
94084087 Andy McCall 1 month ago ↶
326
println! ( " {} {n} " , ui:: note( ) ) ;
6706bdcf Andy McCall 1 month ago ↶
327
}
614541c3 Andy McCall 1 month ago ↶
328
Ok ( 0 )
329
}
252e8cb2 Andy McCall 1 month ago ↶
330
331
pub fn checkpoint ( ) -> Result< i32 > {
332
let repo = open ( ) ? ;
135212de Andy McCall 1 month ago ↶
333
let sp = ui:: spinner( " Writing checkpoint…" ) ;
252e8cb2 Andy McCall 1 month ago ↶
334
let ( r, changes, bytes) = repo.checkpoint ( ) ? ;
94084087 Andy McCall 1 month ago ↶
335
sp.done ( & format! ( " {} {} of {} ({} bytes) for {} " , ui:: done( " Checkpoint" ) , ui:: hash( format! ( " #{} " , r.short ( 12 ) ) ) , plural ( changes, " change" ) , bytes, ui:: id( & repo.config.bookmark) ) ) ;
135212de Andy McCall 1 month ago ↶
336
Ok ( 0 )
337
}
338
339
340
pub fn prompt ( format : & str ) -> Result< i32 > {
341
let Ok ( repo) = Repo:: open( & std:: env:: current_dir( ) ? ) else { return Ok ( 1 ) } ;
342
let info = repo.quick_status ( ) ? ;
343
println! ( " {} " , info.format ( format) ) ;
252e8cb2 Andy McCall 1 month ago ↶
344
Ok ( 0 )
345
}
7421309f Andy McCall 1 month ago ↶
346
347
pub fn sparse ( paths : & [String]) -> Result< i32 > {
348
let mut repo = open ( ) ? ;
349
if paths.is_empty ( ) {
350
if repo.config.sparse_paths.is_empty ( ) {
351
println! ( " No sparse filter: the whole tree is materialized." ) ;
352
} else {
353
println! ( " {} " , ui:: heading( " Sparse filter" ) ) ;
354
for p in & repo.config.sparse_paths {
355
println! ( " {} " , ui:: path( p) ) ;
356
}
357
}
358
return Ok ( 0 ) ;
359
}
360
let snap = repo.snapshot ( " oxy sparse" ) ? ;
361
if ! snap.wc.tree_ops.is_empty ( ) | | ! snap.wc.edits.is_empty ( ) {
362
anyhow:: bail! ( " the working copy has changes; commit them before changing the sparse filter" ) ;
363
}
364
repo.config.set ( " filter.paths" , & paths.join ( " ," ) ) ? ;
365
repo.save_config ( ) ? ;
366
let heads = repo.bookmark_heads ( ) ? ;
367
let sp = ui:: spinner( " Re-checking out with the new filter…" ) ;
368
let r = repo.checkout ( & heads, true , " oxy sparse (checkout)" ) ? ;
369
sp.done ( & format! ( " {} {} : {} written, {} removed" , ui:: ok( " Sparse filter set to" ) , ui:: path( paths.join ( " ," ) ) , plural ( r.written, " file" ) , r.removed) ) ;
370
Ok ( 0 )
371
}
132b884b Andy McCall 1 month ago ↶
372
373
pub fn tag_create ( name : & str , changes : & [String], message : & str ) -> Result< i32 > {
374
let repo = open ( ) ? ;
375
repo.snapshot ( " oxy tag" ) ? ;
376
let heads = if changes.is_empty ( ) {
377
repo.bookmark_heads ( ) ?
378
} else {
379
let mut heads = Vec :: new( ) ;
380
for c in changes {
381
heads.extend ( repo.resolve_heads ( c) ? ) ;
382
}
383
heads
384
} ;
385
let t = repo.tag_create ( name, & heads, message) ? ;
386
println! (
94084087 Andy McCall 1 month ago ↶
387
" {} {} {} {} ({} ){} " ,
388
ui:: done( " Tagged" ) ,
389
ui:: bookmark( & t.name) ,
390
ui:: dim( ui:: glyph( " →" , " ->" ) ) ,
132b884b Andy McCall 1 month ago ↶
391
ui:: hash( format! ( " #{} " , t.state.short ( 12 ) ) ) ,
392
plural ( t.heads.len ( ) , " head" ) ,
393
t.signer.map ( | s | format! ( " , signed by {s} " ) ) .unwrap_or_else ( | | ui:: dim( " , unsigned" ) )
394
) ;
395
Ok ( 0 )
396
}
397
398
pub fn tag_list ( ) -> Result< i32 > {
399
let repo = open ( ) ? ;
400
let tags = repo.tags ( ) ? ;
401
if tags.is_empty ( ) {
402
println! ( " {} " , ui:: dim( " No tags." ) ) ;
403
}
404
for t in tags {
405
println! (
94084087 Andy McCall 1 month ago ↶
406
" {} {} {} {} {} {} " ,
407
ui:: ok( ui:: glyph( " ⚑" , " #" ) ) ,
408
ui:: bookmark( & t.name) ,
132b884b Andy McCall 1 month ago ↶
409
ui:: hash( format! ( " #{} " , t.state.short ( 12 ) ) ) ,
94084087 Andy McCall 1 month ago ↶
410
ui:: sep( ) + & ui:: dim( plural ( t.heads.len ( ) , " head" ) ) ,
411
if t.message.is_empty ( ) { String :: new( ) } else { format! ( " {} " , ui:: subject( subject_of ( & t.message) ) ) } ,
412
t.signer.map ( | s | ui:: sep( ) + & ui:: ok( format! ( " {} {s} " , ui:: glyph( " ✔" , " v" ) ) ) ) .unwrap_or_default ( )
132b884b Andy McCall 1 month ago ↶
413
) ;
414
}
415
Ok ( 0 )
416
}
4e88e774 Andy McCall 1 month ago ↶
417
418
pub fn workspace_add ( path : & std:: path:: Path, changes : & [String]) -> Result< i32 > {
419
let repo = open ( ) ? ;
420
let heads = if changes.is_empty ( ) {
421
None
422
} else {
423
let mut heads = Vec :: new( ) ;
424
for c in changes {
425
heads.extend ( repo.resolve_heads ( c) ? ) ;
426
}
427
Some ( heads)
428
} ;
429
let sp = ui:: spinner( & format! ( " Creating workspace at {} …" , path.display ( ) ) ) ;
430
let ws = repo.workspace_add ( path, heads.as_deref ( ) ) ? ;
94084087 Andy McCall 1 month ago ↶
431
sp.done ( & format! ( " {} {} (workspace {} )" , ui:: done( " Workspace created at" ) , ui:: path( ws.root ( ) .display ( ) ) , ui:: id( ws.workspace ( ) .short ( 8 ) ) ) ) ;
4e88e774 Andy McCall 1 month ago ↶
432
Ok ( 0 )
433
}
434
435
pub fn workspace_list ( ) -> Result< i32 > {
436
let repo = open ( ) ? ;
437
for w in repo.workspaces ( ) ? {
438
println! (
439
" {} {} {} {} " ,
94084087 Andy McCall 1 month ago ↶
440
if w.current { ui:: ok( ui:: glyph( " ●" , " *" ) ) } else { ui:: dim( ui:: glyph( " ○" , " o" ) ) } ,
4e88e774 Andy McCall 1 month ago ↶
441
ui:: id( w.id.short ( 8 ) ) ,
442
ui:: path( w.path.display ( ) ) ,
94084087 Andy McCall 1 month ago ↶
443
w.working_copy.map ( | h | ui:: sep( ) + & ui:: dim( format! ( " working copy #{} " , h.short ( 12 ) ) ) ) .unwrap_or_else ( | | ui:: sep( ) + & ui:: warn( " not in view" ) )
4e88e774 Andy McCall 1 month ago ↶
444
) ;
445
}
446
Ok ( 0 )
447
}
448
449
pub fn workspace_forget ( spec : & str ) -> Result< i32 > {
450
let repo = open ( ) ? ;
451
let all = repo.workspaces ( ) ? ;
452
let target = std:: fs:: canonicalize( spec) .ok ( ) ;
453
let matches: Vec< _ > = all.iter ( ) .filter ( | w | w.id.starts_with_hex ( spec) | | target.as_ref ( ) .is_some_and ( | t | * t = = w.path) ) .collect ( ) ;
454
let w = match matches.as_slice ( ) {
455
[ w] => * w,
456
[ ] => anyhow:: bail! ( " no workspace matches {spec:?}" ) ,
457
_ => anyhow:: bail! ( " {spec:?} is ambiguous" ) ,
458
} ;
459
repo.workspace_forget ( & w.id) ? ;
94084087 Andy McCall 1 month ago ↶
460
println! ( " {} workspace {} at {} ; its files were left in place." , ui:: done( " Forgot" ) , ui:: id( w.id.short ( 8 ) ) , ui:: path( w.path.display ( ) ) ) ;
4e88e774 Andy McCall 1 month ago ↶
461
Ok ( 0 )
462
}
cdb5beba Andy McCall 1 month ago ↶
463
464
pub fn lock ( path : & str ) -> Result< i32 > {
465
let repo = open ( ) ? ;
466
repo.lock_path ( path) ? ;
94084087 Andy McCall 1 month ago ↶
467
println! ( " {} {} {} " , ui:: done( " Locked" ) , ui:: path( path) , ui:: dim( " (advisory, local)" ) ) ;
cdb5beba Andy McCall 1 month ago ↶
468
Ok ( 0 )
469
}
470
471
pub fn unlock ( path : & str ) -> Result< i32 > {
472
let repo = open ( ) ? ;
473
repo.unlock_path ( path) ? ;
94084087 Andy McCall 1 month ago ↶
474
println! ( " {} {} " , ui:: done( " Unlocked" ) , ui:: path( path) ) ;
cdb5beba Andy McCall 1 month ago ↶
475
Ok ( 0 )
476
}
23b217d7 Andy McCall 1 month ago ↶
477
478
pub fn split ( change : & str , paths : & [String]) -> Result< i32 > {
479
let repo = open ( ) ? ;
480
let h = repo.resolve_change ( change) ? ;
481
let ( h1, h2) = repo.split ( & h, paths) ? ;
482
let c1 = repo.store ( ) .get_change ( & h1) ? ;
483
let c2 = repo.store ( ) .get_change ( & h2) ? ;
94084087 Andy McCall 1 month ago ↶
484
println! ( " {} into {} {} and {} {} " , ui:: done( " Split" ) , ui:: id( short_id ( & c1) ) , ui:: hash( format! ( " #{} " , h1.short ( 12 ) ) ) , ui:: id( short_id ( & c2) ) , ui:: hash( format! ( " #{} " , h2.short ( 12 ) ) ) ) ;
23b217d7 Andy McCall 1 month ago ↶
485
Ok ( 0 )
486
}