1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
//! What:
//! The reference locks a killed Git left behind: found, judged one by one, removed when their holder is proven gone, and
//! otherwise described with the command that clears them.
//! Why:
//! A Git killed in the middle of a ref update (a terminal closed mid-fetch, the out-of-memory killer, a reboot) leaves an
//! empty `<ref>.lock` or `packed-refs.lock`, and every later fetch or push of the same reference then fails with
//! "Unable to create ... File exists". Git writes no process number into a lock and removes none it did not create, and a
//! live Git holds its locks with no descriptor open (`refs/packed-backend.c:1254-1261`, `refs/files-backend.c:2888-2897`),
//! so a lock is removed only on a proof (`SPEC.md`, "Reference locks left by a Git that was killed"): the process its pid
//! file names is gone or was reused, or the lock predates the boot. Everything else is left alone and reported.
//! This module extends the sweep of a stopped child's locks (`stopped_git_locks.rs`) to locks no wrapper-started child
//! explains; it reads files and `/proc` in process and starts no Git.
//!
//! In TS you'd write (pseudocode):
//! ```ts
//! const outcome = clearStaleRefLocks(rootsOfCommand(command), Judge.here());
//! if (outcome.clearedAny()) await runAgain(command); else process.stderr.write(outcome.notice());
//! ```
/// The Git directories a command works in.
use crateroots_of_command;
/// How a candidate is judged and what a judgement can say.
pub use crate;
/// The shapes of a finding and of the outcome of one clearing.
pub use crate;
/// Candidates are found here.
use crateref_lock_candidates;
/// Judging and removing one candidate.
use cratejudge_and_clear;
/// The command whose repository is searched.
use Command;
/// The candidates of the repository a command will run in, judged, and the provably stale ones removed.
///
/// In TS you'd write (pseudocode):
/// ```ts
/// function clearStaleRefLocksFor(command: Command, judge: Judge): Outcome;
/// ```
/// What:
/// Judge every reference lock below the given Git directories, remove the ones whose holder is proven gone, and report
/// the rest.
/// Why:
/// One entry for every caller, so the person's forwarded `git fetch`, the commit service's push and the stacked push all
/// decide by the same rule and word their notices the same way.
///
/// In TS you'd write (pseudocode):
/// ```ts
/// function clearStaleRefLocks(roots: string[], judge: Judge): Outcome;
/// ```
/// Controls for the clearing are in the test module.