rust/src/librustpkg/package_source.rs
Daniel Micay 1008945528 remove obsolete foreach keyword
this has been replaced by `for`
2013-08-03 22:48:02 -04:00

244 lines
8.8 KiB
Rust

// Copyright 2012-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 target::*;
use package_id::PkgId;
use std::path::Path;
use std::{os, str};
use context::*;
use crate::Crate;
use messages::*;
use source_control::{git_clone, git_clone_general};
use path_util::pkgid_src_in_workspace;
use util::compile_crate;
// An enumeration of the unpacked source of a package workspace.
// This contains a list of files found in the source workspace.
pub struct PkgSrc {
root: Path, // root of where the package source code lives
dst_dir: Path, // directory where we will put the compiled output
id: PkgId,
libs: ~[Crate],
mains: ~[Crate],
tests: ~[Crate],
benchs: ~[Crate],
}
condition! {
build_err: (~str) -> ();
}
impl PkgSrc {
pub fn new(src_dir: &Path, dst_dir: &Path,
id: &PkgId) -> PkgSrc {
PkgSrc {
root: (*src_dir).clone(),
dst_dir: (*dst_dir).clone(),
id: (*id).clone(),
libs: ~[],
mains: ~[],
tests: ~[],
benchs: ~[]
}
}
fn check_dir(&self) -> Path {
use conditions::nonexistent_package::cond;
debug!("Pushing onto root: %s | %s", self.id.remote_path.to_str(),
self.root.to_str());
let dir;
let dirs = pkgid_src_in_workspace(&self.id, &self.root);
debug!("Checking dirs: %?", dirs);
let path = dirs.iter().find_(|&d| os::path_exists(d));
match path {
Some(d) => dir = (*d).clone(),
None => dir = match self.fetch_git() {
None => cond.raise((self.id.clone(), ~"supplied path for package dir does not \
exist, and couldn't interpret it as a URL fragment")),
Some(d) => d
}
}
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
/// fetching it and caching it in a local directory. Return the cached directory
/// if this was successful, None otherwise. Similarly, if the package id
/// refers to a git repo on the local version, also check it out.
/// (right now we only support git)
pub fn fetch_git(&self) -> Option<Path> {
let mut local = self.root.push("src");
local = local.push(self.id.to_str());
// Git can't clone into a non-empty directory
os::remove_dir_recursive(&local);
debug!("Checking whether %s exists locally. Cwd = %s, does it? %?",
self.id.local_path.to_str(),
os::getcwd().to_str(),
os::path_exists(&*self.id.local_path));
if os::path_exists(&*self.id.local_path) {
debug!("%s exists locally! Cloning it into %s",
self.id.local_path.to_str(), local.to_str());
git_clone(&*self.id.local_path, &local, &self.id.version);
return Some(local);
}
let url = fmt!("https://%s", self.id.remote_path.to_str());
note(fmt!("Fetching package: git clone %s %s [version=%s]",
url, local.to_str(), self.id.version.to_str()));
if git_clone_general(url, &local, &self.id.version) {
Some(local)
}
else {
None
}
}
// If a file named "pkg.rs" in the current directory exists,
// return the path for it. Otherwise, None
pub fn package_script_option(&self, cwd: &Path) -> Option<Path> {
let maybe_path = cwd.push("pkg.rs");
if os::path_exists(&maybe_path) {
Some(maybe_path)
}
else {
None
}
}
/// True if the given path's stem is self's pkg ID's stem
/// or if the pkg ID's stem is <rust-foo> and the given path's
/// stem is foo
/// Requires that dashes in p have already been normalized to
/// underscores
fn stem_matches(&self, p: &Path) -> bool {
let self_id = self.id.local_path.filestem();
if self_id == p.filestem() {
return true;
}
else {
for pth in self_id.iter() {
if pth.starts_with("rust_") // because p is already normalized
&& match p.filestem() {
Some(s) => str::eq_slice(s, pth.slice(5, pth.len())),
None => false
} { return true; }
}
}
false
}
fn push_crate(cs: &mut ~[Crate], prefix: uint, p: &Path) {
assert!(p.components.len() > prefix);
let mut sub = Path("");
for c in p.components.slice(prefix, p.components.len()).iter() {
sub = sub.push(*c);
}
debug!("found crate %s", sub.to_str());
cs.push(Crate::new(&sub));
}
/// Infers crates to build. Called only in the case where there
/// is no custom build logic
pub fn find_crates(&mut self) {
use conditions::missing_pkg_files::cond;
let dir = self.check_dir();
debug!("Called check_dir, I'm in %s", dir.to_str());
let prefix = dir.components.len();
debug!("Matching against %?", self.id.local_path.filestem());
do os::walk_dir(&dir) |pth| {
match pth.filename() {
Some(~"lib.rs") => PkgSrc::push_crate(&mut self.libs,
prefix,
pth),
Some(~"main.rs") => PkgSrc::push_crate(&mut self.mains,
prefix,
pth),
Some(~"test.rs") => PkgSrc::push_crate(&mut self.tests,
prefix,
pth),
Some(~"bench.rs") => PkgSrc::push_crate(&mut self.benchs,
prefix,
pth),
_ => ()
}
true
};
if self.libs.is_empty() && self.mains.is_empty()
&& self.tests.is_empty() && self.benchs.is_empty() {
note("Couldn't infer any crates to build.\n\
Try naming a crate `main.rs`, `lib.rs`, \
`test.rs`, or `bench.rs`.");
cond.raise(self.id.clone());
}
debug!("found %u libs, %u mains, %u tests, %u benchs",
self.libs.len(),
self.mains.len(),
self.tests.len(),
self.benchs.len())
}
fn build_crates(&self,
ctx: &Ctx,
dst_dir: &Path,
src_dir: &Path,
crates: &[Crate],
cfgs: &[~str],
what: OutputType) {
for crate in crates.iter() {
let path = &src_dir.push_rel(&crate.file).normalize();
note(fmt!("build_crates: compiling %s", path.to_str()));
note(fmt!("build_crates: destination dir is %s", dst_dir.to_str()));
let result = compile_crate(ctx,
&self.id,
path,
dst_dir,
crate.flags,
crate.cfgs + cfgs,
false,
what);
if !result {
build_err::cond.raise(fmt!("build failure on %s",
path.to_str()));
}
debug!("Result of compiling %s was %?",
path.to_str(), result);
}
}
pub fn build(&self, ctx: &Ctx, dst_dir: Path, cfgs: ~[~str]) {
let dir = self.check_dir();
debug!("Building libs in %s", dir.to_str());
self.build_crates(ctx, &dst_dir, &dir, self.libs, cfgs, Lib);
debug!("Building mains");
self.build_crates(ctx, &dst_dir, &dir, self.mains, cfgs, Main);
debug!("Building tests");
self.build_crates(ctx, &dst_dir, &dir, self.tests, cfgs, Test);
debug!("Building benches");
self.build_crates(ctx, &dst_dir, &dir, self.benchs, cfgs, Bench);
}
}