patch: fill in the loop verbs, and test them
Every patch verb outside the series work is real. check reads the working tree through checkpatch's stdin, which is the only way it can read one, since --git with no revision dies; format puts --fix-inplace's output back into the tree after setting the uncommitted change aside, and restores it if the fix does not apply; commit and create sit on git; create writes a mail-formatted patch, because git send-email refuses a bare diff with "No subject line"; submit splits get_maintainer.pl's roles into To and Cc, prints the command line it is about to run, and only sends when --dry-run is off; update re-rolls a patch by renaming it and does nothing at the revision it is already at. git.rs grows the plumbing those verbs stand on: diff_unstaged, format_patch, apply, commit, rev_parse. apply feeds the patch in on stdin, so a fixed patch stays in memory until it is known to apply. tests/ holds a fixture kernel tree, so the suite needs no kernel tree, no network, and no configured git send-email. The two tests that do want the host's own checkpatch and get_maintainer are ignored unless asked for, and one of them earned its place immediately: checkpatch's --file means "this argument is source code", so checking a patch with it reported a dirty patch as clean, 8004 lines and no errors. Patchfile mode is checkpatch's default and the path now stands alone. patch check also takes --rev, which is how a committed range gets checked. Checked with cargo fmt --check, cargo clippy --all-targets -- -D warnings, cargo test, and cargo doc --no-deps.
This commit is contained in:
+38
-3
@@ -4,13 +4,18 @@
|
||||
//! call site, and is printed once by `main`.
|
||||
|
||||
use std::path::PathBuf;
|
||||
use std::process::ExitStatus;
|
||||
|
||||
/// Shorthand for the crate's result type.
|
||||
pub type Result<T, E = Error> = std::result::Result<T, E>;
|
||||
|
||||
// Variants that no command constructs yet, but that the command paths below
|
||||
// are written to return. Safe to drop the allow once they are all reached.
|
||||
#[allow(dead_code)]
|
||||
/// How a failed process is described in [`Error::ExternalCommand`].
|
||||
pub(crate) fn exit_code(status: &ExitStatus) -> String {
|
||||
status
|
||||
.code()
|
||||
.map_or_else(|| "signal".to_owned(), |code| code.to_string())
|
||||
}
|
||||
|
||||
#[derive(Debug, thiserror::Error)]
|
||||
pub enum Error {
|
||||
/// Nothing at the configured path at all.
|
||||
@@ -42,9 +47,39 @@ pub enum Error {
|
||||
#[error("no patch named `{name}` in `{dir}`")]
|
||||
PatchNotFound { name: String, dir: PathBuf },
|
||||
|
||||
/// A revision named on the command line does not resolve.
|
||||
#[error("no revision `{rev}` in this tree; `--base` wants a branch or commit that exists")]
|
||||
UnknownRevision { rev: String },
|
||||
|
||||
/// The base is already at the tip, so there is no change to send.
|
||||
#[error("nothing to send: `{base}` and HEAD hold no commits; commit the change first")]
|
||||
NoCommitsToSend { base: String },
|
||||
|
||||
/// One patch file was asked to carry a whole set.
|
||||
#[error(
|
||||
"`{base}..HEAD` holds {count} commits; one patch file cannot carry a set (patch series support is not built yet)"
|
||||
)]
|
||||
RangeHoldsSeveralCommits { base: String, count: usize },
|
||||
|
||||
/// `--fix` was pointed at something that is not a patch file.
|
||||
#[error(
|
||||
"checkpatch only fixes a patch file; give `patch format` a patch instead of a revision"
|
||||
)]
|
||||
FixNeedsPatchFile,
|
||||
|
||||
/// checkpatch's fix could not be put into the working tree.
|
||||
#[error("the fix could not be applied ({reason}); the working tree was left as it was")]
|
||||
FixApplyFailed { reason: String },
|
||||
|
||||
/// Re-rolling would land on a file that is already there.
|
||||
#[error("`{path}` already exists; delete it or pick another revision")]
|
||||
RerollWouldOverwrite { path: PathBuf },
|
||||
|
||||
#[error(transparent)]
|
||||
Io(#[from] std::io::Error),
|
||||
|
||||
// Reached once `kernel quest` stops being a stub.
|
||||
#[allow(dead_code)]
|
||||
#[error(transparent)]
|
||||
Http(#[from] reqwest::Error),
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user