chore: add vpm remove

This commit is contained in:
anatawa12 2023-01-25 01:35:54 +09:00
commit 94aa133052
No known key found for this signature in database
GPG key ID: 9CA909848B8E4EA6
4 changed files with 130 additions and 2 deletions

View file

@ -13,7 +13,7 @@ Open Source command line client of VRChat Package Manager.
For more details, please see --help
- [x] `vrc-get install [pkg] [version]`
- [ ] `vrc-get remove [pkg]`
- [x] `vrc-get remove [pkg]` (with alias `vrc-get rm [pkg]`)
- [x] `vrc-get repo list`
- [x] `vrc-get repo add <url> [NAME]`
- [x] `vrc-get repo remove <name or url>`

View file

@ -25,12 +25,15 @@ macro_rules! multi_command {
#[derive(Parser)]
pub enum Command {
Install(Install),
#[command(alias = "rm")]
Remove(Remove),
#[command(subcommand)]
Repo(Repo),
}
multi_command!(Command is Install, Repo);
multi_command!(Command is Install, Remove, Repo);
/// Adds package to unity project
#[derive(Parser)]
pub struct Install {
/// Name of Package
@ -81,6 +84,33 @@ impl Install {
}
}
/// Remove package from Unity project.
#[derive(Parser)]
pub struct Remove {
/// Name of Packages to remove
#[arg()]
names: Vec<String>,
/// Path to project dir. by default CWD or parents of CWD will be used
#[arg(short = 'p', long = "project")]
project: Option<PathBuf>,
}
impl Remove {
pub async fn run(self) {
let mut unity = crate::vpm::UnityProject::find_unity_project(self.project)
.await
.expect("unity project not found");
unity
.remove(&self.names.iter().map(String::as_ref).collect::<Vec<_>>())
.await
.expect("removing package");
unity.save().await.expect("saving manifest file");
}
}
/// Commands around repositories
#[derive(Subcommand)]
pub enum Repo {

View file

@ -1,3 +1,5 @@
extern crate core;
use clap::Parser;
use reqwest::Client;

View file

@ -621,6 +621,14 @@ mod vpm_manifest {
self.locked.insert(name.to_string(), dependency);
}
pub(crate) fn remove_packages(&mut self, names: &[&str]) {
for name in names {
self.locked.remove(*name);
self.dependencies.remove(*name);
}
self.changed = true;
}
fn add_value(&mut self, key0: &str, key1: &str, value: &impl Serialize) {
let serialized = to_value(value).expect("serialize err");
match self.json.get_mut(key0) {
@ -781,6 +789,50 @@ impl UnityProject {
Ok(())
}
/// Remove specified package from self project.
///
/// This doesn't look packages not listed in vpm-maniefst.json.
pub async fn remove(&mut self, names: &[&str]) -> Result<(), RemovePackageErr> {
use crate::vpm::RemovePackageErr::*;
// check for existence
let mut repos = Vec::with_capacity(names.len());
let mut not_founds = Vec::new();
for name in names.into_iter().copied() {
if let Some(x) = self.manifest.locked().get(name) {
repos.push(x);
} else {
not_founds.push(name.to_owned());
}
}
if !not_founds.is_empty() {
return Err(NotInstalled(not_founds));
}
// check for conflicts: if some package requires some packages to be removed, it's conflict.
let conflicts = self
.manifest
.locked()
.into_iter()
.filter(|(name, _)| !names.contains(&name.as_str()))
.filter(|(_, dep)| names.into_iter().any(|x| dep.dependencies.contains_key(*x)))
.map(|(name, _)| String::from(name))
.collect::<Vec<_>>();
if !conflicts.is_empty() {
return Err(ConflictsWith(conflicts));
}
// there's no conflicts. So do remove
self.manifest.remove_packages(names);
Ok(())
}
async fn collect_adding_packages(
&mut self,
env: &Environment,
@ -919,6 +971,50 @@ impl From<io::Error> for AddPackageErr {
}
}
#[derive(Debug)]
pub enum RemovePackageErr {
Io(io::Error),
NotInstalled(Vec<String>),
ConflictsWith(Vec<String>),
}
impl fmt::Display for RemovePackageErr {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
use RemovePackageErr::*;
match self {
Io(ioerr) => fmt::Display::fmt(ioerr, f),
NotInstalled(names) => {
f.write_str("the following packages are not installed: ")?;
let mut iter = names.iter();
f.write_str(iter.next().unwrap())?;
while let Some(name) = iter.next() {
f.write_str(", ")?;
f.write_str(name)?;
}
Ok(())
}
ConflictsWith(names) => {
f.write_str("removing packages conflicts with the following packages: ")?;
let mut iter = names.iter();
f.write_str(iter.next().unwrap())?;
while let Some(name) = iter.next() {
f.write_str(", ")?;
f.write_str(name)?;
}
Ok(())
}
}
}
}
impl std::error::Error for RemovePackageErr {}
impl From<io::Error> for RemovePackageErr {
fn from(value: io::Error) -> Self {
Self::Io(value)
}
}
/// open file or returns none if not exists
async fn try_open_file(path: &Path) -> io::Result<Option<File>> {
match File::open(path).await {