aboutsummaryrefslogtreecommitdiff
path: root/src/app
diff options
context:
space:
mode:
Diffstat (limited to 'src/app')
-rw-r--r--src/app/api/worktrees.rs101
-rw-r--r--src/app/api/worktrees/deferred.rs15
-rw-r--r--src/app/worktrees.rs35
3 files changed, 113 insertions, 38 deletions
diff --git a/src/app/api/worktrees.rs b/src/app/api/worktrees.rs
index 774b981a..4a3e23a8 100644
--- a/src/app/api/worktrees.rs
+++ b/src/app/api/worktrees.rs
@@ -50,11 +50,18 @@ impl App {
id: String,
params: WorktreeListParams,
) -> String {
- let source = match self.resolve_worktree_list_source(params.workspace_id, params.cwd) {
+ let source = match self.resolve_worktree_list_source(
+ params.workspace_id,
+ params.cwd,
+ params.trust_repository,
+ ) {
Ok(source) => source,
Err(err) => return encode_error(id, err.code, err.message),
};
- let entries = match crate::worktree::list_existing_worktrees(&source.source_repo_root) {
+ let entries = match crate::worktree::list_existing_worktrees(
+ &source.source_repo_root,
+ params.trust_repository,
+ ) {
Ok(entries) => entries,
Err(err) => return encode_error(id, "worktree_list_failed", err),
};
@@ -88,7 +95,12 @@ impl App {
Ok(source) => source,
Err(err) => return encode_error(id, err.code, err.message),
};
- let entry = match self.find_worktree_entry(&source, params.path, params.branch) {
+ let entry = match self.find_worktree_entry(
+ &source,
+ params.path,
+ params.branch,
+ params.trust_repository,
+ ) {
Ok(entry) => entry,
Err(err) => return encode_error(id, err.code, err.message),
};
@@ -235,6 +247,7 @@ impl App {
&mut self,
workspace_id: Option<String>,
cwd: Option<String>,
+ trust_repository: bool,
) -> Result<WorktreeSource, ApiFailure> {
if workspace_id.is_some() && cwd.is_some() {
return Err(ApiFailure::new(
@@ -250,7 +263,7 @@ impl App {
format!("workspace {workspace_id} not found"),
));
};
- return self.worktree_list_source_from_workspace(ws_idx);
+ return self.worktree_list_source_from_workspace(ws_idx, trust_repository);
}
if let Some(cwd) = cwd {
@@ -261,8 +274,13 @@ impl App {
"Herdr worktree actions require a path inside a Git work tree",
)
})?;
- let workspace_idx = self.list_source_workspace_idx_for_space(&space);
- return Ok(worktree_source_from_space(space, workspace_idx, true));
+ let workspace_idx = self.list_source_workspace_idx_for_space(&space, trust_repository);
+ return Ok(worktree_source_from_space(
+ space,
+ workspace_idx,
+ true,
+ trust_repository,
+ ));
}
let Some(ws_idx) = self.state.active.or_else(|| {
@@ -276,7 +294,7 @@ impl App {
"workspace_id or cwd is required when no workspace is active",
));
};
- self.worktree_list_source_from_workspace(ws_idx)
+ self.worktree_list_source_from_workspace(ws_idx, trust_repository)
}
fn worktree_source_from_workspace(&self, ws_idx: usize) -> Result<WorktreeSource, ApiFailure> {
@@ -331,6 +349,7 @@ impl App {
fn worktree_list_source_from_workspace(
&self,
ws_idx: usize,
+ trust_repository: bool,
) -> Result<WorktreeSource, ApiFailure> {
let Some(ws) = self.state.workspaces.get(ws_idx) else {
return Err(ApiFailure::new(
@@ -370,11 +389,16 @@ impl App {
));
};
let workspace_idx = if space.is_linked_worktree {
- self.list_source_workspace_idx_for_space(&space)
+ self.list_source_workspace_idx_for_space(&space, trust_repository)
} else {
Some(ws_idx)
};
- Ok(worktree_source_from_space(space, workspace_idx, true))
+ Ok(worktree_source_from_space(
+ space,
+ workspace_idx,
+ true,
+ trust_repository,
+ ))
}
fn ensure_source_parent_membership(
@@ -415,9 +439,10 @@ impl App {
fn list_source_workspace_idx_for_space(
&self,
space: &crate::workspace::GitSpaceMetadata,
+ trust_repository: bool,
) -> Option<usize> {
if space.is_linked_worktree {
- let parent_checkout = parent_checkout_path_for_space(space);
+ let parent_checkout = parent_checkout_path_for_space(space, trust_repository);
self.open_workspace_idx_for_checkout(&parent_checkout)
} else {
self.find_parent_workspace_for_space(space)
@@ -475,9 +500,11 @@ impl App {
source: &WorktreeSource,
path: Option<String>,
branch: Option<String>,
+ trust_repository: bool,
) -> Result<crate::worktree::ExistingWorktree, ApiFailure> {
- let entries = crate::worktree::list_existing_worktrees(&source.source_repo_root)
- .map_err(|err| ApiFailure::new("worktree_list_failed", err))?;
+ let entries =
+ crate::worktree::list_existing_worktrees(&source.source_repo_root, trust_repository)
+ .map_err(|err| ApiFailure::new("worktree_list_failed", err))?;
if let Some(path) = path {
let expected = absolute_user_path(&path)?;
let expected = crate::worktree::canonical_or_original(&expected);
@@ -667,9 +694,10 @@ fn worktree_source_from_space(
space: crate::workspace::GitSpaceMetadata,
workspace_idx: Option<usize>,
allow_linked: bool,
+ trust_repository: bool,
) -> WorktreeSource {
let source_checkout_path = if allow_linked {
- parent_checkout_path_for_space(&space)
+ parent_checkout_path_for_space(&space, trust_repository)
} else {
space.repo_root.clone()
};
@@ -682,12 +710,15 @@ fn worktree_source_from_space(
}
}
-fn parent_checkout_path_for_space(space: &crate::workspace::GitSpaceMetadata) -> PathBuf {
+fn parent_checkout_path_for_space(
+ space: &crate::workspace::GitSpaceMetadata,
+ trust_repository: bool,
+) -> PathBuf {
if !space.is_linked_worktree {
return space.repo_root.clone();
}
- crate::worktree::list_existing_worktrees(&space.repo_root)
+ crate::worktree::list_existing_worktrees(&space.repo_root, trust_repository)
.ok()
.and_then(|entries| {
entries.into_iter().find_map(|entry| {
@@ -957,8 +988,12 @@ mod tests {
for (_, runtime) in app.terminal_runtimes.drain() {
runtime.shutdown();
}
- let remove =
- crate::worktree::build_worktree_remove_command(&repo, Path::new(&worktree.path), false);
+ let remove = crate::worktree::build_worktree_remove_command(
+ &repo,
+ Path::new(&worktree.path),
+ false,
+ false,
+ );
crate::worktree::run_worktree_command(&remove).unwrap();
let _ = std::fs::remove_dir_all(worktree_root);
let _ = std::fs::remove_dir_all(repo);
@@ -1271,8 +1306,12 @@ mod tests {
for (_, runtime) in app.terminal_runtimes.drain() {
runtime.shutdown();
}
- let remove =
- crate::worktree::build_worktree_remove_command(&repo, Path::new(&worktree.path), false);
+ let remove = crate::worktree::build_worktree_remove_command(
+ &repo,
+ Path::new(&worktree.path),
+ false,
+ false,
+ );
crate::worktree::run_worktree_command(&remove).unwrap();
let _ = std::fs::remove_dir_all(worktree_root);
let _ = std::fs::remove_dir_all(repo);
@@ -1440,7 +1479,7 @@ mod tests {
)
}));
- let remove = crate::worktree::build_worktree_remove_command(&repo, &checkout, false);
+ let remove = crate::worktree::build_worktree_remove_command(&repo, &checkout, false, false);
crate::worktree::run_worktree_command(&remove).unwrap();
let _ = std::fs::remove_dir_all(repo);
}
@@ -1518,7 +1557,7 @@ mod tests {
)
}));
- let remove = crate::worktree::build_worktree_remove_command(&repo, &checkout, false);
+ let remove = crate::worktree::build_worktree_remove_command(&repo, &checkout, false, false);
crate::worktree::run_worktree_command(&remove).unwrap();
let _ = std::fs::remove_dir_all(repo);
}
@@ -1603,6 +1642,7 @@ mod tests {
method: crate::api::schema::Method::WorktreeList(WorktreeListParams {
workspace_id: Some(app.state.workspaces[0].id.clone()),
cwd: None,
+ trust_repository: false,
}),
});
@@ -1620,7 +1660,7 @@ mod tests {
);
assert!(entry.is_linked_worktree);
- let remove = crate::worktree::build_worktree_remove_command(&repo, &checkout, false);
+ let remove = crate::worktree::build_worktree_remove_command(&repo, &checkout, false, false);
crate::worktree::run_worktree_command(&remove).unwrap();
let _ = std::fs::remove_dir_all(repo);
}
@@ -1653,10 +1693,12 @@ mod tests {
crate::api::schema::Method::WorktreeList(WorktreeListParams {
workspace_id: Some(child_id),
cwd: None,
+ trust_repository: false,
}),
crate::api::schema::Method::WorktreeList(WorktreeListParams {
workspace_id: None,
cwd: Some(checkout.display().to_string()),
+ trust_repository: false,
}),
] {
let response = app.handle_api_request(Request {
@@ -1681,7 +1723,7 @@ mod tests {
}));
}
- let remove = crate::worktree::build_worktree_remove_command(&repo, &checkout, false);
+ let remove = crate::worktree::build_worktree_remove_command(&repo, &checkout, false, false);
crate::worktree::run_worktree_command(&remove).unwrap();
let _ = std::fs::remove_dir_all(repo);
}
@@ -1710,6 +1752,7 @@ mod tests {
method: crate::api::schema::Method::WorktreeList(WorktreeListParams {
workspace_id: Some(app.state.workspaces[0].id.clone()),
cwd: None,
+ trust_repository: false,
}),
});
@@ -1767,6 +1810,7 @@ mod tests {
method: crate::api::schema::Method::WorktreeRemove(WorktreeRemoveParams {
workspace_id: child_id.clone(),
force: false,
+ trust_repository: false,
}),
},
);
@@ -1782,6 +1826,7 @@ mod tests {
method: crate::api::schema::Method::WorktreeRemove(WorktreeRemoveParams {
workspace_id: child_id,
force: true,
+ trust_repository: false,
}),
},
);
@@ -1838,6 +1883,7 @@ mod tests {
method: crate::api::schema::Method::WorktreeRemove(WorktreeRemoveParams {
workspace_id: child_id.clone(),
force: false,
+ trust_repository: false,
}),
},
);
@@ -1923,6 +1969,7 @@ mod tests {
method: crate::api::schema::Method::WorktreeRemove(WorktreeRemoveParams {
workspace_id: child_id.clone(),
force: false,
+ trust_repository: false,
}),
},
respond_to,
@@ -1996,6 +2043,7 @@ mod tests {
method: crate::api::schema::Method::WorktreeRemove(WorktreeRemoveParams {
workspace_id: child_id.clone(),
force: false,
+ trust_repository: false,
}),
},
first_tx,
@@ -2006,6 +2054,7 @@ mod tests {
method: crate::api::schema::Method::WorktreeRemove(WorktreeRemoveParams {
workspace_id: child_id,
force: false,
+ trust_repository: false,
}),
},
second_tx,
@@ -2065,6 +2114,7 @@ mod tests {
method: crate::api::schema::Method::WorktreeRemove(WorktreeRemoveParams {
workspace_id: first_id,
force: true,
+ trust_repository: false,
}),
},
first_tx,
@@ -2075,6 +2125,7 @@ mod tests {
method: crate::api::schema::Method::WorktreeRemove(WorktreeRemoveParams {
workspace_id: second_id,
force: true,
+ trust_repository: false,
}),
},
second_tx,
@@ -2110,6 +2161,7 @@ mod tests {
path: Some(checkout.display().to_string()),
label: None,
focus: false,
+ trust_repository: false,
}),
},
respond_to,
@@ -2164,6 +2216,7 @@ mod tests {
method: crate::api::schema::Method::WorktreeRemove(WorktreeRemoveParams {
workspace_id: child_id,
force: false,
+ trust_repository: false,
}),
},
respond_to,
@@ -2175,7 +2228,7 @@ mod tests {
let error: ErrorResponse = serde_json::from_str(&response).unwrap();
assert_eq!(error.error.code, "worktree_operation_in_progress");
assert!(app.event_rx.try_recv().is_err());
- let remove = crate::worktree::build_worktree_remove_command(&repo, &checkout, true);
+ let remove = crate::worktree::build_worktree_remove_command(&repo, &checkout, true, false);
let _ = crate::worktree::run_worktree_command(&remove);
let _ = std::fs::remove_dir_all(repo);
}
diff --git a/src/app/api/worktrees/deferred.rs b/src/app/api/worktrees/deferred.rs
index 3cd5e9f1..4755b38d 100644
--- a/src/app/api/worktrees/deferred.rs
+++ b/src/app/api/worktrees/deferred.rs
@@ -199,6 +199,7 @@ impl App {
&path,
&branch,
&base,
+ params.trust_repository,
)
});
let _ = event_tx.blocking_send(AppEvent::WorktreeAddFinished(Box::new(
@@ -259,7 +260,11 @@ impl App {
#[cfg(windows)]
{
if !params.force
- && crate::worktree::checkout_has_dirty_files(&space.checkout_path).unwrap_or(false)
+ && crate::worktree::checkout_has_dirty_files(
+ &space.checkout_path,
+ params.trust_repository,
+ )
+ .unwrap_or(false)
{
Self::send_api_response(
respond_to,
@@ -311,6 +316,7 @@ impl App {
&space.repo_root,
&space.checkout_path,
params.force,
+ params.trust_repository,
);
let api_request = ApiWorktreeRemoveRequest {
id,
@@ -321,10 +327,15 @@ impl App {
let repo_root = space.repo_root;
let path = space.checkout_path;
let force = params.force;
+ let trust_repository = params.trust_repository;
let event_tx = self.event_tx.clone();
std::thread::spawn(move || {
let result = crate::worktree::run_worktree_remove_command_with_recovery(
- &command, &repo_root, &path, force,
+ &command,
+ &repo_root,
+ &path,
+ force,
+ trust_repository,
);
let _ = event_tx.blocking_send(AppEvent::WorktreeRemoveFinished(Box::new(
crate::events::WorktreeRemoveResult {
diff --git a/src/app/worktrees.rs b/src/app/worktrees.rs
index 414d74b5..9993a70e 100644
--- a/src/app/worktrees.rs
+++ b/src/app/worktrees.rs
@@ -161,7 +161,7 @@ impl App {
}
};
- let list = match crate::worktree::list_existing_worktrees(&space.repo_root) {
+ let list = match crate::worktree::list_existing_worktrees(&space.repo_root, false) {
Ok(list) => list,
Err(err) => {
self.state.config_diagnostic = Some(err);
@@ -551,6 +551,7 @@ impl App {
&path,
&branch,
"HEAD",
+ false,
)
});
let _ = event_tx.blocking_send(AppEvent::WorktreeAddFinished(Box::new(
@@ -599,6 +600,7 @@ impl App {
base: Some("HEAD".into()),
focus: true,
label: None,
+ trust_repository: false,
},
);
if let Some(message) = immediate_api_error_message(immediate_response.as_deref()) {
@@ -641,7 +643,8 @@ impl App {
}
#[cfg(windows)]
if !remove.force_confirmation
- && crate::worktree::checkout_has_dirty_files(&remove.path).unwrap_or(false)
+ && crate::worktree::checkout_has_dirty_files(&remove.path, false)
+ .unwrap_or(false)
{
remove.force_confirmation = true;
remove.error = None;
@@ -686,12 +689,13 @@ impl App {
})
.unwrap_or((None, None));
- let command = crate::worktree::build_worktree_remove_command(&repo_root, &path, force);
+ let command =
+ crate::worktree::build_worktree_remove_command(&repo_root, &path, force, false);
tracing::info!(workspace_id = %workspace_id, path = %path.display(), force, "starting git worktree remove");
let event_tx = self.event_tx.clone();
std::thread::spawn(move || {
let result = crate::worktree::run_worktree_remove_command_with_recovery(
- &command, &repo_root, &path, force,
+ &command, &repo_root, &path, force, false,
);
let _ = event_tx.blocking_send(AppEvent::WorktreeRemoveFinished(Box::new(
WorktreeRemoveResult {
@@ -728,6 +732,7 @@ impl App {
branch: None,
focus: true,
label: None,
+ trust_repository: false,
},
);
if serde_json::from_str::<crate::api::schema::SuccessResponse>(&response).is_ok() {
@@ -751,7 +756,7 @@ impl App {
}
#[cfg(windows)]
if !remove.force_confirmation
- && crate::worktree::checkout_has_dirty_files(&remove.path).unwrap_or(false)
+ && crate::worktree::checkout_has_dirty_files(&remove.path, false).unwrap_or(false)
{
remove.force_confirmation = true;
remove.error = None;
@@ -767,6 +772,7 @@ impl App {
crate::api::schema::WorktreeRemoveParams {
workspace_id,
force,
+ trust_repository: false,
},
);
if let Some(message) = immediate_api_error_message(immediate_response.as_deref()) {
@@ -1831,7 +1837,7 @@ mod tests {
}));
shutdown_test_runtimes(&mut app);
- let remove = crate::worktree::build_worktree_remove_command(&repo, &checkout, false);
+ let remove = crate::worktree::build_worktree_remove_command(&repo, &checkout, false, false);
crate::worktree::run_worktree_command(&remove).unwrap();
let _ = std::fs::remove_dir_all(worktree_root);
let _ = std::fs::remove_dir_all(repo);
@@ -1929,7 +1935,7 @@ mod tests {
}
assert!(checkout.join("README.md").exists());
- let remove = crate::worktree::build_worktree_remove_command(&repo, &checkout, false);
+ let remove = crate::worktree::build_worktree_remove_command(&repo, &checkout, false, false);
crate::worktree::run_worktree_command(&remove).unwrap();
let _ = std::fs::remove_dir_all(worktree_root);
let _ = std::fs::remove_dir_all(repo);
@@ -1988,7 +1994,7 @@ mod tests {
branch
);
- let remove = crate::worktree::build_worktree_remove_command(&repo, &checkout, false);
+ let remove = crate::worktree::build_worktree_remove_command(&repo, &checkout, false, false);
crate::worktree::run_worktree_command(&remove).unwrap();
let _ = std::fs::remove_dir_all(worktree_root);
let _ = std::fs::remove_dir_all(repo);
@@ -2036,8 +2042,12 @@ mod tests {
}
assert!(checkout.join("README.md").exists());
- let remove_new =
- crate::worktree::build_worktree_remove_command(&source_checkout_path, &checkout, false);
+ let remove_new = crate::worktree::build_worktree_remove_command(
+ &source_checkout_path,
+ &checkout,
+ false,
+ false,
+ );
crate::worktree::run_worktree_command(&remove_new).unwrap();
let _ = std::fs::remove_dir_all(worktree_root);
let _ = std::fs::remove_dir_all(source_checkout_path);
@@ -2096,10 +2106,11 @@ mod tests {
}
assert!(checkout.join("SOURCE.md").exists());
- let remove_new = crate::worktree::build_worktree_remove_command(&repo, &checkout, false);
+ let remove_new =
+ crate::worktree::build_worktree_remove_command(&repo, &checkout, false, false);
crate::worktree::run_worktree_command(&remove_new).unwrap();
let remove_source =
- crate::worktree::build_worktree_remove_command(&repo, &source_checkout, false);
+ crate::worktree::build_worktree_remove_command(&repo, &source_checkout, false, false);
crate::worktree::run_worktree_command(&remove_source).unwrap();
let _ = std::fs::remove_dir_all(worktree_root);
let _ = std::fs::remove_dir_all(repo);