Skip to content

Commit 185a23a

Browse files
committed
Name the go.sum version-line key rule once
GoSumEditor spelled the "{module} {version} " / "/go.mod " key rule in three methods, each allocating two format! keys per call. One is_version_line helper now carries the rule without allocating, and the editor reads its lines through one current_lines iterator instead of matching on its state in every method. No behavior change: the step-by-step oracle test still compares the editor with the text transforms over 3000 random go.sum files. Assisted-by: Claude Code:claude-opus-5-5
1 parent a5ad55e commit 185a23a

1 file changed

Lines changed: 64 additions & 44 deletions

File tree

‎crates/socket-patch-core/src/vendor/go_sum_edit.rs‎

Lines changed: 64 additions & 44 deletions
Original file line numberDiff line numberDiff line change
@@ -36,6 +36,17 @@ fn module_lines(module: &str, version: &str, zip_h1: &str, gomod_h1: &str) -> [S
3636
]
3737
}
3838

39+
/// True when `line` is a `go.sum` line (zip or `/go.mod` form) for exactly
40+
/// `module@version`: `"{module} {version} "` or `"{module} {version}/go.mod "`
41+
/// starts it. The trailing space or `/go.mod` keeps `v1.0.0` from matching a
42+
/// longer version such as `v1.0.0-socketpatch.1`.
43+
fn is_version_line(line: &str, module: &str, version: &str) -> bool {
44+
line.strip_prefix(module)
45+
.and_then(|rest| rest.strip_prefix(' '))
46+
.and_then(|rest| rest.strip_prefix(version))
47+
.is_some_and(|rest| rest.starts_with(' ') || rest.starts_with("/go.mod "))
48+
}
49+
3950
/// Upsert the two `go.sum` lines for `module@version`. Any existing lines for
4051
/// exactly that module+version (either suffix form) are replaced; everything
4152
/// else — including stale lines for the *replaced* original module, which go
@@ -310,7 +321,22 @@ impl GoSumEditor {
310321
};
311322
}
312323

