-
Notifications
You must be signed in to change notification settings - Fork 966
Expand file tree
/
Copy pathset.rs
More file actions
148 lines (138 loc) · 5.41 KB
/
set.rs
File metadata and controls
148 lines (138 loc) · 5.41 KB
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
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
// Copyright 2020-2023 The Jujutsu Authors
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// https://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
use std::collections::HashSet;
use clap_complete::ArgValueCandidates;
use clap_complete::ArgValueCompleter;
use itertools::Itertools as _;
use jj_lib::object_id::ObjectId as _;
use jj_lib::op_store::RefTarget;
use jj_lib::ref_name::RefNameBuf;
use super::is_fast_forward;
use crate::cli_util::CommandHelper;
use crate::cli_util::RevisionArg;
use crate::cli_util::has_tracked_remote_bookmarks;
use crate::command_error::CommandError;
use crate::command_error::user_error;
use crate::complete;
use crate::revset_util;
use crate::ui::Ui;
/// Create a new bookmark, or update an existing one by name
///
/// If you want to move bookmarks based on their current location rather than
/// by name, use `jj bookmark move --from <REVSETS>`.
#[derive(clap::Args, Clone, Debug)]
pub struct BookmarkSetArgs {
/// The bookmark's target revision
#[arg(
long,
short,
default_value = "@",
visible_alias = "to",
value_name = "REVSET"
)]
#[arg(add = ArgValueCompleter::new(complete::revset_expression_all))]
revision: RevisionArg,
/// Allow moving the bookmark backwards or sideways
#[arg(long, short = 'B')]
allow_backwards: bool,
/// The bookmarks to update
#[arg(required = true, value_parser = revset_util::parse_bookmark_name)]
#[arg(add = ArgValueCandidates::new(complete::local_bookmarks))]
names: Vec<RefNameBuf>,
}
pub async fn cmd_bookmark_set(
ui: &mut Ui,
command: &CommandHelper,
args: &BookmarkSetArgs,
) -> Result<(), CommandError> {
let mut workspace_command = command.workspace_helper(ui)?;
let target_commit = workspace_command.resolve_single_rev(ui, &args.revision)?;
let repo = workspace_command.repo().as_ref();
let bookmark_names = &args.names;
let mut new_bookmarks = HashSet::new();
let mut moved_bookmark_count = 0;
for name in bookmark_names {
let old_target = repo.view().get_local_bookmark(name);
// If a bookmark is absent locally but is still tracking remote bookmarks,
// we are resurrecting the local bookmark, not "creating" a new bookmark.
if old_target.is_absent() && !has_tracked_remote_bookmarks(repo, name) {
new_bookmarks.insert(name);
} else if old_target.as_normal() != Some(target_commit.id()) {
moved_bookmark_count += 1;
}
if !args.allow_backwards && !is_fast_forward(repo, old_target, target_commit.id())? {
return Err(user_error(format!(
"Refusing to move bookmark backwards or sideways: {name}",
name = name.as_symbol()
))
.hinted("Use --allow-backwards to allow it."));
}
}
if target_commit.is_discardable(repo).await? {
writeln!(ui.warning_default(), "Target revision is empty.")?;
}
let mut tx = workspace_command.start_transaction();
let remote_settings = tx.settings().remote_settings()?;
let remote_auto_track_matchers =
revset_util::parse_remote_auto_track_bookmarks_map_for_new_bookmarks(ui, &remote_settings)?;
let readonly_repo = tx.base_repo().clone();
for name in bookmark_names {
tx.repo_mut()
.set_local_bookmark_target(name, RefTarget::normal(target_commit.id().clone()));
if new_bookmarks.contains(name) {
for (remote_name, matcher) in &remote_auto_track_matchers {
if !matcher.is_match(name.as_str()) {
continue;
}
let Some(view) = readonly_repo.view().get_remote_view(remote_name) else {
continue;
};
let symbol = name.to_remote_symbol(remote_name);
if view.bookmarks.contains_key(name) {
writeln!(
ui.warning_default(),
"Auto-tracking bookmark that exists on the remote: {symbol}"
)?;
}
tx.repo_mut().track_remote_bookmark(symbol)?;
}
}
}
if let Some(mut formatter) = ui.status_formatter() {
let new_bookmark_count = new_bookmarks.len();
if new_bookmark_count > 0 {
write!(
formatter,
"Created {new_bookmark_count} bookmarks pointing to "
)?;
tx.write_commit_summary(formatter.as_mut(), &target_commit)?;
writeln!(formatter)?;
}
if moved_bookmark_count > 0 {
write!(formatter, "Moved {moved_bookmark_count} bookmarks to ")?;
tx.write_commit_summary(formatter.as_mut(), &target_commit)?;
writeln!(formatter)?;
}
}
tx.finish(
ui,
format!(
"point bookmark {names} to commit {id}",
names = bookmark_names.iter().map(|n| n.as_symbol()).join(", "),
id = target_commit.id().hex()
),
)
.await?;
Ok(())
}