Skip to content

cargo: support installing, git://, github:<user>/<repo> #1278

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Closed
wants to merge 5 commits into from
Closed
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
138 changes: 112 additions & 26 deletions src/cargo/cargo.rs
Original file line number Diff line number Diff line change
Expand Up @@ -4,20 +4,31 @@ import rustc::syntax::{ast, codemap, visit};
import rustc::syntax::parse::parser;

import std::fs;
import std::generic_os;
import std::io;
import std::option;
import std::option::{none, some};
import std::os;
import std::run;
import std::str;
import std::tempfile;
import std::vec;

type cargo = {
root: str,
bindir: str,
libdir: str,
workdir: str,
fetchdir: str
};

type pkg = {
name: str,
vers: str,
uuid: str,
desc: option::t<str>,
sigs: option::t<str>
sigs: option::t<str>,
crate_type: option::t<str>
};

fn load_link(mis: [@ast::meta_item]) -> (option::t<str>,
Expand Down Expand Up @@ -50,13 +61,15 @@ fn load_pkg(filename: str) -> option::t<pkg> {
let uuid = none;
let desc = none;
let sigs = none;
let crate_type = none;

for a in c.node.attrs {
alt a.node.value.node {
ast::meta_name_value(v, {node: ast::lit_str(s), span: _}) {
alt v {
"desc" { desc = some(v); }
"sigs" { sigs = some(v); }
"crate_type" { crate_type = some(v); }
_ { }
}
}
Expand All @@ -78,7 +91,8 @@ fn load_pkg(filename: str) -> option::t<pkg> {
vers: vers0,
uuid: uuid0,
desc: desc,
sigs: sigs})
sigs: sigs,
crate_type: crate_type})
}
_ { ret none; }
}
Expand All @@ -96,50 +110,121 @@ fn rest(s: str, start: uint) -> str {
}
}

fn install_source(path: str) {
fn need_dir(s: str) {
if fs::file_is_dir(s) { ret; }
if !fs::make_dir(s, 0x1c0i32) {
fail #fmt["can't make_dir %s", s];
}
}

fn configure() -> cargo {
let p = alt generic_os::getenv("CARGO_ROOT") {
some(_p) { _p }
none. {
alt generic_os::getenv("HOME") {
some(_q) { fs::connect(_q, ".cargo") }
none. { fail "no CARGO_ROOT or HOME"; }
}
}
};

log #fmt["p: %s", p];

let c = {
root: p,
bindir: fs::connect(p, "bin"),
libdir: fs::connect(p, "lib"),
workdir: fs::connect(p, "work"),
fetchdir: fs::connect(p, "fetch")
};

need_dir(c.root);
need_dir(c.fetchdir);
need_dir(c.workdir);
need_dir(c.libdir);
need_dir(c.bindir);

c
}

fn install_one_crate(c: cargo, path: str, cf: str, p: pkg) {
let name = fs::basename(cf);
let ri = str::index(name, '.' as u8);
if ri != -1 {
name = str::slice(name, 0u, ri as uint);
}
log #fmt["Installing: %s", name];
let old = fs::list_dir(".");
run::run_program("rustc", [cf]);
let new = fs::list_dir(".");
let created = vec::filter::<str>({ |n| !vec::member::<str>(n, old) }, new);
for ct: str in created {
if str::ends_with(ct, os::exec_suffix()) {
log #fmt[" bin: %s", ct];
// FIXME: need libstd fs::copy or something
run::run_program("cp", [ct, c.bindir]);
} else {
log #fmt[" lib: %s", ct];
run::run_program("cp", [ct, c.libdir]);
}
}
}

fn install_source(c: cargo, path: str) {
log #fmt["source: %s", path];
fs::change_dir(path);
let contents = fs::list_dir(".");

log #fmt["contents: %s", str::connect(contents, ", ")];

let cratefile = vec::find::<str>({ |n| str::ends_with(n, ".rc") }, contents);
let cratefiles = vec::filter::<str>({ |n| str::ends_with(n, ".rc") }, contents);

// First, try a configure script:
if vec::member("./configure", contents) {
run::run_program("./configure", []);
if vec::is_empty(cratefiles) {
fail "This doesn't look like a rust package (no .rc files).";
}

// Makefile?
if vec::member("./Makefile", contents) {
run::run_program("make", ["RUSTC=rustc"]);
} else if option::is_some::<str>(cratefile) {
run::run_program("rustc", [option::get(cratefile)]);
for cf: str in cratefiles {
let p = load_pkg(cf);
alt p {
none. { cont; }
some(_p) {
install_one_crate(c, path, cf, _p);
}
}
}
}

fn install_file(_path: str) {
let wd = tempfile::mkdtemp("/tmp/cargo-work-", "");
alt wd {
some(p) {
run::run_program("tar", ["-x", "--strip-components=1",
"-C", p, "-f", _path]);
install_source(p);
}
_ { }
}
fn install_git(c: cargo, wd: str, _path: str) {
run::run_program("git", ["clone", _path, wd]);
install_source(c, wd);
}

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);
}

fn cmd_install(argv: [str]) {
fn cmd_install(c: cargo, argv: [str]) {
// cargo install <pkg>
if vec::len(argv) < 3u {
cmd_usage();
ret;
}

if str::starts_with(argv[2], "file:") {
let wd = alt tempfile::mkdtemp(c.workdir + fs::path_sep(), "") {
some(_wd) { _wd }
none. { fail "needed temp dir"; }
};

if str::starts_with(argv[2], "git:") {
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(path);
install_file(c, wd, path);
}
}

Expand All @@ -152,8 +237,9 @@ fn main(argv: [str]) {
cmd_usage();
ret;
}
let c = configure();
alt argv[1] {
"install" { cmd_install(argv); }
"install" { cmd_install(c, argv); }
"usage" { cmd_usage(); }
_ { cmd_usage(); }
}
Expand Down