Skip to content

Commit 6a3e26a

Browse files
committed
rustpkg: Make path searching work as described in the rustpkg doc
rustpkg now searches for package directories in ./src rather than in . . I also added a rudimentary RUST_PATH that's currently hard-wired to the current directory. rustpkg now uses src/, lib/, and build/ directories as described in the manual. Most of the existing test scenarios build now; the README file (in a separate commit) explains which ones.
1 parent c2af1de commit 6a3e26a

File tree

3 files changed

+190
-151
lines changed

3 files changed

+190
-151
lines changed

src/librustpkg/path_util.rs

Lines changed: 116 additions & 52 deletions
Original file line numberDiff line numberDiff line change
@@ -15,39 +15,43 @@ use core::{os, str};
1515
use core::option::*;
1616
use util::PkgId;
1717

18-
/// Returns the output directory to use.
19-
/// Right now is always the default, should
20-
/// support changing it.
21-
pub fn dest_dir(pkgid: PkgId) -> Path {
22-
default_dest_dir(&pkgid.path)
18+
#[deriving(Eq)]
19+
pub enum OutputType { Main, Lib, Bench, Test }
20+
21+
/// Returns the value of RUST_PATH, as a list
22+
/// of Paths. In general this should be read from the
23+
/// environment; for now, it's hard-wired to just be "."
24+
pub fn rust_path() -> ~[Path] {
25+
~[Path(".")]
2326
}
2427

25-
/// Returns the default output directory for compilation.
26-
/// Creates that directory if it doesn't exist.
27-
pub fn default_dest_dir(pkg_dir: &Path) -> Path {
28+
/// Creates a directory that is readable, writeable,
29+
/// and executable by the user. Returns true iff creation
30+
/// succeeded.
31+
pub fn make_dir_rwx(p: &Path) -> bool {
2832
use core::libc::consts::os::posix88::{S_IRUSR, S_IWUSR, S_IXUSR};
29-
use conditions::bad_path::cond;
3033

31-
// For now: assumes that pkg_dir exists and is relative
32-
// to the CWD. Change this later when we do path searching.
33-
let rslt = pkg_dir.push("build");
34-
let is_dir = os::path_is_dir(&rslt);
35-
if os::path_exists(&rslt) {
36-
if is_dir {
37-
rslt
38-
}
39-
else {
40-
cond.raise((rslt, ~"Path names a file that isn't a directory"))
41-
}
34+
os::make_dir(p, (S_IRUSR | S_IWUSR | S_IXUSR) as i32)
35+
}
36+
37+
/// Creates a directory that is readable, writeable,
38+
/// and executable by the user. Returns true iff creation
39+
/// succeeded. Also creates all intermediate subdirectories
40+
/// if they don't already exist.
41+
pub fn mkdir_recursive(p: &Path) -> bool {
42+
if os::path_is_dir(p) {
43+
return true;
44+
}
45+
let parent = p.dir_path();
46+
debug!("mkdir_recursive: parent = %s",
47+
parent.to_str());
48+
if parent.to_str() == ~"."
49+
|| parent.to_str() == ~"/" { // !!!
50+
// No parent directories to create
51+
os::path_is_dir(&parent) && make_dir_rwx(p)
4252
}
4353
else {
44-
// Create it
45-
if os::make_dir(&rslt, (S_IRUSR | S_IWUSR | S_IXUSR) as i32) {
46-
rslt
47-
}
48-
else {
49-
cond.raise((rslt, ~"Could not create directory"))
50-
}
54+
mkdir_recursive(&parent) && make_dir_rwx(p)
5155
}
5256
}
5357

@@ -69,34 +73,94 @@ pub fn normalize(p: ~Path) -> ~Path {
6973
}
7074
}
7175

76+
// n.b. So far this only handles local workspaces
77+
// n.b. The next three functions ignore the package version right
78+
// now. Should fix that.
79+
80+
/// True if there's a directory in <workspace> with
81+
/// pkgid's short name
82+
pub fn workspace_contains_package_id(pkgid: PkgId, workspace: &Path) -> bool {
83+
let pkgpath = workspace.push("src").push(pkgid.path.to_str());
84+
os::path_is_dir(&pkgpath)
85+
}
86+
87+
/// Return the directory for <pkgid>'s source files in <workspace>.
88+
/// Doesn't check that it exists.
89+
pub fn pkgid_src_in_workspace(pkgid: PkgId, workspace: &Path) -> Path {
90+
let result = workspace.push("src");
91+
result.push(pkgid.path.to_str())
92+
}
93+
94+
/// Returns the executable that would be installed for <pkgid>
95+
/// in <workspace>
96+
pub fn target_executable_in_workspace(pkgid: PkgId, workspace: &Path) -> Path {
97+
let result = workspace.push("bin");
98+
// should use a target-specific subdirectory
99+
mk_output_path(Main, pkgid.path.to_str(), result)
100+
}
101+
102+
103+
/// Returns the executable that would be installed for <pkgid>
104+
/// in <workspace>
105+
pub fn target_library_in_workspace(pkgid: PkgId, workspace: &Path) -> Path {
106+
let result = workspace.push("lib");
107+
mk_output_path(Lib, pkgid.path.to_str(), result)
108+
}
109+
110+
/// Returns the test executable that would be installed for <pkgid>
111+
/// in <workspace>
112+
pub fn target_test_in_workspace(pkgid: PkgId, workspace: &Path) -> Path {
113+
let result = workspace.push("build");
114+
mk_output_path(Test, pkgid.path.to_str(), result)
115+
}
116+
117+
/// Returns the bench executable that would be installed for <pkgid>
118+
/// in <workspace>
119+
pub fn target_bench_in_workspace(pkgid: PkgId, workspace: &Path) -> Path {
120+
let result = workspace.push("build");
121+
mk_output_path(Bench, pkgid.path.to_str(), result)
122+
}
123+
124+
/// Return the directory for <pkgid>'s build artifacts in <workspace>.
125+
/// Creates it if it doesn't exist.
126+
pub fn build_pkg_id_in_workspace(pkgid: PkgId, workspace: &Path) -> Path {
127+
use conditions::bad_path::cond;
128+
129+
let mut result = workspace.push("build");
130+
// n.b. Should actually use a target-specific
131+
// subdirectory of build/
132+
result = result.push(normalize(~pkgid.path).to_str());
133+
if os::path_exists(&result) || mkdir_recursive(&result) {
134+
result
135+
}
136+
else {
137+
cond.raise((result, fmt!("Could not create directory for package %s", pkgid.to_str())))
138+
}
139+
}
140+
141+
/// Return the output file for a given directory name,
142+
/// given whether we're building a library and whether we're building tests
143+
pub fn mk_output_path(what: OutputType, short_name: ~str, dir: Path) -> Path {
144+
match what {
145+
Lib => dir.push(os::dll_filename(short_name)),
146+
_ => dir.push(fmt!("%s%s%s", short_name,
147+
if what == Test { ~"test" } else { ~"" },
148+
os::EXE_SUFFIX))
149+
}
150+
}
151+
72152
#[cfg(test)]
73153
mod test {
74-
use core::{os, rand};
75-
use core::path::Path;
76-
use path_util::*;
77-
use core::rand::RngUtil;
78-
79-
// Helper function to create a directory name that doesn't exist
80-
pub fn mk_nonexistent(tmpdir: &Path, suffix: &str) -> Path {
81-
let r = rand::rng();
82-
for 1000.times {
83-
let p = tmpdir.push(r.gen_str(16) + suffix);
84-
if !os::path_exists(&p) {
85-
return p;
86-
}
87-
}
88-
fail!(~"Couldn't compute a non-existent path name; this is worrisome")
89-
}
154+
use core::os;
90155
91156
#[test]
92-
fn default_dir_ok() {
93-
let the_path = os::tmpdir();
94-
let substitute_path = Path("xyzzy");
95-
assert!(default_dest_dir(&the_path) == the_path.push(~"build"));
96-
let nonexistent_path = mk_nonexistent(&the_path, "quux");
97-
let bogus = do ::conditions::bad_path::cond.trap(|_| {
98-
substitute_path
99-
}).in { default_dest_dir(&nonexistent_path) };
100-
assert!(bogus == substitute_path);
157+
fn recursive_mkdir_ok() {
158+
let root = os::tmpdir();
159+
let path = "xy/z/zy";
160+
let nested = root.push(path);
161+
assert!(super::mkdir_recursive(&nested));
162+
assert!(os::path_is_dir(&root.push("xy")));
163+
assert!(os::path_is_dir(&root.push("xy/z")));
164+
assert!(os::path_is_dir(&nested));
101165
}
102166
}

src/librustpkg/rustpkg.rc

Lines changed: 62 additions & 96 deletions
Original file line numberDiff line numberDiff line change
@@ -36,7 +36,8 @@ use rustc::metadata::filesearch;
3636
use std::{getopts};
3737
use syntax::{ast, diagnostic};
3838
use util::*;
39-
use path_util::{dest_dir, normalize};
39+
use path_util::{normalize, workspace_contains_package_id};
40+
use path_util::{build_pkg_id_in_workspace, pkgid_src_in_workspace, rust_path};
4041
use rustc::driver::session::{lib_crate, bin_crate, crate_type};
4142

4243
mod conditions;
@@ -70,7 +71,7 @@ impl PkgScript {
7071
/// Given the path name for a package script
7172
/// and a package ID, parse the package script into
7273
/// a PkgScript that we can then execute
73-
fn parse(script: Path, id: PkgId) -> PkgScript {
74+
fn parse(script: Path, workspace: &Path, id: PkgId) -> PkgScript {
7475
// Get the executable name that was invoked
7576
let binary = os::args()[0];
7677
// Build the rustc session data structures to pass
@@ -85,7 +86,7 @@ impl PkgScript {
8586
let cfg = driver::build_configuration(sess, @binary, &input);
8687
let (crate, _) = driver::compile_upto(sess, cfg, &input,
8788
driver::cu_parse, None);
88-
let work_dir = dest_dir(id);
89+
let work_dir = build_pkg_id_in_workspace(id, workspace);
8990

9091
debug!("Returning package script with id %?", id);
9192

@@ -193,54 +194,60 @@ impl Ctx {
193194
// The package id is presumed to be the first command-line
194195
// argument
195196
let pkgid = PkgId::new(args[0]);
196-
// Should allow the build directory to be configured.
197-
// Right now it's always the "build" subdirectory in
198-
// the package directory
199-
let dst_dir = dest_dir(pkgid);
200-
debug!("Destination dir = %s", dst_dir.to_str());
201-
// Right now, we assume the pkgid path is a valid dir
202-
// relative to the CWD. In the future, we should search
203-
// paths
204-
let cwd = os::getcwd().normalize();
205-
debug!("Current working directory = %s", cwd.to_str());
206-
207-
// Create the package source
208-
let mut src = PkgSrc::new(&cwd, &dst_dir, &pkgid);
209-
debug!("Package src = %?", src);
210-
211-
// Is there custom build logic? If so, use it
212-
let pkg_src_dir = cwd.push_rel(&pkgid.path);
213-
let mut custom = false;;
214-
debug!("Package source directory = %s", pkg_src_dir.to_str());
215-
let cfgs = match src.package_script_option(&pkg_src_dir) {
216-
Some(package_script_path) => {
217-
let pscript = PkgScript::parse(package_script_path,
218-
pkgid);
219-
// Limited right now -- we're only running the post_build
220-
// hook and probably fail otherwise
221-
// also post_build should be called pre_build
222-
let (cfgs, hook_result) = pscript.run_custom(~"post_build");
223-
debug!("Command return code = %?", hook_result);
224-
if hook_result != 0 {
225-
fail!(fmt!("Error running custom build command"))
197+
// Using the RUST_PATH, find workspaces that contain
198+
// this package ID
199+
let workspaces = rust_path().filtered(|ws|
200+
workspace_contains_package_id(pkgid, ws));
201+
if workspaces.is_empty() {
202+
fail!(fmt!("Package %s not found in any of \
203+
the following workspaces: %s",
204+
pkgid.path.to_str(),
205+
rust_path().to_str()));
206+
}
207+
for workspaces.each |workspace| {
208+
let src_dir = pkgid_src_in_workspace(pkgid, workspace);
209+
let build_dir = build_pkg_id_in_workspace(pkgid, workspace);
210+
debug!("Destination dir = %s", build_dir.to_str());
211+
212+
// Create the package source
213+
let mut src = PkgSrc::new(&workspace.push("src"), &build_dir, &pkgid);
214+
debug!("Package src = %?", src);
215+
216+
// Is there custom build logic? If so, use it
217+
let pkg_src_dir = src_dir;
218+
let mut custom = false;
219+
debug!("Package source directory = %s", pkg_src_dir.to_str());
220+
let cfgs = match src.package_script_option(&pkg_src_dir) {
221+
Some(package_script_path) => {
222+
let pscript = PkgScript::parse(package_script_path,
223+
workspace,
224+
pkgid);
225+
// Limited right now -- we're only running the post_build
226+
// hook and probably fail otherwise
227+
// also post_build should be called pre_build
228+
let (cfgs, hook_result) = pscript.run_custom(~"post_build");
229+
debug!("Command return code = %?", hook_result);
230+
if hook_result != 0 {
231+
fail!(fmt!("Error running custom build command"))
232+
}
233+
custom = true;
234+
// otherwise, the package script succeeded
235+
cfgs
226236
}
227-
custom = true;
228-
// otherwise, the package script succeeded
229-
cfgs
230-
}
231-
None => {
232-
debug!("No package script, continuing");
233-
~[]
237+
None => {
238+
debug!("No package script, continuing");
239+
~[]
240+
}
241+
};
242+
243+
// If there was a package script, it should have finished
244+
// the build already. Otherwise...
245+
if !custom {
246+
// Find crates inside the workspace
247+
src.find_crates();
248+
// Build it!
249+
src.build(&build_dir, cfgs);
234250
}
235-
};
236-
237-
// If there was a package script, it should have finished
238-
// the build already. Otherwise...
239-
if !custom {
240-
// Find crates inside the workspace
241-
src.find_crates();
242-
// Build it!
243-
src.build(&dst_dir, cfgs);
244251
}
245252
}
246253
~"clean" => {
@@ -250,8 +257,8 @@ impl Ctx {
250257
// The package id is presumed to be the first command-line
251258
// argument
252259
let pkgid = PkgId::new(args[0]);
253-
254-
self.clean(pkgid);
260+
let cwd = os::getcwd();
261+
self.clean(&cwd, pkgid); // tjc: should use workspace, not cwd
255262
}
256263
~"do" => {
257264
if args.len() < 2 {
@@ -304,57 +311,16 @@ impl Ctx {
304311
}
305312

306313
fn do_cmd(&self, cmd: ~str, pkgname: ~str) {
307-
match cmd {
308-
~"build" | ~"test" => {
309-
util::error(~"that command cannot be manually called");
310-
fail!(~"do_cmd");
311-
}
312-
_ => {}
313-
}
314-
315-
let cwd = &os::getcwd();
316-
let pkgid = PkgId::new(pkgname);
317-
// Always use the "build" subdirectory of the package dir,
318-
// but we should allow this to be configured
319-
let dst_dir = dest_dir(pkgid);
320-
321-
let mut src = PkgSrc::new(cwd, &dst_dir, &pkgid);
322-
match src.package_script_option(cwd) {
323-
Some(script_path) => {
324-
let script = PkgScript::parse(script_path, pkgid);
325-
let (_, status) = script.run_custom(cmd); // Ignore cfgs?
326-
if status == 42 {
327-
util::error(~"no fns are listening for that cmd");
328-
fail!(~"do_cmd");
329-
}
330-
}
331-
None => {
332-
util::error(fmt!("invoked `do`, but there is no package script in %s",
333-
cwd.to_str()));
334-
fail!(~"do_cmd");
335-
}
336-
}
337-
}
338-
339-
fn build(&self, _dir: &Path, _verbose: bool, _opt: bool,
340-
_test: bool) -> Option<PkgScript> {
341-
// either not needed anymore,
342-
// or needed only when we don't have a package script. Not sure which one.
343-
fail!();
344-
}
345-
346-
fn compile(&self, _crate: &Path, _dir: &Path, _flags: ~[~str],
347-
_cfgs: ~[~str], _opt: bool, _test: bool) {
348-
// What's the difference between build and compile?
349-
fail!(~"compile not yet implemented");
314+
// stub
315+
fail!("`do` not yet implemented");
350316
}
351317

352-
fn clean(&self, id: PkgId) {
318+
fn clean(&self, workspace: &Path, id: PkgId) {
353319
// Could also support a custom build hook in the pkg
354320
// script for cleaning files rustpkg doesn't know about.
355321
// Do something reasonable for now
356322

357-
let dir = dest_dir(id);
323+
let dir = build_pkg_id_in_workspace(id, workspace);
358324
util::note(fmt!("Cleaning package %s (removing directory %s)",
359325
id.to_str(), dir.to_str()));
360326
if os::path_exists(&dir) {

0 commit comments

Comments
 (0)