Source

vimpire / vimpire.py

#!/usr/bin/env python3

import os
import os.path
import re

from os.path import exists, expanduser, join, isdir
from subprocess import check_call
from urllib.request import urlretrieve, urlopen
from zipfile import ZipFile

HOME = expanduser('~')

VIMRC = join(HOME, '.vimrc')
VIMRUNTIME = join(HOME, '.vim')
AUTOLOAD = join(VIMRUNTIME, 'autoload')
BUNDLE_DIR = join(VIMRUNTIME, 'bundle')

PATHOGEN_DIR = join(AUTOLOAD, 'pathogen.vim')
PATHOGEN_URL = ('https://raw.github.com/tpope/vim-pathogen'
                '/HEAD/autoload/pathogen.vim')

PLUGIN_RE = re.compile(r'" plugin: (\S+) ((ht|git|svn|vim|zip)\S*) (\S+)')


def sh(cmd, *args, **kwargs):
    if isinstance(cmd, str):
        print('Executing: %s' % cmd)
    else:
        print('Executing: %s' % ' '.join(cmd))
    check_call(cmd, *args, **kwargs)


def check_env():
    if not os.path.exists(PATHOGEN_DIR):
        if not os.path.exists(AUTOLOAD):
            os.makedirs(AUTOLOAD)
        print('Installing pathogen.vim...')
        urlretrieve(PATHOGEN_URL, PATHOGEN_DIR)

    if not os.path.exists(BUNDLE_DIR):
        os.makedirs(BUNDLE_DIR)


resolved = lambda x: os.path.realpath(os.path.abspath(x))


def _badpath(path, base):
    return not resolved(os.path.join(base, path)).startswith(base)


def lstrippath(base, path):
    path = path[len(base) + 1:]
    items = path.split(os.path.sep)
    items.pop(0)
    return os.path.join(base, *items)


def unzip(zipfile, base, strip=False):
    with ZipFile(zipfile) as f:
        for filename in f.namelist():
            path = resolved(os.path.join(base, filename))
            if (not filename.endswith('/') and
                path.startswith(base + os.path.sep)):
                if strip:
                    path = lstrippath(base, path)
                if len(path) > len(base):
                    path_dir = os.path.dirname(path)
                    if not os.path.exists(path_dir):
                        os.makedirs(path_dir)
                    zf = f.open(filename)
                    with open(path, 'wb') as rf:
                        rf.write(zf.read())


class Plugin(object):
    def __init__(self, name, handler, path, kwargs):
        self.name = name
        self.handler = handler
        self.path = path
        self.kwargs = kwargs
        self.run = []

    def handle_hg(self):
        sh(['hg', 'clone', self.path, self.name])

    def handle_git(self):
        sh(['git', 'clone', self.path, self.name])

    def handle_vim(self, strip=False):
        with urlopen(self.path) as f:
            content = f.read().decode('ISO-8859-1')
        m = re.search(r'download_script\.php\?src_id=\d+', content)
        if m is None:
            raise Exception("Can't find vim script to download.")
        filename, headers = urlretrieve('http://www.vim.org/scripts/' + m.group(0))
        base = resolved(self.name)
        unzip(filename, base, strip=strip)

    def get_handler(self):
        return getattr(self, 'handle_%s' % self.handler)

    def install(self):
        if exists(self.name):
            print('plugin: %s (alreading installed)' % self.name)
        else:
            print('plugin: %s installing...' % self.name)
            handler = self.get_handler()
            handler(**self.kwargs)

            if self.run:
                cwd = os.getcwd()
                os.chdir(self.name)
                for cmd in self.run:
                    sh(cmd, shell=True)
                os.chdir(cwd)

            print('  ... installed.\n')


def parse_kwargs(s):
    """

    >>> parse_kwargs('vim')
    ('vim', {})
    >>> parse_kwargs('vim|strip|key=val')
    ('vim', {'key': 'val', 'strip': True})

    """
    if '|' not in s:
        return s, {}

    spl = s.split('|')
    name = spl.pop(0)
    kwargs = {}
    for item in spl:
        if '=' in item:
            key, val = item.split('=', 1)
        else:
            key, val = item, True
        kwargs[key] = val
    return name, kwargs


def get_plugins():
    plugins = []
    pathogen_not_found = True
    with open(VIMRC) as f:
        for line in f:
            if line.startswith('" plugin: '):
                m = PLUGIN_RE.match(line)
                if m:
                    name, handler, x, path = m.groups()
                    handler, kwargs = parse_kwargs(handler)
                    plugin = Plugin(name, handler, path, kwargs)
                    plugins.append(plugin)

            elif line.startswith('" run: ') and plugin is not None:
                cmd = line[len('" run: '):]
                plugin.run.append(cmd)

            elif line.startswith('call pathogen#infect'):
                pathogen_not_found = False
                plugin = None

            else:
                plugin = None

    if pathogen_not_found:
        raise Exception('It seems, that pathogen is not configured.\n'
                        'Make sure, that you have\n'
                        '\n'
                        '    call pathogen#infect()\n'
                        '\n'
                        'line at the top of your ~/.vimrc file.\n')

    return plugins


def main():
    plugins = get_plugins()
    check_env()
    os.chdir(BUNDLE_DIR)

    update_help_tags = False
    installed_plugins = []

    # Install/update plugins
    for plugin in plugins:
        installed_plugins.append(plugin.name)
        if plugin.install():
            update_help_tags = True

    # Uninstall removed plugins
    for name in os.listdir('.'):
        path = join(BUNDLE_DIR, name)
        if isdir(path) and name not in installed_plugins:
            print('plugin: %s uninstalling...' % name)
            sh(['rm', '-rf', path])
            print('  ... uninstalled.\n')
            update_help_tags = True

    # Update help tags
    if update_help_tags:
        sh(['vim', '-c', 'Helptags', '-c', 'q'])


if __name__ == '__main__':
    main()
Tip: Filter by directory path e.g. /media app.js to search for public/media/app.js.
Tip: Use camelCasing e.g. ProjME to search for ProjectModifiedEvent.java.
Tip: Filter by extension type e.g. /repo .js to search for all .js files in the /repo directory.
Tip: Separate your search with spaces e.g. /ssh pom.xml to search for src/ssh/pom.xml.
Tip: Use ↑ and ↓ arrow keys to navigate and return to view the file.
Tip: You can also navigate files with Ctrl+j (next) and Ctrl+k (previous) and view the file with Ctrl+o.
Tip: You can also navigate files with Alt+j (next) and Alt+k (previous) and view the file with Alt+o.