]> git.proxmox.com Git - cargo.git/blame_incremental - src/cargo/core/compiler/layout.rs
Upgrade to Rust 2018
[cargo.git] / src / cargo / core / compiler / layout.rs
... / ...
CommitLineData
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//!
6//! ```ignore
7//! # This is the root directory for all output, the top-level package
8//! # places all of its output here.
9//! target/
10//!
11//! # This is the root directory for all output of *dependencies*
12//! deps/
13//!
14//! # Root directory for all compiled examples
15//! examples/
16//!
17//! # This is the location at which the output of all custom build
18//! # commands are rooted
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
33//! native/
34//!
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/
42//!
43//! # Directory used to store incremental data for the compiler (when
44//! # incremental is enabled.
45//! incremental/
46//!
47//! # Hidden directory that holds all of the fingerprint files for all
48//! # packages
49//! .fingerprint/
50//! ```
51
52use std::fs;
53use std::io;
54use std::path::{Path, PathBuf};
55
56use crate::core::Workspace;
57use crate::util::{CargoResult, Config, FileLock, Filesystem};
58
59/// Contains the paths of all target output locations.
60///
61/// See module docs for more information.
62pub struct Layout {
63 root: PathBuf,
64 deps: PathBuf,
65 native: PathBuf,
66 build: PathBuf,
67 incremental: PathBuf,
68 fingerprint: PathBuf,
69 examples: PathBuf,
70 /// The lockfile for a build, will be unlocked when this struct is `drop`ped.
71 _lock: FileLock,
72}
73
74pub fn is_bad_artifact_name(name: &str) -> bool {
75 ["deps", "examples", "build", "native", "incremental"]
76 .iter()
77 .any(|&reserved| reserved == name)
78}
79
80impl Layout {
81 /// Calculate the paths for build output, lock the build directory, and return as a Layout.
82 ///
83 /// This function will block if the directory is already locked.
84 ///
85 /// Differs from `at` in that this calculates the root path from the workspace target directory,
86 /// adding the target triple and the profile (debug, release, ...).
87 pub fn new(ws: &Workspace, triple: Option<&str>, dest: &str) -> CargoResult<Layout> {
88 let mut path = ws.target_dir();
89 // Flexible target specifications often point at json files, so interpret
90 // the target triple as a Path and then just use the file stem as the
91 // component for the directory name in that case.
92 if let Some(triple) = triple {
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 }
103 }
104 path.push(dest);
105 Layout::at(ws.config(), path)
106 }
107
108 /// Calculate the paths for build output, lock the build directory, and return as a Layout.
109 ///
110 /// This function will block if the directory is already locked.
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.
115 let lock = root.open_rw(".cargo-lock", config, "build directory")?;
116 let root = root.into_path_unlocked();
117
118 Ok(Layout {
119 deps: root.join("deps"),
120 native: root.join("native"),
121 build: root.join("build"),
122 incremental: root.join("incremental"),
123 fingerprint: root.join(".fingerprint"),
124 examples: root.join("examples"),
125 root,
126 _lock: lock,
127 })
128 }
129
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) {
138 use core_foundation::base::TCFType;
139 use core_foundation::{number, string, url};
140 use std::ptr;
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();
144 let path = url::CFURL::from_path(path, false);
145 if let (Some(path), Ok(is_excluded_key)) = (path, is_excluded_key) {
146 unsafe {
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 );
153 }
154 }
155 // Errors are ignored, since it's an optional feature and failure
156 // doesn't prevent Cargo from working
157 }
158
159 /// Make sure all directories stored in the Layout exist on the filesystem.
160 pub fn prepare(&mut self) -> io::Result<()> {
161 if fs::metadata(&self.root).is_err() {
162 fs::create_dir_all(&self.root)?;
163 }
164
165 self.exclude_from_backups(&self.root);
166
167 mkdir(&self.deps)?;
168 mkdir(&self.native)?;
169 mkdir(&self.incremental)?;
170 mkdir(&self.fingerprint)?;
171 mkdir(&self.examples)?;
172 mkdir(&self.build)?;
173
174 return Ok(());
175
176 fn mkdir(dir: &Path) -> io::Result<()> {
177 if fs::metadata(&dir).is_err() {
178 fs::create_dir(dir)?;
179 }
180 Ok(())
181 }
182 }
183
184 /// Fetch the root path.
185 pub fn dest(&self) -> &Path {
186 &self.root
187 }
188 /// Fetch the deps path.
189 pub fn deps(&self) -> &Path {
190 &self.deps
191 }
192 /// Fetch the examples path.
193 pub fn examples(&self) -> &Path {
194 &self.examples
195 }
196 /// Fetch the root path.
197 pub fn root(&self) -> &Path {
198 &self.root
199 }
200 /// Fetch the incremental path.
201 pub fn incremental(&self) -> &Path {
202 &self.incremental
203 }
204 /// Fetch the fingerprint path.
205 pub fn fingerprint(&self) -> &Path {
206 &self.fingerprint
207 }
208 /// Fetch the build path.
209 pub fn build(&self) -> &Path {
210 &self.build
211 }
212}