четверг, 9 октября 2008 г.

Быстрое обновление всех клонированных репозиториев

Не совсем в тему блога, но все же, надеюсь, что кому-то предоставленный ниже скрипт и принцип работы будут полезными.

Итак, работая с любым Django проектом я использую целую тучу разнообразнейших reusable apps. Установка и добавления любого reusable app'а в свой Django-проект проста и не тривиальна: клонирование репозитория, обновление sys.path, добавление appname в INSTALLED_APPS.

Намного интересней становится, когда приходит время пробежаться по всем склонированным локально репозиториям и проверить наличие обновление в них (сейчас и далее актуально только для тех, кто на передовой). Согласитесь, имея в наличии под 100 svn репозиториев c googlecode, да 20-30 git репозиториев с github'а, а также по паре тройке разнообразных bzr с hg репозиториев, их обновление посредством ручного набора поочередно:

$ svn up /path/to/django
$ cd /path/to/werkezeug && hg fetch
$ cd /path/to/django-debug-toolbar && git pull

будет очень и очень надоедливо. И именно по-этому, я быстро на коленке написал простой скрипт для обновления всех склонированных репозиториев в текущем или указанном каталоге. Код скрипта, ниже. Сразу предупреждаю, за именование переменных, а также использование os.system, не ругать, так как в час ночи не до жиру ;)

#!/usr/bin/env python

import os, sys

def run():
    if len(sys.argv) == 2:
        dirname = os.path.expanduser(sys.argv[1])
    else:
        dirname = os.getcwd()

    if not os.path.isdir(dirname):
        sys.stderr.write('Directory "%s" was not exists or you ' % dirname + \
                         'have not permissions to read from it.\n')
        sys.exit(1)

    dirdata = os.listdir(dirname)

    not_scms = []
    scms = (
        ('bzr', []),
        ('git', []),
        ('git-svn', []),
        ('hg', []),
        ('svn', []),
    )

    dirs_len = len(dirdata)
    scms_len = 0

    for name in dirdata:
        subdirname = os.path.join(dirname, name)

        if not os.path.isdir(subdirname):
            continue

        scms_len += 1
        subdirdata = os.listdir(subdirname)

        if '.bzr' in subdirdata:
            scms[0][1].append(subdirname)
        elif '.git' in subdirdata:
            f = open(os.path.join(subdirname, '.git/config'), 'r')
            if not 'svn-remote' in f.read():
                scms[1][1].append(subdirname)
            else:
                scms[2][1].append(subdirname)
            f.close()
        elif '.hg' in subdirdata:
            scms[3][1].append(subdirname)
        elif '.svn' in subdirdata:
            scms[4][1].append(subdirname)
        else:
            scms_len -= 1
            not_scms.append(subdirname)

    print 'Work directory:', dirname
    print 'Number of found subdirs:', dirs_len
    print 'Number of found SCM dirs:', scms_len

    if dirs_len != scms_len:
        print 'Not SCM dirs:', not_scms

    print

    if not scms_len:
        sys.exit(0)

    for protocol, dirs in scms:
        if protocol == 'bzr':
            cmd = "cd '%s' && bzr pull"
        elif protocol == 'git':
            cmd = "cd '%s' && git pull"
        elif protocol == 'git-svn':
            cmd = "cd '%s' && git svn fetch"
        elif protocol == 'hg':
            cmd = "cd '%s' && hg fetch"
        elif protocol == 'svn':
            cmd = "svn update '%s'"

        dirs.sort()

        for d in dirs:
            print '$', cmd % d
            os.system(cmd % d)
            print

if __name__ == '__main__':
    run()

Теперь вы можете сохранить этот код в любой файл (я, например, использую название scm-up-all.py) и поместить этот файл в PATH. Таким образом обновление всех репозиториев в /srv/shared стало плевым делом ;)

UPD: На днях появилось желание чуточку проапдейтить скрипт, потому я решил завести для него проект на GitHub. В ToDo: поддержка CVS, Darcs; вывод информации о последнем коммите (последней ревизии) в репозитории; простой GUI (PyQt4) для управления обновлением.

2 комментариев:

neithere комментирует...

Славно, только founded=основан, а found=найден ;)

playpauseandstop комментирует...

@neithere

ваша правда :( на это вообще внимания не обратил, писал на автомате...