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
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
//! What:
//! The shapes the wrapper's existing queries answer with, built from an in-process `RepoLayout`.
//! Why:
//! Each caller keeps its own result type; the adapter is the one place that says how a layout becomes a
//! `RepositoryLocation`, a `LandingLocation` or a sequencer state, so a caller tries the layout first and asks Git
//! only when the layout declines.
//!
//! In TS you'd write (pseudocode):
//! ```ts
//! const location = locationOf(layout); // same value `parseLocationOutput(rev-parse output)` gives
//! ```
use super::landing_location::LandingLocation;
use super::repo_read_layout::{RepoLayout, git_path};
use super::repository_location::RepositoryLocation;
use super::rule_commit_sequencer::{SequencerFacts, SequencerState, sequencer_state};
use super::worktree_identity::WorktreeIdentity;
/// What:
/// The location `git rev-parse` would report for this layout.
/// Why:
/// A Git directory equal to the common directory is the main worktree, any other is a linked one.
///
/// In TS you'd write (pseudocode):
/// ```ts
/// layout.gitDir === layout.commonDir ? { kind: 'main', ...paths } : { kind: 'linked', ...paths }
/// ```
pub fn location_of(layout: &RepoLayout) -> RepositoryLocation {
let identity: WorktreeIdentity = if layout.git_dir == layout.common_dir {
WorktreeIdentity::MainWorktree {
common_dir: layout.common_dir.clone(),
git_dir: layout.git_dir.clone(),
worktree_root: layout.worktree_root.clone(),
}
} else {
WorktreeIdentity::LinkedWorktree {
common_dir: layout.common_dir.clone(),
git_dir: layout.git_dir.clone(),
worktree_root: layout.worktree_root.clone(),
}
};
return RepositoryLocation { identity, prefix: layout.prefix.clone() };
}
/// What:
/// The landing location (Git directory, index, registry root) for this layout, or `None` for a layout whose
/// per-worktree and shared names Git splits.
/// Why:
/// Only a worktree that owns its Git directory has one answer per name.
///
/// In TS you'd write (pseudocode):
/// ```ts
/// { gitDir, indexPath: gitPath('index'), realIndexPath: join(gitDir, 'index'), registryRoot: gitPath('cli-git-transactions') }
/// ```
pub fn landing_of(layout: &RepoLayout) -> Option<LandingLocation> {
return Some(LandingLocation {
git_dir: layout.git_dir.clone(),
index_path: git_path(layout, "index")?,
real_index_path: layout.git_dir.join("index"),
registry_root: git_path(layout, "cli-git-transactions")?,
});
}
/// What:
/// The sequencer state from the three head files of the layout's Git directory.
/// Why:
/// `MERGE_HEAD`, `CHERRY_PICK_HEAD` and `REVERT_HEAD` are per-worktree names; the state only needs whether each file exists.
///
/// In TS you'd write (pseudocode):
/// ```ts
/// sequencerState({ mergeHead: exists(gitPath('MERGE_HEAD')), cherryPickHead: ..., revertHead: ... })
/// ```
pub fn sequencer_of(layout: &RepoLayout) -> Option<SequencerState> {
let exists = |name: &str| -> Option<bool> {
let path = git_path(layout, name)?;
return Some(std::fs::symlink_metadata(path).is_ok());
};
return Some(sequencer_state(SequencerFacts {
merge_head: exists("MERGE_HEAD")?,
cherry_pick_head: exists("CHERRY_PICK_HEAD")?,
revert_head: exists("REVERT_HEAD")?,
}));
}
/// What:
/// The seven-line report the invocation capture asks `rev-parse` for: top level, Git directory, common directory,
/// index, objects, transaction registry and object format, one per line.
/// Why:
/// The capture parses that text by line number, so an in-process answer is the same text and the parser stays one.
///
/// In TS you'd write (pseudocode):
/// ```ts
/// [toplevel, gitDir, commonDir, gitPath('index'), gitPath('objects'), gitPath('cli-git-transactions'), objectFormat].join('\n')
/// ```
pub fn invocation_report(layout: &RepoLayout) -> Option<String> {
let lines: [String; 7] = [
layout.worktree_root.to_str()?.to_string(),
layout.git_dir.to_str()?.to_string(),
layout.common_dir.to_str()?.to_string(),
git_path(layout, "index")?.to_str()?.to_string(),
git_path(layout, "objects")?.to_str()?.to_string(),
git_path(layout, "cli-git-transactions")?.to_str()?.to_string(),
layout.object_format.name().to_string(),
];
return Some(lines.join("\n"));
}