Skip to content

Commit 8b7a41f

Browse files
author
Elly Jones
committed
cargo: Support distributed package indexes.
Indexes are listed in ~/.cargo/sources.json and ~/.cargo/local-sources.json, the former of which is stored in the rust source tree in src/cargo. Each entry in either of these files is a source, which is a dictionary with (currently) a single key, "url". The supplied url should point to a json list, each element of which should be a dictionary with four keys: "name", "uuid", "url", and "method". The name and uuid serve to identify the package; the method describes how to fetch the package; the url describes where to fetch it from. Currently supported methods are "git", "http", and "file". Signed-off-by: Elly Jones <[email protected]>
1 parent 10cf4a1 commit 8b7a41f

File tree

2 files changed

+135
-36
lines changed

2 files changed

+135
-36
lines changed

src/cargo/cargo.rs

Lines changed: 130 additions & 36 deletions
Original file line numberDiff line numberDiff line change
@@ -26,10 +26,11 @@ tag _src {
2626
}
2727

2828
type package = {
29-
source: _src,
29+
// source: _src,
3030
name: str,
3131
uuid: str,
32-
url: str
32+
url: str,
33+
method: str
3334
};
3435

3536
type source = {
@@ -64,6 +65,10 @@ fn warn(msg: str) {
6465
io::stdout().write_line("warning: " + msg);
6566
}
6667

68+
fn error(msg: str) {
69+
io::stdout().write_line("error: " + msg);
70+
}
71+
6772
fn load_link(mis: [@ast::meta_item]) -> (option::t<str>,
6873
option::t<str>,
6974
option::t<str>) {
@@ -179,7 +184,7 @@ fn try_parse_sources(filename: str, sources: map::hashmap<str, source>) {
179184
}
180185
}
181186

182-
fn load_one_source_package(c: cargo, src: source, p: map::hashmap<str, json::json>) {
187+
fn load_one_source_package(&c: cargo, &src: source, p: map::hashmap<str, json::json>) {
183188
let name = alt p.find("name") {
184189
some(json::string(_n)) { _n }
185190
_ {
@@ -204,16 +209,25 @@ fn load_one_source_package(c: cargo, src: source, p: map::hashmap<str, json::jso
204209
}
205210
};
206211

212+
let method = alt p.find("method") {
213+
some(json::string(_n)) { _n }
214+
_ {
215+
warn("Malformed source json: " + src.name + " (missing method)");
216+
ret;
217+
}
218+
};
219+
207220
vec::grow(src.packages, 1u, {
208-
source: _source(src),
221+
// source: _source(src),
209222
name: name,
210223
uuid: uuid,
211-
url: url
224+
url: url,
225+
method: method
212226
});
213227
info(" Loaded package: " + src.name + "/" + name);
214228
}
215229

216-
fn load_source_packages(c: cargo, src: source) {
230+
fn load_source_packages(&c: cargo, &src: source) {
217231
info("Loading source: " + src.name);
218232
let dir = fs::connect(c.sourcedir, src.name);
219233
let pkgfile = fs::connect(dir, "packages.json");
@@ -229,7 +243,6 @@ fn load_source_packages(c: cargo, src: source) {
229243
}
230244
_ {
231245
warn("Malformed source json: " + src.name + " (non-dict pkg)");
232-
ret;
233246
}
234247
}
235248
}
@@ -269,17 +282,19 @@ fn configure() -> cargo {
269282
need_dir(c.libdir);
270283
need_dir(c.bindir);
271284

272-
sources.values { |v|
273-
load_source_packages(c, v);
285+
sources.keys { |k|
286+
let s = sources.get(k);
287+
load_source_packages(c, s);
288+
sources.insert(k, s);
274289
};
275290

276291
c
277292
}
278293

279-
fn for_each_package(c: cargo, b: block(package)) {
294+
fn for_each_package(c: cargo, b: block(source, package)) {
280295
c.sources.values({ |v|
281296
for p in v.packages {
282-
b(p);
297+
b(v, p);
283298
}
284299
})
285300
}
@@ -335,14 +350,25 @@ fn install_source(c: cargo, path: str) {
335350
}
336351
}
337352

338-
fn install_git(c: cargo, wd: str, _path: str) {
339-
run::run_program("git", ["clone", _path, wd]);
353+
fn install_git(c: cargo, wd: str, url: str) {
354+
run::run_program("git", ["clone", url, wd]);
340355
install_source(c, wd);
341356
}
342357

343-
fn install_file(c: cargo, wd: str, _path: str) {
358+
fn install_curl(c: cargo, wd: str, url: str) {
359+
let tarpath = fs::connect(wd, "pkg.tar");
360+
let p = run::program_output("curl", ["-f", "-s", "-o",
361+
tarpath, url]);
362+
if p.status != 0 {
363+
fail #fmt["Fetch of %s failed: %s", url, p.err];
364+
}
344365
run::run_program("tar", ["-x", "--strip-components=1",
345-
"-C", wd, "-f", _path]);
366+
"-C", wd, "-f", tarpath]);
367+
}
368+
369+
fn install_file(c: cargo, wd: str, path: str) {
370+
run::run_program("tar", ["-x", "--strip-components=1",
371+
"-C", wd, "-f", path]);
346372
install_source(c, wd);
347373
}
348374

@@ -368,30 +394,90 @@ fn install_resolved(c: cargo, wd: str, key: str) {
368394
}
369395
}
370396

397+
fn install_package(c: cargo, wd: str, pkg: package) {
398+
info("Installing with " + pkg.method + " from " + pkg.url + "...");
399+
if pkg.method == "git" {
400+
install_git(c, wd, pkg.url);
401+
} else if pkg.method == "http" {
402+
install_curl(c, wd, pkg.url);
403+
} else if pkg.method == "file" {
404+
install_file(c, wd, pkg.url);
405+
}
406+
}
407+
371408
fn install_uuid(c: cargo, wd: str, uuid: str) {
372409
let ps = [];
373-
for_each_package(c, { |p|
410+
for_each_package(c, { |s, p|
411+
info(#fmt["%s ? %s", p.uuid, uuid]);
374412
if p.uuid == uuid {
375-
vec::grow(ps, 1u, p);
413+
vec::grow(ps, 1u, (s, p));
376414
}
377415
});
378-
info("Found:");
379-
for p in ps {
380-
info(" " + p.source.name + "/" + p.name);
416+
if vec::len(ps) == 1u {
417+
let (s, p) = ps[0];
418+
install_package(c, wd, p);
419+
ret;
420+
} else if vec::len(ps) == 0u {
421+
error("No packages.");
422+
ret;
423+
}
424+
error("Found multiple packages:");
425+
for (s,p) in ps {
426+
info(" " + s.name + "/" + p.uuid + " (" + p.name + ")");
381427
}
382428
}
383429

384430
fn install_named(c: cargo, wd: str, name: str) {
385431
let ps = [];
386-
for_each_package(c, { |p|
432+
for_each_package(c, { |s, p|
387433
if p.name == name {
388-
vec::grow(ps, 1u, p);
434+
vec::grow(ps, 1u, (s, p));
389435
}
390436
});
391-
info("Found:");
392-
for p in ps {
393-
info(" " + p.source.name + "/" + p.name);
437+
if vec::len(ps) == 1u {
438+
let (s, p) = ps[0];
439+
install_package(c, wd, p);
440+
ret;
441+
} else if vec::len(ps) == 0u {
442+
error("No packages.");
443+
ret;
444+
}
445+
error("Found multiple packages:");
446+
for (s,p) in ps {
447+
info(" " + s.name + "/" + p.uuid + " (" + p.name + ")");
448+
}
449+
}
450+
451+
fn install_uuid_specific(c: cargo, wd: str, src: str, uuid: str) {
452+
alt c.sources.find(src) {
453+
some(s) {
454+
if vec::any(s.packages, { |p|
455+
if p.uuid == uuid {
456+
install_package(c, wd, p);
457+
ret true;
458+
}
459+
ret false;
460+
}) { ret; }
461+
}
462+
_ { }
394463
}
464+
error("Can't find package " + src + "/" + uuid);
465+
}
466+
467+
fn install_named_specific(c: cargo, wd: str, src: str, name: str) {
468+
alt c.sources.find(src) {
469+
some(s) {
470+
if vec::any(s.packages, { |p|
471+
if p.name == name {
472+
install_package(c, wd, p);
473+
ret true;
474+
}
475+
ret false;
476+
}) { ret; }
477+
}
478+
_ { }
479+
}
480+
error("Can't find package " + src + "/" + name);
395481
}
396482

397483
fn cmd_install(c: cargo, argv: [str]) {
@@ -406,19 +492,26 @@ fn cmd_install(c: cargo, argv: [str]) {
406492
none. { fail "needed temp dir"; }
407493
};
408494

409-
if str::starts_with(argv[2], "git:") {
410-
install_git(c, wd, argv[2]);
411-
} else if str::starts_with(argv[2], "github:") {
412-
let path = rest(argv[2], 7u);
413-
install_git(c, wd, "git://github.com/" + path);
414-
} else if str::starts_with(argv[2], "file:") {
415-
let path = rest(argv[2], 5u);
416-
install_file(c, wd, path);
417-
} else if str::starts_with(argv[2], "uuid:") {
495+
if str::starts_with(argv[2], "uuid:") {
418496
let uuid = rest(argv[2], 5u);
419-
install_uuid(c, wd, uuid);
497+
let idx = str::index(uuid, '/' as u8);
498+
if idx != -1 {
499+
let source = str::slice(uuid, 0u, idx as uint);
500+
uuid = str::slice(uuid, idx as uint + 1u, str::byte_len(uuid));
501+
install_uuid_specific(c, wd, source, uuid);
502+
} else {
503+
install_uuid(c, wd, uuid);
504+
}
420505
} else {
421-
install_named(c, wd, argv[2]);
506+
let name = argv[2];
507+
let idx = str::index(name, '/' as u8);
508+
if idx != -1 {
509+
let source = str::slice(name, 0u, idx as uint);
510+
name = str::slice(name, idx as uint + 1u, str::byte_len(name));
511+
install_named_specific(c, wd, source, name);
512+
} else {
513+
install_named(c, wd, name);
514+
}
422515
}
423516
}
424517

@@ -427,6 +520,7 @@ fn sync_one(c: cargo, name: str, src: source) {
427520
let pkgfile = fs::connect(dir, "packages.json");
428521
let url = src.url;
429522
need_dir(dir);
523+
info(#fmt["fetching source %s...", name]);
430524
let p = run::program_output("curl", ["-f", "-s", "-o", pkgfile, url]);
431525
if p.status != 0 {
432526
warn(#fmt["fetch for source %s (url %s) failed", name, url]);

src/cargo/sources.json

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
{
2+
"elly": {
3+
"url": "https://raw.github.com/elly/rust-packages/master/packages.json"
4+
}
5+
}

0 commit comments

Comments
 (0)