@@ -30,16 +30,21 @@ type package = {
30
30
name: str ,
31
31
uuid: str,
32
32
url: str,
33
- method: str
33
+ method: str,
34
+ tags: [ str]
34
35
} ;
35
36
36
37
type source = {
37
38
name : str ,
38
39
url : str ,
40
+ sig : option:: t < str > ,
41
+ key : option:: t < str > ,
42
+ keyfp : option:: t < str > ,
39
43
mutable packages: [ package ]
40
44
} ;
41
45
42
46
type cargo = {
47
+ pgp : bool ,
43
48
root : str ,
44
49
bindir : str ,
45
50
libdir : str ,
@@ -158,12 +163,32 @@ fn need_dir(s: str) {
158
163
fn parse_source ( name : str , j : json:: json ) -> source {
159
164
alt j {
160
165
json : : dict ( _j) {
161
- alt _j. find ( "url" ) {
166
+ let url = alt _j. find ( "url" ) {
162
167
some ( json:: string ( u) ) {
163
- ret { name : name , url : u , mutable packages : [ ] } ;
168
+ u
164
169
}
165
170
_ { fail "Needed 'url' field in source." ; }
166
171
} ;
172
+ let sig = alt _j. find ( "sig" ) {
173
+ some ( json:: string ( u) ) {
174
+ some ( u)
175
+ }
176
+ _ { none }
177
+ } ;
178
+ let key = alt _j. find ( "key" ) {
179
+ some ( json:: string ( u) ) {
180
+ some ( u)
181
+ }
182
+ _ { none }
183
+ } ;
184
+ let keyfp = alt _j. find ( "keyfp" ) {
185
+ some ( json:: string ( u) ) {
186
+ some ( u)
187
+ }
188
+ _ { none }
189
+ } ;
190
+ ret { name : name, url : url, sig : sig, key : key, keyfp : keyfp,
191
+ mutable packages : [ ] } ;
167
192
}
168
193
_ { fail "Needed dict value in source." ; }
169
194
} ;
@@ -217,18 +242,31 @@ fn load_one_source_package(&src: source, p: map::hashmap<str, json::json>) {
217
242
}
218
243
} ;
219
244
245
+ let tags = [ ] ;
246
+ alt p. find ( "tags" ) {
247
+ some ( json:: list ( js) ) {
248
+ for j in * js {
249
+ alt j {
250
+ json : : string ( _j) { vec:: grow ( tags, 1 u, _j) ; }
251
+ _ { }
252
+ }
253
+ }
254
+ }
255
+ _ { }
256
+ }
220
257
vec:: grow ( src. packages , 1 u, {
221
258
// source: _source(src),
222
259
name: name,
223
260
uuid: uuid,
224
261
url: url,
225
- method: method
262
+ method: method,
263
+ tags: tags
226
264
} ) ;
227
- info ( " Loaded package: " + src. name + "/" + name) ;
265
+ log " Loaded package: " + src. name + "/" + name;
228
266
}
229
267
230
268
fn load_source_packages ( & c: cargo , & src: source ) {
231
- info ( "Loading source: " + src. name ) ;
269
+ log "Loading source: " + src. name ;
232
270
let dir = fs:: connect ( c. sourcedir , src. name ) ;
233
271
let pkgfile = fs:: connect ( dir, "packages.json" ) ;
234
272
if !fs:: path_exists ( pkgfile) { ret; }
@@ -269,6 +307,7 @@ fn configure() -> cargo {
269
307
try_parse_sources ( fs:: connect ( p, "sources.json" ) , sources) ;
270
308
try_parse_sources ( fs:: connect ( p, "local-sources.json" ) , sources) ;
271
309
let c = {
310
+ pgp: pgp:: supported ( ) ,
272
311
root: p,
273
312
bindir: fs:: connect ( p, "bin" ) ,
274
313
libdir: fs:: connect ( p, "lib" ) ,
@@ -289,6 +328,10 @@ fn configure() -> cargo {
289
328
sources. insert ( k, s) ;
290
329
} ;
291
330
331
+ if c. pgp {
332
+ pgp:: init ( c. root ) ;
333
+ }
334
+
292
335
c
293
336
}
294
337
@@ -501,7 +544,10 @@ fn cmd_install(c: cargo, argv: [str]) {
501
544
502
545
fn sync_one ( c : cargo , name : str , src : source ) {
503
546
let dir = fs:: connect ( c. sourcedir , name) ;
504
- let pkgfile = fs:: connect ( dir, "packages.json" ) ;
547
+ let pkgfile = fs:: connect ( dir, "packages.json.new" ) ;
548
+ let destpkgfile = fs:: connect ( dir, "packages.json" ) ;
549
+ let sigfile = fs:: connect ( dir, "packages.json.sig" ) ;
550
+ let keyfile = fs:: connect ( dir, "key.gpg" ) ;
505
551
let url = src. url ;
506
552
need_dir ( dir) ;
507
553
info ( #fmt[ "fetching source %s..." , name] ) ;
@@ -511,6 +557,43 @@ fn sync_one(c: cargo, name: str, src: source) {
511
557
} else {
512
558
info ( #fmt[ "fetched source: %s" , name] ) ;
513
559
}
560
+ alt src. sig {
561
+ some ( u) {
562
+ let p = run:: program_output ( "curl" , [ "-f" , "-s" , "-o" , sigfile,
563
+ u] ) ;
564
+ if p. status != 0 {
565
+ warn ( #fmt[ "fetch for source %s (sig %s) failed" , name, u] ) ;
566
+ }
567
+ }
568
+ _ { }
569
+ }
570
+ alt src. key {
571
+ some ( u) {
572
+ let p = run:: program_output ( "curl" , [ "-f" , "-s" , "-o" , keyfile,
573
+ u] ) ;
574
+ if p. status != 0 {
575
+ warn ( #fmt[ "fetch for source %s (key %s) failed" , name, u] ) ;
576
+ }
577
+ pgp:: add ( c. root , keyfile) ;
578
+ }
579
+ _ { }
580
+ }
581
+ alt ( src. sig , src. key , src. keyfp ) {
582
+ ( some ( _) , some ( _) , some ( f) ) {
583
+ let r = pgp:: verify ( c. root , pkgfile, sigfile, f) ;
584
+ if !r {
585
+ warn ( #fmt[ "signature verification failed for source %s" ,
586
+ name] ) ;
587
+ ret;
588
+ } else {
589
+ info ( #fmt[ "signature ok for source %s" , name] ) ;
590
+ }
591
+ }
592
+ _ {
593
+ info( #fmt[ "no signature for source %s" , name] ) ;
594
+ }
595
+ }
596
+ run:: run_program ( "cp" , [ pkgfile, destpkgfile] ) ;
514
597
}
515
598
516
599
fn cmd_sync ( c : cargo , argv : [ str ] ) {
@@ -523,10 +606,75 @@ fn cmd_sync(c: cargo, argv: [str]) {
523
606
}
524
607
}
525
608
609
+ fn cmd_init ( c : cargo ) {
610
+ let srcurl = "http://www.rust-lang.org/cargo/sources.json" ;
611
+ let sigurl = "http://www.rust-lang.org/cargo/sources.json.sig" ;
612
+
613
+ let srcfile = fs:: connect ( c. root , "sources.json.new" ) ;
614
+ let sigfile = fs:: connect ( c. root , "sources.json.sig" ) ;
615
+ let destsrcfile = fs:: connect ( c. root , "sources.json" ) ;
616
+
617
+ let p = run:: program_output ( "curl" , [ "-f" , "-s" , "-o" , srcfile, srcurl] ) ;
618
+ if p. status != 0 {
619
+ warn ( #fmt[ "fetch of sources.json failed: %s" , p. out ] ) ;
620
+ ret;
621
+ }
622
+
623
+ let p = run:: program_output ( "curl" , [ "-f" , "-s" , "-o" , sigfile, sigurl] ) ;
624
+ if p. status != 0 {
625
+ warn ( #fmt[ "fetch of sources.json.sig failed: %s" , p. out ] ) ;
626
+ ret;
627
+ }
628
+
629
+ let r = pgp:: verify ( c. root , srcfile, sigfile, pgp:: signing_key_fp ( ) ) ;
630
+ if !r {
631
+ warn ( #fmt[ "signature verification failed for sources.json" ] ) ;
632
+ ret;
633
+ }
634
+ info ( #fmt[ "signature ok for sources.json" ] ) ;
635
+ run:: run_program ( "cp" , [ srcfile, destsrcfile] ) ;
636
+ }
637
+
638
+ fn print_pkg ( s : source , p : package ) {
639
+ let m = s. name + "/" + p. name + " (" + p. uuid + ")" ;
640
+ if vec:: len ( p. tags ) > 0 u {
641
+ m = m + " [" + str:: connect ( p. tags , ", " ) + "]" ;
642
+ }
643
+ info ( m) ;
644
+ }
645
+ fn cmd_list ( c : cargo , argv : [ str ] ) {
646
+ for_each_package ( c, { |s, p|
647
+ if vec:: len ( argv) <= 2 u || argv[ 2 ] == s. name {
648
+ print_pkg ( s, p) ;
649
+ }
650
+ } ) ;
651
+ }
652
+
653
+ fn cmd_search ( c : cargo , argv : [ str ] ) {
654
+ if vec:: len ( argv) < 3 u {
655
+ cmd_usage ( ) ;
656
+ ret;
657
+ }
658
+ let n = 0 ;
659
+ let name = argv[ 2 ] ;
660
+ let tags = vec:: slice ( argv, 3 u, vec:: len ( argv) ) ;
661
+ for_each_package ( c, { |s, p|
662
+ if ( str:: contains ( p. name , name) || name == "*" ) &&
663
+ vec:: all ( tags, { |t| vec:: member ( t, p. tags ) } ) {
664
+ print_pkg ( s, p) ;
665
+ n += 1 ;
666
+ }
667
+ } ) ;
668
+ info ( #fmt[ "Found %d packages." , n] ) ;
669
+ }
670
+
526
671
fn cmd_usage ( ) {
527
672
print ( "Usage: cargo <verb> [args...]" ) ;
673
+ print ( " init Fetch default sources" ) ;
528
674
print ( " install [source/]package-name Install by name" ) ;
529
675
print ( " install uuid:[source/]package-uuid Install by uuid" ) ;
676
+ print ( " list [source] List packages" ) ;
677
+ print ( " search <name | '*'> [tags...] Search packages" ) ;
530
678
print ( " sync Sync all sources" ) ;
531
679
print ( " usage This" ) ;
532
680
}
@@ -538,7 +686,10 @@ fn main(argv: [str]) {
538
686
}
539
687
let c = configure ( ) ;
540
688
alt argv[ 1 ] {
689
+ "init" { cmd_init ( c) ; }
541
690
"install" { cmd_install ( c, argv) ; }
691
+ "list" { cmd_list ( c, argv) ; }
692
+ "search" { cmd_search ( c, argv) ; }
542
693
"sync" { cmd_sync ( c, argv) ; }
543
694
"usage" { cmd_usage ( ) ; }
544
695
_ { cmd_usage( ) ; }
0 commit comments