Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

fix: fix recursive version inference #28

Merged
merged 3 commits into from
Aug 7, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
5 changes: 5 additions & 0 deletions .changeset/curly-maps-fail.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
---
"pactup": patch
---

Fix os arch report and support package.json version lookup
2 changes: 0 additions & 2 deletions .github/workflows/changeset.yml
Original file line number Diff line number Diff line change
Expand Up @@ -16,8 +16,6 @@ jobs:
- uses: actions/checkout@v4
- name: Install pnpm
uses: pnpm/action-setup@v4
with:
version: 9
- name: Use Node.js ${{ matrix.node-version }}
uses: actions/setup-node@v4
with:
Expand Down
2 changes: 1 addition & 1 deletion .pact-version
Original file line number Diff line number Diff line change
@@ -1 +1 @@
4.12
4.13
1 change: 1 addition & 0 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,7 @@
"kadena-community",
"smart-contracts"
],

"homepage": "https://github.com/kadena-community/pactup",
"bugs": "https://github.com/kadena-community/pactup/issues",
"bin": "bin/pactup",
Expand Down
17 changes: 17 additions & 0 deletions src/config.rs
Original file line number Diff line number Diff line change
Expand Up @@ -78,6 +78,18 @@ pub struct PactupConfig {
)]
version_file_strategy: VersionFileStrategy,

/// Resolve `engines.pact` field in `package.json` whenever a `.pact-version` or `.pactrc` file is not present.
/// Experimental: This feature is subject to change.
/// Note: `engines.pact` can be any semver range, with the latest satisfying version being resolved.
#[clap(
long,
env = "PACTUP_RESOLVE_ENGINES",
global = true,
hide_env_values = true,
verbatim_doc_comment
)]
resolve_engines: bool,

#[clap(skip)]
directories: Directories,
}
Expand All @@ -93,6 +105,7 @@ impl Default for PactupConfig {
arch: Arch::default(),
version_file_strategy: VersionFileStrategy::default(),
directories: Directories::default(),
resolve_engines: false,
}
}
}
Expand All @@ -102,6 +115,10 @@ impl PactupConfig {
&self.version_file_strategy
}

pub fn resolve_engines(&self) -> bool {
self.resolve_engines
}

