-
Notifications
You must be signed in to change notification settings - Fork 1.2k
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
introduce dvc list
command
#3246
Changes from all commits
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -26,7 +26,7 @@ innosetup/config.ini | |
.coverage | ||
.coverage.* | ||
|
||
*.swp | ||
*.sw? | ||
|
||
pip-wheel-metadata/ | ||
.vscode/ | ||
|
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,68 @@ | ||
import argparse | ||
import logging | ||
|
||
from dvc.command.base import append_doc_link | ||
from dvc.command.base import CmdBaseNoRepo | ||
from dvc.exceptions import DvcException | ||
|
||
|
||
logger = logging.getLogger(__name__) | ||
|
||
|
||
class CmdList(CmdBaseNoRepo): | ||
def run(self): | ||
from dvc.repo import Repo | ||
|
||
try: | ||
nodes = Repo.ls( | ||
self.args.url, | ||
self.args.target, | ||
rev=self.args.rev, | ||
recursive=self.args.recursive, | ||
outs_only=self.args.outs_only, | ||
) | ||
if nodes: | ||
logger.info("\n".join(nodes)) | ||
return 0 | ||
except DvcException: | ||
logger.exception("failed to list '{}'".format(self.args.url)) | ||
return 1 | ||
|
||
|
||
def add_parser(subparsers, parent_parser): | ||
LIST_HELP = "List files and DVC outputs in the repo." | ||
list_parser = subparsers.add_parser( | ||
"list", | ||
parents=[parent_parser], | ||
description=append_doc_link(LIST_HELP, "list"), | ||
help=LIST_HELP, | ||
formatter_class=argparse.RawTextHelpFormatter, | ||
) | ||
list_parser.add_argument( | ||
"url", | ||
help="Supported urls:\n" | ||
"/path/to/file\n" | ||
"/path/to/directory\n" | ||
"C:\\\\path\\to\\file\n" | ||
"C:\\\\path\\to\\directory\n" | ||
"https://github.com/path/to/repo\n" | ||
"[email protected]:path/to/repo.git\n", | ||
Comment on lines
+43
to
+49
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more.
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. BTW the args in the $ dvc get -h
...
positional arguments:
url Location of DVC project or Git repository to download
from
path Path to a file or directory within the project or
repository
$ dvc import -h
...
positional arguments:
url Location of DVC project or Git repository to download from
path Path to a file or directory within the project or repository |
||
) | ||
list_parser.add_argument( | ||
"-R", | ||
"--recursive", | ||
action="store_true", | ||
help="Recursively list files.", | ||
) | ||
list_parser.add_argument( | ||
"--outs-only", action="store_true", help="Show only DVC outputs." | ||
) | ||
list_parser.add_argument( | ||
"--rev", nargs="?", help="Git revision (e.g. branch, tag, SHA)" | ||
) | ||
list_parser.add_argument( | ||
"target", | ||
nargs="?", | ||
help="Path to directory within the repository to list outputs for", | ||
jorgeorpinel marked this conversation as resolved.
Show resolved
Hide resolved
|
||
) | ||
list_parser.set_defaults(func=CmdList) |
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -294,12 +294,23 @@ def __init__(self, code, reason): | |
|
||
|
||
class PathMissingError(DvcException): | ||
def __init__(self, path, repo): | ||
default_msg = ( | ||
"The path '{}' does not exist in the target repository '{}'" | ||
" neither as an output nor a git-handled file." | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. "...as a DVC output nor as a Git-tracked file." |
||
) | ||
default_msg_output_only = ( | ||
"The path '{}' does not exist in the target repository '{}'" | ||
" as an output." | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. as an DVC output |
||
) | ||
|
||
def __init__(self, path, repo, output_only=False): | ||
msg = ( | ||
"The path '{}' does not exist in the target repository '{}'" | ||
" neither as an output nor a git-handled file." | ||
self.default_msg | ||
if not output_only | ||
else self.default_msg_output_only | ||
) | ||
super().__init__(msg.format(path, repo)) | ||
self.output_only = output_only | ||
|
||
|
||
class RemoteCacheRequiredError(DvcException): | ||
|
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,84 @@ | ||
import os | ||
|
||
from dvc.exceptions import PathMissingError, OutputNotFoundError | ||
|
||
|
||
@staticmethod | ||
def ls(url, target=None, rev=None, recursive=None, outs_only=False): | ||
from dvc.external_repo import external_repo | ||
from dvc.repo import Repo | ||
from dvc.utils import relpath | ||
|
||
with external_repo(url, rev) as repo: | ||
skshetry marked this conversation as resolved.
Show resolved
Hide resolved
|
||
target_path_info = _get_target_path_info(repo, target) | ||
result = [] | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Why not There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Cause I am everywhere uses list (as outs from |
||
if isinstance(repo, Repo): | ||
result.extend(_ls_outs_repo(repo, target_path_info, recursive)) | ||
|
||
if not outs_only: | ||
result.extend(_ls_files_repo(target_path_info, recursive)) | ||
|
||
if target and not result: | ||
raise PathMissingError(target, repo, output_only=outs_only) | ||
|
||
def prettify(path_info): | ||
if path_info == target_path_info: | ||
return path_info.name | ||
return relpath(path_info, target_path_info) | ||
|
||
result = list(set(map(prettify, result))) | ||
result.sort() | ||
return result | ||
|
||
|
||
def _ls_files_repo(target_path_info, recursive=None): | ||
from dvc.compat import fspath | ||
from dvc.ignore import CleanTree | ||
from dvc.path_info import PathInfo | ||
from dvc.scm.tree import WorkingTree | ||
|
||
if not os.path.exists(fspath(target_path_info)): | ||
return [] | ||
|
||
files = [] | ||
tree = CleanTree(WorkingTree(target_path_info)) | ||
try: | ||
for dirpath, dirnames, filenames in tree.walk(target_path_info): | ||
files.extend(map(lambda f: PathInfo(dirpath, f), filenames)) | ||
if not recursive: | ||
files.extend(map(lambda d: PathInfo(dirpath, d), dirnames)) | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. This is probably the cause of that bug. This line should be outside of |
||
break | ||
except NotADirectoryError: | ||
gurobokum marked this conversation as resolved.
Show resolved
Hide resolved
|
||
if os.path.isfile(fspath(target_path_info)): | ||
return [target_path_info] | ||
|
||
return files | ||
gurobokum marked this conversation as resolved.
Show resolved
Hide resolved
|
||
|
||
|
||
def _ls_outs_repo(repo, target_path_info, recursive=None): | ||
from dvc.compat import fspath | ||
from dvc.path_info import PathInfo | ||
|
||
try: | ||
outs = repo.find_outs_by_path(fspath(target_path_info), recursive=True) | ||
except OutputNotFoundError: | ||
return [] | ||
|
||
if recursive: | ||
return [out.path_info for out in outs] | ||
|
||
def get_top_part(path_info): | ||
relpath = path_info.relpath(target_path_info) | ||
if relpath.parts: | ||
return PathInfo(target_path_info, relpath.parts[0]) | ||
return path_info | ||
|
||
return list({get_top_part(out.path_info) for out in outs}) | ||
|
||
|
||
def _get_target_path_info(repo, target=None): | ||
from dvc.path_info import PathInfo | ||
|
||
if not target: | ||
return PathInfo(repo.root_dir) | ||
return PathInfo(repo.root_dir, target) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
per iterative/dvc.org/pull/967