view mercurial/fancyopts.py @ 12570:a72c5ff1260c stable

Correct Content-Type header values for archive downloads. The content type for both .tar.gz and .tar.bz2 downloads was application/x-tar, which is correct for .tar files when no Content-Encoding is present, but is not correct for .tar.gz and .tar.bz2 files unless Content-Encoding is set to gzip or x-bzip2, respectively. However, setting Content-Encoding causes browsers to undo that encoding during download, when a .gz or .bz2 file is usually the desired artifact. Omitting the Content-Encoding header is preferred to avoid having browsers uncompress non-render-able files. Additionally, the Content-Disposition line indicates a final desired filename with .tar.gz or .tar.bz2 extension which makes providing a Content-Encoding header inappropriate. With the current configuration browsers (Chrome and Firefox thus far) are registering the application/x-tar Content-Type and not .tar extension and appending that extension, yielding filename.tar.gz.tar as a final on-disk artifact. This was originally reported here: http://stackoverflow.com/questions/3753659 I've changed the .tar.gz and .tar.bz2 Content-Type values to application/x-gzip and application/x-bzip2, respectively. Which yields correctly named download artifacts on Firefox, Chrome, and IE.
author Ry4an Brase <ry4an-hg@ry4an.org>
date Mon, 20 Sep 2010 14:56:08 -0500
parents 40c06bbf58be
children d3bb825ddae3
line wrap: on
line source

# fancyopts.py - better command line parsing
#
#  Copyright 2005-2009 Matt Mackall <mpm@selenic.com> and others
#
# This software may be used and distributed according to the terms of the
# GNU General Public License version 2 or any later version.

import getopt

def gnugetopt(args, options, longoptions):
    """Parse options mostly like getopt.gnu_getopt.

    This is different from getopt.gnu_getopt in that an argument of - will
    become an argument of - instead of vanishing completely.
    """
    extraargs = []
    if '--' in args:
        stopindex = args.index('--')
        extraargs = args[stopindex + 1:]
        args = args[:stopindex]
    opts, parseargs = getopt.getopt(args, options, longoptions)
    args = []
    while parseargs:
        arg = parseargs.pop(0)
        if arg and arg[0] == '-' and len(arg) > 1:
            parseargs.insert(0, arg)
            topts, newparseargs = getopt.getopt(parseargs, options, longoptions)
            opts = opts + topts
            parseargs = newparseargs
        else:
            args.append(arg)
    args.extend(extraargs)
    return opts, args


def fancyopts(args, options, state, gnu=False):
    """
    read args, parse options, and store options in state

    each option is a tuple of:

      short option or ''
      long option
      default value
      description
      option value label(optional)

    option types include:

      boolean or none - option sets variable in state to true
      string - parameter string is stored in state
      list - parameter string is added to a list
      integer - parameter strings is stored as int
      function - call function with parameter

    non-option args are returned
    """
    namelist = []
    shortlist = ''
    argmap = {}
    defmap = {}

    for option in options:
        if len(option) == 5:
            short, name, default, comment, dummy = option
        else:
            short, name, default, comment = option
        # convert opts to getopt format
        oname = name
        name = name.replace('-', '_')

        argmap['-' + short] = argmap['--' + oname] = name
        defmap[name] = default

        # copy defaults to state
        if isinstance(default, list):
            state[name] = default[:]
        elif hasattr(default, '__call__'):
            state[name] = None
        else:
            state[name] = default

        # does it take a parameter?
        if not (default is None or default is True or default is False):
            if short:
                short += ':'
            if oname:
                oname += '='
        if short:
            shortlist += short
        if name:
            namelist.append(oname)

    # parse arguments
    if gnu:
        parse = gnugetopt
    else:
        parse = getopt.getopt
    opts, args = parse(args, shortlist, namelist)

    # transfer result to state
    for opt, val in opts:
        name = argmap[opt]
        t = type(defmap[name])
        if t is type(fancyopts):
            state[name] = defmap[name](val)
        elif t is type(1):
            state[name] = int(val)
        elif t is type(''):
            state[name] = val
        elif t is type([]):
            state[name].append(val)
        elif t is type(None) or t is type(False):
            state[name] = True

    # return unparsed args
    return args