pub fn multishell_path(&self) -> Option<&std::path::Path> {
match &self.multishell_path {
None => None,
Expand Down
8 changes: 6 additions & 2 deletions src/default_version.rs
Original file line number Diff line number Diff line change
@@ -1,12 +1,16 @@
use log::info;

use crate::config::PactupConfig;
use crate::version::Version;
use std::str::FromStr;

pub fn find_default_version(config: &PactupConfig) -> Option<Version> {
if let Ok(version_path) = config.default_version_dir().canonicalize() {
let file_name = version_path.parent()?.file_name()?;
let file_name = version_path.file_name()?;
info!("Found default version: {:?}", file_name);
Version::from_str(file_name.to_str()?).ok()?.into()
} else {
Some(Version::Alias("default".into()))
info!("No default version found");
None
}
}
1 change: 1 addition & 0 deletions src/main.rs
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,7 @@ mod downloader;
mod fs;
mod http;
mod installed_versions;
mod package_json;
mod path_ext;
mod progress;
mod remote_pact_index;
Expand Down
20 changes: 20 additions & 0 deletions src/package_json.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
use serde::Deserialize;

#[derive(Debug, Deserialize, Default)]
struct EnginesField {
pact: Option<node_semver::Range>,
}

#[derive(Debug, Deserialize, Default)]
pub struct PackageJson {
engines: Option<EnginesField>,
}

impl PackageJson {
pub fn pact_range(&self) -> Option<&node_semver::Range> {
self
.engines
.as_ref()
.and_then(|engines| engines.pact.as_ref())
}
}
18 changes: 9 additions & 9 deletions src/user_version_reader.rs
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,7 @@ impl UserVersionReader {
pub fn into_user_version(self, config: &PactupConfig) -> Option<UserVersion> {
match self {
Self::Direct(uv) => Some(uv),
Self::Path(pathbuf) if pathbuf.is_file() => get_user_version_for_file(pathbuf),
Self::Path(pathbuf) if pathbuf.is_file() => get_user_version_for_file(pathbuf, config),
Self::Path(pathbuf) => get_user_version_for_directory(pathbuf, config),
}
}
Expand Down Expand Up @@ -45,36 +45,36 @@ mod tests {
#[test]
fn test_file_pathbuf_to_version() {
let mut file = NamedTempFile::new().unwrap();
write!(file, "14").unwrap();
write!(file, "4").unwrap();
let pathbuf = file.path().to_path_buf();

let user_version = UserVersionReader::Path(pathbuf).into_user_version(&PactupConfig::default());
assert_eq!(user_version, Some(UserVersion::OnlyMajor(14)));
assert_eq!(user_version, Some(UserVersion::OnlyMajor(4)));
}

#[test]
fn test_directory_pathbuf_to_version() {
let directory = TempDir::new().unwrap();
let pact_version_path = directory.path().join(".pact-version");
std::fs::write(pact_version_path, "14").unwrap();
std::fs::write(pact_version_path, "4").unwrap();
let pathbuf = directory.path().to_path_buf();

let user_version = UserVersionReader::Path(pathbuf).into_user_version(&PactupConfig::default());
assert_eq!(user_version, Some(UserVersion::OnlyMajor(14)));
assert_eq!(user_version, Some(UserVersion::OnlyMajor(4)));
}

#[test]
fn test_direct_to_version() {
let user_version = UserVersionReader::Direct(UserVersion::OnlyMajor(14))
let user_version = UserVersionReader::Direct(UserVersion::OnlyMajor(4))
.into_user_version(&PactupConfig::default());
assert_eq!(user_version, Some(UserVersion::OnlyMajor(14)));
assert_eq!(user_version, Some(UserVersion::OnlyMajor(4)));
}

#[test]
fn test_from_str_directory() {
let directory = TempDir::new().unwrap();
let pact_version_path = directory.path().join(".pact-version");
std::fs::write(pact_version_path, "14").unwrap();
std::fs::write(pact_version_path, "4").unwrap();
let pathbuf = directory.path().to_path_buf();

let user_version = UserVersionReader::from_str(pathbuf.to_str().unwrap());
Expand All @@ -84,7 +84,7 @@ mod tests {
#[test]
fn test_from_str_file() {
let mut file = NamedTempFile::new().unwrap();
write!(file, "14").unwrap();
write!(file, "4").unwrap();
let pathbuf = file.path().to_path_buf();

let user_version = UserVersionReader::from_str(pathbuf.to_str().unwrap());
Expand Down
54 changes: 41 additions & 13 deletions src/version_files.rs
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
use crate::config::PactupConfig;
use crate::default_version;
use crate::package_json::PackageJson;
use crate::user_version::UserVersion;
use crate::version_file_strategy::VersionFileStrategy;
use encoding_rs_io::DecodeReaderBytes;
Expand All @@ -15,30 +16,36 @@ pub fn get_user_version_for_directory(
config: &PactupConfig,
) -> Option<UserVersion> {
match config.version_file_strategy() {
VersionFileStrategy::Local => get_user_version_for_single_directory(path),
VersionFileStrategy::Recursive => {
get_user_version_for_directory_recursive(path).or_else(|| {
VersionFileStrategy::Local => get_user_version_for_single_directory(path, config),
VersionFileStrategy::Recursive => get_user_version_for_directory_recursive(path, config)
.or_else(|| {
info!("Did not find anything recursively. Falling back to default alias.");
default_version::find_default_version(config).map(UserVersion::Full)
})
}
}),
}
}

fn get_user_version_for_directory_recursive(path: impl AsRef<Path>) -> Option<UserVersion> {
fn get_user_version_for_directory_recursive(
path: impl AsRef<Path>,
config: &PactupConfig,
) -> Option<UserVersion> {
let mut current_path = Some(path.as_ref());

while let Some(child_path) = current_path {
if let Some(version) = get_user_version_for_single_directory(child_path) {
if let Some(version) = get_user_version_for_single_directory(child_path, config) {
return Some(version);
}

current_path = child_path.parent();
}

None
}

fn get_user_version_for_single_directory(path: impl AsRef<Path>) -> Option<UserVersion> {
fn get_user_version_for_single_directory(
path: impl AsRef<Path>,
config: &PactupConfig,
) -> Option<UserVersion> {
let path = path.as_ref();

for path_part in &PATH_PARTS {
Expand All @@ -48,30 +55,51 @@ fn get_user_version_for_single_directory(path: impl AsRef<Path>) -> Option<UserV
new_path.display(),
new_path.exists()
);
if let Some(version) = get_user_version_for_file(&new_path) {
if let Some(version) = get_user_version_for_file(&new_path, config) {
return Some(version);
}
}

None
}

pub fn get_user_version_for_file(path: impl AsRef<Path>) -> Option<UserVersion> {
pub fn get_user_version_for_file(
path: impl AsRef<Path>,
config: &PactupConfig,
) -> Option<UserVersion> {
let is_pkg_json = match path.as_ref().file_name() {
Some(name) => name == "package.json",
None => false,
};
let file = std::fs::File::open(path).ok()?;
let file = {
let mut reader = DecodeReaderBytes::new(file);
let mut version = String::new();
reader.read_to_string(&mut version).map(|_| version)
};

match file {
Err(err) => {
match (file, is_pkg_json, config.resolve_engines()) {
(_, true, false) => None,
(Err(err), _, _) => {
info!("Can't read file: {}", err);
None
}
Ok(version) => {
(Ok(version), false, _) => {
info!("Found string {:?} in version file", version);
UserVersion::from_str(version.trim()).ok()
}
(Ok(pkg_json), true, true) => {
let pkg_json = serde_json::from_str::<PackageJson>(&pkg_json).ok();
let range: Option<node_semver::Range> =
pkg_json.as_ref().and_then(PackageJson::pact_range).cloned();

if let Some(range) = range {
info!("Found package.json with {:?} in engines.pact field", range);
Some(UserVersion::SemverRange(range))
} else {
info!("No engines.pact range found in package.json");
None
}
}
}
}