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
694805cc Andy McCall 1 month ago ↶
340
pub fn prompt ( format : & str , glyphs : bool , color : Option< & str > ) -> Result< i32 > {
135212de Andy McCall 1 month ago ↶
341
let Ok ( repo) = Repo:: open( & std:: env:: current_dir( ) ? ) else { return Ok ( 1 ) } ;
342
let info = repo.quick_status ( ) ? ;
694805cc Andy McCall 1 month ago ↶
343
let fmt = if glyphs & & format = = oxy_core:: repo:: DEFAULT_PROMPT_FORMAT { oxy_core:: repo:: GLYPH_PROMPT_FORMAT } else { format } ;
344
let line = match color {
345
Some ( " bash" ) => info.format_colored ( fmt, ( " \\ [" , " \\ ]" ) ) ,
346
Some ( " zsh" ) => info.format_colored ( fmt, ( " %{" , " %}" ) ) ,
347
Some ( _ ) => info.format_colored ( fmt, ( " " , " " ) ) ,
348
None => info.format ( fmt) ,
349
} ;
350
println! ( " {line} " ) ;
252e8cb2 Andy McCall 1 month ago ↶
351
Ok ( 0 )
352
}
7421309f Andy McCall 1 month ago ↶
353
354
pub fn sparse ( paths : & [String]) -> Result< i32 > {
355
let mut repo = open ( ) ? ;
356
if paths.is_empty ( ) {
357
if repo.config.sparse_paths.is_empty ( ) {
358
println! ( " No sparse filter: the whole tree is materialized." ) ;
359
} else {
360
println! ( " {} " , ui:: heading( " Sparse filter" ) ) ;
361
for p in & repo.config.sparse_paths {
362
println! ( " {} " , ui:: path( p) ) ;
363
}
364
}
365
return Ok ( 0 ) ;
366
}
367
let snap = repo.snapshot ( " oxy sparse" ) ? ;
368
if ! snap.wc.tree_ops.is_empty ( ) | | ! snap.wc.edits.is_empty ( ) {
369
anyhow:: bail! ( " the working copy has changes; commit them before changing the sparse filter" ) ;
370
}
371
repo.config.set ( " filter.paths" , & paths.join ( " ," ) ) ? ;
372
repo.save_config ( ) ? ;
373
let heads = repo.bookmark_heads ( ) ? ;
374
let sp = ui:: spinner( " Re-checking out with the new filter…" ) ;
375
let r = repo.checkout ( & heads, true , " oxy sparse (checkout)" ) ? ;
376
sp.done ( & format! ( " {} {} : {} written, {} removed" , ui:: ok( " Sparse filter set to" ) , ui:: path( paths.join ( " ," ) ) , plural ( r.written, " file" ) , r.removed) ) ;
377
Ok ( 0 )
378
}
132b884b Andy McCall 1 month ago ↶
379
380
pub fn tag_create ( name : & str , changes : & [String], message : & str ) -> Result< i32 > {
381
let repo = open ( ) ? ;
382
repo.snapshot ( " oxy tag" ) ? ;
383
let heads = if changes.is_empty ( ) {
384
repo.bookmark_heads ( ) ?
385
} else {
386
let mut heads = Vec :: new( ) ;
387
for c in changes {
388
heads.extend ( repo.resolve_heads ( c) ? ) ;
389
}
390
heads
391
} ;
392
let t = repo.tag_create ( name, & heads, message) ? ;
393
println! (
94084087 Andy McCall 1 month ago ↶
394
" {} {} {} {} ({} ){} " ,
395
ui:: done( " Tagged" ) ,
396
ui:: bookmark( & t.name) ,
397
ui:: dim( ui:: glyph( " →" , " ->" ) ) ,
132b884b Andy McCall 1 month ago ↶
398
ui:: hash( format! ( " #{} " , t.state.short ( 12 ) ) ) ,
399
plural ( t.heads.len ( ) , " head" ) ,
400
t.signer.map ( | s | format! ( " , signed by {s} " ) ) .unwrap_or_else ( | | ui:: dim( " , unsigned" ) )
401
) ;
402
Ok ( 0 )
403
}
404
405
pub fn tag_list ( ) -> Result< i32 > {
406
let repo = open ( ) ? ;
407
let tags = repo.tags ( ) ? ;
408
if tags.is_empty ( ) {
409
println! ( " {} " , ui:: dim( " No tags." ) ) ;
410
}
411
for t in tags {
412
println! (
94084087 Andy McCall 1 month ago ↶
413
" {} {} {} {} {} {} " ,
414
ui:: ok( ui:: glyph( " ⚑" , " #" ) ) ,
415
ui:: bookmark( & t.name) ,
132b884b Andy McCall 1 month ago ↶
416
ui:: hash( format! ( " #{} " , t.state.short ( 12 ) ) ) ,
94084087 Andy McCall 1 month ago ↶
417
ui:: sep( ) + & ui:: dim( plural ( t.heads.len ( ) , " head" ) ) ,
418
if t.message.is_empty ( ) { String :: new( ) } else { format! ( " {} " , ui:: subject( subject_of ( & t.message) ) ) } ,
419
t.signer.map ( | s | ui:: sep( ) + & ui:: ok( format! ( " {} {s} " , ui:: glyph( " ✔" , " v" ) ) ) ) .unwrap_or_default ( )
132b884b Andy McCall 1 month ago ↶
420
) ;
421
}
422
Ok ( 0 )
423
}
4e88e774 Andy McCall 1 month ago ↶
424
425
pub fn workspace_add ( path : & std:: path:: Path, changes : & [String]) -> Result< i32 > {
426
let repo = open ( ) ? ;
427
let heads = if changes.is_empty ( ) {
428
None
429
} else {
430
let mut heads = Vec :: new( ) ;
431
for c in changes {
432
heads.extend ( repo.resolve_heads ( c) ? ) ;
433
}
434
Some ( heads)
435
} ;
436
let sp = ui:: spinner( & format! ( " Creating workspace at {} …" , path.display ( ) ) ) ;
437
let ws = repo.workspace_add ( path, heads.as_deref ( ) ) ? ;
94084087 Andy McCall 1 month ago ↶
438
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 ↶
439
Ok ( 0 )
440
}
441
442
pub fn workspace_list ( ) -> Result< i32 > {
443
let repo = open ( ) ? ;
444
for w in repo.workspaces ( ) ? {
445
println! (
446
" {} {} {} {} " ,
94084087 Andy McCall 1 month ago ↶
447
if w.current { ui:: ok( ui:: glyph( " ●" , " *" ) ) } else { ui:: dim( ui:: glyph( " ○" , " o" ) ) } ,
4e88e774 Andy McCall 1 month ago ↶
448
ui:: id( w.id.short ( 8 ) ) ,
449
ui:: path( w.path.display ( ) ) ,
94084087 Andy McCall 1 month ago ↶
450
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 ↶
451
) ;
452
}
453
Ok ( 0 )
454
}
455
456
pub fn workspace_forget ( spec : & str ) -> Result< i32 > {
457
let repo = open ( ) ? ;
458
let all = repo.workspaces ( ) ? ;
459
let target = std:: fs:: canonicalize( spec) .ok ( ) ;
460
let matches: Vec< _ > = all.iter ( ) .filter ( | w | w.id.starts_with_hex ( spec) | | target.as_ref ( ) .is_some_and ( | t | * t = = w.path) ) .collect ( ) ;
461
let w = match matches.as_slice ( ) {
462
[ w] => * w,
463
[ ] => anyhow:: bail! ( " no workspace matches {spec:?}" ) ,
464
_ => anyhow:: bail! ( " {spec:?} is ambiguous" ) ,
465
} ;
466
repo.workspace_forget ( & w.id) ? ;
94084087 Andy McCall 1 month ago ↶
467
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 ↶
468
Ok ( 0 )
469
}
cdb5beba Andy McCall 1 month ago ↶
470
471
pub fn lock ( path : & str ) -> Result< i32 > {
472
let repo = open ( ) ? ;
473
repo.lock_path ( path) ? ;
94084087 Andy McCall 1 month ago ↶
474
println! ( " {} {} {} " , ui:: done( " Locked" ) , ui:: path( path) , ui:: dim( " (advisory, local)" ) ) ;
cdb5beba Andy McCall 1 month ago ↶
475
Ok ( 0 )
476
}
477
478
pub fn unlock ( path : & str ) -> Result< i32 > {
479
let repo = open ( ) ? ;
480
repo.unlock_path ( path) ? ;
94084087 Andy McCall 1 month ago ↶
481
println! ( " {} {} " , ui:: done( " Unlocked" ) , ui:: path( path) ) ;
cdb5beba Andy McCall 1 month ago ↶
482
Ok ( 0 )
483
}
23b217d7 Andy McCall 1 month ago ↶
484
485
pub fn split ( change : & str , paths : & [String]) -> Result< i32 > {
486
let repo = open ( ) ? ;
487
let h = repo.resolve_change ( change) ? ;
488
let ( h1, h2) = repo.split ( & h, paths) ? ;
489
let c1 = repo.store ( ) .get_change ( & h1) ? ;
490
let c2 = repo.store ( ) .get_change ( & h2) ? ;
94084087 Andy McCall 1 month ago ↶
491
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 ↶
492
Ok ( 0 )
493
}