1
1
// cargo.rs - Rust package manager
2
2
3
+ use rustc;
4
+ use std;
5
+
3
6
import rustc:: syntax:: { ast, codemap, visit} ;
4
7
import rustc:: syntax:: parse:: parser;
5
8
@@ -9,18 +12,39 @@ import std::io;
9
12
import std:: json;
10
13
import option;
11
14
import option:: { none, some} ;
15
+ import result;
16
+ import std:: map;
12
17
import std:: os;
13
18
import std:: run;
14
19
import str;
15
20
import std:: tempfile;
16
21
import vec;
17
22
23
+ tag _src {
24
+ /* Break cycles in package <-> source */
25
+ _source( source) ;
26
+ }
27
+
28
+ type package = {
29
+ source: _src,
30
+ name: str,
31
+ uuid: str,
32
+ url: str
33
+ } ;
34
+
35
+ type source = {
36
+ name : str ,
37
+ url : str ,
38
+ mutable packages: [ package ]
39
+ } ;
40
+
18
41
type cargo = {
19
42
root : str ,
20
43
bindir : str ,
21
44
libdir : str ,
22
45
workdir : str ,
23
- fetchdir : str
46
+ sourcedir : str ,
47
+ sources : map:: hashmap < str , source >
24
48
} ;
25
49
26
50
type pkg = {
@@ -32,6 +56,14 @@ type pkg = {
32
56
crate_type : option:: t < str >
33
57
} ;
34
58
59
+ fn info ( msg : str ) {
60
+ io:: stdout ( ) . write_line ( msg) ;
61
+ }
62
+
63
+ fn warn ( msg : str ) {
64
+ io:: stdout ( ) . write_line ( "warning: " + msg) ;
65
+ }
66
+
35
67
fn load_link ( mis : [ @ast:: meta_item ] ) -> ( option:: t < str > ,
36
68
option:: t < str > ,
37
69
option:: t < str > ) {
@@ -118,6 +150,96 @@ fn need_dir(s: str) {
118
150
}
119
151
}
120
152
153
+ fn parse_source ( name : str , j : json:: json ) -> source {
154
+ alt j {
155
+ json : : dict ( _j) {
156
+ alt _j. find ( "url" ) {
157
+ some ( json:: string ( u) ) {
158
+ ret { name : name, url : u, mutable packages : [ ] } ;
159
+ }
160
+ _ { fail "Needed 'url' field in source." ; }
161
+ } ;
162
+ }
163
+ _ { fail "Needed dict value in source." ; }
164
+ } ;
165
+ }
166
+
167
+ fn try_parse_sources ( filename : str , sources : map:: hashmap < str , source > ) {
168
+ if !fs:: path_exists ( filename) { ret; }
169
+ let c = io:: read_whole_file_str ( filename) ;
170
+ let j = json:: from_str ( result:: get ( c) ) ;
171
+ alt j {
172
+ some( json:: dict ( _j) ) {
173
+ _j. items { |k, v|
174
+ sources. insert ( k, parse_source ( k, v) ) ;
175
+ log #fmt[ "source: %s" , k] ;
176
+ }
177
+ }
178
+ _ { fail "malformed sources.json" ; }
179
+ }
180
+ }
181
+
182
+ fn load_one_source_package ( c : cargo , src : source , p : map:: hashmap < str , json:: json > ) {
183
+ let name = alt p. find ( "name" ) {
184
+ some ( json:: string ( _n) ) { _n }
185
+ _ {
186
+ warn( "Malformed source json: " + src. name + " (missing name)" ) ;
187
+ ret;
188
+ }
189
+ } ;
190
+
191
+ let uuid = alt p. find ( "uuid" ) {
192
+ some ( json:: string ( _n) ) { _n }
193
+ _ {
194
+ warn( "Malformed source json: " + src. name + " (missing uuid)" ) ;
195
+ ret;
196
+ }
197
+ } ;
198
+
199
+ let url = alt p. find ( "url" ) {
200
+ some ( json:: string ( _n) ) { _n }
201
+ _ {
202
+ warn( "Malformed source json: " + src. name + " (missing url)" ) ;
203
+ ret;
204
+ }
205
+ } ;
206
+
207
+ vec:: grow ( src. packages , 1 u, {
208
+ source: _source ( src) ,
209
+ name: name,
210
+ uuid: uuid,
211
+ url: url
212
+ } ) ;
213
+ info ( " Loaded package: " + src. name + "/" + name) ;
214
+ }
215
+
216
+ fn load_source_packages ( c : cargo , src : source ) {
217
+ info ( "Loading source: " + src. name ) ;
218
+ let dir = fs:: connect ( c. sourcedir , src. name ) ;
219
+ let pkgfile = fs:: connect ( dir, "packages.json" ) ;
220
+ if !fs:: path_exists ( pkgfile) { ret; }
221
+ let pkgstr = io:: read_whole_file_str ( pkgfile) ;
222
+ let j = json:: from_str ( result:: get ( pkgstr) ) ;
223
+ alt j {
224
+ some( json:: list ( js) ) {
225
+ for _j: json:: json in * js {
226
+ alt _j {
227
+ json : : dict ( _p) {
228
+ load_one_source_package ( c, src, _p) ;
229
+ }
230
+ _ {
231
+ warn( "Malformed source json: " + src. name + " (non-dict pkg)" ) ;
232
+ ret;
233
+ }
234
+ }
235
+ }
236
+ }
237
+ _ {
238
+ warn( "Malformed source json: " + src. name ) ;
239
+ }
240
+ } ;
241
+ }
242
+
121
243
fn configure ( ) -> cargo {
122
244
let p = alt generic_os:: getenv ( "CARGO_ROOT" ) {
123
245
some ( _p) { _p }
@@ -129,25 +251,39 @@ fn configure() -> cargo {
129
251
}
130
252
} ;
131
253
132
- log #fmt[ "p: %s" , p] ;
133
-
254
+ let sources = map:: new_str_hash :: < source > ( ) ;
255
+ try_parse_sources ( fs:: connect ( p, "sources.json" ) , sources) ;
256
+ try_parse_sources ( fs:: connect ( p, "local-sources.json" ) , sources) ;
134
257
let c = {
135
258
root: p,
136
259
bindir: fs:: connect ( p, "bin" ) ,
137
260
libdir: fs:: connect ( p, "lib" ) ,
138
261
workdir: fs:: connect ( p, "work" ) ,
139
- fetchdir: fs:: connect ( p, "fetch" )
262
+ sourcedir: fs:: connect ( p, "sources" ) ,
263
+ sources: sources
140
264
} ;
141
265
142
266
need_dir ( c. root ) ;
143
- need_dir ( c. fetchdir ) ;
267
+ need_dir ( c. sourcedir ) ;
144
268
need_dir ( c. workdir ) ;
145
269
need_dir ( c. libdir ) ;
146
270
need_dir ( c. bindir ) ;
147
271
272
+ sources. values { |v|
273
+ load_source_packages ( c, v) ;
274
+ } ;
275
+
148
276
c
149
277
}
150
278
279
+ fn for_each_package ( c : cargo , b : block ( package ) ) {
280
+ c. sources . values ( { |v|
281
+ for p in v. packages {
282
+ b ( p) ;
283
+ }
284
+ } )
285
+ }
286
+
151
287
fn install_one_crate ( c : cargo , _path : str , cf : str , _p : pkg ) {
152
288
let name = fs:: basename ( cf) ;
153
289
let ri = str:: index ( name, '.' as u8 ) ;
@@ -233,11 +369,29 @@ fn install_resolved(c: cargo, wd: str, key: str) {
233
369
}
234
370
235
371
fn install_uuid ( c : cargo , wd : str , uuid : str ) {
236
- install_resolved ( c, wd, "by-uuid/" + uuid) ;
372
+ let ps = [ ] ;
373
+ for_each_package ( c, { |p|
374
+ if p. uuid == uuid {
375
+ vec:: grow ( ps, 1 u, p) ;
376
+ }
377
+ } ) ;
378
+ info ( "Found:" ) ;
379
+ for p in ps {
380
+ info ( " " + p. source . name + "/" + p. name ) ;
381
+ }
237
382
}
238
383
239
384
fn install_named ( c : cargo , wd : str , name : str ) {
240
- install_resolved ( c, wd, "by-name/" + name) ;
385
+ let ps = [ ] ;
386
+ for_each_package ( c, { |p|
387
+ if p. name == name {
388
+ vec:: grow ( ps, 1 u, p) ;
389
+ }
390
+ } ) ;
391
+ info ( "Found:" ) ;
392
+ for p in ps {
393
+ info ( " " + p. source . name + "/" + p. name ) ;
394
+ }
241
395
}
242
396
243
397
fn cmd_install ( c : cargo , argv : [ str ] ) {
@@ -268,6 +422,29 @@ fn cmd_install(c: cargo, argv: [str]) {
268
422
}
269
423
}
270
424
425
+ fn sync_one ( c : cargo , name : str , src : source ) {
426
+ let dir = fs:: connect ( c. sourcedir , name) ;
427
+ let pkgfile = fs:: connect ( dir, "packages.json" ) ;
428
+ let url = src. url ;
429
+ need_dir ( dir) ;
430
+ let p = run:: program_output ( "curl" , [ "-f" , "-s" , "-o" , pkgfile, url] ) ;
431
+ if p. status != 0 {
432
+ warn ( #fmt[ "fetch for source %s (url %s) failed" , name, url] ) ;
433
+ } else {
434
+ info ( #fmt[ "fetched source: %s" , name] ) ;
435
+ }
436
+ }
437
+
438
+ fn cmd_sync ( c : cargo , argv : [ str ] ) {
439
+ if vec:: len ( argv) == 3 u {
440
+ sync_one ( c, argv[ 2 ] , c. sources . get ( argv[ 2 ] ) ) ;
441
+ } else {
442
+ c. sources . items { |k, v|
443
+ sync_one ( c, k, v) ;
444
+ }
445
+ }
446
+ }
447
+
271
448
fn cmd_usage ( ) {
272
449
print ( "Usage: cargo <verb> [args...]" ) ;
273
450
}
@@ -280,6 +457,7 @@ fn main(argv: [str]) {
280
457
let c = configure ( ) ;
281
458
alt argv[ 1 ] {
282
459
"install" { cmd_install ( c, argv) ; }
460
+ "sync" { cmd_sync ( c, argv) ; }
283
461
"usage" { cmd_usage ( ) ; }
284
462
_ { cmd_usage( ) ; }
285
463
}
0 commit comments