Commit d5818a9c authored by André Anjos's avatar André Anjos 💬
Browse files

Merge branch 'webdav-tools' into 'master'

Implement easy WebDAV access

See merge request !94
parents 53e52a18 000d87e7
Pipeline #32465 passed with stages
in 8 minutes and 44 seconds
#!/usr/bin/env python
# -*- coding: utf-8 -*-
import os
import configparser
from .log import get_logger
from .deploy import _setup_webdav_client
logger = get_logger(__name__)
def _get_config():
"""Returns a dictionary with server parameters, or ask them to the user"""
# tries to figure if we can authenticate using a global configuration
cfgs = ["~/.bdt-webdav.cfg"]
cfgs = [os.path.expanduser(k) for k in cfgs]
for k in cfgs:
if os.path.exists(k):
data = configparser.ConfigParser()
data.read(k)
if 'global' not in data or \
'server' not in data['global'] or \
'username' not in data['global'] or \
'password' not in data['global']:
assert KeyError, 'The file %s should contain a single ' \
'"global" section with 3 variables defined inside: ' \
'"server", "username", "password".' % (k,)
return data['global']
# ask the user for the information, cache credentials for future use
retval = dict()
retval['server'] = input("The base address of the server: ")
retval['username'] = input("Username: ")
retval['password'] = input("Password: ")
# record file for the user
data = configparser.ConfigParser()
data['global'] = retval
with open(cfgs[0], 'w') as f:
logger.warn('Recorded "%s" configuration file for next queries')
data.write(f)
os.chmod(cfgs[0], 0o600)
logger.warn('Changed mode of "%s" to be read-only to you')
return retval
def setup_webdav_client(private):
"""Returns a ready-to-use WebDAV client"""
config = _get_config()
root = '/private-upload' if private else '/public-upload'
c = _setup_webdav_client(config['server'], root, config['username'],
config['password'])
return c
#!/usr/bin/env python
# -*- coding: utf-8 -*-
import os
import sys
import click
import pkg_resources
from click_plugins import with_plugins
from . import bdt
from ..dav import setup_webdav_client
from ..log import verbosity_option, get_logger, echo_normal, echo_info, \
echo_warning
logger = get_logger(__name__)
@with_plugins(pkg_resources.iter_entry_points("bdt.dav.cli"))
@click.group(cls=bdt.AliasedGroup)
def dav():
"""Commands for reading/listing/renaming/copying content to a WebDAV server
Commands defined here may require a username and a password to operate
properly.
"""
pass
@dav.command(
epilog="""
Examples:
1. List contents of 'public':
$ bdt dav -vv list
2. List contents of 'public/databases/latest':
$ bdt dav -vv list databases/latest
3. List contents of 'private/docs':
$ bdt dav -vv list -p docs
"""
)
@click.option(
"-p",
"--private/--no-private",
default=False,
help="If set, use the 'private' area instead of the public one",
)
@click.option(
"-l",
"--long-format/--no-long-format",
default=False,
help="If set, print details about each listed file",
)
@click.argument(
"path",
default="/",
required=False,
)
@verbosity_option()
@bdt.raise_on_error
def list(private, long_format, path):
"""List the contents of a given WebDAV directory.
"""
if not path.startswith('/'): path = '/' + path
cl = setup_webdav_client(private)
contents = cl.list(path)
remote_path = cl.get_url(path)
echo_info('ls %s' % (remote_path,))
for k in contents:
if long_format:
info = cl.info('/'.join((path, k)))
echo_normal('%-20s %-10s %s' % (info['created'], info['size'], k))
else:
echo_normal(k)
@dav.command(
epilog="""
Examples:
1. Creates directory 'foo/bar' on the remote server:
$ bdt dav -vv mkdir foo/bar
"""
)
@click.option(
"-p",
"--private/--no-private",
default=False,
help="If set, use the 'private' area instead of the public one",
)
@click.argument(
"path",
required=True,
)
@verbosity_option()
@bdt.raise_on_error
def makedirs(private, path):
"""Creates a given directory, recursively (if necessary)
Gracefully exists if the directory is already there.
"""
if not path.startswith('/'): path = '/' + path
cl = setup_webdav_client(private)
remote_path = cl.get_url(path)
if cl.check(path):
echo_warning('directory %s already exists' % (remote_path,))
rpath = ''
for k in path.split('/'):
rpath = '/'.join((rpath, k)) if rpath else k
if not cl.check(rpath):
echo_info('mkdir %s' % (rpath,))
cl.mkdir(rpath)
@dav.command(
epilog="""
Examples:
1. Removes (recursively), everything under the 'remote/path/foo/bar' path:
$ bdt dav -vv rmtree remote/path/foo/bar
Notice this does not do anything for security. It just displays what it
would do. To actually run the rmtree comment pass the --execute flag (or
-x)
2. Realy removes (recursively), everything under the 'remote/path/foo/bar'
path:
$ bdt dav -vv rmtree --execute remote/path/foo/bar
"""
)
@click.option(
"-p",
"--private/--no-private",
default=False,
help="If set, use the 'private' area instead of the public one",
)
@click.option(
"-x",
"--execute/--no-execute",
default=False,
help="If this flag is set, then execute the removal",
)
@click.argument(
"path",
required=True,
)
@verbosity_option()
@bdt.raise_on_error
def rmtree(private, execute, path):
"""Removes a whole directory tree from the WebDAV server
ATTENTION: There is no undo! Use --execute to execute.
"""
if not execute:
echo_warning("!!!! DRY RUN MODE !!!!")
echo_warning("Nothing is being executed on server. Use -x to execute.")
if not path.startswith('/'): path = '/' + path
cl = setup_webdav_client(private)
remote_path = cl.get_url(path)
if not cl.check(path):
echo_warning('resource %s does not exist' % (remote_path,))
return
echo_info('rm -rf %s' % (remote_path,))
if execute:
cl.clean(path)
@dav.command(
epilog="""
Examples:
1. Uploads a single file to a specific location:
$ bdt dav -vv copy local/file remote
2. Uploads various resources at once:
$ bdt dav -vv copy local/file1 local/dir local/file2 remote
"""
)
@click.option(
"-p",
"--private/--no-private",
default=False,
help="If set, use the 'private' area instead of the public one",
)
@click.option(
"-x",
"--execute/--no-execute",
default=False,
help="If this flag is set, then execute the removal",
)
@click.argument(
"local",
required=True,
type=click.Path(file_okay=True, dir_okay=True, exists=True),
nargs=-1,
)
@click.argument(
"remote",
required=True,
)
@verbosity_option()
@bdt.raise_on_error
def upload(private, execute, local, remote):
"""Uploads a local resource (file or directory) to a remote destination
If the local resource is a directory, it is uploaded recursively. If the
remote resource with the same name already exists, an error is raised (use
rmtree to remove it first).
If the remote location does not exist, it is an error as well. As a
consequence, you cannot change the name of the resource being uploaded with
this command.
ATTENTION: There is no undo! Use --execute to execute.
"""
if not execute:
echo_warning("!!!! DRY RUN MODE !!!!")
echo_warning("Nothing is being executed on server. Use -x to execute.")
if not remote.startswith('/'): remote = '/' + remote
cl = setup_webdav_client(private)
if not cl.check(remote):
echo_warning('base remote directory for upload %s does not exist' %
(remote,))
return 1
for k in local:
actual_remote = remote + os.path.basename(k)
remote_path = cl.get_url(actual_remote)
if cl.check(actual_remote):
echo_warning('resource %s already exists' % (remote_path,))
echo_warning('remove it first before uploading a new copy')
continue
if os.path.isdir(k):
echo_info('cp -r %s %s' % (k, remote_path))
if execute:
cl.upload_directory(local_path=k, remote_path=actual_remote)
else:
echo_info('cp %s %s' % (k, remote_path))
if execute:
cl.upload_file(local_path=k, remote_path=actual_remote)
@dav.command(
epilog="""
Examples:
1. Lists the amount of free disk space on the WebDAV server:
$ bdt dav -vv free
"""
)
@click.option(
"-p",
"--private/--no-private",
default=False,
help="If set, use the 'private' area instead of the public one",
)
@verbosity_option()
@bdt.raise_on_error
def free(private):
"""Lists the amount of free space on the webserver disk
"""
cl = setup_webdav_client(private)
echo_info('free')
data = cl.free()
echo_normal(data)
......@@ -52,6 +52,7 @@ setup(
'test = bob.devtools.scripts.test:test',
'caupdate = bob.devtools.scripts.caupdate:caupdate',
'ci = bob.devtools.scripts.ci:ci',
'dav = bob.devtools.scripts.dav:dav',
'local = bob.devtools.scripts.local:local',
'gitlab = bob.devtools.scripts.gitlab:gitlab',
],
......@@ -86,6 +87,14 @@ setup(
'base-build = bob.devtools.scripts.local:base_build',
],
'bdt.dav.cli': [
'list = bob.devtools.scripts.dav:list',
'makedirs = bob.devtools.scripts.dav:makedirs',
'rmtree = bob.devtools.scripts.dav:rmtree',
'upload = bob.devtools.scripts.dav:upload',
#'free = bob.devtools.scripts.dav:free',
],
},
classifiers=[
'Framework :: Bob',
......
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