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