feat(solc): relative remappings (#786)
This commit is contained in:
parent
d2b59d7097
commit
b619a5522f
|
@ -190,6 +190,124 @@ impl Remapping {
|
|||
}
|
||||
}
|
||||
|
||||
/// A relative [`Remapping`] that's aware of the current location
|
||||
///
|
||||
/// See [`RelativeRemappingPathBuf`]
|
||||
#[derive(Clone, Debug, PartialEq)]
|
||||
pub struct RelativeRemapping {
|
||||
pub name: String,
|
||||
pub path: RelativeRemappingPathBuf,
|
||||
}
|
||||
|
||||
impl RelativeRemapping {
|
||||
/// Creates a new `RelativeRemapping` starting prefixed with `root`
|
||||
pub fn new(remapping: Remapping, root: impl AsRef<Path>) -> Self {
|
||||
Self {
|
||||
name: remapping.name,
|
||||
path: RelativeRemappingPathBuf::with_root(root, remapping.path),
|
||||
}
|
||||
}
|
||||
|
||||
/// Converts this relative remapping into an absolute remapping
|
||||
///
|
||||
/// This sets to root of the remapping to the given `root` path
|
||||
pub fn to_remapping(mut self, root: PathBuf) -> Remapping {
|
||||
self.path.parent = Some(root);
|
||||
self.into()
|
||||
}
|
||||
}
|
||||
|
||||
// Remappings are printed as `prefix=target`
|
||||
impl fmt::Display for RelativeRemapping {
|
||||
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
|
||||
write!(f, "{}={}", self.name, self.path.original().display())
|
||||
}
|
||||
}
|
||||
|
||||
impl From<RelativeRemapping> for Remapping {
|
||||
fn from(r: RelativeRemapping) -> Self {
|
||||
Remapping { name: r.name, path: r.path.relative().to_string_lossy().to_string() }
|
||||
}
|
||||
}
|
||||
|
||||
impl From<Remapping> for RelativeRemapping {
|
||||
fn from(r: Remapping) -> Self {
|
||||
Self { name: r.name, path: r.path.into() }
|
||||
}
|
||||
}
|
||||
|
||||
/// The path part of the [`Remapping`] that knows the path of the file it was configured in, if any.
|
||||
///
|
||||
/// A [`Remapping`] is intended to be absolute, but paths in configuration files are often desired
|
||||
/// to be relative to the configuration file itself. For example, a path of
|
||||
/// `weird-erc20/=lib/weird-erc20/src/` configured in a file `/var/foundry.toml` might be desired to
|
||||
/// resolve as a `weird-erc20/=/var/lib/weird-erc20/src/` remapping.
|
||||
#[derive(Debug, Clone, PartialEq)]
|
||||
pub struct RelativeRemappingPathBuf {
|
||||
parent: Option<PathBuf>,
|
||||
path: PathBuf,
|
||||
}
|
||||
|
||||
impl RelativeRemappingPathBuf {
|
||||
/// Creates a new `RelativeRemappingPathBuf` that checks if the `path` is a child path of
|
||||
/// `parent`.
|
||||
pub fn with_root(parent: impl AsRef<Path>, path: impl AsRef<Path>) -> Self {
|
||||
let parent = parent.as_ref();
|
||||
let path = path.as_ref();
|
||||
if let Ok(path) = path.strip_prefix(parent) {
|
||||
Self { parent: Some(parent.to_path_buf()), path: path.to_path_buf() }
|
||||
} else if path.has_root() {
|
||||
Self { parent: None, path: path.to_path_buf() }
|
||||
} else {
|
||||
Self { parent: Some(parent.to_path_buf()), path: path.to_path_buf() }
|
||||
}
|
||||
}
|
||||
|
||||
/// Returns the path as it was declared, without modification.
|
||||
pub fn original(&self) -> &Path {
|
||||
&self.path
|
||||
}
|
||||
|
||||
/// Returns this path relative to the file it was delcared in, if any.
|
||||
/// Returns the original if this path was not declared in a file or if the
|
||||
/// path has a root.
|
||||
pub fn relative(&self) -> PathBuf {
|
||||
if self.original().has_root() {
|
||||
return self.original().into()
|
||||
}
|
||||
self.parent
|
||||
.as_ref()
|
||||
.map(|p| p.join(self.original()))
|
||||
.unwrap_or_else(|| self.original().into())
|
||||
}
|
||||
}
|
||||
|
||||
impl<P: AsRef<Path>> From<P> for RelativeRemappingPathBuf {
|
||||
fn from(path: P) -> RelativeRemappingPathBuf {
|
||||
Self { parent: None, path: path.as_ref().to_path_buf() }
|
||||
}
|
||||
}
|
||||
|
||||
impl Serialize for RelativeRemapping {
|
||||
fn serialize<S>(&self, serializer: S) -> std::result::Result<S::Ok, S::Error>
|
||||
where
|
||||
S: serde::ser::Serializer,
|
||||
{
|
||||
serializer.serialize_str(&self.to_string())
|
||||
}
|
||||
}
|
||||
|
||||
impl<'de> Deserialize<'de> for RelativeRemapping {
|
||||
fn deserialize<D>(deserializer: D) -> std::result::Result<Self, D::Error>
|
||||
where
|
||||
D: serde::de::Deserializer<'de>,
|
||||
{
|
||||
let remapping = String::deserialize(deserializer)?;
|
||||
let remapping = Remapping::from_str(&remapping).map_err(serde::de::Error::custom)?;
|
||||
Ok(RelativeRemapping { name: remapping.name, path: remapping.path.into() })
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Debug, Clone)]
|
||||
struct Candidate {
|
||||
/// dir that opened the window
|
||||
|
@ -358,6 +476,27 @@ mod tests {
|
|||
use super::*;
|
||||
use crate::utils::tempdir;
|
||||
|
||||
#[test]
|
||||
fn relative_remapping() {
|
||||
let remapping = "oz=a/b/c/d";
|
||||
let remapping = Remapping::from_str(remapping).unwrap();
|
||||
|
||||
let relative = RelativeRemapping::new(remapping.clone(), "a/b/c");
|
||||
assert_eq!(relative.path.relative(), Path::new(&remapping.path));
|
||||
assert_eq!(relative.path.original(), Path::new("d"));
|
||||
|
||||
let relative = RelativeRemapping::new(remapping.clone(), "x/y");
|
||||
assert_eq!(relative.path.relative(), Path::new("x/y/a/b/c/d"));
|
||||
assert_eq!(relative.path.original(), Path::new(&remapping.path));
|
||||
|
||||
let remapping = "oz=/a/b/c/d";
|
||||
let remapping = Remapping::from_str(remapping).unwrap();
|
||||
let relative = RelativeRemapping::new(remapping.clone(), "a/b");
|
||||
assert_eq!(relative.path.relative(), Path::new(&remapping.path));
|
||||
assert_eq!(relative.path.original(), Path::new(&remapping.path));
|
||||
assert!(relative.path.parent.is_none());
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn serde() {
|
||||
let remapping = "oz=../b/c/d";
|
||||
|
|
Loading…
Reference in New Issue