98286406 Andy McCall 1 month ago ↶
1
2
1ec6fdbc Andy McCall 16 days ago ↶
3
use super :: tags:: TagCheck;
98286406 Andy McCall 1 month ago ↶
4
use super :: * ;
5
7aa2dc93 Andy McCall 1 month ago ↶
6
7
# [ derive ( Clone, Debug, Default ) ]
8
pub struct PushReport {
9
pub results : Vec< RefResult> ,
10
11
pub updated : Vec< RefUpdated> ,
12
13
pub imported : Vec< ChangeHash> ,
14
}
15
16
# [ derive ( Clone, Debug ) ]
17
pub struct RefUpdated {
18
pub name : String,
19
pub old_state : ObjectRef,
20
pub new_state : ObjectRef,
21
pub heads : Vec< ChangeHash> ,
22
}
23
83e0677b Andy McCall 1 month ago ↶
24
25
# [ derive ( Debug, Clone, PartialEq, Eq, Default ) ]
26
pub struct FetchReport {
27
28
pub refs : Vec< ( String, Vec< ChangeHash> , usize ) > ,
132b884b Andy McCall 1 month ago ↶
29
30
pub new_tags : usize ,
83e0677b Andy McCall 1 month ago ↶
31
32
33
pub unverified : bool ,
4b9d0677 Andy McCall 18 days ago ↶
34
35
36
37
pub log_notes : Vec< String> ,
d36ba2f7 Andy McCall 17 days ago ↶
38
39
40
41
42
pub skipped : Vec< ( String, String) > ,
83e0677b Andy McCall 1 month ago ↶
43
}
44
98286406 Andy McCall 1 month ago ↶
45
# [ derive ( Debug, Clone, PartialEq, Eq ) ]
46
pub struct PullReport {
14edbaaf Andy McCall 1 month ago ↶
47
98286406 Andy McCall 1 month ago ↶
48
pub heads : Vec< ChangeHash> ,
14edbaaf Andy McCall 1 month ago ↶
49
98286406 Andy McCall 1 month ago ↶
50
pub changed : bool ,
51
pub checked_out : bool ,
14edbaaf Andy McCall 1 month ago ↶
52
53
54
pub others : Vec< String> ,
d36ba2f7 Andy McCall 17 days ago ↶
55
56
pub skipped : Vec< ( String, String) > ,
98286406 Andy McCall 1 month ago ↶
57
}
58
cb8b8082 Andy McCall 26 days ago ↶
59
60
61
pub const OBJECTS_RESULT : & str = " objects" ;
62
98286406 Andy McCall 1 month ago ↶
63
impl Repo {
64
65
66
fn ref_attest_path ( & self , bookmark : & str ) -> PathBuf {
54cd08a1 Andy McCall 1 month ago ↶
67
self .oxy.join ( " attest" ) .join ( name_file ( bookmark) )
98286406 Andy McCall 1 month ago ↶
68
}
69
70
71
pub fn latest_ref_attest ( & self , bookmark : & str ) -> Result< Option< ( ObjectRef, SignedAttest) > > {
72
match fs:: read_to_string( self .ref_attest_path ( bookmark) ) {
73
Ok ( h) => {
75167672 Andy McCall 1 month ago
74
let r = ObjectRef:: from_hex( h.trim ( ) )
75
.ok_or_else ( | | RepoError:: Msg( " corrupt attestation pointer" .into ( ) ) ) ? ;
76
Ok ( Some ( (
77
r,
78
SignedAttest {
79
attest: self .store.get_attest ( & r) ? ,
80
sigs: self .store.signatures ( & r) ? ,
81
} ,
82
) ) )
98286406 Andy McCall 1 month ago ↶
83
}
84
Err ( e) if e.kind ( ) = = std:: io:: ErrorKind:: NotFound => Ok ( None ) ,
85
Err ( e) => Err ( e.into ( ) ) ,
86
}
87
}
88
9f9e72b9 Andy McCall 1 month ago ↶
89
pub ( crate ) fn set_ref_attest ( & self , bookmark : & str , r : & ObjectRef) -> Result< ( ) > {
98286406 Andy McCall 1 month ago ↶
90
fs:: create_dir_all( self .oxy.join ( " attest" ) ) ? ;
91
write_atomic ( & self .ref_attest_path ( bookmark) , r.to_hex ( ) .as_bytes ( ) )
92
}
93
83e0677b Andy McCall 1 month ago ↶
94
pub fn remote_refs ( & self ) -> Result< RefsResponse> {
98286406 Andy McCall 1 month ago ↶
95
let view = self .view ( ) ? ;
96
let mut out = Vec :: new( ) ;
97
for ( name, state) in & view.bookmarks {
98
let latest = self .latest_ref_attest ( name) ? .map ( | ( _, a ) | a ) ;
99
let last_serial = latest.as_ref ( ) .and_then ( | a | match a.attest.body {
100
AttestBody:: Ref { serial, .. } => Some ( serial) ,
101
_ => None ,
102
} ) ;
103
let attestation = latest.filter ( | a | matches! ( & a.attest.body, AttestBody:: Ref { new_state, .. } if new_state = = state) ) ;
f53cbe7a Andy McCall 19 days ago ↶
104
let accepted = match & attestation {
105
Some ( a) => self .acceptance_of ( & a.attest.hash ( ) ) ? ,
106
None => None ,
107
} ;
75167672 Andy McCall 1 month ago
108
out.push ( RemoteRef {
109
name: name.clone ( ) ,
110
state: * state,
111
heads: self .store.get_state ( state) ? .heads,
112
attestation,
113
last_serial,
f53cbe7a Andy McCall 19 days ago ↶
114
accepted,
4b9d0677 Andy McCall 18 days ago ↶
115
logged: None ,
028545df Andy McCall 18 days ago ↶
116
integration: vec! [ ] ,
75167672 Andy McCall 1 month ago
117
} ) ;
98286406 Andy McCall 1 month ago ↶
118
}
28fc23d7 Andy McCall 1 month ago ↶
119
let policy = self .current_policy ( ) ? .map ( | ( _, sp ) | sp ) ;
75167672 Andy McCall 1 month ago
120
let history = self
121
.policy_history ( ) ?
122
.into_iter ( )
123
.filter ( | sp | {
124
policy
125
.as_ref ( )
126
.is_some_and ( | p | sp.policy.serial < p.policy.serial )
127
} )
128
.collect ( ) ;
129
Ok ( RefsResponse {
130
refs: out,
131
policy,
132
tags: self .tag_refs ( ) ? ,
133
history,
14edbaaf Andy McCall 1 month ago ↶
134
default_bookmark: Some ( self .config.bookmark.clone ( ) ) ,
4b9d0677 Andy McCall 18 days ago ↶
135
log: None ,
028545df Andy McCall 18 days ago ↶
136
witnesses: vec! [ ] ,
75167672 Andy McCall 1 month ago
137
} )
98286406 Andy McCall 1 month ago ↶
138
}
139
140
141
fn closure_in_store ( & self , heads : & [ChangeHash]) -> Result< BTreeSet< ChangeHash> > {
142
let mut seen = BTreeSet:: new( ) ;
143
let mut stack: Vec< ChangeHash> = heads.to_vec ( ) ;
144
while let Some ( h) = stack.pop ( ) {
145
if seen.contains ( & h) | | ! self .store.has ( & h) {
146
continue ;
147
}
148
seen.insert ( h) ;
69816d68 Andy McCall 1 month ago ↶
149
stack.extend ( self .store.get_change_meta ( & h) ? .deps) ;
98286406 Andy McCall 1 month ago ↶
150
}
151
Ok ( seen)
152
}
153
2863456a Andy McCall 1 month ago ↶
154
155
156
pub fn shallow_changes ( & self , heads : & [ChangeHash], depth : u32 ) -> Result< Vec< ChangeHash> > {
157
let mut out = Vec :: new( ) ;
158
let mut seen: BTreeSet< ChangeHash> = BTreeSet:: new( ) ;
159
let mut layer: Vec< ChangeHash> = heads.to_vec ( ) ;
160
for _ in 0 .. depth.max ( 1 ) {
161
let mut next = Vec :: new( ) ;
162
for h in layer {
163
if ! seen.insert ( h) | | ! self .store.has ( & h) {
164
continue ;
165
}
166
let c = self .store.get_change ( & h) ? ;
167
next.extend ( c.deps.iter ( ) .copied ( ) ) ;
168
out.push ( h) ;
169
}
170
if next.is_empty ( ) {
171
break ;
172
}
173
layer = next;
174
}
175
out.reverse ( ) ;
176
Ok ( out)
177
}
178
179
fn shallow_path ( & self ) -> PathBuf {
180
self .oxy.join ( " shallow" )
181
}
182
183
184
pub fn boundary ( & self ) -> BTreeSet< ChangeHash> {
75167672 Andy McCall 1 month ago
185
fs:: read_to_string( self .shallow_path ( ) )
186
.map ( | t | t.lines ( ) .filter_map ( ObjectRef:: from_hex) .collect ( ) )
187
.unwrap_or_default ( )
2863456a Andy McCall 1 month ago ↶
188
}
189
190
pub fn is_shallow ( & self ) -> bool {
191
! self .boundary ( ) .is_empty ( )
192
}
193
194
fn write_boundary ( & self , boundary : & BTreeSet< ChangeHash> ) -> Result< ( ) > {
195
if boundary.is_empty ( ) {
196
let _ = fs:: remove_file( self .shallow_path ( ) ) ;
197
return Ok ( ( ) ) ;
198
}
75167672 Andy McCall 1 month ago
199
let text: String = boundary
200
.iter ( )
201
.map ( | h | format! ( " {} \n " , h.to_hex ( ) ) )
202
.collect ( ) ;
2863456a Andy McCall 1 month ago ↶
203
write_atomic ( & self .shallow_path ( ) , text.as_bytes ( ) )
204
}
205
206
207
208
fn refresh_boundary ( & self , imported : & [ChangeHash]) -> Result< ( ) > {
209
let mut boundary = self .boundary ( ) ;
210
boundary.retain ( | h | ! self .store.has ( h) ) ;
211
for h in imported {
69816d68 Andy McCall 1 month ago ↶
212
for d in self .store.get_change_meta ( h) ? .deps {
2863456a Andy McCall 1 month ago ↶
213
if ! self .store.has ( & d) {
214
boundary.insert ( d) ;
215
}
216
}
217
}
218
self .write_boundary ( & boundary)
219
}
220
221
222
pub fn deepen ( & self , remote_name : & str , depth : u32 ) -> Result< usize > {
223
let boundary = self .boundary ( ) ;
224
if boundary.is_empty ( ) {
225
return Ok ( 0 ) ;
226
}
227
let remote = self .open_named_remote ( remote_name) ? ;
228
let wanted = remote.shallow ( & boundary.iter ( ) .copied ( ) .collect:: < Vec< _ > > ( ) , depth) ? ;
229
let bundle = remote.fetch ( & wanted, self .config.max_blob) ? ;
230
let imported = self .import_bundle_shallow ( & bundle, false ) ? ;
231
if self .config.max_blob.is_some ( ) {
232
self .register_missing_blobs ( & imported, remote_name) ? ;
233
}
234
self .refresh_boundary ( & imported) ? ;
235
Ok ( imported.len ( ) )
236
}
237
98286406 Andy McCall 1 month ago ↶
238
239
pub fn negotiate ( & self , have : & [ChangeHash], want : & [ChangeHash]) -> Result< Vec< ChangeHash> > {
240
let have = self .closure_in_store ( have) ? ;
2863456a Andy McCall 1 month ago ↶
241
242
243
let boundary = self .boundary ( ) ;
98286406 Andy McCall 1 month ago ↶
244
let mut out = Vec :: new( ) ;
245
let mut done: BTreeSet< ChangeHash> = have.clone ( ) ;
2863456a Andy McCall 1 month ago ↶
246
done.extend ( boundary.iter ( ) .copied ( ) ) ;
98286406 Andy McCall 1 month ago ↶
247
248
let mut stack: Vec< ( ChangeHash, bool ) > = want.iter ( ) .rev ( ) .map ( | h | ( * h, false ) ) .collect ( ) ;
249
while let Some ( ( h, expanded) ) = stack.pop ( ) {
250
if done.contains ( & h) {
251
continue ;
252
}
253
if ! self .store.has ( & h) {
254
return fail ( format! ( " change {} is not in this repository" , h.short ( 12 ) ) ) ;
255
}
256
if expanded {
257
done.insert ( h) ;
258
out.push ( h) ;
259
continue ;
260
}
261
stack.push ( ( h, true ) ) ;
69816d68 Andy McCall 1 month ago ↶
262
for d in self .store.get_change_meta ( & h) ? .deps {
98286406 Andy McCall 1 month ago ↶
263
if ! done.contains ( & d) {
264
stack.push ( ( d, false ) ) ;
265
}
266
}
267
}
268
Ok ( out)
269
}
270
271
272
273
pub fn bundle_for ( & self , changes : & [ChangeHash]) -> Result< Bundle> {
d36ba2f7 Andy McCall 17 days ago ↶
274
self .bundle_of ( changes, None , false , false )
b3c5a59a Andy McCall 1 month ago ↶
275
}
276
277
278
pub fn objects_for ( & self , refs : & [ObjectRef]) -> Result< Vec< ( ObjectType, Vec< u8 > ) > > {
279
let mut out = Vec :: new( ) ;
280
for r in refs {
281
let ( ty, body) = match self .store.get ( r) {
282
Ok ( x) => x,
283
Err ( StoreError:: NotFound( _ ) ) => continue ,
284
Err ( e) => return Err ( e.into ( ) ) ,
285
} ;
286
if ty = = ObjectType:: Blob {
287
for c in Blob:: decode( & body) ? .chunks {
288
if let Ok ( ( cty, cb) ) = self .store.get ( & c) {
289
out.push ( ( cty, cb) ) ;
290
}
291
}
292
}
293
out.push ( ( ty, body) ) ;
294
}
295
Ok ( out)
296
}
297
298
299
d36ba2f7 Andy McCall 17 days ago ↶
300
301
302
303
75167672 Andy McCall 1 month ago
304
pub fn bundle_for_filtered (
305
& self ,
306
changes : & [ChangeHash],
307
max_blob : Option< u64 > ,
308
) -> Result< Bundle> {
d36ba2f7 Andy McCall 17 days ago ↶
309
self .bundle_of ( changes, max_blob, false , true )
2c75672f Andy McCall 1 month ago ↶
310
}
311
312
313
314
315
316
pub fn bundle_raw_for ( & self , changes : & [ChangeHash], max_blob : Option< u64 > ) -> Result< Bundle> {
d36ba2f7 Andy McCall 17 days ago ↶
317
self .bundle_of ( changes, max_blob, true , true )
2c75672f Andy McCall 1 month ago ↶
318
}
319
d36ba2f7 Andy McCall 17 days ago ↶
320
321
322
323
324
325
326
327
pub fn served_attest_signers ( & self ) -> Result< BTreeSet< KeyId> > {
328
let view = self .view ( ) ? ;
329
let pointers = view
330
.bookmarks
331
.keys ( )
332
.map ( | b | self .ref_attest_path ( b) )
333
.chain ( view.tags.keys ( ) .map ( | t | self .tag_attest_path ( t) ) ) ;
334
let mut keys = BTreeSet:: new( ) ;
335
for p in pointers {
336
let Ok ( text) = fs:: read_to_string( & p) else {
337
continue ;
338
} ;
339
let Some ( r) = ObjectRef:: from_hex( text.trim ( ) ) else {
340
continue ;
341
} ;
342
keys.extend ( self .store.signatures ( & r) ? .into_iter ( ) .map ( | s | s.key ) ) ;
343
}
344
Ok ( keys)
345
}
346
347
348
2c75672f Andy McCall 1 month ago ↶
349
fn bundle_of (
350
& self ,
351
changes : & [ChangeHash],
352
max_blob : Option< u64 > ,
353
raw : bool ,
d36ba2f7 Andy McCall 17 days ago ↶
354
serving : bool ,
2c75672f Andy McCall 1 month ago ↶
355
) -> Result< Bundle> {
98286406 Andy McCall 1 month ago ↶
356
let mut bundle = Bundle:: default( ) ;
357
let mut objects: BTreeSet< ObjectRef> = BTreeSet:: new( ) ;
358
let mut seals: BTreeSet< ObjectRef> = BTreeSet:: new( ) ;
359
let add_object = | r : & ObjectRef, objects : & mut BTreeSet< ObjectRef> | {
360
if ! r.is_zero ( ) & & self .store.has ( r) {
361
objects.insert ( * r) ;
362
}
363
} ;
364
for h in changes {
2c75672f Andy McCall 1 month ago ↶
365
366
let ( c, encoded) = if raw {
367
let bytes = self .store.get_typed ( h, ObjectType:: Change) ? ;
368
let ( skel, texts) = Change:: decode_skeleton( & bytes, * h) ? ;
369
for t in texts {
0f93f49c Andy McCall 1 month ago ↶
370
if let crate :: objects:: TextRef:: Blob( r, _ , _ ) = t {
2c75672f Andy McCall 1 month ago ↶
371
let blob = Blob:: decode( & self .store.get_typed ( & r, ObjectType:: Blob) ? ) ? ;
372
objects.insert ( r) ;
373
objects.extend ( blob.chunks) ;
374
}
375
}
376
( skel, Some ( bytes) )
377
} else {
378
( self .store.get_change ( h) ? , None )
379
} ;
98286406 Andy McCall 1 month ago ↶
380
let sigs = self .store.signatures ( h) ? ;
381
add_object ( & c.author, & mut objects) ;
382
for s in & sigs {
383
add_object ( & s.key, & mut objects) ;
384
}
570e3531 Andy McCall 11 days ago ↶
385
386
387
388
98286406 Andy McCall 1 month ago ↶
389
for e in & c.edits {
570e3531 Andy McCall 11 days ago ↶
390
if let Edit:: Replace { new: Some ( b) , .. } = e {
391
if self .store.has ( b) {
392
if let Ok ( blob) = Blob:: decode( & self .store.get_typed ( b, ObjectType:: Blob) ? )
393
{
394
if max_blob.is_some_and ( | m | blob.length > m ) {
395
continue ;
98286406 Andy McCall 1 month ago ↶
396
}
570e3531 Andy McCall 11 days ago ↶
397
objects.insert ( * b) ;
398
objects.extend ( blob.chunks.iter ( ) .copied ( ) ) ;
98286406 Andy McCall 1 month ago ↶
399
}
400
}
401
}
402
}
403
for s in self .store.seals_for ( h) ? {
404
seals.insert ( s) ;
2c75672f Andy McCall 1 month ago ↶
405
}
406
match encoded {
407
Some ( bytes) => bundle.raw_changes.push ( ( bytes, sigs) ) ,
408
None => {
409
bundle.changes.push ( ( c, sigs) ) ;
410
bundle.hashes.push ( * h) ;
411
}
98286406 Andy McCall 1 month ago ↶
412
}
413
}
414
for r in seals {
415
let attest = self .store.get_attest ( & r) ? ;
416
let sigs = self .store.signatures ( & r) ? ;
417
for s in & sigs {
418
add_object ( & s.key, & mut objects) ;
419
}
420
bundle.attests.push ( SignedAttest { attest, sigs } ) ;
421
}
d36ba2f7 Andy McCall 17 days ago ↶
422
let signers: Vec< KeyId> = if serving {
423
let signers = self .served_attest_signers ( ) ? ;
424
for k in & signers {
425
add_object ( k, & mut objects) ;
426
}
427
signers.into_iter ( ) .collect ( )
428
} else {
429
Vec :: new( )
430
} ;
98286406 Andy McCall 1 month ago ↶
431
for r in objects {
432
let ( ty, body) = self .store.get ( & r) ? ;
433
bundle.objects.push ( ( ty, body) ) ;
434
}
d36ba2f7 Andy McCall 17 days ago ↶
435
self .attach_certificates_for ( & mut bundle, & signers) ? ;
98286406 Andy McCall 1 month ago ↶
436
Ok ( bundle)
437
}
438
f0a517d2 Andy McCall 19 days ago ↶
439
440
441
442
443
pub ( crate ) fn attach_certificates_for (
444
& self ,
445
bundle : & mut Bundle,
446
also : & [KeyId],
447
) -> Result< ( ) > {
448
let mut keys: BTreeSet< KeyId> = also.iter ( ) .copied ( ) .collect ( ) ;
449
keys.extend (
450
bundle
451
.changes
452
.iter ( )
453
.flat_map ( | ( _, s ) | s.iter ( ) .map ( | s | s.key ) ) ,
454
) ;
455
keys.extend (
456
bundle
457
.raw_changes
458
.iter ( )
459
.flat_map ( | ( _, s ) | s.iter ( ) .map ( | s | s.key ) ) ,
460
) ;
461
keys.extend (
462
bundle
463
.attests
464
.iter ( )
465
.flat_map ( | a | a.sigs.iter ( ) .map ( | s | s.key ) ) ,
466
) ;
467
for k in keys {
468
let Some ( r) = self .store.certificate_of ( & k) ? else {
469
continue ;
470
} ;
471
let cert = self .store.get_certificate ( & r) ? ;
472
if bundle
473
.certificates
474
.iter ( )
475
.any ( | c | c.cert.hash ( ) = = cert.cert.hash ( ) )
476
{
477
continue ;
478
}
f0ef9778 Andy McCall 12 days ago ↶
479
480
481
let grantor = cert.cert.grant.as_ref ( ) .map ( | g | g.grant.grantor ) ;
482
for id in [ Some ( k) , Some ( cert.cert.issuer) , grantor] .iter ( ) .flatten ( ) {
f0a517d2 Andy McCall 19 days ago ↶
483
if let Ok ( body) = self .store.get_typed ( id, ObjectType:: Identity) {
484
if ! bundle
485
.objects
486
.iter ( )
487
.any ( | ( t , b ) | * t = = ObjectType:: Identity & & * b = = body)
488
{
489
bundle.objects.push ( ( ObjectType:: Identity, body) ) ;
490
}
491
}
492
}
493
bundle.certificates.push ( cert) ;
494
}
495
Ok ( ( ) )
496
}
497
498
499
500
fn adopt_certificates ( & self , certs : & [crate:: cert:: SignedCertificate]) -> Result< ( ) > {
501
for c in certs {
502
let issuer = self .store.get_identity ( & c.cert.issuer) .map_err ( | _| {
503
RepoError:: Msg( format! (
504
" a certificate names issuer {} , whose identity did not come with it" ,
505
c.cert.issuer.short ( 12 )
506
) )
507
} ) ? ;
508
c.verify ( & issuer)
509
.map_err ( | e | RepoError:: Msg( format! ( " a certificate does not verify: {e} " ) ) ) ? ;
510
self .store.put_identity ( & c.cert.key) ? ;
511
self .store.put_certificate ( c) ? ;
512
}
513
Ok ( ( ) )
514
}
515
516
517
518
519
520
pub ( crate ) fn certified_authorized (
521
& self ,
522
p : & crate:: policy:: Policy,
523
signer : & KeyId,
524
reference : & str ,
525
scope : Scope,
526
at_ms : u64 ,
527
) -> bool {
528
let Ok ( Some ( r) ) = self .store.certificate_of ( signer) else {
529
return false ;
530
} ;
531
let Ok ( c) = self .store.get_certificate ( & r) else {
532
return false ;
533
} ;
534
let Some ( issuer) = p
535
.identity ( & c.cert.issuer)
536
.cloned ( )
537
.or_else ( | | self .store.get_identity ( & c.cert.issuer) .ok ( ) )
538
else {
539
return false ;
540
} ;
541
c.verify ( & issuer) .is_ok ( )
542
& & c.cert.key_id ( ) = = * signer
543
& & c.cert.covers ( scope, at_ms)
544
& & p.subject_grant ( reference, & c.cert.issuer, & c.cert.subject, scope)
545
}
546
98286406 Andy McCall 1 month ago ↶
547
548
549
pub fn import_bundle ( & self , bundle : & Bundle, strict : bool ) -> Result< Vec< ChangeHash> > {
2863456a Andy McCall 1 month ago ↶
550
self .import_bundle_inner ( bundle, strict, false )
551
}
552
553
554
555
pub fn import_bundle_shallow ( & self , bundle : & Bundle, strict : bool ) -> Result< Vec< ChangeHash> > {
556
self .import_bundle_inner ( bundle, strict, true )
557
}
558
75167672 Andy McCall 1 month ago
559
fn import_bundle_inner (
560
& self ,
561
bundle : & Bundle,
562
strict : bool ,
563
shallow : bool ,
564
) -> Result< Vec< ChangeHash> > {
8f10a07a Andy McCall 1 month ago ↶
565
let batch = self .store.begin_batch ( ) ? ;
566
let result = self .import_bundle_batched ( bundle, strict, shallow) ;
567
batch.finish ( ) ? ;
568
result
569
}
570
75167672 Andy McCall 1 month ago
571
fn import_bundle_batched (
572
& self ,
573
bundle : & Bundle,
574
strict : bool ,
575
shallow : bool ,
576
) -> Result< Vec< ChangeHash> > {
2c75672f Andy McCall 1 month ago ↶
577
for ( ty, _ ) in & bundle.objects {
578
if ! matches! (
579
ty,
75167672 Andy McCall 1 month ago
580
ObjectType:: Chunk
2c75672f Andy McCall 1 month ago ↶
581
| ObjectType:: Blob
582
| ObjectType:: Identity
583
| ObjectType:: State
584
| ObjectType:: Checkpoint
585
) {
586
return fail ( format! ( " bundle may not carry {} objects" , ty.name ( ) ) ) ;
98286406 Andy McCall 1 month ago ↶
587
}
588
}
2c75672f Andy McCall 1 month ago ↶
589
590
let objects: Vec< ( ObjectType, & [u8 ]) > = bundle
591
.objects
592
.iter ( )
593
.map ( | ( ty , body ) | ( * ty, body.as_slice ( ) ) )
594
.collect ( ) ;
595
self .store.put_many ( & objects) ? ;
f0a517d2 Andy McCall 19 days ago ↶
596
self .adopt_certificates ( & bundle.certificates) ? ;
98286406 Andy McCall 1 month ago ↶
597
for sa in & bundle.attests {
598
let r = self .store.put_attest ( & sa.attest) ? ;
599
for sig in & sa.sigs {
600
self .store.put_signature ( & r, sig) ? ;
601
}
602
if let AttestBody:: Seal { hashes } = & sa.attest.body {
603
for h in hashes {
604
self .store.index_seal ( h, & r) ? ;
605
}
606
}
607
}
598009a7 Andy McCall 1 month ago ↶
608
609
610
611
let hashes: Vec< ChangeHash> = if bundle.hashes.len ( ) = = bundle.changes.len ( ) {
612
bundle.hashes.clone ( )
613
} else {
614
bundle.changes.iter ( ) .map ( | ( c , _) | c.hash ( ) ) .collect ( )
615
} ;
2c75672f Andy McCall 1 month ago ↶
616
let raw_hashes: Vec< ChangeHash> = bundle
617
.raw_changes
618
.iter ( )
619
.map ( | ( b , _) | hash_object ( ObjectType:: Change, b) )
620
.collect ( ) ;
621
let incoming: BTreeSet< ChangeHash> = hashes.iter ( ) .chain ( & raw_hashes) .copied ( ) .collect ( ) ;
2863456a Andy McCall 1 month ago ↶
622
let boundary = self .boundary ( ) ;
98286406 Andy McCall 1 month ago ↶
623
let mut imported = Vec :: new( ) ;
2c75672f Andy McCall 1 month ago ↶
624
625
626
for ( ( bytes, sigs) , h) in bundle.raw_changes.iter ( ) .zip ( raw_hashes) {
627
let ( skel, texts) = Change:: decode_skeleton( bytes, h) ? ;
628
for d in & skel.deps {
629
if ! self .store.has ( d) & & ! incoming.contains ( d) & & ! shallow & & ! boundary.contains ( d)
630
{
631
return fail ( format! (
632
" change {} depends on {} , which is neither stored nor in the bundle" ,
633
h.short ( 12 ) ,
634
d.short ( 12 )
635
) ) ;
636
}
637
}
638
for t in texts {
0f93f49c Andy McCall 1 month ago ↶
639
if let crate :: objects:: TextRef:: Blob( r, _ , _ ) = t {
2c75672f Andy McCall 1 month ago ↶
640
if ! self .store.has ( & r) {
641
return fail ( format! (
642
" change {} came without its text blob {} " ,
643
h.short ( 12 ) ,
644
r.short ( 12 )
645
) ) ;
646
}
647
}
648
}
649
self .store.put ( ObjectType:: Change, bytes) ? ;
650
for sig in sigs {
651
self .store.put_signature ( & h, sig) ? ;
652
}
653
imported.push ( h) ;
654
}
598009a7 Andy McCall 1 month ago ↶
655
for ( ( c, sigs) , h) in bundle.changes.iter ( ) .zip ( hashes) {
98286406 Andy McCall 1 month ago ↶
656
for d in & c.deps {
75167672 Andy McCall 1 month ago
657
if ! self .store.has ( d) & & ! incoming.contains ( d) & & ! shallow & & ! boundary.contains ( d)
658
{
659
return fail ( format! (
660
" change {} depends on {} , which is neither stored nor in the bundle" ,
661
h.short ( 12 ) ,
662
d.short ( 12 )
663
) ) ;
98286406 Andy McCall 1 month ago ↶
664
}
665
}
598009a7 Andy McCall 1 month ago ↶
666
let stored = self .store.put_change ( c) ? ;
667
if stored ! = h {
668
return fail ( format! (
669
" change {} is not the change the bundle names" ,
670
h.short ( 12 )
671
) ) ;
672
}
98286406 Andy McCall 1 month ago ↶
673
for sig in sigs {
674
self .store.put_signature ( & h, sig) ? ;
675
}
676
imported.push ( h) ;
677
}
678
if strict {
679
for h in & imported {
680
if ! matches! ( self .authenticate_change ( h) ? , SignatureStatus:: Valid { .. } ) {
75167672 Andy McCall 1 month ago
681
return fail ( format! (
682
" change {} is not authenticated by its author" ,
683
h.short ( 12 )
684
) ) ;
98286406 Andy McCall 1 month ago ↶
685
}
686
}
687
}
688
Ok ( imported)
689
}
690
691
692
693
84b9e9ac Andy McCall 1 month ago ↶
694
695
7ba155f2 Andy McCall 1 month ago ↶
696
697
698
eae59556 Andy McCall 1 month ago ↶
699
pub ( crate ) fn delegate_authorized (
700
& self ,
701
p : & crate:: policy:: Policy,
702
signer : & KeyId,
703
reference : & str ,
7ba155f2 Andy McCall 1 month ago ↶
704
at_ms : u64 ,
eae59556 Andy McCall 1 month ago ↶
705
) -> bool {
84b9e9ac Andy McCall 1 month ago ↶
706
if p.is_revoked ( signer) {
707
return false ;
708
}
eae59556 Andy McCall 1 month ago ↶
709
let Some ( rule) = p.rule_for ( reference) else {
710
return false ;
711
} ;
84b9e9ac Andy McCall 1 month ago ↶
712
rule.keys.iter ( ) .any ( | k | {
713
! p.is_revoked ( k)
714
& & p.identity ( k)
715
.cloned ( )
716
.or_else ( | | self .store.get_identity ( k) .ok ( ) )
7ba155f2 Andy McCall 1 month ago ↶
717
.is_some_and ( | id | id.delegates_to ( signer, Scope:: REFS , at_ms) )
84b9e9ac Andy McCall 1 month ago ↶
718
} )
719
}
720
e5d9b051 Andy McCall 19 days ago ↶
721
722
723
724
725
726
727
pub ( crate ) fn predecessor_authorized (
728
& self ,
729
p : & crate:: policy:: Policy,
730
signer : & KeyId,
731
reference : & str ,
732
at_ms : u64 ,
733
) -> bool {
734
if p.is_revoked ( signer) {
735
return false ;
736
}
737
let Some ( rule) = p.rule_for ( reference) else {
738
return false ;
739
} ;
740
let identity = | k : & KeyId| {
741
p.identity ( k)
742
.cloned ( )
743
.or_else ( | | self .store.get_identity ( k) .ok ( ) )
744
} ;
745
rule.keys.iter ( ) .any ( | k | {
746
if p.is_revoked ( k) {
747
return false ;
748
}
749
let mut cur = identity ( k) ;
750
for _ in 0 .. 32 {
751
let Some ( id) = cur else {
752
return false ;
753
} ;
754
match id.previous {
755
Some ( prev) if prev = = * signer => return at_ms < id.created,
756
Some ( prev) if ! p.is_revoked ( & prev) => cur = identity ( & prev) ,
757
_ => return false ,
758
}
759
}
760
false
761
} )
762
}
763
75167672 Andy McCall 1 month ago
764
fn check_ref_attest (
d36ba2f7 Andy McCall 17 days ago ↶
765
& self ,
766
sa : & SignedAttest,
767
name : & str ,
768
old_state : & ObjectRef,
769
new_state : & ObjectRef,
770
last_serial : Option< u64 > ,
771
allow_equal : bool ,
772
) -> std:: result:: Result< u64 , String> {
773
let serial =
774
self .check_ref_attest_body ( sa, name, old_state, new_state, last_serial, allow_equal) ? ;
775
self .verify_attest_signature ( sa) ? ;
776
Ok ( serial)
777
}
778
779
780
781
782
fn check_ref_attest_body (
75167672 Andy McCall 1 month ago
783
& self ,
784
sa : & SignedAttest,
785
name : & str ,
786
old_state : & ObjectRef,
787
new_state : & ObjectRef,
788
last_serial : Option< u64 > ,
789
allow_equal : bool ,
790
) -> std:: result:: Result< u64 , String> {
791
let AttestBody:: Ref {
792
name: n,
793
old_state: o,
794
new_state: nw,
795
serial,
796
} = & sa.attest.body
797
else {
98286406 Andy McCall 1 month ago ↶
798
return Err ( " attestation is not a ref attestation" .into ( ) ) ;
799
} ;
800
if n ! = name | | o ! = old_state | | nw ! = new_state {
801
return Err ( " attestation does not describe this update" .into ( ) ) ;
802
}
803
if sa.attest.repo ! = self .id ( ) .map_err ( | e | e.to_string ( ) ) ? {
804
return Err ( " attestation is for a different repository" .into ( ) ) ;
805
}
806
if let Some ( last) = last_serial {
807
if * serial < last | | ( * serial = = last & & ! allow_equal) {
75167672 Andy McCall 1 month ago
808
return Err ( format! (
809
" attestation serial {serial} is not greater than the last seen {last} "
810
) ) ;
98286406 Andy McCall 1 month ago ↶
811
}
812
}
d36ba2f7 Andy McCall 17 days ago ↶
813
Ok ( * serial)
814
}
815
816
817
818
fn verify_attest_signature ( & self , sa : & SignedAttest) -> std:: result:: Result< ( ) , String> {
98286406 Andy McCall 1 month ago ↶
819
let r = sa.attest.hash ( ) ;
820
let sig = sa.sigs.first ( ) .ok_or ( " attestation carries no signature" ) ? ;
75167672 Andy McCall 1 month ago
821
let id = self
822
.store
823
.get_identity ( & sig.key)
824
.map_err ( | _| format! ( " unknown key {} " , sig.key.short ( 12 ) ) ) ? ;
d36ba2f7 Andy McCall 17 days ago ↶
825
verify_signature ( & id, sig, Domain:: Attest, & r) .map_err ( | e | e.to_string ( ) )
98286406 Andy McCall 1 month ago ↶
826
}
827
83e0677b Andy McCall 1 month ago ↶
828
98286406 Andy McCall 1 month ago ↶
829
83e0677b Andy McCall 1 month ago ↶
830
831
832
75167672 Andy McCall 1 month ago
833
pub fn receive_push (
834
& self ,
835
bundle : Bundle,
836
updates : Vec< RefUpdate> ,
837
policy : Option< SignedPolicy> ,
838
tags : Vec< crate:: protocol:: TagRef> ,
839
) -> Result< Vec< RefResult> > {
119bbf50 Andy McCall 1 month ago ↶
840
Ok ( self
841
.receive_push_report ( bundle, updates, policy, tags) ?
842
.results )
7aa2dc93 Andy McCall 1 month ago ↶
843
}
844
845
846
847
848
pub fn receive_push_report (
849
& self ,
850
bundle : Bundle,
851
updates : Vec< RefUpdate> ,
852
policy : Option< SignedPolicy> ,
853
tags : Vec< crate:: protocol:: TagRef> ,
854
) -> Result< PushReport> {
767ac6cd Andy McCall 18 days ago
855
856
857
858
self .refresh ( ) ? ;
7aa2dc93 Andy McCall 1 month ago ↶
859
let mut report = PushReport:: default( ) ;
860
let results = & mut report.results;
83e0677b Andy McCall 1 month ago ↶
861
if let Some ( sp) = policy {
28fc23d7 Andy McCall 1 month ago ↶
862
match self .adopt_policy_chain ( & bundle.policies, & sp, " push received" ) {
83e0677b Andy McCall 1 month ago ↶
863
Ok ( ( ) ) => {
75167672 Andy McCall 1 month ago
864
results.push ( RefResult {
865
name: " policy" .into ( ) ,
866
ok: true ,
867
reason: format! ( " serial {} " , sp.policy.serial) ,
868
} ) ;
83e0677b Andy McCall 1 month ago ↶
869
}
870
Err ( e) => {
75167672 Andy McCall 1 month ago
871
results.push ( RefResult {
872
name: " policy" .into ( ) ,
873
ok: false ,
874
reason: e,
875
} ) ;
83e0677b Andy McCall 1 month ago ↶
876
for u in updates {
75167672 Andy McCall 1 month ago
877
results.push ( RefResult {
878
name: u.name,
879
ok: false ,
880
reason: " policy update was rejected" .into ( ) ,
881
} ) ;
83e0677b Andy McCall 1 month ago ↶
882
}
7aa2dc93 Andy McCall 1 month ago ↶
883
return Ok ( report) ;
83e0677b Andy McCall 1 month ago ↶
884
}
885
}
886
}
887
let policy = self .current_policy ( ) ? .map ( | ( _, sp ) | sp.policy ) ;
cb8b8082 Andy McCall 26 days ago ↶
888
889
890
let objects_only = updates.is_empty ( ) & & tags.is_empty ( ) ;
7aa2dc93 Andy McCall 1 month ago ↶
891
match self .import_bundle ( & bundle, policy.is_some ( ) ) {
cb8b8082 Andy McCall 26 days ago ↶
892
Ok ( imported) => {
893
if objects_only {
894
results.push ( RefResult {
895
name: OBJECTS_RESULT .into ( ) ,
896
ok: true ,
897
reason: format! ( " {} changes stored" , imported.len ( ) ) ,
898
} ) ;
899
}
900
report.imported = imported;
901
}
7aa2dc93 Andy McCall 1 month ago ↶
902
Err ( e) => {
cb8b8082 Andy McCall 26 days ago ↶
903
if objects_only {
904
results.push ( RefResult {
905
name: OBJECTS_RESULT .into ( ) ,
906
ok: false ,
907
reason: e.to_string ( ) ,
908
} ) ;
909
}
7aa2dc93 Andy McCall 1 month ago ↶
910
for u in updates {
911
results.push ( RefResult {
912
name: u.name,
913
ok: false ,
914
reason: e.to_string ( ) ,
915
} ) ;
916
}
917
return Ok ( report) ;
83e0677b Andy McCall 1 month ago ↶
918
}
919
}
98286406 Andy McCall 1 month ago ↶
920
let ( op_ref, op) = self .head_op ( ) ? ;
921
let mut view = op.view.clone ( ) ;
922
let mut names = Vec :: new( ) ;
923
for u in updates {
83e0677b Andy McCall 1 month ago ↶
924
let outcome = self .apply_update ( & mut view, & u, policy.as_ref ( ) ) ;
98286406 Andy McCall 1 month ago ↶
925
let ( ok, reason) = match outcome {
926
Ok ( ( ) ) => ( true , String :: new( ) ) ,
927
Err ( e) => ( false , e) ,
928
} ;
929
if ok {
930
names.push ( u.name.clone ( ) ) ;
119bbf50 Andy McCall 1 month ago ↶
931
let heads = self
932
.store
933
.get_state ( & u.new_state)
934
.map ( | s | s.heads )
935
.unwrap_or_default ( ) ;
936
report.updated.push ( RefUpdated {
937
name: u.name.clone ( ) ,
938
old_state: u.old_state,
939
new_state: u.new_state,
940
heads,
941
} ) ;
98286406 Andy McCall 1 month ago ↶
942
}
75167672 Andy McCall 1 month ago
943
results.push ( RefResult {
944
name: u.name,
945
ok,
946
reason,
947
} ) ;
98286406 Andy McCall 1 month ago ↶
948
}
132b884b Andy McCall 1 month ago ↶
949
for t in & tags {
950
let name = format! ( " tags/{} " , t.name) ;
b2ef93bb Andy McCall 1 month ago ↶
951
let new = ! view.tags.contains_key ( & t.name) ;
1ec6fdbc Andy McCall 16 days ago ↶
952
match self .adopt_tag ( & mut view, t, policy.as_ref ( ) , & mut TagCheck:: Received) {
132b884b Andy McCall 1 month ago ↶
953
Ok ( ( ) ) => {
b2ef93bb Andy McCall 1 month ago ↶
954
955
956
957
if new {
958
report.updated.push ( RefUpdated {
959
name: name.clone ( ) ,
960
old_state: ObjectRef:: ZERO ,
961
new_state: t.state,
962
heads: t.heads.clone ( ) ,
963
} ) ;
964
}
132b884b Andy McCall 1 month ago ↶
965
names.push ( name.clone ( ) ) ;
75167672 Andy McCall 1 month ago
966
results.push ( RefResult {
967
name,
968
ok: true ,
969
reason: String :: new( ) ,
970
} ) ;
132b884b Andy McCall 1 month ago ↶
971
}
75167672 Andy McCall 1 month ago
972
Err ( e) => results.push ( RefResult {
973
name,
974
ok: false ,
1ec6fdbc Andy McCall 16 days ago ↶
975
reason: e.reason,
75167672 Andy McCall 1 month ago
976
} ) ,
132b884b Andy McCall 1 month ago ↶
977
}
978
}
98286406 Andy McCall 1 month ago ↶
979
if ! names.is_empty ( ) {
75167672 Andy McCall 1 month ago
980
self .record_op (
981
& [ op_ref] ,
982
& format! ( " push received: {} " , names.join ( " " ) ) ,
983
view,
984
) ? ;
98286406 Andy McCall 1 month ago ↶
985
}
7aa2dc93 Andy McCall 1 month ago ↶
986
Ok ( report)
98286406 Andy McCall 1 month ago ↶
987
}
988
be451356 Andy McCall 1 month ago ↶
989
990
991
992
993
fn record_update_attest (
994
& self ,
995
u : & RefUpdate,
996
sa : & SignedAttest,
997
) -> std:: result:: Result< ( ) , String> {
998
let name = & u.name;
999
let last = self
1000
.latest_ref_attest ( name)
1001
.map_err ( | e | format! ( " reading the last attestation of {name:?} : {e} " ) ) ?
1002
.and_then ( | ( _, a ) | match a.attest.body {
1003
AttestBody:: Ref { serial, .. } => Some ( serial) ,
1004
_ => None ,
1005
} ) ;
1006
self .check_ref_attest ( sa, name, & u.old_state, & u.new_state, last, false ) ? ;
1007
let store = | e : & dyn std:: fmt:: Display| format! ( " storing the attestation of {name:?} : {e} " ) ;
1008
let r = self .store.put_attest ( & sa.attest) .map_err ( | e | store ( & e) ) ? ;
1009
for sig in & sa.sigs {
1010
self .store.put_signature ( & r, sig) .map_err ( | e | store ( & e) ) ? ;
f53cbe7a Andy McCall 19 days ago ↶
1011
}
1012
self .set_ref_attest ( name, & r) .map_err ( | e | store ( & e) ) ? ;
1013
1014
let certified = sa
1015
.sigs
1016
.first ( )
1017
.is_some_and ( | s | self .store.certificate_of ( & s.key) .ok ( ) .flatten ( ) .is_some ( ) ) ;
1018
if certified {
1019
self .record_acceptance ( & r) .map_err ( | e | store ( & e) ) ? ;
be451356 Andy McCall 1 month ago ↶
1020
}
f53cbe7a Andy McCall 19 days ago ↶
1021
Ok ( ( ) )
be451356 Andy McCall 1 month ago ↶
1022
}
1023
f53cbe7a Andy McCall 19 days ago ↶
1024
1025
1026
pub ( crate ) fn record_acceptance ( & self , r : & ObjectRef) -> Result< ( ) > {
1027
let Some ( acceptor) = & self .acceptor else {
1028
return Ok ( ( ) ) ;
1029
} ;
1030
let ( id, sk) = ( & acceptor.0 , & acceptor.1 ) ;
1031
let attest = Attest {
1032
repo: self .id ( ) ? ,
1033
hlc: Hlc:: now( ) ,
1034
body: AttestBody:: Accepted { attest: * r } ,
1035
} ;
1036
let sig = sk.sign ( Domain:: Attest, & id.hash ( ) , & attest.hash ( ) ) ;
1037
self .store.put_identity ( id) ? ;
1038
let a = self .store.put_attest ( & attest) ? ;
1039
self .store.put_signature ( & a, & sig) ? ;
1040
self .store.index_add_pub ( " accepted" , r, & a) ? ;
1041
Ok ( ( ) )
1042
}
1043
1044
1045
pub fn acceptance_of ( & self , r : & ObjectRef) -> Result< Option< SignedAttest> > {
1046
let Some ( a) = self .store.index_get_pub ( " accepted" , r) ? .into_iter ( ) .next ( ) else {
1047
return Ok ( None ) ;
1048
} ;
1049
Ok ( Some ( SignedAttest {
1050
attest: self .store.get_attest ( & a) ? ,
1051
sigs: self .store.signatures ( & a) ? ,
1052
} ) )
1053
}
1054
1055
1056
1057
1058
1059
pub ( crate ) fn certified_time (
1060
& self ,
1061
signer : & KeyId,
1062
sa : & SignedAttest,
1063
accepted : Option< & SignedAttest> ,
1064
) -> u64 {
1ec6fdbc Andy McCall 16 days ago ↶
1065
self .issuer_acceptance ( signer, sa, accepted)
1066
.unwrap_or ( sa.attest.hlc.wall_ms)
1067
}
1068
1069
1070
1071
pub ( crate ) fn issuer_acceptance (
1072
& self ,
1073
signer : & KeyId,
1074
sa : & SignedAttest,
1075
accepted : Option< & SignedAttest> ,
1076
) -> Option< u64 > {
1077
let acc = accepted? ;
1078
let c = self .store.certificate_of ( signer) .ok ( ) .flatten ( ) ? ;
1079
let cert = self .store.get_certificate ( & c) .ok ( ) ? ;
f53cbe7a Andy McCall 19 days ago ↶
1080
let AttestBody:: Accepted { attest } = & acc.attest.body else {
1ec6fdbc Andy McCall 16 days ago ↶
1081
return None ;
f53cbe7a Andy McCall 19 days ago ↶
1082
} ;
1ec6fdbc Andy McCall 16 days ago ↶
1083
let sig = acc.sigs.iter ( ) .find ( | s | s.key = = cert.cert.issuer ) ? ;
1084
let issuer = self .store.get_identity ( & cert.cert.issuer) .ok ( ) ? ;
1085
( * attest = = sa.attest.hash ( )
1086
& & verify_signature ( & issuer, sig, Domain:: Attest, & acc.attest.hash ( ) ) .is_ok ( ) )
1087
.then_some ( acc.attest.hlc.wall_ms)
1088
}
1089
1090
1091
1092
1093
pub ( crate ) fn keep_acceptance ( & self , r : & ObjectRef, acc : & SignedAttest) -> Result< ( ) > {
1094
let a = self .store.put_attest ( & acc.attest) ? ;
1095
for sig in & acc.sigs {
1096
self .store.put_signature ( & a, sig) ? ;
f53cbe7a Andy McCall 19 days ago ↶
1097
}
1ec6fdbc Andy McCall 16 days ago ↶
1098
self .store.index_add_pub ( " accepted" , r, & a) ? ;
1099
Ok ( ( ) )
f53cbe7a Andy McCall 19 days ago ↶
1100
}
1101
028545df Andy McCall 18 days ago ↶
1102
1103
1104
1105
1106
1107
1108
1109
1110
1111
# [ allow ( clippy::too_many_arguments ) ]
1112
pub ( crate ) fn authorize_in_time (
1113
& self ,
1114
p : & crate:: policy:: Policy,
1115
remote_name : & str ,
1116
r : & crate:: protocol:: RemoteRef,
1117
sa : & SignedAttest,
1118
signer : & KeyId,
1119
log : & super:: transparency:: LogCheck,
1120
notes : & mut Vec< String> ,
1121
) -> Result< ( ) > {
1122
use super :: transparency:: { gap_note, judge, Timed} ;
1123
let own = sa.attest.hlc.wall_ms;
1124
let at = self .certified_time ( signer, sa, r.accepted.as_ref ( ) ) ;
1125
let time = log.time_of ( & r.name) ;
1126
let check = | t_delegate : u64 , t_cert : u64 | {
1127
self .delegate_authorized ( p, signer, & r.name, t_delegate)
1128
| | self .certified_authorized ( p, signer, & r.name, Scope:: REFS , t_cert)
1129
} ;
1130
let before = if at ! = own {
1131
" the host's acceptance"
1132
} else {
1133
" the time it claims"
1134
} ;
1135
let what = format! ( " {remote_name} /{} " , r.name) ;
1136
match judge ( time.as_ref ( ) .ok ( ) .map ( | i | i.ms ( ) ) , | t | check ( t, t) , | | check ( own, at) ) {
1137
Timed:: Refused => {
1138
return fail ( format! (
1139
" {what} : attested by {} , which the policy does not authorize for this bookmark; a policy owner can grant it with `oxy policy grant`" ,
1140
signer.short ( 12 )
1141
) )
1142
}
1143
Timed:: Integrated => { }
1144
Timed:: Disagrees => notes.push ( format! (
1145
" {what} : {} 's authority had lapsed when witness {} first saw its attestation, though not at {before} ; accepted while transparency logs are new" ,
1146
signer.short ( 12 ) ,
1147
time.as_ref ( ) .map ( | i | i.witness.as_str ( ) ) .unwrap_or ( " ?" )
1148
) ) ,
1149
Timed:: Fallback if log.kept => notes.push ( format! (
1150
" {what} : {} checked at {before} , not at a witnessed time: {} " ,
1151
signer.short ( 12 ) ,
1152
time.as_ref ( ) .err ( ) .map ( String :: as_str) .unwrap_or ( " none" )
1153
) ) ,
1154
Timed:: Fallback => { }
1155
}
1156
if let Some ( n) = time.ok ( ) .and_then ( | i | gap_note ( own, i) ) {
1157
notes.push ( format! ( " {what} 's attestation {n} " ) ) ;
1158
}
1159
Ok ( ( ) )
1160
}
1161
f8c69576 Andy McCall 1 month ago ↶
1162
8c30d814 Andy McCall 1 month ago ↶
1163
1164
1165
1166
f8c69576 Andy McCall 1 month ago ↶
1167
1168
1169
fn apply_deletion (
1170
& self ,
1171
view : & mut View,
1172
u : & RefUpdate,
1173
policy : Option< & crate:: policy:: Policy> ,
1174
) -> std:: result:: Result< ( ) , String> {
1175
let Some ( current) = view.bookmarks.get ( & u.name) .copied ( ) else {
1176
return Err ( format! ( " no bookmark {:?} to delete" , u.name) ) ;
1177
} ;
1178
if current ! = u.old_state {
1179
return Err ( " stale: the remote bookmark has moved; pull first" .into ( ) ) ;
1180
}
8c30d814 Andy McCall 1 month ago ↶
1181
if ! self .is_bare ( ) & & u.name = = self .config.bookmark {
f8c69576 Andy McCall 1 month ago ↶
1182
return Err ( format! (
8c30d814 Andy McCall 1 month ago ↶
1183
" {:?} is this repository's default bookmark (checked out there) and cannot be deleted" ,
f8c69576 Andy McCall 1 month ago ↶
1184
u.name
1185
) ) ;
1186
}
1187
if let Some ( p) = policy {
1188
let Some ( sa) = & u.attestation else {
1189
return Err ( format! (
1190
" deleting {:?} requires a signed reference attestation under this repository's policy" ,
1191
u.name
1192
) ) ;
1193
} ;
1194
let signer = sa
1195
.sigs
1196
.first ( )
1197
.map ( | s | s.key )
1198
.ok_or ( " attestation carries no signature" ) ? ;
f0a517d2 Andy McCall 19 days ago ↶
1199
1200
let now = Hlc:: now( ) .wall_ms;
7ba155f2 Andy McCall 1 month ago ↶
1201
if ! p.authorizes ( & signer, & u.name)
1202
& & ! self .delegate_authorized ( p, & signer, & u.name, sa.attest.hlc.wall_ms)
f0a517d2 Andy McCall 19 days ago ↶
1203
& & ! self .certified_authorized ( p, & signer, & u.name, Scope:: REFS , now)
7ba155f2 Andy McCall 1 month ago ↶
1204
{
f8c69576 Andy McCall 1 month ago ↶
1205
return Err ( format! (
1206
" key {} may not delete {:?} under this repository's policy" ,
1207
signer.short ( 12 ) ,
1208
u.name
1209
) ) ;
1210
}
1211
}
1212
if let Some ( sa) = & u.attestation {
be451356 Andy McCall 1 month ago ↶
1213
self .record_update_attest ( u, sa) ? ;
f8c69576 Andy McCall 1 month ago ↶
1214
}
1215
view.bookmarks.remove ( & u.name) ;
1216
Ok ( ( ) )
1217
}
1218
75167672 Andy McCall 1 month ago
1219
fn apply_update (
1220
& self ,
1221
view : & mut View,
1222
u : & RefUpdate,
1223
policy : Option< & crate:: policy:: Policy> ,
1224
) -> std:: result:: Result< ( ) , String> {
83e0677b Andy McCall 1 month ago ↶
1225
if u.name = = " policy" {
75167672 Andy McCall 1 month ago
1226
return Err (
1227
" the policy reference is updated by sending a policy, not a bookmark update" .into ( ) ,
1228
) ;
83e0677b Andy McCall 1 month ago ↶
1229
}
75167672 Andy McCall 1 month ago
1230
let empty = self
1231
.store
1232
.put_state ( & StateObject:: new( vec! [ ] ) )
1233
.map_err ( | e | e.to_string ( ) ) ? ;
f8c69576 Andy McCall 1 month ago ↶
1234
if u.new_state.is_zero ( ) {
1235
return self .apply_deletion ( view, u, policy) ;
1236
}
98286406 Andy McCall 1 month ago ↶
1237
let current = view.bookmarks.get ( & u.name) .copied ( ) .unwrap_or ( empty) ;
1238
if current ! = u.old_state {
1239
return Err ( " stale: the remote bookmark has moved; pull first" .into ( ) ) ;
1240
}
75167672 Andy McCall 1 month ago
1241
let new_state = self
1242
.store
1243
.get_state ( & u.new_state)
1244
.map_err ( | _| " new state object is missing" .to_string ( ) ) ? ;
98286406 Andy McCall 1 month ago ↶
1245
for h in & new_state.heads {
1246
if ! self .store.has ( h) {
1247
return Err ( format! ( " head {} is missing" , h.short ( 12 ) ) ) ;
1248
}
1249
}
1250
if ! u.force {
75167672 Andy McCall 1 month ago
1251
let old_heads = self
1252
.store
1253
.get_state ( & current)
1254
.map_err ( | e | e.to_string ( ) ) ?
1255
.heads;
1256
let closure = self
1257
.closure_in_store ( & new_state.heads)
1258
.map_err ( | e | e.to_string ( ) ) ? ;
98286406 Andy McCall 1 month ago ↶
1259
if let Some ( h) = old_heads.iter ( ) .find ( | h | ! closure.contains ( h) ) {
75167672 Andy McCall 1 month ago
1260
return Err ( format! (
1261
" not a fast-forward: current head {} would be dropped (use --force)" ,
1262
h.short ( 12 )
1263
) ) ;
98286406 Andy McCall 1 month ago ↶
1264
}
1265
}
83e0677b Andy McCall 1 month ago ↶
1266
if let Some ( p) = policy {
1267
let Some ( sa) = & u.attestation else {
75167672 Andy McCall 1 month ago
1268
return Err ( format! (
1269
" {:?} requires a signed reference attestation under this repository's policy" ,
1270
u.name
1271
) ) ;
83e0677b Andy McCall 1 month ago ↶
1272
} ;
75167672 Andy McCall 1 month ago
1273
let signer = sa
1274
.sigs
1275
.first ( )
1276
.map ( | s | s.key )
1277
.ok_or ( " attestation carries no signature" ) ? ;
f0a517d2 Andy McCall 19 days ago ↶
1278
1279
let now = Hlc:: now( ) .wall_ms;
7ba155f2 Andy McCall 1 month ago ↶
1280
if ! p.authorizes ( & signer, & u.name)
1281
& & ! self .delegate_authorized ( p, & signer, & u.name, sa.attest.hlc.wall_ms)
f0a517d2 Andy McCall 19 days ago ↶
1282
& & ! self .certified_authorized ( p, & signer, & u.name, Scope:: REFS , now)
7ba155f2 Andy McCall 1 month ago ↶
1283
{
75167672 Andy McCall 1 month ago
1284
return Err ( format! (
1285
" key {} may not update {:?} under this repository's policy" ,
1286
signer.short ( 12 ) ,
1287
u.name
1288
) ) ;
83e0677b Andy McCall 1 month ago ↶
1289
}
75167672 Andy McCall 1 month ago
1290
let old_heads = self
1291
.store
1292
.get_state ( & current)
1293
.map_err ( | e | e.to_string ( ) ) ?
1294
.heads;
83e0677b Andy McCall 1 month ago ↶
1295
self .state_allowed ( & old_heads, & new_state.heads, p, & u.name) ? ;
1296
}
98286406 Andy McCall 1 month ago ↶
1297
if let Some ( sa) = & u.attestation {
be451356 Andy McCall 1 month ago ↶
1298
self .record_update_attest ( u, sa) ? ;
98286406 Andy McCall 1 month ago ↶
1299
}
1300
view.bookmarks.insert ( u.name.clone ( ) , u.new_state) ;
1301
Ok ( ( ) )
1302
}
1303
1304
1305
1306
fn remote_url ( & self , name : & str ) -> Result< String> {
75167672 Andy McCall 1 month ago
1307
self .config.remotes.get ( name) .cloned ( ) .ok_or_else ( | | {
42ccf504 Andy McCall 28 days ago ↶
1308
let names: Vec< & str > = self .config.remotes.keys ( ) .map ( String :: as_str) .collect ( ) ;
1309
RepoError:: Msg( match names.as_slice ( ) {
1310
[ ] => format! ( " no remote named {name:?} ; add one with `oxy remote add`" ) ,
1311
_ if name = = " origin" & & names.len ( ) > 1 & & self .config.default_remote.is_none ( ) => format! (
1312
" this repository has no remote named origin, and several others ({} ): name one (`oxy pull {} `), or make one the default with `oxy config core.remote {} `" ,
1313
names.join ( " , " ) ,
1314
names[ 0 ] ,
1315
names[ 0 ]
1316
) ,
1317
_ => format! (
1318
" no remote named {name:?} ; this repository has {} " ,
1319
names.join ( " , " )
1320
) ,
1321
} )
75167672 Andy McCall 1 month ago
1322
} )
98286406 Andy McCall 1 month ago ↶
1323
}
1324
75167672 Andy McCall 1 month ago
1325
1326
1327
05e71ed6 Andy McCall 1 month ago ↶
1328
fn check_remote_id (
1329
& self ,
1330
remote : & dyn crate:: protocol:: Remote,
1331
remote_name : & str ,
1332
allow_unbound : bool ,
1333
) -> Result< ( ) > {
75167672 Andy McCall 1 month ago
1334
let theirs = remote.repo_id ( ) ? ;
1335
if theirs = = self .id ( ) ? {
1336
return Ok ( ( ) ) ;
1337
}
1338
if theirs = = crate :: protocol:: UNBOUND_ID {
1339
if allow_unbound {
1340
return Ok ( ( ) ) ;
1341
}
05e71ed6 Andy McCall 1 month ago ↶
1342
return fail ( format! (
1343
" remote {remote_name:?} is empty and unbound: push to it first"
1344
) ) ;
75167672 Andy McCall 1 month ago
1345
}
05e71ed6 Andy McCall 1 month ago ↶
1346
fail ( format! (
3e5772cc Andy McCall 1 month ago ↶
1347
" remote {remote_name:?} is a different repository (repository IDs differ); check its URL with `oxy remote list`"
05e71ed6 Andy McCall 1 month ago ↶
1348
) )
75167672 Andy McCall 1 month ago
1349
}
1350
ff1f62fe Andy McCall 1 month ago ↶
1351
1352
1353
3e5772cc Andy McCall 1 month ago ↶
1354
pub ( crate ) fn remote_options ( & self , name : & str ) -> RemoteOptions {
ff1f62fe Andy McCall 1 month ago ↶
1355
let url = self .config.remotes.get ( name) .cloned ( ) .unwrap_or_default ( ) ;
1356
let mut options = RemoteOptions {
75167672 Andy McCall 1 month ago
1357
repo_id: self .id ( ) .ok ( ) ,
ff1f62fe Andy McCall 1 month ago ↶
1358
token: self .config.remote_tokens.get ( name) .cloned ( ) ,
1359
ca: self .config.remote_cas.get ( name) .map ( PathBuf:: from) ,
9f9e72b9 Andy McCall 1 month ago ↶
1360
cache_dir: Some ( self .oxy.join ( " remotes" ) .join ( name) .join ( " strata" ) ) ,
68a92484 Andy McCall 22 days ago ↶
1361
.. RemoteOptions:: default( )
ff1f62fe Andy McCall 1 month ago ↶
1362
} ;
1363
self .fill_credentials ( & url, & mut options) ;
1364
options
1365
}
1366
1367
1368
1369
pub fn credentials ( & self ) -> crate:: credentials:: Credentials {
1370
crate :: credentials:: Credentials:: at(
1371
self .user_config
1372
.parent ( )
1373
.map ( Path:: to_path_buf)
1374
.unwrap_or_else ( default_home) ,
1375
)
1376
}
1377
1378
1379
1380
68a92484 Andy McCall 22 days ago ↶
1381
1382
1383
1384
ff1f62fe Andy McCall 1 month ago ↶
1385
fn fill_credentials ( & self , url : & str , options : & mut RemoteOptions) {
1386
if options.token.is_some ( ) & & options.ca.is_some ( ) {
1387
return ;
1388
}
68a92484 Andy McCall 22 days ago ↶
1389
let explicit =
1390
options.token.is_some ( ) | | std:: env:: var( " OXY_TOKEN" ) .is_ok_and ( | t | ! t.is_empty ( ) ) ;
ff1f62fe Andy McCall 1 month ago ↶
1391
let stored = self .credentials ( ) .options_for ( url) ;
1392
options.token = options.token.take ( ) .or ( stored.token) ;
1393
options.ca = options.ca.take ( ) .or ( stored.ca) ;
68a92484 Andy McCall 22 days ago ↶
1394
let enclosing = self .enclosing_credentials ( url) ;
1395
if options.token.is_none ( ) {
1396
options.token = enclosing.iter ( ) .find_map ( | ( t , _) | t.clone ( ) ) ;
1397
}
1398
if options.ca.is_none ( ) {
1399
options.ca = enclosing.iter ( ) .find_map ( | ( _, c ) | c.clone ( ) ) ;
1400
}
1401
if ! explicit {
1402
for t in enclosing.into_iter ( ) .filter_map ( | ( t , _) | t ) {
1403
if options.token.as_ref ( ) ! = Some ( & t) & & ! options.fallback_tokens.contains ( & t) {
1404
options.fallback_tokens.push ( t) ;
1405
}
1406
}
2b5ee371 Andy McCall 1 month ago ↶
1407
}
68a92484 Andy McCall 22 days ago ↶
1408
}
1409
1410
1411
1412
fn enclosing_credentials ( & self , url : & str ) -> Vec< ( Option< String> , Option< PathBuf> ) > {
1413
let mut out = Vec :: new( ) ;
ff1f62fe Andy McCall 1 month ago ↶
1414
let Some ( hub) = crate :: credentials:: hub_of( url) else {
68a92484 Andy McCall 22 days ago ↶
1415
return out;
ff1f62fe Andy McCall 1 month ago ↶
1416
} ;
1417
let mut at = self .root.parent ( ) ;
1418
while let Some ( dir) = at {
1419
let Ok ( cfg) = read_config_file ( & dir.join ( OXY_DIR ) .join ( " config" ) ) else {
1420
break ;
1421
} ;
1422
for ( key, remote_url) in & cfg {
1423
let Some ( name) = key
1424
.strip_prefix ( " remote." )
1425
.and_then ( | k | k.strip_suffix ( " .url" ) )
1426
else {
1427
continue ;
1428
} ;
1429
if crate :: credentials:: hub_of( remote_url) .as_deref ( ) ! = Some ( hub.as_str ( ) ) {
1430
continue ;
1431
}
68a92484 Andy McCall 22 days ago ↶
1432
out.push ( (
1433
cfg.get ( & format! ( " remote.{name} .token" ) ) .cloned ( ) ,
1434
cfg.get ( & format! ( " remote.{name} .ca" ) ) .map ( PathBuf:: from) ,
1435
) ) ;
ff1f62fe Andy McCall 1 month ago ↶
1436
}
1437
at = dir.parent ( ) ;
1438
}
68a92484 Andy McCall 22 days ago ↶
1439
out
98286406 Andy McCall 1 month ago ↶
1440
}
1441
d82e4409 Andy McCall 1 month ago ↶
1442
1443
1444
pub fn push_seals ( & self , remote_name : & str , seals : & [ObjectRef]) -> Result< ( ) > {
1445
let remote = self .open_named_remote ( remote_name) ? ;
1446
self .check_remote_id ( remote.as_ref ( ) , remote_name, false ) ? ;
1447
let mut bundle = Bundle:: default( ) ;
1448
for r in seals {
1449
let attest = self .store.get_attest ( r) ? ;
1450
let sigs = self .store.signatures ( r) ? ;
4213c41d Andy McCall 1 month ago ↶
1451
bundle
1452
.attests
1453
.push ( crate :: protocol:: SignedAttest { attest, sigs } ) ;
d82e4409 Andy McCall 1 month ago ↶
1454
}
1455
let results = remote.push ( bundle, vec! [ ] , None , vec! [ ] ) ? ;
1456
if let Some ( r) = results.iter ( ) .find ( | r | ! r.ok) {
1457
return fail ( format! ( " {} : {} " , r.name, r.reason) ) ;
1458
}
1459
Ok ( ( ) )
1460
}
1461
1462
1463
pub fn remote_for_url ( & self , base : & str ) -> Option< String> {
1464
let base = base.trim_end_matches ( ' /' ) ;
4213c41d Andy McCall 1 month ago ↶
1465
self .config
1466
.remotes
1467
.iter ( )
1468
.find ( | ( _, url ) | url.trim_end_matches ( ' /' ) = = base )
1469
.map ( | ( name , _) | name.clone ( ) )
d82e4409 Andy McCall 1 month ago ↶
1470
}
1471
1472
ff1f62fe Andy McCall 1 month ago ↶
1473
d82e4409 Andy McCall 1 month ago ↶
1474
pub fn open_remote_at ( & self , url : & str ) -> Result< ( String, Box< dyn crate:: protocol:: Remote> ) > {
1475
if let Some ( name) = self .remote_for_url ( url) {
1476
return Ok ( ( name.clone ( ) , self .open_named_remote ( & name) ? ) ) ;
1477
}
1478
let options = RemoteOptions {
1479
repo_id: self .id ( ) .ok ( ) ,
ff1f62fe Andy McCall 1 month ago ↶
1480
.. self .credentials_for ( url)
d82e4409 Andy McCall 1 month ago ↶
1481
} ;
1482
Ok ( ( url.to_string ( ) , open_remote ( url, & options) ? ) )
1483
}
1484
1485
1486
1487
pub fn options_for_url ( & self , url : & str ) -> RemoteOptions {
1488
match self .remote_for_url ( url) {
1489
Some ( name) => self .remote_options ( & name) ,
1490
None => RemoteOptions {
1491
repo_id: self .id ( ) .ok ( ) ,
ff1f62fe Andy McCall 1 month ago ↶
1492
.. self .credentials_for ( url)
d82e4409 Andy McCall 1 month ago ↶
1493
} ,
1494
}
1495
}
1496
c8d9059e Andy McCall 11 days ago ↶
1497
pub ( crate ) fn open_named_remote ( & self , name : & str ) -> Result< Box< dyn crate:: protocol:: Remote> > {
2b5ee371 Andy McCall 1 month ago ↶
1498
open_remote ( & self .remote_url ( name) ? , & self .remote_options ( name) )
98286406 Andy McCall 1 month ago ↶
1499
}
1500
1501
fn serial_path ( & self , remote : & str , bookmark : & str ) -> PathBuf {
75167672 Andy McCall 1 month ago
1502
self .oxy
1503
.join ( " remotes" )
1504
.join ( remote)
1505
.join ( format! ( " {bookmark} .serial" ) )
98286406 Andy McCall 1 month ago ↶
1506
}
1507
1508
fn last_seen_serial ( & self , remote : & str , bookmark : & str ) -> Option< u64 > {
75167672 Andy McCall 1 month ago
1509
fs:: read_to_string( self .serial_path ( remote, bookmark) )
1510
.ok ( )
1511
.and_then ( | s | s.trim ( ) .parse ( ) .ok ( ) )
98286406 Andy McCall 1 month ago ↶
1512
}
1513
1514
fn record_serial ( & self , remote : & str , bookmark : & str , serial : u64 ) -> Result< ( ) > {
1515
let p = self .serial_path ( remote, bookmark) ;
1516
fs:: create_dir_all( p.parent ( ) .unwrap ( ) ) ? ;
1517
write_atomic ( & p, serial.to_string ( ) .as_bytes ( ) )
1518
}
1519
83e0677b Andy McCall 1 month ago ↶
1520
fn policy_serial_path ( & self , remote : & str ) -> PathBuf {
1521
self .oxy.join ( " remotes" ) .join ( remote) .join ( " policy.serial" )
1522
}
1523
1524
1525
fn remote_policy_serial ( & self , remote : & str ) -> Option< u64 > {
75167672 Andy McCall 1 month ago
1526
fs:: read_to_string( self .policy_serial_path ( remote) )
1527
.ok ( )
1528
.and_then ( | s | s.trim ( ) .parse ( ) .ok ( ) )
83e0677b Andy McCall 1 month ago ↶
1529
}
1530
1531
fn record_policy_serial ( & self , remote : & str , serial : u64 ) -> Result< ( ) > {
1532
let p = self .policy_serial_path ( remote) ;
1533
fs:: create_dir_all( p.parent ( ) .unwrap ( ) ) ? ;
1534
write_atomic ( & p, serial.to_string ( ) .as_bytes ( ) )
1535
}
1536
b3c5a59a Andy McCall 1 month ago ↶
1537
fn lazy_dir ( & self ) -> PathBuf {
1538
self .oxy.join ( " lazy" )
1539
}
1540
1541
1542
fn register_lazy ( & self , blob : & ObjectRef, remote : & str ) -> Result< ( ) > {
1543
fs:: create_dir_all( self .lazy_dir ( ) ) ? ;
1544
write_atomic ( & self .lazy_dir ( ) .join ( blob.to_hex ( ) ) , remote.as_bytes ( ) )
1545
}
1546
1547
1548
pub fn lazy_remote ( & self , blob : & ObjectRef) -> Option< String> {
75167672 Andy McCall 1 month ago
1549
fs:: read_to_string( self .lazy_dir ( ) .join ( blob.to_hex ( ) ) )
1550
.ok ( )
1551
.map ( | s | s.trim ( ) .to_string ( ) )
b3c5a59a Andy McCall 1 month ago ↶
1552
}
1553
1554
1555
pub ( crate ) fn fetch_lazy_blob ( & self , blob : & ObjectRef) -> Result< ( ) > {
1556
let Some ( remote_name) = self .lazy_remote ( blob) else {
1557
return Err ( RepoError:: Store( StoreError:: NotFound( * blob) ) ) ;
1558
} ;
1559
let remote = self .open_named_remote ( & remote_name) ? ;
1560
let objects = remote.objects ( & [ * blob] ) ? ;
1561
for ( ty, body) in objects {
1562
if matches! ( ty, ObjectType:: Blob | ObjectType:: Chunk) {
1563
self .store.put ( ty, & body) ? ;
1564
}
1565
}
1566
if ! self .store.has ( blob) {
75167672 Andy McCall 1 month ago
1567
return fail ( format! (
1568
" {remote_name} did not send blob {} " ,
1569
blob.short ( 12 )
1570
) ) ;
b3c5a59a Andy McCall 1 month ago ↶
1571
}
1572
let _ = fs:: remove_file( self .lazy_dir ( ) .join ( blob.to_hex ( ) ) ) ;
1573
Ok ( ( ) )
1574
}
1575
1576
1577
1578
fn register_missing_blobs ( & self , changes : & [ChangeHash], remote : & str ) -> Result< usize > {
1579
let mut n = 0 ;
1580
for h in changes {
1581
let c = self .store.get_change ( h) ? ;
1582
for e in & c.edits {
1583
if let Edit:: Replace { old, new, .. } = e {
1584
for b in [ old, new] .into_iter ( ) .flatten ( ) {
1585
if ! self .store.has ( b) {
1586
self .register_lazy ( b, remote) ? ;
1587
n + = 1 ;
1588
}
1589
}
1590
}
1591
}
1592
}
1593
Ok ( n)
1594
}
1595
98286406 Andy McCall 1 month ago ↶
1596
d82e4409 Andy McCall 1 month ago ↶
1597
pub fn known_heads ( & self , view : & View) -> Result< Vec< ChangeHash> > {
98286406 Andy McCall 1 month ago ↶
1598
let mut have: BTreeSet< ChangeHash> = BTreeSet:: new( ) ;
75167672 Andy McCall 1 month ago
1599
for st in view
1600
.bookmarks
1601
.values ( )
1602
.chain ( view.remotes.values ( ) .flat_map ( | b | b.values ( ) ) )
1603
{
98286406 Andy McCall 1 month ago ↶
1604
if let Ok ( s) = self .store.get_state ( st) {
1605
have.extend ( s.heads) ;
1606
}
1607
}
1608
have.extend ( view.workspaces.values ( ) .copied ( ) ) ;
1609
Ok ( have.into_iter ( ) .collect ( ) )
1610
}
1611
1612
83e0677b Andy McCall 1 month ago ↶
1613
pub fn fetch ( & self , remote_name : & str ) -> Result< FetchReport> {
98286406 Andy McCall 1 month ago ↶
1614
let remote = self .open_named_remote ( remote_name) ? ;
75167672 Andy McCall 1 month ago
1615
self .check_remote_id ( remote.as_ref ( ) , remote_name, false ) ? ;
83e0677b Andy McCall 1 month ago ↶
1616
let resp = remote.refs ( ) ? ;
4b9d0677 Andy McCall 18 days ago ↶
1617
028545df Andy McCall 18 days ago ↶
1618
let log = self .check_log (
4b9d0677 Andy McCall 18 days ago ↶
1619
& self .remote_url ( remote_name) ? ,
1620
self .config.remote_cas.get ( remote_name) .map ( Path:: new) ,
1621
& resp,
1622
) ? ;
028545df Andy McCall 18 days ago ↶
1623
let mut log_notes = log.notes.clone ( ) ;
83e0677b Andy McCall 1 month ago ↶
1624
1625
1626
1627
1628
1629
let local_policy = self .current_policy ( ) ? .map ( | ( _, sp ) | sp.policy ) ;
1630
let seen = self .remote_policy_serial ( remote_name) ;
1631
let mut unverified = false ;
1632
match & resp.policy {
1633
Some ( sp) => {
1634
if seen.is_some_and ( | s | sp.policy.serial < s ) {
1635
return fail ( format! ( " {remote_name} presents policy serial {} but presented {} before: refusing the downgrade" , sp.policy.serial, seen.unwrap ( ) ) ) ;
1636
}
1637
match & local_policy {
1638
Some ( l) if sp.policy.serial < l.serial => { }
1639
Some ( l) if sp.policy.serial = = l.serial => {
1640
if sp.policy.hash ( ) ! = l.hash ( ) {
75167672 Andy McCall 1 month ago
1641
return fail ( format! (
1642
" {remote_name} presents a different policy with the same serial {} " ,
1643
l.serial
1644
) ) ;
83e0677b Andy McCall 1 month ago ↶
1645
}
1646
}
28fc23d7 Andy McCall 1 month ago ↶
1647
_ => {
75167672 Andy McCall 1 month ago
1648
self .adopt_policy_chain (
1649
& resp.history,
1650
sp,
1651
& format! ( " oxy fetch {remote_name} " ) ,
1652
)
1653
.map_err ( | e | RepoError:: Msg( format! ( " policy from {remote_name} : {e} " ) ) ) ? ;
83e0677b Andy McCall 1 month ago ↶
1654
}
1655
}
1656
self .record_policy_serial ( remote_name, sp.policy.serial) ? ;
1657
}
1658
None => {
1659
if seen.is_some ( ) {
1660
return fail ( format! ( " {remote_name} presented a policy before but has none now: refusing the downgrade" ) ) ;
1661
}
1662
unverified = true ;
1663
}
1664
}
75167672 Andy McCall 1 month ago
1665
let policy = if unverified {
1666
None
1667
} else {
1668
self .current_policy ( ) ? .map ( | ( _, sp ) | sp.policy )
1669
} ;
98286406 Andy McCall 1 month ago ↶
1670
let ( op_ref, op) = self .head_op ( ) ? ;
1671
let mut view = op.view.clone ( ) ;
1672
let have = self .known_heads ( & view) ? ;
1673
let mut report = Vec :: new( ) ;
d36ba2f7 Andy McCall 17 days ago ↶
1674
let mut skipped = Vec :: new( ) ;
b3c5a59a Andy McCall 1 month ago ↶
1675
let max_blob = self .config.max_blob;
83e0677b Andy McCall 1 month ago ↶
1676
for r in resp.refs {
091fef80 Andy McCall 1 month ago ↶
1677
let needed = {
1678
let _t = crate :: timing:: phase( " fetch: negotiate" ) ;
1679
remote.negotiate ( & have, & r.heads) ?
1680
} ;
1681
let bundle = {
1682
let _t = crate :: timing:: phase( " fetch: bundle" ) ;
1683
remote.fetch ( & needed, max_blob) ?
1684
} ;
83e0677b Andy McCall 1 month ago ↶
1685
1686
1687
091fef80 Andy McCall 1 month ago ↶
1688
let imported = {
1689
let _t = crate :: timing:: phase( " fetch: import" ) ;
1690
self .import_bundle ( & bundle, false ) ?
1691
} ;
b3c5a59a Andy McCall 1 month ago ↶
1692
if max_blob.is_some ( ) {
1693
self .register_missing_blobs ( & imported, remote_name) ? ;
1694
}
98286406 Andy McCall 1 month ago ↶
1695
for h in & r.heads {
1696
if ! self .store.has ( h) {
1697
return fail ( format! ( " remote did not send head {} " , h.short ( 12 ) ) ) ;
1698
}
1699
}
1700
let state = self .store.put_state ( & StateObject:: new( r.heads.clone ( ) ) ) ? ;
1701
if state ! = r.state {
75167672 Andy McCall 1 month ago
1702
return fail ( format! (
1703
" remote state {} does not match its heads" ,
1704
r.state.short ( 12 )
1705
) ) ;
98286406 Andy McCall 1 month ago ↶
1706
}
83e0677b Andy McCall 1 month ago ↶
1707
if let Some ( p) = & policy {
1708
let Some ( sa) = & r.attestation else {
75167672 Andy McCall 1 month ago
1709
return fail ( format! (
1710
" {remote_name} /{} has no attestation, which its policy requires" ,
1711
r.name
1712
) ) ;
83e0677b Andy McCall 1 month ago ↶
1713
} ;
75167672 Andy McCall 1 month ago
1714
let signer = sa
1715
.sigs
1716
.first ( )
1717
.map ( | s | s.key )
1718
.ok_or_else ( | | RepoError:: Msg( " attestation carries no signature" .into ( ) ) ) ? ;
028545df Andy McCall 18 days ago ↶
1719
if ! p.authorizes ( & signer, & r.name) {
1720
self .authorize_in_time ( p, remote_name, & r, sa, & signer, & log, & mut log_notes) ? ;
83e0677b Andy McCall 1 month ago ↶
1721
}
1722
}
98286406 Andy McCall 1 month ago ↶
1723
if let Some ( sa) = & r.attestation {
75167672 Andy McCall 1 month ago
1724
let AttestBody:: Ref {
1725
old_state,
1726
new_state,
1727
..
1728
} = & sa.attest.body
1729
else {
98286406 Andy McCall 1 month ago ↶
1730
return fail ( " remote sent a non-ref attestation for a bookmark" ) ;
1731
} ;
1732
let ( old_state, new_state) = ( * old_state, * new_state) ;
1733
let serial = self
d36ba2f7 Andy McCall 17 days ago ↶
1734
.check_ref_attest_body (
75167672 Andy McCall 1 month ago
1735
sa,
1736
& r.name,
1737
& old_state,
1738
& new_state,
1739
self .last_seen_serial ( remote_name, & r.name) ,
1740
true ,
1741
)
1742
.map_err ( | e | {
1743
RepoError:: Msg( format! ( " attestation for {} /{} : {e} " , remote_name, r.name) )
1744
} ) ? ;
98286406 Andy McCall 1 month ago ↶
1745
if new_state ! = r.state {
75167672 Andy McCall 1 month ago
1746
return fail ( format! (
1747
" attestation for {} /{} does not cover its current state" ,
1748
remote_name, r.name
1749
) ) ;
98286406 Andy McCall 1 month ago ↶
1750
}
d36ba2f7 Andy McCall 17 days ago ↶
1751
1752
1753
1754
1755
1756
1757
if let Err ( e) = self .verify_attest_signature ( sa) {
1758
let why = format! ( " attestation for {remote_name} /{} : {e} " , r.name) ;
1759
if r.name = = self .config.bookmark {
1760
return fail ( why) ;
1761
}
1762
skipped.push ( ( r.name, why) ) ;
1763
continue ;
1764
}
98286406 Andy McCall 1 month ago ↶
1765
let ar = self .store.put_attest ( & sa.attest) ? ;
1766
for sig in & sa.sigs {
1767
self .store.put_signature ( & ar, sig) ? ;
1768
}
1769
self .record_serial ( remote_name, & r.name, serial) ? ;
1770
}
75167672 Andy McCall 1 month ago
1771
view.remotes
1772
.entry ( remote_name.to_string ( ) )
1773
.or_default ( )
1774
.insert ( r.name.clone ( ) , state) ;
98286406 Andy McCall 1 month ago ↶
1775
report.push ( ( r.name, r.heads, imported.len ( ) ) ) ;
1776
}
132b884b Andy McCall 1 month ago ↶
1777
let mut new_tags = 0 ;
1778
for t in & resp.tags {
1779
if view.tags.contains_key ( & t.name) {
1780
continue ;
1781
}
1782
75167672 Andy McCall 1 month ago
1783
let missing: Vec< ChangeHash> = t
1784
.heads
1785
.iter ( )
1786
.filter ( | h | ! self .store.has ( h) )
1787
.copied ( )
1788
.collect ( ) ;
132b884b Andy McCall 1 month ago ↶
1789
if ! missing.is_empty ( ) {
1790
let needed = remote.negotiate ( & self .known_heads ( & view) ? , & missing) ? ;
1791
let bundle = remote.fetch ( & needed, max_blob) ? ;
1792
self .import_bundle ( & bundle, false ) ? ;
1793
}
1794
self .store.put_state ( & StateObject:: new( t.heads.clone ( ) ) ) ? ;
1ec6fdbc Andy McCall 16 days ago ↶
1795
let mut check = TagCheck:: Fetched {
1796
remote: remote_name,
1797
log: & log,
1798
notes: & mut log_notes,
1799
} ;
1800
match self .adopt_tag ( & mut view, t, policy.as_ref ( ) , & mut check) {
1801
Ok ( ( ) ) => new_tags + = 1 ,
1802
1803
1804
Err ( e) if e.untimed => {
1805
skipped.push ( ( format! ( " tags/{} " , t.name) , e.reason) ) ;
1806
}
1807
Err ( e) => return fail ( format! ( " {remote_name} {} : {} " , t.name, e.reason) ) ,
1808
}
132b884b Andy McCall 1 month ago ↶
1809
}
98286406 Andy McCall 1 month ago ↶
1810
if view ! = op.view {
1811
self .record_op ( & [ op_ref] , & format! ( " oxy fetch {remote_name} " ) , view) ? ;
1812
}
6d3eefbc Andy McCall 1 month ago ↶
1813
let _ = self .run_hook (
1814
" post-fetch" ,
1815
& format! (
1816
" {{ \" event\" :\" post-fetch\" ,\" remote\" :{} ,\" bookmarks\" :{} }} " ,
1817
json_str ( remote_name) ,
75167672 Andy McCall 1 month ago
1818
json_array ( report.iter ( ) .map ( | ( n , heads , _) | format! (
1819
" {{ \" name\" :{} ,\" heads\" :{} }} " ,
1820
json_str ( n) ,
1821
json_array ( heads.iter ( ) .map ( | h | json_str ( & h.to_hex ( ) ) ) )
1822
) ) )
6d3eefbc Andy McCall 1 month ago ↶
1823
) ,
1824
) ;
75167672 Andy McCall 1 month ago
1825
Ok ( FetchReport {
1826
refs: report,
1827
unverified,
1828
new_tags,
4b9d0677 Andy McCall 18 days ago ↶
1829
log_notes,
d36ba2f7 Andy McCall 17 days ago ↶
1830
skipped,
75167672 Andy McCall 1 month ago
1831
} )
98286406 Andy McCall 1 month ago ↶
1832
}
1833
2863456a Andy McCall 1 month ago ↶
1834
1835
1836
pub fn fetch_shallow ( & self , remote_name : & str , depth : u32 ) -> Result< usize > {
1837
let remote = self .open_named_remote ( remote_name) ? ;
75167672 Andy McCall 1 month ago
1838
self .check_remote_id ( remote.as_ref ( ) , remote_name, false ) ? ;
2863456a Andy McCall 1 month ago ↶
1839
let resp = remote.refs ( ) ? ;
1840
let bookmark = self .config.bookmark.clone ( ) ;
1841
if let Some ( sp) = & resp.policy {
75167672 Andy McCall 1 month ago
1842
self .adopt_policy_chain ( & resp.history, sp, " oxy clone --depth" )
1843
.map_err ( | e | RepoError:: Msg( format! ( " policy from {remote_name} : {e} " ) ) ) ? ;
2863456a Andy McCall 1 month ago ↶
1844
self .record_policy_serial ( remote_name, sp.policy.serial) ? ;
1845
}
1846
let Some ( r) = resp.refs.into_iter ( ) .find ( | r | r.name = = bookmark ) else {
1847
return fail ( format! ( " {remote_name} has no bookmark {bookmark:?} " ) ) ;
1848
} ;
1849
if r.heads.is_empty ( ) {
1850
return Ok ( 0 ) ;
1851
}
1852
1853
let cp_bundle = remote.checkpoint ( & r.heads) ? ;
7bd805ff Andy McCall 11 days ago ↶
1854
1855
1856
1857
let objects: Vec< ( ObjectType, & [u8 ]) > = cp_bundle
1858
.objects
1859
.iter ( )
1860
.map ( | ( ty , body ) | ( * ty, body.as_slice ( ) ) )
1861
.collect ( ) ;
1862
let batch = self .store.begin_batch ( ) ? ;
1863
let stored = self .store.put_many ( & objects) ;
1864
batch.finish ( ) ? ;
1865
let cp_ref = objects
1866
.iter ( )
1867
.zip ( stored? )
1868
.find ( | ( (ty , _ ) , _) | * ty = = ObjectType:: Checkpoint)
1869
.map ( | ( _, r ) | r ) ;
75167672 Andy McCall 1 month ago
1870
let Some ( cp_ref) = cp_ref else {
1871
return fail ( format! ( " {remote_name} sent no checkpoint" ) ) ;
1872
} ;
2863456a Andy McCall 1 month ago ↶
1873
self .install_checkpoint ( & bookmark, & cp_ref) ? ;
7bd805ff Andy McCall 11 days ago ↶
1874
1875
1876
1877
let cp = crate :: objects:: Checkpoint:: decode(
1878
& self .store.get_typed ( & cp_ref, ObjectType:: Checkpoint) ? ,
1879
) ? ;
1880
let base = State:: from_checkpoint_history( & self .read_blob ( & cp.payload) ? ) ? ;
1881
let mut missing: Vec< ObjectRef> = base
1882
.opaque_nodes ( )
1883
.iter ( )
1884
.flat_map ( | n | base.live_blobs ( n) )
1885
.filter ( | b | ! self .store.has ( b) )
1886
.collect ( ) ;
1887
missing.sort ( ) ;
1888
missing.dedup ( ) ;
1889
if self .config.max_blob.is_some ( ) {
1890
for b in & missing {
1891
self .register_lazy ( b, remote_name) ? ;
1892
}
1893
} else {
1894
for part in missing.chunks ( 512 ) {
1895
let objects = remote.objects ( part) ? ;
1896
let objects: Vec< ( ObjectType, & [u8 ]) > = objects
1897
.iter ( )
1898
.filter ( | ( ty , _) | matches! ( ty, ObjectType:: Blob | ObjectType:: Chunk) )
1899
.map ( | ( ty , body ) | ( * ty, body.as_slice ( ) ) )
1900
.collect ( ) ;
1901
let batch = self .store.begin_batch ( ) ? ;
1902
let stored = self .store.put_many ( & objects) ;
1903
batch.finish ( ) ? ;
1904
stored? ;
1905
}
1906
if let Some ( b) = missing.iter ( ) .find ( | b | ! self .store.has ( b) ) {
1907
return fail ( format! ( " {remote_name} did not send blob {} " , b.short ( 12 ) ) ) ;
1908
}
1909
}
2863456a Andy McCall 1 month ago ↶
1910
1911
let wanted = remote.shallow ( & r.heads, depth) ? ;
1912
let bundle = remote.fetch ( & wanted, self .config.max_blob) ? ;
1913
let imported = self .import_bundle_shallow ( & bundle, false ) ? ;
1914
if self .config.max_blob.is_some ( ) {
1915
self .register_missing_blobs ( & imported, remote_name) ? ;
1916
}
1917
self .refresh_boundary ( & imported) ? ;
1918
if let Some ( sa) = & r.attestation {
1919
let ar = self .store.put_attest ( & sa.attest) ? ;
1920
for sig in & sa.sigs {
1921
self .store.put_signature ( & ar, sig) ? ;
1922
}
1923
if let AttestBody:: Ref { serial, .. } = sa.attest.body {
1924
self .record_serial ( remote_name, & r.name, serial) ? ;
1925
}
1926
}
1927
let state = self .store.put_state ( & StateObject:: new( r.heads.clone ( ) ) ) ? ;
1928
let ( op_ref, op) = self .head_op ( ) ? ;
1929
let mut view = op.view.clone ( ) ;
75167672 Andy McCall 1 month ago
1930
view.remotes
1931
.entry ( remote_name.to_string ( ) )
1932
.or_default ( )
1933
.insert ( r.name.clone ( ) , state) ;
1934
self .record_op (
1935
& [ op_ref] ,
1936
& format! ( " oxy fetch {remote_name} --depth {depth} " ) ,
1937
view,
1938
) ? ;
2863456a Andy McCall 1 month ago ↶
1939
Ok ( imported.len ( ) )
1940
}
1941
98286406 Andy McCall 1 month ago ↶
1942
1943
1944
pub fn pull ( & self , remote_name : & str ) -> Result< PullReport> {
6caacfff Andy McCall 1 month ago ↶
1945
let _wc = self .lock_working_copy ( ) ? ;
d36ba2f7 Andy McCall 17 days ago ↶
1946
let skipped = self .fetch ( remote_name) ? .skipped;
98286406 Andy McCall 1 month ago ↶
1947
let ( op_ref, op) = self .head_op ( ) ? ;
14edbaaf Andy McCall 1 month ago ↶
1948
let current = self .config.bookmark.clone ( ) ;
1949
let mut local_current = self .heads_of ( & op.view, & current) ? ;
1950
local_current.sort ( ) ;
1951
let mut view = op.view.clone ( ) ;
1952
let mut current_heads = local_current.clone ( ) ;
1953
let mut changed = false ;
1954
let mut others = Vec :: new( ) ;
1955
let tracked = op
75167672 Andy McCall 1 month ago
1956
.view
1957
.remotes
1958
.get ( remote_name)
14edbaaf Andy McCall 1 month ago ↶
1959
.cloned ( )
1960
.unwrap_or_default ( ) ;
1961
for ( name, remote_state) in tracked {
1962
1963
1964
let local_state = op.view.bookmarks.get ( & name) .copied ( ) ;
1965
if local_state.is_none ( ) & & name ! = current {
1966
continue ;
1967
}
1968
if local_state = = Some ( remote_state) {
1969
continue ;
1970
}
1971
let local = self .heads_of ( & op.view, & name) ? ;
1972
let remote_heads = self .store.get_state ( & remote_state) ? .heads;
1973
if remote_heads.iter ( ) .all ( | h | local.contains ( h) ) {
1974
continue ;
1975
}
1976
let mut all = local.clone ( ) ;
1977
all.extend ( remote_heads) ;
1978
let st = self .load_state_history ( & all) ? ;
1979
let mut heads = st.maximal ( & all) ;
1980
heads.sort ( ) ;
1981
let mut sorted_local = local;
1982
sorted_local.sort ( ) ;
1983
if heads = = sorted_local {
1984
continue ;
1985
}
1986
view.bookmarks.insert (
1987
name.clone ( ) ,
1988
self .store.put_state ( & StateObject:: new( heads.clone ( ) ) ) ? ,
1989
) ;
1990
if name = = current {
1991
changed = true ;
1992
current_heads = heads;
1993
} else {
1994
others.push ( name) ;
1995
}
1996
}
f6dccc45 Andy McCall 27 days ago ↶
1997
if changed | | ! others.is_empty ( ) {
1998
self .record_op ( & [ op_ref] , & format! ( " oxy pull {remote_name} " ) , view) ? ;
98286406 Andy McCall 1 month ago ↶
1999
}
f6dccc45 Andy McCall 27 days ago ↶
2000
2001
2002
2003
let checked_out = self .follow_bookmark ( & current_heads, & current, " oxy pull" ) ? ;
75167672 Andy McCall 1 month ago
2004
Ok ( PullReport {
f6dccc45 Andy McCall 27 days ago ↶
2005
heads: if changed {
2006
current_heads
2007
} else {
2008
local_current
2009
} ,
14edbaaf Andy McCall 1 month ago ↶
2010
changed,
75167672 Andy McCall 1 month ago
2011
checked_out,
14edbaaf Andy McCall 1 month ago ↶
2012
others,
d36ba2f7 Andy McCall 17 days ago ↶
2013
skipped,
75167672 Andy McCall 1 month ago
2014
} )
f6dccc45 Andy McCall 27 days ago ↶
2015
}
2016
2017
2018
2019
2020
2021
2022
pub fn working_copy_behind ( & self ) -> Result< Option< usize > > {
2023
let ( _ , wc) = self .working_copy ( ) ? ;
2024
let mut base = wc.deps.clone ( ) ;
2025
base.sort ( ) ;
2026
let mut heads = self .bookmark_heads ( ) ? ;
2027
heads.sort ( ) ;
2028
if base = = heads | | heads.is_empty ( ) {
2029
return Ok ( None ) ;
2030
}
2031
let state = self .load_state_history ( & heads) ? ;
2032
if ! base.iter ( ) .all ( | h | state.contains ( h) ) {
2033
return Ok ( None ) ;
2034
}
2035
let had = if base.is_empty ( ) {
2036
0
2037
} else {
2038
self .load_state_history ( & base) ? .len ( )
2039
} ;
2040
Ok ( Some ( state.len ( ) .saturating_sub ( had) ) .filter ( | n | * n > 0 ) )
2041
}
2042
2043
2044
2045
2046
2047
2048
2049
2050
2051
2052
pub fn follow_bookmark (
2053
& self ,
2054
heads : & [ChangeHash],
2055
bookmark : & str ,
2056
command : & str ,
2057
) -> Result< bool > {
2058
let snap = self .snapshot ( command) ? ;
2059
let clean = snap.wc.tree_ops.is_empty ( ) & & snap.wc.edits.is_empty ( ) ;
2060
let mut base = snap.base.maximal ( & snap.wc.deps) ;
2061
base.sort ( ) ;
2062
let mut target = heads.to_vec ( ) ;
2063
target.sort ( ) ;
2064
if base = = target {
2065
return Ok ( false ) ;
2066
}
2067
let state = self .load_state_history ( heads) ? ;
2068
if ! base.iter ( ) .all ( | h | state.contains ( h) ) {
2069
2070
return Ok ( false ) ;
2071
}
2072
if clean {
2073
self .checkout ( heads, false , & format! ( " {command} (checkout)" ) ) ? ;
2074
Ok ( true )
2075
} else {
2076
Ok ( self
2077
.checkout_carry ( heads, bookmark, & format! ( " {command} (checkout --carry)" ) )
2078
.is_ok ( ) )
2079
}
98286406 Andy McCall 1 month ago ↶
2080
}
2081
2082
2083
f8c69576 Andy McCall 1 month ago ↶
2084
2085
2086
2087
pub fn push_delete ( & self , remote_name : & str , bookmark : & str ) -> Result< Vec< RefResult> > {
2088
let remote = self .open_named_remote ( remote_name) ? ;
2089
self .check_remote_id ( remote.as_ref ( ) , remote_name, true ) ? ;
2090
let resp = remote.refs ( ) ? ;
2091
let Some ( r) = resp.refs.iter ( ) .find ( | r | r.name = = bookmark ) else {
2092
return fail ( format! ( " {remote_name} has no bookmark {bookmark} " ) ) ;
2093
} ;
2094
if resp.policy.is_some ( ) & & self .secret_key ( ) ? .is_none ( ) {
2095
return fail ( format! ( " {remote_name} enforces a trust policy; deleting needs an identity (`oxy identity create`)" ) ) ;
2096
}
2097
let attestation = match self .secret_key ( ) ? {
2098
Some ( _ ) => Some ( self .sign_attest ( & Attest {
2099
repo: self .id ( ) ? ,
2100
hlc: Hlc:: now( ) ,
2101
body: AttestBody:: Ref {
2102
name: bookmark.to_string ( ) ,
2103
old_state: r.state,
2104
new_state: ObjectRef:: ZERO ,
2105
serial: r.last_serial.unwrap_or ( 0 ) + 1 ,
2106
} ,
2107
} ) ? ) ,
2108
None => None ,
2109
} ;
2110
let results = remote.push (
2111
Bundle:: default( ) ,
2112
vec! [ RefUpdate {
2113
name: bookmark.to_string ( ) ,
2114
old_state: r.state,
2115
new_state: ObjectRef:: ZERO ,
2116
force: true ,
2117
attestation,
2118
} ] ,
2119
None ,
2120
vec! [ ] ,
2121
) ? ;
2122
if results.iter ( ) .any ( | x | x.ok & & x.name = = bookmark ) {
2123
let ( op_ref, op) = self .head_op ( ) ? ;
2124
let mut view = op.view.clone ( ) ;
2125
if let Some ( m) = view.remotes.get_mut ( remote_name) {
2126
m.remove ( bookmark) ;
2127
}
2128
self .record_op (
2129
& [ op_ref] ,
2130
& format! ( " oxy push {remote_name} --delete {bookmark} " ) ,
2131
view,
2132
) ? ;
2133
}
2134
Ok ( results)
2135
}
2136
34fad4a9 Andy McCall 26 days ago ↶
2137
2138
2139
2140
2141
pub fn remove_remote ( & mut self , name : & str ) -> Result< ( ) > {
2142
if ! self .config.remotes.contains_key ( name) {
2143
return fail ( format! ( " no remote {name} : `oxy remote list` shows them" ) ) ;
2144
}
2145
let prefix = format! ( " remote.{name} ." ) ;
2146
let keys: Vec< String> = self
2147
.config
2148
.repo_layer ( )
2149
.keys ( )
2150
.filter ( | k | k.starts_with ( & prefix) )
2151
.cloned ( )
2152
.collect ( ) ;
2153
for k in keys {
2154
self .config.set ( & k, " " ) ? ;
2155
}
2156
self .config.remotes.remove ( name) ;
2157
self .save_config ( ) ? ;
2158
let ( op_ref, op) = self .head_op ( ) ? ;
2159
if op.view.remotes.contains_key ( name) {
2160
let mut view = op.view.clone ( ) ;
2161
view.remotes.remove ( name) ;
2162
self .record_op ( & [ op_ref] , & format! ( " oxy remote remove {name} " ) , view) ? ;
2163
}
2164
let mirror = self .oxy.join ( " remotes" ) .join ( name) ;
2165
if mirror.is_dir ( ) {
2166
fs:: remove_dir_all( & mirror) ? ;
2167
}
2168
Ok ( ( ) )
2169
}
2170
d3b27090 Andy McCall 12 days ago ↶
2171
2172
2173
2174
2175
2176
2177
2178
fn send_objects_ahead (
2179
& self ,
2180
remote : & dyn crate:: protocol:: Remote,
2181
remote_name : & str ,
2182
mut bundle : Bundle,
2183
progress : crate:: store:: Progress,
2184
) -> Result< Bundle> {
2185
let limit = self .config.push_batch_bytes;
2186
let changes: u64 = bundle
2187
.changes
2188
.iter ( )
2189
.map ( | ( c , _) | c.encode ( ) .len ( ) as u64 )
2190
.sum ( ) ;
2191
let objects: u64 = bundle.objects.iter ( ) .map ( | ( _, b ) | b.len ( ) as u64 ) .sum ( ) ;
2192
if changes + objects < = limit {
2193
return Ok ( bundle) ;
2194
}
2195
let ( mut kept, mut parts, mut part, mut bytes) = ( Vec :: new( ) , Vec :: new( ) , Vec :: new( ) , 0 u64 ) ;
2196
for ( ty, body) in std:: mem:: take( & mut bundle.objects) {
2197
if ! matches! ( ty, ObjectType:: Blob | ObjectType:: Chunk) {
2198
kept.push ( ( ty, body) ) ;
2199
continue ;
2200
}
2201
if ! part.is_empty ( ) & & bytes + body.len ( ) as u64 > limit {
2202
parts.push ( std:: mem:: take( & mut part) ) ;
2203
bytes = 0 ;
2204
}
2205
bytes + = body.len ( ) as u64 ;
2206
part.push ( ( ty, body) ) ;
2207
}
2208
if ! part.is_empty ( ) {
2209
parts.push ( part) ;
2210
}
2211
let n = parts.len ( ) ;
2212
for ( i, objects) in parts.into_iter ( ) .enumerate ( ) {
2213
progress ( & format! (
2214
" objects {} of {n} : {} blobs and chunks" ,
2215
i + 1 ,
2216
objects.len ( )
2217
) ) ;
2218
let results = remote.push (
2219
Bundle {
2220
objects,
2221
.. Default :: default( )
2222
} ,
2223
vec! [ ] ,
2224
None ,
2225
vec! [ ] ,
2226
) ? ;
2227
match results.iter ( ) .find ( | r | r.name = = OBJECTS_RESULT ) {
2228
Some ( r) if r.ok => { }
2229
Some ( r) => {
2230
return fail ( format! (
2231
" {remote_name} refused objects part {} of {n} : {} " ,
2232
i + 1 ,
2233
r.reason
2234
) )
2235
}
2236
None => {
2237
return fail ( format! (
2238
" {remote_name} does not take a push in parts, and this one is too large for one: update the server's oxy"
2239
) )
2240
}
2241
}
2242
}
2243
bundle.objects = kept;
2244
Ok ( bundle)
2245
}
2246
cb8b8082 Andy McCall 26 days ago ↶
2247
2248
2249
2250
fn push_batches ( & self , changes : & [ChangeHash]) -> Result< Vec< Vec< ChangeHash> > > {
2251
let blob_len = | r : & ObjectRef| -> u64 {
2252
self .store
2253
.get_typed ( r, ObjectType:: Blob)
2254
.ok ( )
2255
.and_then ( | b | Blob:: decode( & b) .ok ( ) )
2256
.map_or ( 0 , | b | b.length )
2257
} ;
2258
let ( mut out, mut batch, mut bytes) = ( Vec :: new( ) , Vec :: new( ) , 0 u64 ) ;
2259
for h in changes {
2260
let raw = self .store.get_typed ( h, ObjectType:: Change) ? ;
2261
let ( c, texts) = Change:: decode_skeleton( & raw, * h) ? ;
2262
let mut weight = raw.len ( ) as u64 ;
2263
for t in & texts {
2264
if let crate :: objects:: TextRef:: Blob( r, _ , _ ) = t {
2265
weight + = blob_len ( r) ;
2266
}
2267
}
2268
for e in & c.edits {
2269
if let Edit:: Replace { new: Some ( b) , .. } = e {
2270
weight + = blob_len ( b) ;
2271
}
2272
}
2273
if ! batch.is_empty ( ) & & bytes + weight > self .config.push_batch_bytes {
2274
out.push ( std:: mem:: take( & mut batch) ) ;
2275
bytes = 0 ;
2276
}
2277
batch.push ( * h) ;
2278
bytes + = weight;
2279
}
2280
out.push ( batch) ;
2281
Ok ( out)
2282
}
2283
98286406 Andy McCall 1 month ago ↶
2284
pub fn push ( & self , remote_name : & str , force : bool ) -> Result< Vec< RefResult> > {
6d3eefbc Andy McCall 1 month ago ↶
2285
let bookmark = self .config.bookmark.clone ( ) ;
7b9809e6 Andy McCall 1 month ago ↶
2286
self .push_bookmark ( remote_name, & bookmark, force)
2287
}
2288
2289
75167672 Andy McCall 1 month ago
2290
pub fn push_bookmark (
cb8b8082 Andy McCall 26 days ago ↶
2291
& self ,
2292
remote_name : & str ,
2293
bookmark : & str ,
2294
force : bool ,
2295
) -> Result< Vec< RefResult> > {
2296
self .push_bookmark_with ( remote_name, bookmark, force, & mut | _ | { } )
2297
}
2298
2299
2300
c8d9059e Andy McCall 11 days ago ↶
2301
2302
2303
2304
2305
pub ( crate ) fn remote_holds (
2306
& self ,
2307
refs : & [crate:: protocol:: RemoteRef],
2308
bookmark_heads : & [ChangeHash],
2309
) -> Vec< ChangeHash> {
2310
let mut have: Vec< ChangeHash> = bookmark_heads.to_vec ( ) ;
2311
for h in refs.iter ( ) .flat_map ( | r | & r.heads) {
2312
if ! have.contains ( h) & & self .store.has ( h) {
2313
have.push ( * h) ;
2314
}
2315
}
2316
have
2317
}
2318
cb8b8082 Andy McCall 26 days ago ↶
2319
pub fn push_bookmark_with (
75167672 Andy McCall 1 month ago
2320
& self ,
2321
remote_name : & str ,
2322
bookmark : & str ,
2323
force : bool ,
cb8b8082 Andy McCall 26 days ago ↶
2324
progress : crate:: store:: Progress,
75167672 Andy McCall 1 month ago
2325
) -> Result< Vec< RefResult> > {
7b9809e6 Andy McCall 1 month ago ↶
2326
let ( op_ref, op) = self .head_op ( ) ? ;
2327
if ! op.view.bookmarks.contains_key ( bookmark) {
2328
return fail ( format! ( " no bookmark {bookmark} " ) ) ;
2329
}
2330
let bookmark = bookmark.to_string ( ) ;
6d3eefbc Andy McCall 1 month ago ↶
2331
let local_heads = self .heads_of ( & op.view, & bookmark) ? ;
2332
2333
self .run_hook (
2334
" pre-push" ,
75167672 Andy McCall 1 month ago
2335
& format! (
2336
" {{ \" event\" :\" pre-push\" ,\" remote\" :{} ,\" bookmark\" :{} ,\" heads\" :{} }} " ,
2337
json_str ( remote_name) ,
2338
json_str ( & bookmark) ,
2339
json_array ( local_heads.iter ( ) .map ( | h | json_str ( & h.to_hex ( ) ) ) )
2340
) ,
6d3eefbc Andy McCall 1 month ago ↶
2341
) ? ;
98286406 Andy McCall 1 month ago ↶
2342
let remote = self .open_named_remote ( remote_name) ? ;
75167672 Andy McCall 1 month ago
2343
self .check_remote_id ( remote.as_ref ( ) , remote_name, true ) ? ;
83e0677b Andy McCall 1 month ago ↶
2344
let resp = remote.refs ( ) ? ;
2345
let local_policy = self .current_policy ( ) ? .map ( | ( _, sp ) | sp ) ;
28fc23d7 Andy McCall 1 month ago ↶
2346
let resp_policy_serial = resp.policy.as_ref ( ) .map ( | p | p.policy.serial ) ;
83e0677b Andy McCall 1 month ago ↶
2347
let policy_to_send = match ( & local_policy, & resp.policy) {
2348
( Some ( l) , Some ( r) ) if l.policy.serial > r.policy.serial => Some ( l.clone ( ) ) ,
2349
( Some ( l) , None ) => Some ( l.clone ( ) ) ,
2350
( Some ( l) , Some ( r) ) if l.policy.serial < r.policy.serial => {
75167672 Andy McCall 1 month ago
2351
return fail ( format! (
2352
" {remote_name} has a newer policy (serial {} ); fetch first" ,
2353
r.policy.serial
2354
) ) ;
83e0677b Andy McCall 1 month ago ↶
2355
}
2356
_ => None ,
2357
} ;
2358
let remote_has_policy = resp.policy.is_some ( ) | | policy_to_send.is_some ( ) ;
2359
if remote_has_policy & & self .secret_key ( ) ? .is_none ( ) {
2360
return fail ( format! ( " {remote_name} enforces a trust policy; pushing needs an identity (`oxy identity create`)" ) ) ;
2361
}
132b884b Andy McCall 1 month ago ↶
2362
let remote_tags: BTreeSet< String> = resp.tags.iter ( ) .map ( | t | t.name.clone ( ) ) .collect ( ) ;
75167672 Andy McCall 1 month ago
2363
let tags_to_send: Vec< crate:: protocol:: TagRef> = self
2364
.tag_refs ( ) ?
2365
.into_iter ( )
2366
.filter ( | t | ! remote_tags.contains ( & t.name) )
2367
.collect ( ) ;
83e0677b Andy McCall 1 month ago ↶
2368
let refs = resp.refs;
98286406 Andy McCall 1 month ago ↶
2369
let empty = self .store.put_state ( & StateObject:: new( vec! [ ] ) ) ? ;
75167672 Andy McCall 1 month ago
2370
let ( remote_state, remote_heads, last_serial) =
2371
match refs.iter ( ) .find ( | r | r.name = = bookmark ) {
2372
Some ( r) => ( r.state, r.heads.clone ( ) , r.last_serial) ,
2373
None => ( empty, vec! [ ] , None ) ,
2374
} ;
2375
let new_state = self
2376
.store
2377
.put_state ( & StateObject:: new( local_heads.clone ( ) ) ) ? ;
83e0677b Andy McCall 1 month ago ↶
2378
2379
2380
2381
132b884b Andy McCall 1 month ago ↶
2382
if new_state = = remote_state & & policy_to_send.is_none ( ) & & tags_to_send.is_empty ( ) {
75167672 Andy McCall 1 month ago
2383
return Ok ( vec! [ RefResult {
2384
name: bookmark,
2385
ok: true ,
2386
reason: " already up to date" .into ( ) ,
2387
} ] ) ;
98286406 Andy McCall 1 month ago ↶
2388
}
2389
for h in & remote_heads {
2390
if ! self .store.has ( h) {
75167672 Andy McCall 1 month ago
2391
return fail ( format! (
3e5772cc Andy McCall 1 month ago ↶
2392
" the remote has change {} which you do not; pull first (`oxy pull {remote_name} `), then push again" ,
75167672 Andy McCall 1 month ago
2393
h.short ( 12 )
2394
) ) ;
98286406 Andy McCall 1 month ago ↶
2395
}
2396
}
2397
if ! force {
2398
let closure = self .closure_in_store ( & local_heads) ? ;
2399
if let Some ( h) = remote_heads.iter ( ) .find ( | h | ! closure.contains ( h) ) {
2400
return fail ( format! ( " not a fast-forward: remote head {} is not in your state; pull first or use --force" , h.short ( 12 ) ) ) ;
2401
}
2402
}
c8d9059e Andy McCall 11 days ago ↶
2403
let to_send = self .negotiate ( & self .remote_holds ( & refs, & remote_heads) , & local_heads) ? ;
98286406 Andy McCall 1 month ago ↶
2404
let key = self .secret_key ( ) ? .map ( | ( k , _) | k ) ;
2405
if let Some ( key) = key {
05e71ed6 Andy McCall 1 month ago ↶
2406
cb8b8082 Andy McCall 26 days ago ↶
2407
2408
98286406 Andy McCall 1 month ago ↶
2409
let mut unsigned = Vec :: new( ) ;
2410
for h in & to_send {
cb8b8082 Andy McCall 26 days ago ↶
2411
let c = self .store.get_change_meta ( h) ? ;
a2387d54 Andy McCall 19 days ago ↶
2412
if self .seals_for_author ( & c.author, & key)
75167672 Andy McCall 1 month ago
2413
& & ! matches! ( self .authenticate_change ( h) ? , SignatureStatus:: Valid { .. } )
2414
{
98286406 Andy McCall 1 month ago ↶
2415
unsigned.push ( * h) ;
2416
}
2417
}
2418
for chunk in unsigned.chunks ( crate :: attest:: MAX_SEAL_HASHES ) {
cb8b8082 Andy McCall 26 days ago ↶
2419
self .sign_attest ( & Attest:: seal( self .id ( ) ? , chunk.to_vec ( ) ) ) ? ;
98286406 Andy McCall 1 month ago ↶
2420
}
cb8b8082 Andy McCall 26 days ago ↶
2421
}
2422
2423
2424
2425
2426
let batches = self .push_batches ( & to_send) ? ;
2427
let ( last, earlier) = batches.split_last ( ) .expect ( " at least one batch" ) ;
2428
for ( i, batch) in earlier.iter ( ) .enumerate ( ) {
2429
progress ( & format! (
2430
" part {} of {} : {} changes" ,
2431
i + 1 ,
2432
batches.len ( ) ,
2433
batch.len ( )
2434
) ) ;
d3b27090 Andy McCall 12 days ago ↶
2435
let bundle = self .send_objects_ahead (
2436
remote.as_ref ( ) ,
2437
remote_name,
2438
self .bundle_for ( batch) ? ,
2439
& mut * progress,
2440
) ? ;
2441
let results = remote.push ( bundle, vec! [ ] , None , vec! [ ] ) ? ;
cb8b8082 Andy McCall 26 days ago ↶
2442
match results.iter ( ) .find ( | r | r.name = = OBJECTS_RESULT ) {
2443
Some ( r) if r.ok => { }
2444
Some ( r) => {
2445
return fail ( format! (
2446
" {remote_name} refused part {} of the push: {} " ,
2447
i + 1 ,
2448
r.reason
2449
) )
2450
}
2451
None => {
2452
return fail ( format! (
2453
" {remote_name} does not take a push in parts, and this one is too long for one: update the server's oxy"
2454
) )
2455
}
2456
}
2457
}
2458
if batches.len ( ) > 1 {
2459
progress ( & format! (
2460
" part {} of {} : {} changes" ,
2461
batches.len ( ) ,
2462
batches.len ( ) ,
2463
last.len ( )
2464
) ) ;
98286406 Andy McCall 1 month ago ↶
2465
}
d3b27090 Andy McCall 12 days ago ↶
2466
let mut bundle = self .send_objects_ahead (
2467
remote.as_ref ( ) ,
2468
remote_name,
2469
self .bundle_for ( last) ? ,
2470
& mut * progress,
2471
) ? ;
75167672 Andy McCall 1 month ago
2472
bundle.objects.push ( (
2473
ObjectType:: State,
2474
StateObject:: new( local_heads.clone ( ) ) .encode ( ) ,
2475
) ) ;
98286406 Andy McCall 1 month ago ↶
2476
let attestation = match key {
2477
Some ( _ ) => Some ( self .sign_attest ( & Attest {
2478
repo: self .id ( ) ? ,
2479
hlc: Hlc:: now( ) ,
75167672 Andy McCall 1 month ago
2480
body: AttestBody:: Ref {
2481
name: bookmark.clone ( ) ,
2482
old_state: remote_state,
2483
new_state,
f8c69576 Andy McCall 1 month ago ↶
2484
serial: next_serial ( last_serial) ,
75167672 Andy McCall 1 month ago
2485
} ,
98286406 Andy McCall 1 month ago ↶
2486
} ) ? ) ,
2487
None => None ,
2488
} ;
68a92484 Andy McCall 22 days ago ↶
2489
2490
2491
2492
if attestation.is_some ( ) {
2493
for k in [ self .signing_key ( ) , self .config.author_key]
2494
.into_iter ( )
2495
.flatten ( )
2496
{
2497
if let Ok ( id) = self .identity ( & k) {
2498
let body = id.encode ( ) ;
2499
if ! bundle
2500
.objects
2501
.iter ( )
2502
.any ( | ( t , b ) | * t = = ObjectType:: Identity & & * b = = body)
2503
{
2504
bundle.objects.push ( ( ObjectType:: Identity, body) ) ;
2505
}
2506
}
2507
}
f0a517d2 Andy McCall 19 days ago ↶
2508
2509
let signers: Vec< KeyId> = self .signing_key ( ) .into_iter ( ) .collect ( ) ;
2510
self .attach_certificates_for ( & mut bundle, & signers) ? ;
68a92484 Andy McCall 22 days ago ↶
2511
}
98286406 Andy McCall 1 month ago ↶
2512
let serial = attestation.as_ref ( ) .and_then ( | a | match a.attest.body {
2513
AttestBody:: Ref { serial, .. } => Some ( serial) ,
2514
_ => None ,
2515
} ) ;
83e0677b Andy McCall 1 month ago ↶
2516
let sent_serial = policy_to_send.as_ref ( ) .map ( | p | p.policy.serial ) ;
132b884b Andy McCall 1 month ago ↶
2517
2518
for t in & tags_to_send {
2519
let extra = self .negotiate ( & remote_heads, & t.heads) ? ;
75167672 Andy McCall 1 month ago
2520
let extra: Vec< ChangeHash> =
2521
extra.into_iter ( ) .filter ( | h | ! to_send.contains ( h) ) .collect ( ) ;
132b884b Andy McCall 1 month ago ↶
2522
if ! extra.is_empty ( ) {
2523
let more = self .bundle_for ( & extra) ? ;
2524
bundle.changes.extend ( more.changes) ;
2c75672f Andy McCall 1 month ago ↶
2525
bundle.hashes.extend ( more.hashes) ;
132b884b Andy McCall 1 month ago ↶
2526
bundle.attests.extend ( more.attests) ;
2527
bundle.objects.extend ( more.objects) ;
2528
}
75167672 Andy McCall 1 month ago
2529
bundle.objects.push ( (
2530
ObjectType:: State,
2531
StateObject:: new( t.heads.clone ( ) ) .encode ( ) ,
2532
) ) ;
132b884b Andy McCall 1 month ago ↶
2533
}
d8524a9f Andy McCall 16 days ago ↶
2534
2535
2536
2537
let tag_signers: Vec< KeyId> = tags_to_send
2538
.iter ( )
2539
.filter_map ( | t | t.attestation.as_ref ( ) )
2540
.flat_map ( | a | a.sigs.iter ( ) .map ( | s | s.key ) )
2541
.collect ( ) ;
2542
for k in & tag_signers {
2543
if let Ok ( id) = self .identity ( k) {
2544
let body = id.encode ( ) ;
2545
if ! bundle
2546
.objects
2547
.iter ( )
2548
.any ( | ( t , b ) | * t = = ObjectType:: Identity & & * b = = body)
2549
{
2550
bundle.objects.push ( ( ObjectType:: Identity, body) ) ;
2551
}
2552
}
2553
}
2554
if ! tag_signers.is_empty ( ) {
2555
self .attach_certificates_for ( & mut bundle, & tag_signers) ? ;
2556
}
28fc23d7 Andy McCall 1 month ago ↶
2557
if let Some ( l) = & policy_to_send {
2558
let remote_serial = resp_policy_serial;
75167672 Andy McCall 1 month ago
2559
bundle.policies = self
2560
.policy_history ( ) ?
2561
.into_iter ( )
2562
.filter ( | sp | {
2563
remote_serial.is_none_or ( | r | sp.policy.serial > r )
2564
& & sp.policy.serial < l.policy.serial
2565
} )
2566
.collect ( ) ;
28fc23d7 Andy McCall 1 month ago ↶
2567
}
75167672 Andy McCall 1 month ago
2568
let results = remote.push (
2569
bundle,
2570
vec! [ RefUpdate {
2571
name: bookmark.clone ( ) ,
2572
old_state: remote_state,
2573
new_state,
2574
force,
2575
attestation,
2576
} ] ,
2577
policy_to_send,
2578
tags_to_send,
2579
) ? ;
2580
if let ( Some ( serial) , true ) = (
2581
sent_serial,
2582
results.iter ( ) .any ( | r | r.ok & & r.name = = " policy" ) ,
2583
) {
83e0677b Andy McCall 1 month ago ↶
2584
self .record_policy_serial ( remote_name, serial) ? ;
2585
}
2586
if results.iter ( ) .any ( | r | r.ok & & r.name = = bookmark ) {
98286406 Andy McCall 1 month ago ↶
2587
let mut view = op.view.clone ( ) ;
75167672 Andy McCall 1 month ago
2588
view.remotes
2589
.entry ( remote_name.to_string ( ) )
2590
.or_default ( )
2591
.insert ( bookmark.clone ( ) , new_state) ;
98286406 Andy McCall 1 month ago ↶
2592
self .record_op ( & [ op_ref] , & format! ( " oxy push {remote_name} " ) , view) ? ;
2593
if let Some ( s) = serial {
2594
self .record_serial ( remote_name, & bookmark, s) ? ;
2595
}
2596
}
2597
Ok ( results)
2598
}
2599
2600
2601
2602
pub fn clone ( url : & str , dest : & Path) -> Result< Repo> {
7421309f Andy McCall 1 month ago ↶
2603
Self :: clone_with( url, dest, None , & [ ] )
b3c5a59a Andy McCall 1 month ago ↶
2604
}
2605
7421309f Andy McCall 1 month ago ↶
2606
2607
2608
75167672 Andy McCall 1 month ago
2609
pub fn clone_with (
2610
url : & str ,
2611
dest : & Path,
2612
max_blob : Option< u64 > ,
2613
sparse : & [String],
2614
) -> Result< Repo> {
2863456a Andy McCall 1 month ago ↶
2615
Self :: clone_full( url, dest, max_blob, sparse, None )
2616
}
2617
2618
2619
75167672 Andy McCall 1 month ago
2620
pub fn clone_shallow (
2621
url : & str ,
2622
dest : & Path,
2623
depth : u32 ,
2624
max_blob : Option< u64 > ,
2625
sparse : & [String],
2626
) -> Result< Repo> {
2863456a Andy McCall 1 month ago ↶
2627
Self :: clone_full( url, dest, max_blob, sparse, Some ( depth) )
2628
}
2629
75167672 Andy McCall 1 month ago
2630
fn clone_full (
2631
url : & str ,
2632
dest : & Path,
2633
max_blob : Option< u64 > ,
2634
sparse : & [String],
2635
depth : Option< u32 > ,
2636
) -> Result< Repo> {
d36ba2f7 Andy McCall 17 days ago ↶
2637
Ok ( Self :: clone_reporting( url, dest, max_blob, sparse, depth) ? .0 )
2638
}
2639
2640
2641
2642
2643
2644
2645
pub fn clone_reporting (
2646
url : & str ,
2647
dest : & Path,
2648
max_blob : Option< u64 > ,
2649
sparse : & [String],
2650
depth : Option< u32 > ,
2651
) -> Result< ( Repo, Vec< ( String, String) > ) > {
ff1f62fe Andy McCall 1 month ago ↶
2652
let options = crate :: credentials:: Credentials:: user( ) .options_for ( url) ;
2653
Self :: clone_using( url, dest, max_blob, sparse, depth, & options)
a07f60a3 Andy McCall 1 month ago ↶
2654
}
2655
ff1f62fe Andy McCall 1 month ago ↶
2656
2657
2658
a07f60a3 Andy McCall 1 month ago ↶
2659
pub ( crate ) fn clone_as_subrepo ( & self , url : & str , dest : & Path) -> Result< Repo> {
2660
let options = self .credentials_for ( url) ;
d36ba2f7 Andy McCall 17 days ago ↶
2661
Ok ( Self :: clone_using( url, dest, None , & [ ] , None , & options) ? .0 )
a07f60a3 Andy McCall 1 month ago ↶
2662
}
2663
2664
2665
2666
fn remote_on_same_hub ( & self , url : & str ) -> Option< String> {
2667
let origin = | u : & str | -> Option< String> {
2668
let ( scheme, rest) = u.split_once ( " ://" ) ? ;
9f9e72b9 Andy McCall 1 month ago ↶
2669
if ! matches! ( scheme, " http" | " https" ) {
2670
return None ;
2671
}
a07f60a3 Andy McCall 1 month ago ↶
2672
let host = rest.split ( ' /' ) .next ( ) ? ;
2673
Some ( format! (
2674
" {} ://{} " ,
2675
scheme.to_ascii_lowercase ( ) ,
2676
host.to_ascii_lowercase ( )
2677
) )
2678
} ;
2679
let want = origin ( url) ? ;
2680
self .config
2681
.remotes
2682
.iter ( )
2683
.find ( | ( _, u ) | origin ( u) .as_deref ( ) = = Some ( want.as_str ( ) ) )
2684
.map ( | ( name , _) | name.clone ( ) )
2685
}
2686
2687
2688
ff1f62fe Andy McCall 1 month ago ↶
2689
2690
a07f60a3 Andy McCall 1 month ago ↶
2691
pub ( crate ) fn credentials_for ( & self , url : & str ) -> RemoteOptions {
2692
match self .remote_on_same_hub ( url) {
2693
Some ( name) => RemoteOptions {
2694
repo_id: None ,
9f9e72b9 Andy McCall 1 month ago ↶
2695
cache_dir: None ,
a07f60a3 Andy McCall 1 month ago ↶
2696
.. self .remote_options ( & name)
2697
} ,
ff1f62fe Andy McCall 1 month ago ↶
2698
None => {
2699
let mut options = RemoteOptions:: default( ) ;
2700
self .fill_credentials ( url, & mut options) ;
2701
options
2702
}
a07f60a3 Andy McCall 1 month ago ↶
2703
}
2704
}
2705
2706
fn clone_using (
2707
url : & str ,
2708
dest : & Path,
2709
max_blob : Option< u64 > ,
2710
sparse : & [String],
2711
depth : Option< u32 > ,
2712
options : & RemoteOptions,
d36ba2f7 Andy McCall 17 days ago ↶
2713
) -> Result< ( Repo, Vec< ( String, String) > ) > {
a07f60a3 Andy McCall 1 month ago ↶
2714
let remote = open_remote ( url, options) ? ;
98286406 Andy McCall 1 month ago ↶
2715
let id = remote.repo_id ( ) ? ;
75167672 Andy McCall 1 month ago
2716
if id = = crate :: protocol:: UNBOUND_ID {
05e71ed6 Andy McCall 1 month ago ↶
2717
return fail ( format! (
2718
" {url} is empty and unbound: push a repository to it first"
2719
) ) ;
75167672 Andy McCall 1 month ago
2720
}
98286406 Andy McCall 1 month ago ↶
2721
let mut repo = Repo:: init_with_id( dest, id) ? ;
827281ee Andy McCall 1 month ago ↶
2722
repo.config
2723
.set ( " remote.origin.url" , & crate :: protocol:: stored_url( url) ) ? ;
b3c5a59a Andy McCall 1 month ago ↶
2724
if let Some ( m) = max_blob {
2725
repo.config.set ( " filter.max-blob" , & m.to_string ( ) ) ? ;
7421309f Andy McCall 1 month ago ↶
2726
} else if ! sparse.is_empty ( ) {
2727
repo.config.set ( " filter.max-blob" , " 0" ) ? ;
2728
}
2729
if ! sparse.is_empty ( ) {
2730
repo.config.set ( " filter.paths" , & sparse.join ( " ," ) ) ? ;
b3c5a59a Andy McCall 1 month ago ↶
2731
}
98286406 Andy McCall 1 month ago ↶
2732
repo.save_config ( ) ? ;
d36ba2f7 Andy McCall 17 days ago ↶
2733
let skipped = if let Some ( depth) = depth {
2863456a Andy McCall 1 month ago ↶
2734
repo.fetch_shallow ( " origin" , depth) ? ;
d36ba2f7 Andy McCall 17 days ago ↶
2735
Vec :: new( )
2863456a Andy McCall 1 month ago ↶
2736
} else {
d36ba2f7 Andy McCall 17 days ago ↶
2737
repo.fetch ( " origin" ) ? .skipped
2738
} ;
98286406 Andy McCall 1 month ago ↶
2739
let ( op_ref, op) = repo.head_op ( ) ? ;
d36ba2f7 Andy McCall 17 days ago ↶
2740
2741
2742
2743
let mut theirs = op.view.remotes.get ( " origin" ) .cloned ( ) .unwrap_or_default ( ) ;
2744
for ( name, _ ) in & skipped {
2745
theirs.insert ( name.clone ( ) , ObjectRef:: ZERO ) ;
2746
}
9f9e72b9 Andy McCall 1 month ago ↶
2747
2748
2749
let advertised = repo
2750
.open_named_remote ( " origin" )
2751
.ok ( )
2752
.and_then ( | r | r.refs ( ) .ok ( ) )
2753
.and_then ( | r | r.default_bookmark ) ;
14edbaaf Andy McCall 1 month ago ↶
2754
let bookmark = advertised
2755
.filter ( | b | theirs.contains_key ( b) )
2756
.or_else ( | | {
2757
theirs
2758
.contains_key ( & repo.config.bookmark)
2759
.then ( | | repo.config.bookmark.clone ( ) )
2760
} )
2761
.or_else ( | | {
2762
( theirs.len ( ) = = 1 )
2763
.then ( | | theirs.keys ( ) .next ( ) .cloned ( ) )
2764
.flatten ( )
2765
} )
2766
.unwrap_or_else ( | | repo.config.bookmark.clone ( ) ) ;
d36ba2f7 Andy McCall 17 days ago ↶
2767
if let Some ( ( _ , why) ) = skipped.iter ( ) .find ( | ( name , _) | * name = = bookmark) {
2768
return fail ( format! ( " cannot check out {bookmark} : {why} " ) ) ;
2769
}
14edbaaf Andy McCall 1 month ago ↶
2770
let initial = repo.config.bookmark.clone ( ) ;
2771
if bookmark ! = repo.config.bookmark {
2772
fs:: create_dir_all( repo.workspace_bookmark_path ( ) .parent ( ) .unwrap ( ) ) ? ;
2773
write_atomic ( & repo.workspace_bookmark_path ( ) , bookmark.as_bytes ( ) ) ? ;
2774
repo.config.bookmark = bookmark.clone ( ) ;
2775
}
2776
if let Some ( state) = theirs.get ( & bookmark) .copied ( ) {
98286406 Andy McCall 1 month ago ↶
2777
let heads = repo.store.get_state ( & state) ? .heads;
2778
let mut view = op.view.clone ( ) ;
14edbaaf Andy McCall 1 month ago ↶
2779
2780
if initial ! = bookmark & & repo.heads_of ( & view, & initial) ? .is_empty ( ) {
2781
view.bookmarks.remove ( & initial) ;
2782
}
98286406 Andy McCall 1 month ago ↶
2783
view.bookmarks.insert ( bookmark, state) ;
2784
repo.record_op ( & [ op_ref] , & format! ( " oxy clone {url} " ) , view) ? ;
2785
repo.checkout ( & heads, false , " oxy clone (checkout)" ) ? ;
2786
}
d36ba2f7 Andy McCall 17 days ago ↶
2787
Ok ( ( repo, skipped) )
f8c69576 Andy McCall 1 month ago ↶
2788
}
2789
}
2790
2791
2792
2793
2794
2795
fn next_serial ( last : Option< u64 > ) -> u64 {
2796
match last {
2797
Some ( l) => l + 1 ,
2798
None => Hlc:: now( ) .wall_ms.max ( 1 ) ,
98286406 Andy McCall 1 month ago ↶
2799
}
2800
}