use std::path::Path;
pub const LOG_COMMAND: &str = "journalctl --user --unit cli-git.service";
pub const LINGER_COMMAND: &str = "loginctl enable-linger";
pub const RESTART_COMMAND: &str = "systemctl --user restart cli-git.service";
pub const CHECK_COMMANDS: [&str; 2] = ["git log -1", "git status"];
pub const STARTING_NOTICE: &str = "Starting the commit service...";
pub const UPDATING_NOTICE: &str = "Updating the commit service...";
#[derive(Clone, Copy, Debug, Eq, PartialEq)]
pub enum Platform {
Windows,
Bsd,
LinuxWithoutUserServices,
Other,
}
#[derive(Clone, Debug, Eq, PartialEq)]
pub enum ClientFailure {
DidNotStart,
NoActivation(Platform),
OtherAccount,
MayNotHaveLanded,
NoCommonVersion,
OtherRelease,
RepositoryFull(String),
RepositoryReadOnly(String),
BranchKeepsChanging { branch: String, times: usize },
BranchMoved { branch: String },
BranchMovedMessageSaved { branch: String, file: String, amend: bool },
WaitedTooLong { minutes: u64 },
Refused,
IndexInUse(String),
Unavailable,
ProgramMissing(String),
CouldNotStart(String),
UnitInTheWay(String),
WorkNotHandedOver(String),
ContentPruned,
}
pub const NOTHING_CHANGED: &str = "Nothing in the repository changed.";
pub fn render(failure: &ClientFailure) -> String {
return match failure {
ClientFailure::DidNotStart => format!(
"The commit service did not start, so this commit was not made. Its log shows why: `{LOG_COMMAND}`. \
Run the commit again after fixing that. {NOTHING_CHANGED}"
),
ClientFailure::NoActivation(platform) => format!(
"This computer cannot start the commit service on demand, so this commit was not made. {} {NOTHING_CHANGED}",
platform_remedy(*platform)
),
ClientFailure::OtherAccount => format!(
"Another account runs the commit service here, so this commit was not made. Use your own account, or ask \
the other account to stop its service, then run the commit again. {NOTHING_CHANGED}"
),
ClientFailure::MayNotHaveLanded => format!(
"The commit service stopped before it confirmed this commit. Run `{}` to see whether it was made, and `{}` \
to see what is still staged. If it was not made, run the commit again.",
CHECK_COMMANDS[0], CHECK_COMMANDS[1]
),
ClientFailure::NoCommonVersion => format!(
"This git is older than the installed commit service and cannot work with it, so this commit was not made. \
Update the git wrapper with the tool that installed it, and run the commit again. {NOTHING_CHANGED}"
),
ClientFailure::OtherRelease => format!(
"The commit service that is running was started from another release of this git wrapper and did not stop when \
asked, so this commit was not made. Restart it with `{RESTART_COMMAND}`, and run the commit again. {NOTHING_CHANGED}"
),
ClientFailure::RepositoryFull(path) => format!(
"There is no space left for {path}, so this commit was not made. Free some space and run the commit again. \
{NOTHING_CHANGED}"
),
ClientFailure::RepositoryReadOnly(path) => format!(
"{path} cannot be written to, so this commit was not made. Make the repository writable (check its \
permissions and whether the disk is mounted read-only) and run the commit again. {NOTHING_CHANGED}"
),
ClientFailure::BranchKeepsChanging { branch, times } => format!(
"The branch {branch} changed {times} times while this commit was being prepared, so it was not made. Run \
the commit again; if other people commit to the same branch at the same moment, it will succeed once they \
pause. {NOTHING_CHANGED}"
),
ClientFailure::BranchMoved { branch } => format!(
"The branch {branch} moved while this commit was being prepared, and a commit that replaces the last one, or one \
that was written or signed by hand, cannot be moved onto a different last commit, so it was not made. Run the \
commit again to make it on the branch as it is now. {NOTHING_CHANGED}"
),
ClientFailure::BranchMovedMessageSaved { branch, file, amend } => format!(
"The branch {branch} moved while this commit was being prepared, so it was not made. The message you wrote is saved \
in {file}. Run `git commit {}-F {file}` to make the commit on the branch as it is now. {NOTHING_CHANGED}",
if *amend { "--amend " } else { "" }
),
ClientFailure::WaitedTooLong { minutes } => format!(
"This commit waited {minutes} minutes behind other commits and was not made. Run it again later, or raise \
the waiting limit in the settings for the wrapper. {NOTHING_CHANGED}"
),
ClientFailure::Refused => format!(
"The commit service refused this commit because it names a path or a value that cannot be committed, so it \
was not made. Check the paths you passed to the commit. {NOTHING_CHANGED}"
),
ClientFailure::IndexInUse(holder) => format!(
"{holder} is using this repository's index, so this commit was not made. Wait for it to finish, or close \
it, and run the commit again. {NOTHING_CHANGED}"
),
ClientFailure::ProgramMissing(path) => format!(
"The commit service program was not found at {path}, so this commit was not made. Reinstall the git wrapper \
with the tool that installed it, so that the program sits next to it, then run the commit again. \
{NOTHING_CHANGED}"
),
ClientFailure::UnitInTheWay(path) => format!(
"The file `{path}` has the name of a settings file of the commit service but was not written by the git wrapper, \
so the commit service could not be set up and this commit was not made. Move or delete that file, then run the \
commit again. {NOTHING_CHANGED}"
),
ClientFailure::WorkNotHandedOver(reason) => format!(
"Your commit is saved. Its backup push and upkeep could not be handed to the commit service: {reason}. \
Run `git push` when ready."
),
ClientFailure::ContentPruned => format!(
"The files of this commit were removed from the repository while the commit was being made, so it was not made. \
Git removes content that no branch or index refers to yet when `git gc --prune=now` or `git prune` runs in the \
same repository, and Git's documentation says that `--prune=now` risks failures and corruption when another \
process writes to the repository at the same moment. Run the commit again once the cleanup has finished, and avoid `--prune=now` while commits are \
being made (the default `git gc` keeps new content for two weeks). If nothing like that was running, run \
`git fsck` to check the repository. {NOTHING_CHANGED}"
),
ClientFailure::CouldNotStart(reason) => format!(
"The commit service could not be set up, so this commit was not made: {reason}. Fix that and run the commit \
again. {NOTHING_CHANGED}"
),
ClientFailure::Unavailable => format!(
"The commit service could not finish this commit, so it was not made. Run the commit again; if it fails \
again, look at the service's log with `{LOG_COMMAND}`. {NOTHING_CHANGED}"
),
};
}
pub fn platform_remedy(platform: Platform) -> String {
return match platform {
Platform::Windows => String::from(
"Committing through this wrapper is not supported on Windows yet. Use the Linux or macOS machine for commits \
to this repository.",
),
Platform::Bsd => String::from(
"Committing through this wrapper is not supported on this system yet. Use a Linux or macOS machine for \
commits to this repository.",
),
Platform::LinuxWithoutUserServices => format!(
"This account has no user service manager. Turn it on with `{LINGER_COMMAND}` (the system must run \
systemd), or commit from a system that does."
),
Platform::Other => String::from(
"Committing through this wrapper is not supported on this system. Use a Linux or macOS machine for \
commits to this repository.",
),
};
}
pub fn position_notice(number: usize, of: usize) -> String {
let ahead: usize = number.saturating_sub(1);
let _ = of;
return match ahead {
0 => String::from("This commit is next."),
1 => String::from("Waiting for 1 earlier commit."),
many => format!("Waiting for {many} earlier commits."),
};
}
pub const DENYLIST: [&str; 22] = [
"protocol", "journal", "request id", "daemon", "socket", "errno", "epipe", "econnrefused", "eagain", "flock",
"lock file", "peer", "frame", "handshake", "batch", "oid", "fast-import", "unix domain", "abstract", "pid",
"uid", "os error",
];
pub fn path_text(path: &Path) -> String {
return path.display().to_string();
}
#[cfg(test)]
#[path = "service_messages_tests.rs"]
mod tests;