Skip to content

Commit df9067c

Browse files
committed
rustpkg: Compute hash to find crate
Previously rustpkg tried to parse filenames to find crate. Now ue use deterministic hashes, so it becomes possible to directly construct filename and check if the file exists.
1 parent 655433e commit df9067c

File tree

5 files changed

+99
-199
lines changed

5 files changed

+99
-199
lines changed

src/librustpkg/crate_id.rs

Lines changed: 18 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -9,8 +9,9 @@
99
// except according to those terms.
1010

1111
use std::hash::Streaming;
12-
use std::hash;
1312
use syntax::crateid;
13+
use extra::hex::ToHex;
14+
use rustc::util::sha2::{Digest, Sha256};
1415

1516
/// Path-fragment identifier of a package such as
1617
/// 'github.com/graydon/test'; path must be a relative
@@ -41,7 +42,7 @@ impl Eq for CrateId {
4142
}
4243

4344
impl CrateId {
44-
pub fn get_version<'a>(&'a self) -> &'a str {
45+
pub fn version_or_default<'a>(&'a self) -> &'a str {
4546
match self.version {
4647
Some(ref ver) => ver.as_slice(),
4748
None => "0.0"
@@ -66,16 +67,24 @@ impl CrateId {
6667
}
6768
}
6869

70+
pub fn to_crate_id_str(&self) -> ~str {
71+
format!("{}\\#{}", self.path.as_str().unwrap(), self.version_or_default())
72+
}
73+
74+
pub fn to_lib_name(&self) -> ~str {
75+
format!("{}-{}-{}", self.short_name, self.hash(), self.version_or_default())
76+
}
77+
6978
pub fn hash(&self) -> ~str {
70-
// FIXME (#9639): hash should take a &[u8] so we can hash the real path
71-
self.path.display().with_str(|s| {
72-
let vers = self.get_version();
73-
format!("{}-{}-{}", s, hash(s + vers), vers)
74-
})
79+
let mut hasher = Sha256::new();
80+
hasher.reset();
81+
hasher.input_str(self.to_crate_id_str());
82+
let hash = hasher.result_bytes().to_hex();
83+
hash.slice_chars(0, 8).to_owned()
7584
}
7685

7786
pub fn short_name_with_version(&self) -> ~str {
78-
format!("{}-{}", self.short_name, self.get_version())
87+
format!("{}-{}", self.short_name, self.version_or_default())
7988
}
8089

