view fetch/main.py @ 0:3497a30190d2

initial commit of fetch, WIP
author Jeff Hammel <jhammel@mozilla.com>
date Sun, 18 Sep 2011 10:33:04 -0700
parents
children 0c344ed749ac
line wrap: on
line source

#!/usr/bin/env python

"""
fetch stuff from the interwebs
"""

import os
import sys
import optparse

class Fetcher(object):
  """abstract base class for resource fetchers"""

  @classmethod
  def match(cls, _type):
    return _type == cls.type

  def __init__(self, url):
    self.url = url

  def __call__(self, dest):
    raise NotImplementedError


import urllib2

class FileFetcher(object):
  """fetch a single file"""
  
  type = 'file'

  @classmethod
  def download(cls, url):
    return urllib2.urlopen(url).read()

  def __call__(self, dest):
    if os.path.isdir(dest):
      filename = url.rsplit('/', 1)[-1]
      dest = os.path.join(dest, filename)
    f = file(dest, 'w')
    f.write(self.download(self.url))
    f.close()

class TarballFetcher(object):
  """fetch and extract a tarball"""

  type = 'tar'

class HgFetcher(object):
  """checkout a mercurial repository"""

class GitFetcher(object):
  """checkout a git repository"""

fetchers = [FileFetcher]

class Fetch(object):
  
  def __init__(self, fetchers, relative_to=None, strict=True):
    self.fetchers = fetchers
    self.relative_to = relative_to
    self.strict = strict

  def fetcher(self, _type):
    """find the fetcher for the appropriate type"""
    for fetcher in fetchers:
      if fetcher.match(_type):
        return fetcher

  def __call__(self, url, destination, type, **options):
    fetcher = self.fetcher(type)
    assert fetcher is not None
    fetcher = fetcher(url, **options)
    fetcher(destination)

  def fetch(self, *items):
    for item in items:
      self(item['url'])

format_string = "[URL] [destination] [type] <options>"
def read_manifests(*manifests):
  """
  read some manifests and return the items

  Format:
  %s
  """ % format_string

  # sanity check
  assert not [i for i in manifest if not.os.path.exists(i)]

  retval = []

  for manifest in manifests:
    for line in file(i).readlines():
      line = line.strip()
      if line.startswith('#'):
        pass
      line = line.split()
      if len(line) not in (3,4):
        raise Exception("Format should be: %s; line %s" % (format_string, line))
      options = {}
      if len(line) == 4:
        option_string = line.pop().rstrip(',')
        try:
          options = dict([[j.strip() for j in i.split('=', 1)]
                          for i in option_string.split(',')])
        except:
          raise Exception("Options format should be: key=value,key2=value2,...; got %s" % option_string)

      url, dest, _type = line
      retval.append(dict(url=url, dest=dest, type=_type, options=options, manifest=manifest))
  return retval

def main(args=sys.argv[:]):

  # parse command line options
  usage = '%prog [options] manifest [manifest] [...]'

  # description formatter
  class PlainDescriptionFormatter(optparse.IndentedHelpFormatter):
    def format_description(self, description):
      if description:
        return description + '\n'
      else:
        return ''
  
  parser = optparse.OptionParser(usage=usage, description=__doc__, formatter=PlainDescriptionFormatter())
  parser.add_option('-o', '--output',
                    help="output relative to this location vs. the manifest location")
  parser.add_option('-d', '--dest',
                    action='append',
                    help="output only these destinations")
  parser.add_option('-s', '--strict',
                    action='store_true', default=False,
                    help="fail on error")
  options, args = parser.parse_args(args)

  if not args:
    parser.print_help()
    parser.exit()

  items = read_manifests(*args)
  fetch = Fetch(fetchers, strict=options.strict)

  # ensure the all the required fetchers are available
  # TODO: to Fetch class
  types = set([i['type'] for i in items])
  assert not [i for i in types
              if [True for fetcher in fetchers if fetcher.match(i)]]

  # download the files
  fetch.fetch(*items)

if __name__ == '__main__':
  main()