mirror of
https://github.com/Stone-Red-Code/dvc.git
synced 2026-11-04 15:28:27 +01:00
Compare commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
a5ae8b19a4 | ||
|
|
f2b1c41cdf | ||
|
|
ffd32dfe8a |
+129
-5
@@ -31,6 +31,27 @@ _dvc_compgen_remotes() {
|
|||||||
_dvc_compgen_config_vars() {
|
_dvc_compgen_config_vars() {
|
||||||
compgen -W "${_dvc_config_vars[*]}" -- $1
|
compgen -W "${_dvc_config_vars[*]}" -- $1
|
||||||
}
|
}
|
||||||
|
|
||||||
|
_dvc_compgen_remote_config_vars() {
|
||||||
|
local cur prev words cword remote_name filtered
|
||||||
|
_init_completion || return
|
||||||
|
|
||||||
|
# last non-option word before cursor
|
||||||
|
local nonopts=()
|
||||||
|
for w in "${words[@]:1:$((cword-1))}"; do
|
||||||
|
[[ $w == -* ]] || nonopts+=("$w")
|
||||||
|
done
|
||||||
|
|
||||||
|
remote_name="${nonopts[-1]}"
|
||||||
|
if [[ -n $remote_name ]]; then
|
||||||
|
local _dvc_remote_config_vars=($(
|
||||||
|
dvc config --available-options -q 2> /dev/null \
|
||||||
|
| grep "^remote\\.${remote_name}\\." \
|
||||||
|
| sed "s/^remote\\.${remote_name}\\.//"
|
||||||
|
))
|
||||||
|
compgen -W "${_dvc_remote_config_vars[*]}" -- $1
|
||||||
|
fi
|
||||||
|
}
|
||||||
"""
|
"""
|
||||||
|
|
||||||
ZSH_PREAMBLE = """
|
ZSH_PREAMBLE = """
|
||||||
@@ -69,27 +90,111 @@ _dvc_compadd_remotes() {
|
|||||||
_describe 'remotes' "($(dvc remote list | cut -d' ' -f1))"
|
_describe 'remotes' "($(dvc remote list | cut -d' ' -f1))"
|
||||||
}
|
}
|
||||||
|
|
||||||
|
_dvc_config_config_vars_for_completion() {
|
||||||
|
dvc config --available-options -q 2> /dev/null
|
||||||
|
}
|
||||||
|
|
||||||
_dvc_compadd_config_vars() {
|
_dvc_compadd_config_vars() {
|
||||||
_describe 'config_vars' _dvc_config_vars
|
_describe 'config_vars' _dvc_config_vars
|
||||||
}
|
}
|
||||||
|
|
||||||
|
_dvc_compadd_remote_config_vars() {
|
||||||
|
local remote_name filtered
|
||||||
|
|
||||||
|
# last non-option word before cursor
|
||||||
|
remote_name=${${words[1,CURRENT-1]##-*}[-1]}
|
||||||
|
if [[ -n $remote_name ]]; then
|
||||||
|
filtered=$(_dvc_config_config_vars_for_completion \\
|
||||||
|
| grep "^remote.${remote_name}\\\\." \\
|
||||||
|
| sed "s/^remote\\\\.${remote_name}\\\\.//"
|
||||||
|
)
|
||||||
|
compadd -- $=filtered
|
||||||
|
fi
|
||||||
|
}
|
||||||
|
"""
|
||||||
|
|
||||||
|
FISH_PREAMBLE = """
|
||||||
|
function __fish_complete_dvc_files
|
||||||
|
__fish_complete_path | string match -re '\\*?.dvc|Dvcfile|dvc\\.yaml'
|
||||||
|
end
|
||||||
|
|
||||||
|
function __fish_complete_dvc_stages
|
||||||
|
for line in (dvc stage list -q)
|
||||||
|
set -l parts (string split -m1 ' ' -- $line)
|
||||||
|
set -l name $parts[1]
|
||||||
|
set -l desc (string trim $parts[2])
|
||||||
|
echo -e "$name $desc"
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
function __fish_complete_dvc_stages_and_files
|
||||||
|
__fish_complete_dvc_stages
|
||||||
|
__fish_complete_dvc_files
|
||||||
|
end
|
||||||
|
|
||||||
|
function __fish_complete_dvc_experiments
|
||||||
|
dvc exp list -q --all-commits --names-only
|
||||||
|
end
|
||||||
|
|
||||||
|
function __fish_complete_dvc_remotes
|
||||||
|
dvc remote list | cut -d' ' -f1
|
||||||
|
end
|
||||||
|
|
||||||
|
function __fish_complete_dvc_remote_config_vars
|
||||||
|
# last non-option word before cursor
|
||||||
|
set -l remote_name (commandline -opc | string match -rv '^-' | tail -n 1)
|
||||||
|
|
||||||
|
if test -n "$remote_name"
|
||||||
|
dvc config --available-options -q 2>/dev/null |
|
||||||
|
string match -re "^remote\\.$remote_name\\." |
|
||||||
|
string replace -r "^remote\\.$remote_name\\." ''
|
||||||
|
end
|
||||||
|
end
|
||||||
"""
|
"""
|
||||||
|
|
||||||
PREAMBLE = {
|
PREAMBLE = {
|
||||||
"bash": BASH_PREAMBLE,
|
"bash": BASH_PREAMBLE,
|
||||||
"zsh": ZSH_PREAMBLE,
|
"zsh": ZSH_PREAMBLE,
|
||||||
|
"fish": FISH_PREAMBLE,
|
||||||
}
|
}
|
||||||
|
|
||||||
FILE = shtab.FILE
|
FILE = shtab.FILE
|
||||||
DIR = shtab.DIRECTORY
|
DIR = shtab.DIRECTORY
|
||||||
DVC_FILE = {"bash": "_dvc_compgen_DVCFiles", "zsh": "_dvc_compadd_DVCFiles"}
|
DVC_FILE = {
|
||||||
STAGE = {"bash": "_dvc_compgen_stages", "zsh": "_dvc_compadd_stages"}
|
"bash": "_dvc_compgen_DVCFiles",
|
||||||
|
"zsh": "_dvc_compadd_DVCFiles",
|
||||||
|
"fish": '-f -a "(__fish_complete_dvc_files)"',
|
||||||
|
}
|
||||||
|
STAGE = {
|
||||||
|
"bash": "_dvc_compgen_stages",
|
||||||
|
"zsh": "_dvc_compadd_stages",
|
||||||
|
"fish": '-f -a "(__fish_complete_dvc_stages)"',
|
||||||
|
}
|
||||||
DVCFILES_AND_STAGE = {
|
DVCFILES_AND_STAGE = {
|
||||||
"bash": "_dvc_compgen_stages_and_files",
|
"bash": "_dvc_compgen_stages_and_files",
|
||||||
"zsh": "_dvc_compadd_stages_and_files",
|
"zsh": "_dvc_compadd_stages_and_files",
|
||||||
|
"fish": '-f -a "(__fish_complete_dvc_stages_and_files)"',
|
||||||
|
}
|
||||||
|
EXPERIMENT = {
|
||||||
|
"bash": "_dvc_compgen_exps",
|
||||||
|
"zsh": "_dvc_compadd_exps",
|
||||||
|
"fish": '-f -a "(__fish_complete_dvc_experiments)"',
|
||||||
|
}
|
||||||
|
REMOTE = {
|
||||||
|
"bash": "_dvc_compgen_remotes",
|
||||||
|
"zsh": "_dvc_compadd_remotes",
|
||||||
|
"fish": '-f -a "(__fish_complete_dvc_remotes)"',
|
||||||
|
}
|
||||||
|
CONFIG_VARS = {
|
||||||
|
"bash": "_dvc_compgen_config_vars",
|
||||||
|
"zsh": "_dvc_compadd_config_vars",
|
||||||
|
"fish": '-f -a "(__fish_complete_dvc_config_vars)"',
|
||||||
|
}
|
||||||
|
REMOTE_CONFIG_VARS = {
|
||||||
|
"bash": "_dvc_compgen_remote_config_vars",
|
||||||
|
"zsh": "_dvc_compadd_remote_config_vars",
|
||||||
|
"fish": '-f -a "(__fish_complete_dvc_remote_config_vars)"',
|
||||||
}
|
}
|
||||||
EXPERIMENT = {"bash": "_dvc_compgen_exps", "zsh": "_dvc_compadd_exps"}
|
|
||||||
REMOTE = {"bash": "_dvc_compgen_remotes", "zsh": "_dvc_compadd_remotes"}
|
|
||||||
CONFIG_VARS = {"bash": "_dvc_compgen_config_vars", "zsh": "_dvc_compadd_config_vars"}
|
|
||||||
|
|
||||||
|
|
||||||
def get_preamble() -> dict[str, str]:
|
def get_preamble() -> dict[str, str]:
|
||||||
@@ -103,7 +208,26 @@ def get_preamble() -> dict[str, str]:
|
|||||||
_dvc_config_vars=(
|
_dvc_config_vars=(
|
||||||
{nl.join(config_vars)}
|
{nl.join(config_vars)}
|
||||||
)
|
)
|
||||||
|
"""
|
||||||
|
indent = "\t\t".expandtabs(4) # 8 spaces
|
||||||
|
lines = (
|
||||||
|
"\n".join(
|
||||||
|
f"{indent}{c} \\"
|
||||||
|
for c in config_vars[:-1] # all but last
|
||||||
|
)
|
||||||
|
+ "\n"
|
||||||
|
+ f"{indent}{config_vars[-1]}"
|
||||||
|
) # last line without backslash
|
||||||
|
config_vars_arr_fish = f"""
|
||||||
|
function __fish_complete_dvc_config_vars
|
||||||
|
set -l _dvc_config_vars \\
|
||||||
|
{lines}
|
||||||
|
printf %s\\n $_dvc_config_vars
|
||||||
|
end
|
||||||
"""
|
"""
|
||||||
for shell, preamble in PREAMBLE.items():
|
for shell, preamble in PREAMBLE.items():
|
||||||
|
if shell != "fish":
|
||||||
ret[shell] = config_vars_arr + preamble
|
ret[shell] = config_vars_arr + preamble
|
||||||
|
else:
|
||||||
|
ret[shell] = config_vars_arr_fish + preamble
|
||||||
return ret
|
return ret
|
||||||
|
|||||||
@@ -8,7 +8,7 @@ from dvc.ui import ui
|
|||||||
logger = logger.getChild(__name__)
|
logger = logger.getChild(__name__)
|
||||||
|
|
||||||
|
|
||||||
SUPPORTED_SHELLS = ["bash", "zsh"]
|
SUPPORTED_SHELLS = ["bash", "zsh", "fish"]
|
||||||
|
|
||||||
|
|
||||||
class CmdCompletion(CmdBaseNoRepo):
|
class CmdCompletion(CmdBaseNoRepo):
|
||||||
|
|||||||
@@ -40,6 +40,15 @@ class CmdConfig(CmdBaseNoRepo):
|
|||||||
self.config = Config.from_cwd(validate=False)
|
self.config = Config.from_cwd(validate=False)
|
||||||
|
|
||||||
def run(self):
|
def run(self):
|
||||||
|
if self.args.available_options:
|
||||||
|
from dvc.config_schema import contextual_config_vars_for_completion
|
||||||
|
|
||||||
|
ui.write(
|
||||||
|
"\n".join(list(contextual_config_vars_for_completion(self.config))),
|
||||||
|
force=True,
|
||||||
|
)
|
||||||
|
return 0
|
||||||
|
|
||||||
if self.args.show_origin and (self.args.value or self.args.unset):
|
if self.args.show_origin and (self.args.value or self.args.unset):
|
||||||
logger.error(
|
logger.error(
|
||||||
"--show-origin can't be used together with any of these "
|
"--show-origin can't be used together with any of these "
|
||||||
@@ -212,6 +221,9 @@ def add_parser(subparsers, parent_parser):
|
|||||||
help=CONFIG_HELP,
|
help=CONFIG_HELP,
|
||||||
formatter_class=formatter.RawDescriptionHelpFormatter,
|
formatter_class=formatter.RawDescriptionHelpFormatter,
|
||||||
)
|
)
|
||||||
|
config_parser.add_argument(
|
||||||
|
"--available-options", default=False, action="store_true"
|
||||||
|
)
|
||||||
config_parser.add_argument(
|
config_parser.add_argument(
|
||||||
"-u",
|
"-u",
|
||||||
"--unset",
|
"--unset",
|
||||||
|
|||||||
@@ -233,7 +233,9 @@ def add_parser(subparsers, parent_parser):
|
|||||||
remote_modify_parser.add_argument(
|
remote_modify_parser.add_argument(
|
||||||
"name", help="Name of the remote"
|
"name", help="Name of the remote"
|
||||||
).complete = completion.REMOTE
|
).complete = completion.REMOTE
|
||||||
remote_modify_parser.add_argument("option", help="Name of the option to modify.")
|
remote_modify_parser.add_argument(
|
||||||
|
"option", help="Name of the option to modify."
|
||||||
|
).complete = completion.REMOTE_CONFIG_VARS
|
||||||
remote_modify_parser.add_argument(
|
remote_modify_parser.add_argument(
|
||||||
"value", nargs="?", help="(optional) Value of the option."
|
"value", nargs="?", help="(optional) Value of the option."
|
||||||
)
|
)
|
||||||
|
|||||||
+34
-14
@@ -60,23 +60,27 @@ def Choices(*choices): # noqa: N802
|
|||||||
return Any(*choices, msg="expected one of {}".format(", ".join(choices)))
|
return Any(*choices, msg="expected one of {}".format(", ".join(choices)))
|
||||||
|
|
||||||
|
|
||||||
|
def _get_schema_from_url(url: str) -> str:
|
||||||
|
parsed = urlparse(url)
|
||||||
|
# Windows absolute paths should really have scheme == "" (local)
|
||||||
|
if os.name == "nt" and len(parsed.scheme) == 1 and not parsed.netloc:
|
||||||
|
return ""
|
||||||
|
if not parsed.netloc:
|
||||||
|
return ""
|
||||||
|
return parsed.scheme
|
||||||
|
|
||||||
|
|
||||||
def ByUrl(mapping): # noqa: N802
|
def ByUrl(mapping): # noqa: N802
|
||||||
schemas = walk_values(Schema, mapping)
|
schemas: dict[str, Schema] = walk_values(Schema, mapping)
|
||||||
|
|
||||||
def validate(data):
|
def validate(data):
|
||||||
if "url" not in data:
|
if "url" not in data:
|
||||||
raise Invalid("expected 'url'")
|
raise Invalid("expected 'url'")
|
||||||
|
|
||||||
parsed = urlparse(data["url"])
|
scheme = _get_schema_from_url(data["url"])
|
||||||
# Windows absolute paths should really have scheme == "" (local)
|
if scheme not in schemas:
|
||||||
if os.name == "nt" and len(parsed.scheme) == 1 and not parsed.netloc:
|
raise Invalid(f"Unsupported URL type {scheme}://")
|
||||||
return schemas[""](data)
|
return schemas[scheme](data)
|
||||||
if not parsed.netloc:
|
|
||||||
return schemas[""](data)
|
|
||||||
if parsed.scheme not in schemas:
|
|
||||||
raise Invalid(f"Unsupported URL type {parsed.scheme}://")
|
|
||||||
|
|
||||||
return schemas[parsed.scheme](data)
|
|
||||||
|
|
||||||
return validate
|
return validate
|
||||||
|
|
||||||
@@ -396,9 +400,25 @@ def config_vars_for_completion(d: dict = SCHEMA, path: str = "") -> "Iterator[st
|
|||||||
k = k.schema
|
k = k.schema
|
||||||
if not isinstance(k, str):
|
if not isinstance(k, str):
|
||||||
continue
|
continue
|
||||||
|
keypath = f"{path}.{k}" if path else k
|
||||||
keypath = path + k
|
|
||||||
if isinstance(v, dict):
|
if isinstance(v, dict):
|
||||||
yield from config_vars_for_completion(v, keypath + ".")
|
yield from config_vars_for_completion(v, keypath)
|
||||||
else:
|
else:
|
||||||
yield keypath
|
yield keypath
|
||||||
|
|
||||||
|
|
||||||
|
def contextual_config_vars_for_completion(config) -> "Iterator[str]":
|
||||||
|
yield from config_vars_for_completion()
|
||||||
|
for name, data in config["remote"].items():
|
||||||
|
if "url" not in data:
|
||||||
|
continue
|
||||||
|
scheme = _get_schema_from_url(data["url"])
|
||||||
|
if scheme not in REMOTE_SCHEMAS:
|
||||||
|
continue
|
||||||
|
schema = REMOTE_SCHEMAS[scheme]
|
||||||
|
if schema:
|
||||||
|
yield from config_vars_for_completion(schema, f"remote.{name}") # type: ignore[arg-type]
|
||||||
|
|
||||||
|
db_schema = SCHEMA["db"][str] # type: ignore[index]
|
||||||
|
for name in config["db"]:
|
||||||
|
yield from config_vars_for_completion(db_schema, f"db.{name}") # type: ignore[arg-type]
|
||||||
|
|||||||
+2
-1
@@ -69,7 +69,8 @@ dependencies = [
|
|||||||
"ruamel.yaml>=0.17.11",
|
"ruamel.yaml>=0.17.11",
|
||||||
"scmrepo>=3.5.2,<4",
|
"scmrepo>=3.5.2,<4",
|
||||||
"shortuuid>=0.5",
|
"shortuuid>=0.5",
|
||||||
"shtab<2,>=1.3.4",
|
# "shtab<2,>=1.3.4",
|
||||||
|
"shtab @ git+https://github.com/skshetry/shtab.git@fish-shell-v2",
|
||||||
"tabulate>=0.8.7",
|
"tabulate>=0.8.7",
|
||||||
"tomlkit>=0.11.1",
|
"tomlkit>=0.11.1",
|
||||||
"tqdm<5,>=4.63.1",
|
"tqdm<5,>=4.63.1",
|
||||||
|
|||||||
Reference in New Issue
Block a user