mirror of
https://github.com/rust-lang/rust.git
synced 2025-01-20 11:43:04 +00:00
auto merge of #9034 : catamorphism/rust/rustpkg-workcache, r=metajack
r? @metajack or @brson - This pull request makes rustpkg use the workcache library to avoid recompilation.
This commit is contained in:
commit
8c7c0b41d7
@ -12,17 +12,15 @@
|
|||||||
|
|
||||||
use digest::Digest;
|
use digest::Digest;
|
||||||
use json;
|
use json;
|
||||||
|
use json::ToJson;
|
||||||
use sha1::Sha1;
|
use sha1::Sha1;
|
||||||
use serialize::{Encoder, Encodable, Decoder, Decodable};
|
use serialize::{Encoder, Encodable, Decoder, Decodable};
|
||||||
use arc::{Arc,RWArc};
|
use arc::{Arc,RWArc};
|
||||||
use treemap::TreeMap;
|
use treemap::TreeMap;
|
||||||
|
|
||||||
use std::cell::Cell;
|
use std::cell::Cell;
|
||||||
use std::comm::{PortOne, oneshot};
|
use std::comm::{PortOne, oneshot};
|
||||||
use std::either::{Either, Left, Right};
|
use std::either::{Either, Left, Right};
|
||||||
use std::io;
|
use std::{io, os, task};
|
||||||
use std::run;
|
|
||||||
use std::task;
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
*
|
*
|
||||||
@ -107,11 +105,27 @@ impl WorkKey {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// FIXME #8883: The key should be a WorkKey and not a ~str.
|
||||||
|
// This is working around some JSON weirdness.
|
||||||
#[deriving(Clone, Eq, Encodable, Decodable)]
|
#[deriving(Clone, Eq, Encodable, Decodable)]
|
||||||
struct WorkMap(TreeMap<WorkKey, ~str>);
|
struct WorkMap(TreeMap<~str, KindMap>);
|
||||||
|
|
||||||
|
#[deriving(Clone, Eq, Encodable, Decodable)]
|
||||||
|
struct KindMap(TreeMap<~str, ~str>);
|
||||||
|
|
||||||
impl WorkMap {
|
impl WorkMap {
|
||||||
fn new() -> WorkMap { WorkMap(TreeMap::new()) }
|
fn new() -> WorkMap { WorkMap(TreeMap::new()) }
|
||||||
|
|
||||||
|
fn insert_work_key(&mut self, k: WorkKey, val: ~str) {
|
||||||
|
let WorkKey { kind, name } = k;
|
||||||
|
match self.find_mut(&name) {
|
||||||
|
Some(&KindMap(ref mut m)) => { m.insert(kind, val); return; }
|
||||||
|
None => ()
|
||||||
|
}
|
||||||
|
let mut new_map = TreeMap::new();
|
||||||
|
new_map.insert(kind, val);
|
||||||
|
self.insert(name, KindMap(new_map));
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
struct Database {
|
struct Database {
|
||||||
@ -123,11 +137,15 @@ struct Database {
|
|||||||
impl Database {
|
impl Database {
|
||||||
|
|
||||||
pub fn new(p: Path) -> Database {
|
pub fn new(p: Path) -> Database {
|
||||||
Database {
|
let mut rslt = Database {
|
||||||
db_filename: p,
|
db_filename: p,
|
||||||
db_cache: TreeMap::new(),
|
db_cache: TreeMap::new(),
|
||||||
db_dirty: false
|
db_dirty: false
|
||||||
|
};
|
||||||
|
if os::path_exists(&rslt.db_filename) {
|
||||||
|
rslt.load();
|
||||||
}
|
}
|
||||||
|
rslt
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn prepare(&self,
|
pub fn prepare(&self,
|
||||||
@ -154,6 +172,41 @@ impl Database {
|
|||||||
self.db_cache.insert(k,v);
|
self.db_cache.insert(k,v);
|
||||||
self.db_dirty = true
|
self.db_dirty = true
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// FIXME #4330: This should have &mut self and should set self.db_dirty to false.
|
||||||
|
fn save(&self) {
|
||||||
|
let f = io::file_writer(&self.db_filename, [io::Create, io::Truncate]).unwrap();
|
||||||
|
self.db_cache.to_json().to_pretty_writer(f);
|
||||||
|
}
|
||||||
|
|
||||||
|
fn load(&mut self) {
|
||||||
|
assert!(!self.db_dirty);
|
||||||
|
assert!(os::path_exists(&self.db_filename));
|
||||||
|
let f = io::file_reader(&self.db_filename);
|
||||||
|
match f {
|
||||||
|
Err(e) => fail!("Couldn't load workcache database %s: %s",
|
||||||
|
self.db_filename.to_str(), e.to_str()),
|
||||||
|
Ok(r) =>
|
||||||
|
match json::from_reader(r) {
|
||||||
|
Err(e) => fail!("Couldn't parse workcache database (from file %s): %s",
|
||||||
|
self.db_filename.to_str(), e.to_str()),
|
||||||
|
Ok(r) => {
|
||||||
|
let mut decoder = json::Decoder(r);
|
||||||
|
self.db_cache = Decodable::decode(&mut decoder);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// FIXME #4330: use &mut self here
|
||||||
|
#[unsafe_destructor]
|
||||||
|
impl Drop for Database {
|
||||||
|
fn drop(&self) {
|
||||||
|
if self.db_dirty {
|
||||||
|
self.save();
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
struct Logger {
|
struct Logger {
|
||||||
@ -172,12 +225,20 @@ impl Logger {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
type FreshnessMap = TreeMap<~str,extern fn(&str,&str)->bool>;
|
||||||
|
|
||||||
#[deriving(Clone)]
|
#[deriving(Clone)]
|
||||||
struct Context {
|
struct Context {
|
||||||
db: RWArc<Database>,
|
db: RWArc<Database>,
|
||||||
logger: RWArc<Logger>,
|
logger: RWArc<Logger>,
|
||||||
cfg: Arc<json::Object>,
|
cfg: Arc<json::Object>,
|
||||||
freshness: Arc<TreeMap<~str,extern fn(&str,&str)->bool>>
|
/// Map from kinds (source, exe, url, etc.) to a freshness function.
|
||||||
|
/// The freshness function takes a name (e.g. file path) and value
|
||||||
|
/// (e.g. hash of file contents) and determines whether it's up-to-date.
|
||||||
|
/// For example, in the file case, this would read the file off disk,
|
||||||
|
/// hash it, and return the result of comparing the given hash and the
|
||||||
|
/// read hash for equality.
|
||||||
|
freshness: Arc<FreshnessMap>
|
||||||
}
|
}
|
||||||
|
|
||||||
struct Prep<'self> {
|
struct Prep<'self> {
|
||||||
@ -205,6 +266,7 @@ fn json_encode<T:Encodable<json::Encoder>>(t: &T) -> ~str {
|
|||||||
|
|
||||||
// FIXME(#5121)
|
// FIXME(#5121)
|
||||||
fn json_decode<T:Decodable<json::Decoder>>(s: &str) -> T {
|
fn json_decode<T:Decodable<json::Decoder>>(s: &str) -> T {
|
||||||
|
debug!("json decoding: %s", s);
|
||||||
do io::with_str_reader(s) |rdr| {
|
do io::with_str_reader(s) |rdr| {
|
||||||
let j = json::from_reader(rdr).unwrap();
|
let j = json::from_reader(rdr).unwrap();
|
||||||
let mut decoder = json::Decoder(j);
|
let mut decoder = json::Decoder(j);
|
||||||
@ -230,11 +292,18 @@ impl Context {
|
|||||||
pub fn new(db: RWArc<Database>,
|
pub fn new(db: RWArc<Database>,
|
||||||
lg: RWArc<Logger>,
|
lg: RWArc<Logger>,
|
||||||
cfg: Arc<json::Object>) -> Context {
|
cfg: Arc<json::Object>) -> Context {
|
||||||
|
Context::new_with_freshness(db, lg, cfg, Arc::new(TreeMap::new()))
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn new_with_freshness(db: RWArc<Database>,
|
||||||
|
lg: RWArc<Logger>,
|
||||||
|
cfg: Arc<json::Object>,
|
||||||
|
freshness: Arc<FreshnessMap>) -> Context {
|
||||||
Context {
|
Context {
|
||||||
db: db,
|
db: db,
|
||||||
logger: lg,
|
logger: lg,
|
||||||
cfg: cfg,
|
cfg: cfg,
|
||||||
freshness: Arc::new(TreeMap::new())
|
freshness: freshness
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -249,6 +318,36 @@ impl Context {
|
|||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
impl Exec {
|
||||||
|
pub fn discover_input(&mut self,
|
||||||
|
dependency_kind: &str,
|
||||||
|
dependency_name: &str,
|
||||||
|
dependency_val: &str) {
|
||||||
|
debug!("Discovering input %s %s %s", dependency_kind, dependency_name, dependency_val);
|
||||||
|
self.discovered_inputs.insert_work_key(WorkKey::new(dependency_kind, dependency_name),
|
||||||
|
dependency_val.to_owned());
|
||||||
|
}
|
||||||
|
pub fn discover_output(&mut self,
|
||||||
|
dependency_kind: &str,
|
||||||
|
dependency_name: &str,
|
||||||
|
dependency_val: &str) {
|
||||||
|
debug!("Discovering output %s %s %s", dependency_kind, dependency_name, dependency_val);
|
||||||
|
self.discovered_outputs.insert_work_key(WorkKey::new(dependency_kind, dependency_name),
|
||||||
|
dependency_val.to_owned());
|
||||||
|
}
|
||||||
|
|
||||||
|
// returns pairs of (kind, name)
|
||||||
|
pub fn lookup_discovered_inputs(&self) -> ~[(~str, ~str)] {
|
||||||
|
let mut rs = ~[];
|
||||||
|
for (k, v) in self.discovered_inputs.iter() {
|
||||||
|
for (k1, _) in v.iter() {
|
||||||
|
rs.push((k1.clone(), k.clone()));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
rs
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
impl<'self> Prep<'self> {
|
impl<'self> Prep<'self> {
|
||||||
fn new(ctxt: &'self Context, fn_name: &'self str) -> Prep<'self> {
|
fn new(ctxt: &'self Context, fn_name: &'self str) -> Prep<'self> {
|
||||||
Prep {
|
Prep {
|
||||||
@ -257,11 +356,22 @@ impl<'self> Prep<'self> {
|
|||||||
declared_inputs: WorkMap::new()
|
declared_inputs: WorkMap::new()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub fn lookup_declared_inputs(&self) -> ~[~str] {
|
||||||
|
let mut rs = ~[];
|
||||||
|
for (_, v) in self.declared_inputs.iter() {
|
||||||
|
for (inp, _) in v.iter() {
|
||||||
|
rs.push(inp.clone());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
rs
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<'self> Prep<'self> {
|
impl<'self> Prep<'self> {
|
||||||
fn declare_input(&mut self, kind:&str, name:&str, val:&str) {
|
pub fn declare_input(&mut self, kind: &str, name: &str, val: &str) {
|
||||||
self.declared_inputs.insert(WorkKey::new(kind, name),
|
debug!("Declaring input %s %s %s", kind, name, val);
|
||||||
|
self.declared_inputs.insert_work_key(WorkKey::new(kind, name),
|
||||||
val.to_owned());
|
val.to_owned());
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -269,6 +379,7 @@ impl<'self> Prep<'self> {
|
|||||||
name: &str, val: &str) -> bool {
|
name: &str, val: &str) -> bool {
|
||||||
let k = kind.to_owned();
|
let k = kind.to_owned();
|
||||||
let f = self.ctxt.freshness.get().find(&k);
|
let f = self.ctxt.freshness.get().find(&k);
|
||||||
|
debug!("freshness for: %s/%s/%s/%s", cat, kind, name, val)
|
||||||
let fresh = match f {
|
let fresh = match f {
|
||||||
None => fail!("missing freshness-function for '%s'", kind),
|
None => fail!("missing freshness-function for '%s'", kind),
|
||||||
Some(f) => (*f)(name, val)
|
Some(f) => (*f)(name, val)
|
||||||
@ -286,27 +397,31 @@ impl<'self> Prep<'self> {
|
|||||||
}
|
}
|
||||||
|
|
||||||
fn all_fresh(&self, cat: &str, map: &WorkMap) -> bool {
|
fn all_fresh(&self, cat: &str, map: &WorkMap) -> bool {
|
||||||
for (k, v) in map.iter() {
|
for (k_name, kindmap) in map.iter() {
|
||||||
if ! self.is_fresh(cat, k.kind, k.name, *v) {
|
for (k_kind, v) in kindmap.iter() {
|
||||||
return false;
|
if ! self.is_fresh(cat, *k_kind, *k_name, *v) {
|
||||||
|
return false;
|
||||||
}
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
fn exec<T:Send +
|
pub fn exec<T:Send +
|
||||||
Encodable<json::Encoder> +
|
Encodable<json::Encoder> +
|
||||||
Decodable<json::Decoder>>(
|
Decodable<json::Decoder>>(
|
||||||
&'self self, blk: ~fn(&Exec) -> T) -> T {
|
&'self self, blk: ~fn(&mut Exec) -> T) -> T {
|
||||||
self.exec_work(blk).unwrap()
|
self.exec_work(blk).unwrap()
|
||||||
}
|
}
|
||||||
|
|
||||||
fn exec_work<T:Send +
|
fn exec_work<T:Send +
|
||||||
Encodable<json::Encoder> +
|
Encodable<json::Encoder> +
|
||||||
Decodable<json::Decoder>>( // FIXME(#5121)
|
Decodable<json::Decoder>>( // FIXME(#5121)
|
||||||
&'self self, blk: ~fn(&Exec) -> T) -> Work<'self, T> {
|
&'self self, blk: ~fn(&mut Exec) -> T) -> Work<'self, T> {
|
||||||
let mut bo = Some(blk);
|
let mut bo = Some(blk);
|
||||||
|
|
||||||
|
debug!("exec_work: looking up %s and %?", self.fn_name,
|
||||||
|
self.declared_inputs);
|
||||||
let cached = do self.ctxt.db.read |db| {
|
let cached = do self.ctxt.db.read |db| {
|
||||||
db.prepare(self.fn_name, &self.declared_inputs)
|
db.prepare(self.fn_name, &self.declared_inputs)
|
||||||
};
|
};
|
||||||
@ -316,21 +431,26 @@ impl<'self> Prep<'self> {
|
|||||||
if self.all_fresh("declared input",&self.declared_inputs) &&
|
if self.all_fresh("declared input",&self.declared_inputs) &&
|
||||||
self.all_fresh("discovered input", disc_in) &&
|
self.all_fresh("discovered input", disc_in) &&
|
||||||
self.all_fresh("discovered output", disc_out) => {
|
self.all_fresh("discovered output", disc_out) => {
|
||||||
|
debug!("Cache hit!");
|
||||||
|
debug!("Trying to decode: %? / %? / %?",
|
||||||
|
disc_in, disc_out, *res);
|
||||||
Left(json_decode(*res))
|
Left(json_decode(*res))
|
||||||
}
|
}
|
||||||
|
|
||||||
_ => {
|
_ => {
|
||||||
|
debug!("Cache miss!");
|
||||||
let (port, chan) = oneshot();
|
let (port, chan) = oneshot();
|
||||||
let blk = bo.take_unwrap();
|
let blk = bo.take_unwrap();
|
||||||
let chan = Cell::new(chan);
|
let chan = Cell::new(chan);
|
||||||
|
|
||||||
|
// What happens if the task fails?
|
||||||
do task::spawn {
|
do task::spawn {
|
||||||
let exe = Exec {
|
let mut exe = Exec {
|
||||||
discovered_inputs: WorkMap::new(),
|
discovered_inputs: WorkMap::new(),
|
||||||
discovered_outputs: WorkMap::new(),
|
discovered_outputs: WorkMap::new(),
|
||||||
};
|
};
|
||||||
let chan = chan.take();
|
let chan = chan.take();
|
||||||
let v = blk(&exe);
|
let v = blk(&mut exe);
|
||||||
chan.send((exe, v));
|
chan.send((exe, v));
|
||||||
}
|
}
|
||||||
Right(port)
|
Right(port)
|
||||||
@ -371,9 +491,10 @@ impl<'self, T:Send +
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
//#[test]
|
#[test]
|
||||||
fn test() {
|
fn test() {
|
||||||
use std::io::WriterUtil;
|
use std::io::WriterUtil;
|
||||||
|
use std::{os, run};
|
||||||
|
|
||||||
let pth = Path("foo.c");
|
let pth = Path("foo.c");
|
||||||
{
|
{
|
||||||
@ -381,7 +502,12 @@ fn test() {
|
|||||||
r.unwrap().write_str("int main() { return 0; }");
|
r.unwrap().write_str("int main() { return 0; }");
|
||||||
}
|
}
|
||||||
|
|
||||||
let cx = Context::new(RWArc::new(Database::new(Path("db.json"))),
|
let db_path = os::self_exe_path().expect("workcache::test failed").pop().push("db.json");
|
||||||
|
if os::path_exists(&db_path) {
|
||||||
|
os::remove_file(&db_path);
|
||||||
|
}
|
||||||
|
|
||||||
|
let cx = Context::new(RWArc::new(Database::new(db_path)),
|
||||||
RWArc::new(Logger::new()),
|
RWArc::new(Logger::new()),
|
||||||
Arc::new(TreeMap::new()));
|
Arc::new(TreeMap::new()));
|
||||||
|
|
||||||
|
@ -13,75 +13,105 @@ use crate::*;
|
|||||||
use package_id::*;
|
use package_id::*;
|
||||||
use package_source::*;
|
use package_source::*;
|
||||||
use version::Version;
|
use version::Version;
|
||||||
|
use workcache_support::*;
|
||||||
|
|
||||||
use std::os;
|
use extra::arc::{Arc,RWArc};
|
||||||
use std::hashmap::*;
|
use extra::workcache;
|
||||||
|
use extra::workcache::{Database, Logger, FreshnessMap};
|
||||||
|
use extra::treemap::TreeMap;
|
||||||
|
|
||||||
/// Convenience functions intended for calling from pkg.rs
|
/// Convenience functions intended for calling from pkg.rs
|
||||||
|
/// p is where to put the cache file for dependencies
|
||||||
|
pub fn default_context(p: Path) -> BuildContext {
|
||||||
|
new_default_context(new_workcache_context(&p), p)
|
||||||
|
}
|
||||||
|
|
||||||
fn default_ctxt(p: @Path) -> Ctx {
|
pub fn new_default_context(c: workcache::Context, p: Path) -> BuildContext {
|
||||||
Ctx {
|
BuildContext {
|
||||||
use_rust_path_hack: false,
|
context: Context {
|
||||||
sysroot_opt: Some(p),
|
use_rust_path_hack: false,
|
||||||
json: false,
|
sysroot: p
|
||||||
dep_cache: @mut HashMap::new()
|
},
|
||||||
|
workcache_context: c
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn build_lib(sysroot: @Path, root: Path, name: ~str, version: Version,
|
fn file_is_fresh(path: &str, in_hash: &str) -> bool {
|
||||||
|
in_hash == digest_file_with_date(&Path(path))
|
||||||
|
}
|
||||||
|
|
||||||
|
fn binary_is_fresh(path: &str, in_hash: &str) -> bool {
|
||||||
|
in_hash == digest_only_date(&Path(path))
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
pub fn new_workcache_context(p: &Path) -> workcache::Context {
|
||||||
|
let db_file = p.push("rustpkg_db.json"); // ??? probably wrong
|
||||||
|
debug!("Workcache database file: %s", db_file.to_str());
|
||||||
|
let db = RWArc::new(Database::new(db_file));
|
||||||
|
let lg = RWArc::new(Logger::new());
|
||||||
|
let cfg = Arc::new(TreeMap::new());
|
||||||
|
let mut freshness: FreshnessMap = TreeMap::new();
|
||||||
|
// Set up freshness functions for every type of dependency rustpkg
|
||||||
|
// knows about
|
||||||
|
freshness.insert(~"file", file_is_fresh);
|
||||||
|
freshness.insert(~"binary", binary_is_fresh);
|
||||||
|
workcache::Context::new_with_freshness(db, lg, cfg, Arc::new(freshness))
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn build_lib(sysroot: Path, root: Path, name: ~str, version: Version,
|
||||||
lib: Path) {
|
lib: Path) {
|
||||||
|
let cx = default_context(sysroot);
|
||||||
let pkg_src = PkgSrc {
|
let subroot = root.clone();
|
||||||
root: root,
|
let subversion = version.clone();
|
||||||
id: PkgId{ version: version, ..PkgId::new(name)},
|
let sublib = lib.clone();
|
||||||
libs: ~[mk_crate(lib)],
|
do cx.workcache_context.with_prep(name) |prep| {
|
||||||
mains: ~[],
|
let pkg_src = PkgSrc {
|
||||||
tests: ~[],
|
workspace: subroot.clone(),
|
||||||
benchs: ~[]
|
start_dir: subroot.push("src").push(name),
|
||||||
|
id: PkgId{ version: subversion.clone(), ..PkgId::new(name)},
|
||||||
|
libs: ~[mk_crate(sublib.clone())],
|
||||||
|
mains: ~[],
|
||||||
|
tests: ~[],
|
||||||
|
benchs: ~[]
|
||||||
|
};
|
||||||
|
pkg_src.declare_inputs(prep);
|
||||||
|
let subcx = cx.clone();
|
||||||
|
let subsrc = pkg_src.clone();
|
||||||
|
do prep.exec |exec| {
|
||||||
|
subsrc.build(exec, &subcx.clone(), ~[]);
|
||||||
|
}
|
||||||
};
|
};
|
||||||
pkg_src.build(&default_ctxt(sysroot), ~[]);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn build_exe(sysroot: @Path, root: Path, name: ~str, version: Version, main: Path) {
|
pub fn build_exe(sysroot: Path, root: Path, name: ~str, version: Version,
|
||||||
let pkg_src = PkgSrc {
|
main: Path) {
|
||||||
root: root,
|
let cx = default_context(sysroot);
|
||||||
id: PkgId{ version: version, ..PkgId::new(name)},
|
let subroot = root.clone();
|
||||||
libs: ~[],
|
let submain = main.clone();
|
||||||
mains: ~[mk_crate(main)],
|
do cx.workcache_context.with_prep(name) |prep| {
|
||||||
tests: ~[],
|
let pkg_src = PkgSrc {
|
||||||
benchs: ~[]
|
workspace: subroot.clone(),
|
||||||
};
|
start_dir: subroot.push("src").push(name),
|
||||||
pkg_src.build(&default_ctxt(sysroot), ~[]);
|
id: PkgId{ version: version.clone(), ..PkgId::new(name)},
|
||||||
|
libs: ~[],
|
||||||
|
mains: ~[mk_crate(submain.clone())],
|
||||||
|
tests: ~[],
|
||||||
|
benchs: ~[]
|
||||||
|
};
|
||||||
|
pkg_src.declare_inputs(prep);
|
||||||
|
let subsrc = pkg_src.clone();
|
||||||
|
let subcx = cx.clone();
|
||||||
|
do prep.exec |exec| {
|
||||||
|
subsrc.clone().build(exec, &subcx.clone(), ~[]);
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn install_lib(sysroot: @Path,
|
pub fn install_pkg(sysroot: Path, workspace: Path, name: ~str, version: Version) {
|
||||||
workspace: Path,
|
let cx = default_context(sysroot);
|
||||||
name: ~str,
|
let pkgid = PkgId{ version: version, ..PkgId::new(name)};
|
||||||
lib_path: Path,
|
cx.install(PkgSrc::new(workspace, false, pkgid));
|
||||||
version: Version) {
|
|
||||||
debug!("self_exe: %?", os::self_exe_path());
|
|
||||||
debug!("sysroot = %s", sysroot.to_str());
|
|
||||||
debug!("workspace = %s", workspace.to_str());
|
|
||||||
// make a PkgSrc
|
|
||||||
let pkg_id = PkgId{ version: version, ..PkgId::new(name)};
|
|
||||||
let pkg_src = PkgSrc {
|
|
||||||
root: workspace.clone(),
|
|
||||||
id: pkg_id.clone(),
|
|
||||||
libs: ~[mk_crate(lib_path)],
|
|
||||||
mains: ~[],
|
|
||||||
tests: ~[],
|
|
||||||
benchs: ~[]
|
|
||||||
};
|
|
||||||
let cx = default_ctxt(sysroot);
|
|
||||||
pkg_src.build(&cx, ~[]);
|
|
||||||
cx.install_no_build(&workspace, &pkg_id);
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn install_exe(sysroot: @Path, workspace: Path, name: ~str, version: Version) {
|
|
||||||
default_ctxt(sysroot).install(&workspace, &PkgId{ version: version,
|
|
||||||
..PkgId::new(name)});
|
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
fn mk_crate(p: Path) -> Crate {
|
fn mk_crate(p: Path) -> Crate {
|
||||||
|
@ -12,11 +12,17 @@
|
|||||||
|
|
||||||
pub use std::path::Path;
|
pub use std::path::Path;
|
||||||
pub use package_id::PkgId;
|
pub use package_id::PkgId;
|
||||||
|
pub use std::libc;
|
||||||
|
pub use std::libc::stat;
|
||||||
|
|
||||||
condition! {
|
condition! {
|
||||||
pub bad_path: (Path, ~str) -> Path;
|
pub bad_path: (Path, ~str) -> Path;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
condition! {
|
||||||
|
pub bad_stat: (Path, ~str) -> stat;
|
||||||
|
}
|
||||||
|
|
||||||
condition! {
|
condition! {
|
||||||
pub nonexistent_package: (PkgId, ~str) -> Path;
|
pub nonexistent_package: (PkgId, ~str) -> Path;
|
||||||
}
|
}
|
||||||
|
@ -10,43 +10,57 @@
|
|||||||
|
|
||||||
// Context data structure used by rustpkg
|
// Context data structure used by rustpkg
|
||||||
|
|
||||||
|
|
||||||
use std::hashmap::HashMap;
|
|
||||||
use std::os;
|
use std::os;
|
||||||
|
use extra::workcache;
|
||||||
|
|
||||||
pub struct Ctx {
|
#[deriving(Clone)]
|
||||||
|
pub struct Context {
|
||||||
// If use_rust_path_hack is true, rustpkg searches for sources
|
// If use_rust_path_hack is true, rustpkg searches for sources
|
||||||
// in *package* directories that are in the RUST_PATH (for example,
|
// in *package* directories that are in the RUST_PATH (for example,
|
||||||
// FOO/src/bar-0.1 instead of FOO). The flag doesn't affect where
|
// FOO/src/bar-0.1 instead of FOO). The flag doesn't affect where
|
||||||
// rustpkg stores build artifacts.
|
// rustpkg stores build artifacts.
|
||||||
use_rust_path_hack: bool,
|
use_rust_path_hack: bool,
|
||||||
// Sysroot -- if this is None, uses rustc filesearch's
|
// The root directory containing the Rust standard libraries
|
||||||
// idea of the default
|
sysroot: Path
|
||||||
sysroot_opt: Option<@Path>,
|
|
||||||
// I'm not sure what this is for
|
|
||||||
json: bool,
|
|
||||||
// Cache of hashes of things already installed
|
|
||||||
// though I'm not sure why the value is a bool
|
|
||||||
dep_cache: @mut HashMap<~str, bool>,
|
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Ctx {
|
#[deriving(Clone)]
|
||||||
|
pub struct BuildContext {
|
||||||
|
// Context for workcache
|
||||||
|
workcache_context: workcache::Context,
|
||||||
|
// Everything else
|
||||||
|
context: Context
|
||||||
|
}
|
||||||
|
|
||||||
|
impl BuildContext {
|
||||||
|
pub fn sysroot(&self) -> Path {
|
||||||
|
self.context.sysroot.clone()
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn sysroot_to_use(&self) -> Path {
|
||||||
|
self.context.sysroot_to_use()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Context {
|
||||||
|
pub fn sysroot(&self) -> Path {
|
||||||
|
self.sysroot.clone()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Context {
|
||||||
/// Debugging
|
/// Debugging
|
||||||
pub fn sysroot_opt_str(&self) -> ~str {
|
pub fn sysroot_str(&self) -> ~str {
|
||||||
match self.sysroot_opt {
|
self.sysroot.to_str()
|
||||||
None => ~"[none]",
|
|
||||||
Some(p) => p.to_str()
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// Hack so that rustpkg can run either out of a rustc target dir,
|
// Hack so that rustpkg can run either out of a rustc target dir,
|
||||||
// or the host dir
|
// or the host dir
|
||||||
pub fn sysroot_to_use(&self) -> Option<@Path> {
|
pub fn sysroot_to_use(&self) -> Path {
|
||||||
if !in_target(self.sysroot_opt) {
|
if !in_target(&self.sysroot) {
|
||||||
self.sysroot_opt
|
self.sysroot.clone()
|
||||||
}
|
} else {
|
||||||
else {
|
self.sysroot.pop().pop().pop()
|
||||||
self.sysroot_opt.map(|p| { @p.pop().pop().pop() })
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -54,12 +68,7 @@ impl Ctx {
|
|||||||
/// We assume that if ../../rustc exists, then we're running
|
/// We assume that if ../../rustc exists, then we're running
|
||||||
/// rustpkg from a Rust target directory. This is part of a
|
/// rustpkg from a Rust target directory. This is part of a
|
||||||
/// kludgy hack used to adjust the sysroot.
|
/// kludgy hack used to adjust the sysroot.
|
||||||
pub fn in_target(sysroot_opt: Option<@Path>) -> bool {
|
pub fn in_target(sysroot: &Path) -> bool {
|
||||||
match sysroot_opt {
|
debug!("Checking whether %s is in target", sysroot.to_str());
|
||||||
None => false,
|
os::path_is_dir(&sysroot.pop().pop().push("rustc"))
|
||||||
Some(p) => {
|
|
||||||
debug!("Checking whether %s is in target", p.to_str());
|
|
||||||
os::path_is_dir(&p.pop().pop().push("rustc"))
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
@ -51,12 +51,10 @@ impl PkgId {
|
|||||||
// Did the user request a specific version?
|
// Did the user request a specific version?
|
||||||
let s = match split_version(s) {
|
let s = match split_version(s) {
|
||||||
Some((path, v)) => {
|
Some((path, v)) => {
|
||||||
debug!("s = %s, path = %s, v = %s", s, path, v.to_str());
|
|
||||||
given_version = Some(v);
|
given_version = Some(v);
|
||||||
path
|
path
|
||||||
}
|
}
|
||||||
None => {
|
None => {
|
||||||
debug!("%s has no explicit version", s);
|
|
||||||
s
|
s
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
@ -81,7 +79,6 @@ impl PkgId {
|
|||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
debug!("path = %s", path.to_str());
|
|
||||||
PkgId {
|
PkgId {
|
||||||
path: path.clone(),
|
path: path.clone(),
|
||||||
short_name: short_name.to_owned(),
|
short_name: short_name.to_owned(),
|
||||||
|
@ -18,14 +18,21 @@ use context::*;
|
|||||||
use crate::Crate;
|
use crate::Crate;
|
||||||
use messages::*;
|
use messages::*;
|
||||||
use source_control::{git_clone, git_clone_general};
|
use source_control::{git_clone, git_clone_general};
|
||||||
use path_util::{pkgid_src_in_workspace, find_dir_using_rust_path_hack, default_workspace};
|
use path_util::{find_dir_using_rust_path_hack, default_workspace};
|
||||||
use util::compile_crate;
|
use util::compile_crate;
|
||||||
use workspace::is_workspace;
|
use workspace::is_workspace;
|
||||||
|
use workcache_support;
|
||||||
|
use extra::workcache;
|
||||||
|
|
||||||
// An enumeration of the unpacked source of a package workspace.
|
// An enumeration of the unpacked source of a package workspace.
|
||||||
// This contains a list of files found in the source workspace.
|
// This contains a list of files found in the source workspace.
|
||||||
|
#[deriving(Clone)]
|
||||||
pub struct PkgSrc {
|
pub struct PkgSrc {
|
||||||
root: Path, // root of where the package source code lives
|
/// Root of where the package source code lives
|
||||||
|
workspace: Path,
|
||||||
|
// Directory to start looking in for packages -- normally
|
||||||
|
// this is workspace/src/id but it may be just workspace
|
||||||
|
start_dir: Path,
|
||||||
id: PkgId,
|
id: PkgId,
|
||||||
libs: ~[Crate],
|
libs: ~[Crate],
|
||||||
mains: ~[Crate],
|
mains: ~[Crate],
|
||||||
@ -33,17 +40,85 @@ pub struct PkgSrc {
|
|||||||
benchs: ~[Crate],
|
benchs: ~[Crate],
|
||||||
}
|
}
|
||||||
|
|
||||||
|
impl ToStr for PkgSrc {
|
||||||
|
fn to_str(&self) -> ~str {
|
||||||
|
fmt!("Package ID %s in start dir %s [workspace = %s]",
|
||||||
|
self.id.to_str(),
|
||||||
|
self.start_dir.to_str(), self.workspace.to_str())
|
||||||
|
}
|
||||||
|
}
|
||||||
condition! {
|
condition! {
|
||||||
// #6009: should this be pub or not, when #8215 is fixed?
|
// #6009: should this be pub or not, when #8215 is fixed?
|
||||||
build_err: (~str) -> ();
|
build_err: (~str) -> ~str;
|
||||||
}
|
}
|
||||||
|
|
||||||
impl PkgSrc {
|
impl PkgSrc {
|
||||||
|
|
||||||
pub fn new(src_dir: &Path, id: &PkgId) -> PkgSrc {
|
pub fn new(workspace: Path, use_rust_path_hack: bool, id: PkgId) -> PkgSrc {
|
||||||
|
use conditions::nonexistent_package::cond;
|
||||||
|
|
||||||
|
debug!("Checking package source for package ID %s, \
|
||||||
|
workspace = %s", id.to_str(), workspace.to_str());
|
||||||
|
|
||||||
|
let mut to_try = ~[];
|
||||||
|
if use_rust_path_hack {
|
||||||
|
to_try.push(workspace.clone());
|
||||||
|
} else {
|
||||||
|
let result = workspace.push("src").push_rel(&id.path.pop()).push(fmt!("%s-%s",
|
||||||
|
id.short_name, id.version.to_str()));
|
||||||
|
to_try.push(result);
|
||||||
|
to_try.push(workspace.push("src").push_rel(&id.path));
|
||||||
|
}
|
||||||
|
|
||||||
|
debug!("Checking dirs: %?", to_try.map(|s| s.to_str()).connect(":"));
|
||||||
|
|
||||||
|
let path = to_try.iter().find(|&d| os::path_exists(d));
|
||||||
|
|
||||||
|
let dir: Path = match path {
|
||||||
|
Some(d) => (*d).clone(),
|
||||||
|
None => {
|
||||||
|
let mut ok_d = None;
|
||||||
|
for w in to_try.iter() {
|
||||||
|
debug!("Calling fetch_git on %s", w.to_str());
|
||||||
|
let gf = PkgSrc::fetch_git(w, &id);
|
||||||
|
for p in gf.iter() {
|
||||||
|
ok_d = Some(p.clone());
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
if ok_d.is_some() { break; }
|
||||||
|
}
|
||||||
|
match ok_d {
|
||||||
|
Some(d) => d,
|
||||||
|
None => {
|
||||||
|
if use_rust_path_hack {
|
||||||
|
match find_dir_using_rust_path_hack(&id) {
|
||||||
|
Some(d) => d,
|
||||||
|
None => cond.raise((id.clone(),
|
||||||
|
~"supplied path for package dir does not \
|
||||||
|
exist, and couldn't interpret it as a URL fragment"))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
cond.raise((id.clone(),
|
||||||
|
~"supplied path for package dir does not \
|
||||||
|
exist, and couldn't interpret it as a URL fragment"))
|
||||||
|
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
};
|
||||||
|
debug!("For package id %s, returning %s", id.to_str(), dir.to_str());
|
||||||
|
|
||||||
|
if !os::path_is_dir(&dir) {
|
||||||
|
cond.raise((id.clone(), ~"supplied path for package dir is a \
|
||||||
|
non-directory"));
|
||||||
|
}
|
||||||
|
|
||||||
PkgSrc {
|
PkgSrc {
|
||||||
root: (*src_dir).clone(),
|
workspace: workspace,
|
||||||
id: (*id).clone(),
|
start_dir: dir,
|
||||||
|
id: id,
|
||||||
libs: ~[],
|
libs: ~[],
|
||||||
mains: ~[],
|
mains: ~[],
|
||||||
tests: ~[],
|
tests: ~[],
|
||||||
@ -51,47 +126,12 @@ impl PkgSrc {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
fn check_dir(&self, cx: &Ctx) -> Path {
|
|
||||||
use conditions::nonexistent_package::cond;
|
|
||||||
|
|
||||||
debug!("Pushing onto root: %s | %s", self.id.path.to_str(), self.root.to_str());
|
|
||||||
|
|
||||||
let dirs = pkgid_src_in_workspace(&self.id, &self.root);
|
|
||||||
debug!("Checking dirs: %?", dirs.map(|s| s.to_str()).connect(":"));
|
|
||||||
let path = dirs.iter().find(|&d| os::path_exists(d));
|
|
||||||
|
|
||||||
let dir = match path {
|
|
||||||
Some(d) => (*d).clone(),
|
|
||||||
None => {
|
|
||||||
match self.fetch_git() {
|
|
||||||
Some(d) => d,
|
|
||||||
None => {
|
|
||||||
match find_dir_using_rust_path_hack(cx, &self.id) {
|
|
||||||
Some(d) => d,
|
|
||||||
None => cond.raise((self.id.clone(),
|
|
||||||
~"supplied path for package dir does not \
|
|
||||||
exist, and couldn't interpret it as a URL fragment"))
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
};
|
|
||||||
debug!("For package id %s, returning %s", self.id.to_str(), dir.to_str());
|
|
||||||
if !os::path_is_dir(&dir) {
|
|
||||||
cond.raise((self.id.clone(), ~"supplied path for package dir is a \
|
|
||||||
non-directory"));
|
|
||||||
}
|
|
||||||
|
|
||||||
dir
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Try interpreting self's package id as a git repository, and try
|
/// Try interpreting self's package id as a git repository, and try
|
||||||
/// fetching it and caching it in a local directory. Return the cached directory
|
/// fetching it and caching it in a local directory. Return the cached directory
|
||||||
/// if this was successful, None otherwise. Similarly, if the package id
|
/// if this was successful, None otherwise. Similarly, if the package id
|
||||||
/// refers to a git repo on the local version, also check it out.
|
/// refers to a git repo on the local version, also check it out.
|
||||||
/// (right now we only support git)
|
/// (right now we only support git)
|
||||||
pub fn fetch_git(&self) -> Option<Path> {
|
pub fn fetch_git(local: &Path, pkgid: &PkgId) -> Option<Path> {
|
||||||
use conditions::failed_to_create_temp_dir::cond;
|
use conditions::failed_to_create_temp_dir::cond;
|
||||||
|
|
||||||
// We use a temporary directory because if the git clone fails,
|
// We use a temporary directory because if the git clone fails,
|
||||||
@ -103,38 +143,35 @@ impl PkgSrc {
|
|||||||
None => cond.raise(~"Failed to create temporary directory for fetching git sources")
|
None => cond.raise(~"Failed to create temporary directory for fetching git sources")
|
||||||
};
|
};
|
||||||
|
|
||||||
let mut local = self.root.push("src");
|
debug!("Checking whether %s (path = %s) exists locally. Cwd = %s, does it? %?",
|
||||||
local = local.push(self.id.to_str());
|
pkgid.to_str(), pkgid.path.to_str(),
|
||||||
|
|
||||||
debug!("Checking whether %s exists locally. Cwd = %s, does it? %?",
|
|
||||||
self.id.path.to_str(),
|
|
||||||
os::getcwd().to_str(),
|
os::getcwd().to_str(),
|
||||||
os::path_exists(&self.id.path));
|
os::path_exists(&pkgid.path));
|
||||||
|
|
||||||
if os::path_exists(&self.id.path) {
|
if os::path_exists(&pkgid.path) {
|
||||||
debug!("%s exists locally! Cloning it into %s",
|
debug!("%s exists locally! Cloning it into %s",
|
||||||
self.id.path.to_str(), local.to_str());
|
pkgid.path.to_str(), local.to_str());
|
||||||
// Ok to use local here; we know it will succeed
|
// Ok to use local here; we know it will succeed
|
||||||
git_clone(&self.id.path, &local, &self.id.version);
|
git_clone(&pkgid.path, local, &pkgid.version);
|
||||||
return Some(local);
|
return Some(local.clone());
|
||||||
}
|
}
|
||||||
|
|
||||||
if self.id.path.components().len() < 2 {
|
if pkgid.path.components().len() < 2 {
|
||||||
// If a non-URL, don't bother trying to fetch
|
// If a non-URL, don't bother trying to fetch
|
||||||
return None;
|
return None;
|
||||||
}
|
}
|
||||||
|
|
||||||
let url = fmt!("https://%s", self.id.path.to_str());
|
let url = fmt!("https://%s", pkgid.path.to_str());
|
||||||
note(fmt!("Fetching package: git clone %s %s [version=%s]",
|
debug!("Fetching package: git clone %s %s [version=%s]",
|
||||||
url, clone_target.to_str(), self.id.version.to_str()));
|
url, clone_target.to_str(), pkgid.version.to_str());
|
||||||
|
|
||||||
if git_clone_general(url, &clone_target, &self.id.version) {
|
if git_clone_general(url, &clone_target, &pkgid.version) {
|
||||||
// since the operation succeeded, move clone_target to local
|
// since the operation succeeded, move clone_target to local
|
||||||
if !os::rename_file(&clone_target, &local) {
|
if !os::rename_file(&clone_target, local) {
|
||||||
None
|
None
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
Some(local)
|
Some(local.clone())
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
@ -143,10 +180,11 @@ impl PkgSrc {
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
// If a file named "pkg.rs" in the current directory exists,
|
// If a file named "pkg.rs" in the start directory exists,
|
||||||
// return the path for it. Otherwise, None
|
// return the path for it. Otherwise, None
|
||||||
pub fn package_script_option(&self, cwd: &Path) -> Option<Path> {
|
pub fn package_script_option(&self) -> Option<Path> {
|
||||||
let maybe_path = cwd.push("pkg.rs");
|
let maybe_path = self.start_dir.push("pkg.rs");
|
||||||
|
debug!("package_script_option: checking whether %s exists", maybe_path.to_str());
|
||||||
if os::path_exists(&maybe_path) {
|
if os::path_exists(&maybe_path) {
|
||||||
Some(maybe_path)
|
Some(maybe_path)
|
||||||
}
|
}
|
||||||
@ -166,20 +204,18 @@ impl PkgSrc {
|
|||||||
for c in p.components.slice(prefix, p.components.len()).iter() {
|
for c in p.components.slice(prefix, p.components.len()).iter() {
|
||||||
sub = sub.push(*c);
|
sub = sub.push(*c);
|
||||||
}
|
}
|
||||||
debug!("found crate %s", sub.to_str());
|
debug!("Will compile crate %s", sub.to_str());
|
||||||
cs.push(Crate::new(&sub));
|
cs.push(Crate::new(&sub));
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Infers crates to build. Called only in the case where there
|
/// Infers crates to build. Called only in the case where there
|
||||||
/// is no custom build logic
|
/// is no custom build logic
|
||||||
pub fn find_crates(&mut self, cx: &Ctx) {
|
pub fn find_crates(&mut self) {
|
||||||
use conditions::missing_pkg_files::cond;
|
use conditions::missing_pkg_files::cond;
|
||||||
|
|
||||||
let dir = self.check_dir(cx);
|
let prefix = self.start_dir.components.len();
|
||||||
debug!("Called check_dir, I'm in %s", dir.to_str());
|
debug!("Matching against %s", self.id.short_name);
|
||||||
let prefix = dir.components.len();
|
do os::walk_dir(&self.start_dir) |pth| {
|
||||||
debug!("Matching against %?", self.id.short_name);
|
|
||||||
do os::walk_dir(&dir) |pth| {
|
|
||||||
let maybe_known_crate_set = match pth.filename() {
|
let maybe_known_crate_set = match pth.filename() {
|
||||||
Some(filename) => match filename {
|
Some(filename) => match filename {
|
||||||
"lib.rs" => Some(&mut self.libs),
|
"lib.rs" => Some(&mut self.libs),
|
||||||
@ -207,7 +243,8 @@ impl PkgSrc {
|
|||||||
cond.raise(self.id.clone());
|
cond.raise(self.id.clone());
|
||||||
}
|
}
|
||||||
|
|
||||||
debug!("found %u libs, %u mains, %u tests, %u benchs",
|
debug!("In %s, found %u libs, %u mains, %u tests, %u benchs",
|
||||||
|
self.start_dir.to_str(),
|
||||||
self.libs.len(),
|
self.libs.len(),
|
||||||
self.mains.len(),
|
self.mains.len(),
|
||||||
self.tests.len(),
|
self.tests.len(),
|
||||||
@ -215,68 +252,88 @@ impl PkgSrc {
|
|||||||
}
|
}
|
||||||
|
|
||||||
fn build_crates(&self,
|
fn build_crates(&self,
|
||||||
ctx: &Ctx,
|
ctx: &BuildContext,
|
||||||
src_dir: &Path,
|
exec: &mut workcache::Exec,
|
||||||
destination_dir: &Path,
|
destination_dir: &Path,
|
||||||
crates: &[Crate],
|
crates: &[Crate],
|
||||||
cfgs: &[~str],
|
cfgs: &[~str],
|
||||||
what: OutputType) {
|
what: OutputType) {
|
||||||
for crate in crates.iter() {
|
for crate in crates.iter() {
|
||||||
let path = &src_dir.push_rel(&crate.file).normalize();
|
let path = self.start_dir.push_rel(&crate.file).normalize();
|
||||||
note(fmt!("build_crates: compiling %s", path.to_str()));
|
debug!("build_crates: compiling %s", path.to_str());
|
||||||
note(fmt!("build_crates: using as workspace %s", self.root.to_str()));
|
let path_str = path.to_str();
|
||||||
|
let cfgs = crate.cfgs + cfgs;
|
||||||
|
|
||||||
let result = compile_crate(ctx,
|
let result =
|
||||||
&self.id,
|
// compile_crate should return the path of the output artifact
|
||||||
path,
|
compile_crate(ctx,
|
||||||
// compile_crate wants the destination workspace
|
exec,
|
||||||
destination_dir,
|
&self.id,
|
||||||
crate.flags,
|
&path,
|
||||||
crate.cfgs + cfgs,
|
destination_dir,
|
||||||
false,
|
crate.flags,
|
||||||
what);
|
cfgs,
|
||||||
if !result {
|
false,
|
||||||
build_err::cond.raise(fmt!("build failure on %s",
|
what).to_str();
|
||||||
path.to_str()));
|
debug!("Result of compiling %s was %s", path_str, result);
|
||||||
}
|
|
||||||
debug!("Result of compiling %s was %?",
|
|
||||||
path.to_str(), result);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn build(&self, ctx: &Ctx, cfgs: ~[~str]) -> Path {
|
/// Declare all the crate files in the package source as inputs
|
||||||
|
pub fn declare_inputs(&self, prep: &mut workcache::Prep) {
|
||||||
|
let to_do = ~[self.libs.clone(), self.mains.clone(),
|
||||||
|
self.tests.clone(), self.benchs.clone()];
|
||||||
|
for cs in to_do.iter() {
|
||||||
|
for c in cs.iter() {
|
||||||
|
let path = self.start_dir.push_rel(&c.file).normalize();
|
||||||
|
debug!("Declaring input: %s", path.to_str());
|
||||||
|
prep.declare_input("file",
|
||||||
|
path.to_str(),
|
||||||
|
workcache_support::digest_file_with_date(&path.clone()));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// It would be better if build returned a Path, but then Path would have to derive
|
||||||
|
// Encodable.
|
||||||
|
pub fn build(&self,
|
||||||
|
exec: &mut workcache::Exec,
|
||||||
|
build_context: &BuildContext,
|
||||||
|
cfgs: ~[~str]) -> ~str {
|
||||||
use conditions::not_a_workspace::cond;
|
use conditions::not_a_workspace::cond;
|
||||||
|
|
||||||
// Determine the destination workspace (which depends on whether
|
// Determine the destination workspace (which depends on whether
|
||||||
// we're using the rust_path_hack)
|
// we're using the rust_path_hack)
|
||||||
let destination_workspace = if is_workspace(&self.root) {
|
let destination_workspace = if is_workspace(&self.workspace) {
|
||||||
debug!("%s is indeed a workspace", self.root.to_str());
|
debug!("%s is indeed a workspace", self.workspace.to_str());
|
||||||
self.root.clone()
|
self.workspace.clone()
|
||||||
}
|
} else {
|
||||||
else {
|
|
||||||
// It would be nice to have only one place in the code that checks
|
// It would be nice to have only one place in the code that checks
|
||||||
// for the use_rust_path_hack flag...
|
// for the use_rust_path_hack flag...
|
||||||
if ctx.use_rust_path_hack {
|
if build_context.context.use_rust_path_hack {
|
||||||
let rs = default_workspace();
|
let rs = default_workspace();
|
||||||
debug!("Using hack: %s", rs.to_str());
|
debug!("Using hack: %s", rs.to_str());
|
||||||
rs
|
rs
|
||||||
}
|
} else {
|
||||||
else {
|
|
||||||
cond.raise(fmt!("Package root %s is not a workspace; pass in --rust_path_hack \
|
cond.raise(fmt!("Package root %s is not a workspace; pass in --rust_path_hack \
|
||||||
if you want to treat it as a package source", self.root.to_str()))
|
if you want to treat it as a package source",
|
||||||
|
self.workspace.to_str()))
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
let dir = self.check_dir(ctx);
|
let libs = self.libs.clone();
|
||||||
debug!("Building libs in %s, destination = %s", dir.to_str(),
|
let mains = self.mains.clone();
|
||||||
destination_workspace.to_str());
|
let tests = self.tests.clone();
|
||||||
self.build_crates(ctx, &dir, &destination_workspace, self.libs, cfgs, Lib);
|
let benchs = self.benchs.clone();
|
||||||
|
debug!("Building libs in %s, destination = %s",
|
||||||
|
destination_workspace.to_str(), destination_workspace.to_str());
|
||||||
|
self.build_crates(build_context, exec, &destination_workspace, libs, cfgs, Lib);
|
||||||
debug!("Building mains");
|
debug!("Building mains");
|
||||||
self.build_crates(ctx, &dir, &destination_workspace, self.mains, cfgs, Main);
|
self.build_crates(build_context, exec, &destination_workspace, mains, cfgs, Main);
|
||||||
debug!("Building tests");
|
debug!("Building tests");
|
||||||
self.build_crates(ctx, &dir, &destination_workspace, self.tests, cfgs, Test);
|
self.build_crates(build_context, exec, &destination_workspace, tests, cfgs, Test);
|
||||||
debug!("Building benches");
|
debug!("Building benches");
|
||||||
self.build_crates(ctx, &dir, &destination_workspace, self.benchs, cfgs, Bench);
|
self.build_crates(build_context, exec, &destination_workspace, benchs, cfgs, Bench);
|
||||||
destination_workspace
|
destination_workspace.to_str()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -14,7 +14,6 @@ pub use package_id::PkgId;
|
|||||||
pub use target::{OutputType, Main, Lib, Test, Bench, Target, Build, Install};
|
pub use target::{OutputType, Main, Lib, Test, Bench, Target, Build, Install};
|
||||||
pub use version::{Version, NoVersion, split_version_general, try_parsing_version};
|
pub use version::{Version, NoVersion, split_version_general, try_parsing_version};
|
||||||
pub use rustc::metadata::filesearch::rust_path;
|
pub use rustc::metadata::filesearch::rust_path;
|
||||||
use context::Ctx;
|
|
||||||
|
|
||||||
use std::libc::consts::os::posix88::{S_IRUSR, S_IWUSR, S_IXUSR};
|
use std::libc::consts::os::posix88::{S_IRUSR, S_IWUSR, S_IXUSR};
|
||||||
use std::os::mkdir_recursive;
|
use std::os::mkdir_recursive;
|
||||||
@ -62,12 +61,7 @@ pub fn workspace_contains_package_id_(pkgid: &PkgId, workspace: &Path,
|
|||||||
|
|
||||||
let mut found = None;
|
let mut found = None;
|
||||||
do os::walk_dir(&src_dir) |p| {
|
do os::walk_dir(&src_dir) |p| {
|
||||||
debug!("=> p = %s", p.to_str());
|
|
||||||
|
|
||||||
if os::path_is_dir(p) {
|
if os::path_is_dir(p) {
|
||||||
debug!("p = %s, path = %s [%s]", p.to_str(), pkgid.path.to_str(),
|
|
||||||
src_dir.push_rel(&pkgid.path).to_str());
|
|
||||||
|
|
||||||
if *p == src_dir.push_rel(&pkgid.path) || {
|
if *p == src_dir.push_rel(&pkgid.path) || {
|
||||||
let pf = p.filename();
|
let pf = p.filename();
|
||||||
do pf.iter().any |pf| {
|
do pf.iter().any |pf| {
|
||||||
@ -75,8 +69,6 @@ pub fn workspace_contains_package_id_(pkgid: &PkgId, workspace: &Path,
|
|||||||
match split_version_general(g, '-') {
|
match split_version_general(g, '-') {
|
||||||
None => false,
|
None => false,
|
||||||
Some((ref might_match, ref vers)) => {
|
Some((ref might_match, ref vers)) => {
|
||||||
debug!("might_match = %s, vers = %s", *might_match,
|
|
||||||
vers.to_str());
|
|
||||||
*might_match == pkgid.short_name
|
*might_match == pkgid.short_name
|
||||||
&& (pkgid.version == *vers || pkgid.version == NoVersion)
|
&& (pkgid.version == *vers || pkgid.version == NoVersion)
|
||||||
}
|
}
|
||||||
@ -90,32 +82,14 @@ pub fn workspace_contains_package_id_(pkgid: &PkgId, workspace: &Path,
|
|||||||
true
|
true
|
||||||
};
|
};
|
||||||
|
|
||||||
debug!(if found.is_some() { fmt!("Found %s in %s", pkgid.to_str(), workspace.to_str()) }
|
if found.is_some() {
|
||||||
else { fmt!("Didn't find %s in %s", pkgid.to_str(), workspace.to_str()) });
|
debug!("Found %s in %s", pkgid.to_str(), workspace.to_str());
|
||||||
|
} else {
|
||||||
|
debug!("Didn't find %s in %s", pkgid.to_str(), workspace.to_str());
|
||||||
|
}
|
||||||
found
|
found
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Returns a list of possible directories
|
|
||||||
/// for <pkgid>'s source files in <workspace>.
|
|
||||||
/// Doesn't check that any of them exist.
|
|
||||||
/// (for example, try both with and without the version)
|
|
||||||
pub fn pkgid_src_in_workspace(pkgid: &PkgId, workspace: &Path) -> ~[Path] {
|
|
||||||
let mut results = ~[];
|
|
||||||
let result = workspace.push("src").push(fmt!("%s-%s",
|
|
||||||
pkgid.path.to_str(), pkgid.version.to_str()));
|
|
||||||
results.push(result);
|
|
||||||
results.push(workspace.push("src").push_rel(&pkgid.path));
|
|
||||||
results
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Returns a src for pkgid that does exist -- None if none of them do
|
|
||||||
pub fn first_pkgid_src_in_workspace(pkgid: &PkgId, workspace: &Path) -> Option<Path> {
|
|
||||||
let rs = pkgid_src_in_workspace(pkgid, workspace);
|
|
||||||
do rs.iter().find |&p| {
|
|
||||||
os::path_exists(p)
|
|
||||||
}.map(|p| (**p).clone())
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Figure out what the executable name for <pkgid> in <workspace>'s build
|
/// Figure out what the executable name for <pkgid> in <workspace>'s build
|
||||||
/// directory is, and if the file exists, return it.
|
/// directory is, and if the file exists, return it.
|
||||||
pub fn built_executable_in_workspace(pkgid: &PkgId, workspace: &Path) -> Option<Path> {
|
pub fn built_executable_in_workspace(pkgid: &PkgId, workspace: &Path) -> Option<Path> {
|
||||||
@ -402,10 +376,7 @@ fn dir_has_file(dir: &Path, file: &str) -> bool {
|
|||||||
os::path_exists(&dir.push(file))
|
os::path_exists(&dir.push(file))
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn find_dir_using_rust_path_hack(cx: &Ctx, p: &PkgId) -> Option<Path> {
|
pub fn find_dir_using_rust_path_hack(p: &PkgId) -> Option<Path> {
|
||||||
if !cx.use_rust_path_hack {
|
|
||||||
return None;
|
|
||||||
}
|
|
||||||
let rp = rust_path();
|
let rp = rust_path();
|
||||||
for dir in rp.iter() {
|
for dir in rp.iter() {
|
||||||
debug!("In find_dir_using_rust_path_hack: checking dir %s", dir.to_str());
|
debug!("In find_dir_using_rust_path_hack: checking dir %s", dir.to_str());
|
||||||
|
@ -24,8 +24,9 @@ extern mod syntax;
|
|||||||
|
|
||||||
use std::{io, os, result, run, str};
|
use std::{io, os, result, run, str};
|
||||||
pub use std::path::Path;
|
pub use std::path::Path;
|
||||||
use std::hashmap::HashMap;
|
|
||||||
|
|
||||||
|
use extra::workcache;
|
||||||
|
use extra::arc::RWArc;
|
||||||
use rustc::driver::{driver, session};
|
use rustc::driver::{driver, session};
|
||||||
use rustc::metadata::filesearch;
|
use rustc::metadata::filesearch;
|
||||||
use rustc::metadata::filesearch::rust_path;
|
use rustc::metadata::filesearch::rust_path;
|
||||||
@ -33,15 +34,16 @@ use extra::{getopts};
|
|||||||
use syntax::{ast, diagnostic};
|
use syntax::{ast, diagnostic};
|
||||||
use util::*;
|
use util::*;
|
||||||
use messages::*;
|
use messages::*;
|
||||||
use path_util::{build_pkg_id_in_workspace, first_pkgid_src_in_workspace};
|
use path_util::build_pkg_id_in_workspace;
|
||||||
use path_util::{U_RWX, in_rust_path};
|
use path_util::{U_RWX, in_rust_path};
|
||||||
use path_util::{built_executable_in_workspace, built_library_in_workspace, default_workspace};
|
use path_util::{built_executable_in_workspace, built_library_in_workspace, default_workspace};
|
||||||
use path_util::{target_executable_in_workspace, target_library_in_workspace};
|
use path_util::{target_executable_in_workspace, target_library_in_workspace};
|
||||||
use source_control::is_git_dir;
|
use source_control::is_git_dir;
|
||||||
use workspace::{each_pkg_parent_workspace, pkg_parent_workspaces, cwd_to_workspace};
|
use workspace::{each_pkg_parent_workspace, pkg_parent_workspaces, cwd_to_workspace};
|
||||||
use context::Ctx;
|
use context::{BuildContext, Context};
|
||||||
use package_id::PkgId;
|
use package_id::PkgId;
|
||||||
use package_source::PkgSrc;
|
use package_source::PkgSrc;
|
||||||
|
use workcache_support::{discover_outputs, digest_only_date};
|
||||||
|
|
||||||
pub mod api;
|
pub mod api;
|
||||||
mod conditions;
|
mod conditions;
|
||||||
@ -59,6 +61,7 @@ mod target;
|
|||||||
mod tests;
|
mod tests;
|
||||||
mod util;
|
mod util;
|
||||||
mod version;
|
mod version;
|
||||||
|
pub mod workcache_support;
|
||||||
mod workspace;
|
mod workspace;
|
||||||
|
|
||||||
pub mod usage;
|
pub mod usage;
|
||||||
@ -69,11 +72,8 @@ pub mod usage;
|
|||||||
struct PkgScript<'self> {
|
struct PkgScript<'self> {
|
||||||
/// Uniquely identifies this package
|
/// Uniquely identifies this package
|
||||||
id: &'self PkgId,
|
id: &'self PkgId,
|
||||||
// Used to have this field: deps: ~[(~str, Option<~str>)]
|
/// File path for the package script
|
||||||
// but I think it shouldn't be stored here
|
input: Path,
|
||||||
/// The contents of the package script: either a file path,
|
|
||||||
/// or a string containing the text of the input
|
|
||||||
input: driver::input,
|
|
||||||
/// The session to use *only* for compiling the custom
|
/// The session to use *only* for compiling the custom
|
||||||
/// build script
|
/// build script
|
||||||
sess: session::Session,
|
sess: session::Session,
|
||||||
@ -104,7 +104,7 @@ impl<'self> PkgScript<'self> {
|
|||||||
crate_type: session::bin_crate,
|
crate_type: session::bin_crate,
|
||||||
.. (*session::basic_options()).clone()
|
.. (*session::basic_options()).clone()
|
||||||
};
|
};
|
||||||
let input = driver::file_input(script);
|
let input = driver::file_input(script.clone());
|
||||||
let sess = driver::build_session(options, diagnostic::emit);
|
let sess = driver::build_session(options, diagnostic::emit);
|
||||||
let cfg = driver::build_configuration(sess);
|
let cfg = driver::build_configuration(sess);
|
||||||
let crate = driver::phase_1_parse_input(sess, cfg.clone(), &input);
|
let crate = driver::phase_1_parse_input(sess, cfg.clone(), &input);
|
||||||
@ -115,7 +115,7 @@ impl<'self> PkgScript<'self> {
|
|||||||
|
|
||||||
PkgScript {
|
PkgScript {
|
||||||
id: id,
|
id: id,
|
||||||
input: input,
|
input: script,
|
||||||
sess: sess,
|
sess: sess,
|
||||||
cfg: cfg,
|
cfg: cfg,
|
||||||
crate: crate,
|
crate: crate,
|
||||||
@ -127,22 +127,24 @@ impl<'self> PkgScript<'self> {
|
|||||||
/// is the command to pass to it (e.g., "build", "clean", "install")
|
/// is the command to pass to it (e.g., "build", "clean", "install")
|
||||||
/// Returns a pair of an exit code and list of configs (obtained by
|
/// Returns a pair of an exit code and list of configs (obtained by
|
||||||
/// calling the package script's configs() function if it exists
|
/// calling the package script's configs() function if it exists
|
||||||
// FIXME (#4432): Use workcache to only compile the script when changed
|
fn run_custom(&self, exec: &mut workcache::Exec, sysroot: &Path) -> (~[~str], ExitCode) {
|
||||||
fn run_custom(&self, sysroot: @Path) -> (~[~str], ExitCode) {
|
|
||||||
let sess = self.sess;
|
let sess = self.sess;
|
||||||
|
|
||||||
debug!("Working directory = %s", self.build_dir.to_str());
|
debug!("Working directory = %s", self.build_dir.to_str());
|
||||||
// Collect together any user-defined commands in the package script
|
// Collect together any user-defined commands in the package script
|
||||||
let crate = util::ready_crate(sess, self.crate);
|
let crate = util::ready_crate(sess, self.crate);
|
||||||
debug!("Building output filenames with script name %s",
|
debug!("Building output filenames with script name %s",
|
||||||
driver::source_name(&self.input));
|
driver::source_name(&driver::file_input(self.input.clone())));
|
||||||
let exe = self.build_dir.push(~"pkg" + util::exe_suffix());
|
let exe = self.build_dir.push(~"pkg" + util::exe_suffix());
|
||||||
util::compile_crate_from_input(&self.input,
|
util::compile_crate_from_input(&self.input,
|
||||||
|
exec,
|
||||||
&self.build_dir,
|
&self.build_dir,
|
||||||
sess,
|
sess,
|
||||||
crate);
|
crate);
|
||||||
debug!("Running program: %s %s %s", exe.to_str(),
|
debug!("Running program: %s %s %s", exe.to_str(),
|
||||||
sysroot.to_str(), "install");
|
sysroot.to_str(), "install");
|
||||||
|
// Discover the output
|
||||||
|
exec.discover_output("binary", exe.to_str(), digest_only_date(&exe));
|
||||||
// FIXME #7401 should support commands besides `install`
|
// FIXME #7401 should support commands besides `install`
|
||||||
let status = run::process_status(exe.to_str(), [sysroot.to_str(), ~"install"]);
|
let status = run::process_status(exe.to_str(), [sysroot.to_str(), ~"install"]);
|
||||||
if status != 0 {
|
if status != 0 {
|
||||||
@ -162,47 +164,67 @@ impl<'self> PkgScript<'self> {
|
|||||||
fn hash(&self) -> ~str {
|
fn hash(&self) -> ~str {
|
||||||
self.id.hash()
|
self.id.hash()
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
pub trait CtxMethods {
|
pub trait CtxMethods {
|
||||||
fn run(&self, cmd: &str, args: ~[~str]);
|
fn run(&self, cmd: &str, args: ~[~str]);
|
||||||
fn do_cmd(&self, _cmd: &str, _pkgname: &str);
|
fn do_cmd(&self, _cmd: &str, _pkgname: &str);
|
||||||
|
fn build_from_src(&self, pkg_src: PkgSrc);
|
||||||
/// Returns the destination workspace
|
/// Returns the destination workspace
|
||||||
fn build(&self, workspace: &Path, pkgid: &PkgId) -> Path;
|
fn build(&self, exec: &mut workcache::Exec, pkg_src: PkgSrc) -> Path;
|
||||||
fn clean(&self, workspace: &Path, id: &PkgId);
|
fn clean(&self, workspace: &Path, id: &PkgId);
|
||||||
fn info(&self);
|
fn info(&self);
|
||||||
fn install(&self, workspace: &Path, id: &PkgId);
|
/// Returns a pair. First component is a list of installed paths,
|
||||||
fn install_no_build(&self, workspace: &Path, id: &PkgId);
|
/// second is a list of declared and discovered inputs
|
||||||
|
fn install(&self, src: PkgSrc) -> (~[Path], ~[(~str, ~str)]);
|
||||||
|
/// Returns a list of installed files
|
||||||
|
fn install_no_build(&self, workspace: &Path, id: &PkgId) -> ~[Path];
|
||||||
fn prefer(&self, _id: &str, _vers: Option<~str>);
|
fn prefer(&self, _id: &str, _vers: Option<~str>);
|
||||||
fn test(&self);
|
fn test(&self);
|
||||||
fn uninstall(&self, _id: &str, _vers: Option<~str>);
|
fn uninstall(&self, _id: &str, _vers: Option<~str>);
|
||||||
fn unprefer(&self, _id: &str, _vers: Option<~str>);
|
fn unprefer(&self, _id: &str, _vers: Option<~str>);
|
||||||
}
|
}
|
||||||
|
|
||||||
impl CtxMethods for Ctx {
|
impl CtxMethods for BuildContext {
|
||||||
|
fn build_from_src(&self, pkg_src: PkgSrc) {
|
||||||
|
let tag = pkg_src.id.to_str();
|
||||||
|
debug!("package source = %s", pkg_src.to_str());
|
||||||
|
do self.workcache_context.with_prep(tag) |prep| {
|
||||||
|
let subsrc = pkg_src.clone();
|
||||||
|
let subself = self.clone();
|
||||||
|
declare_package_script_dependency(prep, &subsrc);
|
||||||
|
pkg_src.declare_inputs(prep);
|
||||||
|
do prep.exec |exec| {
|
||||||
|
subself.build(exec, subsrc.clone());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
fn run(&self, cmd: &str, args: ~[~str]) {
|
fn run(&self, cmd: &str, args: ~[~str]) {
|
||||||
match cmd {
|
match cmd {
|
||||||
"build" => {
|
"build" => {
|
||||||
if args.len() < 1 {
|
if args.len() < 1 {
|
||||||
match cwd_to_workspace() {
|
match cwd_to_workspace() {
|
||||||
None if self.use_rust_path_hack => {
|
None if self.context.use_rust_path_hack => {
|
||||||
let cwd = os::getcwd();
|
let cwd = os::getcwd();
|
||||||
self.build(&cwd, &PkgId::new(cwd.components[cwd.components.len() - 1]));
|
let pkgid = PkgId::new(cwd.components[cwd.components.len() - 1]);
|
||||||
|
self.build_from_src(PkgSrc::new(cwd, true, pkgid));
|
||||||
}
|
}
|
||||||
None => { usage::build(); return; }
|
None => { usage::build(); return; }
|
||||||
Some((ws, pkgid)) => { self.build(&ws, &pkgid); }
|
Some((ws, pkgid)) => {
|
||||||
|
self.build_from_src(PkgSrc::new(ws, false, pkgid));
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
// The package id is presumed to be the first command-line
|
// The package id is presumed to be the first command-line
|
||||||
// argument
|
// argument
|
||||||
let pkgid = PkgId::new(args[0].clone());
|
let pkgid = PkgId::new(args[0].clone());
|
||||||
do each_pkg_parent_workspace(self, &pkgid) |workspace| {
|
do each_pkg_parent_workspace(&self.context, &pkgid) |workspace| {
|
||||||
debug!("found pkg %s in workspace %s, trying to build",
|
debug!("found pkg %s in workspace %s, trying to build",
|
||||||
pkgid.to_str(), workspace.to_str());
|
pkgid.to_str(), workspace.to_str());
|
||||||
self.build(workspace, &pkgid);
|
let pkg_src = PkgSrc::new(workspace.clone(), false, pkgid.clone());
|
||||||
|
self.build_from_src(pkg_src);
|
||||||
true
|
true
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
@ -236,35 +258,40 @@ impl CtxMethods for Ctx {
|
|||||||
self.info();
|
self.info();
|
||||||
}
|
}
|
||||||
"install" => {
|
"install" => {
|
||||||
if args.len() < 1 {
|
if args.len() < 1 {
|
||||||
match cwd_to_workspace() {
|
match cwd_to_workspace() {
|
||||||
None if self.use_rust_path_hack => {
|
None if self.context.use_rust_path_hack => {
|
||||||
let cwd = os::getcwd();
|
let cwd = os::getcwd();
|
||||||
self.install(&cwd,
|
let inferred_pkgid =
|
||||||
&PkgId::new(cwd.components[cwd.components.len() - 1]));
|
PkgId::new(cwd.components[cwd.components.len() - 1]);
|
||||||
|
self.install(PkgSrc::new(cwd, true, inferred_pkgid));
|
||||||
}
|
}
|
||||||
None => { usage::install(); return; }
|
None => { usage::install(); return; }
|
||||||
Some((ws, pkgid)) => self.install(&ws, &pkgid),
|
Some((ws, pkgid)) => {
|
||||||
}
|
let pkg_src = PkgSrc::new(ws, false, pkgid);
|
||||||
|
self.install(pkg_src);
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
// The package id is presumed to be the first command-line
|
// The package id is presumed to be the first command-line
|
||||||
// argument
|
// argument
|
||||||
let pkgid = PkgId::new(args[0]);
|
let pkgid = PkgId::new(args[0]);
|
||||||
let workspaces = pkg_parent_workspaces(self, &pkgid);
|
let workspaces = pkg_parent_workspaces(&self.context, &pkgid);
|
||||||
debug!("package ID = %s, found it in %? workspaces",
|
debug!("package ID = %s, found it in %? workspaces",
|
||||||
pkgid.to_str(), workspaces.len());
|
pkgid.to_str(), workspaces.len());
|
||||||
if workspaces.is_empty() {
|
if workspaces.is_empty() {
|
||||||
let rp = rust_path();
|
let rp = rust_path();
|
||||||
assert!(!rp.is_empty());
|
assert!(!rp.is_empty());
|
||||||
let src = PkgSrc::new(&rp[0], &pkgid);
|
let src = PkgSrc::new(rp[0].clone(), false, pkgid.clone());
|
||||||
src.fetch_git();
|
self.install(src);
|
||||||
self.install(&rp[0], &pkgid);
|
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
do each_pkg_parent_workspace(self, &pkgid) |workspace| {
|
for workspace in workspaces.iter() {
|
||||||
self.install(workspace, &pkgid);
|
let src = PkgSrc::new(workspace.clone(),
|
||||||
true
|
self.context.use_rust_path_hack,
|
||||||
|
pkgid.clone());
|
||||||
|
self.install(src);
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -299,7 +326,7 @@ impl CtxMethods for Ctx {
|
|||||||
else {
|
else {
|
||||||
let rp = rust_path();
|
let rp = rust_path();
|
||||||
assert!(!rp.is_empty());
|
assert!(!rp.is_empty());
|
||||||
do each_pkg_parent_workspace(self, &pkgid) |workspace| {
|
do each_pkg_parent_workspace(&self.context, &pkgid) |workspace| {
|
||||||
path_util::uninstall_package_from(workspace, &pkgid);
|
path_util::uninstall_package_from(workspace, &pkgid);
|
||||||
note(fmt!("Uninstalled package %s (was installed in %s)",
|
note(fmt!("Uninstalled package %s (was installed in %s)",
|
||||||
pkgid.to_str(), workspace.to_str()));
|
pkgid.to_str(), workspace.to_str()));
|
||||||
@ -325,44 +352,42 @@ impl CtxMethods for Ctx {
|
|||||||
|
|
||||||
/// Returns the destination workspace
|
/// Returns the destination workspace
|
||||||
/// In the case of a custom build, we don't know, so we just return the source workspace
|
/// In the case of a custom build, we don't know, so we just return the source workspace
|
||||||
fn build(&self, workspace: &Path, pkgid: &PkgId) -> Path {
|
fn build(&self, exec: &mut workcache::Exec, mut pkg_src: PkgSrc) -> Path {
|
||||||
|
let workspace = pkg_src.workspace.clone();
|
||||||
|
let pkgid = pkg_src.id.clone();
|
||||||
|
|
||||||
debug!("build: workspace = %s (in Rust path? %? is git dir? %? \
|
debug!("build: workspace = %s (in Rust path? %? is git dir? %? \
|
||||||
pkgid = %s", workspace.to_str(),
|
pkgid = %s pkgsrc start_dir = %s", workspace.to_str(),
|
||||||
in_rust_path(workspace), is_git_dir(&workspace.push_rel(&pkgid.path)),
|
in_rust_path(&workspace), is_git_dir(&workspace.push_rel(&pkgid.path)),
|
||||||
pkgid.to_str());
|
pkgid.to_str(), pkg_src.start_dir.to_str());
|
||||||
let src_dir = first_pkgid_src_in_workspace(pkgid, workspace);
|
|
||||||
|
|
||||||
// If workspace isn't in the RUST_PATH, and it's a git repo,
|
// If workspace isn't in the RUST_PATH, and it's a git repo,
|
||||||
// then clone it into the first entry in RUST_PATH, and repeat
|
// then clone it into the first entry in RUST_PATH, and repeat
|
||||||
debug!("%? %? %s", in_rust_path(workspace),
|
if !in_rust_path(&workspace) && is_git_dir(&workspace.push_rel(&pkgid.path)) {
|
||||||
is_git_dir(&workspace.push_rel(&pkgid.path)),
|
|
||||||
workspace.to_str());
|
|
||||||
if !in_rust_path(workspace) && is_git_dir(&workspace.push_rel(&pkgid.path)) {
|
|
||||||
let out_dir = default_workspace().push("src").push_rel(&pkgid.path);
|
let out_dir = default_workspace().push("src").push_rel(&pkgid.path);
|
||||||
source_control::git_clone(&workspace.push_rel(&pkgid.path),
|
source_control::git_clone(&workspace.push_rel(&pkgid.path),
|
||||||
&out_dir, &pkgid.version);
|
&out_dir, &pkgid.version);
|
||||||
let default_ws = default_workspace();
|
let default_ws = default_workspace();
|
||||||
debug!("Calling build recursively with %? and %?", default_ws.to_str(),
|
debug!("Calling build recursively with %? and %?", default_ws.to_str(),
|
||||||
pkgid.to_str());
|
pkgid.to_str());
|
||||||
return self.build(&default_ws, pkgid);
|
return self.build(exec, PkgSrc::new(default_ws, false, pkgid.clone()));
|
||||||
}
|
}
|
||||||
|
|
||||||
// Create the package source
|
|
||||||
let mut src = PkgSrc::new(workspace, pkgid);
|
|
||||||
debug!("Package src = %?", src);
|
|
||||||
|
|
||||||
// Is there custom build logic? If so, use it
|
// Is there custom build logic? If so, use it
|
||||||
let pkg_src_dir = src_dir;
|
|
||||||
let mut custom = false;
|
let mut custom = false;
|
||||||
debug!("Package source directory = %?", pkg_src_dir);
|
debug!("Package source directory = %s", pkg_src.to_str());
|
||||||
let cfgs = match pkg_src_dir.chain_ref(|p| src.package_script_option(p)) {
|
let opt = pkg_src.package_script_option();
|
||||||
|
debug!("Calling pkg_script_option on %?", opt);
|
||||||
|
let cfgs = match pkg_src.package_script_option() {
|
||||||
Some(package_script_path) => {
|
Some(package_script_path) => {
|
||||||
let sysroot = self.sysroot_to_use().expect("custom build needs a sysroot");
|
let sysroot = self.sysroot_to_use();
|
||||||
let pscript = PkgScript::parse(sysroot,
|
let (cfgs, hook_result) = {
|
||||||
package_script_path,
|
let pscript = PkgScript::parse(@sysroot.clone(),
|
||||||
workspace,
|
package_script_path.clone(),
|
||||||
pkgid);
|
&workspace.clone(),
|
||||||
let (cfgs, hook_result) = pscript.run_custom(sysroot);
|
&pkgid);
|
||||||
|
pscript.run_custom(exec, &sysroot)
|
||||||
|
};
|
||||||
debug!("Command return code = %?", hook_result);
|
debug!("Command return code = %?", hook_result);
|
||||||
if hook_result != 0 {
|
if hook_result != 0 {
|
||||||
fail!("Error running custom build command")
|
fail!("Error running custom build command")
|
||||||
@ -381,9 +406,10 @@ impl CtxMethods for Ctx {
|
|||||||
// the build already. Otherwise...
|
// the build already. Otherwise...
|
||||||
if !custom {
|
if !custom {
|
||||||
// Find crates inside the workspace
|
// Find crates inside the workspace
|
||||||
src.find_crates(self);
|
pkg_src.find_crates();
|
||||||
// Build it!
|
// Build it!
|
||||||
src.build(self, cfgs)
|
let rs_path = pkg_src.build(exec, self, cfgs);
|
||||||
|
Path(rs_path)
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
// Just return the source workspace
|
// Just return the source workspace
|
||||||
@ -412,20 +438,44 @@ impl CtxMethods for Ctx {
|
|||||||
fail!("info not yet implemented");
|
fail!("info not yet implemented");
|
||||||
}
|
}
|
||||||
|
|
||||||
fn install(&self, workspace: &Path, id: &PkgId) {
|
fn install(&self, pkg_src: PkgSrc) -> (~[Path], ~[(~str, ~str)]) {
|
||||||
// Also should use workcache to not build if not necessary.
|
|
||||||
let destination_workspace = self.build(workspace, id);
|
|
||||||
// See #7402: This still isn't quite right yet; we want to
|
|
||||||
// install to the first workspace in the RUST_PATH if there's
|
|
||||||
// a non-default RUST_PATH. This code installs to the same
|
|
||||||
// workspace the package was built in.
|
|
||||||
debug!("install: destination workspace = %s, id = %s",
|
|
||||||
destination_workspace.to_str(), id.to_str());
|
|
||||||
self.install_no_build(&destination_workspace, id);
|
|
||||||
|
|
||||||
|
let id = &pkg_src.id;
|
||||||
|
|
||||||
|
let installed_files = RWArc::new(~[]);
|
||||||
|
let inputs = RWArc::new(~[]);
|
||||||
|
// FIXME #7402: Use RUST_PATH to determine target dir
|
||||||
|
self.workcache_context.with_prep(id.to_str(), |p| pkg_src.declare_inputs(p));
|
||||||
|
do self.workcache_context.with_prep(id.to_str()) |prep| {
|
||||||
|
let sub_inputs = inputs.clone();
|
||||||
|
let sub_files = installed_files.clone();
|
||||||
|
let subsrc = pkg_src.clone();
|
||||||
|
let subself = self.clone();
|
||||||
|
let id_str = id.to_str();
|
||||||
|
let sub_id = id.clone();
|
||||||
|
sub_inputs.write(|r| *r = prep.lookup_declared_inputs().map(|v|
|
||||||
|
{ (~"file", (*v).clone()) }));
|
||||||
|
do prep.exec |exec| {
|
||||||
|
let destination_workspace = subself.build(exec, subsrc.clone()).to_str();
|
||||||
|
// See #7402: This still isn't quite right yet; we want to
|
||||||
|
// install to the first workspace in the RUST_PATH if there's
|
||||||
|
// a non-default RUST_PATH. This code installs to the same
|
||||||
|
// workspace the package was built in.
|
||||||
|
debug!("install: destination workspace = %s, id = %s",
|
||||||
|
destination_workspace, id_str);
|
||||||
|
let result = subself.install_no_build(&Path(destination_workspace), &sub_id);
|
||||||
|
debug!("install: id = %s, about to call discover_outputs, %?",
|
||||||
|
id_str, result.to_str());
|
||||||
|
|
||||||
|
discover_outputs(exec, result.clone());
|
||||||
|
sub_files.write(|r| { *r = result.clone(); });
|
||||||
|
sub_inputs.write(|r| { *r = *r + exec.lookup_discovered_inputs() });
|
||||||
|
}
|
||||||
|
};
|
||||||
|
(installed_files.unwrap(), inputs.unwrap())
|
||||||
}
|
}
|
||||||
|
|
||||||
fn install_no_build(&self, workspace: &Path, id: &PkgId) {
|
fn install_no_build(&self, workspace: &Path, id: &PkgId) -> ~[Path] {
|
||||||
use conditions::copy_failed::cond;
|
use conditions::copy_failed::cond;
|
||||||
|
|
||||||
// Now copy stuff into the install dirs
|
// Now copy stuff into the install dirs
|
||||||
@ -439,12 +489,15 @@ impl CtxMethods for Ctx {
|
|||||||
target_exec.to_str(), target_lib,
|
target_exec.to_str(), target_lib,
|
||||||
maybe_executable, maybe_library);
|
maybe_executable, maybe_library);
|
||||||
|
|
||||||
|
let mut outputs = ~[];
|
||||||
|
|
||||||
for exec in maybe_executable.iter() {
|
for exec in maybe_executable.iter() {
|
||||||
debug!("Copying: %s -> %s", exec.to_str(), target_exec.to_str());
|
debug!("Copying: %s -> %s", exec.to_str(), target_exec.to_str());
|
||||||
if !(os::mkdir_recursive(&target_exec.dir_path(), U_RWX) &&
|
if !(os::mkdir_recursive(&target_exec.dir_path(), U_RWX) &&
|
||||||
os::copy_file(exec, &target_exec)) {
|
os::copy_file(exec, &target_exec)) {
|
||||||
cond.raise(((*exec).clone(), target_exec.clone()));
|
cond.raise(((*exec).clone(), target_exec.clone()));
|
||||||
}
|
}
|
||||||
|
outputs.push(target_exec.clone());
|
||||||
}
|
}
|
||||||
for lib in maybe_library.iter() {
|
for lib in maybe_library.iter() {
|
||||||
let target_lib = target_lib.clone().expect(fmt!("I built %s but apparently \
|
let target_lib = target_lib.clone().expect(fmt!("I built %s but apparently \
|
||||||
@ -455,7 +508,9 @@ impl CtxMethods for Ctx {
|
|||||||
os::copy_file(lib, &target_lib)) {
|
os::copy_file(lib, &target_lib)) {
|
||||||
cond.raise(((*lib).clone(), target_lib.clone()));
|
cond.raise(((*lib).clone(), target_lib.clone()));
|
||||||
}
|
}
|
||||||
|
outputs.push(target_lib.clone());
|
||||||
}
|
}
|
||||||
|
outputs
|
||||||
}
|
}
|
||||||
|
|
||||||
fn prefer(&self, _id: &str, _vers: Option<~str>) {
|
fn prefer(&self, _id: &str, _vers: Option<~str>) {
|
||||||
@ -476,7 +531,6 @@ impl CtxMethods for Ctx {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
pub fn main() {
|
pub fn main() {
|
||||||
io::println("WARNING: The Rust package manager is experimental and may be unstable");
|
io::println("WARNING: The Rust package manager is experimental and may be unstable");
|
||||||
let args = os::args();
|
let args = os::args();
|
||||||
@ -485,7 +539,6 @@ pub fn main() {
|
|||||||
|
|
||||||
pub fn main_args(args: &[~str]) {
|
pub fn main_args(args: &[~str]) {
|
||||||
let opts = ~[getopts::optflag("h"), getopts::optflag("help"),
|
let opts = ~[getopts::optflag("h"), getopts::optflag("help"),
|
||||||
getopts::optflag("j"), getopts::optflag("json"),
|
|
||||||
getopts::optmulti("c"), getopts::optmulti("cfg"),
|
getopts::optmulti("c"), getopts::optmulti("cfg"),
|
||||||
getopts::optflag("v"), getopts::optflag("version"),
|
getopts::optflag("v"), getopts::optflag("version"),
|
||||||
getopts::optflag("r"), getopts::optflag("rust-path-hack")];
|
getopts::optflag("r"), getopts::optflag("rust-path-hack")];
|
||||||
@ -499,8 +552,6 @@ pub fn main_args(args: &[~str]) {
|
|||||||
};
|
};
|
||||||
let help = getopts::opt_present(matches, "h") ||
|
let help = getopts::opt_present(matches, "h") ||
|
||||||
getopts::opt_present(matches, "help");
|
getopts::opt_present(matches, "help");
|
||||||
let json = getopts::opt_present(matches, "j") ||
|
|
||||||
getopts::opt_present(matches, "json");
|
|
||||||
|
|
||||||
if getopts::opt_present(matches, "v") ||
|
if getopts::opt_present(matches, "v") ||
|
||||||
getopts::opt_present(matches, "version") {
|
getopts::opt_present(matches, "version") {
|
||||||
@ -512,7 +563,6 @@ pub fn main_args(args: &[~str]) {
|
|||||||
getopts::opt_present(matches, "rust-path-hack");
|
getopts::opt_present(matches, "rust-path-hack");
|
||||||
|
|
||||||
let mut args = matches.free.clone();
|
let mut args = matches.free.clone();
|
||||||
|
|
||||||
args.shift();
|
args.shift();
|
||||||
|
|
||||||
if (args.len() < 1) {
|
if (args.len() < 1) {
|
||||||
@ -553,13 +603,15 @@ pub fn main_args(args: &[~str]) {
|
|||||||
// I had to add this type annotation to get the code to typecheck
|
// I had to add this type annotation to get the code to typecheck
|
||||||
let mut remaining_args: ~[~str] = remaining_args.map(|s| (*s).clone()).collect();
|
let mut remaining_args: ~[~str] = remaining_args.map(|s| (*s).clone()).collect();
|
||||||
remaining_args.shift();
|
remaining_args.shift();
|
||||||
let sroot = Some(@filesearch::get_or_default_sysroot());
|
let sroot = filesearch::get_or_default_sysroot();
|
||||||
debug!("Using sysroot: %?", sroot);
|
debug!("Using sysroot: %s", sroot.to_str());
|
||||||
Ctx {
|
debug!("Will store workcache in %s", default_workspace().to_str());
|
||||||
use_rust_path_hack: use_rust_path_hack,
|
BuildContext {
|
||||||
sysroot_opt: sroot, // Currently, only tests override this
|
context: Context {
|
||||||
json: json,
|
use_rust_path_hack: use_rust_path_hack,
|
||||||
dep_cache: @mut HashMap::new()
|
sysroot: sroot, // Currently, only tests override this
|
||||||
|
},
|
||||||
|
workcache_context: api::default_context(default_workspace()).workcache_context
|
||||||
}.run(*cmd, remaining_args)
|
}.run(*cmd, remaining_args)
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -581,3 +633,11 @@ pub fn work_dir() -> Path {
|
|||||||
pub fn src_dir() -> Path {
|
pub fn src_dir() -> Path {
|
||||||
os::getcwd()
|
os::getcwd()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fn declare_package_script_dependency(prep: &mut workcache::Prep, pkg_src: &PkgSrc) {
|
||||||
|
match pkg_src.package_script_option() {
|
||||||
|
Some(ref p) => prep.declare_input("file", p.to_str(),
|
||||||
|
workcache_support::digest_file_with_date(p)),
|
||||||
|
None => ()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
@ -11,16 +11,6 @@
|
|||||||
use path_util::{installed_library_in_workspace, rust_path};
|
use path_util::{installed_library_in_workspace, rust_path};
|
||||||
use version::Version;
|
use version::Version;
|
||||||
|
|
||||||
/// If a library with path `p` matching pkg_id's name exists under sroot_opt,
|
|
||||||
/// return Some(p). Return None if there's no such path or if sroot_opt is None.
|
|
||||||
pub fn find_library_in_search_path(sroot_opt: Option<@Path>, short_name: &str) -> Option<Path> {
|
|
||||||
do sroot_opt.chain |sroot| {
|
|
||||||
debug!("Will search for a library with short name %s in \
|
|
||||||
%s", short_name, (sroot.push("lib")).to_str());
|
|
||||||
installed_library_in_workspace(short_name, sroot)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/// If some workspace `p` in the RUST_PATH contains a package matching short_name,
|
/// If some workspace `p` in the RUST_PATH contains a package matching short_name,
|
||||||
/// return Some(p) (returns the first one of there are multiple matches.) Return
|
/// return Some(p) (returns the first one of there are multiple matches.) Return
|
||||||
/// None if there's no such path.
|
/// None if there's no such path.
|
||||||
|
@ -10,10 +10,14 @@
|
|||||||
|
|
||||||
// rustpkg unit tests
|
// rustpkg unit tests
|
||||||
|
|
||||||
use context::Ctx;
|
use context::{BuildContext, Context};
|
||||||
use std::hashmap::HashMap;
|
use std::{io, libc, os, run, str, task};
|
||||||
use std::{io, libc, os, run, str};
|
use extra::arc::Arc;
|
||||||
|
use extra::arc::RWArc;
|
||||||
use extra::tempfile::mkdtemp;
|
use extra::tempfile::mkdtemp;
|
||||||
|
use extra::workcache;
|
||||||
|
use extra::workcache::{Database, Logger};
|
||||||
|
use extra::treemap::TreeMap;
|
||||||
use std::run::ProcessOutput;
|
use std::run::ProcessOutput;
|
||||||
use installed_packages::list_installed_packages;
|
use installed_packages::list_installed_packages;
|
||||||
use package_id::{PkgId};
|
use package_id::{PkgId};
|
||||||
@ -26,18 +30,24 @@ use path_util::{target_executable_in_workspace, target_test_in_workspace,
|
|||||||
use rustc::metadata::filesearch::rust_path;
|
use rustc::metadata::filesearch::rust_path;
|
||||||
use rustc::driver::driver::host_triple;
|
use rustc::driver::driver::host_triple;
|
||||||
use target::*;
|
use target::*;
|
||||||
|
use package_source::PkgSrc;
|
||||||
|
|
||||||
/// Returns the last-modified date as an Option
|
/// Returns the last-modified date as an Option
|
||||||
fn datestamp(p: &Path) -> Option<libc::time_t> {
|
fn datestamp(p: &Path) -> Option<libc::time_t> {
|
||||||
p.stat().map(|stat| stat.st_mtime)
|
p.stat().map(|stat| stat.st_mtime)
|
||||||
}
|
}
|
||||||
|
|
||||||
fn fake_ctxt(sysroot_opt: Option<@Path>) -> Ctx {
|
fn fake_ctxt(sysroot: Path, workspace: &Path) -> BuildContext {
|
||||||
Ctx {
|
let context = workcache::Context::new(
|
||||||
use_rust_path_hack: false,
|
RWArc::new(Database::new(workspace.push("rustpkg_db.json"))),
|
||||||
sysroot_opt: sysroot_opt,
|
RWArc::new(Logger::new()),
|
||||||
json: false,
|
Arc::new(TreeMap::new()));
|
||||||
dep_cache: @mut HashMap::new()
|
BuildContext {
|
||||||
|
workcache_context: context,
|
||||||
|
context: Context {
|
||||||
|
use_rust_path_hack: false,
|
||||||
|
sysroot: sysroot
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -388,7 +398,7 @@ fn lib_output_file_name(workspace: &Path, parent: &str, short_name: &str) -> Pat
|
|||||||
}
|
}
|
||||||
|
|
||||||
fn output_file_name(workspace: &Path, short_name: &str) -> Path {
|
fn output_file_name(workspace: &Path, short_name: &str) -> Path {
|
||||||
workspace.push(fmt!("%s%s", short_name, os::EXE_SUFFIX))
|
workspace.push("build").push(short_name).push(fmt!("%s%s", short_name, os::EXE_SUFFIX))
|
||||||
}
|
}
|
||||||
|
|
||||||
fn touch_source_file(workspace: &Path, pkgid: &PkgId) {
|
fn touch_source_file(workspace: &Path, pkgid: &PkgId) {
|
||||||
@ -401,12 +411,11 @@ fn touch_source_file(workspace: &Path, pkgid: &PkgId) {
|
|||||||
if run::process_output("touch", [p.to_str()]).status != 0 {
|
if run::process_output("touch", [p.to_str()]).status != 0 {
|
||||||
let _ = cond.raise((pkg_src_dir.clone(), ~"Bad path"));
|
let _ = cond.raise((pkg_src_dir.clone(), ~"Bad path"));
|
||||||
}
|
}
|
||||||
break;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Add a blank line at the end
|
/// Add a comment at the end
|
||||||
fn frob_source_file(workspace: &Path, pkgid: &PkgId) {
|
fn frob_source_file(workspace: &Path, pkgid: &PkgId) {
|
||||||
use conditions::bad_path::cond;
|
use conditions::bad_path::cond;
|
||||||
let pkg_src_dir = workspace.push("src").push(pkgid.to_str());
|
let pkg_src_dir = workspace.push("src").push(pkgid.to_str());
|
||||||
@ -423,7 +432,7 @@ fn frob_source_file(workspace: &Path, pkgid: &PkgId) {
|
|||||||
let w = io::file_writer(p, &[io::Append]);
|
let w = io::file_writer(p, &[io::Append]);
|
||||||
match w {
|
match w {
|
||||||
Err(s) => { let _ = cond.raise((p.clone(), fmt!("Bad path: %s", s))); }
|
Err(s) => { let _ = cond.raise((p.clone(), fmt!("Bad path: %s", s))); }
|
||||||
Ok(w) => w.write_line("")
|
Ok(w) => w.write_line("/* hi */")
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
None => fail!(fmt!("frob_source_file failed to find a source file in %s",
|
None => fail!(fmt!("frob_source_file failed to find a source file in %s",
|
||||||
@ -450,12 +459,13 @@ fn test_install_valid() {
|
|||||||
|
|
||||||
let sysroot = test_sysroot();
|
let sysroot = test_sysroot();
|
||||||
debug!("sysroot = %s", sysroot.to_str());
|
debug!("sysroot = %s", sysroot.to_str());
|
||||||
let ctxt = fake_ctxt(Some(@sysroot));
|
|
||||||
let temp_pkg_id = fake_pkg();
|
let temp_pkg_id = fake_pkg();
|
||||||
let temp_workspace = mk_temp_workspace(&temp_pkg_id.path, &NoVersion).pop().pop();
|
let temp_workspace = mk_temp_workspace(&temp_pkg_id.path, &NoVersion).pop().pop();
|
||||||
|
let ctxt = fake_ctxt(sysroot, &temp_workspace);
|
||||||
debug!("temp_workspace = %s", temp_workspace.to_str());
|
debug!("temp_workspace = %s", temp_workspace.to_str());
|
||||||
// should have test, bench, lib, and main
|
// should have test, bench, lib, and main
|
||||||
ctxt.install(&temp_workspace, &temp_pkg_id);
|
let src = PkgSrc::new(temp_workspace.clone(), false, temp_pkg_id.clone());
|
||||||
|
ctxt.install(src);
|
||||||
// Check that all files exist
|
// Check that all files exist
|
||||||
let exec = target_executable_in_workspace(&temp_pkg_id, &temp_workspace);
|
let exec = target_executable_in_workspace(&temp_pkg_id, &temp_workspace);
|
||||||
debug!("exec = %s", exec.to_str());
|
debug!("exec = %s", exec.to_str());
|
||||||
@ -476,32 +486,19 @@ fn test_install_valid() {
|
|||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn test_install_invalid() {
|
fn test_install_invalid() {
|
||||||
use conditions::nonexistent_package::cond;
|
let sysroot = test_sysroot();
|
||||||
use cond1 = conditions::missing_pkg_files::cond;
|
|
||||||
use cond2 = conditions::not_a_workspace::cond;
|
|
||||||
|
|
||||||
let ctxt = fake_ctxt(None);
|
|
||||||
let pkgid = fake_pkg();
|
let pkgid = fake_pkg();
|
||||||
let temp_workspace = mkdtemp(&os::tmpdir(), "test").expect("couldn't create temp dir");
|
let temp_workspace = mkdtemp(&os::tmpdir(), "test").expect("couldn't create temp dir");
|
||||||
let mut error_occurred = false;
|
let ctxt = fake_ctxt(sysroot, &temp_workspace);
|
||||||
let mut error1_occurred = false;
|
|
||||||
let mut error2_occurred = false;
|
// Uses task::try because of #9001
|
||||||
do cond1.trap(|_| {
|
let result = do task::try {
|
||||||
error1_occurred = true;
|
let pkg_src = PkgSrc::new(temp_workspace.clone(), false, pkgid.clone());
|
||||||
}).inside {
|
ctxt.install(pkg_src);
|
||||||
do cond.trap(|_| {
|
};
|
||||||
error_occurred = true;
|
// Not the best test -- doesn't test that we failed in the right way.
|
||||||
temp_workspace.clone()
|
// Best we can do for now.
|
||||||
}).inside {
|
assert!(result == Err(()));
|
||||||
do cond2.trap(|_| {
|
|
||||||
error2_occurred = true;
|
|
||||||
temp_workspace.clone()
|
|
||||||
}).inside {
|
|
||||||
ctxt.install(&temp_workspace, &pkgid);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
assert!(error_occurred && error1_occurred && error2_occurred);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// Tests above should (maybe) be converted to shell out to rustpkg, too
|
// Tests above should (maybe) be converted to shell out to rustpkg, too
|
||||||
@ -898,7 +895,6 @@ fn install_check_duplicates() {
|
|||||||
}
|
}
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
#[ignore(reason = "Workcache not yet implemented -- see #7075")]
|
|
||||||
fn no_rebuilding() {
|
fn no_rebuilding() {
|
||||||
let p_id = PkgId::new("foo");
|
let p_id = PkgId::new("foo");
|
||||||
let workspace = create_local_package(&p_id);
|
let workspace = create_local_package(&p_id);
|
||||||
@ -912,24 +908,28 @@ fn no_rebuilding() {
|
|||||||
}
|
}
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
#[ignore(reason = "Workcache not yet implemented -- see #7075")]
|
|
||||||
fn no_rebuilding_dep() {
|
fn no_rebuilding_dep() {
|
||||||
let p_id = PkgId::new("foo");
|
let p_id = PkgId::new("foo");
|
||||||
let dep_id = PkgId::new("bar");
|
let dep_id = PkgId::new("bar");
|
||||||
let workspace = create_local_package_with_dep(&p_id, &dep_id);
|
let workspace = create_local_package_with_dep(&p_id, &dep_id);
|
||||||
command_line_test([~"build", ~"foo"], &workspace);
|
command_line_test([~"build", ~"foo"], &workspace);
|
||||||
let bar_date = datestamp(&lib_output_file_name(&workspace,
|
let bar_date_1 = datestamp(&lib_output_file_name(&workspace,
|
||||||
".rust",
|
".rust",
|
||||||
"bar"));
|
"bar"));
|
||||||
let foo_date = datestamp(&output_file_name(&workspace, "foo"));
|
let foo_date_1 = datestamp(&output_file_name(&workspace, "foo"));
|
||||||
assert!(bar_date < foo_date);
|
|
||||||
|
frob_source_file(&workspace, &p_id);
|
||||||
|
command_line_test([~"build", ~"foo"], &workspace);
|
||||||
|
let bar_date_2 = datestamp(&lib_output_file_name(&workspace,
|
||||||
|
".rust",
|
||||||
|
"bar"));
|
||||||
|
let foo_date_2 = datestamp(&output_file_name(&workspace, "foo"));
|
||||||
|
assert_eq!(bar_date_1, bar_date_2);
|
||||||
|
assert!(foo_date_1 < foo_date_2);
|
||||||
|
assert!(foo_date_1 > bar_date_1);
|
||||||
}
|
}
|
||||||
|
|
||||||
// n.b. The following two tests are ignored; they worked "accidentally" before,
|
|
||||||
// when the behavior was "always rebuild libraries" (now it's "never rebuild
|
|
||||||
// libraries if they already exist"). They can be un-ignored once #7075 is done.
|
|
||||||
#[test]
|
#[test]
|
||||||
#[ignore(reason = "Workcache not yet implemented -- see #7075")]
|
|
||||||
fn do_rebuild_dep_dates_change() {
|
fn do_rebuild_dep_dates_change() {
|
||||||
let p_id = PkgId::new("foo");
|
let p_id = PkgId::new("foo");
|
||||||
let dep_id = PkgId::new("bar");
|
let dep_id = PkgId::new("bar");
|
||||||
@ -946,7 +946,6 @@ fn do_rebuild_dep_dates_change() {
|
|||||||
}
|
}
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
#[ignore(reason = "Workcache not yet implemented -- see #7075")]
|
|
||||||
fn do_rebuild_dep_only_contents_change() {
|
fn do_rebuild_dep_only_contents_change() {
|
||||||
let p_id = PkgId::new("foo");
|
let p_id = PkgId::new("foo");
|
||||||
let dep_id = PkgId::new("bar");
|
let dep_id = PkgId::new("bar");
|
||||||
|
@ -9,6 +9,7 @@
|
|||||||
// except according to those terms.
|
// except according to those terms.
|
||||||
|
|
||||||
use std::os;
|
use std::os;
|
||||||
|
use extra::workcache;
|
||||||
use rustc::driver::{driver, session};
|
use rustc::driver::{driver, session};
|
||||||
use extra::getopts::groups::getopts;
|
use extra::getopts::groups::getopts;
|
||||||
use syntax::ast_util::*;
|
use syntax::ast_util::*;
|
||||||
@ -18,12 +19,13 @@ use syntax::{ast, attr, codemap, diagnostic, fold};
|
|||||||
use syntax::attr::AttrMetaMethods;
|
use syntax::attr::AttrMetaMethods;
|
||||||
use rustc::back::link::output_type_exe;
|
use rustc::back::link::output_type_exe;
|
||||||
use rustc::driver::session::{lib_crate, bin_crate};
|
use rustc::driver::session::{lib_crate, bin_crate};
|
||||||
use context::{Ctx, in_target};
|
use context::{in_target, BuildContext};
|
||||||
use package_id::PkgId;
|
use package_id::PkgId;
|
||||||
use search::{find_library_in_search_path, find_installed_library_in_rust_path};
|
use package_source::PkgSrc;
|
||||||
use path_util::{target_library_in_workspace, U_RWX};
|
use path_util::{installed_library_in_workspace, U_RWX};
|
||||||
|
|
||||||
pub use target::{OutputType, Main, Lib, Bench, Test};
|
pub use target::{OutputType, Main, Lib, Bench, Test};
|
||||||
use version::NoVersion;
|
use workcache_support::{digest_file_with_date, digest_only_date};
|
||||||
|
|
||||||
// It would be nice to have the list of commands in just one place -- for example,
|
// It would be nice to have the list of commands in just one place -- for example,
|
||||||
// you could update the match in rustpkg.rc but forget to update this list. I think
|
// you could update the match in rustpkg.rc but forget to update this list. I think
|
||||||
@ -151,16 +153,15 @@ pub fn ready_crate(sess: session::Session,
|
|||||||
@fold.fold_crate(crate)
|
@fold.fold_crate(crate)
|
||||||
}
|
}
|
||||||
|
|
||||||
// FIXME (#4432): Use workcache to only compile when needed
|
pub fn compile_input(ctxt: &BuildContext,
|
||||||
pub fn compile_input(ctxt: &Ctx,
|
exec: &mut workcache::Exec,
|
||||||
pkg_id: &PkgId,
|
pkg_id: &PkgId,
|
||||||
in_file: &Path,
|
in_file: &Path,
|
||||||
workspace: &Path,
|
workspace: &Path,
|
||||||
flags: &[~str],
|
flags: &[~str],
|
||||||
cfgs: &[~str],
|
cfgs: &[~str],
|
||||||
opt: bool,
|
opt: bool,
|
||||||
what: OutputType) -> bool {
|
what: OutputType) -> Path {
|
||||||
|
|
||||||
assert!(in_file.components.len() > 1);
|
assert!(in_file.components.len() > 1);
|
||||||
let input = driver::file_input((*in_file).clone());
|
let input = driver::file_input((*in_file).clone());
|
||||||
debug!("compile_input: %s / %?", in_file.to_str(), what);
|
debug!("compile_input: %s / %?", in_file.to_str(), what);
|
||||||
@ -173,7 +174,7 @@ pub fn compile_input(ctxt: &Ctx,
|
|||||||
|
|
||||||
debug!("flags: %s", flags.connect(" "));
|
debug!("flags: %s", flags.connect(" "));
|
||||||
debug!("cfgs: %s", cfgs.connect(" "));
|
debug!("cfgs: %s", cfgs.connect(" "));
|
||||||
debug!("out_dir = %s", out_dir.to_str());
|
debug!("compile_input's sysroot = %s", ctxt.sysroot().to_str());
|
||||||
|
|
||||||
let crate_type = match what {
|
let crate_type = match what {
|
||||||
Lib => lib_crate,
|
Lib => lib_crate,
|
||||||
@ -191,19 +192,19 @@ pub fn compile_input(ctxt: &Ctx,
|
|||||||
driver::optgroups()).unwrap();
|
driver::optgroups()).unwrap();
|
||||||
// Hack so that rustpkg can run either out of a rustc target dir,
|
// Hack so that rustpkg can run either out of a rustc target dir,
|
||||||
// or the host dir
|
// or the host dir
|
||||||
let sysroot_to_use = if !in_target(ctxt.sysroot_opt) {
|
let sysroot_to_use = @if !in_target(&ctxt.sysroot()) {
|
||||||
ctxt.sysroot_opt
|
ctxt.sysroot()
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
ctxt.sysroot_opt.map(|p| { @p.pop().pop().pop() })
|
ctxt.sysroot().pop().pop().pop()
|
||||||
};
|
};
|
||||||
debug!("compile_input's sysroot = %?", ctxt.sysroot_opt_str());
|
debug!("compile_input's sysroot = %s", ctxt.sysroot().to_str());
|
||||||
debug!("sysroot_to_use = %?", sysroot_to_use);
|
debug!("sysroot_to_use = %s", sysroot_to_use.to_str());
|
||||||
let options = @session::options {
|
let options = @session::options {
|
||||||
crate_type: crate_type,
|
crate_type: crate_type,
|
||||||
optimize: if opt { session::Aggressive } else { session::No },
|
optimize: if opt { session::Aggressive } else { session::No },
|
||||||
test: what == Test || what == Bench,
|
test: what == Test || what == Bench,
|
||||||
maybe_sysroot: sysroot_to_use,
|
maybe_sysroot: Some(sysroot_to_use),
|
||||||
addl_lib_search_paths: @mut (~[out_dir.clone()]),
|
addl_lib_search_paths: @mut (~[out_dir.clone()]),
|
||||||
// output_type should be conditional
|
// output_type should be conditional
|
||||||
output_type: output_type_exe, // Use this to get a library? That's weird
|
output_type: output_type_exe, // Use this to get a library? That's weird
|
||||||
@ -228,11 +229,11 @@ pub fn compile_input(ctxt: &Ctx,
|
|||||||
// `extern mod` directives.
|
// `extern mod` directives.
|
||||||
let cfg = driver::build_configuration(sess);
|
let cfg = driver::build_configuration(sess);
|
||||||
let mut crate = driver::phase_1_parse_input(sess, cfg.clone(), &input);
|
let mut crate = driver::phase_1_parse_input(sess, cfg.clone(), &input);
|
||||||
crate = driver::phase_2_configure_and_expand(sess, cfg, crate);
|
crate = driver::phase_2_configure_and_expand(sess, cfg.clone(), crate);
|
||||||
|
|
||||||
// Not really right. Should search other workspaces too, and the installed
|
// Not really right. Should search other workspaces too, and the installed
|
||||||
// database (which doesn't exist yet)
|
// database (which doesn't exist yet)
|
||||||
find_and_install_dependencies(ctxt, sess, workspace, crate,
|
find_and_install_dependencies(ctxt, sess, exec, workspace, crate,
|
||||||
|p| {
|
|p| {
|
||||||
debug!("a dependency: %s", p.to_str());
|
debug!("a dependency: %s", p.to_str());
|
||||||
// Pass the directory containing a dependency
|
// Pass the directory containing a dependency
|
||||||
@ -269,8 +270,7 @@ pub fn compile_input(ctxt: &Ctx,
|
|||||||
|
|
||||||
debug!("calling compile_crate_from_input, workspace = %s,
|
debug!("calling compile_crate_from_input, workspace = %s,
|
||||||
building_library = %?", out_dir.to_str(), sess.building_library);
|
building_library = %?", out_dir.to_str(), sess.building_library);
|
||||||
compile_crate_from_input(&input, &out_dir, sess, crate);
|
compile_crate_from_input(in_file, exec, &out_dir, sess, crate)
|
||||||
true
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// Should use workcache to avoid recompiling when not necessary
|
// Should use workcache to avoid recompiling when not necessary
|
||||||
@ -278,17 +278,19 @@ pub fn compile_input(ctxt: &Ctx,
|
|||||||
// If crate_opt is present, then finish compilation. If it's None, then
|
// If crate_opt is present, then finish compilation. If it's None, then
|
||||||
// call compile_upto and return the crate
|
// call compile_upto and return the crate
|
||||||
// also, too many arguments
|
// also, too many arguments
|
||||||
pub fn compile_crate_from_input(input: &driver::input,
|
pub fn compile_crate_from_input(input: &Path,
|
||||||
|
exec: &mut workcache::Exec,
|
||||||
// should be of the form <workspace>/build/<pkg id's path>
|
// should be of the form <workspace>/build/<pkg id's path>
|
||||||
out_dir: &Path,
|
out_dir: &Path,
|
||||||
sess: session::Session,
|
sess: session::Session,
|
||||||
crate: @ast::Crate) {
|
crate: @ast::Crate) -> Path {
|
||||||
debug!("Calling build_output_filenames with %s, building library? %?",
|
debug!("Calling build_output_filenames with %s, building library? %?",
|
||||||
out_dir.to_str(), sess.building_library);
|
out_dir.to_str(), sess.building_library);
|
||||||
|
|
||||||
// bad copy
|
// bad copy
|
||||||
debug!("out_dir = %s", out_dir.to_str());
|
debug!("out_dir = %s", out_dir.to_str());
|
||||||
let outputs = driver::build_output_filenames(input, &Some(out_dir.clone()), &None,
|
let outputs = driver::build_output_filenames(&driver::file_input(input.clone()),
|
||||||
|
&Some(out_dir.clone()), &None,
|
||||||
crate.attrs, sess);
|
crate.attrs, sess);
|
||||||
|
|
||||||
debug!("Outputs are out_filename: %s and obj_filename: %s and output type = %?",
|
debug!("Outputs are out_filename: %s and obj_filename: %s and output type = %?",
|
||||||
@ -304,8 +306,13 @@ pub fn compile_crate_from_input(input: &driver::input,
|
|||||||
&analysis,
|
&analysis,
|
||||||
outputs);
|
outputs);
|
||||||
driver::phase_5_run_llvm_passes(sess, &translation, outputs);
|
driver::phase_5_run_llvm_passes(sess, &translation, outputs);
|
||||||
if driver::stop_after_phase_5(sess) { return; }
|
if driver::stop_after_phase_5(sess) { return outputs.out_filename; }
|
||||||
driver::phase_6_link_output(sess, &translation, outputs);
|
driver::phase_6_link_output(sess, &translation, outputs);
|
||||||
|
|
||||||
|
// Register dependency on the source file
|
||||||
|
exec.discover_input("file", input.to_str(), digest_file_with_date(input));
|
||||||
|
|
||||||
|
outputs.out_filename
|
||||||
}
|
}
|
||||||
|
|
||||||
#[cfg(windows)]
|
#[cfg(windows)]
|
||||||
@ -318,76 +325,92 @@ pub fn exe_suffix() -> ~str { ~".exe" }
|
|||||||
pub fn exe_suffix() -> ~str { ~"" }
|
pub fn exe_suffix() -> ~str { ~"" }
|
||||||
|
|
||||||
// Called by build_crates
|
// Called by build_crates
|
||||||
// FIXME (#4432): Use workcache to only compile when needed
|
pub fn compile_crate(ctxt: &BuildContext,
|
||||||
pub fn compile_crate(ctxt: &Ctx, pkg_id: &PkgId,
|
exec: &mut workcache::Exec,
|
||||||
|
pkg_id: &PkgId,
|
||||||
crate: &Path, workspace: &Path,
|
crate: &Path, workspace: &Path,
|
||||||
flags: &[~str], cfgs: &[~str], opt: bool,
|
flags: &[~str], cfgs: &[~str], opt: bool,
|
||||||
what: OutputType) -> bool {
|
what: OutputType) -> Path {
|
||||||
debug!("compile_crate: crate=%s, workspace=%s", crate.to_str(), workspace.to_str());
|
debug!("compile_crate: crate=%s, workspace=%s", crate.to_str(), workspace.to_str());
|
||||||
debug!("compile_crate: short_name = %s, flags =...", pkg_id.to_str());
|
debug!("compile_crate: short_name = %s, flags =...", pkg_id.to_str());
|
||||||
for fl in flags.iter() {
|
for fl in flags.iter() {
|
||||||
debug!("+++ %s", *fl);
|
debug!("+++ %s", *fl);
|
||||||
}
|
}
|
||||||
compile_input(ctxt, pkg_id, crate, workspace, flags, cfgs, opt, what)
|
compile_input(ctxt, exec, pkg_id, crate, workspace, flags, cfgs, opt, what)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
/// Collect all `extern mod` directives in `c`, then
|
/// Collect all `extern mod` directives in `c`, then
|
||||||
/// try to install their targets, failing if any target
|
/// try to install their targets, failing if any target
|
||||||
/// can't be found.
|
/// can't be found.
|
||||||
pub fn find_and_install_dependencies(ctxt: &Ctx,
|
pub fn find_and_install_dependencies(ctxt: &BuildContext,
|
||||||
sess: session::Session,
|
sess: session::Session,
|
||||||
|
exec: &mut workcache::Exec,
|
||||||
workspace: &Path,
|
workspace: &Path,
|
||||||
c: &ast::Crate,
|
c: &ast::Crate,
|
||||||
save: @fn(Path)
|
save: @fn(Path)
|
||||||
) {
|
) {
|
||||||
// :-(
|
debug!("Finding and installing dependencies...");
|
||||||
debug!("In find_and_install_dependencies...");
|
do c.each_view_item |vi| {
|
||||||
let my_workspace = (*workspace).clone();
|
|
||||||
let my_ctxt = *ctxt;
|
|
||||||
do c.each_view_item() |vi: &ast::view_item| {
|
|
||||||
debug!("A view item!");
|
debug!("A view item!");
|
||||||
match vi.node {
|
match vi.node {
|
||||||
// ignore metadata, I guess
|
// ignore metadata, I guess
|
||||||
ast::view_item_extern_mod(lib_ident, path_opt, _, _) => {
|
ast::view_item_extern_mod(lib_ident, path_opt, _, _) => {
|
||||||
match my_ctxt.sysroot_opt {
|
let lib_name = match path_opt {
|
||||||
Some(ref x) => debug!("*** sysroot: %s", x.to_str()),
|
Some(p) => p,
|
||||||
None => debug!("No sysroot given")
|
None => sess.str_of(lib_ident)
|
||||||
};
|
};
|
||||||
let lib_name = match path_opt { // ???
|
match installed_library_in_workspace(lib_name, &ctxt.sysroot()) {
|
||||||
Some(p) => p, None => sess.str_of(lib_ident) };
|
Some(ref installed_path) => {
|
||||||
match find_library_in_search_path(my_ctxt.sysroot_opt, lib_name) {
|
|
||||||
Some(installed_path) => {
|
|
||||||
debug!("It exists: %s", installed_path.to_str());
|
debug!("It exists: %s", installed_path.to_str());
|
||||||
|
// Say that [path for c] has a discovered dependency on
|
||||||
|
// installed_path
|
||||||
|
// For binary files, we only hash the datestamp, not the contents.
|
||||||
|
// I'm not sure what the right thing is.
|
||||||
|
// Now we know that this crate has a discovered dependency on
|
||||||
|
// installed_path
|
||||||
|
exec.discover_input("binary", installed_path.to_str(),
|
||||||
|
digest_only_date(installed_path));
|
||||||
}
|
}
|
||||||
None => {
|
None => {
|
||||||
// FIXME #8711: need to parse version out of path_opt
|
// FIXME #8711: need to parse version out of path_opt
|
||||||
match find_installed_library_in_rust_path(lib_name, &NoVersion) {
|
debug!("Trying to install library %s, rebuilding it",
|
||||||
Some(installed_path) => {
|
lib_name.to_str());
|
||||||
debug!("Found library %s, not rebuilding it",
|
// Try to install it
|
||||||
installed_path.to_str());
|
let pkg_id = PkgId::new(lib_name);
|
||||||
// Once workcache is implemented, we'll actually check
|
let (outputs_disc, inputs_disc) =
|
||||||
// whether or not the library at installed_path is fresh
|
ctxt.install(PkgSrc::new(workspace.clone(), false, pkg_id));
|
||||||
save(installed_path.pop());
|
debug!("Installed %s, returned %? dependencies and \
|
||||||
|
%? transitive dependencies",
|
||||||
|
lib_name, outputs_disc.len(), inputs_disc.len());
|
||||||
|
for dep in outputs_disc.iter() {
|
||||||
|
debug!("Discovering a binary input: %s", dep.to_str());
|
||||||
|
exec.discover_input("binary", dep.to_str(),
|
||||||
|
digest_only_date(dep));
|
||||||
|
}
|
||||||
|
for &(ref what, ref dep) in inputs_disc.iter() {
|
||||||
|
if *what == ~"file" {
|
||||||
|
exec.discover_input(*what, *dep,
|
||||||
|
digest_file_with_date(&Path(*dep)));
|
||||||
}
|
}
|
||||||
None => {
|
else if *what == ~"binary" {
|
||||||
debug!("Trying to install library %s, rebuilding it",
|
exec.discover_input(*what, *dep,
|
||||||
lib_name.to_str());
|
digest_only_date(&Path(*dep)));
|
||||||
// Try to install it
|
}
|
||||||
let pkg_id = PkgId::new(lib_name);
|
else {
|
||||||
my_ctxt.install(&my_workspace, &pkg_id);
|
fail!("Bad kind: %s", *what);
|
||||||
// Also, add an additional search path
|
}
|
||||||
debug!("let installed_path...")
|
}
|
||||||
let installed_path = target_library_in_workspace(&pkg_id,
|
// Also, add an additional search path
|
||||||
&my_workspace).pop();
|
let installed_library =
|
||||||
debug!("Great, I installed %s, and it's in %s",
|
installed_library_in_workspace(lib_name, workspace)
|
||||||
lib_name, installed_path.to_str());
|
.expect( fmt!("rustpkg failed to install dependency %s",
|
||||||
save(installed_path);
|
lib_name));
|
||||||
}
|
let install_dir = installed_library.pop();
|
||||||
|
debug!("Installed %s into %s", lib_name, install_dir.to_str());
|
||||||
|
save(install_dir);
|
||||||
}
|
}
|
||||||
}
|
}}
|
||||||
}
|
|
||||||
}
|
|
||||||
// Ignore `use`s
|
// Ignore `use`s
|
||||||
_ => ()
|
_ => ()
|
||||||
}
|
}
|
||||||
|
@ -99,12 +99,14 @@ pub fn try_getting_local_version(local_path: &Path) -> Option<Version> {
|
|||||||
let rustpath = rust_path();
|
let rustpath = rust_path();
|
||||||
for rp in rustpath.iter() {
|
for rp in rustpath.iter() {
|
||||||
let local_path = rp.push_rel(local_path);
|
let local_path = rp.push_rel(local_path);
|
||||||
debug!("in try_getting_local_version");
|
let git_dir = local_path.push(".git");
|
||||||
|
if !os::path_is_dir(&git_dir) {
|
||||||
|
loop;
|
||||||
|
}
|
||||||
let outp = run::process_output("git",
|
let outp = run::process_output("git",
|
||||||
[fmt!("--git-dir=%s", local_path.push(".git").to_str()),
|
[fmt!("--git-dir=%s", git_dir.to_str()), ~"tag", ~"-l"]);
|
||||||
~"tag", ~"-l"]);
|
|
||||||
|
|
||||||
debug!("git --git-dir=%s tag -l ~~~> %?", local_path.push(".git").to_str(), outp.status);
|
debug!("git --git-dir=%s tag -l ~~~> %?", git_dir.to_str(), outp.status);
|
||||||
|
|
||||||
if outp.status != 0 {
|
if outp.status != 0 {
|
||||||
loop;
|
loop;
|
||||||
@ -129,9 +131,7 @@ pub fn try_getting_local_version(local_path: &Path) -> Option<Version> {
|
|||||||
/// and the most recent tag in that repo denotes a version, return it;
|
/// and the most recent tag in that repo denotes a version, return it;
|
||||||
/// otherwise, `None`
|
/// otherwise, `None`
|
||||||
pub fn try_getting_version(remote_path: &Path) -> Option<Version> {
|
pub fn try_getting_version(remote_path: &Path) -> Option<Version> {
|
||||||
debug!("try_getting_version: %s", remote_path.to_str());
|
|
||||||
if is_url_like(remote_path) {
|
if is_url_like(remote_path) {
|
||||||
debug!("Trying to fetch its sources..");
|
|
||||||
let tmp_dir = mkdtemp(&os::tmpdir(),
|
let tmp_dir = mkdtemp(&os::tmpdir(),
|
||||||
"test").expect("try_getting_version: couldn't create temp dir");
|
"test").expect("try_getting_version: couldn't create temp dir");
|
||||||
debug!("(to get version) executing {git clone https://%s %s}",
|
debug!("(to get version) executing {git clone https://%s %s}",
|
||||||
@ -218,14 +218,11 @@ pub fn split_version<'a>(s: &'a str) -> Option<(&'a str, Version)> {
|
|||||||
pub fn split_version_general<'a>(s: &'a str, sep: char) -> Option<(&'a str, Version)> {
|
pub fn split_version_general<'a>(s: &'a str, sep: char) -> Option<(&'a str, Version)> {
|
||||||
match s.rfind(sep) {
|
match s.rfind(sep) {
|
||||||
Some(i) => {
|
Some(i) => {
|
||||||
debug!("in %s, i = %?", s, i);
|
|
||||||
let path = s.slice(0, i);
|
let path = s.slice(0, i);
|
||||||
debug!("path = %s", path);
|
|
||||||
// n.b. for now, assuming an exact revision is intended, not a SemVer
|
// n.b. for now, assuming an exact revision is intended, not a SemVer
|
||||||
Some((path, ExactRevision(s.slice(i + 1, s.len()).to_owned())))
|
Some((path, ExactRevision(s.slice(i + 1, s.len()).to_owned())))
|
||||||
}
|
}
|
||||||
None => {
|
None => {
|
||||||
debug!("%s doesn't look like an explicit-version thing", s);
|
|
||||||
None
|
None
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
58
src/librustpkg/workcache_support.rs
Normal file
58
src/librustpkg/workcache_support.rs
Normal file
@ -0,0 +1,58 @@
|
|||||||
|
// Copyright 2013 The Rust Project Developers. See the COPYRIGHT
|
||||||
|
// file at the top-level directory of this distribution and at
|
||||||
|
// http://rust-lang.org/COPYRIGHT.
|
||||||
|
//
|
||||||
|
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
|
||||||
|
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
|
||||||
|
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
|
||||||
|
// option. This file may not be copied, modified, or distributed
|
||||||
|
// except according to those terms.
|
||||||
|
|
||||||
|
use extra::sha1::Sha1;
|
||||||
|
use extra::digest::Digest;
|
||||||
|
use extra::workcache;
|
||||||
|
use std::io;
|
||||||
|
|
||||||
|
/// Hashes the file contents along with the last-modified time
|
||||||
|
pub fn digest_file_with_date(path: &Path) -> ~str {
|
||||||
|
use conditions::bad_path::cond;
|
||||||
|
use cond1 = conditions::bad_stat::cond;
|
||||||
|
|
||||||
|
let mut sha = ~Sha1::new();
|
||||||
|
let s = io::read_whole_file_str(path);
|
||||||
|
match s {
|
||||||
|
Ok(s) => {
|
||||||
|
(*sha).input_str(s);
|
||||||
|
let st = match path.stat() {
|
||||||
|
Some(st) => st,
|
||||||
|
None => cond1.raise((path.clone(), fmt!("Couldn't get file access time")))
|
||||||
|
};
|
||||||
|
(*sha).input_str(st.st_mtime.to_str());
|
||||||
|
(*sha).result_str()
|
||||||
|
}
|
||||||
|
Err(e) => cond.raise((path.clone(), fmt!("Couldn't read file: %s", e))).to_str()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Hashes only the last-modified time
|
||||||
|
pub fn digest_only_date(path: &Path) -> ~str {
|
||||||
|
use cond = conditions::bad_stat::cond;
|
||||||
|
|
||||||
|
let mut sha = ~Sha1::new();
|
||||||
|
let st = match path.stat() {
|
||||||
|
Some(st) => st,
|
||||||
|
None => cond.raise((path.clone(), fmt!("Couldn't get file access time")))
|
||||||
|
};
|
||||||
|
(*sha).input_str(st.st_mtime.to_str());
|
||||||
|
(*sha).result_str()
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Adds multiple discovered outputs
|
||||||
|
pub fn discover_outputs(e: &mut workcache::Exec, outputs: ~[Path]) {
|
||||||
|
debug!("Discovering %? outputs", outputs.len());
|
||||||
|
for p in outputs.iter() {
|
||||||
|
debug!("Discovering output! %s", p.to_str());
|
||||||
|
// For now, assume that all discovered outputs are binaries
|
||||||
|
e.discover_output("binary", p.to_str(), digest_only_date(p));
|
||||||
|
}
|
||||||
|
}
|
@ -12,14 +12,14 @@
|
|||||||
|
|
||||||
use std::{os,util};
|
use std::{os,util};
|
||||||
use std::path::Path;
|
use std::path::Path;
|
||||||
use context::Ctx;
|
use context::Context;
|
||||||
use path_util::{workspace_contains_package_id, find_dir_using_rust_path_hack};
|
use path_util::{workspace_contains_package_id, find_dir_using_rust_path_hack};
|
||||||
use util::option_to_vec;
|
use util::option_to_vec;
|
||||||
use package_id::PkgId;
|
use package_id::PkgId;
|
||||||
|
|
||||||
use path_util::rust_path;
|
use path_util::rust_path;
|
||||||
|
|
||||||
pub fn each_pkg_parent_workspace(cx: &Ctx, pkgid: &PkgId, action: &fn(&Path) -> bool) -> bool {
|
pub fn each_pkg_parent_workspace(cx: &Context, pkgid: &PkgId, action: &fn(&Path) -> bool) -> bool {
|
||||||
// Using the RUST_PATH, find workspaces that contain
|
// Using the RUST_PATH, find workspaces that contain
|
||||||
// this package ID
|
// this package ID
|
||||||
let workspaces = pkg_parent_workspaces(cx, pkgid);
|
let workspaces = pkg_parent_workspaces(cx, pkgid);
|
||||||
@ -38,12 +38,12 @@ pub fn each_pkg_parent_workspace(cx: &Ctx, pkgid: &PkgId, action: &fn(&Path) ->
|
|||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn pkg_parent_workspaces(cx: &Ctx, pkgid: &PkgId) -> ~[Path] {
|
pub fn pkg_parent_workspaces(cx: &Context, pkgid: &PkgId) -> ~[Path] {
|
||||||
let rs: ~[Path] = rust_path().move_iter()
|
let rs: ~[Path] = rust_path().move_iter()
|
||||||
.filter(|ws| workspace_contains_package_id(pkgid, ws))
|
.filter(|ws| workspace_contains_package_id(pkgid, ws))
|
||||||
.collect();
|
.collect();
|
||||||
if cx.use_rust_path_hack {
|
if cx.use_rust_path_hack {
|
||||||
rs + option_to_vec(find_dir_using_rust_path_hack(cx, pkgid))
|
rs + option_to_vec(find_dir_using_rust_path_hack(pkgid))
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
rs
|
rs
|
||||||
|
@ -14,7 +14,7 @@ use ast_util;
|
|||||||
use codemap::{Span, dummy_sp};
|
use codemap::{Span, dummy_sp};
|
||||||
use opt_vec;
|
use opt_vec;
|
||||||
use parse::token;
|
use parse::token;
|
||||||
use visit::{SimpleVisitor, SimpleVisitorVisitor, Visitor};
|
use visit::{SimpleVisitor, Visitor};
|
||||||
use visit;
|
use visit;
|
||||||
|
|
||||||
use std::hashmap::HashMap;
|
use std::hashmap::HashMap;
|
||||||
@ -684,94 +684,25 @@ pub fn walk_pat(pat: @Pat, it: &fn(@Pat) -> bool) -> bool {
|
|||||||
}
|
}
|
||||||
|
|
||||||
pub trait EachViewItem {
|
pub trait EachViewItem {
|
||||||
fn each_view_item(&self, f: @fn(&ast::view_item) -> bool) -> bool;
|
fn each_view_item(&self, f: &fn(&ast::view_item) -> bool) -> bool;
|
||||||
}
|
}
|
||||||
|
|
||||||
struct EachViewItemData {
|
struct EachViewItemData<'self> {
|
||||||
callback: @fn(&ast::view_item) -> bool,
|
callback: &'self fn(&ast::view_item) -> bool,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl SimpleVisitor for EachViewItemData {
|
impl<'self> Visitor<()> for EachViewItemData<'self> {
|
||||||
fn visit_mod(&mut self, _: &_mod, _: Span, _: NodeId) {
|
fn visit_view_item(&mut self, view_item: &ast::view_item, _: ()) {
|
||||||
// XXX: Default method.
|
|
||||||
}
|
|
||||||
fn visit_view_item(&mut self, view_item: &view_item) {
|
|
||||||
let _ = (self.callback)(view_item);
|
let _ = (self.callback)(view_item);
|
||||||
}
|
}
|
||||||
fn visit_foreign_item(&mut self, _: @foreign_item) {
|
|
||||||
// XXX: Default method.
|
|
||||||
}
|
|
||||||
fn visit_item(&mut self, _: @item) {
|
|
||||||
// XXX: Default method.
|
|
||||||
}
|
|
||||||
fn visit_local(&mut self, _: @Local) {
|
|
||||||
// XXX: Default method.
|
|
||||||
}
|
|
||||||
fn visit_block(&mut self, _: &Block) {
|
|
||||||
// XXX: Default method.
|
|
||||||
}
|
|
||||||
fn visit_stmt(&mut self, _: @Stmt) {
|
|
||||||
// XXX: Default method.
|
|
||||||
}
|
|
||||||
fn visit_arm(&mut self, _: &Arm) {
|
|
||||||
// XXX: Default method.
|
|
||||||
}
|
|
||||||
fn visit_pat(&mut self, _: @Pat) {
|
|
||||||
// XXX: Default method.
|
|
||||||
}
|
|
||||||
fn visit_decl(&mut self, _: @Decl) {
|
|
||||||
// XXX: Default method.
|
|
||||||
}
|
|
||||||
fn visit_expr(&mut self, _: @Expr) {
|
|
||||||
// XXX: Default method.
|
|
||||||
}
|
|
||||||
fn visit_expr_post(&mut self, _: @Expr) {
|
|
||||||
// XXX: Default method.
|
|
||||||
}
|
|
||||||
fn visit_ty(&mut self, _: &Ty) {
|
|
||||||
// XXX: Default method.
|
|
||||||
}
|
|
||||||
fn visit_generics(&mut self, _: &Generics) {
|
|
||||||
// XXX: Default method.
|
|
||||||
}
|
|
||||||
fn visit_fn(&mut self,
|
|
||||||
_: &visit::fn_kind,
|
|
||||||
_: &fn_decl,
|
|
||||||
_: &Block,
|
|
||||||
_: Span,
|
|
||||||
_: NodeId) {
|
|
||||||
// XXX: Default method.
|
|
||||||
}
|
|
||||||
fn visit_ty_method(&mut self, _: &TypeMethod) {
|
|
||||||
// XXX: Default method.
|
|
||||||
}
|
|
||||||
fn visit_trait_method(&mut self, _: &trait_method) {
|
|
||||||
// XXX: Default method.
|
|
||||||
}
|
|
||||||
fn visit_struct_def(&mut self,
|
|
||||||
_: @struct_def,
|
|
||||||
_: Ident,
|
|
||||||
_: &Generics,
|
|
||||||
_: NodeId) {
|
|
||||||
// XXX: Default method.
|
|
||||||
}
|
|
||||||
fn visit_struct_field(&mut self, _: @struct_field) {
|
|
||||||
// XXX: Default method.
|
|
||||||
}
|
|
||||||
fn visit_struct_method(&mut self, _: @method) {
|
|
||||||
// XXX: Default method.
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
impl EachViewItem for ast::Crate {
|
impl EachViewItem for ast::Crate {
|
||||||
fn each_view_item(&self, f: @fn(&ast::view_item) -> bool) -> bool {
|
fn each_view_item(&self, f: &fn(&ast::view_item) -> bool) -> bool {
|
||||||
let data = @mut EachViewItemData {
|
let mut visit = EachViewItemData {
|
||||||
callback: f,
|
callback: f,
|
||||||
};
|
};
|
||||||
let visitor = @mut SimpleVisitorVisitor {
|
visit::walk_crate(&mut visit, self, ());
|
||||||
simple_visitor: data as @mut SimpleVisitor,
|
|
||||||
};
|
|
||||||
visit::walk_crate(visitor, self, ());
|
|
||||||
true
|
true
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
Loading…
Reference in New Issue
Block a user