mirror of
https://github.com/pesde-pkg/pesde.git
synced 2025-04-18 10:53:56 +01:00
Patches now work much better with incremental installs. They use a Git repository to reset the patch to the original state before applying it. They are now also properly cleaned up after being removed. Also, to allow more flexability the patching process is now done before type extracting, so that types can be patched. Lastly, the patch-commit command now doesn't delete the patch directory until it has done everything else to prevent data loss.
101 lines
2.5 KiB
Rust
101 lines
2.5 KiB
Rust
use crate::cli::up_to_date_lockfile;
|
|
use anyhow::Context;
|
|
use clap::Args;
|
|
use fs_err::tokio as fs;
|
|
use pesde::{
|
|
names::PackageNames,
|
|
patches::create_patch,
|
|
source::ids::{PackageId, VersionId},
|
|
Project,
|
|
};
|
|
use std::{path::PathBuf, str::FromStr};
|
|
|
|
#[derive(Debug, Args)]
|
|
pub struct PatchCommitCommand {
|
|
/// The directory containing the patch to commit
|
|
#[arg(index = 1)]
|
|
directory: PathBuf,
|
|
}
|
|
|
|
impl PatchCommitCommand {
|
|
pub async fn run(self, project: Project) -> anyhow::Result<()> {
|
|
let graph = if let Some(lockfile) = up_to_date_lockfile(&project).await? {
|
|
lockfile.graph
|
|
} else {
|
|
anyhow::bail!("outdated lockfile, please run the install command first")
|
|
};
|
|
|
|
let id = PackageId::new(
|
|
PackageNames::from_escaped(
|
|
self.directory
|
|
.parent()
|
|
.context("directory has no parent")?
|
|
.parent()
|
|
.context("directory has no grandparent")?
|
|
.file_name()
|
|
.context("directory grandparent has no name")?
|
|
.to_str()
|
|
.context("directory grandparent name is not valid")?,
|
|
)?,
|
|
VersionId::from_escaped(
|
|
self.directory
|
|
.parent()
|
|
.context("directory has no parent")?
|
|
.file_name()
|
|
.context("directory parent has no name")?
|
|
.to_str()
|
|
.context("directory parent name is not valid")?,
|
|
)?,
|
|
);
|
|
|
|
graph.get(&id).context("package not found in graph")?;
|
|
|
|
let mut manifest = toml_edit::DocumentMut::from_str(
|
|
&project
|
|
.read_manifest()
|
|
.await
|
|
.context("failed to read manifest")?,
|
|
)
|
|
.context("failed to parse manifest")?;
|
|
|
|
let patch = create_patch(&self.directory).context("failed to create patch")?;
|
|
|
|
let patches_dir = project.package_dir().join("patches");
|
|
fs::create_dir_all(&patches_dir)
|
|
.await
|
|
.context("failed to create patches directory")?;
|
|
|
|
let patch_file_name = format!(
|
|
"{}-{}.patch",
|
|
id.name().escaped(),
|
|
id.version_id().escaped()
|
|
);
|
|
|
|
let patch_file = patches_dir.join(&patch_file_name);
|
|
|
|
fs::write(&patch_file, patch)
|
|
.await
|
|
.context("failed to write patch file")?;
|
|
|
|
manifest["patches"].or_insert(toml_edit::Item::Table(toml_edit::Table::new()))
|
|
[&id.name().to_string()][&id.version_id().to_string()] =
|
|
toml_edit::value(format!("patches/{patch_file_name}"));
|
|
|
|
project
|
|
.write_manifest(manifest.to_string())
|
|
.await
|
|
.context("failed to write manifest")?;
|
|
|
|
fs::remove_dir_all(self.directory)
|
|
.await
|
|
.context("failed to remove patch directory")?;
|
|
|
|
println!(concat!(
|
|
"done! run `",
|
|
env!("CARGO_BIN_NAME"),
|
|
" install` to apply the patch"
|
|
));
|
|
|
|
Ok(())
|
|
}
|
|
}
|