Gitlab Community Edition Instance

Commit 04d6e57a authored by Marcel Hellkamp's avatar Marcel Hellkamp
Browse files

New 'ls' command

parent 2e24f972
......@@ -39,6 +39,7 @@ setup(
'requests >= 2.22',
'requests-toolbelt >= 0.9.1',
'tqdm >= 4.32.2',
'iso8601 >= 0.1.12',
],
extras_require={
'dev': ['flake8', 'wheel', 'twine', 'tox'],
......
import argparse
import os
import re
import sys
......@@ -14,12 +15,27 @@ def walk_up(start):
current_dir = parent
def hbytes(n):
for unit in ('B', 'KiB', 'MiB', 'GiB', 'TiB', 'PiB', 'EiB', 'ZiB', 'YiB'):
def hbytes(n, units=None):
for unit in units or ('B', 'KB', 'MB', 'GB', 'TB', 'PB', 'EB', 'ZB', 'YB'):
if abs(n) < 1024.0:
return "{:.1f} {}".format(n, unit)
n /= 1024.0
return "alot"
raise AssertionError("Number out of range")
def kvtype(val):
""" Argparse type that parses a KEY=VALUE parameter into a tuple.
The value may be empty, but the '=' is required. """
k, _, v = val.partition('=')
if not _:
raise argparse.ArgumentTypeError("Expected KAY=VALUE argument.")
return k, v
def globtype(str):
""" Argparse type that accepts glob file patterns """
return compile_glob(str)
def compile_glob(pattern):
......@@ -39,7 +55,7 @@ def compile_glob(pattern):
class FileProgress:
def __init__(self, fp, chunksize=1024*8, **baropts):
def __init__(self, fp, chunksize=1024 * 8, **baropts):
from requests.utils import super_len
self.opts = baropts
self.fp = fp
......@@ -48,7 +64,8 @@ class FileProgress:
def __iter__(self):
from tqdm import tqdm
with tqdm(total=self.len, unit='b', unit_scale=True, unit_divisor=1024, dynamic_ncols=True, **self.opts) as pbar:
with tqdm(total=self.len, unit='b', unit_scale=True, unit_divisor=1024, dynamic_ncols=True,
**self.opts) as pbar:
read = self.fp.read
update = pbar.update
while True:
......
"""
List files in an archive or in a sub directory.
"""
from collections import defaultdict
import iso8601 as iso8601
from pycdstar3.cli import printer
from pycdstar3.cli._utils import hbytes
def register(subparsers):
parser = subparsers.add_parser("ls", help=__doc__.strip().splitlines()[0], description=__doc__)
parser.add_argument("REF", help="Archive to list")
parser.add_argument("-f", "--format", default="name",
help="Change what is printed per file. provide either a python format string, "
"or a csv with field names. Available fields: "
"name, id, type, size, created, modified, md5, sha1, sha256, meta[...]\n"
" (default: name)")
parser.add_argument("--order", default="name",
choices=["name", "type", "size", "created", "modified", "hash", "id"],
help="Order by name, type, size, created, modified, hash or id. (default: name)")
parser.add_argument("--reverse", action="store_true", help="Reverse list order")
parser.add_argument("-i", "--include", metavar="GLOB", action="append",
help="Include files by glob pattern (default: all)")
parser.add_argument("-x", "--exclude", metavar="GLOB", action="append",
help="Exclude files by glob pattern")
parser.set_defaults(main=ls)
def ls(ctx, args):
client, vault, archive, prefix = ctx.resolve(args.REF)
opts = {}
opts["order"] = args.order
opts["reverse"] = args.reverse
if prefix.strip('/'):
opts['include_glob'] = ["/{}/**".format(prefix.strip('/'))]
if args.include:
opts.setdefault("include_glob", []).append(args.include)
if args.exclude:
opts.setdefault("exclude_glob", []).append(args.exclude)
fmt = args.format
fmt = fmt.replace("\\t", "\t").replace("\\0", "\0").replace("\\n", "\n").replace("\\\\", "\\")
if "{" not in fmt:
# translate csv format to tab separated format string
fmt = "{" + "}\t{".join(fmt.split(",")) + "}"
if '{meta' in fmt:
# Load metadata only if requested
opts["meta"] = True
def file2str(file):
attrs = defaultdict(lambda: "-")
attrs.update(file)
attrs.update(file['digests'])
if '{hsize' in fmt:
attrs["hsize"] = hbytes(attrs["size"])
if '{created' in fmt:
attrs["created"] = iso8601.parse_date(attrs["created"])
if '{modified' in fmt:
attrs["modified"] = iso8601.parse_date(attrs["modified"])
if '{meta' in fmt:
meta = defaultdict(lambda: "-")
meta.update(attrs["meta"])
attrs["meta"] = meta
return fmt.format_map(attrs)
with client.begin(readonly=True):
n = b = 0
for file in client.iter_files(vault, archive, **opts):
n += 1
b += file['size']
print(file2str(file))
printer("\nTotal: {:,} files {:,} bytes", n, b)
Supports Markdown
0% or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment