Zsh Mailing List Archive
Messages sorted by: Reverse Date, Date, Thread, Author

Re: [PATCH v5] vcs_info: choose backend by basedir



Ping

On Fri, Jun 4, 2021 at 12:14 PM Aleksandr Mezin
<mezin.alexander@xxxxxxxxx> wrote:
>
> Previously, vcs_info iterated over enabled VCS backends and output repository
> status from the first backend that works (i.e. first backend that can find a
> repository).
>
> But I prefer a different behavior: I want to see the status of the repository
> closest to the current working directory. For example: if there is a Mercurial
> repository inside a Git repository, and I 'cd' into the Mercurial repository,
> I want to see the status of Mercurial repo, even if 'git' comes before 'hg' in
> the 'enable' list.
>
> This patch adds a new algorithm for vcs_info to choose the backend:
>
> 1. Among backends whose basedir isn't an ancestor of the current directory,
> old algorithm is used: whichever comes first in 'enable' list.
>
> 2. If all backends return basedirs that are ancestors of the current directory,
> the one with basedir closest to the current directory is chosen.
>
> As far as I know, unless the user has set basedir manually (GIT_WORK_TREE),
> all backend return basedirs that are ancestors of the current directory.
> Backends that return non-ancestor basedirs have higher priority to show the
> status of that manually-configured repository.
>
> The algorithm used by vcs_info can be configured using 'choose-closest-backend'
> zstyle:
>
>     zstyle ':vcs_info:*' choose-closest-backend yes
>
> By default, old algorithm is used.
>
> It can also be configured per-backend:
>
>     zstyle ':vcs_info:hg:*' choose-closest-backend no
>
> This effectively moves the backend into group (1), as if its basedir is never
> an ancestor of the current directory. Not sure how useful this is though.
>
> Signed-off-by: Aleksandr Mezin <mezin.alexander@xxxxxxxxx>
> ---
> v4: back to boolean zstyle, keep old behavior by default, documentation
> v5: described expected vcs_info[basedir] use in a comment, addressed Daniel's
> questions in comments.
>
>  Completion/Zsh/Command/_zstyle |  1 +
>  Doc/Zsh/contrib.yo             | 41 ++++++++++++++++++++++
>  Functions/VCS_Info/vcs_info    | 62 +++++++++++++++++++++++++++++++---
>  3 files changed, 100 insertions(+), 4 deletions(-)
>
> diff --git a/Completion/Zsh/Command/_zstyle b/Completion/Zsh/Command/_zstyle
> index 9d06076e4..b7a73c5a2 100644
> --- a/Completion/Zsh/Command/_zstyle
> +++ b/Completion/Zsh/Command/_zstyle
> @@ -193,6 +193,7 @@ styles=(
>    quilt-standalone       v:bool
>    quilt-patch-dir        v:_directories
>    quiltcommand           v:_command_names
> +  choose-closest-backend v:bool
>
>    chpwd                         z:bool
>    progress              z:progress
> diff --git a/Doc/Zsh/contrib.yo b/Doc/Zsh/contrib.yo
> index a972f08d6..67823716a 100644
> --- a/Doc/Zsh/contrib.yo
> +++ b/Doc/Zsh/contrib.yo
> @@ -1238,6 +1238,46 @@ of unapplied patches (for example with Mercurial Queue patches).
>
>  Used by the tt(quilt), tt(hg), and tt(git) backends.
>  )
> +kindex(choose-closest-backend)
> +item(tt(choose-closest-backend))(
> +By default, tt(vcs_info) tries backends in the order given by the tt(enable)
> +style, and operates on the repository detected by the first backend to
> +successfully detect a repository.
> +
> +If this style (tt(choose-closest-backend)) is set to tt(true) for some (or all)
> +backends, all backends will be divided into two groups:
> +
> +1) Backends, for which this style is set to tt(true), that detect a
> +repository/working copy that is an ancestor of the current directory (including
> +the current directory itself).
> +
> +2) All other backends: backends with tt(choose-closest-backend) unset/set to
> +tt(false); and backends that detected a repository/working copy that's not an
> +ancestor of the current directory, even if tt(choose-closest-backend) is set to
> +tt(true) for them.
> +
> +First, tt(vcs_info) will try backends from the 2nd group in the order given by
> +the tt(enable) style, and operate on the repository detected by the first
> +backend to successfully detect a repository (the default behavior of
> +tt(vcs_info), only limited to backends from the 2nd group).
> +
> +If no backends from the 2nd group detected a repository (or if there are no
> +backends in that group), tt(vcs_info) will try backends from the 1st group.
> +tt(vcs_info) will then operate on the repository closest to the current working
> +directory.
> +
> +Usually, all VCS backends search for repositories only in ancestors of the
> +current directory, and choose the repository closest to the current directory.
> +So if tt(choose-closest-backend) is set to tt(true) globally for all backends,
> +tt(vcs_info) will effectively search for the repository closest to the current
> +directory.
> +
> +However, there is at least one backend that can detect a repository in an
> +arbitrary location - Git backend. tt(GIT_WORK_TREE) can be set to a path that
> +doesn't point to an ancestor of the current directory. In this case, even if
> +tt(choose-closest-backend) is set to tt(true) globally for all backends,
> +the repository/working copy pointed by tt(GIT_WORK_TREE) will be preferred.
> +)
>  enditem()
>
>  The default values for these styles in all contexts are:
> @@ -1272,6 +1312,7 @@ sitem(tt(quiltcommand))(quilt)
>  sitem(tt(patch-format))(var(backend dependent))
>  sitem(tt(nopatch-format))(var(backend dependent))
>  sitem(tt(get-unapplied))(false)
> +sitem(tt(choose-closest-backend))(false)
>  endsitem()
>
>  In normal tt(formats) and tt(actionformats) the following replacements are
> diff --git a/Functions/VCS_Info/vcs_info b/Functions/VCS_Info/vcs_info
> index 786b61918..85f7ca0ab 100644
> --- a/Functions/VCS_Info/vcs_info
> +++ b/Functions/VCS_Info/vcs_info
> @@ -54,7 +54,7 @@ vcs_info () {
>      [[ -r . ]] || return 0
>
>      local pat
> -    local -i found retval
> +    local -i retval
>      local -a enabled disabled dps
>      local usercontext vcs rrn quiltmode
>      local -x LC_MESSAGES
> @@ -64,6 +64,9 @@ vcs_info () {
>      # vcs_comm is used internally for passing values among VCS_INFO_* functions.
>      # It is not part of the public API.
>      #
> +    # VCS_INFO_detect_* functions should set vcs_comm[basedir] to the path to
> +    # the root of the working copy.
> +    #
>      # hook_com, backend_misc, and user_data are public API; see zshcontrib(1)
>      # and Misc/vcs_info-examples.
>      local -A vcs_comm hook_com backend_misc user_data
> @@ -114,7 +117,9 @@ vcs_info () {
>
>      VCS_INFO_maxexports
>
> -    (( found = 0 ))
> +    local -A chosen_vcs_comm chosen_backend_misc
> +    local chosen_vcs basedir_realpath chosen_basedir_realpath choose_first_available
> +
>      for vcs in ${enabled} ; do
>          [[ -n ${(M)disabled:#${vcs}} ]] && continue
>          if (( ${+functions[VCS_INFO_detect_${vcs}]} == 0 )) ; then
> @@ -124,10 +129,59 @@ vcs_info () {
>          fi
>          vcs_comm=()
>          VCS_INFO_get_cmd
> -        VCS_INFO_detect_${vcs} && (( found = 1 )) && break
> +        if VCS_INFO_detect_${vcs}; then
> +            # Most backends already set vcs_comm[basedir] to an absolute path
> +            # with symlinks resolved:
> +            #
> +            # * Backends using VCS_INFO_bydir_detect:
> +            #   bzr, cdv, darcs, fossil, hg, mtn, p4, svn
> +            #
> +            # * cvs - custom logic, but uses :P too
> +            #
> +            # * git - $(git rev-parse --show-toplevel) resolves symlinks and
> +            #   returns an absolute path
> +            #
> +            # * for tla (GNU Arch) I can't find any online documentation or
> +            #   packages (seems to be dead)
> +            #
> +            # * svk doesn't use :P modifier and returns the path as is from
> +            #   the config file (as far as I understand)
> +            #
> +            # So I'm not sure whether to modify the backends or just resolve
> +            # the path here to be sure. VCS_INFO_get_data_* usually reads
> +            # vcs_comm[basedir] too. In particular, I'm not sure if it's safe to
> +            # resolve symlinks in vcs_comm[basedir] for svk.
> +            #
> +            # Because most backends already do :P substitution, I expect all
> +            # the info needed to resolve the path to be cached in memory by the
> +            # OS (so it shouldn't cause performance issues).
> +            basedir_realpath="${vcs_comm[basedir]:P}"
> +
> +            zstyle -t ":vcs_info:${vcs}:${usercontext}:${rrn}" choose-closest-backend
> +            choose_first_available=$?
> +
> +            [[ "${PWD:P}/" == "${basedir_realpath}"/* ]] || [[ "${basedir_realpath}" == "/" ]] || choose_first_available=1
> +
> +            # If choose_first_available is 0 at this point, all basedir_realpaths
> +            # (and thus chosen_basedir_realpath) are parents (and thus prefixes)
> +            # of PWD:P. So comparing their lengths is enough to figure out which
> +            # one is closer to PWD.
> +            if (( choose_first_available )) || (( ${#basedir_realpath} > ${#chosen_basedir_realpath} )) ; then
> +                chosen_vcs="${vcs}"
> +                chosen_vcs_comm=("${(kv)vcs_comm[@]}")
> +                chosen_backend_misc=("${(kv)backend_misc[@]}")
> +                chosen_basedir_realpath="${basedir_realpath}"
> +
> +                (( choose_first_available )) && break
> +            fi
> +        fi
>      done
>
> -    (( found == 0 )) && {
> +    vcs="${chosen_vcs}"
> +    vcs_comm=("${(kv)chosen_vcs_comm[@]}")
> +    backend_misc=("${(kv)chosen_backend_misc[@]}")
> +
> +    [ -z "${vcs}" ] && {
>          vcs='-quilt-'; quiltmode='standalone'
>          VCS_INFO_quilt standalone || VCS_INFO_set --nvcs
>          return 0
> --
> 2.31.1
>




Messages sorted by: Reverse Date, Date, Thread, Author