From 405bc3d80c0e169ea74dd12422b9504b7383dab3 Mon Sep 17 00:00:00 2001 From: FintanH Date: Mon, 12 Aug 2019 22:22:24 +0100 Subject: Refactor of File to be the combination of Directory and the file name, where Directory is the Vector of component paths. The refactor meant changing some sections of the code where we were parsing and manipulating Files/Directories. This also includes a new trait Canonicalization which is needed for import logic. --- dhall/src/phase/binary.rs | 29 ++++++++++++++++++++--------- dhall/src/phase/resolve.rs | 11 ++++++----- 2 files changed, 26 insertions(+), 14 deletions(-) (limited to 'dhall/src') diff --git a/dhall/src/phase/binary.rs b/dhall/src/phase/binary.rs index 1812131..3acd2d4 100644 --- a/dhall/src/phase/binary.rs +++ b/dhall/src/phase/binary.rs @@ -1,12 +1,13 @@ use itertools::Itertools; use serde_cbor::value::value as cbor; use std::iter::FromIterator; +use std::vec; use dhall_syntax::map::DupTreeMap; use dhall_syntax::{ rc, ExprF, FilePrefix, Hash, Import, ImportHashed, ImportLocation, ImportMode, Integer, InterpolatedText, Label, Natural, Scheme, SubExpr, - URL, V, + URL, V, Directory, File, }; use crate::error::{DecodeError, EncodeError}; @@ -243,7 +244,7 @@ fn cbor_value_to_dhall( "import/remote/query".to_owned(), ))?, }; - let path = rest + let mut components: Vec<_> = rest .map(|s| match s.as_string() { Some(s) => Ok(s.clone()), None => Err(DecodeError::WrongFormatError( @@ -251,6 +252,11 @@ fn cbor_value_to_dhall( )), }) .collect::>()?; + let file = components.pop().ok_or( + DecodeError::WrongFormatError( + "import/remote/path".to_owned(), + ))?; + let path = File { directory: Directory { components: components }, file: file }; ImportLocation::Remote(URL { scheme, authority, @@ -269,7 +275,7 @@ fn cbor_value_to_dhall( "import/local/prefix".to_owned(), ))?, }; - let path = rest + let mut components: Vec<_> = rest .map(|s| match s.as_string() { Some(s) => Ok(s.clone()), None => Err(DecodeError::WrongFormatError( @@ -277,6 +283,11 @@ fn cbor_value_to_dhall( )), }) .collect::>()?; + let file = components.pop().ok_or( + DecodeError::WrongFormatError( + "import/remote/path".to_owned(), + ))?; + let path = File { directory: Directory { components: components }, file: file }; ImportLocation::Local(prefix, path) } 6 => { @@ -520,8 +531,8 @@ where use serde::ser::SerializeSeq; let count = 4 + match &import.location_hashed.location { - ImportLocation::Remote(url) => 3 + url.path.len(), - ImportLocation::Local(_, path) => path.len(), + ImportLocation::Remote(url) => 3 + url.path.clone().into_iter().len(), + ImportLocation::Local(_, path) => path.clone().into_iter().len(), ImportLocation::Env(_) => 1, ImportLocation::Missing => 0, }; @@ -573,8 +584,8 @@ where )?, }; ser_seq.serialize_element(&url.authority)?; - for p in &url.path { - ser_seq.serialize_element(p)?; + for p in url.path.clone().into_iter() { + ser_seq.serialize_element(&p)?; } match &url.query { None => ser_seq.serialize_element(&Null)?, @@ -582,8 +593,8 @@ where }; } ImportLocation::Local(_, path) => { - for p in path { - ser_seq.serialize_element(p)?; + for p in path.clone().into_iter() { + ser_seq.serialize_element(&p)?; } } ImportLocation::Env(env) => { diff --git a/dhall/src/phase/resolve.rs b/dhall/src/phase/resolve.rs index c4d7e5f..ba75be4 100644 --- a/dhall/src/phase/resolve.rs +++ b/dhall/src/phase/resolve.rs @@ -16,6 +16,7 @@ type ImportCache = HashMap; pub type ImportStack = Vec; + fn resolve_import( import: &Import, root: &ImportRoot, @@ -30,14 +31,14 @@ fn resolve_import( }; match &import.location_hashed.location { Local(prefix, path) => { - let path: PathBuf = path.iter().cloned().collect(); - let path = match prefix { + let path_buf: PathBuf = path.clone().into_iter().collect(); + let path_buf = match prefix { // TODO: fail gracefully - Parent => cwd.parent().unwrap().join(path), - Here => cwd.join(path), + Parent => cwd.parent().unwrap().join(path_buf), + Here => cwd.join(path_buf), _ => unimplemented!("{:?}", import), }; - Ok(load_import(&path, import_cache, import_stack).map_err(|e| { + Ok(load_import(&path_buf, import_cache, import_stack).map_err(|e| { ImportError::Recursive(import.clone(), Box::new(e)) })?) } -- cgit v1.2.3 From e73f822b6972e8fa2e72b56ff5378b91bea1a5e6 Mon Sep 17 00:00:00 2001 From: Fintan Halpenny Date: Mon, 2 Sep 2019 21:17:00 +0100 Subject: Remove the notion of Directory and have File be the vector of components --- dhall/src/phase/binary.rs | 18 +++++------------- 1 file changed, 5 insertions(+), 13 deletions(-) (limited to 'dhall/src') diff --git a/dhall/src/phase/binary.rs b/dhall/src/phase/binary.rs index 6bdc3f9..89b6db2 100644 --- a/dhall/src/phase/binary.rs +++ b/dhall/src/phase/binary.rs @@ -7,7 +7,7 @@ use dhall_syntax::map::DupTreeMap; use dhall_syntax::{ rc, ExprF, FilePrefix, Hash, Import, ImportHashed, ImportLocation, ImportMode, Integer, InterpolatedText, Label, Natural, Scheme, SubExpr, - URL, V, Directory, File, + URL, V, File, }; use crate::error::{DecodeError, EncodeError}; @@ -291,7 +291,7 @@ fn cbor_value_to_dhall( "import/remote/query".to_owned(), ))?, }; - let mut components: Vec<_> = rest + let file_path: Vec<_> = rest .map(|s| match s.as_string() { Some(s) => Ok(s.clone()), None => Err(DecodeError::WrongFormatError( @@ -299,11 +299,7 @@ fn cbor_value_to_dhall( )), }) .collect::>()?; - let file = components.pop().ok_or( - DecodeError::WrongFormatError( - "import/remote/path".to_owned(), - ))?; - let path = File { directory: Directory { components: components }, file: file }; + let path = File { file_path }; ImportLocation::Remote(URL { scheme, authority, @@ -322,7 +318,7 @@ fn cbor_value_to_dhall( "import/local/prefix".to_owned(), ))?, }; - let mut components: Vec<_> = rest + let file_path: Vec<_> = rest .map(|s| match s.as_string() { Some(s) => Ok(s.clone()), None => Err(DecodeError::WrongFormatError( @@ -330,11 +326,7 @@ fn cbor_value_to_dhall( )), }) .collect::>()?; - let file = components.pop().ok_or( - DecodeError::WrongFormatError( - "import/remote/path".to_owned(), - ))?; - let path = File { directory: Directory { components: components }, file: file }; + let path = File { file_path }; ImportLocation::Local(prefix, path) } 6 => { -- cgit v1.2.3 From 74fdefa4375a60648b667136e94119bcdd377a32 Mon Sep 17 00:00:00 2001 From: Fintan Halpenny Date: Tue, 3 Sep 2019 13:53:31 +0100 Subject: swp file accidentally checked in --- dhall/src/phase/.resolve.rs.swp | Bin 16384 -> 0 bytes 1 file changed, 0 insertions(+), 0 deletions(-) delete mode 100644 dhall/src/phase/.resolve.rs.swp (limited to 'dhall/src') diff --git a/dhall/src/phase/.resolve.rs.swp b/dhall/src/phase/.resolve.rs.swp deleted file mode 100644 index 5314300..0000000 Binary files a/dhall/src/phase/.resolve.rs.swp and /dev/null differ -- cgit v1.2.3 From 4edaf0814868e604eed5cfd594ea3f448ca90678 Mon Sep 17 00:00:00 2001 From: Fintan Halpenny Date: Tue, 3 Sep 2019 14:42:30 +0100 Subject: Move Canonicalize into resolve. Rename File to FilePath and have more consistent naming. --- dhall/src/phase/binary.rs | 10 +++---- dhall/src/phase/resolve.rs | 70 ++++++++++++++++++++++++++++++++++++++++++++++ 2 files changed, 75 insertions(+), 5 deletions(-) (limited to 'dhall/src') diff --git a/dhall/src/phase/binary.rs b/dhall/src/phase/binary.rs index 16e7ce9..3c45e81 100644 --- a/dhall/src/phase/binary.rs +++ b/dhall/src/phase/binary.rs @@ -6,7 +6,7 @@ use std::vec; use dhall_syntax::map::DupTreeMap; use dhall_syntax::{ rc, Expr, ExprF, FilePrefix, Hash, Import, ImportLocation, ImportMode, - Integer, InterpolatedText, Label, Natural, Scheme, URL, V, File + Integer, InterpolatedText, Label, Natural, Scheme, URL, V, FilePath }; use crate::error::{DecodeError, EncodeError}; @@ -279,7 +279,7 @@ fn cbor_value_to_dhall(data: &cbor::Value) -> Result { "import/remote/query".to_owned(), ))?, }; - let file_path: Vec<_> = rest + let file_path = rest .map(|s| match s.as_string() { Some(s) => Ok(s.clone()), None => Err(DecodeError::WrongFormatError( @@ -287,7 +287,7 @@ fn cbor_value_to_dhall(data: &cbor::Value) -> Result { )), }) .collect::>()?; - let path = File { file_path }; + let path = FilePath { file_path }; ImportLocation::Remote(URL { scheme, authority, @@ -306,7 +306,7 @@ fn cbor_value_to_dhall(data: &cbor::Value) -> Result { "import/local/prefix".to_owned(), ))?, }; - let file_path: Vec<_> = rest + let file_path = rest .map(|s| match s.as_string() { Some(s) => Ok(s.clone()), None => Err(DecodeError::WrongFormatError( @@ -314,7 +314,7 @@ fn cbor_value_to_dhall(data: &cbor::Value) -> Result { )), }) .collect::>()?; - let path = File { file_path }; + let path = FilePath { file_path }; ImportLocation::Local(prefix, path) } 6 => { diff --git a/dhall/src/phase/resolve.rs b/dhall/src/phase/resolve.rs index 5bde68a..54a0f27 100644 --- a/dhall/src/phase/resolve.rs +++ b/dhall/src/phase/resolve.rs @@ -3,6 +3,7 @@ use std::path::{Path, PathBuf}; use crate::error::{Error, ImportError}; use crate::phase::{Normalized, NormalizedExpr, Parsed, Resolved}; +use dhall_syntax::{FilePath, ImportLocation, URL}; type Import = dhall_syntax::Import; @@ -105,6 +106,75 @@ pub(crate) fn skip_resolve_expr( Ok(Resolved(expr)) } +pub trait Canonicalize { + fn canonicalize(&self) -> Self; +} + +impl Canonicalize for FilePath { + fn canonicalize(&self) -> FilePath { + let mut file_path = Vec::new(); + let mut file_path_components = self.file_path.clone().into_iter(); + + loop { + let component = file_path_components.next(); + match component.as_ref() { + // ─────────────────── + // canonicalize(ε) = ε + None => break, + + // canonicalize(directory₀) = directory₁ + // ─────────────────────────────────────── + // canonicalize(directory₀/.) = directory₁ + Some(c) if c == "." => continue, + + Some(c) if c == ".." => match file_path_components.next() { + // canonicalize(directory₀) = ε + // ──────────────────────────── + // canonicalize(directory₀/..) = /.. + None => file_path.push("..".to_string()), + + // canonicalize(directory₀) = directory₁/.. + // ────────────────────────────────────────────── + // canonicalize(directory₀/..) = directory₁/../.. + Some(ref c) if c == ".." => { + file_path.push("..".to_string()); + file_path.push("..".to_string()); + }, + + // canonicalize(directory₀) = directory₁/component + // ─────────────────────────────────────────────── ; If "component" is not + // canonicalize(directory₀/..) = directory₁ ; ".." + Some(_) => continue, + }, + + // canonicalize(directory₀) = directory₁ + // ───────────────────────────────────────────────────────── ; If no other + // canonicalize(directory₀/component) = directory₁/component ; rule matches + Some(c) => file_path.push(c.clone()), + } + } + + FilePath { file_path } + } +} + +impl Canonicalize for ImportLocation { + fn canonicalize(&self) -> ImportLocation { + match self { + ImportLocation::Local(prefix, file) => ImportLocation::Local(*prefix, file.canonicalize()), + ImportLocation::Remote(url) => ImportLocation::Remote(URL { + scheme: url.scheme, + authority: url.authority.clone(), + path: url.path.canonicalize(), + query: url.query.clone(), + headers: url.headers.clone(), + }), + ImportLocation::Env(name) => ImportLocation::Env(name.to_string()), + ImportLocation::Missing => ImportLocation::Missing, + } + } +} + #[cfg(test)] #[rustfmt::skip] mod spec_tests { -- cgit v1.2.3