Mike Gerwitz

Activist for User Freedom

aboutsummaryrefslogtreecommitdiffstats
path: root/tamer
diff options
context:
space:
mode:
authorMike Gerwitz <mike.gerwitz@ryansg.com>2020-04-07 11:40:19 -0400
committerMike Gerwitz <mike.gerwitz@ryansg.com>2020-04-28 09:06:25 -0400
commit0f423f3b24837cb2d6d5dc254427751ff709ab54 (patch)
treef8e4b6731c9ef28edf8e01198c654355e1b660f9 /tamer
parent4a7e00c404c14261c4a7d492b54c84e22e060e37 (diff)
downloadtame-0f423f3b24837cb2d6d5dc254427751ff709ab54.tar.gz
tame-0f423f3b24837cb2d6d5dc254427751ff709ab54.tar.bz2
tame-0f423f3b24837cb2d6d5dc254427751ff709ab54.zip
[DEV-7084] TAMER: Simplify path canonicalization
This abstracts away the canonicalizer and solves the problem whereby canonicalization was not being performed prior to recording whether a path has been visited. This ensures that multiple relative paths to the same file will be properly recognized as visited.
Diffstat (limited to 'tamer')
-rw-r--r--tamer/src/fs.rs91
-rw-r--r--tamer/src/ld/poc.rs18
-rw-r--r--tamer/src/obj/xmlo/asg_builder.rs2
-rw-r--r--tamer/src/obj/xmlo/mod.rs2
4 files changed, 81 insertions, 32 deletions
diff --git a/tamer/src/fs.rs b/tamer/src/fs.rs
index ede456a..fa512c1 100644
--- a/tamer/src/fs.rs
+++ b/tamer/src/fs.rs
@@ -42,6 +42,7 @@ use std::ffi::OsString;
use std::fs;
use std::hash::BuildHasher;
use std::io::{BufReader, Read, Result};
+use std::marker::PhantomData;
use std::path::{Path, PathBuf};
/// A file.
@@ -65,20 +66,21 @@ impl<F: File + Read> File for BufReader<F> {
}
}
-pub struct CanonicalFile<F: File>(PathBuf, F);
+#[derive(Debug, PartialEq)]
+pub struct PathFile<F: File>(PathBuf, F);
-impl<F: File> Into<(PathBuf, F)> for CanonicalFile<F> {
+impl<F: File> Into<(PathBuf, F)> for PathFile<F> {
fn into(self) -> (PathBuf, F) {
(self.0, self.1)
}
}
-impl<F: File> File for CanonicalFile<F> {
+impl<F: File> File for PathFile<F> {
fn open<P: AsRef<Path>>(path: P) -> Result<Self> {
- let cpath = fs::canonicalize(path)?;
- let file = F::open(&cpath)?;
+ let buf = path.as_ref().to_path_buf();
+ let file = F::open(&buf)?;
- Ok(Self(cpath, file))
+ Ok(Self(buf, file))
}
}
@@ -122,21 +124,25 @@ impl<F: File> File for VisitOnceFile<F> {
/// [`VisitOnceFile::Visited`] without attempting to open the file.
///
/// A file will not be marked as visited if it fails to be opened.
-pub struct VisitOnceFilesystem<S = RandomState>
+pub struct VisitOnceFilesystem<C, S = RandomState>
where
+ C: Canonicalizer,
S: BuildHasher,
{
visited: HashSet<OsString, S>,
+ _c: PhantomData<C>,
}
-impl<S> VisitOnceFilesystem<S>
+impl<C, S> VisitOnceFilesystem<C, S>
where
+ C: Canonicalizer,
S: BuildHasher + Default,
{
/// New filesystem with no recorded paths.
pub fn new() -> Self {
Self {
visited: Default::default(),
+ _c: PhantomData,
}
}
@@ -146,8 +152,9 @@ where
}
}
-impl<S, F> Filesystem<VisitOnceFile<F>> for VisitOnceFilesystem<S>
+impl<C, S, F> Filesystem<VisitOnceFile<F>> for VisitOnceFilesystem<C, S>
where
+ C: Canonicalizer,
S: BuildHasher,
F: File,
{
@@ -158,7 +165,8 @@ where
///
/// `path` will not be marked as visited if opening fails.
fn open<P: AsRef<Path>>(&mut self, path: P) -> Result<VisitOnceFile<F>> {
- let ostr = path.as_ref().as_os_str();
+ let cpath = C::canonicalize(path)?;
+ let ostr = cpath.as_os_str();
if self.visited.contains(ostr) {
return Ok(VisitOnceFile::Visited);
@@ -171,6 +179,18 @@ where
}
}
+pub trait Canonicalizer {
+ fn canonicalize<P: AsRef<Path>>(path: P) -> Result<PathBuf>;
+}
+
+pub struct FsCanonicalizer;
+
+impl Canonicalizer for FsCanonicalizer {
+ fn canonicalize<P: AsRef<Path>>(path: P) -> Result<PathBuf> {
+ std::fs::canonicalize(path)
+ }
+}
+
#[cfg(test)]
mod test {
use super::*;
@@ -200,16 +220,49 @@ mod test {
}
#[test]
- fn vist_once() {
- let mut fs = VisitOnceFilesystem::<RandomState>::new();
- let path: PathBuf = "foo/bar".into();
- let result = fs.open(path.clone()).unwrap();
+ fn path_file() {
+ let path: PathBuf = "buf/path".into();
+ let result: PathFile<DummyFile> = File::open(path.clone()).unwrap();
- // First time, return file.
- assert_eq!(VisitOnceFile::FirstVisit(DummyFile(path.clone())), result);
+ assert_eq!(PathFile(path.clone(), DummyFile(path.clone())), result);
+
+ // Tuple conversion.
+ assert_eq!((path.clone(), DummyFile(path.clone())), result.into());
+ }
- // Second time, already visited.
- let result_2: VisitOnceFile<DummyFile> = fs.open(path).unwrap();
- assert_eq!(VisitOnceFile::Visited, result_2);
+ mod canonicalizer {
+ use super::*;
+
+ struct StubCanonicalizer;
+
+ impl Canonicalizer for StubCanonicalizer {
+ fn canonicalize<P: AsRef<Path>>(path: P) -> Result<PathBuf> {
+ let mut buf = path.as_ref().to_path_buf();
+ buf.push("CANONICALIZED");
+
+ Ok(buf)
+ }
+ }
+
+ #[test]
+ fn vist_once() {
+ let mut fs =
+ VisitOnceFilesystem::<StubCanonicalizer, RandomState>::new();
+ let path: PathBuf = "foo/bar".into();
+ let result = fs.open(path.clone()).unwrap();
+
+ let mut expected_path = path.clone().to_path_buf();
+ expected_path.push("CANONICALIZED");
+
+ // First time, return file.
+ assert_eq!(
+ VisitOnceFile::FirstVisit(DummyFile(expected_path)),
+ result
+ );
+
+ // Second time, already visited.
+ let result_2: VisitOnceFile<DummyFile> = fs.open(path).unwrap();
+ assert_eq!(VisitOnceFile::Visited, result_2);
+ }
}
}
diff --git a/tamer/src/ld/poc.rs b/tamer/src/ld/poc.rs
index 80abaed..0a395ba 100644
--- a/tamer/src/ld/poc.rs
+++ b/tamer/src/ld/poc.rs
@@ -21,7 +21,7 @@
//! banished to its own file to try to make that more clear.
use crate::fs::{
- CanonicalFile, Filesystem, VisitOnceFile, VisitOnceFilesystem,
+ Filesystem, FsCanonicalizer, PathFile, VisitOnceFile, VisitOnceFilesystem,
};
use crate::global;
use crate::ir::asg::{
@@ -36,7 +36,7 @@ use fxhash::FxBuildHasher;
use std::error::Error;
use std::fs;
use std::io::BufReader;
-use std::path::PathBuf;
+use std::path::{Path, PathBuf};
type LinkerAsg<'i> = DefaultAsg<'i, IdentObject<'i>, global::ProgIdentSize>;
@@ -111,14 +111,14 @@ pub fn main(package_path: &str, output: &str) -> Result<(), Box<dyn Error>> {
Ok(())
}
-fn load_xmlo<'a, 'i, I: Interner<'i>>(
- path_str: &'a str,
- fs: &mut VisitOnceFilesystem<FxBuildHasher>,
+fn load_xmlo<'a, 'i, I: Interner<'i>, P: AsRef<Path>>(
+ path_str: P,
+ fs: &mut VisitOnceFilesystem<FsCanonicalizer, FxBuildHasher>,
depgraph: &mut LinkerAsg<'i>,
interner: &'i I,
state: LinkerAsgBuilderState<'i>,
) -> Result<LinkerAsgBuilderState<'i>, Box<dyn Error>> {
- let cfile: CanonicalFile<BufReader<fs::File>> = match fs.open(path_str)? {
+ let cfile: PathFile<BufReader<fs::File>> = match fs.open(path_str)? {
VisitOnceFile::FirstVisit(file) => file,
VisitOnceFile::Visited => return Ok(state),
};
@@ -139,11 +139,7 @@ fn load_xmlo<'a, 'i, I: Interner<'i>>(
path_buf.push(relpath);
path_buf.set_extension("xmlo");
- // println!("Trying {:?}", path_buf);
- let path_abs = path_buf.canonicalize()?;
- let path = path_abs.to_str().unwrap();
-
- state = load_xmlo(path, fs, depgraph, interner, state)?;
+ state = load_xmlo(path_buf, fs, depgraph, interner, state)?;
}
Ok(state)
diff --git a/tamer/src/obj/xmlo/asg_builder.rs b/tamer/src/obj/xmlo/asg_builder.rs
index 1f50249..ec563ff 100644
--- a/tamer/src/obj/xmlo/asg_builder.rs
+++ b/tamer/src/obj/xmlo/asg_builder.rs
@@ -21,10 +21,10 @@ use super::reader::{XmloError, XmloEvent, XmloReader};
use crate::ir::asg::{Asg, IdentKind, IdentObjectState, ObjectRef, Source};
use crate::sym::{Interner, Symbol};
use petgraph::graph::IndexType;
+use std::collections::HashSet;
use std::convert::TryInto;
use std::error::Error;
use std::hash::BuildHasher;
-use std::collections::HashSet;
use std::io::BufRead;
// TODO error type
diff --git a/tamer/src/obj/xmlo/mod.rs b/tamer/src/obj/xmlo/mod.rs
index 113c9c7..cda31dd 100644
--- a/tamer/src/obj/xmlo/mod.rs
+++ b/tamer/src/obj/xmlo/mod.rs
@@ -74,7 +74,7 @@
//! </package>
//! ```
-pub mod reader;
mod asg_builder;
+pub mod reader;
pub use asg_builder::{AsgBuilder, AsgBuilderState};