mirror of
https://github.com/YunoHost/moulinette.git
synced 2024-09-03 20:06:31 +02:00
Merge branch 'unstable' into testing
This commit is contained in:
commit
f4c5f37614
6 changed files with 156 additions and 6 deletions
2
debian/copyright
vendored
2
debian/copyright
vendored
|
@ -2,7 +2,7 @@ Format: http://www.debian.org/doc/packaging-manuals/copyright-format/1.0/
|
||||||
Source: https://github.com/YunoHost/moulinette
|
Source: https://github.com/YunoHost/moulinette
|
||||||
|
|
||||||
Files: *
|
Files: *
|
||||||
Copyright: 2014 YUNOHOST.ORG
|
Copyright: 2015 YUNOHOST.ORG
|
||||||
License: AGPL-3
|
License: AGPL-3
|
||||||
|
|
||||||
License: AGPL-3
|
License: AGPL-3
|
||||||
|
|
0
debian/install
vendored
0
debian/install
vendored
|
@ -94,7 +94,7 @@ def api(namespaces, host='localhost', port=80, routes={},
|
||||||
'use_cache': use_cache })
|
'use_cache': use_cache })
|
||||||
moulinette.run(host, port)
|
moulinette.run(host, port)
|
||||||
|
|
||||||
def cli(namespaces, args, print_json=False, use_cache=True):
|
def cli(namespaces, args, print_json=False, print_plain=False, use_cache=True):
|
||||||
"""Command line interface
|
"""Command line interface
|
||||||
|
|
||||||
Execute an action with the moulinette from the CLI and print its
|
Execute an action with the moulinette from the CLI and print its
|
||||||
|
@ -104,6 +104,7 @@ def cli(namespaces, args, print_json=False, use_cache=True):
|
||||||
- namespaces -- The list of namespaces to use
|
- namespaces -- The list of namespaces to use
|
||||||
- args -- A list of argument strings
|
- args -- A list of argument strings
|
||||||
- print_json -- True to print result as a JSON encoded string
|
- print_json -- True to print result as a JSON encoded string
|
||||||
|
- print_plain -- True to print result as a script-usable string
|
||||||
- use_cache -- False if it should parse the actions map file
|
- use_cache -- False if it should parse the actions map file
|
||||||
instead of using the cached one
|
instead of using the cached one
|
||||||
|
|
||||||
|
@ -114,7 +115,7 @@ def cli(namespaces, args, print_json=False, use_cache=True):
|
||||||
moulinette = init_interface('cli',
|
moulinette = init_interface('cli',
|
||||||
actionsmap={'namespaces': namespaces,
|
actionsmap={'namespaces': namespaces,
|
||||||
'use_cache': use_cache})
|
'use_cache': use_cache})
|
||||||
moulinette.run(args, print_json)
|
moulinette.run(args, print_json, print_plain)
|
||||||
except MoulinetteError as e:
|
except MoulinetteError as e:
|
||||||
print('%s %s' % (colorize(m18n.g('error'), 'red'), e.strerror))
|
print('%s %s' % (colorize(m18n.g('error'), 'red'), e.strerror))
|
||||||
return e.errno
|
return e.errno
|
||||||
|
|
|
@ -194,7 +194,7 @@ class Translator(object):
|
||||||
|
|
||||||
try:
|
try:
|
||||||
return _load_key(self.locale)
|
return _load_key(self.locale)
|
||||||
except KeyError:
|
except (KeyError, IndexError):
|
||||||
if self.default_locale != self.locale:
|
if self.default_locale != self.locale:
|
||||||
logger.info("untranslated key '%s' for locale '%s'",
|
logger.info("untranslated key '%s' for locale '%s'",
|
||||||
key, self.locale)
|
key, self.locale)
|
||||||
|
|
|
@ -42,8 +42,47 @@ def colorize(astr, color):
|
||||||
else:
|
else:
|
||||||
return astr
|
return astr
|
||||||
|
|
||||||
|
def plain_print_dict(d, depth=0):
|
||||||
|
"""Print in a plain way a dictionary recursively
|
||||||
|
|
||||||
|
Print a dictionary recursively for scripting usage to the standard output.
|
||||||
|
|
||||||
|
Output formatting:
|
||||||
|
>>> d = {'key': 'value', 'list': [1,2], 'dict': {'key2': 'value2'}}
|
||||||
|
>>> plain_print_dict(d)
|
||||||
|
#key
|
||||||
|
value
|
||||||
|
#list
|
||||||
|
1
|
||||||
|
2
|
||||||
|
#dict
|
||||||
|
##key2
|
||||||
|
value2
|
||||||
|
|
||||||
|
Keyword arguments:
|
||||||
|
- d -- The dictionary to print
|
||||||
|
- depth -- The recursive depth of the dictionary
|
||||||
|
|
||||||
|
"""
|
||||||
|
# skip first key printing
|
||||||
|
if depth == 0 and (isinstance(d, dict) and len(d) == 1):
|
||||||
|
_, d = d.popitem()
|
||||||
|
if isinstance(d, (tuple, set)):
|
||||||
|
d = list(d)
|
||||||
|
if isinstance(d, list):
|
||||||
|
for v in d:
|
||||||
|
plain_print_dict(v, depth+1)
|
||||||
|
elif isinstance(d, dict):
|
||||||
|
for k,v in d.items():
|
||||||
|
print("{}{}".format("#" * (depth+1), k))
|
||||||
|
plain_print_dict(v, depth+1)
|
||||||
|
else:
|
||||||
|
if isinstance(d, unicode):
|
||||||
|
d = d.encode('utf-8')
|
||||||
|
print(d)
|
||||||
|
|
||||||
def pretty_print_dict(d, depth=0):
|
def pretty_print_dict(d, depth=0):
|
||||||
"""Print a dictionary recursively
|
"""Print in a pretty way a dictionary recursively
|
||||||
|
|
||||||
Print a dictionary recursively with colors to the standard output.
|
Print a dictionary recursively with colors to the standard output.
|
||||||
|
|
||||||
|
@ -187,7 +226,7 @@ class Interface(BaseInterface):
|
||||||
|
|
||||||
self.actionsmap = actionsmap
|
self.actionsmap = actionsmap
|
||||||
|
|
||||||
def run(self, args, print_json=False):
|
def run(self, args, print_json=False, print_plain=False):
|
||||||
"""Run the moulinette
|
"""Run the moulinette
|
||||||
|
|
||||||
Process the action corresponding to the given arguments 'args'
|
Process the action corresponding to the given arguments 'args'
|
||||||
|
@ -196,8 +235,12 @@ class Interface(BaseInterface):
|
||||||
Keyword arguments:
|
Keyword arguments:
|
||||||
- args -- A list of argument strings
|
- args -- A list of argument strings
|
||||||
- print_json -- True to print result as a JSON encoded string
|
- print_json -- True to print result as a JSON encoded string
|
||||||
|
- print_plain -- True to print result as a script-usable string
|
||||||
|
|
||||||
"""
|
"""
|
||||||
|
if print_json and print_plain:
|
||||||
|
raise MoulinetteError(errno.EINVAL, m18n.g('invalid_usage'))
|
||||||
|
|
||||||
try:
|
try:
|
||||||
ret = self.actionsmap.process(args, timeout=5)
|
ret = self.actionsmap.process(args, timeout=5)
|
||||||
except KeyboardInterrupt, EOFError:
|
except KeyboardInterrupt, EOFError:
|
||||||
|
@ -211,6 +254,8 @@ class Interface(BaseInterface):
|
||||||
import json
|
import json
|
||||||
from moulinette.utils.serialize import JSONExtendedEncoder
|
from moulinette.utils.serialize import JSONExtendedEncoder
|
||||||
print(json.dumps(ret, cls=JSONExtendedEncoder))
|
print(json.dumps(ret, cls=JSONExtendedEncoder))
|
||||||
|
elif print_plain:
|
||||||
|
plain_print_dict(ret)
|
||||||
elif isinstance(ret, dict):
|
elif isinstance(ret, dict):
|
||||||
pretty_print_dict(ret)
|
pretty_print_dict(ret)
|
||||||
else:
|
else:
|
||||||
|
|
104
moulinette/utils/filesystem.py
Normal file
104
moulinette/utils/filesystem.py
Normal file
|
@ -0,0 +1,104 @@
|
||||||
|
import os
|
||||||
|
import shutil
|
||||||
|
from pwd import getpwnam
|
||||||
|
from grp import getgrnam
|
||||||
|
|
||||||
|
|
||||||
|
# Files & directories --------------------------------------------------
|
||||||
|
|
||||||
|
def mkdir(path, mode=0777, parents=False, uid=None, gid=None, force=False):
|
||||||
|
"""Create a directory with optional features
|
||||||
|
|
||||||
|
Create a directory and optionaly set its permissions to mode and its
|
||||||
|
owner and/or group. If path refers to an existing path, nothing is done
|
||||||
|
unless force is True.
|
||||||
|
|
||||||
|
Keyword arguments:
|
||||||
|
- path -- The directory to create
|
||||||
|
- mode -- Numeric path mode to set
|
||||||
|
- parents -- Make parent directories as needed
|
||||||
|
- uid -- Numeric uid or user name
|
||||||
|
- gid -- Numeric gid or group name
|
||||||
|
- force -- Force directory creation and owning even if the path exists
|
||||||
|
|
||||||
|
"""
|
||||||
|
if os.path.exists(path) and not force:
|
||||||
|
return
|
||||||
|
if parents:
|
||||||
|
os.makedirs(path, mode)
|
||||||
|
else:
|
||||||
|
os.mkdir(path, mode)
|
||||||
|
try:
|
||||||
|
chown(path, uid, gid)
|
||||||
|
except:
|
||||||
|
pass
|
||||||
|
|
||||||
|
|
||||||
|
def chown(path, uid=None, gid=None, recursive=False):
|
||||||
|
"""Change the owner and/or group of a path
|
||||||
|
|
||||||
|
Keyword arguments:
|
||||||
|
- uid -- Numeric uid or user name
|
||||||
|
- gid -- Numeric gid or group name
|
||||||
|
- recursive -- Operate on path recursively
|
||||||
|
|
||||||
|
"""
|
||||||
|
if uid is None and gid is None:
|
||||||
|
raise ValueError("either uid or gid argument is required")
|
||||||
|
|
||||||
|
# Retrieve uid/gid
|
||||||
|
if isinstance(uid, basestring):
|
||||||
|
uid = getpwnam(uid).pw_uid
|
||||||
|
elif uid is None:
|
||||||
|
uid = -1
|
||||||
|
if isinstance(gid, basestring):
|
||||||
|
gid = getpwnam(gid).gr_gid
|
||||||
|
elif gid is None:
|
||||||
|
gid = -1
|
||||||
|
|
||||||
|
os.chown(path, uid, gid)
|
||||||
|
if recursive and os.path.isdir(path):
|
||||||
|
for root, dirs, files in os.walk(path):
|
||||||
|
for d in dirs:
|
||||||
|
os.chown(os.path.join(root, d), uid, gid)
|
||||||
|
for f in files:
|
||||||
|
os.chown(os.path.join(root, f), uid, gid)
|
||||||
|
|
||||||
|
|
||||||
|
def chmod(path, mode, fmode=None, recursive=False):
|
||||||
|
"""Change the mode of a path
|
||||||
|
|
||||||
|
Keyword arguments:
|
||||||
|
- mode -- Numeric path mode to set
|
||||||
|
- fmode -- Numeric file mode to set in case of a recursive directory
|
||||||
|
- recursive -- Operate on path recursively
|
||||||
|
|
||||||
|
"""
|
||||||
|
os.chmod(path, mode)
|
||||||
|
if recursive and os.path.isdir(path):
|
||||||
|
if fmode is None:
|
||||||
|
fmode = mode
|
||||||
|
for root, dirs, files in os.walk(path):
|
||||||
|
for d in dirs:
|
||||||
|
os.chmod(path, mode)
|
||||||
|
for f in files:
|
||||||
|
os.chmod(path, fmode)
|
||||||
|
|
||||||
|
|
||||||
|
def rm(path, recursive=False, force=False):
|
||||||
|
"""Remove a file or directory
|
||||||
|
|
||||||
|
Keyword arguments:
|
||||||
|
- path -- The path to remove
|
||||||
|
- recursive -- Remove directories and their contents recursively
|
||||||
|
- force -- Ignore nonexistent files
|
||||||
|
|
||||||
|
"""
|
||||||
|
if recursive and os.path.isdir(path):
|
||||||
|
shutil.rmtree(path, ignore_errors=force)
|
||||||
|
else:
|
||||||
|
try:
|
||||||
|
os.remove(path)
|
||||||
|
except OSError:
|
||||||
|
if not force:
|
||||||
|
raise
|
Loading…
Add table
Reference in a new issue