Skip to content

Commit

Permalink
Implement file hashing, except when inputs are present
Browse files Browse the repository at this point in the history
  • Loading branch information
gsoltis authored and Greg Soltis committed May 8, 2023
1 parent e4c26b7 commit cb9e8d2
Show file tree
Hide file tree
Showing 21 changed files with 919 additions and 56 deletions.
10 changes: 6 additions & 4 deletions Cargo.lock

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

2 changes: 2 additions & 0 deletions cli/internal/ffi/bindings.h
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,8 @@ struct Buffer previous_content(struct Buffer buffer);

struct Buffer recursive_copy(struct Buffer buffer);

struct Buffer recursive_copy(struct Buffer buffer);

struct Buffer transitive_closure(struct Buffer buf);

struct Buffer subgraph(struct Buffer buf);
Expand Down
1 change: 1 addition & 0 deletions crates/turbopath/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@ edition = "2021"
# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html

[dependencies]
bstr = "1.4.0"
path-slash = "0.2.1"
# TODO: Make this a crate feature
serde = { workspace = true }
Expand Down
21 changes: 21 additions & 0 deletions crates/turbopath/src/absolute_system_path_buf.rs
Original file line number Diff line number Diff line change
Expand Up @@ -62,6 +62,10 @@ impl AbsoluteSystemPathBuf {
Ok(AbsoluteSystemPathBuf(system_path))
}

pub fn new_unchecked(raw: impl Into<PathBuf>) -> Self {
Self(raw.into())
}

/// Anchors `path` at `self`.
///
/// # Arguments
Expand Down Expand Up @@ -163,6 +167,14 @@ impl AbsoluteSystemPathBuf {
AbsoluteSystemPathBuf(self.0.join(Path::new(segment)))
}

pub fn join_unix_path_literal<S: AsRef<str>>(
&self,
unix_path: S,
) -> Result<AbsoluteSystemPathBuf, PathError> {
let tail = Path::new(unix_path.as_ref()).into_system()?;
Ok(AbsoluteSystemPathBuf(self.0.join(tail)))
}

