Source

gorilla / lib / gorilla / guts / cli.py

from __future__ import with_statement

import operator, os, sys, textwrap
from gorilla.guts import util
from gorilla.guts.catalog import Card, all_cards
from gorilla.guts.shelf import Shelf
from gorilla.turnstile import turnstile


class ui(object):
    def __init__(self):
        super(ui, self).__init__()
        self.buffers = []
    
    def write(self, text):
        if self.buffers:
            self.buffers[-1] += text
        else:
            sys.stdout.write(text)
    
    def error(self, text):
        text = "ERROR ==> %s" % text
        if self.buffers:
            self.buffers[-1] += text
        else:
            sys.stderr.write(text)
    
    def prompt(self, prompt):
        text = "%s\n? " % prompt
        return raw_input(text)
    
    def push_buffer(self):
        self.buffers.append('')
    
    def pop_buffer(self):
        return self.pop()
    


def _handle_init(ui, **opts):
    ui.write("Sample init.\n")
    ui.write(str(opts))

def _handle_home(ui, **opts):
    import webbrowser
    
    if not opts['args']:
        webbrowser.open('http://bitbucket.org/sjl/gorilla/')
    else:
        for c in opts['args']:
            try:
                card = Card(c)
            except Card.DoesNotExist, exc:
                ui.error("Unknown package: %s\n" % exc.name)
                continue
            
            if card.homepage != None:
                webbrowser.open(card.homepage)
            else:
                ui.error('%s does not have a home page listed.' % card.name)

def _handle_list(ui, **opts):
    card_names = [card.name for card in all_cards()]
    ui.write('\n'.join(sorted(card_names)) + '\n')

def _handle_search(ui, **opts):
    args = opts.pop('args')
    if not args:
        return _handle_list(ui)
    
    find = [f.replace('-', '_').lower() for f in args]
    check = any if opts.pop('any') else all
    
    for card in all_cards():
        content = '%s %s' % (card.name, card.description)
        content = content.replace('-', '_').lower()
        if check(map(lambda f: f in content, find)):
            ui.write('%s\n' % card.name)

def _handle_info(ui, **opts):
    if opts['args']:
        for name in opts['args']:
            try:
                card = Card(name)
            except Card.DoesNotExist, exc:
                ui.error('Unknown package: %s\n' % exc.name)
                continue
            
            ui.write('%s\n' % card.name)
            ui.write('%s\n\n' % card.homepage)
            ui.write('%s\n' % card.description)
            
            shelf = Shelf(card)
            
            download_status = 'yes (vcs: %s)' % shelf.vcs if shelf.present else 'no'
            install_status = 'yes' if shelf.installed else 'no'
            
            ui.write('\ndownloaded: %s\n' % download_status)
            ui.write('installed:  %s\n\n' % install_status)
            
            shelf = Shelf(card)
            if shelf.present:
                ui.write('available versions:\n')
                
                version_lines = textwrap.wrap(', '.join(shelf.versions), 77)
                for line in version_lines:
                    ui.write('  %s\n' % line)
    else:
        ui.write('Gorilla knows about %d packages\n' % len(list(all_cards())))

def _handle_create(ui, **opts):
    if len(opts['args']) > 1:
        ui.error('Slow down!  One package at a time!\n')
        return
    elif not opts['args']:
        name = ui.prompt('Enter the name of the package/project:')
    else:
        name = opts['args'][0]
    
    name = name.lower()
    filename = name.replace('-', '_').replace('.', '') + '.py'
    
    catalog = os.path.join(util.GORILLA_PATH, 'catalog')
    template = os.path.join(catalog, 'template')
    dest = os.path.join(catalog, filename)
    
    if name in map(operator.attrgetter('name'), all_cards()):
        ui.error('Gorilla already seems to know about that package.\n')
        return
    
    ui.write('\nCreating %s ...\n' % dest)
    
    import shutil, subprocess
    editor = os.getenv('EDITOR') or 'vim'
    command = '%s %s' % (editor, dest)
    
    shutil.copyfile(template, dest)
    error = subprocess.call(command, shell=True)
    
    with open(dest, 'r') as df:
        with open(template, 'r') as tf:
            saved = df.readlines() != tf.readlines()
    
    if saved and not error:
        ui.write('Card saved.\nRun "gorilla install %s" to install.\n' % name)
    else:
        if error:
            ui.error('The card was not successfully saved.\n')
        else:
            ui.error('The template card was not edited.\n')
        ui.error('Edit %s and run "gorilla install %s"\n' % (dest, name))
        ui.error('Alternately, delete %s and forget about it.\n'% dest)

