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 <elly@leptoquark.net>
This commit is contained in:
parent
10cf4a1b0a
commit
8b7a41f23d
@ -26,10 +26,11 @@ tag _src {
|
|||||||
}
|
}
|
||||||
|
|
||||||
type package = {
|
type package = {
|
||||||
source: _src,
|
// source: _src,
|
||||||
name: str,
|
name: str,
|
||||||
uuid: str,
|
uuid: str,
|
||||||
url: str
|
url: str,
|
||||||
|
method: str
|
||||||
};
|
};
|
||||||
|
|
||||||
type source = {
|
type source = {
|
||||||
@ -64,6 +65,10 @@ fn warn(msg: str) {
|
|||||||
io::stdout().write_line("warning: " + msg);
|
io::stdout().write_line("warning: " + msg);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fn error(msg: str) {
|
||||||
|
io::stdout().write_line("error: " + msg);
|
||||||
|
}
|
||||||
|
|
||||||
fn load_link(mis: [@ast::meta_item]) -> (option::t<str>,
|
fn load_link(mis: [@ast::meta_item]) -> (option::t<str>,
|
||||||
option::t<str>,
|
option::t<str>,
|
||||||
option::t<str>) {
|
option::t<str>) {
|
||||||
@ -179,7 +184,7 @@ fn try_parse_sources(filename: str, sources: map::hashmap<str, source>) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fn load_one_source_package(c: cargo, src: source, p: map::hashmap<str, json::json>) {
|
fn load_one_source_package(&c: cargo, &src: source, p: map::hashmap<str, json::json>) {
|
||||||
let name = alt p.find("name") {
|
let name = alt p.find("name") {
|
||||||
some(json::string(_n)) { _n }
|
some(json::string(_n)) { _n }
|
||||||
_ {
|
_ {
|
||||||
@ -204,16 +209,25 @@ fn load_one_source_package(c: cargo, src: source, p: map::hashmap<str, json::jso
|
|||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
let method = alt p.find("method") {
|
||||||
|
some(json::string(_n)) { _n }
|
||||||
|
_ {
|
||||||
|
warn("Malformed source json: " + src.name + " (missing method)");
|
||||||
|
ret;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
vec::grow(src.packages, 1u, {
|
vec::grow(src.packages, 1u, {
|
||||||
source: _source(src),
|
// source: _source(src),
|
||||||
name: name,
|
name: name,
|
||||||
uuid: uuid,
|
uuid: uuid,
|
||||||
url: url
|
url: url,
|
||||||
|
method: method
|
||||||
});
|
});
|
||||||
info(" Loaded package: " + src.name + "/" + name);
|
info(" Loaded package: " + src.name + "/" + name);
|
||||||
}
|
}
|
||||||
|
|
||||||
fn load_source_packages(c: cargo, src: source) {
|
fn load_source_packages(&c: cargo, &src: source) {
|
||||||
info("Loading source: " + src.name);
|
info("Loading source: " + src.name);
|
||||||
let dir = fs::connect(c.sourcedir, src.name);
|
let dir = fs::connect(c.sourcedir, src.name);
|
||||||
let pkgfile = fs::connect(dir, "packages.json");
|
let pkgfile = fs::connect(dir, "packages.json");
|
||||||
@ -229,7 +243,6 @@ fn load_source_packages(c: cargo, src: source) {
|
|||||||
}
|
}
|
||||||
_ {
|
_ {
|
||||||
warn("Malformed source json: " + src.name + " (non-dict pkg)");
|
warn("Malformed source json: " + src.name + " (non-dict pkg)");
|
||||||
ret;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -269,17 +282,19 @@ fn configure() -> cargo {
|
|||||||
need_dir(c.libdir);
|
need_dir(c.libdir);
|
||||||
need_dir(c.bindir);
|
need_dir(c.bindir);
|
||||||
|
|
||||||
sources.values { |v|
|
sources.keys { |k|
|
||||||
load_source_packages(c, v);
|
let s = sources.get(k);
|
||||||
|
load_source_packages(c, s);
|
||||||
|
sources.insert(k, s);
|
||||||
};
|
};
|
||||||
|
|
||||||
c
|
c
|
||||||
}
|
}
|
||||||
|
|
||||||
fn for_each_package(c: cargo, b: block(package)) {
|
fn for_each_package(c: cargo, b: block(source, package)) {
|
||||||
c.sources.values({ |v|
|
c.sources.values({ |v|
|
||||||
for p in v.packages {
|
for p in v.packages {
|
||||||
b(p);
|
b(v, p);
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
@ -335,14 +350,25 @@ fn install_source(c: cargo, path: str) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fn install_git(c: cargo, wd: str, _path: str) {
|
fn install_git(c: cargo, wd: str, url: str) {
|
||||||
run::run_program("git", ["clone", _path, wd]);
|
run::run_program("git", ["clone", url, wd]);
|
||||||
install_source(c, wd);
|
install_source(c, wd);
|
||||||
}
|
}
|
||||||
|
|
||||||
fn install_file(c: cargo, wd: str, _path: str) {
|
fn install_curl(c: cargo, wd: str, url: str) {
|
||||||
|
let tarpath = fs::connect(wd, "pkg.tar");
|
||||||
|
let p = run::program_output("curl", ["-f", "-s", "-o",
|
||||||
|
tarpath, url]);
|
||||||
|
if p.status != 0 {
|
||||||
|
fail #fmt["Fetch of %s failed: %s", url, p.err];
|
||||||
|
}
|
||||||
run::run_program("tar", ["-x", "--strip-components=1",
|
run::run_program("tar", ["-x", "--strip-components=1",
|
||||||
"-C", wd, "-f", _path]);
|
"-C", wd, "-f", tarpath]);
|
||||||
|
}
|
||||||
|
|
||||||
|
fn install_file(c: cargo, wd: str, path: str) {
|
||||||
|
run::run_program("tar", ["-x", "--strip-components=1",
|
||||||
|
"-C", wd, "-f", path]);
|
||||||
install_source(c, wd);
|
install_source(c, wd);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -368,30 +394,90 @@ fn install_resolved(c: cargo, wd: str, key: str) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fn install_package(c: cargo, wd: str, pkg: package) {
|
||||||
|
info("Installing with " + pkg.method + " from " + pkg.url + "...");
|
||||||
|
if pkg.method == "git" {
|
||||||
|
install_git(c, wd, pkg.url);
|
||||||
|
} else if pkg.method == "http" {
|
||||||
|
install_curl(c, wd, pkg.url);
|
||||||
|
} else if pkg.method == "file" {
|
||||||
|
install_file(c, wd, pkg.url);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
fn install_uuid(c: cargo, wd: str, uuid: str) {
|
fn install_uuid(c: cargo, wd: str, uuid: str) {
|
||||||
let ps = [];
|
let ps = [];
|
||||||
for_each_package(c, { |p|
|
for_each_package(c, { |s, p|
|
||||||
|
info(#fmt["%s ? %s", p.uuid, uuid]);
|
||||||
if p.uuid == uuid {
|
if p.uuid == uuid {
|
||||||
vec::grow(ps, 1u, p);
|
vec::grow(ps, 1u, (s, p));
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
info("Found:");
|
if vec::len(ps) == 1u {
|
||||||
for p in ps {
|
let (s, p) = ps[0];
|
||||||
info(" " + p.source.name + "/" + p.name);
|
install_package(c, wd, p);
|
||||||
|
ret;
|
||||||
|
} else if vec::len(ps) == 0u {
|
||||||
|
error("No packages.");
|
||||||
|
ret;
|
||||||
|
}
|
||||||
|
error("Found multiple packages:");
|
||||||
|
for (s,p) in ps {
|
||||||
|
info(" " + s.name + "/" + p.uuid + " (" + p.name + ")");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fn install_named(c: cargo, wd: str, name: str) {
|
fn install_named(c: cargo, wd: str, name: str) {
|
||||||
let ps = [];
|
let ps = [];
|
||||||
for_each_package(c, { |p|
|
for_each_package(c, { |s, p|
|
||||||
if p.name == name {
|
if p.name == name {
|
||||||
vec::grow(ps, 1u, p);
|
vec::grow(ps, 1u, (s, p));
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
info("Found:");
|
if vec::len(ps) == 1u {
|
||||||
for p in ps {
|
let (s, p) = ps[0];
|
||||||
info(" " + p.source.name + "/" + p.name);
|
install_package(c, wd, p);
|
||||||
|
ret;
|
||||||
|
} else if vec::len(ps) == 0u {
|
||||||
|
error("No packages.");
|
||||||
|
ret;
|
||||||
}
|
}
|
||||||
|
error("Found multiple packages:");
|
||||||
|
for (s,p) in ps {
|
||||||
|
info(" " + s.name + "/" + p.uuid + " (" + p.name + ")");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn install_uuid_specific(c: cargo, wd: str, src: str, uuid: str) {
|
||||||
|
alt c.sources.find(src) {
|
||||||
|
some(s) {
|
||||||
|
if vec::any(s.packages, { |p|
|
||||||
|
if p.uuid == uuid {
|
||||||
|
install_package(c, wd, p);
|
||||||
|
ret true;
|
||||||
|
}
|
||||||
|
ret false;
|
||||||
|
}) { ret; }
|
||||||
|
}
|
||||||
|
_ { }
|
||||||
|
}
|
||||||
|
error("Can't find package " + src + "/" + uuid);
|
||||||
|
}
|
||||||
|
|
||||||
|
fn install_named_specific(c: cargo, wd: str, src: str, name: str) {
|
||||||
|
alt c.sources.find(src) {
|
||||||
|
some(s) {
|
||||||
|
if vec::any(s.packages, { |p|
|
||||||
|
if p.name == name {
|
||||||
|
install_package(c, wd, p);
|
||||||
|
ret true;
|
||||||
|
}
|
||||||
|
ret false;
|
||||||
|
}) { ret; }
|
||||||
|
}
|
||||||
|
_ { }
|
||||||
|
}
|
||||||
|
error("Can't find package " + src + "/" + name);
|
||||||
}
|
}
|
||||||
|
|
||||||
fn cmd_install(c: cargo, argv: [str]) {
|
fn cmd_install(c: cargo, argv: [str]) {
|
||||||
@ -406,19 +492,26 @@ fn cmd_install(c: cargo, argv: [str]) {
|
|||||||
none. { fail "needed temp dir"; }
|
none. { fail "needed temp dir"; }
|
||||||
};
|
};
|
||||||
|
|
||||||
if str::starts_with(argv[2], "git:") {
|
if str::starts_with(argv[2], "uuid:") {
|
||||||
install_git(c, wd, argv[2]);
|
|
||||||
} else if str::starts_with(argv[2], "github:") {
|
|
||||||
let path = rest(argv[2], 7u);
|
|
||||||
install_git(c, wd, "git://github.com/" + path);
|
|
||||||
} else if str::starts_with(argv[2], "file:") {
|
|
||||||
let path = rest(argv[2], 5u);
|
|
||||||
install_file(c, wd, path);
|
|
||||||
} else if str::starts_with(argv[2], "uuid:") {
|
|
||||||
let uuid = rest(argv[2], 5u);
|
let uuid = rest(argv[2], 5u);
|
||||||
install_uuid(c, wd, uuid);
|
let idx = str::index(uuid, '/' as u8);
|
||||||
|
if idx != -1 {
|
||||||
|
let source = str::slice(uuid, 0u, idx as uint);
|
||||||
|
uuid = str::slice(uuid, idx as uint + 1u, str::byte_len(uuid));
|
||||||
|
install_uuid_specific(c, wd, source, uuid);
|
||||||
|
} else {
|
||||||
|
install_uuid(c, wd, uuid);
|
||||||
|
}
|
||||||
} else {
|
} else {
|
||||||
install_named(c, wd, argv[2]);
|
let name = argv[2];
|
||||||
|
let idx = str::index(name, '/' as u8);
|
||||||
|
if idx != -1 {
|
||||||
|
let source = str::slice(name, 0u, idx as uint);
|
||||||
|
name = str::slice(name, idx as uint + 1u, str::byte_len(name));
|
||||||
|
install_named_specific(c, wd, source, name);
|
||||||
|
} else {
|
||||||
|
install_named(c, wd, name);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -427,6 +520,7 @@ fn sync_one(c: cargo, name: str, src: source) {
|
|||||||
let pkgfile = fs::connect(dir, "packages.json");
|
let pkgfile = fs::connect(dir, "packages.json");
|
||||||
let url = src.url;
|
let url = src.url;
|
||||||
need_dir(dir);
|
need_dir(dir);
|
||||||
|
info(#fmt["fetching source %s...", name]);
|
||||||
let p = run::program_output("curl", ["-f", "-s", "-o", pkgfile, url]);
|
let p = run::program_output("curl", ["-f", "-s", "-o", pkgfile, url]);
|
||||||
if p.status != 0 {
|
if p.status != 0 {
|
||||||
warn(#fmt["fetch for source %s (url %s) failed", name, url]);
|
warn(#fmt["fetch for source %s (url %s) failed", name, url]);
|
||||||
|
5
src/cargo/sources.json
Normal file
5
src/cargo/sources.json
Normal file
@ -0,0 +1,5 @@
|
|||||||
|
{
|
||||||
|
"elly": {
|
||||||
|
"url": "https://raw.github.com/elly/rust-packages/master/packages.json"
|
||||||
|
}
|
||||||
|
}
|
Loading…
Reference in New Issue
Block a user