313-
/// [`upsert_module_lines`] in place; `true` when it changed the content.
324+
/// The current content's lines, as `str::lines` splits them.
325+
fn current_lines(&self) -> impl Iterator<Item = &str> {
326+
let (text, lines) = match &self.state {
327+
GoSumState::Text(text) => (Some(text.lines()), None),
328+
GoSumState::Lines { lines, .. } => (None, Some(lines.iter().map(String::as_str))),
329+
};
330+
text.into_iter().flatten().chain(lines.into_iter().flatten())
331+
}
332+
333+
/// Upsert the two `go.sum` lines for `module@version`. Any existing lines
334+
/// for exactly that module+version (either suffix form) are replaced;
335+
/// everything else — including stale lines for the *replaced* original
336+
/// module, which go tolerates and `go mod tidy` prunes — is preserved
337+
/// verbatim. The content may be empty (a project whose `go.sum` does not
338+
/// exist yet). `true` when it changed the content, `false` when the file
339+
/// already carries exactly these lines.
314340
pub(crate) fn upsert_module_lines(
315341
&mut self,
316342
module: &str,
@@ -319,34 +345,32 @@ impl GoSumEditor {
319345
gomod_h1: &str,
320346
) -> bool {
321347
let want = module_lines(module, version, zip_h1, gomod_h1);
322-
let zip_key = format!("{module} {version} ");
323-
let gomod_key = format!("{module} {version}/go.mod ");
324-
let is_key = |l: &str| l.starts_with(&zip_key) || l.starts_with(&gomod_key);
325-
let applied = {
326-
let mut want_seen = [0usize; 2];
327-
let mut stale_key_line = false;
328-
let mut scan = |l: &str| {
329-
if l == want[0] {
330-
want_seen[0] += 1;
331-
} else if l == want[1] {
332-
want_seen[1] += 1;
333-
} else if is_key(l) {
334-
stale_key_line = true;
335-
}
336-
};
337-
match &self.state {
338-
GoSumState::Text(text) => text.lines().for_each(&mut scan),
339-
GoSumState::Lines { lines, .. } => {
340-
lines.iter().map(String::as_str).for_each(&mut scan)
341-
}
348+
let is_key = |l: &str| is_version_line(l, module, version);
349+
// "Already applied" means the key-matching lines are exactly the two
350+
// wanted ones — a bare match count is not enough: a stale same-key
351+
// line with a different hash (a union-merged go.sum straddling a
352+
// republish) is a hard go `SECURITY ERROR`, and a duplicated zip line
353+
// can stand in for a missing /go.mod line. Both still need the
354+
// rewrite below.
355+
let mut want_seen = [0usize; 2];
356+
let mut stale_key_line = false;
357+
for l in self.current_lines() {
358+
if l == want[0] {
359+
want_seen[0] += 1;
360+
} else if l == want[1] {
361+
want_seen[1] += 1;
362+
} else if is_key(l) {
363+
stale_key_line = true;
342364
}
343-
want_seen == [1, 1] && !stale_key_line
344-
};
345-
if applied {
365+
}
366+
if want_seen == [1, 1] && !stale_key_line {
346367
return false;
347368
}
348369
let (mut lines, eol) = self.take_lines();
349370
lines.retain(|l| !is_key(l));
371+
// Insert both lines at their sorted position (stable against an
372+
// unsorted user file: first line strictly greater wins; ties cannot
373+
// occur — the exact-key duplicates were just removed).
350374
let mut out: Vec<String> = Vec::with_capacity(lines.len() + 2);
351375
let mut pending = want.into_iter().peekable();
352376
for line in lines {
@@ -364,37 +388,33 @@ impl GoSumEditor {
364388
true
365389
}
366390

367-
/// [`has_module_version`] over the current content.
391+
/// True when the content carries a line (zip or `/go.mod` form) for
392+
/// exactly `module@version` — go records one for every module version
393+
/// its build graph loads.
368394
pub(crate) fn has_module_version(&self, module: &str, version: &str) -> bool {
369-
let zip_key = format!("{module} {version} ");
370-
let gomod_key = format!("{module} {version}/go.mod ");
371-
let is_key = |l: &str| l.starts_with(&zip_key) || l.starts_with(&gomod_key);
372-
match &self.state {
373-
GoSumState::Text(text) => text.lines().any(is_key),
374-
GoSumState::Lines { lines, .. } => lines.iter().any(|l| is_key(l)),
375-
}
395+
self.current_lines()
396+
.any(|l| is_version_line(l, module, version))
376397
}
377398

378-
/// [`remove_exact_module_version_lines`] in place: the removed lines, or
379-
/// `None` when nothing matched.
399+
/// Remove the lines for exactly `module@version` (both the zip and
400+
/// `/go.mod` forms). Used to prune the REPLACED original's lines: once a
401+
/// version-pinned `replace` covers the resolved version, go never fetches
402+
/// (or verifies) the original at all, and `go mod tidy` prunes exactly
403+
/// these lines — writing that state up front keeps the first day-2 tidy
404+
/// a byte-level no-op. Returns the removed lines, or `None` when nothing
405+
/// matched.
380406
pub(crate) fn remove_exact_module_version_lines(
381407
&mut self,
382408
module: &str,
383409
version: &str,
384410
) -> Option<Vec<String>> {
385-
let zip_key = format!("{module} {version} ");
386-
let gomod_key = format!("{module} {version}/go.mod ");
387-
let is_key = |l: &str| l.starts_with(&zip_key) || l.starts_with(&gomod_key);
388-
let any = match &self.state {
389-
GoSumState::Text(text) => text.lines().any(is_key),
390-
GoSumState::Lines { lines, .. } => lines.iter().any(|l| is_key(l)),
391-
};
392-
if !any {
411+
if !self.has_module_version(module, version) {
393412
return None;
394413
}
395414
let (lines, eol) = self.take_lines();
396-
let (removed, kept): (Vec<String>, Vec<String>) =
397-
lines.into_iter().partition(|l| is_key(l));
415+
let (removed, kept): (Vec<String>, Vec<String>) = lines
416+
.into_iter()
417+
.partition(|l| is_version_line(l, module, version));
398418
self.commit(kept, eol);
399419
Some(removed)
400420
}

0 commit comments

Comments
 (0)