def _handle_submit(ui, **opts):
    pass

def _handle_update(ui, **opts):
    pass

def _handle_prefer(ui, **opts):
    pass

def _handle_install(ui, **opts):
    if opts['args']:
        for name in opts['args']:
            try:
                card = Card(name)
            except Card.DoesNotExist, exc:
                ui.error('Unknown package: %s\n' % exc.name)
                continue
            
            ui.write('Installing %s (version: %s) ...\n' % (card.name,
                opts['version']))
            
            shelf = Shelf(card)
            installed = shelf.install(opts['version'])
            
            if installed:
                ui.write('Successfully installed %s.\n' % card.name)
            else:
                ui.error('There was a problem installing %s!\n' % card.name)
    else:
        ui.error('You must specify a package to install!\n')

def _handle_remove(ui, **opts):
    if opts['args']:
        for name in opts['args']:
            try:
                card = Card(name)
            except Card.DoesNotExist, exc:
                ui.error('Unknown package: %s\n' % exc.name)
                continue
            
            shelf = Shelf(card)
            
            if not shelf.installed:
                ui.error('%s is not installed!\n' % card.name)
                continue
            
            removed = shelf.remove()
            
            if removed:
                ui.write('Successfully removed %s.\n' % card.name)
            else:
                ui.error('There was a problem removing %s!\n' % card.name)
    else:
        ui.error('You must specify a package to remove!\n')

def _handle_smash(ui, **opts):
    pass

def _handle_grab(ui, **opts):
    try:
        cards = [Card(name) for name in opts['args']]
    except Card.DoesNotExist, exc:
        ui.error("Unknown package: %s\n" % exc.name)
        return
    
    for card in cards:
        ui.write('Grabbing %s ...\n' % card.name)
        shelf = Shelf(card)
        
        if shelf.present:
            ui.write('Already present, retrieving updates ...\n')
        else:
            ui.write('Not present, downloading a full copy ...\n')
        
        shelf.grab()
    

_options_grab = {
    'prefer': {
        'short': 'p',
        'default': '',
        'values': ['hg', 'git', 'static'],
        'help': 'specify your preferred VCS',
    }
}
_options_init = {
    'prefer': {
        'short': 'p',
        'default': '',
        'values': ['hg', 'git', 'static'],
        'help': 'specify your preferred VCS',
    }
}
_options_install = {
    'version': {
        'short': 'v',
        'default': 'latest',
        'help': 'install package version VERSION',
    }
}
_options_search = {
    'any': {
        'short': 'a',
        'default': False,
        'help': 'find packages that match any given STRING',
    }
}

_interface = {
    'create': {
        'aliases': ['new'],
        'handler': _handle_create,
        'options': {},
        'help': 'create a card for a package',
        'usage': '%s create [PACKAGE]',
    },
    'grab': {
        'aliases': ['download'],
        'handler': _handle_grab,
        'options': _options_grab,
        'help': 'download (but don\'t install) a package',
        'usage': '%s grab PACKAGE [PACKAGE ...]',
    },
    'home': {
        'aliases': [],
        'handler': _handle_home,
        'options': {},
        'help': 'go to the home page',
        'usage': '%s home [PACKAGE]',
    },
    'info': {
        'aliases': [],
        'handler': _handle_info,
        'options': {},
        'help': 'show information about a package',
        'usage': '%s info [PACKAGE]',
    },
    'init': {
        'aliases': ['bootstrap'],
        'handler': _handle_init,
        'options': _options_init,
        'help': 'initialize this gorilla installation',
        'usage': '%s init',
    },
    'install': {
        'aliases': [],
        'handler': _handle_install,
        'options': _options_install,
        'help': 'install a package',
        'usage': '%s install PACKAGE [PACKAGE ...]',
    },
    'list': {
        'aliases': ['ls'],
        'handler': _handle_list,
        'options': {},
        'help': 'list available packages',
        'usage': '%s list',
    },
    'remove': {
        'aliases': ['uninstall'],
        'handler': _handle_remove,
        'options': {},
        'help': 'remove a package',
        'usage': '%s remove PACKAGE [PACKAGE ...]',
    },
    'search': {
        'aliases': ['find'],
        'handler': _handle_search,
        'options': _options_search,
        'help': 'search for packages',
        'usage': '%s search STRING [STRING ...]',
    },
}

def main(ui, args):
    turnstile.handle(_interface, args, extra=[ui])