]> git.proxmox.com Git - cargo.git/blame - src/cargo/core/compiler/layout.rs
Upgrade to Rust 2018
[cargo.git] / src / cargo / core / compiler / layout.rs
CommitLineData
9f5d9b81
AC
1//! Management of the directory layout of a build
2//!
3//! The directory layout is a little tricky at times, hence a separate file to
4//! house this logic. The current layout looks like this:
5//!
39f0bd47
AC
6//! ```ignore
7//! # This is the root directory for all output, the top-level package
8//! # places all of its output here.
9//! target/
9f5d9b81 10//!
39f0bd47
AC
11//! # This is the root directory for all output of *dependencies*
12//! deps/
9f5d9b81 13//!
e969e495
AC
14//! # Root directory for all compiled examples
15//! examples/
16//!
39f0bd47
AC
17//! # This is the location at which the output of all custom build
18//! # commands are rooted
34ace110
PK
19//! build/
20//!
21//! # Each package gets its own directory where its build script and
22//! # script output are placed
23//! $pkg1/
24//! $pkg2/
25//! $pkg3/
26//!
27//! # Each directory package has a `out` directory where output
28//! # is placed.
29//! out/
30//!
31//! # This is the location at which the output of all old custom build
32//! # commands are rooted
39f0bd47 33//! native/
c2b23512 34//!
39f0bd47
AC
35//! # Each package gets its own directory for where its output is
36//! # placed. We can't track exactly what's getting put in here, so
37//! # we just assume that all relevant output is in these
38//! # directories.
39//! $pkg1/
40//! $pkg2/
41//! $pkg3/
c2b23512 42//!
a5bf3b88
NM
43//! # Directory used to store incremental data for the compiler (when
44//! # incremental is enabled.
45//! incremental/
46//!
39f0bd47
AC
47//! # Hidden directory that holds all of the fingerprint files for all
48//! # packages
49//! .fingerprint/
39f0bd47 50//! ```
9f5d9b81 51
a6dad622 52use std::fs;
a6dad622 53use std::io;
1e682848 54use std::path::{Path, PathBuf};
9f5d9b81 55
04ddd4d0
DW
56use crate::core::Workspace;
57use crate::util::{CargoResult, Config, FileLock, Filesystem};
c2b23512 58
72899f5b
RD
59/// Contains the paths of all target output locations.
60///
61/// See module docs for more information.
9f5d9b81 62pub struct Layout {
a6dad622
AC
63 root: PathBuf,
64 deps: PathBuf,
65 native: PathBuf,
66 build: PathBuf,
a5bf3b88 67 incremental: PathBuf,
a6dad622
AC
68 fingerprint: PathBuf,
69 examples: PathBuf,
72899f5b 70 /// The lockfile for a build, will be unlocked when this struct is `drop`ped.
a9fd1c2c 71 _lock: FileLock,
9f5d9b81
AC
72}
73
6633e290
AK
74pub fn is_bad_artifact_name(name: &str) -> bool {
75 ["deps", "examples", "build", "native", "incremental"]
76 .iter()
23591fe5 77 .any(|&reserved| reserved == name)
6633e290
AK
78}
79
9f5d9b81 80impl Layout {
ffd5e0fc 81 /// Calculate the paths for build output, lock the build directory, and return as a Layout.
72899f5b
RD
82 ///
83 /// This function will block if the directory is already locked.
84 ///
ffd5e0fc 85 /// Differs from `at` in that this calculates the root path from the workspace target directory,
72899f5b 86 /// adding the target triple and the profile (debug, release, ...).
1e682848 87 pub fn new(ws: &Workspace, triple: Option<&str>, dest: &str) -> CargoResult<Layout> {
3c9b362b 88 let mut path = ws.target_dir();
a1f241a3 89 // Flexible target specifications often point at json files, so interpret
29b24cdb 90 // the target triple as a Path and then just use the file stem as the
a1f241a3 91 // component for the directory name in that case.
29b24cdb 92 if let Some(triple) = triple {
a1f241a3 93 let triple = Path::new(triple);
94 if triple.extension().and_then(|s| s.to_str()) == Some("json") {
95 path.push(
96 triple
97 .file_stem()
98 .ok_or_else(|| format_err!("invalid target"))?,
99 );
100 } else {
101 path.push(triple);
102 }
325c5f2d 103 }
14ff482d 104 path.push(dest);
58ddb28a 105 Layout::at(ws.config(), path)
325c5f2d
AC
106 }
107
ffd5e0fc 108 /// Calculate the paths for build output, lock the build directory, and return as a Layout.
72899f5b
RD
109 ///
110 /// This function will block if the directory is already locked.
a9fd1c2c
AC
111 pub fn at(config: &Config, root: Filesystem) -> CargoResult<Layout> {
112 // For now we don't do any more finer-grained locking on the artifact
113 // directory, so just lock the entire thing for the duration of this
114 // compile.
82655b46 115 let lock = root.open_rw(".cargo-lock", config, "build directory")?;
a9fd1c2c
AC
116 let root = root.into_path_unlocked();
117
118 Ok(Layout {
9f5d9b81 119 deps: root.join("deps"),
c2b23512 120 native: root.join("native"),
34ace110 121 build: root.join("build"),
a5bf3b88 122 incremental: root.join("incremental"),
79768eb0 123 fingerprint: root.join(".fingerprint"),
e969e495 124 examples: root.join("examples"),
0247dc42 125 root,
a9fd1c2c
AC
126 _lock: lock,
127 })
9f5d9b81
AC
128 }
129
8e0a7cad
K
130 #[cfg(not(target_os = "macos"))]
131 fn exclude_from_backups(&self, _: &Path) {}
132
133 #[cfg(target_os = "macos")]
134 /// Marks files or directories as excluded from Time Machine on macOS
135 ///
136 /// This is recommended to prevent derived/temporary files from bloating backups.
137 fn exclude_from_backups(&self, path: &Path) {
8e0a7cad 138 use core_foundation::base::TCFType;
dae87a26
E
139 use core_foundation::{number, string, url};
140 use std::ptr;
8e0a7cad
K
141
142 // For compatibility with 10.7 a string is used instead of global kCFURLIsExcludedFromBackupKey
143 let is_excluded_key: Result<string::CFString, _> = "NSURLIsExcludedFromBackupKey".parse();
d4999dc8
DW
144 let path = url::CFURL::from_path(path, false);
145 if let (Some(path), Ok(is_excluded_key)) = (path, is_excluded_key) {
146 unsafe {
8e0a7cad
K
147 url::CFURLSetResourcePropertyForKey(
148 path.as_concrete_TypeRef(),
149 is_excluded_key.as_concrete_TypeRef(),
150 number::kCFBooleanTrue as *const _,
151 ptr::null_mut(),
152 );
d4999dc8 153 }
8e0a7cad 154 }
d4999dc8
DW
155 // Errors are ignored, since it's an optional feature and failure
156 // doesn't prevent Cargo from working
8e0a7cad
K
157 }
158
72899f5b 159 /// Make sure all directories stored in the Layout exist on the filesystem.
a6dad622 160 pub fn prepare(&mut self) -> io::Result<()> {
97a2f271 161 if fs::metadata(&self.root).is_err() {
82655b46 162 fs::create_dir_all(&self.root)?;
9f5d9b81
AC
163 }
164
8e0a7cad
K
165 self.exclude_from_backups(&self.root);
166
82655b46
SG
167 mkdir(&self.deps)?;
168 mkdir(&self.native)?;
a5bf3b88 169 mkdir(&self.incremental)?;
82655b46
SG
170 mkdir(&self.fingerprint)?;
171 mkdir(&self.examples)?;
172 mkdir(&self.build)?;
9f5d9b81 173
e969e495
AC
174 return Ok(());
175
a6dad622 176 fn mkdir(dir: &Path) -> io::Result<()> {
97a2f271 177 if fs::metadata(&dir).is_err() {
82655b46 178 fs::create_dir(dir)?;
e969e495
AC
179 }
180 Ok(())
181 }
9f5d9b81
AC
182 }
183
72899f5b 184 /// Fetch the root path.
1e682848
AC
185 pub fn dest(&self) -> &Path {
186 &self.root
187 }
72899f5b 188 /// Fetch the deps path.
1e682848
AC
189 pub fn deps(&self) -> &Path {
190 &self.deps
191 }
72899f5b 192 /// Fetch the examples path.
1e682848
AC
193 pub fn examples(&self) -> &Path {
194 &self.examples
195 }
72899f5b 196 /// Fetch the root path.
1e682848
AC
197 pub fn root(&self) -> &Path {
198 &self.root
199 }
72899f5b 200 /// Fetch the incremental path.
1e682848
AC
201 pub fn incremental(&self) -> &Path {
202 &self.incremental
203 }
72899f5b 204 /// Fetch the fingerprint path.
1e682848
AC
205 pub fn fingerprint(&self) -> &Path {
206 &self.fingerprint
207 }
72899f5b 208 /// Fetch the build path.
1e682848
AC
209 pub fn build(&self) -> &Path {
210 &self.build
211 }
9f5d9b81 212}