nextcloud-android/third_party/transifex-client/txclib/utils.py
2012-07-21 22:10:36 +02:00

259 lines
7.8 KiB
Python

import os, sys, re, errno
try:
from json import loads as parse_json, dumps as compile_json
except ImportError:
from simplejson import loads as parse_json, dumps as compile_json
import urllib2 # This should go and instead use do_url_request everywhere
from urls import API_URLS
from txclib.log import logger
from txclib.exceptions import UnknownCommandError
def find_dot_tx(path = os.path.curdir, previous = None):
"""
Return the path where .tx folder is found.
The 'path' should be a DIRECTORY.
This process is functioning recursively from the current directory to each
one of the ancestors dirs.
"""
path = os.path.abspath(path)
if path == previous:
return None
joined = os.path.join(path, ".tx")
if os.path.isdir(joined):
return path
else:
return find_dot_tx(os.path.dirname(path), path)
#################################################
# Parse file filter expressions and create regex
def regex_from_filefilter(file_filter, root_path = os.path.curdir):
"""
Create proper regex from <lang> expression
"""
# Force expr to be a valid regex expr (escaped) but keep <lang> intact
expr_re = re.escape(os.path.join(root_path, file_filter))
expr_re = expr_re.replace("\\<lang\\>", '<lang>').replace(
'<lang>', '([^%(sep)s]+)' % { 'sep': re.escape(os.path.sep)})
return "^%s$" % expr_re
TX_URLS = {
'resource': '(?P<hostname>https?://(\w|\.|:|-)+)/projects/p/(?P<project>(\w|-)+)/resource/(?P<resource>(\w|-)+)/?$',
'release': '(?P<hostname>https?://(\w|\.|:|-)+)/projects/p/(?P<project>(\w|-)+)/r/(?P<release>(\w|-)+)/?$',
'project': '(?P<hostname>https?://(\w|\.|:|-)+)/projects/p/(?P<project>(\w|-)+)/?$',
}
def parse_tx_url(url):
"""
Try to match given url to any of the valid url patterns specified in
TX_URLS. If not match is found, we raise exception
"""
for type in TX_URLS.keys():
pattern = TX_URLS[type]
m = re.match(pattern, url)
if m:
return type, m.groupdict()
raise Exception("tx: Malformed url given. Please refer to our docs: http://bit.ly/txautor")
def get_details(api_call, username, password, *args, **kwargs):
"""
Get the tx project info through the API.
This function can also be used to check the existence of a project.
"""
import base64
url = (API_URLS[api_call] % (kwargs)).encode('UTF-8')
req = urllib2.Request(url=url)
base64string = base64.encodestring('%s:%s' % (username, password))[:-1]
authheader = "Basic %s" % base64string
req.add_header("Authorization", authheader)
try:
fh = urllib2.urlopen(req)
raw = fh.read()
fh.close()
remote_project = parse_json(raw)
except urllib2.HTTPError, e:
if e.code in [401, 403, 404]:
raise e
else:
# For other requests, we should print the message as well
raise Exception("Remote server replied: %s" % e.read())
except urllib2.URLError, e:
error = e.args[0]
raise Exception("Remote server replied: %s" % error[1])
return remote_project
def valid_slug(slug):
"""
Check if a slug contains only valid characters.
Valid chars include [-_\w]
"""
try:
a, b = slug.split('.')
except ValueError:
return False
else:
if re.match("^[A-Za-z0-9_-]*$", a) and re.match("^[A-Za-z0-9_-]*$", b):
return True
return False
def discover_commands():
"""
Inspect commands.py and find all available commands
"""
import inspect
from txclib import commands
command_table = {}
fns = inspect.getmembers(commands, inspect.isfunction)
for name, fn in fns:
if name.startswith("cmd_"):
command_table.update({
name.split("cmd_")[1]:fn
})
return command_table
def exec_command(command, *args, **kwargs):
"""
Execute given command
"""
commands = discover_commands()
try:
cmd_fn = commands[command]
except KeyError:
raise UnknownCommandError
cmd_fn(*args,**kwargs)
def mkdir_p(path):
try:
if path:
os.makedirs(path)
except OSError, exc: # Python >2.5
if exc.errno == errno.EEXIST:
pass
else:
raise
def confirm(prompt='Continue?', default=True):
"""
Prompt the user for a Yes/No answer.
Args:
prompt: The text displayed to the user ([Y/n] will be appended)
default: If the default value will be yes or no
"""
valid_yes = ['Y', 'y', 'Yes', 'yes', ]
valid_no = ['N', 'n', 'No', 'no', ]
if default:
prompt = prompt + '[Y/n]'
valid_yes.append('')
else:
prompt = prompt + '[y/N]'
valid_no.append('')
ans = raw_input(prompt)
while (ans not in valid_yes and ans not in valid_no):
ans = raw_input(prompt)
return ans in valid_yes
# Stuff for command line colored output
COLORS = [
'BLACK', 'RED', 'GREEN', 'YELLOW',
'BLUE', 'MAGENTA', 'CYAN', 'WHITE'
]
DISABLE_COLORS = False
def color_text(text, color_name, bold=False):
"""
This command can be used to colorify command line output. If the shell
doesn't support this or the --disable-colors options has been set, it just
returns the plain text.
Usage:
print "%s" % color_text("This text is red", "RED")
"""
if color_name in COLORS and not DISABLE_COLORS:
return '\033[%s;%sm%s\033[0m' % (
int(bold), COLORS.index(color_name) + 30, text)
else:
return text
##############################################
# relpath implementation taken from Python 2.7
if not hasattr(os.path, 'relpath'):
if os.path is sys.modules.get('ntpath'):
def relpath(path, start=os.path.curdir):
"""Return a relative version of a path"""
if not path:
raise ValueError("no path specified")
start_list = os.path.abspath(start).split(os.path.sep)
path_list = os.path.abspath(path).split(os.path.sep)
if start_list[0].lower() != path_list[0].lower():
unc_path, rest = os.path.splitunc(path)
unc_start, rest = os.path.splitunc(start)
if bool(unc_path) ^ bool(unc_start):
raise ValueError("Cannot mix UNC and non-UNC paths (%s and %s)"
% (path, start))
else:
raise ValueError("path is on drive %s, start on drive %s"
% (path_list[0], start_list[0]))
# Work out how much of the filepath is shared by start and path.
for i in range(min(len(start_list), len(path_list))):
if start_list[i].lower() != path_list[i].lower():
break
else:
i += 1
rel_list = [os.path.pardir] * (len(start_list)-i) + path_list[i:]
if not rel_list:
return os.path.curdir
return os.path.join(*rel_list)
else:
# default to posixpath definition
def relpath(path, start=os.path.curdir):
"""Return a relative version of a path"""
if not path:
raise ValueError("no path specified")
start_list = os.path.abspath(start).split(os.path.sep)
path_list = os.path.abspath(path).split(os.path.sep)
# Work out how much of the filepath is shared by start and path.
i = len(os.path.commonprefix([start_list, path_list]))
rel_list = [os.path.pardir] * (len(start_list)-i) + path_list[i:]
if not rel_list:
return os.path.curdir
return os.path.join(*rel_list)
else:
from os.path import relpath