1. Steve Losh
  2. hg-paste


hg-paste / paste.py

#!/usr/bin/env python

'''send diffs from Mercurial to various pastebin websites

import sys
import urllib2
from netrc import netrc
from base64 import urlsafe_b64encode
from mercurial import cmdutil, commands, help, util
from urllib import urlencode

def _paste_dpaste(content, **parameters):
    data = {'content': content, 'language': parameters['syntax'] or 'Diff'}
    if parameters['title']:
        data['title'] = parameters['title']
    if parameters['user']:
        data['poster'] = parameters['user']

    if len(data['poster']) > 30:
        data['poster'] = data['poster'][:30]

    if parameters['keep']:
        data['hold'] = 'on'
    return data

def _paste_dpaste_org(content, **parameters):
    data = {'content': content, 'lexer': parameters['syntax'] or 'diff'}
    if parameters['title']:
        data['title'] = parameters['title']
    if parameters['user']:
        data['author'] = parameters['user']

    if len(data['author']) > 30:
        data['author'] = data['author'][:30]

    # Same values used in dpaste.org form for default (a month) and forever expires.
    data['expire_options'] = '3110400000' if parameters['keep'] else '2592000'
    return data

def _paste_pastebin_dixo_net(content, **parameters):
    return {
            'paste': 'Send',
            'code2': content,
            'format': parameters['syntax'] or 'diff',
            'expiry': 'f' if parameters['keep'] else 'm',
            'poster': parameters.get('user', ''),

pastebins = {
    'dpaste': { 'url': 'http://dpaste.com/api/v1/',
                'parameters': {
                    'required': ['content'],
                    'optional': ['title', 'user', 'keep'], },
                'handler': _paste_dpaste,
    'dpaste.org': { 'url': 'http://dpaste.org/',
                'parameters': {
                    'required': ['content'],
                    'optional': ['title', 'user', 'keep'], },
                'handler': _paste_dpaste_org,
    'pastebin.dixo.net': { 'url': 'http://pastebin.dixo.net/',
                'parameters': {
                    'required': ['content'],
                    'optional': ['user', 'keep'], },
                'handler': _paste_pastebin_dixo_net,

def _authorize_request(request, httpauth=None, usenetrc=None, **kwargs):
    """Sets basic authorization header using httpauth flag or netrc if enabled"""
    if httpauth:
        b64cred = urlsafe_b64encode(httpauth)
        request.add_header('Authorization', 'Basic %s' % b64cred)
    elif usenetrc:
        cred = netrc().authenticators(request.get_host())
        if cred:
            b64cred = urlsafe_b64encode('%s:%s' % (cred[0], cred[2]))
            request.add_header('Authorization', 'Basic %s' % b64cred)

def _do_paste(pastebin, content, parameters):
    url = parameters.get('url') or pastebin['url']
    data = pastebin['handler'](content, **parameters)
    request = urllib2.Request(url, urlencode(data))
    _authorize_request(request, **parameters)
    response = urllib2.urlopen(request)
    geturl = pastebin.get('geturl')
    return geturl(response) if geturl else response.geturl()

def paste(ui, repo, *fnames, **opts):
    '''send diffs from Mercurial to various pastebin websites
    Send a diff of the specified files to a pastebin website to easily
    share with other people.  If no files are specified all files will
    be included.
    To paste a diff of all uncommitted changes in the working directory:
        hg paste
    To paste the changes that revision REV made:
        hg paste -r REV
    To paste the changes between revisions REV1 and REV2:
        hg paste -r REV1:REV2
    Several options can be used to specify more metadata about the paste:
        hg paste --user Steve --title 'Progress on feature X' --keep
    The pastebin website to use can be specified with --dest.  See
    'hg help pastebins' for more information.
    dest = opts.pop('dest')
    dry = opts.pop('dry_run')
    if not dest:
        dest = 'dpaste'
    if dest not in pastebins:
        raise util.Abort('unknown pastebin (see "hg help pastebins")!')

    if not opts['user']:
        opts['user'] = ui.username().replace('<', '').replace('>', '')

    if opts['rev'] and opts['stdin']:
        raise util.Abort('--rev and --stdin options are mutually exclusive')

    if opts['stdin']:
        content = sys.stdin.read()
        if opts['rev']:
            rev = opts.pop('rev')
            revs = cmdutil.revrange(repo, rev)

            if len(revs) == 1:
                opts['change'] = revs[0]
                opts['rev'] = rev

            commands.diff(ui, repo, *fnames, **opts)
            commands.diff(ui, repo, *fnames, **opts)
        content = ui.popbuffer()

    if not content.strip():
        raise util.Abort('nothing to paste!')

    if ui.verbose:
        ui.status('Pasting:\n%s\n' % content)

    if not dry:
        url = _do_paste(pastebins[dest], content, opts)
        ui.write('%s\n' % url)

cmdtable = {
    'paste': (paste, [
        ('r', 'rev',   [], 'paste a patch of the given revision(s)'),
        ('d', 'dest',  '', 'the pastebin site to use (defaults to dpaste)'),
        ('t', 'title', '', 'the title of the paste (optional)'),
        ('u', 'user',  '', 'the name of the paste\'s author (defaults to the '
                           'username configured for Mercurial)'),
        ('k', 'keep', False, 'specify that the pastebin should keep the paste '
                             'for as long as possible (optional)'),
        ('',  'dry-run', False, 'do not paste to the pastebin'),
        ('',  'url', '', 'perform request against this url'),
        ('',  'httpauth', '', 'http authorization (user:pass)'),
        ('',  'usenetrc', False, 'use ~/.netrc for http authorization'),
        ('',  'stdin', False, 'read content from standard input'),
        ('',  'syntax', '', 'choose syntax'),
    ] + commands.diffopts + commands.walkopts,
    'hg paste [OPTION] [-r REV] [FILE...]')

help.helptable += (
    (['pastebins', 'pastebins'], ('Pastebins supported by hg-paste'),
    hg-paste currently supports dpaste.com and dpaste.org.  More pastebins
    will be supported in the future.
    Available pastebins:
        website: http://dpaste.com/
        supported metadata options: --title, --keep, --user

        website: http://dpaste.org/
        supported metadata options: --title, --keep, --user