pub fn ensure_dir(&self) -> Result<(), io::Error> {
if let Some(parent) = self.0.parent() {
fs::create_dir_all(parent)
Expand All @@ -171,6 +183,10 @@ impl AbsoluteSystemPathBuf {
}
}

pub fn create_dir(&self) -> Result<(), io::Error> {
fs::create_dir_all(self.0.as_path())
}

pub fn remove(&self) -> Result<(), io::Error> {
fs::remove_file(self.0.as_path())
}
Expand Down Expand Up @@ -245,6 +261,11 @@ impl AbsoluteSystemPathBuf {
pub fn open(&self) -> Result<fs::File, PathError> {
Ok(fs::File::open(&self.0)?)
}

pub fn to_realpath(&self) -> Result<Self, PathError> {
let realpath = fs::canonicalize(&self.0)?;
Ok(Self(realpath))
}
}

impl From<AbsoluteSystemPathBuf> for PathBuf {
Expand Down
31 changes: 29 additions & 2 deletions crates/turbopath/src/anchored_system_path_buf.rs
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,9 @@ use std::path::{Path, PathBuf};

use serde::{Deserialize, Serialize};

use crate::{AbsoluteSystemPathBuf, IntoSystem, PathError, PathValidationError};
use crate::{
AbsoluteSystemPathBuf, IntoSystem, PathError, PathValidationError, RelativeUnixPathBuf,
};

#[derive(Debug, Clone, PartialEq, Eq, PartialOrd, Ord, Hash, Default, Serialize, Deserialize)]
pub struct AnchoredSystemPathBuf(PathBuf);
Expand All @@ -12,7 +14,8 @@ impl TryFrom<&Path> for AnchoredSystemPathBuf {

fn try_from(path: &Path) -> Result<Self, Self::Error> {
if path.is_absolute() {
return Err(PathValidationError::NotRelative(path.to_path_buf()).into());
let bad_path = path.display().to_string();
return Err(PathValidationError::NotRelative(bad_path).into());
}

Ok(AnchoredSystemPathBuf(path.into_system()?))
Expand All @@ -33,6 +36,12 @@ impl AnchoredSystemPathBuf {
Ok(AnchoredSystemPathBuf(stripped_path))
}

pub fn from_raw<P: AsRef<Path>>(raw: P) -> Result<Self, PathError> {
let system_path = raw.as_ref();
let system_path = system_path.into_system()?;
Ok(Self(system_path))
}

pub fn as_path(&self) -> &Path {
self.0.as_path()
}
Expand All @@ -42,6 +51,24 @@ impl AnchoredSystemPathBuf {
.to_str()
.ok_or_else(|| PathValidationError::InvalidUnicode(self.0.clone()).into())
}

pub fn to_unix(&self) -> Result<RelativeUnixPathBuf, PathError> {
#[cfg(unix)]
{
use std::os::unix::ffi::OsStrExt;
let bytes = self.0.as_os_str().as_bytes();
return RelativeUnixPathBuf::new(bytes);
}
#[cfg(not(unix))]
{
use crate::IntoUnix;
let unix_buf = self.0.as_path().into_unix()?;
let unix_str = unix_buf
.to_str()
.ok_or_else(|| PathValidationError::InvalidUnicode(unix_buf.clone()))?;
return RelativeUnixPathBuf::new(unix_str.as_bytes());
}
}
}

impl From<AnchoredSystemPathBuf> for PathBuf {
Expand Down
15 changes: 13 additions & 2 deletions crates/turbopath/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@ mod relative_unix_path_buf;

use std::{
io,
path::{Path, PathBuf},
path::{Path, PathBuf, StripPrefixError},
};

pub use absolute_system_path_buf::AbsoluteSystemPathBuf;
Expand All @@ -24,6 +24,10 @@ pub enum PathError {
PathValidationError(#[from] PathValidationError),
#[error("IO Error {0}")]
IO(#[from] io::Error),
#[error("Path prefix error: {0}")]
PrefixError(#[from] StripPrefixError),
#[error("Invalid UTF8: {0}")]
Utf8Error(#[from] bstr::Utf8Error),
}

impl PathError {
Expand All @@ -43,11 +47,18 @@ pub enum PathValidationError {
#[error("Path is not absolute: {0}")]
NotAbsolute(PathBuf),
#[error("Path is not relative: {0}")]
NotRelative(PathBuf),
NotRelative(String),
#[error("Path {0} is not parent of {1}")]
NotParent(String, String),
#[error("Path {0} is not a unix path")]
NotUnix(String),
#[error("{0} is not a prefix for {1}")]
PrefixError(String, String),
}

pub(crate) fn not_relative_error(bytes: &[u8]) -> PathValidationError {
let s = String::from_utf8_lossy(bytes).to_string();
PathValidationError::NotRelative(s)
}

trait IntoSystem {
Expand Down
3 changes: 2 additions & 1 deletion crates/turbopath/src/relative_system_path_buf.rs
Original file line number Diff line number Diff line change
Expand Up @@ -36,7 +36,8 @@ impl RelativeSystemPathBuf {
pub fn new(unchecked_path: impl Into<PathBuf>) -> Result<Self, PathValidationError> {
let unchecked_path = unchecked_path.into();
if unchecked_path.is_absolute() {
return Err(PathValidationError::NotRelative(unchecked_path));
let bad_path = unchecked_path.display().to_string();
return Err(PathValidationError::NotRelative(bad_path));
}

let system_path = unchecked_path.into_system()?;
Expand Down
41 changes: 32 additions & 9 deletions crates/turbopath/src/relative_unix_path.rs
Original file line number Diff line number Diff line change
@@ -1,25 +1,48 @@
use std::path::Path;
use std::path::PathBuf;

use crate::{IntoSystem, PathError, PathValidationError, RelativeSystemPathBuf};
use bstr::BStr;

use crate::{not_relative_error, PathError, RelativeSystemPathBuf};

#[repr(transparent)]
pub struct RelativeUnixPath {
inner: Path,
inner: BStr,
}

impl RelativeUnixPath {
pub fn new<P: AsRef<Path>>(value: &P) -> Result<&Self, PathError> {
pub fn new<P: AsRef<BStr>>(value: &P) -> Result<&Self, PathError> {
let path = value.as_ref();
if path.is_absolute() {
return Err(PathValidationError::NotRelative(path.to_owned()).into());
if path[0] == b'/' {
return Err(not_relative_error(path).into());
}
// copied from stdlib path.rs: relies on the representation of
// RelativeUnixPath being just a Path, the same way Path relies on
// just being an OsStr
Ok(unsafe { &*(path as *const Path as *const Self) })
Ok(unsafe { &*(path as *const BStr as *const Self) })
}

pub fn to_system_path(&self) -> Result<RelativeSystemPathBuf, PathError> {
let system_path = self.inner.into_system()?;
Ok(RelativeSystemPathBuf::new_unchecked(system_path))
#[cfg(unix)]
{
// On unix, unix paths are already system paths. Copy the bytes
// but skip validation.
use std::{ffi::OsString, os::unix::prelude::OsStringExt};
let path = PathBuf::from(OsString::from_vec(self.inner.to_vec()));
Ok(RelativeSystemPathBuf::new_unchecked(path))
}

#[cfg(windows)]
{
let system_path_bytes = self
.inner
.iter()
.map(|byte| if *byte == b'/' { b'\\' } else { *byte })
.collect::<Vec<u8>>();
// Is this safe to do? We think we have utf8 bytes or bytes that roundtrip
// through utf8
let system_path_string = unsafe { String::from_utf8_unchecked(system_path_bytes) };
let system_path_buf = PathBuf::from(system_path_string);
Ok(RelativeSystemPathBuf::new_unchecked(system_path_buf))
}
}
}

0 comments on commit cb9e8d2

Please sign in to comment.