8190
/// True if the ID has multiple components
@@ -126,18 +135,10 @@ impl Iterator<(Path, Path)> for Prefixes {
126135
impl ToStr for CrateId {
127136
fn to_str(&self) -> ~str {
128137
// should probably use the filestem and not the whole path
129-
format!("{}-{}", self.path.as_str().unwrap(), self.get_version())
138+
format!("{}-{}", self.path.as_str().unwrap(), self.version_or_default())
130139
}
131140
}
132141

133-
134142
pub fn write<W: Writer>(writer: &mut W, string: &str) {
135143
writer.write(string.as_bytes());
136144
}
137-
138-
pub fn hash(data: ~str) -> ~str {
139-
let hasher = &mut hash::default_state();
140-
write(hasher, data);
141-
hasher.result_str()
142-
}
143-

src/librustpkg/package_source.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -287,7 +287,7 @@ impl PkgSrc {
287287
// FIXME (#9639): This needs to handle non-utf8 paths
288288
let url = format!("https://{}", crateid.path.as_str().unwrap());
289289
debug!("Fetching package: git clone {} {} [version={}]",
290-
url, clone_target.display(), crateid.get_version());
290+
url, clone_target.display(), crateid.version_or_default());
291291

292292
let mut failed = false;
293293

src/librustpkg/path_util.rs

Lines changed: 30 additions & 125 deletions
Original file line numberDiff line numberDiff line change
@@ -14,17 +14,16 @@
1414

1515
pub use crate_id::CrateId;
1616
pub use target::{OutputType, Main, Lib, Test, Bench, Target, Build, Install};
17-
pub use version::{Version, split_version, split_version_general,
18-
try_parsing_version};
17+
pub use version::{Version, split_version, split_version_general, try_parsing_version};
1918
pub use rustc::metadata::filesearch::rust_path;
20-
use rustc::metadata::filesearch::{libdir, relative_target_lib_path};
21-
use rustc::driver::driver::host_triple;
2219

2320
use std::libc;
2421
use std::libc::consts::os::posix88::{S_IRUSR, S_IWUSR, S_IXUSR};
2522
use std::os;
2623
use std::io;
2724
use std::io::fs;
25+
use rustc::metadata::filesearch::{libdir, relative_target_lib_path};
26+
use rustc::driver::driver::host_triple;
2827
use messages::*;
2928

3029
pub fn default_workspace() -> Path {
@@ -173,151 +172,57 @@ fn output_in_workspace(crateid: &CrateId, workspace: &Path, what: OutputType) ->
173172
/// Figure out what the library name for <crateid> in <workspace>'s build
174173
/// directory is, and if the file exists, return it.
175174
pub fn built_library_in_workspace(crateid: &CrateId, workspace: &Path) -> Option<Path> {
176-
library_in_workspace(&crateid.path, crateid.short_name, Build, workspace, "build",
177-
&crateid.version)
175+
library_in_workspace(crateid, Build, workspace)
178176
}
179177

180178
/// Does the actual searching stuff
181-
pub fn installed_library_in_workspace(pkg_path: &Path, workspace: &Path) -> Option<Path> {
179+
pub fn installed_library_in_workspace(crate_id: &CrateId, workspace: &Path) -> Option<Path> {
182180
// This could break once we're handling multiple versions better -- I should add a test for it
183181
// FIXME (#9639): This needs to handle non-utf8 paths
184-
match pkg_path.filename_str() {
182+
match crate_id.path.filename_str() {
185183
None => None,
186-
Some(short_name) => library_in_workspace(pkg_path,
187-
short_name,
188-
Install,
189-
workspace,
190-
libdir(),
191-
&None)
184+
Some(_short_name) => library_in_workspace(crate_id, Install, workspace)
192185
}
193186
}
194187

195188
/// `workspace` is used to figure out the directory to search.
196189
/// `short_name` is taken as the link name of the library.
197-
pub fn library_in_workspace(path: &Path, short_name: &str, where: Target,
198-
workspace: &Path, prefix: &str, version: &Version) -> Option<Path> {
190+
pub fn library_in_workspace(crate_id: &CrateId, where: Target, workspace: &Path) -> Option<Path> {
199191
debug!("library_in_workspace: checking whether a library named {} exists",
200-
short_name);
201-
202-
// We don't know what the hash is, so we have to search through the directory
203-
// contents
204-
205-
debug!("short_name = {} where = {:?} workspace = {} \
206-
prefix = {}", short_name, where, workspace.display(), prefix);
192+
crate_id.short_name);
207193

208194
let dir_to_search = match where {
209-
Build => target_build_dir(workspace).join(path),
195+
Build => target_build_dir(workspace).join(&crate_id.path),
210196
Install => target_lib_dir(workspace)
211197
};
212198

213-
library_in(short_name, version, &dir_to_search)
199+
library_in(crate_id, &dir_to_search)
214200
}
215201

216202
pub fn system_library(sysroot: &Path, crate_id: &str) -> Option<Path> {
217-
let (lib_name, version) = split_crate_id(crate_id);
218-
library_in(lib_name, &version, &sysroot.join(relative_target_lib_path(host_triple())))
219-
}
220-
221-
fn library_in(short_name: &str, version: &Version, dir_to_search: &Path) -> Option<Path> {
222-
debug!("Listing directory {}", dir_to_search.display());
223-
let dir_contents = {
224-
let _guard = io::ignore_io_error();
225-
fs::readdir(dir_to_search)
226-
};
227-
debug!("dir has {:?} entries", dir_contents.len());
228-
229-
let dll_prefix = format!("{}{}", os::consts::DLL_PREFIX, short_name);
230-
let dll_filetype = os::consts::DLL_EXTENSION;
231-
let rlib_prefix = format!("{}{}", "lib", short_name);
232-
let rlib_filetype = "rlib";
233-
234-
debug!("dll_prefix = {} and dll_filetype = {}", dll_prefix, dll_filetype);
235-
debug!("rlib_prefix = {} and rlib_filetype = {}", rlib_prefix, rlib_filetype);
236-
237-
// Find a filename that matches the pattern:
238-
// (lib_prefix)-hash-(version)(lib_suffix)
239-
let mut libraries = dir_contents.iter().filter(|p| {
240-
let extension = p.extension_str();
241-
debug!("p = {}, p's extension is {:?}", p.display(), extension);
242-
match extension {
243-
None => false,
244-
Some(ref s) => dll_filetype == *s || rlib_filetype == *s,
203+
library_in(&CrateId::new(crate_id), &sysroot.join(relative_target_lib_path(host_triple())))
204+
}
205+
206+
fn library_in(crate_id: &CrateId, dir_to_search: &Path) -> Option<Path> {
207+
let lib_name = crate_id.to_lib_name();
208+
let filenames = [
209+
format!("{}{}.{}", "lib", lib_name, "rlib"),
210+
format!("{}{}{}", os::consts::DLL_PREFIX, lib_name, os::consts::DLL_SUFFIX),
211+
];
212+
213+
for filename in filenames.iter() {
214+
debug!("filename = {}", filename.as_slice());
215+
let path = dir_to_search.join(filename.as_slice());
216+
if path.exists() {
217+
debug!("found: {}", path.display());
218+
return Some(path);
245219
}
246-
});
247-
248-
let mut result_filename = None;
249-
for p_path in libraries {
250-
// Find a filename that matches the pattern: (lib_prefix)-hash-(version)(lib_suffix)
251-
// and remember what the hash was
252-
let mut f_name = match p_path.filestem_str() {
253-
Some(s) => s, None => continue
254-
};
255-
// Already checked the filetype above
256-
257-
// This is complicated because library names and versions can both contain dashes
258-
loop {
259-
if f_name.is_empty() { break; }
260-
match f_name.rfind('-') {
261-
Some(i) => {
262-
debug!("Maybe {} is a version", f_name.slice(i + 1, f_name.len()));
263-
match try_parsing_version(f_name.slice(i + 1, f_name.len())) {
264-
Some(ref found_vers) if version == &Some(found_vers.to_owned()) ||
265-
version == &None => {
266-
match f_name.slice(0, i).rfind('-') {
267-
Some(j) => {
268-
let lib_prefix = match p_path.extension_str() {
269-
Some(ref s) if dll_filetype == *s => &dll_prefix,
270-
_ => &rlib_prefix,
271-
};
272-
debug!("Maybe {} equals {}", f_name.slice(0, j), *lib_prefix);
273-
if f_name.slice(0, j) == *lib_prefix {
274-
result_filename = Some(p_path.clone());
275-
}
276-
break;
277-
}
278-
None => break
279-
}
280-
}
281-
_ => { f_name = f_name.slice(0, i); }
282-
}
283-
}
284-
None => break
285-
} // match
286-
} // loop
287-
} // for
288-
289-
if result_filename.is_none() {
290-
debug!("warning: library_in_workspace didn't find a library in {} for {}",
291-
dir_to_search.display(), short_name);
292-
}
293-
294-
// Return the filename that matches, which we now know exists
295-
// (if result_filename != None)
296-
let abs_path = result_filename.map(|result_filename| {
297-
let absolute_path = dir_to_search.join(&result_filename);
298-
debug!("result_filename = {}", absolute_path.display());
299-
absolute_path
300-
});
301-
302-
abs_path
303-
}
304-
305-
fn split_crate_id<'a>(crate_id: &'a str) -> (&'a str, Version) {
306-
match split_version(crate_id) {
307-
Some((name, vers)) =>
308-
match vers {
309-
Some(ref v) => match v.find('-') {
310-
Some(pos) => (name, Some(v.slice(0, pos).to_owned())),
311-
None => (name, Some(v.to_owned()))
312-
},
313-
_ => (name, vers)
314-
},
315-
None => (crate_id, None)
316220
}
221+
debug!("warning: library_in_workspace didn't find a library in {} for {}",
222+
dir_to_search.display(), crate_id.short_name);
223+
return None;
317224
}
318225

319-
320-
321226
/// Returns the executable that would be installed for <crateid>
322227
/// in <workspace>
323228
/// As a side effect, creates the bin-dir if it doesn't exist

0 commit comments

Comments
 (0)