318bee91701d9fa926e4882da67d408da562ab2c
1 import os
, sys
, re
, errno
3 from json
import loads
as parse_json
, dumps
as compile_json
5 from simplejson
import loads
as parse_json
, dumps
as compile_json
6 import urllib2
# This should go and instead use do_url_request everywhere
8 from urls
import API_URLS
9 from txclib
.log
import logger
10 from txclib
.exceptions
import UnknownCommandError
13 def find_dot_tx(path
= os
.path
.curdir
, previous
= None):
15 Return the path where .tx folder is found.
17 The 'path' should be a DIRECTORY.
18 This process is functioning recursively from the current directory to each
19 one of the ancestors dirs.
21 path
= os
.path
.abspath(path
)
24 joined
= os
.path
.join(path
, ".tx")
25 if os
.path
.isdir(joined
):
28 return find_dot_tx(os
.path
.dirname(path
), path
)
31 #################################################
32 # Parse file filter expressions and create regex
34 def regex_from_filefilter(file_filter
, root_path
= os
.path
.curdir
):
36 Create proper regex from <lang> expression
38 # Force expr to be a valid regex expr (escaped) but keep <lang> intact
39 expr_re
= re
.escape(os
.path
.join(root_path
, file_filter
))
40 expr_re
= expr_re
.replace("\\<lang\\>", '<lang>').replace(
41 '<lang>', '([^%(sep)s]+)' %
{ 'sep': re
.escape(os
.path
.sep
)})
43 return "^%s$" % expr_re
47 'resource': '(?P<hostname>https?://(\w|\.|:|-)+)/projects/p/(?P<project>(\w|-)+)/resource/(?P<resource>(\w|-)+)/?$',
48 'release': '(?P<hostname>https?://(\w|\.|:|-)+)/projects/p/(?P<project>(\w|-)+)/r/(?P<release>(\w|-)+)/?$',
49 'project': '(?P<hostname>https?://(\w|\.|:|-)+)/projects/p/(?P<project>(\w|-)+)/?$',
53 def parse_tx_url(url
):
55 Try to match given url to any of the valid url patterns specified in
56 TX_URLS. If not match is found, we raise exception
58 for type in TX_URLS
.keys():
59 pattern
= TX_URLS
[type]
60 m
= re
.match(pattern
, url
)
62 return type, m
.groupdict()
64 raise Exception("tx: Malformed url given. Please refer to our docs: http://bit.ly/txautor")
67 def get_details(api_call
, username
, password
, *args
, **kwargs
):
69 Get the tx project info through the API.
71 This function can also be used to check the existence of a project.
74 url
= (API_URLS
[api_call
] %
(kwargs
)).encode('UTF-8')
76 req
= urllib2
.Request(url
=url
)
77 base64string
= base64
.encodestring('%s:%s' %
(username
, password
))[:-1]
78 authheader
= "Basic %s" % base64string
79 req
.add_header("Authorization", authheader
)
82 fh
= urllib2
.urlopen(req
)
85 remote_project
= parse_json(raw
)
86 except urllib2
.HTTPError
, e
:
87 if e
.code
in [401, 403, 404]:
90 # For other requests, we should print the message as well
91 raise Exception("Remote server replied: %s" % e
.read())
92 except urllib2
.URLError
, e
:
94 raise Exception("Remote server replied: %s" % error
[1])
101 Check if a slug contains only valid characters.
103 Valid chars include [-_\w]
106 a
, b
= slug
.split('.')
110 if re
.match("^[A-Za-z0-9_-]*$", a
) and re
.match("^[A-Za-z0-9_-]*$", b
):
115 def discover_commands():
117 Inspect commands.py and find all available commands
120 from txclib
import commands
123 fns
= inspect
.getmembers(commands
, inspect
.isfunction
)
126 if name
.startswith("cmd_"):
127 command_table
.update({
128 name
.split("cmd_")[1]:fn
134 def exec_command(command
, *args
, **kwargs
):
136 Execute given command
138 commands
= discover_commands()
140 cmd_fn
= commands
[command
]
142 raise UnknownCommandError
143 cmd_fn(*args
,**kwargs
)
150 except OSError, exc
: # Python >2.5
151 if exc
.errno
== errno
.EEXIST
:
157 def confirm(prompt
='Continue?', default
=True):
159 Prompt the user for a Yes/No answer.
162 prompt: The text displayed to the user ([Y/n] will be appended)
163 default: If the default value will be yes or no
165 valid_yes
= ['Y', 'y', 'Yes', 'yes', ]
166 valid_no
= ['N', 'n', 'No', 'no', ]
168 prompt
= prompt
+ '[Y/n]'
171 prompt
= prompt
+ '[y/N]'
174 ans
= raw_input(prompt
)
175 while (ans
not in valid_yes
and ans
not in valid_no
):
176 ans
= raw_input(prompt
)
178 return ans
in valid_yes
181 # Stuff for command line colored output
184 'BLACK', 'RED', 'GREEN', 'YELLOW',
185 'BLUE', 'MAGENTA', 'CYAN', 'WHITE'
188 DISABLE_COLORS
= False
191 def color_text(text
, color_name
, bold
=False):
193 This command can be used to colorify command line output. If the shell
194 doesn't support this or the --disable-colors options has been set, it just
195 returns the plain text.
198 print "%s" % color_text("This text is red", "RED")
200 if color_name
in COLORS
and not DISABLE_COLORS
:
201 return '\033[%s;%sm%s\033[0m' %
(
202 int(bold
), COLORS
.index(color_name
) + 30, text
)
207 ##############################################
208 # relpath implementation taken from Python 2.7
210 if not hasattr(os
.path
, 'relpath'):
211 if os
.path
is sys
.modules
.get('ntpath'):
212 def relpath(path
, start
=os
.path
.curdir
):
213 """Return a relative version of a path"""
216 raise ValueError("no path specified")
217 start_list
= os
.path
.abspath(start
).split(os
.path
.sep
)
218 path_list
= os
.path
.abspath(path
).split(os
.path
.sep
)
219 if start_list
[0].lower() != path_list
[0].lower():
220 unc_path
, rest
= os
.path
.splitunc(path
)
221 unc_start
, rest
= os
.path
.splitunc(start
)
222 if bool(unc_path
) ^
bool(unc_start
):
223 raise ValueError("Cannot mix UNC and non-UNC paths (%s and %s)"
226 raise ValueError("path is on drive %s, start on drive %s"
227 %
(path_list
[0], start_list
[0]))
228 # Work out how much of the filepath is shared by start and path.
229 for i
in range(min(len(start_list
), len(path_list
))):
230 if start_list
[i
].lower() != path_list
[i
].lower():
235 rel_list
= [os
.path
.pardir
] * (len(start_list
)-i
) + path_list
[i
:]
237 return os
.path
.curdir
238 return os
.path
.join(*rel_list
)
241 # default to posixpath definition
242 def relpath(path
, start
=os
.path
.curdir
):
243 """Return a relative version of a path"""
246 raise ValueError("no path specified")
248 start_list
= os
.path
.abspath(start
).split(os
.path
.sep
)
249 path_list
= os
.path
.abspath(path
).split(os
.path
.sep
)
251 # Work out how much of the filepath is shared by start and path.
252 i
= len(os
.path
.commonprefix([start_list
, path_list
]))
254 rel_list
= [os
.path
.pardir
] * (len(start_list
)-i
) + path_list
[i
:]
256 return os
.path
.curdir
257 return os
.path
.join(*rel_list
)
259 from os
.path
import relpath