Skip to content

Commit

Permalink
Merge pull request #14 from integer32llc/remove
Browse files Browse the repository at this point in the history
Support removing a crate from the registry
  • Loading branch information
shepmaster authored May 19, 2024
2 parents 0277920 + 946bec8 commit cdef6a0
Show file tree
Hide file tree
Showing 4 changed files with 134 additions and 4 deletions.
4 changes: 2 additions & 2 deletions Cargo.lock

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

2 changes: 1 addition & 1 deletion Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -26,7 +26,7 @@ unused_crate_dependencies = "deny"

[workspace.dependencies]
argh = { version = "0.1.12", default-features = false }
registry-conformance = { version = "0.4.0", registry = "registry-conformance" }
registry-conformance = { version = "0.5.0", registry = "registry-conformance" }
snafu = { version = "0.8.2", default-features = false, features = ["rust_1_65", "std"] }
tokio = { version = "1.37.0", default-features = false, features = ["macros", "process", "rt-multi-thread"] }

Expand Down
32 changes: 32 additions & 0 deletions conformance/src/main.rs
Original file line number Diff line number Diff line change
Expand Up @@ -185,6 +185,22 @@ impl Margo {
Ok(())
}

async fn remove_crate_(&mut self, crate_: &CreatedCrate) -> Result<(), RemoveError> {
use remove_error::*;

self.command()
.arg("rm")
.arg("--registry")
.arg(&self.directory)
.arg(crate_.name())
.args(["--version", crate_.version()])
.expect_success()
.await
.context(ExecutionSnafu)?;

Ok(())
}

async fn yank_crate_(&mut self, crate_: &CreatedCrate, yanked: bool) -> Result<(), YankError> {
use yank_error::*;

Expand Down Expand Up @@ -262,6 +278,15 @@ pub enum PublishError {
},
}

#[derive(Debug, Snafu)]
#[snafu(module)]
pub enum RemoveError {
#[snafu(display("Could not remove the crate from the registry"))]
Execution {
source: registry_conformance::CommandError,
},
}

