@@ -30,16 +30,21 @@ type package = {
3030 name: str ,
3131 uuid: str,
3232 url: str,
33- method: str
33+ method: str,
34+ tags: [ str]
3435} ;
3536
3637type source = {
3738 name : str ,
3839 url : str ,
40+ sig : option:: t < str > ,
41+ key : option:: t < str > ,
42+ keyfp : option:: t < str > ,
3943 mutable packages: [ package ]
4044} ;
4145
4246type cargo = {
47+ pgp : bool ,
4348 root : str ,
4449 bindir : str ,
4550 libdir : str ,
@@ -158,12 +163,32 @@ fn need_dir(s: str) {
158163fn parse_source ( name : str , j : json:: json ) -> source {
159164 alt j {
160165 json : : dict ( _j) {
161- alt _j. find ( "url" ) {
166+ let url = alt _j. find ( "url" ) {
162167 some ( json:: string ( u) ) {
163- ret { name : name , url : u , mutable packages : [ ] } ;
168+ u
164169 }
165170 _ { fail "Needed 'url' field in source." ; }
166171 } ;
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 : [ ] } ;
167192 }
168193 _ { fail "Needed dict value in source." ; }
169194 } ;
@@ -217,18 +242,31 @@ fn load_one_source_package(&src: source, p: map::hashmap<str, json::json>) {
217242 }
218243 } ;
219244
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+ }
220257 vec:: grow ( src. packages , 1 u, {
221258 // source: _source(src),
222259 name: name,
223260 uuid: uuid,
224261 url: url,
225- method: method
262+ method: method,
263+ tags: tags
226264 } ) ;
227- info ( " Loaded package: " + src. name + "/" + name) ;
265+ log " Loaded package: " + src. name + "/" + name;
228266}
229267
230268fn load_source_packages ( & c: cargo , & src: source ) {
231- info ( "Loading source: " + src. name ) ;
269+ log "Loading source: " + src. name ;
232270 let dir = fs:: connect ( c. sourcedir , src. name ) ;
233271 let pkgfile = fs:: connect ( dir, "packages.json" ) ;
234272 if !fs:: path_exists ( pkgfile) { ret; }
@@ -269,6 +307,7 @@ fn configure() -> cargo {
269307 try_parse_sources ( fs:: connect ( p, "sources.json" ) , sources) ;
270308 try_parse_sources ( fs:: connect ( p, "local-sources.json" ) , sources) ;
271309 let c = {
310+ pgp: pgp:: supported ( ) ,
272311 root: p,
273312 bindir: fs:: connect ( p, "bin" ) ,
274313 libdir: fs:: connect ( p, "lib" ) ,
@@ -289,6 +328,10 @@ fn configure() -> cargo {
289328 sources. insert ( k, s) ;
290329 } ;
291330
331+ if c. pgp {
332+ pgp:: init ( c. root ) ;
333+ }
334+
292335 c
293336}
294337
@@ -501,7 +544,10 @@ fn cmd_install(c: cargo, argv: [str]) {
501544
502545fn sync_one ( c : cargo , name : str , src : source ) {
503546 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" ) ;
505551 let url = src. url ;
506552 need_dir ( dir) ;
507553 info ( #fmt[ "fetching source %s..." , name] ) ;
@@ -511,6 +557,43 @@ fn sync_one(c: cargo, name: str, src: source) {
511557 } else {
512558 info ( #fmt[ "fetched source: %s" , name] ) ;
513559 }
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] ) ;
514597}
515598
516599fn cmd_sync ( c : cargo , argv : [ str ] ) {
@@ -523,10 +606,75 @@ fn cmd_sync(c: cargo, argv: [str]) {
523606 }
524607}
525608
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+
526671fn cmd_usage ( ) {
527672 print ( "Usage: cargo <verb> [args...]" ) ;
673+ print ( " init Fetch default sources" ) ;
528674 print ( " install [source/]package-name Install by name" ) ;
529675 print ( " install uuid:[source/]package-uuid Install by uuid" ) ;
676+ print ( " list [source] List packages" ) ;
677+ print ( " search <name | '*'> [tags...] Search packages" ) ;
530678 print ( " sync Sync all sources" ) ;
531679 print ( " usage This" ) ;
532680}
@@ -538,7 +686,10 @@ fn main(argv: [str]) {
538686 }
539687 let c = configure ( ) ;
540688 alt argv[ 1 ] {
689+ "init" { cmd_init ( c) ; }
541690 "install" { cmd_install ( c, argv) ; }
691+ "list" { cmd_list ( c, argv) ; }
692+ "search" { cmd_search ( c, argv) ; }
542693 "sync" { cmd_sync ( c, argv) ; }
543694 "usage" { cmd_usage ( ) ; }
544695 _ { cmd_usage( ) ; }
0 commit comments