Martin von Zweigbergkindex: make is_ancestor() async06112543 months agoHistory
246 lines · 8.1 KB · Rust
RawDownload
// 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. mod advance;mod create;mod delete;mod forget;mod list;mod r#move;mod rename;mod set;mod track;mod untrack; use std::io; use itertools::Itertools as _;use jj_lib::backend::CommitId;use jj_lib::iter_util::fallible_any;use jj_lib::op_store::RefTarget;use jj_lib::op_store::RemoteRef;use jj_lib::ref_name::RefName;use jj_lib::ref_name::RemoteName;use jj_lib::ref_name::RemoteRefSymbol;use jj_lib::ref_name::RemoteRefSymbolBuf;use jj_lib::repo::Repo;use jj_lib::str_util::StringExpression;use jj_lib::str_util::StringMatcher;use jj_lib::view::View; use self::advance::BookmarkAdvanceArgs;use self::advance::cmd_bookmark_advance;use self::create::BookmarkCreateArgs;use self::create::cmd_bookmark_create;use self::delete::BookmarkDeleteArgs;use self::delete::cmd_bookmark_delete;use self::forget::BookmarkForgetArgs;use self::forget::cmd_bookmark_forget;use self::list::BookmarkListArgs;use self::list::cmd_bookmark_list;use self::r#move::BookmarkMoveArgs;use self::r#move::cmd_bookmark_move;use self::rename::BookmarkRenameArgs;use self::rename::cmd_bookmark_rename;use self::set::BookmarkSetArgs;use self::set::cmd_bookmark_set;use self::track::BookmarkTrackArgs;use self::track::cmd_bookmark_track;use self::untrack::BookmarkUntrackArgs;use self::untrack::cmd_bookmark_untrack;use crate::cli_util::CommandHelper;use crate::command_error::CommandError;use crate::ui::Ui; // Unlike most other aliases, `b` is defined in the config and can be overridden// by the user. /// Manage bookmarks [default alias: b]////// See [`jj help -k bookmarks`] for more information.////// [`jj help -k bookmarks`]:///     https://docs.jj-vcs.dev/latest/bookmarks#[derive(clap::Subcommand, Clone, Debug)]pub enum BookmarkCommand {    #[command(visible_alias("a"))]    Advance(BookmarkAdvanceArgs),    #[command(visible_alias("c"))]    Create(BookmarkCreateArgs),    #[command(visible_alias("d"))]    Delete(BookmarkDeleteArgs),    #[command(visible_alias("f"))]    Forget(BookmarkForgetArgs),    #[command(visible_alias("l"))]    List(BookmarkListArgs),    #[command(visible_alias("m"))]    Move(BookmarkMoveArgs),    #[command(visible_alias("r"))]    Rename(BookmarkRenameArgs),    #[command(visible_alias("s"))]    Set(BookmarkSetArgs),    #[command(visible_alias("t"))]    Track(BookmarkTrackArgs),    Untrack(BookmarkUntrackArgs),} pub async fn cmd_bookmark(    ui: &mut Ui,    command: &CommandHelper,    subcommand: &BookmarkCommand,) -> Result<(), CommandError> {    match subcommand {        BookmarkCommand::Advance(args) => cmd_bookmark_advance(ui, command, args).await,        BookmarkCommand::Create(args) => cmd_bookmark_create(ui, command, args).await,        BookmarkCommand::Delete(args) => cmd_bookmark_delete(ui, command, args).await,        BookmarkCommand::Forget(args) => cmd_bookmark_forget(ui, command, args).await,        BookmarkCommand::List(args) => cmd_bookmark_list(ui, command, args).await,        BookmarkCommand::Move(args) => cmd_bookmark_move(ui, command, args).await,        BookmarkCommand::Rename(args) => cmd_bookmark_rename(ui, command, args).await,        BookmarkCommand::Set(args) => cmd_bookmark_set(ui, command, args).await,        BookmarkCommand::Track(args) => cmd_bookmark_track(ui, command, args).await,        BookmarkCommand::Untrack(args) => cmd_bookmark_untrack(ui, command, args).await,    }} fn resolve_trackable_remote_bookmarks<'a>(    ui: &Ui,    view: &'a View,    symbols: &'a [RemoteRefSymbolBuf],) -> Result<Vec<(RemoteRefSymbol<'a>, &'a RemoteRef)>, CommandError> {    let mut trackable_refs = vec![];    let mut unmatched_symbols = vec![];    for symbol in symbols {        let symbol = symbol.as_ref();        let remote_ref = view.get_remote_bookmark(symbol);        if remote_ref.is_present()            || view.get_local_bookmark(symbol.name).is_present()                && view.get_remote_view(symbol.remote).is_some()        {            trackable_refs.push((symbol, remote_ref));        } else {            unmatched_symbols.push(symbol);        }    }    trackable_refs.sort_unstable_by_key(|(sym, _)| *sym);    trackable_refs.dedup_by(|(sym1, _), (sym2, _)| sym1 == sym2);    if !unmatched_symbols.is_empty() {        writeln!(            ui.warning_default(),            "No matching remote bookmarks for names: {}",            unmatched_symbols.iter().join(", ")        )?;    }    Ok(trackable_refs)} fn trackable_remote_bookmarks_matching<'a>(    view: &'a View,    bookmark_matcher: &StringMatcher,    remote_matcher: &StringMatcher,) -> impl Iterator<Item = (RemoteRefSymbol<'a>, &'a RemoteRef)> {    let present_or_tracked_matches =        view.remote_bookmarks_matching(bookmark_matcher, remote_matcher);    let absent_matches =        view.remote_views_matching(remote_matcher)            .flat_map(move |(remote, remote_view)| {                view.local_bookmarks_matching(bookmark_matcher)                    .filter(|&(name, _)| !remote_view.bookmarks.contains_key(name))                    .map(|(name, _)| (name.to_remote_symbol(remote), RemoteRef::absent_ref()))            });    itertools::chain(present_or_tracked_matches, absent_matches)} async fn is_fast_forward(    repo: &dyn Repo,    old_target: &RefTarget,    new_target_id: &CommitId,) -> Result<bool, CommandError> {    if old_target.is_present() {        // Strictly speaking, "all" old targets should be ancestors, but we allow        // conflict resolution by setting bookmark to "any" of the old target        // descendants.        let found = fallible_any(old_target.added_ids(), async |old| {            repo.index().is_ancestor(old, new_target_id).await        })        .await?;        Ok(found)    } else {        Ok(true)    }} /// Warns about exact patterns that don't match local bookmarks.fn warn_unmatched_local_bookmarks(    ui: &Ui,    view: &View,    name_expr: &StringExpression,) -> io::Result<()> {    let mut names = name_expr        .exact_strings()        .map(RefName::new)        .filter(|name| view.get_local_bookmark(name).is_absent())        .peekable();    if names.peek().is_none() {        return Ok(());    }    writeln!(        ui.warning_default(),        "No matching bookmarks for names: {}",        names.map(|name| name.as_symbol()).join(", ")    )} /// Warns about exact patterns that don't match local or remote bookmarks.fn warn_unmatched_local_or_remote_bookmarks(    ui: &Ui,    view: &View,    name_expr: &StringExpression,) -> io::Result<()> {    let mut names = name_expr        .exact_strings()        .map(RefName::new)        .filter(|&name| {            view.get_local_bookmark(name).is_absent()                && view                    .remote_views()                    .all(|(_, remote_view)| !remote_view.bookmarks.contains_key(name))        })        .peekable();    if names.peek().is_none() {        return Ok(());    }    writeln!(        ui.warning_default(),        "No matching bookmarks for names: {}",        names.map(|name| name.as_symbol()).join(", ")    )} /// Warns about exact patterns that don't match remotes.fn warn_unmatched_remotes(ui: &Ui, view: &View, name_expr: &StringExpression) -> io::Result<()> {    let mut names = name_expr        .exact_strings()        .map(RemoteName::new)        .filter(|name| view.get_remote_view(name).is_none())        .peekable();    if names.peek().is_none() {        return Ok(());    }    writeln!(        ui.warning_default(),        "No matching remotes for names: {}",        names.map(|name| name.as_symbol()).join(", ")    )}