feat(toml): Allow adding/removing from cargo scripts

This commit is contained in:
Ed Page 2024-11-22 20:56:54 -06:00
parent 89d1fafbfd
commit 26844a3331
17 changed files with 139 additions and 119 deletions

View File

@ -1252,6 +1252,8 @@ mod tests {
let mut local = LocalManifest {
path: crate_root.clone(),
manifest,
embedded: None,
raw: toml.to_owned(),
};
assert_eq!(local.manifest.to_string(), toml);
let gctx = GlobalContext::default().unwrap();

View File

@ -11,6 +11,7 @@ use crate::core::dependency::DepKind;
use crate::core::{FeatureValue, Features, Workspace};
use crate::util::closest;
use crate::util::interning::InternedString;
use crate::util::toml::{is_embedded, ScriptSource};
use crate::{CargoResult, GlobalContext};
/// Dependency table to add deps to.
@ -245,6 +246,10 @@ pub struct LocalManifest {
pub path: PathBuf,
/// Manifest contents.
pub manifest: Manifest,
/// The raw, unparsed package file
pub raw: String,
/// Edit location for an embedded manifest, if relevant
pub embedded: Option<Embedded>,
}
impl Deref for LocalManifest {
@ -267,18 +272,56 @@ impl LocalManifest {
if !path.is_absolute() {
anyhow::bail!("can only edit absolute paths, got {}", path.display());
}
let data = cargo_util::paths::read(&path)?;
let raw = cargo_util::paths::read(&path)?;
let mut data = raw.clone();
let mut embedded = None;
if is_embedded(path) {
let source = ScriptSource::parse(&data)?;
if let Some(frontmatter) = source.frontmatter() {
embedded = Some(Embedded::exists(&data, frontmatter));
data = frontmatter.to_owned();
} else if let Some(shebang) = source.shebang() {
embedded = Some(Embedded::after(&data, shebang));
data = String::new();
} else {
embedded = Some(Embedded::start());
data = String::new();
}
}
let manifest = data.parse().context("Unable to parse Cargo.toml")?;
Ok(LocalManifest {
manifest,
path: path.to_owned(),
raw,
embedded,
})
}
/// Write changes back to the file.
pub fn write(&self) -> CargoResult<()> {
let s = self.manifest.data.to_string();
let new_contents_bytes = s.as_bytes();
let mut manifest = self.manifest.data.to_string();
let raw = match self.embedded.as_ref() {
Some(Embedded::Implicit(start)) => {
if !manifest.ends_with("\n") {
manifest.push_str("\n");
}
let fence = "---\n";
let prefix = &self.raw[0..*start];
let suffix = &self.raw[*start..];
let empty_line = if prefix.is_empty() { "\n" } else { "" };
format!("{prefix}{fence}{manifest}{fence}{empty_line}{suffix}")
}
Some(Embedded::Explicit(span)) => {
if !manifest.ends_with("\n") {
manifest.push_str("\n");
}
let prefix = &self.raw[0..span.start];
let suffix = &self.raw[span.end..];
format!("{prefix}{manifest}{suffix}")
}
None => manifest,
};
let new_contents_bytes = raw.as_bytes();
cargo_util::paths::write_atomic(&self.path, new_contents_bytes)
}
@ -531,6 +574,51 @@ impl std::fmt::Display for LocalManifest {
}
}
/// Edit location for an embedded manifest
#[derive(Clone, Debug)]
pub enum Embedded {
/// Manifest is implicit
///
/// This is the insert location for a frontmatter
Implicit(usize),
/// Manifest is explicit in a frontmatter
///
/// This is the span of the frontmatter body
Explicit(std::ops::Range<usize>),
}
impl Embedded {
fn start() -> Self {
Self::Implicit(0)
}
fn after(input: &str, after: &str) -> Self {
let span = substr_span(input, after);
let end = span.end;
Self::Implicit(end)
}
fn exists(input: &str, exists: &str) -> Self {
let span = substr_span(input, exists);
Self::Explicit(span)
}
}
fn substr_span(haystack: &str, needle: &str) -> std::ops::Range<usize> {
let haystack_start_ptr = haystack.as_ptr();
let haystack_end_ptr = haystack[haystack.len()..haystack.len()].as_ptr();
let needle_start_ptr = needle.as_ptr();
let needle_end_ptr = needle[needle.len()..needle.len()].as_ptr();
assert!(needle_end_ptr < haystack_end_ptr);
assert!(haystack_start_ptr <= needle_start_ptr);
let start = needle_start_ptr as usize - haystack_start_ptr as usize;
let end = start + needle.len();
start..end
}
#[derive(Copy, Clone, PartialEq, Eq, PartialOrd, Ord)]
enum DependencyStatus {
None,

View File

@ -31,7 +31,7 @@ fn case() {
.arg_line("--manifest-path cargo-test-fixture.rs my-package")
.current_dir(cwd)
.assert()
.failure()
.success()
.stdout_eq(str![""])
.stderr_eq(file!["stderr.term.svg"]);

View File

@ -1 +1,6 @@
---
[dependencies]
my-package = "99999.0.0"
---
fn main() {}

View File

@ -1,8 +1,8 @@
<svg width="740px" height="254px" xmlns="http://www.w3.org/2000/svg">
<svg width="740px" height="128px" xmlns="http://www.w3.org/2000/svg">
<style>
.fg { fill: #AAAAAA }
.bg { background: #000000 }
.fg-red { fill: #AA0000 }
.fg-green { fill: #00AA00 }
.fg-yellow { fill: #AA5500 }
.container {
padding: 0 10px;
@ -21,29 +21,15 @@
<text xml:space="preserve" class="container fg">
<tspan x="10px" y="28px"><tspan class="fg-yellow bold">warning</tspan><tspan class="bold">:</tspan><tspan> `package.edition` is unspecified, defaulting to `[..]`</tspan>
</tspan>
<tspan x="10px" y="46px"><tspan class="fg-red bold">error</tspan><tspan class="bold">:</tspan><tspan> Unable to parse Cargo.toml</tspan>
<tspan x="10px" y="46px"><tspan class="fg-green bold"> Updating</tspan><tspan> `dummy-registry` index</tspan>
</tspan>
<tspan x="10px" y="64px">
<tspan x="10px" y="64px"><tspan class="fg-green bold"> Adding</tspan><tspan> my-package v99999.0.0 to dependencies</tspan>
</tspan>
<tspan x="10px" y="82px"><tspan>Caused by:</tspan>
<tspan x="10px" y="82px"><tspan class="fg-yellow bold">warning</tspan><tspan class="bold">:</tspan><tspan> `package.edition` is unspecified, defaulting to `[..]`</tspan>
</tspan>
<tspan x="10px" y="100px"><tspan> Manifest not valid TOML</tspan>
<tspan x="10px" y="100px"><tspan class="fg-green bold"> Locking</tspan><tspan> 1 package to latest [..]compatible version</tspan>
</tspan>
<tspan x="10px" y="118px">
</tspan>
<tspan x="10px" y="136px"><tspan>Caused by:</tspan>
</tspan>
<tspan x="10px" y="154px"><tspan> TOML parse error at line 1, column 4</tspan>
</tspan>
<tspan x="10px" y="172px"><tspan> |</tspan>
</tspan>
<tspan x="10px" y="190px"><tspan> 1 | fn main() {}</tspan>
</tspan>
<tspan x="10px" y="208px"><tspan> | ^</tspan>
</tspan>
<tspan x="10px" y="226px"><tspan> expected `.`, `=`</tspan>
</tspan>
<tspan x="10px" y="244px">
</tspan>
</text>

Before

Width:  |  Height:  |  Size: 1.6 KiB

After

Width:  |  Height:  |  Size: 1.4 KiB

View File

@ -31,7 +31,7 @@ fn case() {
.arg_line("--manifest-path cargo-test-fixture.rs my-package")
.current_dir(cwd)
.assert()
.failure()
.success()
.stdout_eq(str![""])
.stderr_eq(file!["stderr.term.svg"]);

View File

@ -1,6 +1,9 @@
---
[package]
edition = "2015"
[dependencies]
my-package = "99999.0.0"
---
fn main() {

View File

@ -1,8 +1,8 @@
<svg width="740px" height="236px" xmlns="http://www.w3.org/2000/svg">
<svg width="740px" height="92px" xmlns="http://www.w3.org/2000/svg">
<style>
.fg { fill: #AAAAAA }
.bg { background: #000000 }
.fg-red { fill: #AA0000 }
.fg-green { fill: #00AA00 }
.container {
padding: 0 10px;
line-height: 18px;
@ -18,29 +18,13 @@
<rect width="100%" height="100%" y="0" rx="4.5" class="bg" />
<text xml:space="preserve" class="container fg">
<tspan x="10px" y="28px"><tspan class="fg-red bold">error</tspan><tspan class="bold">:</tspan><tspan> Unable to parse Cargo.toml</tspan>
<tspan x="10px" y="28px"><tspan class="fg-green bold"> Updating</tspan><tspan> `dummy-registry` index</tspan>
</tspan>
<tspan x="10px" y="46px">
<tspan x="10px" y="46px"><tspan class="fg-green bold"> Adding</tspan><tspan> my-package v99999.0.0 to dependencies</tspan>
</tspan>
<tspan x="10px" y="64px"><tspan>Caused by:</tspan>
<tspan x="10px" y="64px"><tspan class="fg-green bold"> Locking</tspan><tspan> 1 package to latest [..]compatible version</tspan>
</tspan>
<tspan x="10px" y="82px"><tspan> Manifest not valid TOML</tspan>
</tspan>
<tspan x="10px" y="100px">
</tspan>
<tspan x="10px" y="118px"><tspan>Caused by:</tspan>
</tspan>
<tspan x="10px" y="136px"><tspan> TOML parse error at line 1, column 4</tspan>
</tspan>
<tspan x="10px" y="154px"><tspan> |</tspan>
</tspan>
<tspan x="10px" y="172px"><tspan> 1 | ---</tspan>
</tspan>
<tspan x="10px" y="190px"><tspan> | ^</tspan>
</tspan>
<tspan x="10px" y="208px"><tspan> expected `.`, `=`</tspan>
</tspan>
<tspan x="10px" y="226px">
<tspan x="10px" y="82px">
</tspan>
</text>

Before

Width:  |  Height:  |  Size: 1.4 KiB

After

Width:  |  Height:  |  Size: 1016 B

View File

@ -31,7 +31,7 @@ fn case() {
.arg_line("--manifest-path cargo-test-fixture.rs my-package")
.current_dir(cwd)
.assert()
.failure()
.success()
.stdout_eq(str![""])
.stderr_eq(file!["stderr.term.svg"]);

View File

@ -1,3 +1,7 @@
#!/usr/bin/env cargo
---
[dependencies]
my-package = "99999.0.0"
---
fn main() {}

View File

@ -1,8 +1,8 @@
<svg width="740px" height="254px" xmlns="http://www.w3.org/2000/svg">
<svg width="740px" height="128px" xmlns="http://www.w3.org/2000/svg">
<style>
.fg { fill: #AAAAAA }
.bg { background: #000000 }
.fg-red { fill: #AA0000 }
.fg-green { fill: #00AA00 }
.fg-yellow { fill: #AA5500 }
.container {
padding: 0 10px;
@ -21,29 +21,15 @@
<text xml:space="preserve" class="container fg">
<tspan x="10px" y="28px"><tspan class="fg-yellow bold">warning</tspan><tspan class="bold">:</tspan><tspan> `package.edition` is unspecified, defaulting to `[..]`</tspan>
</tspan>
<tspan x="10px" y="46px"><tspan class="fg-red bold">error</tspan><tspan class="bold">:</tspan><tspan> Unable to parse Cargo.toml</tspan>
<tspan x="10px" y="46px"><tspan class="fg-green bold"> Updating</tspan><tspan> `dummy-registry` index</tspan>
</tspan>
<tspan x="10px" y="64px">
<tspan x="10px" y="64px"><tspan class="fg-green bold"> Adding</tspan><tspan> my-package v99999.0.0 to dependencies</tspan>
</tspan>
<tspan x="10px" y="82px"><tspan>Caused by:</tspan>
<tspan x="10px" y="82px"><tspan class="fg-yellow bold">warning</tspan><tspan class="bold">:</tspan><tspan> `package.edition` is unspecified, defaulting to `[..]`</tspan>
</tspan>
<tspan x="10px" y="100px"><tspan> Manifest not valid TOML</tspan>
<tspan x="10px" y="100px"><tspan class="fg-green bold"> Locking</tspan><tspan> 1 package to latest [..]compatible version</tspan>
</tspan>
<tspan x="10px" y="118px">
</tspan>
<tspan x="10px" y="136px"><tspan>Caused by:</tspan>
</tspan>
<tspan x="10px" y="154px"><tspan> TOML parse error at line 3, column 4</tspan>
</tspan>
<tspan x="10px" y="172px"><tspan> |</tspan>
</tspan>
<tspan x="10px" y="190px"><tspan> 3 | fn main() {}</tspan>
</tspan>
<tspan x="10px" y="208px"><tspan> | ^</tspan>
</tspan>
<tspan x="10px" y="226px"><tspan> expected `.`, `=`</tspan>
</tspan>
<tspan x="10px" y="244px">
</tspan>
</text>

Before

Width:  |  Height:  |  Size: 1.6 KiB

After

Width:  |  Height:  |  Size: 1.4 KiB

View File

@ -32,7 +32,7 @@ fn case() {
.arg_line("--manifest-path cargo-remove-test-fixture.rs docopt")
.current_dir(cwd)
.assert()
.failure()
.success()
.stdout_eq(str![""])
.stderr_eq(file!["stderr.term.svg"]);

View File

@ -5,7 +5,6 @@ edition = "2015"
semver = "0.1.0"
[dependencies]
docopt = "0.6"
rustc-serialize = "0.4"
semver = "0.1"
toml = "0.1"

View File

@ -1,8 +1,8 @@
<svg width="740px" height="254px" xmlns="http://www.w3.org/2000/svg">
<svg width="740px" height="92px" xmlns="http://www.w3.org/2000/svg">
<style>
.fg { fill: #AAAAAA }
.bg { background: #000000 }
.fg-red { fill: #AA0000 }
.fg-green { fill: #00AA00 }
.fg-yellow { fill: #AA5500 }
.container {
padding: 0 10px;
@ -21,29 +21,11 @@
<text xml:space="preserve" class="container fg">
<tspan x="10px" y="28px"><tspan class="fg-yellow bold">warning</tspan><tspan class="bold">:</tspan><tspan> `package.edition` is unspecified, defaulting to `[..]`</tspan>
</tspan>
<tspan x="10px" y="46px"><tspan class="fg-red bold">error</tspan><tspan class="bold">:</tspan><tspan> Unable to parse Cargo.toml</tspan>
<tspan x="10px" y="46px"><tspan class="fg-green bold"> Removing</tspan><tspan> docopt from dependencies</tspan>
</tspan>
<tspan x="10px" y="64px">
<tspan x="10px" y="64px"><tspan class="fg-yellow bold">warning</tspan><tspan class="bold">:</tspan><tspan> `package.edition` is unspecified, defaulting to `[..]`</tspan>
</tspan>
<tspan x="10px" y="82px"><tspan>Caused by:</tspan>
</tspan>
<tspan x="10px" y="100px"><tspan> Manifest not valid TOML</tspan>
</tspan>
<tspan x="10px" y="118px">
</tspan>
<tspan x="10px" y="136px"><tspan>Caused by:</tspan>
</tspan>
<tspan x="10px" y="154px"><tspan> TOML parse error at line 1, column 4</tspan>
</tspan>
<tspan x="10px" y="172px"><tspan> |</tspan>
</tspan>
<tspan x="10px" y="190px"><tspan> 1 | ---</tspan>
</tspan>
<tspan x="10px" y="208px"><tspan> | ^</tspan>
</tspan>
<tspan x="10px" y="226px"><tspan> expected `.`, `=`</tspan>
</tspan>
<tspan x="10px" y="244px">
<tspan x="10px" y="82px">
</tspan>
</text>

Before

Width:  |  Height:  |  Size: 1.6 KiB

After

Width:  |  Height:  |  Size: 1.1 KiB

View File

@ -22,7 +22,7 @@ fn case() {
.arg_line("--manifest-path cargo-remove-test-fixture.rs docopt")
.current_dir(cwd)
.assert()
.failure()
.success()
.stdout_eq(str![""])
.stderr_eq(file!["stderr.term.svg"]);

View File

@ -1,6 +1,5 @@
---
[dependencies]
docopt = "0.6"
---
fn main() {

View File

@ -1,8 +1,8 @@
<svg width="740px" height="254px" xmlns="http://www.w3.org/2000/svg">
<svg width="740px" height="92px" xmlns="http://www.w3.org/2000/svg">
<style>
.fg { fill: #AAAAAA }
.bg { background: #000000 }
.fg-red { fill: #AA0000 }
.fg-green { fill: #00AA00 }
.fg-yellow { fill: #AA5500 }
.container {
padding: 0 10px;
@ -21,29 +21,11 @@
<text xml:space="preserve" class="container fg">
<tspan x="10px" y="28px"><tspan class="fg-yellow bold">warning</tspan><tspan class="bold">:</tspan><tspan> `package.edition` is unspecified, defaulting to `[..]`</tspan>
</tspan>
<tspan x="10px" y="46px"><tspan class="fg-red bold">error</tspan><tspan class="bold">:</tspan><tspan> Unable to parse Cargo.toml</tspan>
<tspan x="10px" y="46px"><tspan class="fg-green bold"> Removing</tspan><tspan> docopt from dependencies</tspan>
</tspan>
<tspan x="10px" y="64px">
<tspan x="10px" y="64px"><tspan class="fg-yellow bold">warning</tspan><tspan class="bold">:</tspan><tspan> `package.edition` is unspecified, defaulting to `[..]`</tspan>
</tspan>
<tspan x="10px" y="82px"><tspan>Caused by:</tspan>
</tspan>
<tspan x="10px" y="100px"><tspan> Manifest not valid TOML</tspan>
</tspan>
<tspan x="10px" y="118px">
</tspan>
<tspan x="10px" y="136px"><tspan>Caused by:</tspan>
</tspan>
<tspan x="10px" y="154px"><tspan> TOML parse error at line 1, column 4</tspan>
</tspan>
<tspan x="10px" y="172px"><tspan> |</tspan>
</tspan>
<tspan x="10px" y="190px"><tspan> 1 | ---</tspan>
</tspan>
<tspan x="10px" y="208px"><tspan> | ^</tspan>
</tspan>
<tspan x="10px" y="226px"><tspan> expected `.`, `=`</tspan>
</tspan>
<tspan x="10px" y="244px">
<tspan x="10px" y="82px">
</tspan>
</text>

Before

Width:  |  Height:  |  Size: 1.6 KiB

After

Width:  |  Height:  |  Size: 1.1 KiB