auto merge of #6054 : catamorphism/rust/rustpkg, r=graydon
r? @graydon Sorry, this pull request is a few different things at once, but I tried to make them separate commits. First, as before, this should do file searching the way that's described in the doc now. Second, there's also some preliminary work on the install command (really just tests for it).
This commit is contained in:
commit
0604468fd5
@ -43,8 +43,6 @@ use vec;
|
|||||||
pub use libc::fclose;
|
pub use libc::fclose;
|
||||||
pub use os::consts::*;
|
pub use os::consts::*;
|
||||||
|
|
||||||
// FIXME: move these to str perhaps? #2620
|
|
||||||
|
|
||||||
pub fn close(fd: c_int) -> c_int {
|
pub fn close(fd: c_int) -> c_int {
|
||||||
unsafe {
|
unsafe {
|
||||||
libc::close(fd)
|
libc::close(fd)
|
||||||
@ -79,6 +77,8 @@ pub fn getcwd() -> Path {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// FIXME: move these to str perhaps? #2620
|
||||||
|
|
||||||
pub fn as_c_charp<T>(s: &str, f: &fn(*c_char) -> T) -> T {
|
pub fn as_c_charp<T>(s: &str, f: &fn(*c_char) -> T) -> T {
|
||||||
str::as_c_str(s, |b| f(b as *c_char))
|
str::as_c_str(s, |b| f(b as *c_char))
|
||||||
}
|
}
|
||||||
|
@ -1,4 +1,24 @@
|
|||||||
Right now (2013-04-11), only one package works, the branch of rust-sdl at:
|
Right now, commands that work are "build" and "clean".
|
||||||
https://github.com/catamorphism/rust-sdl/tree/new-rustpkg
|
|
||||||
|
|
||||||
and only one command works, "build".
|
`rustpkg build` and `rustpkg clean` should work
|
||||||
|
|
||||||
|
for example:
|
||||||
|
$ cd ~/rust/src/librustpkg/testsuite/pass
|
||||||
|
$ rustpkg build hello-world
|
||||||
|
... some output ...
|
||||||
|
$ rustpkg clean hello-world
|
||||||
|
|
||||||
|
-------------
|
||||||
|
the following test packages in librustpkg/testsuite/pass:
|
||||||
|
* hello-world
|
||||||
|
* install-paths
|
||||||
|
* simple-lib
|
||||||
|
* deeply/nested/path
|
||||||
|
* fancy-lib
|
||||||
|
|
||||||
|
It fails on the following test packages:
|
||||||
|
* external-crate (no support for `extern mod` inference yet)
|
||||||
|
|
||||||
|
and should fail with proper error messages
|
||||||
|
on all of the test packages in librustpkg/testsuite/fail
|
||||||
|
* no-inferred-crates
|
||||||
|
@ -11,7 +11,12 @@
|
|||||||
// Useful conditions
|
// Useful conditions
|
||||||
|
|
||||||
pub use core::path::Path;
|
pub use core::path::Path;
|
||||||
|
pub use util::PkgId;
|
||||||
|
|
||||||
condition! {
|
condition! {
|
||||||
bad_path: (super::Path, ~str) -> super::Path;
|
bad_path: (super::Path, ~str) -> super::Path;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
condition! {
|
||||||
|
nonexistent_package: (super::PkgId, ~str) -> super::Path;
|
||||||
|
}
|
||||||
|
21
src/librustpkg/context.rs
Normal file
21
src/librustpkg/context.rs
Normal file
@ -0,0 +1,21 @@
|
|||||||
|
// 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.
|
||||||
|
|
||||||
|
// Context data structure used by rustpkg
|
||||||
|
|
||||||
|
use core::hashmap::HashMap;
|
||||||
|
|
||||||
|
pub struct Ctx {
|
||||||
|
// 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>,
|
||||||
|
}
|
@ -15,39 +15,43 @@ use core::{os, str};
|
|||||||
use core::option::*;
|
use core::option::*;
|
||||||
use util::PkgId;
|
use util::PkgId;
|
||||||
|
|
||||||
/// Returns the output directory to use.
|
#[deriving(Eq)]
|
||||||
/// Right now is always the default, should
|
pub enum OutputType { Main, Lib, Bench, Test }
|
||||||
/// support changing it.
|
|
||||||
pub fn dest_dir(pkgid: PkgId) -> Path {
|
/// Returns the value of RUST_PATH, as a list
|
||||||
default_dest_dir(&pkgid.path)
|
/// of Paths. In general this should be read from the
|
||||||
|
/// environment; for now, it's hard-wired to just be "."
|
||||||
|
pub fn rust_path() -> ~[Path] {
|
||||||
|
~[Path(".")]
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Returns the default output directory for compilation.
|
/// Creates a directory that is readable, writeable,
|
||||||
/// Creates that directory if it doesn't exist.
|
/// and executable by the user. Returns true iff creation
|
||||||
pub fn default_dest_dir(pkg_dir: &Path) -> Path {
|
/// succeeded.
|
||||||
|
pub fn make_dir_rwx(p: &Path) -> bool {
|
||||||
use core::libc::consts::os::posix88::{S_IRUSR, S_IWUSR, S_IXUSR};
|
use core::libc::consts::os::posix88::{S_IRUSR, S_IWUSR, S_IXUSR};
|
||||||
use conditions::bad_path::cond;
|
|
||||||
|
|
||||||
// For now: assumes that pkg_dir exists and is relative
|
os::make_dir(p, (S_IRUSR | S_IWUSR | S_IXUSR) as i32)
|
||||||
// to the CWD. Change this later when we do path searching.
|
}
|
||||||
let rslt = pkg_dir.push("build");
|
|
||||||
let is_dir = os::path_is_dir(&rslt);
|
/// Creates a directory that is readable, writeable,
|
||||||
if os::path_exists(&rslt) {
|
/// and executable by the user. Returns true iff creation
|
||||||
if is_dir {
|
/// succeeded. Also creates all intermediate subdirectories
|
||||||
rslt
|
/// if they don't already exist.
|
||||||
}
|
pub fn mkdir_recursive(p: &Path) -> bool {
|
||||||
else {
|
if os::path_is_dir(p) {
|
||||||
cond.raise((rslt, ~"Path names a file that isn't a directory"))
|
return true;
|
||||||
}
|
}
|
||||||
|
let parent = p.dir_path();
|
||||||
|
debug!("mkdir_recursive: parent = %s",
|
||||||
|
parent.to_str());
|
||||||
|
if parent.to_str() == ~"."
|
||||||
|
|| parent.to_str() == ~"/" { // !!!
|
||||||
|
// No parent directories to create
|
||||||
|
os::path_is_dir(&parent) && make_dir_rwx(p)
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
// Create it
|
mkdir_recursive(&parent) && make_dir_rwx(p)
|
||||||
if os::make_dir(&rslt, (S_IRUSR | S_IWUSR | S_IXUSR) as i32) {
|
|
||||||
rslt
|
|
||||||
}
|
|
||||||
else {
|
|
||||||
cond.raise((rslt, ~"Could not create directory"))
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -69,34 +73,94 @@ pub fn normalize(p: ~Path) -> ~Path {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
#[cfg(test)]
|
// n.b. So far this only handles local workspaces
|
||||||
mod test {
|
// n.b. The next three functions ignore the package version right
|
||||||
use core::{os, rand};
|
// now. Should fix that.
|
||||||
use core::path::Path;
|
|
||||||
use path_util::*;
|
|
||||||
use core::rand::RngUtil;
|
|
||||||
|
|
||||||
// Helper function to create a directory name that doesn't exist
|
/// True if there's a directory in <workspace> with
|
||||||
pub fn mk_nonexistent(tmpdir: &Path, suffix: &str) -> Path {
|
/// pkgid's short name
|
||||||
let r = rand::rng();
|
pub fn workspace_contains_package_id(pkgid: PkgId, workspace: &Path) -> bool {
|
||||||
for 1000.times {
|
let pkgpath = workspace.push("src").push(pkgid.path.to_str());
|
||||||
let p = tmpdir.push(r.gen_str(16) + suffix);
|
os::path_is_dir(&pkgpath)
|
||||||
if !os::path_exists(&p) {
|
}
|
||||||
return p;
|
|
||||||
}
|
/// Return the directory for <pkgid>'s source files in <workspace>.
|
||||||
}
|
/// Doesn't check that it exists.
|
||||||
fail!(~"Couldn't compute a non-existent path name; this is worrisome")
|
pub fn pkgid_src_in_workspace(pkgid: PkgId, workspace: &Path) -> Path {
|
||||||
|
let result = workspace.push("src");
|
||||||
|
result.push(pkgid.path.to_str())
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Returns the executable that would be installed for <pkgid>
|
||||||
|
/// in <workspace>
|
||||||
|
pub fn target_executable_in_workspace(pkgid: PkgId, workspace: &Path) -> Path {
|
||||||
|
let result = workspace.push("bin");
|
||||||
|
// should use a target-specific subdirectory
|
||||||
|
mk_output_path(Main, pkgid.path.to_str(), result)
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/// Returns the executable that would be installed for <pkgid>
|
||||||
|
/// in <workspace>
|
||||||
|
pub fn target_library_in_workspace(pkgid: PkgId, workspace: &Path) -> Path {
|
||||||
|
let result = workspace.push("lib");
|
||||||
|
mk_output_path(Lib, pkgid.path.to_str(), result)
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Returns the test executable that would be installed for <pkgid>
|
||||||
|
/// in <workspace>
|
||||||
|
pub fn target_test_in_workspace(pkgid: PkgId, workspace: &Path) -> Path {
|
||||||
|
let result = workspace.push("build");
|
||||||
|
mk_output_path(Test, pkgid.path.to_str(), result)
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Returns the bench executable that would be installed for <pkgid>
|
||||||
|
/// in <workspace>
|
||||||
|
pub fn target_bench_in_workspace(pkgid: PkgId, workspace: &Path) -> Path {
|
||||||
|
let result = workspace.push("build");
|
||||||
|
mk_output_path(Bench, pkgid.path.to_str(), result)
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Return the directory for <pkgid>'s build artifacts in <workspace>.
|
||||||
|
/// Creates it if it doesn't exist.
|
||||||
|
pub fn build_pkg_id_in_workspace(pkgid: PkgId, workspace: &Path) -> Path {
|
||||||
|
use conditions::bad_path::cond;
|
||||||
|
|
||||||
|
let mut result = workspace.push("build");
|
||||||
|
// n.b. Should actually use a target-specific
|
||||||
|
// subdirectory of build/
|
||||||
|
result = result.push(normalize(~pkgid.path).to_str());
|
||||||
|
if os::path_exists(&result) || mkdir_recursive(&result) {
|
||||||
|
result
|
||||||
}
|
}
|
||||||
|
else {
|
||||||
#[test]
|
cond.raise((result, fmt!("Could not create directory for package %s", pkgid.to_str())))
|
||||||
fn default_dir_ok() {
|
}
|
||||||
let the_path = os::tmpdir();
|
}
|
||||||
let substitute_path = Path("xyzzy");
|
|
||||||
assert!(default_dest_dir(&the_path) == the_path.push(~"build"));
|
/// Return the output file for a given directory name,
|
||||||
let nonexistent_path = mk_nonexistent(&the_path, "quux");
|
/// given whether we're building a library and whether we're building tests
|
||||||
let bogus = do ::conditions::bad_path::cond.trap(|_| {
|
pub fn mk_output_path(what: OutputType, short_name: ~str, dir: Path) -> Path {
|
||||||
substitute_path
|
match what {
|
||||||
}).in { default_dest_dir(&nonexistent_path) };
|
Lib => dir.push(os::dll_filename(short_name)),
|
||||||
assert!(bogus == substitute_path);
|
_ => dir.push(fmt!("%s%s%s", short_name,
|
||||||
|
if what == Test { ~"test" } else { ~"" },
|
||||||
|
os::EXE_SUFFIX))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#[cfg(test)]
|
||||||
|
mod test {
|
||||||
|
use core::os;
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn recursive_mkdir_ok() {
|
||||||
|
let root = os::tmpdir();
|
||||||
|
let path = "xy/z/zy";
|
||||||
|
let nested = root.push(path);
|
||||||
|
assert!(super::mkdir_recursive(&nested));
|
||||||
|
assert!(os::path_is_dir(&root.push("xy")));
|
||||||
|
assert!(os::path_is_dir(&root.push("xy/z")));
|
||||||
|
assert!(os::path_is_dir(&nested));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -36,13 +36,19 @@ use rustc::metadata::filesearch;
|
|||||||
use std::{getopts};
|
use std::{getopts};
|
||||||
use syntax::{ast, diagnostic};
|
use syntax::{ast, diagnostic};
|
||||||
use util::*;
|
use util::*;
|
||||||
use path_util::{dest_dir, normalize};
|
use path_util::normalize;
|
||||||
|
use path_util::{build_pkg_id_in_workspace, pkgid_src_in_workspace};
|
||||||
|
use workspace::pkg_parent_workspaces;
|
||||||
use rustc::driver::session::{lib_crate, bin_crate, crate_type};
|
use rustc::driver::session::{lib_crate, bin_crate, crate_type};
|
||||||
|
use context::Ctx;
|
||||||
|
|
||||||
mod conditions;
|
mod conditions;
|
||||||
|
mod context;
|
||||||
mod usage;
|
mod usage;
|
||||||
mod path_util;
|
mod path_util;
|
||||||
|
mod tests;
|
||||||
mod util;
|
mod util;
|
||||||
|
mod workspace;
|
||||||
|
|
||||||
/// A PkgScript represents user-supplied custom logic for
|
/// A PkgScript represents user-supplied custom logic for
|
||||||
/// special build hooks. This only exists for packages with
|
/// special build hooks. This only exists for packages with
|
||||||
@ -70,7 +76,7 @@ impl PkgScript {
|
|||||||
/// Given the path name for a package script
|
/// Given the path name for a package script
|
||||||
/// and a package ID, parse the package script into
|
/// and a package ID, parse the package script into
|
||||||
/// a PkgScript that we can then execute
|
/// a PkgScript that we can then execute
|
||||||
fn parse(script: Path, id: PkgId) -> PkgScript {
|
fn parse(script: Path, workspace: &Path, id: PkgId) -> PkgScript {
|
||||||
// Get the executable name that was invoked
|
// Get the executable name that was invoked
|
||||||
let binary = os::args()[0];
|
let binary = os::args()[0];
|
||||||
// Build the rustc session data structures to pass
|
// Build the rustc session data structures to pass
|
||||||
@ -85,7 +91,7 @@ impl PkgScript {
|
|||||||
let cfg = driver::build_configuration(sess, @binary, &input);
|
let cfg = driver::build_configuration(sess, @binary, &input);
|
||||||
let (crate, _) = driver::compile_upto(sess, cfg, &input,
|
let (crate, _) = driver::compile_upto(sess, cfg, &input,
|
||||||
driver::cu_parse, None);
|
driver::cu_parse, None);
|
||||||
let work_dir = dest_dir(id);
|
let work_dir = build_pkg_id_in_workspace(id, workspace);
|
||||||
|
|
||||||
debug!("Returning package script with id %?", id);
|
debug!("Returning package script with id %?", id);
|
||||||
|
|
||||||
@ -153,14 +159,6 @@ impl PkgScript {
|
|||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
struct Ctx {
|
|
||||||
// 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 {
|
impl Ctx {
|
||||||
|
|
||||||
fn run(&self, cmd: ~str, args: ~[~str]) {
|
fn run(&self, cmd: ~str, args: ~[~str]) {
|
||||||
@ -193,54 +191,50 @@ impl Ctx {
|
|||||||
// 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]);
|
||||||
// Should allow the build directory to be configured.
|
for pkg_parent_workspaces(pkgid) |workspace| {
|
||||||
// Right now it's always the "build" subdirectory in
|
let src_dir = pkgid_src_in_workspace(pkgid, workspace);
|
||||||
// the package directory
|
let build_dir = build_pkg_id_in_workspace(pkgid, workspace);
|
||||||
let dst_dir = dest_dir(pkgid);
|
debug!("Destination dir = %s", build_dir.to_str());
|
||||||
debug!("Destination dir = %s", dst_dir.to_str());
|
|
||||||
// Right now, we assume the pkgid path is a valid dir
|
|
||||||
// relative to the CWD. In the future, we should search
|
|
||||||
// paths
|
|
||||||
let cwd = os::getcwd().normalize();
|
|
||||||
debug!("Current working directory = %s", cwd.to_str());
|
|
||||||
|
|
||||||
// Create the package source
|
// Create the package source
|
||||||
let mut src = PkgSrc::new(&cwd, &dst_dir, &pkgid);
|
let mut src = PkgSrc::new(&workspace.push("src"), &build_dir, &pkgid);
|
||||||
debug!("Package src = %?", src);
|
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 = cwd.push_rel(&pkgid.path);
|
let pkg_src_dir = src_dir;
|
||||||
let mut custom = false;;
|
let mut custom = false;
|
||||||
debug!("Package source directory = %s", pkg_src_dir.to_str());
|
debug!("Package source directory = %s", pkg_src_dir.to_str());
|
||||||
let cfgs = match src.package_script_option(&pkg_src_dir) {
|
let cfgs = match src.package_script_option(&pkg_src_dir) {
|
||||||
Some(package_script_path) => {
|
Some(package_script_path) => {
|
||||||
let pscript = PkgScript::parse(package_script_path,
|
let pscript = PkgScript::parse(package_script_path,
|
||||||
pkgid);
|
workspace,
|
||||||
// Limited right now -- we're only running the post_build
|
pkgid);
|
||||||
// hook and probably fail otherwise
|
// Limited right now -- we're only running the post_build
|
||||||
// also post_build should be called pre_build
|
// hook and probably fail otherwise
|
||||||
let (cfgs, hook_result) = pscript.run_custom(~"post_build");
|
// also post_build should be called pre_build
|
||||||
debug!("Command return code = %?", hook_result);
|
let (cfgs, hook_result) = pscript.run_custom(~"post_build");
|
||||||
if hook_result != 0 {
|
debug!("Command return code = %?", hook_result);
|
||||||
fail!(fmt!("Error running custom build command"))
|
if hook_result != 0 {
|
||||||
|
fail!(fmt!("Error running custom build command"))
|
||||||
|
}
|
||||||
|
custom = true;
|
||||||
|
// otherwise, the package script succeeded
|
||||||
|
cfgs
|
||||||
}
|
}
|
||||||
custom = true;
|
None => {
|
||||||
// otherwise, the package script succeeded
|
debug!("No package script, continuing");
|
||||||
cfgs
|
~[]
|
||||||
}
|
}
|
||||||
None => {
|
};
|
||||||
debug!("No package script, continuing");
|
|
||||||
~[]
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
// If there was a package script, it should have finished
|
// If there was a package script, it should have finished
|
||||||
// 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();
|
src.find_crates();
|
||||||
// Build it!
|
// Build it!
|
||||||
src.build(&dst_dir, cfgs);
|
src.build(&build_dir, cfgs);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
~"clean" => {
|
~"clean" => {
|
||||||
@ -250,8 +244,8 @@ impl Ctx {
|
|||||||
// 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 cwd = os::getcwd();
|
||||||
self.clean(pkgid);
|
self.clean(&cwd, pkgid); // tjc: should use workspace, not cwd
|
||||||
}
|
}
|
||||||
~"do" => {
|
~"do" => {
|
||||||
if args.len() < 2 {
|
if args.len() < 2 {
|
||||||
@ -264,10 +258,16 @@ impl Ctx {
|
|||||||
self.info();
|
self.info();
|
||||||
}
|
}
|
||||||
~"install" => {
|
~"install" => {
|
||||||
self.install(if args.len() >= 1 { Some(args[0]) }
|
if args.len() < 1 {
|
||||||
else { None },
|
return usage::install();
|
||||||
if args.len() >= 2 { Some(args[1]) }
|
}
|
||||||
else { None }, false);
|
|
||||||
|
// The package id is presumed to be the first command-line
|
||||||
|
// argument
|
||||||
|
let pkgid = PkgId::new(args[0]);
|
||||||
|
for pkg_parent_workspaces(pkgid) |workspace| {
|
||||||
|
self.install(workspace, pkgid);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
~"prefer" => {
|
~"prefer" => {
|
||||||
if args.len() < 1 {
|
if args.len() < 1 {
|
||||||
@ -303,58 +303,17 @@ impl Ctx {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fn do_cmd(&self, cmd: ~str, pkgname: ~str) {
|
fn do_cmd(&self, _cmd: ~str, _pkgname: ~str) {
|
||||||
match cmd {
|
// stub
|
||||||
~"build" | ~"test" => {
|
fail!(~"`do` not yet implemented");
|
||||||
util::error(~"that command cannot be manually called");
|
|
||||||
fail!(~"do_cmd");
|
|
||||||
}
|
|
||||||
_ => {}
|
|
||||||
}
|
|
||||||
|
|
||||||
let cwd = &os::getcwd();
|
|
||||||
let pkgid = PkgId::new(pkgname);
|
|
||||||
// Always use the "build" subdirectory of the package dir,
|
|
||||||
// but we should allow this to be configured
|
|
||||||
let dst_dir = dest_dir(pkgid);
|
|
||||||
|
|
||||||
let mut src = PkgSrc::new(cwd, &dst_dir, &pkgid);
|
|
||||||
match src.package_script_option(cwd) {
|
|
||||||
Some(script_path) => {
|
|
||||||
let script = PkgScript::parse(script_path, pkgid);
|
|
||||||
let (_, status) = script.run_custom(cmd); // Ignore cfgs?
|
|
||||||
if status == 42 {
|
|
||||||
util::error(~"no fns are listening for that cmd");
|
|
||||||
fail!(~"do_cmd");
|
|
||||||
}
|
|
||||||
}
|
|
||||||
None => {
|
|
||||||
util::error(fmt!("invoked `do`, but there is no package script in %s",
|
|
||||||
cwd.to_str()));
|
|
||||||
fail!(~"do_cmd");
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
fn build(&self, _dir: &Path, _verbose: bool, _opt: bool,
|
fn clean(&self, workspace: &Path, id: PkgId) {
|
||||||
_test: bool) -> Option<PkgScript> {
|
|
||||||
// either not needed anymore,
|
|
||||||
// or needed only when we don't have a package script. Not sure which one.
|
|
||||||
fail!();
|
|
||||||
}
|
|
||||||
|
|
||||||
fn compile(&self, _crate: &Path, _dir: &Path, _flags: ~[~str],
|
|
||||||
_cfgs: ~[~str], _opt: bool, _test: bool) {
|
|
||||||
// What's the difference between build and compile?
|
|
||||||
fail!(~"compile not yet implemented");
|
|
||||||
}
|
|
||||||
|
|
||||||
fn clean(&self, id: PkgId) {
|
|
||||||
// Could also support a custom build hook in the pkg
|
// Could also support a custom build hook in the pkg
|
||||||
// script for cleaning files rustpkg doesn't know about.
|
// script for cleaning files rustpkg doesn't know about.
|
||||||
// Do something reasonable for now
|
// Do something reasonable for now
|
||||||
|
|
||||||
let dir = dest_dir(id);
|
let dir = build_pkg_id_in_workspace(id, workspace);
|
||||||
util::note(fmt!("Cleaning package %s (removing directory %s)",
|
util::note(fmt!("Cleaning package %s (removing directory %s)",
|
||||||
id.to_str(), dir.to_str()));
|
id.to_str(), dir.to_str()));
|
||||||
if os::path_exists(&dir) {
|
if os::path_exists(&dir) {
|
||||||
@ -370,8 +329,7 @@ impl Ctx {
|
|||||||
fail!(~"info not yet implemented");
|
fail!(~"info not yet implemented");
|
||||||
}
|
}
|
||||||
|
|
||||||
fn install(&self, _url: Option<~str>,
|
fn install(&self, _workspace: &Path, _id: PkgId) {
|
||||||
_target: Option<~str>, _cache: bool) {
|
|
||||||
// stub
|
// stub
|
||||||
fail!(~"install not yet implemented");
|
fail!(~"install not yet implemented");
|
||||||
}
|
}
|
||||||
|
@ -9,3 +9,96 @@
|
|||||||
// except according to those terms.
|
// except according to those terms.
|
||||||
|
|
||||||
// rustpkg unit tests
|
// rustpkg unit tests
|
||||||
|
|
||||||
|
use context::Ctx;
|
||||||
|
use core::hashmap::HashMap;
|
||||||
|
use core::path::Path;
|
||||||
|
use core::os;
|
||||||
|
use core::io;
|
||||||
|
use core::option::*;
|
||||||
|
use std::tempfile::mkdtemp;
|
||||||
|
use util::{PkgId, default_version};
|
||||||
|
use path_util::{target_executable_in_workspace, target_library_in_workspace,
|
||||||
|
target_test_in_workspace, target_bench_in_workspace,
|
||||||
|
make_dir_rwx};
|
||||||
|
|
||||||
|
fn fake_ctxt() -> Ctx {
|
||||||
|
Ctx {
|
||||||
|
json: false,
|
||||||
|
dep_cache: @mut HashMap::new()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn fake_pkg() -> PkgId {
|
||||||
|
PkgId {
|
||||||
|
path: Path(~"bogus"),
|
||||||
|
version: default_version()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn mk_temp_workspace() -> Path {
|
||||||
|
mkdtemp(&os::tmpdir(), "test").expect("couldn't create temp dir")
|
||||||
|
}
|
||||||
|
|
||||||
|
fn is_rwx(p: &Path) -> bool {
|
||||||
|
use core::libc::consts::os::posix88::{S_IRUSR, S_IWUSR, S_IXUSR};
|
||||||
|
|
||||||
|
match p.get_mode() {
|
||||||
|
None => return false,
|
||||||
|
Some(m) => {
|
||||||
|
((m & S_IRUSR as uint) == S_IRUSR as uint
|
||||||
|
&& (m & S_IWUSR as uint) == S_IWUSR as uint
|
||||||
|
&& (m & S_IXUSR as uint) == S_IXUSR as uint)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn test_make_dir_rwx() {
|
||||||
|
let temp = &os::tmpdir();
|
||||||
|
let dir = temp.push(~"quux");
|
||||||
|
let _ = os::remove_dir(&dir);
|
||||||
|
assert!(make_dir_rwx(&dir));
|
||||||
|
assert!(os::path_is_dir(&dir));
|
||||||
|
assert!(is_rwx(&dir));
|
||||||
|
assert!(os::remove_dir(&dir));
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
#[ignore(reason = "install not yet implemented")]
|
||||||
|
fn test_install_valid() {
|
||||||
|
let ctxt = fake_ctxt();
|
||||||
|
let temp_pkg_id = fake_pkg();
|
||||||
|
let temp_workspace() = mk_temp_workspace();
|
||||||
|
// should have test, bench, lib, and main
|
||||||
|
ctxt.install(&temp_workspace, temp_pkg_id);
|
||||||
|
// Check that all files exist
|
||||||
|
let exec = target_executable_in_workspace(temp_pkg_id, &temp_workspace);
|
||||||
|
assert!(os::path_exists(&exec));
|
||||||
|
assert!(is_rwx(&exec));
|
||||||
|
let lib = target_library_in_workspace(temp_pkg_id, &temp_workspace);
|
||||||
|
assert!(os::path_exists(&lib));
|
||||||
|
assert!(is_rwx(&lib));
|
||||||
|
// And that the test and bench executables aren't installed
|
||||||
|
assert!(!os::path_exists(&target_test_in_workspace(temp_pkg_id, &temp_workspace)));
|
||||||
|
assert!(!os::path_exists(&target_bench_in_workspace(temp_pkg_id, &temp_workspace)));
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
#[ignore(reason = "install not yet implemented")]
|
||||||
|
fn test_install_invalid() {
|
||||||
|
use conditions::nonexistent_package::cond;
|
||||||
|
|
||||||
|
let ctxt = fake_ctxt();
|
||||||
|
let pkgid = fake_pkg();
|
||||||
|
let temp_workspace = mk_temp_workspace();
|
||||||
|
let expected_path = Path(~"quux");
|
||||||
|
let substituted: Path = do cond.trap(|_| {
|
||||||
|
expected_path
|
||||||
|
}).in {
|
||||||
|
ctxt.install(&temp_workspace, pkgid);
|
||||||
|
// ok
|
||||||
|
fail!(~"test_install_invalid failed, should have raised a condition");
|
||||||
|
};
|
||||||
|
assert!(substituted == expected_path);
|
||||||
|
}
|
@ -21,4 +21,4 @@ extern mod std;
|
|||||||
|
|
||||||
pub mod foo;
|
pub mod foo;
|
||||||
pub mod bar;
|
pub mod bar;
|
||||||
#[path = "build/generated.rs"] pub mod generated;
|
#[path = "../../build/fancy_lib/generated.rs"] pub mod generated;
|
@ -11,13 +11,18 @@
|
|||||||
use core::run;
|
use core::run;
|
||||||
|
|
||||||
pub fn main() {
|
pub fn main() {
|
||||||
let cwd = os::getcwd();
|
use core::libc::consts::os::posix88::{S_IRUSR, S_IWUSR, S_IXUSR};
|
||||||
debug!("cwd = %s", cwd.to_str());
|
|
||||||
let file = io::file_writer(&Path(~"fancy-lib/build/generated.rs"),
|
let out_path = Path(~"build/fancy_lib");
|
||||||
|
if !os::path_exists(&out_path) {
|
||||||
|
assert!(os::make_dir(&out_path, (S_IRUSR | S_IWUSR | S_IXUSR) as i32));
|
||||||
|
}
|
||||||
|
|
||||||
|
let file = io::file_writer(&out_path.push("generated.rs"),
|
||||||
[io::Create]).get();
|
[io::Create]).get();
|
||||||
file.write_str("pub fn wheeeee() { for [1, 2, 3].each() |_| { assert!(true); } }");
|
file.write_str("pub fn wheeeee() { for [1, 2, 3].each() |_| { assert!(true); } }");
|
||||||
|
|
||||||
// now compile the crate itself
|
// now compile the crate itself
|
||||||
run::run_program("rustc", ~[~"fancy-lib/fancy-lib.rs", ~"--lib",
|
run::run_program("rustc", ~[~"src/fancy-lib/fancy-lib.rs", ~"--lib",
|
||||||
~"-o", ~"fancy-lib/build/fancy_lib"]);
|
~"-o", out_path.push(~"fancy_lib").to_str()]);
|
||||||
}
|
}
|
@ -78,7 +78,7 @@ impl ToStr for Version {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/// Placeholder
|
/// Placeholder
|
||||||
fn default_version() -> Version { ExactRevision(0.1) }
|
pub fn default_version() -> Version { ExactRevision(0.1) }
|
||||||
|
|
||||||
// Path-fragment identifier of a package such as
|
// Path-fragment identifier of a package such as
|
||||||
// 'github.com/graydon/test'; path must be a relative
|
// 'github.com/graydon/test'; path must be a relative
|
||||||
@ -116,7 +116,14 @@ pub impl PkgId {
|
|||||||
impl ToStr for PkgId {
|
impl ToStr for PkgId {
|
||||||
fn to_str(&self) -> ~str {
|
fn to_str(&self) -> ~str {
|
||||||
// should probably use the filestem and not the whole path
|
// should probably use the filestem and not the whole path
|
||||||
fmt!("%s-%s", self.path.to_str(), self.version.to_str())
|
fmt!("%s-%s", self.path.to_str(),
|
||||||
|
// Replace dots with -s in the version
|
||||||
|
// this is because otherwise rustc will think
|
||||||
|
// that foo-0.1 has .1 as its extension
|
||||||
|
// (Temporary hack until I figure out how to
|
||||||
|
// get rustc to not name the object file
|
||||||
|
// foo-0.o if I pass in foo-0.1 to build_output_filenames)
|
||||||
|
str::replace(self.version.to_str(), ".", "-"))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -438,7 +445,9 @@ pub fn compile_input(sysroot: Option<Path>,
|
|||||||
test: bool,
|
test: bool,
|
||||||
crate_type: session::crate_type) -> bool {
|
crate_type: session::crate_type) -> bool {
|
||||||
|
|
||||||
let short_name = pkg_id.to_str();
|
// Want just the directory component here
|
||||||
|
let pkg_filename = pkg_id.path.filename().expect(~"Weird pkg id");
|
||||||
|
let short_name = fmt!("%s-%s", pkg_filename, pkg_id.version.to_str());
|
||||||
|
|
||||||
assert!(in_file.components.len() > 1);
|
assert!(in_file.components.len() > 1);
|
||||||
let input = driver::file_input(copy *in_file);
|
let input = driver::file_input(copy *in_file);
|
||||||
@ -515,7 +524,7 @@ pub fn compile_crate_from_input(input: driver::input,
|
|||||||
out_file: Path,
|
out_file: Path,
|
||||||
binary: ~str,
|
binary: ~str,
|
||||||
what: driver::compile_upto) -> @ast::crate {
|
what: driver::compile_upto) -> @ast::crate {
|
||||||
debug!("Calling build_output_filenames with %?", build_dir_opt);
|
debug!("Calling build_output_filenames with %? and %s", build_dir_opt, out_file.to_str());
|
||||||
let outputs = driver::build_output_filenames(&input, &build_dir_opt, &Some(out_file), sess);
|
let outputs = driver::build_output_filenames(&input, &build_dir_opt, &Some(out_file), sess);
|
||||||
debug!("Outputs are %? and output type = %?", outputs, sess.opts.output_type);
|
debug!("Outputs are %? and output type = %?", outputs, sess.opts.output_type);
|
||||||
let cfg = driver::build_configuration(sess, @binary, &input);
|
let cfg = driver::build_configuration(sess, @binary, &input);
|
||||||
|
34
src/librustpkg/workspace.rs
Normal file
34
src/librustpkg/workspace.rs
Normal file
@ -0,0 +1,34 @@
|
|||||||
|
// 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.
|
||||||
|
|
||||||
|
// rustpkg utilities having to do with workspaces
|
||||||
|
|
||||||
|
use path_util::{rust_path, workspace_contains_package_id};
|
||||||
|
use util::PkgId;
|
||||||
|
use core::path::Path;
|
||||||
|
|
||||||
|
pub fn pkg_parent_workspaces(pkgid: PkgId, action: &fn(&Path) -> bool) {
|
||||||
|
// Using the RUST_PATH, find workspaces that contain
|
||||||
|
// this package ID
|
||||||
|
let workspaces = rust_path().filtered(|ws|
|
||||||
|
workspace_contains_package_id(pkgid, ws));
|
||||||
|
if workspaces.is_empty() {
|
||||||
|
// tjc: make this a condition
|
||||||
|
fail!(fmt!("Package %s not found in any of \
|
||||||
|
the following workspaces: %s",
|
||||||
|
pkgid.path.to_str(),
|
||||||
|
rust_path().to_str()));
|
||||||
|
}
|
||||||
|
for workspaces.each |ws| {
|
||||||
|
if action(ws) {
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
Loading…
Reference in New Issue
Block a user