from __future__ import division import urllib, urllib2, urlparse import sys import struct import array import os.path import cgi from dosage.output import out from dosage.version import VERSION class NoMatchError(Exception): pass def getMatchValues(matches): return [match.group(1) for match in matches] def fetchManyMatches(url, regexes): '''Returns a list containing lists of matches for each regular expression, in the same order.''' out.write('Matching regex(es) %r multiple times against %s...' % ([rex.pattern for rex in regexes], url), 2) page = urlopen(url) data = page.read() matches = [getMatchValues(regex.finditer(data)) for regex in regexes] if matches: out.write('...found %r' % (matches,), 2) else: out.write('...not found!', 2) return matches def fetchMatches(url, regexes): out.write('Matching regex(es) %r against %s...' % ([rex.pattern for rex in regexes], url), 2) page = urlopen(url) data = page.read() matches = [] for regex in regexes: match = regex.search(data) matches.append(match and match.group(1)) if matches: out.write('...found %r' % (matches,), 2) else: out.write('...not found!', 2) return matches def fetchMatch(url, regex): return fetchMatches(url, (regex,))[0] def fetchUrl(url, regex): match = fetchMatch(url, regex) return match and urllib.basejoin(url, match) def fetchUrls(url, regexes): matches = fetchMatches(url, regexes) return [urllib.basejoin(url, match) for match in matches] def fetchManyUrls(url, regexes): matchGroups = fetchManyMatches(url, regexes) xformedGroups = [] for matchGroup in matchGroups: xformedGroups.append([urllib.basejoin(url, match) for match in matchGroup]) return xformedGroups def normalizeUrl(url): '''Removes any leading empty segments to avoid breaking urllib2.''' pu = list(urlparse.urlparse(url)) segments = pu[2].split('/') while segments and segments[0] == '': del segments[0] pu[2] = '/' + '/'.join(segments) return urlparse.urlunparse(pu) def urlopen(url, referrer=None, retries=5): # Work around urllib2 brokenness url = normalizeUrl(url) req = urllib2.Request(url) if referrer: req.add_header('Referrer', referrer) req.add_header('Referer', referrer) req.add_header('User-Agent', 'Dosage %s (http://slipgate.za.net/dosage)' % (VERSION,)) tries = 0 while 1: try: urlobj = urllib2.urlopen(req) break except IOError: out.write('URL retrieval failed, retrying (%d)' % (tries,), 2) tries += 1 if tries >= retries: raise return urlobj def getWindowSize(): try: from fcntl import ioctl from termios import TIOCGWINSZ except ImportError: raise NotImplementedError st = 'HHHH' names = 'ws_row', 'ws_col', 'ws_xpixel', 'ws_ypixel' buf = array.array('b', ' ' * struct.calcsize(st)) try: ioctl(sys.stderr, TIOCGWINSZ, buf, True) except IOError: raise NotImplementedError winsize = dict(zip(names, struct.unpack(st, buf))) return winsize['ws_col'] suffixes = ('B', 'KB', 'MB', 'GB', 'TB', 'PB', 'EB', 'ZB', 'YB') def saneDataSize(size): fsize = float(size) for exponent, suffix in enumerate(suffixes): saneSize = fsize / 1024 ** exponent saneSizeStr = '%0.3f %s' % (saneSize, suffix) if (saneSize >= 0 and saneSize < 1024) or (saneSize < 0 and saneSize > -1024): break return saneSizeStr def splitpath(path): c = [] head, tail = os.path.split(path) while tail: c.insert(0, tail) head, tail = os.path.split(head) return c def getRelativePath(basepath, path): basepath = splitpath(os.path.abspath(basepath)) path = splitpath(os.path.abspath(path)) afterCommon = False for c in basepath: if afterCommon or path[0] != c: path.insert(0, os.path.pardir) afterCommon = True else: del path[0] return os.path.join(*path) def getQueryParams(url): query = urllib.splitquery(url)[-1] out.write('Extracting query parameters from %r (%r)...' % (url, query), 3) return cgi.parse_qs(query)