1use std::path::Path;
16
17pub const LOG_COMMAND: &str = "journalctl --user --unit cli-git.service";
19
20pub const LINGER_COMMAND: &str = "loginctl enable-linger";
22
23pub const CHECK_COMMANDS: [&str; 2] = ["git log -1", "git status"];
25
26pub const STARTING_NOTICE: &str = "Starting the commit service...";
28
29pub const UPDATING_NOTICE: &str = "Updating the commit service...";
31
32#[derive(Clone, Copy, Debug, Eq, PartialEq)]
42pub enum Platform {
43 Windows,
45 Bsd,
47 LinuxWithoutUserServices,
49 Other,
51}
52
53#[derive(Clone, Debug, Eq, PartialEq)]
63pub enum ClientFailure {
64 DidNotStart,
66 NoActivation(Platform),
68 OtherAccount,
70 MayNotHaveLanded,
72 NoCommonVersion,
74 RepositoryFull(String),
76 RepositoryReadOnly(String),
78 BranchKeepsChanging { branch: String, times: usize },
80 BranchMoved { branch: String },
82 BranchMovedMessageSaved { branch: String, file: String, amend: bool },
84 WaitedTooLong { minutes: u64 },
86 Refused,
88 IndexInUse(String),
90 Unavailable,
92 ProgramMissing(String),
94 CouldNotStart(String),
96 UnitInTheWay(String),
98 WorkNotHandedOver(String),
100}
101
102const NOTHING_CHANGED: &str = "Nothing in the repository changed.";
104
105pub fn render(failure: &ClientFailure) -> String {
115 return match failure {
116 ClientFailure::DidNotStart => format!(
117 "The commit service did not start, so this commit was not made. Its log shows why: `{LOG_COMMAND}`. \
118 Run the commit again after fixing that. {NOTHING_CHANGED}"
119 ),
120 ClientFailure::NoActivation(platform) => format!(
121 "This computer cannot start the commit service on demand, so this commit was not made. {} {NOTHING_CHANGED}",
122 platform_remedy(*platform)
123 ),
124 ClientFailure::OtherAccount => format!(
125 "Another account runs the commit service here, so this commit was not made. Use your own account, or ask \
126 the other account to stop its service, then run the commit again. {NOTHING_CHANGED}"
127 ),
128 ClientFailure::MayNotHaveLanded => format!(
129 "The commit service stopped before it confirmed this commit. Run `{}` to see whether it was made, and `{}` \
130 to see what is still staged. If it was not made, run the commit again.",
131 CHECK_COMMANDS[0], CHECK_COMMANDS[1]
132 ),
133 ClientFailure::NoCommonVersion => format!(
134 "This git is older than the installed commit service and cannot work with it, so this commit was not made. \
135 Update the git wrapper with the tool that installed it, and run the commit again. {NOTHING_CHANGED}"
136 ),
137 ClientFailure::RepositoryFull(path) => format!(
138 "There is no space left for {path}, so this commit was not made. Free some space and run the commit again. \
139 {NOTHING_CHANGED}"
140 ),
141 ClientFailure::RepositoryReadOnly(path) => format!(
142 "{path} cannot be written to, so this commit was not made. Make the repository writable (check its \
143 permissions and whether the disk is mounted read-only) and run the commit again. {NOTHING_CHANGED}"
144 ),
145 ClientFailure::BranchKeepsChanging { branch, times } => format!(
146 "The branch {branch} changed {times} times while this commit was being prepared, so it was not made. Run \
147 the commit again; if other people commit to the same branch at the same moment, it will succeed once they \
148 pause. {NOTHING_CHANGED}"
149 ),
150 ClientFailure::BranchMoved { branch } => format!(
151 "The branch {branch} moved while this commit was being prepared, and a commit that replaces the last one, or one \
152 that was written or signed by hand, cannot be moved onto a different last commit, so it was not made. Run the \
153 commit again to make it on the branch as it is now. {NOTHING_CHANGED}"
154 ),
155 ClientFailure::BranchMovedMessageSaved { branch, file, amend } => format!(
156 "The branch {branch} moved while this commit was being prepared, so it was not made. The message you wrote is saved \
157 in {file}. Run `git commit {}-F {file}` to make the commit on the branch as it is now. {NOTHING_CHANGED}",
158 if *amend { "--amend " } else { "" }
159 ),
160 ClientFailure::WaitedTooLong { minutes } => format!(
161 "This commit waited {minutes} minutes behind other commits and was not made. Run it again later, or raise \
162 the waiting limit in the settings for the wrapper. {NOTHING_CHANGED}"
163 ),
164 ClientFailure::Refused => format!(
165 "The commit service refused this commit because it names a path or a value that cannot be committed, so it \
166 was not made. Check the paths you passed to the commit. {NOTHING_CHANGED}"
167 ),
168 ClientFailure::IndexInUse(holder) => format!(
169 "{holder} is using this repository's index, so this commit was not made. Wait for it to finish, or close \
170 it, and run the commit again. {NOTHING_CHANGED}"
171 ),
172 ClientFailure::ProgramMissing(path) => format!(
173 "The commit service program was not found at {path}, so this commit was not made. Reinstall the git wrapper \
174 with the tool that installed it, so that the program sits next to it, then run the commit again. \
175 {NOTHING_CHANGED}"
176 ),
177 ClientFailure::UnitInTheWay(path) => format!(
178 "The file `{path}` has the name of a settings file of the commit service but was not written by the git wrapper, \
179 so the commit service could not be set up and this commit was not made. Move or delete that file, then run the \
180 commit again. {NOTHING_CHANGED}"
181 ),
182 ClientFailure::WorkNotHandedOver(reason) => format!(
183 "Your commit is saved. Its backup push and upkeep could not be handed to the commit service: {reason}. \
184 Run `git push` when ready."
185 ),
186 ClientFailure::CouldNotStart(reason) => format!(
187 "The commit service could not be set up, so this commit was not made: {reason}. Fix that and run the commit \
188 again. {NOTHING_CHANGED}"
189 ),
190 ClientFailure::Unavailable => format!(
191 "The commit service could not finish this commit, so it was not made. Run the commit again; if it fails \
192 again, look at the service's log with `{LOG_COMMAND}`. {NOTHING_CHANGED}"
193 ),
194 };
195}
196
197pub fn platform_remedy(platform: Platform) -> String {
207 return match platform {
208 Platform::Windows => String::from(
209 "Committing through this wrapper is not supported on Windows yet. Use the Linux or macOS machine for commits \
210 to this repository.",
211 ),
212 Platform::Bsd => String::from(
213 "Committing through this wrapper is not supported on this system yet. Use a Linux or macOS machine for \
214 commits to this repository.",
215 ),
216 Platform::LinuxWithoutUserServices => format!(
217 "This account has no user service manager. Turn it on with `{LINGER_COMMAND}` (the system must run \
218 systemd), or commit from a system that does."
219 ),
220 Platform::Other => String::from(
221 "Committing through this wrapper is not supported on this system. Use a Linux or macOS machine for \
222 commits to this repository.",
223 ),
224 };
225}
226
227pub fn position_notice(number: usize, of: usize) -> String {
237 let ahead: usize = number.saturating_sub(1);
238 let _ = of;
239 return match ahead {
240 0 => String::from("This commit is next."),
241 1 => String::from("Waiting for 1 earlier commit."),
242 many => format!("Waiting for {many} earlier commits."),
243 };
244}
245
246pub fn push_failed_notice(commit: &str, said: &str) -> String {
257 let short: &str = commit.get(..7).unwrap_or(commit);
258 let detail: String = if said.is_empty() { String::from("Git gave no reason.") } else { format!("Git said: {said}") };
259 return format!(
260 "The backup push of your commit {short} failed, so it exists only on this computer for now. {detail} The commit \
261 service runs with its own settings, not your terminal's, so a push that works in your terminal can fail here \
262 when it needs a variable your terminal has. Run `git push` when ready."
263 );
264}
265
266pub const DENYLIST: [&str; 22] = [
269 "protocol", "journal", "request id", "daemon", "socket", "errno", "epipe", "econnrefused", "eagain", "flock",
270 "lock file", "peer", "frame", "handshake", "batch", "oid", "fast-import", "unix domain", "abstract", "pid",
271 "uid", "os error",
272];
273
274pub fn path_text(path: &Path) -> String {
276 return path.display().to_string();
277}
278
279#[cfg(test)]
281#[path = "service_messages_tests.rs"]
282mod tests;