#[derive(Debug, Snafu)]
#[snafu(module)]
pub enum ShutdownError {
Expand Down Expand Up @@ -297,6 +322,10 @@ impl Registry for Margo {
Ok(self.publish_crate_(crate_).await?)
}

async fn remove_crate(&mut self, crate_: &CreatedCrate) -> Result<(), Error> {
Ok(self.remove_crate_(crate_).await?)
}

async fn yank_crate(&mut self, crate_: &CreatedCrate) -> Result<(), Error> {
Ok(self.yank_crate_(crate_, true).await?)
}
Expand All @@ -319,6 +348,9 @@ pub enum Error {
#[snafu(transparent)]
Publish { source: PublishError },

#[snafu(transparent)]
Remove { source: RemoveError },

#[snafu(transparent)]
Yank { source: YankError },

Expand Down
100 changes: 99 additions & 1 deletion src/main.rs
Original file line number Diff line number Diff line change
Expand Up @@ -26,6 +26,7 @@ struct Args {
enum Subcommand {
Init(InitArgs),
Add(AddArgs),
Remove(RemoveArgs),
GenerateHtml(GenerateHtmlArgs),
Yank(YankArgs),
}
Expand Down Expand Up @@ -72,6 +73,24 @@ struct AddArgs {
path: PathBuf,
}

/// Remove a crate from the registry
#[derive(Debug, argh::FromArgs)]
#[argh(subcommand)]
#[argh(name = "rm")]
struct RemoveArgs {
/// path to the registry to modify
#[argh(option)]
registry: PathBuf,

// FUTURE: Allow removing all versions at once?
/// the version of the crate
#[argh(option)]
version: Version,

#[argh(positional)]
name: CrateName,
}

/// Generate an HTML index for the registry
#[derive(Debug, argh::FromArgs)]
#[argh(subcommand)]
Expand Down Expand Up @@ -114,6 +133,7 @@ fn main() -> Result<(), Error> {
match args.subcommand {
Subcommand::Init(init) => do_init(global, init)?,
Subcommand::Add(add) => do_add(global, add)?,
Subcommand::Remove(rm) => do_remove(global, rm)?,
Subcommand::GenerateHtml(html) => do_generate_html(global, html)?,
Subcommand::Yank(yank) => do_yank(global, yank)?,
}
Expand All @@ -136,6 +156,9 @@ enum Error {
#[snafu(transparent)]
Add { source: AddError },

#[snafu(transparent)]
Remove { source: RemoveError },

#[snafu(transparent)]
Html { source: HtmlError },

Expand Down Expand Up @@ -278,6 +301,15 @@ fn do_add(global: &Global, add: AddArgs) -> Result<(), Error> {
Ok(())
}

fn do_remove(_global: &Global, rm: RemoveArgs) -> Result<(), Error> {
let r = Registry::open(&rm.registry)?;

r.remove(rm.name, rm.version)?;
r.maybe_generate_html()?;

Ok(())
}

fn do_generate_html(_global: &Global, html: GenerateHtmlArgs) -> Result<(), Error> {
let r = Registry::open(html.registry)?;
r.generate_html()?;
Expand Down Expand Up @@ -388,8 +420,8 @@ impl Registry {
fs::create_dir_all(path).context(CrateDirSnafu { path })?;
}

// FUTURE: Add `remove` subcommand
// FUTURE: Stronger file system consistency (atomic file overwrites, rollbacks on error)
// FUTURE: "transactional" adding of multiple crates

self.read_modify_write(&index_entry.name.clone(), |index_file| {
index_file.insert(index_entry.vers.clone(), index_entry);
Expand All @@ -406,6 +438,22 @@ impl Registry {
Ok(())
}

fn remove(&self, name: CrateName, version: Version) -> Result<(), RemoveError> {
use remove_error::*;

self.read_modify_write(&name, |index| {
index.remove(&version);
Ok::<_, RemoveError>(())
})?;

let crate_file = self.crate_file_path_for(&name, &version);
match fs::remove_file(&crate_file) {
Ok(()) => Ok(()),
Err(e) if e.kind() == io::ErrorKind::NotFound => Ok(()),
Err(e) => Err(e).context(DeleteSnafu { path: crate_file }),
}
}

#[cfg(feature = "html")]
fn generate_html(&self) -> Result<(), HtmlError> {
html::write(self)
Expand Down Expand Up @@ -651,6 +699,16 @@ enum AddError {
CrateWrite { source: io::Error, path: PathBuf },
}

#[derive(Debug, Snafu)]
#[snafu(module)]
enum RemoveError {
#[snafu(transparent)]
IndexModify { source: ReadModifyWriteError },

#[snafu(display("Could not delete the crate file {}", path.display()))]
Delete { source: io::Error, path: PathBuf },
}

#[cfg(feature = "html")]
use html::Error as HtmlError;

Expand Down Expand Up @@ -1501,4 +1559,44 @@ mod test {
);
}
}

#[tokio::test]
async fn removing_a_crate_deletes_from_disk() {
let global = Global::new().unwrap();
let scratch = ScratchSpace::new().await.unwrap();

let config = default_config();

let r = Registry::initialize(config, scratch.registry()).unwrap();

let name = "to-go-away";
let version = "1.0.0";

let c = Crate::new(name, version)
.lib_rs(r#"pub const ID: u8 = 1;"#)
.create_in(&scratch)
.await
.unwrap();
let p = c.package().await.unwrap();

let name = name.parse().unwrap();
let version = version.parse().unwrap();
let crate_path = r.crate_file_path_for(&name, &version);

r.add(&global, p).unwrap();

assert!(
crate_path.exists(),
"The crate file should be in the registry at {}",
crate_path.display(),
);

r.remove(name, version).unwrap();

assert!(
!crate_path.exists(),
"The crate file should not be in the registry at {}",
crate_path.display(),
);
}
}

0 comments on commit cdef6a0

Please sign in to comment.