mirror of
https://github.com/pesde-pkg/pesde.git
synced 2024-12-12 11:00:36 +00:00
feat: support manifest-less repos & running local package bin export
This commit is contained in:
parent
8dfdc6dfa8
commit
de35d5906a
8 changed files with 235 additions and 113 deletions
|
@ -10,8 +10,8 @@ repository = "https://github.com/daimond113/pesde"
|
|||
include = ["src/**/*", "Cargo.toml", "Cargo.lock", "README.md", "LICENSE", "CHANGELOG.md"]
|
||||
|
||||
[features]
|
||||
bin = ["clap", "directories", "keyring", "anyhow", "ignore", "pretty_env_logger", "serde_json", "reqwest/json", "reqwest/multipart", "lune", "futures-executor", "indicatif", "auth-git2", "indicatif-log-bridge", "inquire", "once_cell"]
|
||||
wally = ["toml", "zip", "serde_json"]
|
||||
bin = ["clap", "directories", "keyring", "anyhow", "ignore", "pretty_env_logger", "reqwest/json", "reqwest/multipart", "lune", "futures-executor", "indicatif", "auth-git2", "indicatif-log-bridge", "inquire", "once_cell"]
|
||||
wally = ["toml", "zip"]
|
||||
|
||||
[[bin]]
|
||||
name = "pesde"
|
||||
|
@ -21,6 +21,7 @@ required-features = ["bin"]
|
|||
[dependencies]
|
||||
serde = { version = "1.0.197", features = ["derive"] }
|
||||
serde_yaml = "0.9.33"
|
||||
serde_json = "1.0.114"
|
||||
git2 = "0.18.3"
|
||||
semver = { version = "1.0.22", features = ["serde"] }
|
||||
reqwest = { version = "0.12.1", default-features = false, features = ["rustls-tls", "blocking"] }
|
||||
|
@ -47,7 +48,6 @@ keyring = { version = "2.3.2", optional = true }
|
|||
anyhow = { version = "1.0.81", optional = true }
|
||||
ignore = { version = "0.4.22", optional = true }
|
||||
pretty_env_logger = { version = "0.5.0", optional = true }
|
||||
serde_json = { version = "1.0.114", optional = true }
|
||||
lune = { version = "0.8.2", optional = true }
|
||||
futures-executor = { version = "0.3.30", optional = true }
|
||||
indicatif = { version = "0.17.8", optional = true }
|
||||
|
|
|
@ -90,7 +90,7 @@ pub enum Command {
|
|||
Run {
|
||||
/// The package to run
|
||||
#[clap(value_name = "PACKAGE")]
|
||||
package: StandardPackageName,
|
||||
package: Option<StandardPackageName>,
|
||||
|
||||
/// The arguments to pass to the package
|
||||
#[clap(last = true)]
|
||||
|
|
|
@ -2,7 +2,7 @@ use cfg_if::cfg_if;
|
|||
use chrono::Utc;
|
||||
use std::{
|
||||
collections::{BTreeMap, HashMap},
|
||||
fs::{create_dir_all, read, remove_dir_all, write, File},
|
||||
fs::{create_dir_all, read, remove_dir_all, write},
|
||||
str::FromStr,
|
||||
time::Duration,
|
||||
};
|
||||
|
@ -105,7 +105,7 @@ pub fn root_command(cmd: Command) -> anyhow::Result<()> {
|
|||
|
||||
multithreaded_bar(
|
||||
download_job,
|
||||
lockfile.children.len() as u64,
|
||||
lockfile.children.values().map(|v| v.len() as u64).sum(),
|
||||
"Downloading packages".to_string(),
|
||||
)?;
|
||||
|
||||
|
@ -144,36 +144,47 @@ pub fn root_command(cmd: Command) -> anyhow::Result<()> {
|
|||
)?;
|
||||
}
|
||||
Command::Run { package, args } => {
|
||||
let lockfile = project
|
||||
.lockfile()?
|
||||
.ok_or(anyhow::anyhow!("lockfile not found"))?;
|
||||
let bin_path = if let Some(package) = package {
|
||||
let lockfile = project
|
||||
.lockfile()?
|
||||
.ok_or(anyhow::anyhow!("lockfile not found"))?;
|
||||
|
||||
let resolved_pkg = lockfile
|
||||
.children
|
||||
.get(&package.into())
|
||||
.and_then(|versions| {
|
||||
versions
|
||||
.values()
|
||||
.find(|pkg_ref| lockfile.root_specifier(pkg_ref).is_some())
|
||||
})
|
||||
.ok_or(anyhow::anyhow!(
|
||||
"package not found in lockfile (or isn't root)"
|
||||
))?;
|
||||
let resolved_pkg = lockfile
|
||||
.children
|
||||
.get(&package.clone().into())
|
||||
.and_then(|versions| {
|
||||
versions
|
||||
.values()
|
||||
.find(|pkg_ref| lockfile.root_specifier(pkg_ref).is_some())
|
||||
})
|
||||
.ok_or(anyhow::anyhow!(
|
||||
"package not found in lockfile (or isn't root)"
|
||||
))?;
|
||||
|
||||
let pkg_path = resolved_pkg.directory(project.path()).1;
|
||||
let manifest = Manifest::from_path(&pkg_path)?;
|
||||
let pkg_path = resolved_pkg.directory(project.path()).1;
|
||||
let manifest = Manifest::from_path(&pkg_path)?;
|
||||
|
||||
let Some(bin_path) = manifest.exports.bin else {
|
||||
anyhow::bail!("no bin found in package");
|
||||
let Some(bin_path) = manifest.exports.bin else {
|
||||
anyhow::bail!("no bin found in package");
|
||||
};
|
||||
|
||||
bin_path.to_path(pkg_path)
|
||||
} else {
|
||||
let manifest = project.manifest();
|
||||
let bin_path = manifest
|
||||
.exports
|
||||
.bin
|
||||
.clone()
|
||||
.ok_or(anyhow::anyhow!("no bin found in package"))?;
|
||||
|
||||
bin_path.to_path(project.path())
|
||||
};
|
||||
|
||||
let absolute_bin_path = bin_path.to_path(pkg_path);
|
||||
|
||||
let mut runtime = Runtime::new().with_args(args);
|
||||
|
||||
block_on(runtime.run(
|
||||
resolved_pkg.pkg_ref.name().to_string(),
|
||||
&read(absolute_bin_path)?,
|
||||
bin_path.with_extension("").display().to_string(),
|
||||
&read(bin_path)?,
|
||||
))?;
|
||||
}
|
||||
Command::Search { query } => {
|
||||
|
@ -347,9 +358,7 @@ pub fn root_command(cmd: Command) -> anyhow::Result<()> {
|
|||
);
|
||||
}
|
||||
Command::Init => {
|
||||
let manifest_path = CWD.join(MANIFEST_FILE_NAME);
|
||||
|
||||
if manifest_path.exists() {
|
||||
if CWD.join(MANIFEST_FILE_NAME).exists() {
|
||||
anyhow::bail!("manifest already exists");
|
||||
}
|
||||
|
||||
|
@ -427,7 +436,7 @@ pub fn root_command(cmd: Command) -> anyhow::Result<()> {
|
|||
repository: none_if_empty!(repository),
|
||||
};
|
||||
|
||||
serde_yaml::to_writer(File::create(manifest_path)?, &manifest)?;
|
||||
manifest.write(CWD.to_path_buf())?;
|
||||
}
|
||||
Command::Add {
|
||||
package,
|
||||
|
@ -484,10 +493,7 @@ pub fn root_command(cmd: Command) -> anyhow::Result<()> {
|
|||
insert_into(&mut manifest.dependencies, specifier, package.0.clone());
|
||||
}
|
||||
|
||||
serde_yaml::to_writer(
|
||||
File::create(project.path().join(MANIFEST_FILE_NAME))?,
|
||||
&manifest,
|
||||
)?;
|
||||
manifest.write(CWD.to_path_buf())?
|
||||
}
|
||||
Command::Remove { package } => {
|
||||
let mut manifest = project.manifest().clone();
|
||||
|
@ -520,10 +526,7 @@ pub fn root_command(cmd: Command) -> anyhow::Result<()> {
|
|||
});
|
||||
}
|
||||
|
||||
serde_yaml::to_writer(
|
||||
File::create(project.path().join(MANIFEST_FILE_NAME))?,
|
||||
&manifest,
|
||||
)?;
|
||||
manifest.write(project.path())?
|
||||
}
|
||||
Command::Outdated => {
|
||||
let project = Lazy::force_mut(&mut project);
|
||||
|
|
|
@ -1,4 +1,9 @@
|
|||
use std::{fs::create_dir_all, path::Path, sync::Arc};
|
||||
use std::{
|
||||
fs::create_dir_all,
|
||||
hash::{DefaultHasher, Hash, Hasher},
|
||||
path::Path,
|
||||
sync::Arc,
|
||||
};
|
||||
|
||||
use git2::{build::RepoBuilder, Repository};
|
||||
use log::{debug, error, warn};
|
||||
|
@ -9,7 +14,7 @@ use url::Url;
|
|||
|
||||
use crate::{
|
||||
index::{remote_callbacks, CredentialsFn},
|
||||
manifest::{Manifest, ManifestConvertError, Realm},
|
||||
manifest::{update_sync_tool_files, Manifest, ManifestConvertError, Realm},
|
||||
package_name::StandardPackageName,
|
||||
project::{get_index, Indices},
|
||||
};
|
||||
|
@ -60,10 +65,87 @@ pub enum GitDownloadError {
|
|||
#[error("invalid URL")]
|
||||
InvalidUrl(#[from] url::ParseError),
|
||||
|
||||
/// An error that occurred because the manifest is not present in the git repository, and the wally feature is not enabled
|
||||
#[cfg(not(feature = "wally"))]
|
||||
#[error("wally feature is not enabled, but the manifest is not present in the git repository")]
|
||||
ManifestNotPresent,
|
||||
/// An error that occurred while resolving a git dependency's manifest
|
||||
#[error("error resolving git dependency manifest")]
|
||||
Resolve(#[from] GitManifestResolveError),
|
||||
}
|
||||
|
||||
/// An error that occurred while resolving a git dependency's manifest
|
||||
#[derive(Debug, Error)]
|
||||
pub enum GitManifestResolveError {
|
||||
/// An error that occurred because the scope and name could not be extracted from the URL
|
||||
#[error("could not extract scope and name from URL: {0}")]
|
||||
ScopeAndNameFromUrl(Url),
|
||||
|
||||
/// An error that occurred because the package name is invalid
|
||||
#[error("invalid package name")]
|
||||
InvalidPackageName(#[from] crate::package_name::StandardPackageNameValidationError),
|
||||
|
||||
/// An error that occurred while interacting with the file system
|
||||
#[error("error interacting with the file system")]
|
||||
Io(#[from] std::io::Error),
|
||||
}
|
||||
|
||||
fn to_snake_case(s: &str) -> String {
|
||||
s.chars()
|
||||
.enumerate()
|
||||
.map(|(i, c)| {
|
||||
if c.is_uppercase() {
|
||||
format!("{}{}", if i == 0 { "" } else { "_" }, c.to_lowercase())
|
||||
} else if c == '-' {
|
||||
"_".to_string()
|
||||
} else {
|
||||
c.to_string()
|
||||
}
|
||||
})
|
||||
.collect()
|
||||
}
|
||||
|
||||
pub(crate) fn manifest(path: &Path, url: &Url) -> Result<Manifest, GitManifestResolveError> {
|
||||
Manifest::from_path_or_convert(path).or_else(|_| {
|
||||
let (scope, name) = url
|
||||
.path_segments()
|
||||
.and_then(|mut s| {
|
||||
let scope = s.next();
|
||||
let name = s.next();
|
||||
|
||||
if let (Some(scope), Some(name)) = (scope, name) {
|
||||
Some((scope.to_string(), name.to_string()))
|
||||
} else {
|
||||
None
|
||||
}
|
||||
})
|
||||
.ok_or_else(|| GitManifestResolveError::ScopeAndNameFromUrl(url.clone()))?;
|
||||
|
||||
let manifest = Manifest {
|
||||
name: StandardPackageName::new(
|
||||
&to_snake_case(&scope),
|
||||
&to_snake_case(name.trim_end_matches(".git")),
|
||||
)?,
|
||||
version: Version::new(0, 1, 0),
|
||||
description: None,
|
||||
license: None,
|
||||
authors: None,
|
||||
repository: None,
|
||||
exports: Default::default(),
|
||||
path_style: Default::default(),
|
||||
private: true,
|
||||
realm: None,
|
||||
indices: Default::default(),
|
||||
#[cfg(feature = "wally")]
|
||||
sourcemap_generator: None,
|
||||
overrides: Default::default(),
|
||||
|
||||
dependencies: Default::default(),
|
||||
peer_dependencies: Default::default(),
|
||||
};
|
||||
|
||||
manifest.write(path).unwrap();
|
||||
|
||||
update_sync_tool_files(path, manifest.name.name().to_string())?;
|
||||
|
||||
Ok(manifest)
|
||||
})
|
||||
}
|
||||
|
||||
impl GitDependencySpecifier {
|
||||
|
@ -75,41 +157,22 @@ impl GitDependencySpecifier {
|
|||
debug!("resolving git dependency {}", self.repo);
|
||||
|
||||
// should also work with ssh urls
|
||||
let is_url = self.repo.contains(':');
|
||||
|
||||
let repo_name = if !is_url {
|
||||
self.repo.to_string()
|
||||
} else {
|
||||
let parts: Vec<&str> = self.repo.split('/').collect();
|
||||
format!(
|
||||
"{}/{}",
|
||||
parts[parts.len() - 2],
|
||||
parts[parts.len() - 1].trim_end_matches(".git")
|
||||
)
|
||||
};
|
||||
|
||||
if is_url {
|
||||
debug!("resolved git repository name to: {}", &repo_name);
|
||||
} else {
|
||||
debug!("assuming git repository is a name: {}", &repo_name);
|
||||
}
|
||||
|
||||
let repo_url = if !is_url {
|
||||
Url::parse(&format!("https://github.com/{}.git", &self.repo))
|
||||
} else {
|
||||
let repo_url = if self.repo.contains(':') {
|
||||
debug!("resolved git repository name to: {}", self.repo);
|
||||
Url::parse(&self.repo)
|
||||
} else {
|
||||
debug!("assuming git repository is a name: {}", self.repo);
|
||||
Url::parse(&format!("https://github.com/{}.git", &self.repo))
|
||||
}?;
|
||||
|
||||
if is_url {
|
||||
debug!("assuming git repository is a url: {}", &repo_url);
|
||||
} else {
|
||||
debug!("resolved git repository url to: {}", &repo_url);
|
||||
}
|
||||
debug!("resolved git repository url to: {}", &repo_url);
|
||||
|
||||
let dest = cache_dir
|
||||
.join("git")
|
||||
.join(repo_name.replace('/', "_"))
|
||||
.join(&self.rev);
|
||||
let mut hasher = DefaultHasher::new();
|
||||
repo_url.hash(&mut hasher);
|
||||
self.rev.hash(&mut hasher);
|
||||
let repo_hash = hasher.finish();
|
||||
|
||||
let dest = cache_dir.join("git").join(repo_hash.to_string());
|
||||
|
||||
let repo = if !dest.exists() {
|
||||
create_dir_all(&dest)?;
|
||||
|
@ -129,11 +192,7 @@ impl GitDependencySpecifier {
|
|||
|
||||
repo.reset(&obj, git2::ResetType::Hard, None)?;
|
||||
|
||||
Ok((
|
||||
Manifest::from_path_or_convert(dest)?,
|
||||
repo_url,
|
||||
obj.id().to_string(),
|
||||
))
|
||||
Ok((manifest(&dest, &repo_url)?, repo_url, obj.id().to_string()))
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -21,7 +21,7 @@ use crate::{
|
|||
resolution::RootLockfileNode,
|
||||
},
|
||||
index::{CredentialsFn, Index},
|
||||
manifest::{Manifest, Realm},
|
||||
manifest::{ManifestWriteError, Realm},
|
||||
multithread::MultithreadedJob,
|
||||
package_name::PackageName,
|
||||
project::{get_index, get_index_by_url, InstallProjectError, Project},
|
||||
|
@ -251,6 +251,10 @@ pub enum ConvertManifestsError {
|
|||
#[error("error converting the manifest")]
|
||||
Manifest(#[from] crate::manifest::ManifestConvertError),
|
||||
|
||||
/// An error that occurred while converting a git dependency's manifest
|
||||
#[error("error converting a git dependency's manifest")]
|
||||
Git(#[from] crate::dependencies::git::GitManifestResolveError),
|
||||
|
||||
/// An error that occurred while reading the sourcemap
|
||||
#[error("error reading the sourcemap")]
|
||||
Sourcemap(#[from] std::io::Error),
|
||||
|
@ -262,7 +266,7 @@ pub enum ConvertManifestsError {
|
|||
|
||||
/// An error that occurred while writing the manifest
|
||||
#[error("error writing the manifest")]
|
||||
Write(#[from] serde_yaml::Error),
|
||||
Write(#[from] ManifestWriteError),
|
||||
|
||||
/// A manifest is not present in a dependency, and the wally feature is not enabled
|
||||
#[cfg(not(feature = "wally"))]
|
||||
|
@ -338,7 +342,12 @@ impl Project {
|
|||
_ => continue,
|
||||
};
|
||||
|
||||
let mut manifest = Manifest::from_path_or_convert(&source)?;
|
||||
let mut manifest = match &resolved_package.pkg_ref {
|
||||
PackageRef::Git(git) => {
|
||||
crate::dependencies::git::manifest(&source, &git.repo_url)?
|
||||
}
|
||||
_ => crate::manifest::Manifest::from_path_or_convert(&source)?,
|
||||
};
|
||||
|
||||
generate_sourcemap(source.to_path_buf());
|
||||
|
||||
|
@ -359,10 +368,7 @@ impl Project {
|
|||
})
|
||||
.or_else(|| Some(relative_path::RelativePathBuf::from("true")));
|
||||
|
||||
serde_yaml::to_writer(
|
||||
&std::fs::File::create(&source.join(crate::MANIFEST_FILE_NAME))?,
|
||||
&manifest,
|
||||
)?;
|
||||
manifest.write(&source)?;
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -383,7 +389,12 @@ impl Project {
|
|||
_ => continue,
|
||||
};
|
||||
|
||||
if Manifest::from_path_or_convert(&source).is_err() {
|
||||
if match &resolved_package.pkg_ref {
|
||||
PackageRef::Git(git) => {
|
||||
crate::dependencies::git::manifest(&source, &git.repo_url).is_err()
|
||||
}
|
||||
_ => crate::manifest::Manifest::from_path_or_convert(&source).is_err(),
|
||||
} {
|
||||
return Err(ConvertManifestsError::ManifestNotPresent);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -17,7 +17,7 @@ use crate::{
|
|||
},
|
||||
index::{Index, IndexFileEntry, IndexPackageError},
|
||||
manifest::{DependencyType, Manifest, OverrideKey, Realm},
|
||||
package_name::PackageName,
|
||||
package_name::{PackageName, StandardPackageName},
|
||||
project::{get_index, get_index_by_url, Project, ReadLockfileError},
|
||||
DEV_PACKAGES_FOLDER, INDEX_FOLDER, PACKAGES_FOLDER, SERVER_PACKAGES_FOLDER,
|
||||
};
|
||||
|
@ -26,9 +26,12 @@ use crate::{
|
|||
pub type PackageMap<T> = BTreeMap<PackageName, BTreeMap<Version, T>>;
|
||||
|
||||
/// The root node of the dependency graph
|
||||
#[derive(Serialize, Deserialize, Debug, Clone, PartialEq, Eq, Hash, Default)]
|
||||
#[derive(Serialize, Deserialize, Debug, Clone, PartialEq, Eq, Hash)]
|
||||
#[serde(deny_unknown_fields)]
|
||||
pub struct RootLockfileNode {
|
||||
/// The name of the package
|
||||
pub name: StandardPackageName,
|
||||
|
||||
/// Dependency overrides
|
||||
#[serde(default, skip_serializing_if = "BTreeMap::is_empty")]
|
||||
pub overrides: BTreeMap<OverrideKey, DependencySpecifier>,
|
||||
|
@ -214,6 +217,10 @@ impl Manifest {
|
|||
project: &Project,
|
||||
) -> Result<BTreeMap<String, (DependencySpecifier, DependencyType)>, ResolveError> {
|
||||
Ok(if let Some(old_root) = project.lockfile()? {
|
||||
if self.name != old_root.name && locked {
|
||||
return Err(ResolveError::OutOfDateLockfile);
|
||||
}
|
||||
|
||||
if self.overrides != old_root.overrides {
|
||||
// TODO: resolve only the changed dependencies (will this be worth it?)
|
||||
debug!("overrides have changed, resolving all dependencies");
|
||||
|
@ -331,8 +338,10 @@ impl Manifest {
|
|||
debug!("resolving dependency graph for project {}", self.name);
|
||||
// try to reuse versions (according to semver specifiers) to decrease the amount of downloads and storage
|
||||
let mut root = RootLockfileNode {
|
||||
name: self.name.clone(),
|
||||
overrides: self.overrides.clone(),
|
||||
..Default::default()
|
||||
specifiers: Default::default(),
|
||||
children: Default::default(),
|
||||
};
|
||||
|
||||
let missing_dependencies = self.missing_dependencies(&mut root, locked, project)?;
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
use std::{collections::BTreeMap, fmt::Display, fs::read, str::FromStr};
|
||||
use std::{collections::BTreeMap, fmt::Display, fs::read, path::Path, str::FromStr};
|
||||
|
||||
use cfg_if::cfg_if;
|
||||
use relative_path::RelativePathBuf;
|
||||
|
@ -177,12 +177,13 @@ pub struct Manifest {
|
|||
#[serde(default)]
|
||||
pub private: bool,
|
||||
/// The realm of the package
|
||||
#[serde(default, skip_serializing_if = "Option::is_none")]
|
||||
pub realm: Option<Realm>,
|
||||
/// Indices of the package
|
||||
pub indices: BTreeMap<String, String>,
|
||||
/// The command to generate a `sourcemap.json`
|
||||
#[cfg(feature = "wally")]
|
||||
#[serde(default)]
|
||||
#[serde(default, skip_serializing_if = "Option::is_none")]
|
||||
pub sourcemap_generator: Option<String>,
|
||||
/// Dependency overrides
|
||||
#[serde(default, skip_serializing_if = "BTreeMap::is_empty")]
|
||||
|
@ -229,18 +230,9 @@ cfg_if! {
|
|||
#[error("error interacting with the file system")]
|
||||
Io(#[from] std::io::Error),
|
||||
|
||||
/// An error that occurred while making a package name from a string
|
||||
#[error("error making a package name from a string")]
|
||||
PackageName(
|
||||
#[from]
|
||||
crate::package_name::FromStrPackageNameParseError<
|
||||
crate::package_name::StandardPackageNameValidationError,
|
||||
>,
|
||||
),
|
||||
|
||||
/// An error that occurred while writing the manifest
|
||||
#[error("error writing the manifest")]
|
||||
ManifestWrite(#[from] serde_yaml::Error),
|
||||
ManifestWrite(#[from] crate::manifest::ManifestWriteError),
|
||||
|
||||
/// An error that occurred while parsing the dependencies
|
||||
#[error("error parsing the dependencies")]
|
||||
|
@ -252,6 +244,18 @@ cfg_if! {
|
|||
}
|
||||
}
|
||||
|
||||
/// An error that occurred while writing the manifest
|
||||
#[derive(Debug, Error)]
|
||||
pub enum ManifestWriteError {
|
||||
/// An error that occurred while interacting with the file system
|
||||
#[error("error interacting with the file system")]
|
||||
Io(#[from] std::io::Error),
|
||||
|
||||
/// An error that occurred while serializing the manifest
|
||||
#[error("error serializing manifest")]
|
||||
ManifestSer(#[from] serde_yaml::Error),
|
||||
}
|
||||
|
||||
/// The type of dependency
|
||||
#[derive(Serialize, Deserialize, Debug, Clone, Copy, PartialEq, Eq, Hash, Default)]
|
||||
#[serde(rename_all = "snake_case")]
|
||||
|
@ -263,6 +267,25 @@ pub enum DependencyType {
|
|||
Peer,
|
||||
}
|
||||
|
||||
pub(crate) fn update_sync_tool_files(project_path: &Path, name: String) -> std::io::Result<()> {
|
||||
if let Ok(file) = std::fs::File::open(project_path.join("default.project.json")) {
|
||||
let mut project: serde_json::Value = serde_json::from_reader(file)?;
|
||||
|
||||
if project["name"].as_str() == Some(&name) {
|
||||
return Ok(());
|
||||
}
|
||||
|
||||
project["name"] = serde_json::Value::String(name);
|
||||
|
||||
serde_json::to_writer_pretty(
|
||||
std::fs::File::create(project_path.join("default.project.json"))?,
|
||||
&project,
|
||||
)?;
|
||||
}
|
||||
|
||||
Ok(())
|
||||
}
|
||||
|
||||
impl Manifest {
|
||||
/// Reads a manifest from a path (if the path is a directory, it will look for the manifest file inside it, otherwise it will read the file directly)
|
||||
pub fn from_path<P: AsRef<std::path::Path>>(path: P) -> Result<Self, ManifestReadError> {
|
||||
|
@ -318,7 +341,7 @@ impl Manifest {
|
|||
}
|
||||
|
||||
let manifest = Self {
|
||||
name: wally_manifest.package.name.replace('-', "_").parse()?,
|
||||
name: wally_manifest.package.name.into(),
|
||||
version: wally_manifest.package.version,
|
||||
exports: Exports {
|
||||
lib: Some(RelativePathBuf::from("true")),
|
||||
|
@ -326,10 +349,7 @@ impl Manifest {
|
|||
},
|
||||
path_style: PathStyle::Roblox { place },
|
||||
private: wally_manifest.package.private.unwrap_or(false),
|
||||
realm: wally_manifest
|
||||
.package
|
||||
.realm
|
||||
.map(|r| r.parse().unwrap_or(Realm::Shared)),
|
||||
realm: wally_manifest.package.realm,
|
||||
indices: BTreeMap::from([(
|
||||
crate::project::DEFAULT_INDEX_NAME.to_string(),
|
||||
"".to_string(),
|
||||
|
@ -345,8 +365,9 @@ impl Manifest {
|
|||
repository: None,
|
||||
};
|
||||
|
||||
let manifest_path = dir_path.join(MANIFEST_FILE_NAME);
|
||||
serde_yaml::to_writer(std::fs::File::create(manifest_path)?, &manifest)?;
|
||||
manifest.write(&dir_path)?;
|
||||
|
||||
update_sync_tool_files(&dir_path, manifest.name.name().to_string())?;
|
||||
|
||||
Ok(manifest)
|
||||
})
|
||||
|
@ -382,4 +403,13 @@ impl Manifest {
|
|||
)
|
||||
.collect()
|
||||
}
|
||||
|
||||
/// Writes the manifest to a path
|
||||
pub fn write<P: AsRef<std::path::Path>>(&self, to: P) -> Result<(), ManifestWriteError> {
|
||||
let manifest_path = to.as_ref().join(MANIFEST_FILE_NAME);
|
||||
|
||||
serde_yaml::to_writer(std::fs::File::create(manifest_path)?, self)?;
|
||||
|
||||
Ok(())
|
||||
}
|
||||
}
|
||||
|
|
|
@ -13,7 +13,7 @@ use crate::{
|
|||
dependencies::{resolution::RootLockfileNode, DownloadError, UrlResolveError},
|
||||
index::Index,
|
||||
linking_file::LinkingDependenciesError,
|
||||
manifest::{Manifest, ManifestReadError},
|
||||
manifest::{update_sync_tool_files, Manifest, ManifestReadError},
|
||||
LOCKFILE_FILE_NAME,
|
||||
};
|
||||
|
||||
|
@ -124,6 +124,10 @@ pub enum InstallProjectError {
|
|||
/// An error that occurred while resolving the url of a package
|
||||
#[error("failed to resolve package URL")]
|
||||
UrlResolve(#[from] UrlResolveError),
|
||||
|
||||
/// An error that occurred while reading the lockfile
|
||||
#[error("failed to read lockfile")]
|
||||
ReadLockfile(#[from] ReadLockfileError),
|
||||
}
|
||||
|
||||
/// The name of the default index to use
|
||||
|
@ -289,6 +293,8 @@ impl Project {
|
|||
|
||||
/// Downloads the project's dependencies, applies patches, and links the dependencies
|
||||
pub fn install(&mut self, install_options: InstallOptions) -> Result<(), InstallProjectError> {
|
||||
let old_lockfile = self.lockfile()?;
|
||||
|
||||
let lockfile = match install_options.lockfile {
|
||||
Some(map) => map,
|
||||
None => {
|
||||
|
@ -311,6 +317,10 @@ impl Project {
|
|||
.map_err(InstallProjectError::LockfileSer)?;
|
||||
}
|
||||
|
||||
if !old_lockfile.is_some_and(|old| old.name == lockfile.name) {
|
||||
update_sync_tool_files(self.path(), lockfile.name.name().to_string())?;
|
||||
}
|
||||
|
||||
Ok(())
|
||||
}
|
||||
}
|
||||
|
|
Loading…
Reference in a new issue