Skip to content

Commit c9cd86d

Browse files
mikolalysenkoclaude
andcommitted
Merge origin/main into arch-fix/purl-key
Resolve the apply `--check` conflict with #1029. Main hoisted the vendored key set into `run_check`'s outer scope (`vendored_purl_keys`, already a `PurlKey` set via `purl_keys_cover`). The Go redirect check now reuses that set instead of loading the vendor ledger a second time. Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
2 parents 450f7f0 + b96a785 commit c9cd86d

49 files changed

Lines changed: 3946 additions & 1353 deletions

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

‎crates/socket-patch-cli/CLI_CONTRACT.md‎

Lines changed: 7 additions & 3 deletions
Large diffs are not rendered by default.

‎crates/socket-patch-cli/src/args.rs‎

Lines changed: 75 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -95,7 +95,11 @@ pub(crate) const GLOBAL_OPTIONS: &str = "Global options";
9595
//
9696
// **Every** global flag is parseable on **every** subcommand. Commands that
9797
// don't use a given flag ignore it silently — e.g. `list --global` parses
98-
// fine and the `global` field is unused at runtime.
98+
// fine and the `global` field is unused at runtime. The one exception is
99+
// the path flags (`--cwd`, `--global-prefix`, `--manifest-path`): `main`
100+
// validates them on every project command, used or not
101+
// ([`GlobalArgs::validate_paths`]), because a path that names nothing must
102+
// never read as an empty project.
99103
//
100104
// (Plain `//` comments: clap turns a doc comment here into the `--help`
101105
// description of any subcommand that has none of its own.)
@@ -383,6 +387,76 @@ pub struct GlobalArgs {
383387
}
384388

385389
impl GlobalArgs {
390+
/// Reject path flags that name nothing: `--cwd` and `--global-prefix`
391+
/// (flag or env) must be existing directories, and a `--manifest-path`
392+
/// other than the default must sit in an existing project directory and
393+
/// must not itself be a directory. `main` maps `Err` to the usage exit
394+
/// (2), the same exit a hosted/vendored `scan` PATH that is not a
395+
/// directory gets.
396+
///
397+
/// Without this a typo in `--cwd` / `SOCKET_CWD` read as an empty
398+
/// project: `apply`, `list`, `scan`, `get` and the `vendor --check` CI
399+
/// gate all exited 0 having checked nothing.
400+
///
401+
/// A missing manifest FILE stays legal: hosted and vendored projects
402+
/// have none, and `get` / `scan --mode agent` create it. Only its
403+
/// project directory has to exist — except for the commands that
404+
/// create the manifest (`creates_manifest`: `get`, `scan`), which make
405+
/// a missing directory as they always have; writing it is no vacuous
406+
/// pass.
407+
pub fn validate_paths(&self, creates_manifest: bool) -> Result<(), String> {
408+
let not_dir = |flag: &str, env: &str, path: &Path, what: &str| {
409+
format!("{flag} (or {env}) `{}` {what}", path.display())
410+
};
411+
if !self.cwd.is_dir() {
412+
let what = if self.cwd.exists() {
413+
"is not a directory"
414+
} else {
415+
"does not exist"
416+
};
417+
return Err(not_dir("--cwd", "SOCKET_CWD", &self.cwd, what));
418+
}
419+
if let Some(prefix) = &self.global_prefix {
420+
if !prefix.is_dir() {
421+
let what = if prefix.exists() {
422+
"is not a directory"
423+
} else {
424+
"does not exist"
425+
};
426+
return Err(not_dir(
427+
"--global-prefix",
428+
"SOCKET_GLOBAL_PREFIX",
429+
prefix,
430+
what,
431+
));
432+
}
433+
}
434+
if self.manifest_path != DEFAULT_PATCH_MANIFEST_PATH {
435+
let manifest = self.resolved_manifest_path();
436+
if manifest.is_dir() {
437+
return Err(not_dir(
438+
"--manifest-path",
439+
"SOCKET_MANIFEST_PATH",
440+
&manifest,
441+
"is a directory, not a manifest file",
442+
));
443+
}
444+
let root = self.project_root();
445+
if !creates_manifest && !root.is_dir() {
446+
return Err(not_dir(
447+
"--manifest-path",
448+
"SOCKET_MANIFEST_PATH",
449+
&manifest,
450+
&format!(
451+
"is in a project directory that does not exist ({})",
452+
root.display()
453+
),
454+
));
455+
}
456+
}
457+
Ok(())
458+
}
459+
386460
/// The crawler options this run's `--cwd` / `--global` /
387461
/// `--global-prefix` select.
388462
pub(crate) fn crawler_options(&self) -> socket_patch_core::crawlers::CrawlerOptions {

0 commit comments

Comments
 (0)