]> git.proxmox.com Git - rustc.git/blob - src/librustpkg/path_util.rs
Imported Upstream version 0.7
[rustc.git] / src / librustpkg / path_util.rs
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.
4 //
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.
10
11 // rustpkg utilities having to do with paths and directories
12
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;
19 use std::os;
20 use std::iterator::IteratorUtil;
21 use messages::*;
22 use package_id::*;
23
24 fn push_if_exists(vec: &mut ~[Path], p: &Path) {
25 let maybe_dir = p.push(".rust");
26 if os::path_exists(&maybe_dir) {
27 vec.push(maybe_dir);
28 }
29 }
30
31 #[cfg(windows)]
32 static path_entry_separator: &'static str = ";";
33 #[cfg(not(windows))]
34 static path_entry_separator: &'static str = ":";
35
36 /// Returns the value of RUST_PATH, as a list
37 /// of Paths. Includes default entries for, if they exist:
38 /// $HOME/.rust
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") {
43 Some(env_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))
47 }
48 None => ~[]
49 };
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); }
56 env_rust_path
57 }
58
59 pub static u_rwx: i32 = (S_IRUSR | S_IWUSR | S_IXUSR) as i32;
60
61 /// Creates a directory that is readable, writeable,
62 /// and executable by the user. Returns true iff creation
63 /// succeeded.
64 pub fn make_dir_rwx(p: &Path) -> bool { os::make_dir(p, u_rwx) }
65
66 // n.b. The next three functions ignore the package version right
67 // now. Should fix that.
68
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| {
75 let p = Path(p);
76 debug!("=> p = %s", p.to_str());
77 if !os::path_is_dir(&src_dir.push_rel(&p)) {
78 loop;
79 }
80 debug!("p = %s, remote_path = %s", p.to_str(), pkgid.remote_path.to_str());
81
82 if p == *pkgid.remote_path {
83 return true;
84 }
85 else {
86 let pf = p.filename();
87 for pf.iter().advance |&pf| {
88 let f_ = copy pf;
89 let g = f_.to_str();
90 match split_version_general(g, '-') {
91 Some((ref might_match, ref vers)) => {
92 debug!("might_match = %s, vers = %s", *might_match,
93 vers.to_str());
94 if *might_match == pkgid.short_name
95 && (*vers == pkgid.version || pkgid.version == NoVersion)
96 {
97 return true;
98 }
99 }
100 None => ()
101 }
102 }
103 }
104 }
105 false
106 }
107
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));
118 results
119 }
120
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);
127 }
128 }
129 None
130 }
131
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",
139 result.to_str());
140 if os::path_exists(&result) {
141 Some(result)
142 }
143 else {
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()));
146 None
147 }
148 }
149
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)
154 }
155
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)
160 }
161
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",
167 result.to_str());
168 if os::path_exists(&result) {
169 Some(result)
170 }
171 else {
172 error!(fmt!("output_in_workspace: %s does not exist", result.to_str()));
173 None
174 }
175 }
176
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")
182 }
183
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")
188 }
189
190
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",
198 short_name);
199
200 // We don't know what the hash is, so we have to search through the directory
201 // contents
202
203 debug!("short_name = %s where = %? workspace = %s \
204 prefix = %s", short_name, where, workspace.to_str(), prefix);
205
206 let dir_to_search = match where {
207 Build => workspace.push(prefix).push_rel(&**path),
208 Install => workspace.push(prefix)
209 };
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());
213
214 let lib_prefix = fmt!("%s%s", os::consts::DLL_PREFIX, short_name);
215 let lib_filetype = os::consts::DLL_SUFFIX;
216
217 debug!("lib_prefix = %s and lib_filetype = %s", lib_prefix, lib_filetype);
218
219 let mut result_filename = None;
220 for dir_contents.iter().advance |&p| {
221 let mut which = 0;
222 let mut hash = None;
223 let p_path = Path(p);
224 let extension = p_path.filetype();
225 debug!("p = %s, p's extension is %?", p.to_str(), extension);
226 match extension {
227 Some(ref s) if lib_filetype == *s => (),
228 _ => loop
229 }
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
234 };
235 for f_name.split_iter('-').advance |piece| {
236 debug!("a piece = %s", piece);
237 if which == 0 && piece != lib_prefix {
238 break;
239 }
240 else if which == 0 {
241 which += 1;
242 }
243 else if which == 1 {
244 hash = Some(piece.to_owned());
245 break;
246 }
247 else {
248 // something went wrong
249 hash = None;
250 break;
251 }
252 }
253 if hash.is_some() {
254 result_filename = Some(p_path);
255 break;
256 }
257 }
258
259 // Return the filename that matches, which we now know exists
260 // (if result_filename != None)
261 match result_filename {
262 None => {
263 warn(fmt!("library_in_workspace didn't find a library in %s for %s",
264 dir_to_search.to_str(), short_name));
265 None
266 }
267 Some(result_filename) => {
268 let absolute_path = dir_to_search.push_rel(&result_filename);
269 debug!("result_filename = %s", absolute_path.to_str());
270 Some(absolute_path)
271 }
272 }
273 }
274
275 /// Returns the executable that would be installed for <pkgid>
276 /// in <workspace>
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)
280 }
281
282
283 /// Returns the executable that would be installed for <pkgid>
284 /// in <workspace>
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())));
292 }
293 target_file_in_workspace(pkgid, workspace, Lib, Install)
294 }
295
296 /// Returns the test executable that would be installed for <pkgid>
297 /// in <workspace>
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)
301 }
302
303 /// Returns the bench executable that would be installed for <pkgid>
304 /// in <workspace>
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)
308 }
309
310
311 /// Returns the path that pkgid `pkgid` would have if placed `where`
312 /// in `workspace`
313 fn target_file_in_workspace(pkgid: &PkgId, workspace: &Path,
314 what: OutputType, where: Target) -> Path {
315 use conditions::bad_path::cond;
316
317 let subdir = match what {
318 Lib => "lib", Main | Test | Bench => "bin"
319 };
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)));
325 }
326 mk_output_path(what, where, pkgid, &result)
327 }
328
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;
333
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) {
339 result
340 }
341 else {
342 cond.raise((result, fmt!("Could not create directory for package %s", pkgid.to_str())))
343 }
344 }
345
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)
359 };
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 },
362 dir.to_str());
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,
368 match what {
369 Test => "test",
370 Bench => "bench",
371 _ => ""
372 }
373 os::EXE_SUFFIX))
374 };
375 if !output_path.is_absolute() {
376 output_path = os::getcwd().push_rel(&output_path).normalize();
377 }
378 debug!("mk_output_path: returning %s", output_path.to_str());
379 output_path
380 }