Skip to content

Commit

Permalink
Remove anyhow and commandbase from package_manager
Browse files Browse the repository at this point in the history
  • Loading branch information
Greg Soltis authored and Greg Soltis committed Jun 3, 2023
1 parent 678d775 commit e747323
Show file tree
Hide file tree
Showing 6 changed files with 77 additions and 51 deletions.
25 changes: 25 additions & 0 deletions Cargo.lock

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

1 change: 1 addition & 0 deletions crates/turborepo-lib/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -85,6 +85,7 @@ url = "2.3.1"
const_format = "0.2.30"
go-parse-duration = "0.1.1"
is-terminal = "0.4.7"
lazy-regex = "2.5.0"
node-semver = "2.1.0"
num_cpus = "1.15.0"
owo-colors.workspace = true
Expand Down
71 changes: 37 additions & 34 deletions crates/turborepo-lib/src/package_manager/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -6,11 +6,10 @@ use std::{
backtrace,
fmt::{self, Display},
fs,
path::PathBuf,
};

use anyhow::{anyhow, Result as AnyhowResult};
use itertools::{Either, Itertools};
use lazy_regex::{lazy_regex, Lazy};
use regex::Regex;
use serde::{Deserialize, Serialize};
use thiserror::Error;
Expand Down Expand Up @@ -129,14 +128,15 @@ impl Globs {
})
}

pub fn test(&self, root: &AbsoluteSystemPath, target: PathBuf) -> AnyhowResult<bool> {
let search_value = target
.strip_prefix(root)?
.to_str()
.ok_or_else(|| anyhow!("The relative path is not UTF8."))?;
pub fn test(
&self,
root: &AbsoluteSystemPath,
target: &AbsoluteSystemPath,
) -> Result<bool, Error> {
let search_value = root.anchor(target)?;

let includes = self.inclusions.is_match(search_value);
let excludes = self.exclusions.is_match(search_value);
let includes = self.inclusions.is_match(&search_value);
let excludes = self.exclusions.is_match(&search_value);

Ok(includes && !excludes)
}
Expand All @@ -151,6 +151,8 @@ pub struct MissingWorkspaceError {
pub struct NoPackageManager;

impl NoPackageManager {
// TODO: determine how to thread through user-friendly error message and apply
// our UI
pub fn ui_display(&self, ui: &UI) -> String {
let url =
ui.apply(UNDERLINE.apply_to("https://nodejs.org/api/packages.html#packagemanager"));
Expand Down Expand Up @@ -223,8 +225,17 @@ pub enum Error {
Which(#[from] which::Error),
#[error("invalid utf8: {0}")]
Utf8Error(#[from] std::string::FromUtf8Error),
#[error(transparent)]
Path(#[from] turbopath::PathError),
#[error(
"We could not parse the packageManager field in package.json, expected: {0}, received: {1}"
)]
InvalidPackageManager(String, String),
}

static PACKAGE_MANAGER_PATTERN: Lazy<Regex> =
lazy_regex!(r"(?P<manager>npm|pnpm|yarn)@(?P<version>\d+\.\d+\.\d+(-.+)?)");

impl PackageManager {
/// Returns the set of globs for the workspace.
pub fn get_workspace_globs(
Expand Down Expand Up @@ -283,7 +294,7 @@ impl PackageManager {
}

// Attempts to read the package manager from the package.json
fn read_package_manager(pkg: &PackageJson) -> AnyhowResult<Option<Self>> {
fn read_package_manager(pkg: &PackageJson) -> Result<Option<Self>, Error> {
let Some(package_manager) = &pkg.package_manager else {
return Ok(None)
};
Expand Down Expand Up @@ -319,19 +330,15 @@ impl PackageManager {
}
}

pub(crate) fn parse_package_manager_string(manager: &str) -> AnyhowResult<(&str, &str)> {
let package_manager_pattern =
Regex::new(r"(?P<manager>npm|pnpm|yarn)@(?P<version>\d+\.\d+\.\d+(-.+)?)")?;
if let Some(captures) = package_manager_pattern.captures(manager) {
pub(crate) fn parse_package_manager_string(manager: &str) -> Result<(&str, &str), Error> {
if let Some(captures) = PACKAGE_MANAGER_PATTERN.captures(manager) {
let manager = captures.name("manager").unwrap().as_str();
let version = captures.name("version").unwrap().as_str();
Ok((manager, version))
} else {
Err(anyhow!(
"We could not parse packageManager field in package.json, expected: {}, received: \
{}",
package_manager_pattern,
manager
Err(Error::InvalidPackageManager(
PACKAGE_MANAGER_PATTERN.to_string(),
manager.to_string(),
))
}
}
Expand Down Expand Up @@ -435,7 +442,7 @@ mod tests {
}

#[test]
fn test_read_package_manager() -> AnyhowResult<()> {
fn test_read_package_manager() -> Result<(), Error> {
let mut package_json = PackageJson {
package_manager: Some("npm@8.19.4".to_string()),
};
Expand All @@ -462,7 +469,7 @@ mod tests {
}

#[test]
fn test_detect_multiple_package_managers() -> AnyhowResult<()> {
fn test_detect_multiple_package_managers() -> Result<(), Error> {
let repo_root = tempdir()?;
let repo_root_path = AbsoluteSystemPathBuf::new(repo_root.path())?;

Expand All @@ -471,8 +478,7 @@ mod tests {
let pnpm_lock_path = repo_root.path().join(pnpm::LOCKFILE);
File::create(pnpm_lock_path)?;

let error =
PackageManager::detect_package_manager(repo_root_path.as_absolute_path()).unwrap_err();
let error = PackageManager::detect_package_manager(&repo_root_path).unwrap_err();
assert_eq!(
error.to_string(),
"We detected multiple package managers in your repository: pnpm, npm. Please remove \
Expand All @@ -481,8 +487,7 @@ mod tests {

fs::remove_file(&package_lock_json_path)?;

let package_manager =
PackageManager::detect_package_manager(repo_root_path.as_absolute_path())?;
let package_manager = PackageManager::detect_package_manager(&repo_root_path)?;
assert_eq!(package_manager, PackageManager::Pnpm);

Ok(())
Expand All @@ -497,9 +502,7 @@ mod tests {
.unwrap();
let with_yarn = repo_root.join_components(&["examples", "with-yarn"]);
let package_manager = PackageManager::Npm;
let globs = package_manager
.get_workspace_globs(&with_yarn)
.unwrap();
let globs = package_manager.get_workspace_globs(&with_yarn).unwrap();

let expected = Globs::new(vec!["apps/*", "packages/*"], vec![]).unwrap();
assert_eq!(globs, expected);
Expand All @@ -510,8 +513,8 @@ mod tests {
struct TestCase {
globs: Globs,
root: AbsoluteSystemPathBuf,
target: PathBuf,
output: AnyhowResult<bool>,
target: AbsoluteSystemPathBuf,
output: Result<bool, Error>,
}

#[cfg(unix)]
Expand All @@ -520,9 +523,9 @@ mod tests {
let root = AbsoluteSystemPathBuf::new("C:\\a\\b\\c").unwrap();

#[cfg(unix)]
let target = PathBuf::from("/a/b/c/d/e/f");
let target = AbsoluteSystemPathBuf::new("/a/b/c/d/e/f").unwrap();
#[cfg(windows)]
let target = PathBuf::from("C:\\a\\b\\c\\d\\e\\f");
let target = AbsoluteSystemPathBuf::new("C:\\a\\b\\c\\d\\e\\f").unwrap();

let tests = [TestCase {
globs: Globs::new(vec!["d/**".to_string()], vec![]).unwrap(),
Expand All @@ -532,15 +535,15 @@ mod tests {
}];

for test in tests {
match test.globs.test(&test.root, test.target) {
match test.globs.test(&test.root, &test.target) {
Ok(value) => assert_eq!(value, test.output.unwrap()),
Err(value) => assert_eq!(value.to_string(), test.output.unwrap_err().to_string()),
};
}
}

#[test]
fn test_nested_workspace_globs() -> AnyhowResult<()> {
fn test_nested_workspace_globs() -> Result<(), Error> {
let top_level: PackageJsonWorkspaces =
serde_json::from_str("{ \"workspaces\": [\"packages/**\"]}")?;
assert_eq!(top_level.workspaces.as_ref(), vec!["packages/**"]);
Expand Down
23 changes: 6 additions & 17 deletions crates/turborepo-lib/src/shim.rs
Original file line number Diff line number Diff line change
Expand Up @@ -445,11 +445,9 @@ impl InferInfo {
info.has_turbo_json
}

pub fn is_workspace_root_of(&self, target_path: &Path) -> bool {
pub fn is_workspace_root_of(&self, target_path: &AbsoluteSystemPath) -> bool {
match &self.workspace_globs {
Some(globs) => globs
.test(&self.path, target_path.to_path_buf())
.unwrap_or(false),
Some(globs) => globs.test(&self.path, target_path).unwrap_or(false),
None => false,
}
}
Expand All @@ -469,19 +467,10 @@ impl RepoState {
return None;
}

// FIXME: This should be based upon detecting the pacakage manager.
// However, we don't have that functionality implemented in Rust yet.
// PackageManager::detect(path).get_workspace_globs().unwrap_or(None)
let workspace_globs = PackageManager::get_package_manager(reference_dir, None)
.and_then(|mgr| mgr.get_workspace_globs(reference_dir))
// FIXME: We should save this package manager that we detected
let workspace_globs = PackageManager::get_package_manager(path, None)
.and_then(|mgr| mgr.get_workspace_globs(path))
.ok();
// let workspace_globs = PackageManager::Pnpm
// .get_workspace_globs(path)
// .unwrap_or_else(|_| {
// PackageManager::Npm
// .get_workspace_globs(path)
// .unwrap_or(None)
// });

Some(InferInfo {
path: path.to_owned(),
Expand Down Expand Up @@ -558,7 +547,7 @@ impl RepoState {
// Failing that we just choose the closest.
} else {
for ancestor_infer in check_roots {
if ancestor_infer.is_workspace_root_of(current.path.as_path()) {
if ancestor_infer.is_workspace_root_of(&current.path) {
let local_turbo_state =
LocalTurboState::infer(ancestor_infer.path.as_path());
return Ok(Self {
Expand Down
1 change: 1 addition & 0 deletions crates/turborepo-paths/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,7 @@ path-slash = "0.2.1"
# TODO: Make this a crate feature
serde = { workspace = true }
thiserror = { workspace = true }
wax = { workspace = true }

[dev-dependencies]
anyhow = { workspace = true }
7 changes: 7 additions & 0 deletions crates/turborepo-paths/src/anchored_system_path_buf.rs
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,13 @@ impl TryFrom<&Path> for AnchoredSystemPathBuf {
}
}

// TODO: perhaps we ought to be converting to a unix path?
impl<'a> Into<wax::CandidatePath<'a>> for &'a AnchoredSystemPathBuf {
fn into(self) -> wax::CandidatePath<'a> {
self.as_path().into()
}
}

impl AnchoredSystemPathBuf {
pub fn new(
root: impl AsRef<AbsoluteSystemPath>,
Expand Down

0 comments on commit e747323

Please sign in to comment.