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
use super::*;
impl Controller {
/// Where a session's repositories live on its target, and what each one
/// contributes to an export.
///
/// A checkpoint and a diff, a file read or a branch push all need the same
/// answers - which target, which directory, which repository is the
/// primary - so they are derived once here rather than restated wherever a
/// caller reaches the target.
pub fn session_export_layout(
&self,
session_id: &str,
executor: &(impl CommandExecutor + Sync),
) -> Result<SessionExportLayout> {
let session = self
.state
.sessions
.get(session_id)
.with_context(|| format!("unknown session {session_id}"))?
.clone();
let locator = session
.target
.as_ref()
.context("session has no live target")?;
let backend = backend_locator(locator, &session, &self.config)?;
let (workspace_root, primary_repository, repositories) = if let Some(project_directory) =
&session.project_directory
{
let parent = project_directory
.parent()
.context("bare project directory has no parent")?;
let destination = project_directory
.file_name()
.context("bare project directory cannot be the filesystem root")?;
(
parent.to_string_lossy().into_owned(),
"project".to_owned(),
vec![CheckpointRepositorySpec {
id: "project".into(),
relative_destination: PathBuf::from(destination),
// Managed worktrees are retired on Stop, so their
// dirty/untracked state must travel in the archive.
// Capturing from the branch's creation point means the
// bundle also carries the session's own commits. The
// branch and objects remain in the owning Git
// repository as well; no remote origin is required.
// Unmanaged raw checkouts remain in place.
capture: match &session.managed_worktree {
Some(worktree) => CheckpointRepositoryCapture::DeltaFrom {
base_commit: crate::controller::worktree::managed_worktree_base_commit(
worktree, executor,
)?,
},
None => CheckpointRepositoryCapture::MetadataOnly,
},
origin_override: None,
}],
)
} else {
let bundle = self
.config
.bundles
.get(&session.bundle_id)
.context("session bundle is missing")?;
let workspace_root = crate::controller::network_git::workspace_root(
&backend,
session.container_workspace.as_deref(),
);
let repositories = bundle
.repositories
.iter()
.map(|repository| CheckpointRepositorySpec {
id: repository.id.clone(),
relative_destination: repository.destination.clone(),
capture: CheckpointRepositoryCapture::RemoteWorkspace,
origin_override: None,
})
.collect();
(workspace_root, bundle.primary_repo.clone(), repositories)
};
Ok(SessionExportLayout {
backend,
workspace_root,
primary_repository,
repositories,
managed_worktree: session.managed_worktree,
})
}
}