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