Skip to content

Commit 2a5fdea

Browse files
committed
feat(toml): Allow adding/removing from cargo scripts
1 parent b4a8940 commit 2a5fdea

File tree

17 files changed

+130
-119
lines changed

17 files changed

+130
-119
lines changed

src/cargo/util/toml_mut/dependency.rs

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1252,6 +1252,8 @@ mod tests {
12521252
let mut local = LocalManifest {
12531253
path: crate_root.clone(),
12541254
manifest,
1255+
embedded: None,
1256+
raw: toml.to_owned(),
12551257
};
12561258
assert_eq!(local.manifest.to_string(), toml);
12571259
let gctx = GlobalContext::default().unwrap();

src/cargo/util/toml_mut/manifest.rs

Lines changed: 82 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -11,6 +11,7 @@ use crate::core::dependency::DepKind;
1111
use crate::core::{FeatureValue, Features, Workspace};
1212
use crate::util::closest;
1313
use crate::util::interning::InternedString;
14+
use crate::util::toml::{is_embedded, ScriptSource};
1415
use crate::{CargoResult, GlobalContext};
1516

1617
/// Dependency table to add deps to.
@@ -245,6 +246,8 @@ pub struct LocalManifest {
245246
pub path: PathBuf,
246247
/// Manifest contents.
247248
pub manifest: Manifest,
249+
pub raw: String,
250+
pub embedded: Option<Embedded>,
248251
}
249252

250253
impl Deref for LocalManifest {
@@ -267,18 +270,56 @@ impl LocalManifest {
267270
if !path.is_absolute() {
268271
anyhow::bail!("can only edit absolute paths, got {}", path.display());
269272
}
270-
let data = cargo_util::paths::read(&path)?;
273+
let raw = cargo_util::paths::read(&path)?;
274+
let mut data = raw.clone();
275+
let mut embedded = None;
276+
if is_embedded(path) {
277+
let source = ScriptSource::parse(&data)?;
278+
if let Some(frontmatter) = source.frontmatter() {
279+
embedded = Some(Embedded::exists(&data, frontmatter));
280+
data = frontmatter.to_owned();
281+
} else if let Some(shebang) = source.shebang() {
282+
embedded = Some(Embedded::after(&data, shebang));
283+
data = String::new();
284+
} else {
285+
embedded = Some(Embedded::start());
286+
data = String::new();
287+
}
288+
}
271289
let manifest = data.parse().context("Unable to parse Cargo.toml")?;
272290
Ok(LocalManifest {
273291
manifest,
274292
path: path.to_owned(),
293+
raw,
294+
embedded,
275295
})
276296
}
277297

278298
/// Write changes back to the file.
279299
pub fn write(&self) -> CargoResult<()> {
280-
let s = self.manifest.data.to_string();
281-
let new_contents_bytes = s.as_bytes();
300+
let mut manifest = self.manifest.data.to_string();
301+
let raw = match self.embedded.as_ref() {
302+
Some(Embedded::Implicit(start)) => {
303+
if !manifest.ends_with("\n") {
304+
manifest.push_str("\n");
305+
}
306+
let fence = "---\n";
307+
let prefix = &self.raw[0..*start];
308+
let suffix = &self.raw[*start..];
309+
let empty_line = if prefix.is_empty() { "\n" } else { "" };
310+
format!("{prefix}{fence}{manifest}{fence}{empty_line}{suffix}")
311+
}
312+
Some(Embedded::Explicit(span)) => {
313+
if !manifest.ends_with("\n") {
314+
manifest.push_str("\n");
315+
}
316+
let prefix = &self.raw[0..span.start];
317+
let suffix = &self.raw[span.end..];
318+
format!("{prefix}{manifest}{suffix}")
319+
}
320+
None => manifest,
321+
};
322+
let new_contents_bytes = raw.as_bytes();
282323

283324
cargo_util::paths::write_atomic(&self.path, new_contents_bytes)
284325
}
@@ -531,6 +572,44 @@ impl std::fmt::Display for LocalManifest {
531572
}
532573
}
533574

575+
#[derive(Clone, Debug)]
576+
pub enum Embedded {
577+
Implicit(usize),
578+
Explicit(std::ops::Range<usize>),
579+
}
580+
581+
impl Embedded {
582+
fn start() -> Self {
583+
Self::Implicit(0)
584+
}
585+
586+
fn after(input: &str, after: &str) -> Self {
587+
let span = substr_span(input, after);
588+
let end = span.end;
589+
Self::Implicit(end)
590+
}
591+
592+
fn exists(input: &str, exists: &str) -> Self {
593+
let span = substr_span(input, exists);
594+
Self::Explicit(span)
595+
}
596+
}
597+
598+
fn substr_span(haystack: &str, needle: &str) -> std::ops::Range<usize> {
599+
let haystack_start_ptr = haystack.as_ptr();
600+
let haystack_end_ptr = haystack[haystack.len()..haystack.len()].as_ptr();
601+
602+
let needle_start_ptr = needle.as_ptr();
603+
let needle_end_ptr = needle[needle.len()..needle.len()].as_ptr();
604+
605+
assert!(needle_end_ptr < haystack_end_ptr);
606+
assert!(haystack_start_ptr <= needle_start_ptr);
607+
let start = needle_start_ptr as usize - haystack_start_ptr as usize;
608+
let end = start + needle.len();
609+
610+
start..end
611+
}
612+
534613
#[derive(Copy, Clone, PartialEq, Eq, PartialOrd, Ord)]
535614
enum DependencyStatus {
536615
None,

tests/testsuite/cargo_add/script_bare/mod.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -31,7 +31,7 @@ fn case() {
3131
.arg_line("--manifest-path cargo-test-fixture.rs my-package")
3232
.current_dir(cwd)
3333
.assert()
34-
.failure()
34+
.success()
3535
.stdout_eq(str![""])
3636
.stderr_eq(file!["stderr.term.svg"]);
3737

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1 +1,6 @@
1+
---
2+
[dependencies]
3+
my-package = "99999.0.0"
4+
---
5+
16
fn main() {}

tests/testsuite/cargo_add/script_bare/stderr.term.svg

Lines changed: 6 additions & 20 deletions
Loading

tests/testsuite/cargo_add/script_frontmatter/mod.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -31,7 +31,7 @@ fn case() {
3131
.arg_line("--manifest-path cargo-test-fixture.rs my-package")
3232
.current_dir(cwd)
3333
.assert()
34-
.failure()
34+
.success()
3535
.stdout_eq(str![""])
3636
.stderr_eq(file!["stderr.term.svg"]);
3737

tests/testsuite/cargo_add/script_frontmatter/out/cargo-test-fixture.rs

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,9 @@
11
---
22
[package]
33
edition = "2015"
4+
5+
[dependencies]
6+
my-package = "99999.0.0"
47
---
58

69
fn main() {

tests/testsuite/cargo_add/script_frontmatter/stderr.term.svg

Lines changed: 6 additions & 22 deletions
Loading

tests/testsuite/cargo_add/script_shebang/mod.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -31,7 +31,7 @@ fn case() {
3131
.arg_line("--manifest-path cargo-test-fixture.rs my-package")
3232
.current_dir(cwd)
3333
.assert()
34-
.failure()
34+
.success()
3535
.stdout_eq(str![""])
3636
.stderr_eq(file!["stderr.term.svg"]);
3737

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,7 @@
11
#!/usr/bin/env cargo
2+
---
3+
[dependencies]
4+
my-package = "99999.0.0"
5+
---
26

37
fn main() {}

tests/testsuite/cargo_add/script_shebang/stderr.term.svg

Lines changed: 6 additions & 20 deletions
Loading

tests/testsuite/cargo_remove/script/mod.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -32,7 +32,7 @@ fn case() {
3232
.arg_line("--manifest-path cargo-remove-test-fixture.rs docopt")
3333
.current_dir(cwd)
3434
.assert()
35-
.failure()
35+
.success()
3636
.stdout_eq(str![""])
3737
.stderr_eq(file!["stderr.term.svg"]);
3838

tests/testsuite/cargo_remove/script/out/cargo-remove-test-fixture.rs

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -5,7 +5,6 @@ edition = "2015"
55
semver = "0.1.0"
66

77
[dependencies]
8-
docopt = "0.6"
98
rustc-serialize = "0.4"
109
semver = "0.1"
1110
toml = "0.1"

tests/testsuite/cargo_remove/script/stderr.term.svg

Lines changed: 5 additions & 23 deletions
Loading

tests/testsuite/cargo_remove/script_last/mod.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -22,7 +22,7 @@ fn case() {
2222
.arg_line("--manifest-path cargo-remove-test-fixture.rs docopt")
2323
.current_dir(cwd)
2424
.assert()
25-
.failure()
25+
.success()
2626
.stdout_eq(str![""])
2727
.stderr_eq(file!["stderr.term.svg"]);
2828

tests/testsuite/cargo_remove/script_last/out/cargo-remove-test-fixture.rs

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,5 @@
11
---
2-
[dependencies]
3-
docopt = "0.6"
2+
43
---
54

65
fn main() {

0 commit comments

Comments
 (0)