Add explicit read-only mixed source8 CLI checking
This commit is contained in:
+66
-11
@@ -170,6 +170,47 @@ fn disk_error(report: &mut Report, error: SourceFileError) {
|
||||
report.fail(3, code, error.to_string());
|
||||
}
|
||||
|
||||
/// Validate captured mixed source8 bytes without creating an editable candidate.
|
||||
pub fn check_mixed(entry: &Path) -> Report {
|
||||
let mut report = Report::empty(entry, "check-mixed");
|
||||
let snapshot = match source_files::load_mixed_source(entry, LIMITS) {
|
||||
Ok(snapshot) => snapshot,
|
||||
Err(error) => {
|
||||
disk_error(&mut report, error);
|
||||
return report;
|
||||
}
|
||||
};
|
||||
let diagnostics = if snapshot.diagnostics().is_empty() {
|
||||
match language::check_mixed_bundle(snapshot.bundle(), LIMITS) {
|
||||
Ok(checked) => checked.warnings().to_vec(),
|
||||
Err(errors) => errors,
|
||||
}
|
||||
} else {
|
||||
snapshot.diagnostics().to_vec()
|
||||
};
|
||||
if diagnostics
|
||||
.iter()
|
||||
.any(|d| d.diagnostic.severity == Severity::Error)
|
||||
{
|
||||
report.status = "invalid".into();
|
||||
report.exit_code = if diagnostics.iter().any(|d| {
|
||||
matches!(
|
||||
d.diagnostic.code.as_str(),
|
||||
"pending_save" | "missing_include" | "invalid_path"
|
||||
)
|
||||
}) {
|
||||
3
|
||||
} else {
|
||||
1
|
||||
};
|
||||
}
|
||||
report.diagnostics = diagnostics
|
||||
.into_iter()
|
||||
.map(|d| located(d, "input"))
|
||||
.collect();
|
||||
report
|
||||
}
|
||||
|
||||
/// A candidate owns its original expectations and is consumed by saving.
|
||||
/// Callers cannot replace its source/model/expectations after preparation.
|
||||
pub struct Prepared {
|
||||
@@ -406,14 +447,19 @@ fn unified_diff(path: &str, before: &str, after: &str) -> String {
|
||||
out
|
||||
}
|
||||
|
||||
/// Read-only mixed checking cannot acquire ordinary edit/write authority.
|
||||
pub enum Dispatch {
|
||||
Editable { operation: Operation, write: bool },
|
||||
CheckMixed,
|
||||
}
|
||||
|
||||
pub struct Arguments {
|
||||
pub entry: PathBuf,
|
||||
pub operation: Operation,
|
||||
pub write: bool,
|
||||
pub dispatch: Dispatch,
|
||||
pub json: bool,
|
||||
}
|
||||
|
||||
pub const HELP: &str = "arcadia check ROOT [--json]\narcadia lint ROOT [--json]\narcadia stabilize ROOT [--write] [--json]\narcadia rename-alias ROOT OLD NEW [--write] [--json]\n\nROOT is an explicit .arcadia entry file; includes resolve relative to it.\nMutation commands preview by default. --write applies this invocation's candidate.\nMissing UUIDs in a preview are provisional until written. No canonical formatting.\nExit: 0 valid/success (engineering warnings allowed), 1 invalid source or semantic\ncommand rejection, 2 usage, 3 disk/path/conflict/pending-journal/output failure.\nNo implicit journal recovery. Limits: 64 MiB, 256 files, include depth32/edges1024,\n100000 graph objects, 250000 records, 500000 ordered references.\n";
|
||||
pub const HELP: &str = "arcadia check ROOT [--json]\narcadia lint ROOT [--json]\narcadia check-mixed ROOT [--json]\narcadia stabilize ROOT [--write] [--json]\narcadia rename-alias ROOT OLD NEW [--write] [--json]\n\nROOT is an explicit .arcadia entry file; includes resolve relative to it.\ncheck-mixed requires source8 and explicit UUIDs; it never migrates, stabilizes or writes.\nMutation commands preview by default. --write applies this invocation's candidate.\nMissing UUIDs in a preview are provisional until written. No canonical formatting.\nExit: 0 valid/success (engineering warnings allowed), 1 invalid source or semantic\ncommand rejection, 2 usage, 3 disk/path/conflict/pending-journal/output failure.\nNo implicit journal recovery. Limits: 64 MiB, 256 files, include depth32/edges1024,\n100000 graph objects, 250000 records, 500000 ordered references.\n";
|
||||
|
||||
pub fn arguments(args: &[std::ffi::OsString]) -> Result<Arguments, String> {
|
||||
let mut positional = Vec::new();
|
||||
@@ -433,19 +479,28 @@ pub fn arguments(args: &[std::ffi::OsString]) -> Result<Arguments, String> {
|
||||
}
|
||||
}
|
||||
let command = positional.first().and_then(|s| s.to_str()).unwrap_or("");
|
||||
let operation = match (command, positional.len()) {
|
||||
("check" | "lint", 2) if !write => Operation::Check,
|
||||
("stabilize", 2) => Operation::Stabilize,
|
||||
("rename-alias", 4) => Operation::RenameAlias {
|
||||
old: positional[2].to_str().ok_or("Alias must be UTF-8")?.into(),
|
||||
new: positional[3].to_str().ok_or("Alias must be UTF-8")?.into(),
|
||||
let dispatch = match (command, positional.len()) {
|
||||
("check-mixed", 2) if !write => Dispatch::CheckMixed,
|
||||
("check" | "lint", 2) if !write => Dispatch::Editable {
|
||||
operation: Operation::Check,
|
||||
write,
|
||||
},
|
||||
("stabilize", 2) => Dispatch::Editable {
|
||||
operation: Operation::Stabilize,
|
||||
write,
|
||||
},
|
||||
("rename-alias", 4) => Dispatch::Editable {
|
||||
operation: Operation::RenameAlias {
|
||||
old: positional[2].to_str().ok_or("Alias must be UTF-8")?.into(),
|
||||
new: positional[3].to_str().ok_or("Alias must be UTF-8")?.into(),
|
||||
},
|
||||
write,
|
||||
},
|
||||
_ => return Err(HELP.into()),
|
||||
};
|
||||
Ok(Arguments {
|
||||
entry: PathBuf::from(positional[1]),
|
||||
operation,
|
||||
write,
|
||||
dispatch,
|
||||
json,
|
||||
})
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user