1 // Copyright 2013 The Rust Project Developers. See the COPYRIGHT
2 // file at the top-level directory of this distribution and at
3 // http://rust-lang.org/COPYRIGHT.
5 // Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
6 // http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
7 // <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
8 // option. This file may not be copied, modified, or distributed
9 // except according to those terms.
11 // rustpkg utilities having to do with paths and directories
13 pub use package_path
::{RemotePath, LocalPath, normalize}
;
14 pub use package_id
::PkgId
;
15 pub use target
::{OutputType, Main, Lib, Test, Bench, Target, Build, Install}
;
16 pub use version
::{Version, NoVersion, split_version_general}
;
17 use std
::libc
::consts
::os
::posix88
::{S_IRUSR, S_IWUSR, S_IXUSR}
;
18 use std
::os
::mkdir_recursive
;
20 use std
::iterator
::IteratorUtil
;
24 fn push_if_exists(vec
: &mut ~[Path
], p
: &Path
) {
25 let maybe_dir
= p
.push(".rust");
26 if os
::path_exists(&maybe_dir
) {
32 static path_entry_separator
: &'
static str = ";";
34 static path_entry_separator
: &'
static str = ":";
36 /// Returns the value of RUST_PATH, as a list
37 /// of Paths. Includes default entries for, if they exist:
39 /// DIR/.rust for any DIR that's the current working directory
40 /// or an ancestor of it
41 pub fn rust_path() -> ~[Path
] {
42 let mut env_rust_path
: ~[Path
] = match os
::getenv("RUST_PATH") {
44 let env_path_components
: ~[&str] =
45 env_path
.split_str_iter(path_entry_separator
).collect();
46 env_path_components
.map(|&s
| Path(s
))
50 let cwd
= os
::getcwd();
51 // now add in default entries
52 env_rust_path
.push(copy cwd
);
53 do cwd
.each_parent() |p
| { push_if_exists(&mut env_rust_path, p) }
;
54 let h
= os
::homedir();
55 for h
.iter().advance
|h
| { push_if_exists(&mut env_rust_path, h); }
59 pub static u_rwx
: i32 = (S_IRUSR
| S_IWUSR
| S_IXUSR
) as i32;
61 /// Creates a directory that is readable, writeable,
62 /// and executable by the user. Returns true iff creation
64 pub fn make_dir_rwx(p
: &Path
) -> bool { os::make_dir(p, u_rwx) }
66 // n.b. The next three functions ignore the package version right
67 // now. Should fix that.
69 /// True if there's a directory in <workspace> with
70 /// pkgid's short name
71 pub fn workspace_contains_package_id(pkgid
: &PkgId
, workspace
: &Path
) -> bool
{
72 let src_dir
= workspace
.push("src");
73 let dirs
= os
::list_dir(&src_dir
);
74 for dirs
.iter().advance
|&p
| {
76 debug
!("=> p = %s", p
.to_str());
77 if !os
::path_is_dir(&src_dir
.push_rel(&p
)) {
80 debug
!("p = %s, remote_path = %s", p
.to_str(), pkgid
.remote_path
.to_str());
82 if p
== *pkgid
.remote_path
{
86 let pf
= p
.filename();
87 for pf
.iter().advance
|&pf
| {
90 match split_version_general(g
, '
-'
) {
91 Some((ref might_match
, ref vers
)) => {
92 debug
!("might_match = %s, vers = %s", *might_match
,
94 if *might_match
== pkgid
.short_name
95 && (*vers
== pkgid
.version
|| pkgid
.version
== NoVersion
)
108 /// Returns a list of possible directories
109 /// for <pkgid>'s source files in <workspace>.
110 /// Doesn't check that any of them exist.
111 /// (for example, try both with and without the version)
112 pub fn pkgid_src_in_workspace(pkgid
: &PkgId
, workspace
: &Path
) -> ~[Path
] {
113 let mut results
= ~[];
114 let result
= workspace
.push("src").push(fmt
!("%s-%s",
115 pkgid
.local_path
.to_str(), pkgid
.version
.to_str()));
116 results
.push(result
);
117 results
.push(workspace
.push("src").push_rel(&*pkgid
.remote_path
));
121 /// Returns a src for pkgid that does exist -- None if none of them do
122 pub fn first_pkgid_src_in_workspace(pkgid
: &PkgId
, workspace
: &Path
) -> Option
<Path
> {
123 let rs
= pkgid_src_in_workspace(pkgid
, workspace
);
124 for rs
.iter().advance
|p
| {
125 if os
::path_exists(p
) {
126 return Some(copy
*p
);
132 /// Figure out what the executable name for <pkgid> in <workspace>'s build
133 /// directory is, and if the file exists, return it.
134 pub fn built_executable_in_workspace(pkgid
: &PkgId
, workspace
: &Path
) -> Option
<Path
> {
135 let mut result
= workspace
.push("build");
136 // should use a target-specific subdirectory
137 result
= mk_output_path(Main
, Build
, pkgid
, &result
);
138 debug
!("built_executable_in_workspace: checking whether %s exists",
140 if os
::path_exists(&result
) {
144 // This is not an error, but it's worth logging it
145 error
!(fmt
!("built_executable_in_workspace: %s does not exist", result
.to_str()));
150 /// Figure out what the test name for <pkgid> in <workspace>'s build
151 /// directory is, and if the file exists, return it.
152 pub fn built_test_in_workspace(pkgid
: &PkgId
, workspace
: &Path
) -> Option
<Path
> {
153 output_in_workspace(pkgid
, workspace
, Test
)
156 /// Figure out what the test name for <pkgid> in <workspace>'s build
157 /// directory is, and if the file exists, return it.
158 pub fn built_bench_in_workspace(pkgid
: &PkgId
, workspace
: &Path
) -> Option
<Path
> {
159 output_in_workspace(pkgid
, workspace
, Bench
)
162 fn output_in_workspace(pkgid
: &PkgId
, workspace
: &Path
, what
: OutputType
) -> Option
<Path
> {
163 let mut result
= workspace
.push("build");
164 // should use a target-specific subdirectory
165 result
= mk_output_path(what
, Build
, pkgid
, &result
);
166 debug
!("output_in_workspace: checking whether %s exists",
168 if os
::path_exists(&result
) {
172 error
!(fmt
!("output_in_workspace: %s does not exist", result
.to_str()));
177 /// Figure out what the library name for <pkgid> in <workspace>'s build
178 /// directory is, and if the file exists, return it.
179 pub fn built_library_in_workspace(pkgid
: &PkgId
, workspace
: &Path
) -> Option
<Path
> {
180 library_in_workspace(&pkgid
.local_path
, pkgid
.short_name
,
181 Build
, workspace
, "build")
184 /// Does the actual searching stuff
185 pub fn installed_library_in_workspace(short_name
: &str, workspace
: &Path
) -> Option
<Path
> {
186 library_in_workspace(&normalize(RemotePath(Path(short_name
))),
187 short_name
, Install
, workspace
, "lib")
191 /// This doesn't take a PkgId, so we can use it for `extern mod` inference, where we
192 /// don't know the entire package ID.
193 /// `workspace` is used to figure out the directory to search.
194 /// `short_name` is taken as the link name of the library.
195 pub fn library_in_workspace(path
: &LocalPath
, short_name
: &str, where: Target
,
196 workspace
: &Path
, prefix
: &str) -> Option
<Path
> {
197 debug
!("library_in_workspace: checking whether a library named %s exists",
200 // We don't know what the hash is, so we have to search through the directory
203 debug
!("short_name = %s where = %? workspace = %s \
204 prefix = %s", short_name
, where, workspace
.to_str(), prefix
);
206 let dir_to_search
= match where {
207 Build
=> workspace
.push(prefix
).push_rel(&**path
),
208 Install
=> workspace
.push(prefix
)
210 debug
!("Listing directory %s", dir_to_search
.to_str());
211 let dir_contents
= os
::list_dir(&dir_to_search
);
212 debug
!("dir has %? entries", dir_contents
.len());
214 let lib_prefix
= fmt
!("%s%s", os
::consts
::DLL_PREFIX
, short_name
);
215 let lib_filetype
= os
::consts
::DLL_SUFFIX
;
217 debug
!("lib_prefix = %s and lib_filetype = %s", lib_prefix
, lib_filetype
);
219 let mut result_filename
= None
;
220 for dir_contents
.iter().advance
|&p
| {
223 let p_path
= Path(p
);
224 let extension
= p_path
.filetype();
225 debug
!("p = %s, p's extension is %?", p
.to_str(), extension
);
227 Some(ref s
) if lib_filetype
== *s
=> (),
230 // Find a filename that matches the pattern: (lib_prefix)-hash-(version)(lib_suffix)
231 // and remember what the hash was
232 let f_name
= match p_path
.filename() {
233 Some(s
) => s
, None
=> loop
235 for f_name
.split_iter('
-'
).advance
|piece
| {
236 debug
!("a piece = %s", piece
);
237 if which
== 0 && piece
!= lib_prefix
{
244 hash
= Some(piece
.to_owned());
248 // something went wrong
254 result_filename
= Some(p_path
);
259 // Return the filename that matches, which we now know exists
260 // (if result_filename != None)
261 match result_filename
{
263 warn(fmt
!("library_in_workspace didn't find a library in %s for %s",
264 dir_to_search
.to_str(), short_name
));
267 Some(result_filename
) => {
268 let absolute_path
= dir_to_search
.push_rel(&result_filename
);
269 debug
!("result_filename = %s", absolute_path
.to_str());
275 /// Returns the executable that would be installed for <pkgid>
277 /// As a side effect, creates the bin-dir if it doesn't exist
278 pub fn target_executable_in_workspace(pkgid
: &PkgId
, workspace
: &Path
) -> Path
{
279 target_file_in_workspace(pkgid
, workspace
, Main
, Install
)
283 /// Returns the executable that would be installed for <pkgid>
285 /// As a side effect, creates the lib-dir if it doesn't exist
286 pub fn target_library_in_workspace(pkgid
: &PkgId
, workspace
: &Path
) -> Path
{
287 use conditions
::bad_path
::cond
;
288 if !os
::path_is_dir(workspace
) {
289 cond
.raise((copy
*workspace
,
290 fmt
!("Workspace supplied to target_library_in_workspace \
291 is not a directory! %s", workspace
.to_str())));
293 target_file_in_workspace(pkgid
, workspace
, Lib
, Install
)
296 /// Returns the test executable that would be installed for <pkgid>
298 /// note that we *don't* install test executables, so this is just for unit testing
299 pub fn target_test_in_workspace(pkgid
: &PkgId
, workspace
: &Path
) -> Path
{
300 target_file_in_workspace(pkgid
, workspace
, Test
, Install
)
303 /// Returns the bench executable that would be installed for <pkgid>
305 /// note that we *don't* install bench executables, so this is just for unit testing
306 pub fn target_bench_in_workspace(pkgid
: &PkgId
, workspace
: &Path
) -> Path
{
307 target_file_in_workspace(pkgid
, workspace
, Bench
, Install
)
311 /// Returns the path that pkgid `pkgid` would have if placed `where`
313 fn target_file_in_workspace(pkgid
: &PkgId
, workspace
: &Path
,
314 what
: OutputType
, where: Target
) -> Path
{
315 use conditions
::bad_path
::cond
;
317 let subdir
= match what
{
318 Lib
=> "lib", Main
| Test
| Bench
=> "bin"
320 let result
= workspace
.push(subdir
);
321 if !os
::path_exists(&result
) && !mkdir_recursive(&result
, u_rwx
) {
322 cond
.raise((copy result
, fmt
!("target_file_in_workspace couldn't \
323 create the %s dir (pkgid=%s, workspace=%s, what=%?, where=%?",
324 subdir
, pkgid
.to_str(), workspace
.to_str(), what
, where)));
326 mk_output_path(what
, where, pkgid
, &result
)
329 /// Return the directory for <pkgid>'s build artifacts in <workspace>.
330 /// Creates it if it doesn't exist.
331 pub fn build_pkg_id_in_workspace(pkgid
: &PkgId
, workspace
: &Path
) -> Path
{
332 use conditions
::bad_path
::cond
;
334 let mut result
= workspace
.push("build");
335 // n.b. Should actually use a target-specific
336 // subdirectory of build/
337 result
= result
.push_rel(&*pkgid
.local_path
);
338 if os
::path_exists(&result
) || os
::mkdir_recursive(&result
, u_rwx
) {
342 cond
.raise((result
, fmt
!("Could not create directory for package %s", pkgid
.to_str())))
346 /// Return the output file for a given directory name,
347 /// given whether we're building a library and whether we're building tests
348 pub fn mk_output_path(what
: OutputType
, where: Target
,
349 pkg_id
: &PkgId
, workspace
: &Path
) -> Path
{
350 let short_name_with_version
= fmt
!("%s-%s", pkg_id
.short_name
,
351 pkg_id
.version
.to_str());
352 // Not local_path.dir_path()! For package foo/bar/blat/, we want
353 // the executable blat-0.5 to live under blat/
354 let dir
= match where {
355 // If we're installing, it just goes under <workspace>...
356 Install
=> copy
*workspace
, // bad copy, but I just couldn't make the borrow checker happy
357 // and if we're just building, it goes in a package-specific subdir
358 Build
=> workspace
.push_rel(&*pkg_id
.local_path
)
360 debug
!("[%?:%?] mk_output_path: short_name = %s, path = %s", what
, where,
361 if what
== Lib { copy short_name_with_version }
else { copy pkg_id.short_name }
,
363 let mut output_path
= match what
{
364 // this code is duplicated from elsewhere; fix this
365 Lib
=> dir
.push(os
::dll_filename(short_name_with_version
)),
366 // executable names *aren't* versioned
367 _
=> dir
.push(fmt
!("%s%s%s", pkg_id
.short_name
,
375 if !output_path
.is_absolute() {
376 output_path
= os
::getcwd().push_rel(&output_path
).normalize();
378 debug
!("mk_output_path: returning %s", output_path
.to_str());