Сегодня неожиданно понял, что скрипты — это сила (спустя несколько месяцев использования fabric). На самом деле 30 минут потраченные на написание адекватного сценария избавляют от многих совокупных часов повторения ненужных действий. Для упрощения жизни адептов python'а существует такой прекрасный модуль как fabric. И я хочу поделиться парой кусков своего fab-файла как пример упрощения жизни девелопера.
Это будут функции: «умный» комментатор локальных файлов и git-коммитер.
Прежде всего поставьте fabric и, впредь, ставьте её везде (если, вдруг, Вы ещё так не делаете)!
pip install fabric
Коммитер
Ничего сверхъестественного — просто удобный рецепт:
# -*- coding: utf-8 -*-
from fabric.api import local, prompt, settings
env.test_branch = 'test'
env.dev_branch = 'dev'
def commit():
"""
Коммит изменений.
"""
with settings(warn_only=True):
local('git status')
prompt('Press <Enter> to continue or <Ctrl+C> to cancel.') # тут можно прервать коммит,
# если в него попали ненужные файлы или наоборот
local('git add .')
local('git commit') # тут вылазит консольный редактор и можно ввести комментарий
def merge_dev_to_test(with_return=True):
"""
Слияние изменений из разработки в тестовую ветку.
"""
local('git checkout %s' % env.test_branch) # переход в тестовую ветку
local('git merge --no-ff %s' % env.dev_branch) # слияние с веткой разработки
if with_return:
local('git checkout %s' % env.dev_branch) # опциональное возвращение назад
def to_test()
"""
Коммит изменений в тестовую ветку.
"""
commit()
merge_dev_to_test()
Функция merge_dev_to_test
очень прикладная и её можно легко универсализировать.
Собственно этот скриптик заменяет ввод 6 команд, на ввод одной fab to_test
и ввод комментария в редакторе. При этом он даёт предпросмотр — какие изменения произойдут в бранче и сливает наработки из разработческой ветки в тестовую. Если слияние не нужно — просто выполняем fab commit
.
Комментер
Я использую его как переключатель вариантов настроек Django.
Отвлекаясь, сразу хочу сказать, что это не единственно верный способ использования разных настроек django для разных ситуаций. Это просто один из них. Другие варианты можно посмотреть здесь.
# -*- coding: utf-8 -*-
from os import path
from fabric.api import env, local
env.settings_files = (
path.join('projcet_root', 'settings.py'),
path.join('projcet_root', 'module', 'settings.py'),
)
env.settings_versions = {
'develop': '#-D',
'test': '#-T',
'production': '#-P',
}
def _commenter(type, filename, regex, use_sudo=False, char='#', backup='.bak'):
"""
Обработка комментариев в локальных файлах.
"""
if use_sudo:
sudoer = 'sudo '
else:
sudoer = ''
if regex.startswith('^'):
regex = regex[1:]
if regex.endswith('$'):
regex = regex[:-1]
if type == 'comment':
replacement = '%s ' % char
char = '[^%s ]' % char
regex = '(%s.+%s.*)' % (char, regex)
else:
replacement = ''
regex = r'%s ?(.+%s.*)' % (char, regex)
local(r"{sudo}sed -i{backup} -r -e 's/^([[:space:]]*){regex}$/"
r"1{replacement}2/g' {filename}".format(**{
'sudo': sudoer,
'backup': backup,
'replacement': replacement,
'regex': regex,
'filename': filename,
}))
def lcomment(*args, **kwargs):
"""
Комментирование.
"""
_commenter('comment', *args, **kwargs)
def luncomment(*args, **kwargs):
"""
Разкомментирование.
"""
_commenter('uncomment', *args, **kwargs)
def update_settings(mode):
"""
Изменение настроек.
"""
for filename in env.settings_files:
for version in env.settings_versions:
if mode == version:
luncomment(filename, versions[version])
elif:
lcomment(filename, versions[version])
Код также доступен в гисте.
В самом fabric
есть модуль contrib.files
с функцией comment
которую, по большому счёту, и повторяет «комментер» с той разницей, что работает локально, и комментарии ставит не в начало строки, а перед текстом вставляя между символом комментария и текстом пробел (как это делает sublime text) и ищет маркер только в конце строки.
Что он умеет. По команде fab update_settings:mode=<режим>
он у меет обходить файлы из списка env.settings_files
по дороге раскомментируя строки с маркером соответствующим режиму и комментируя с маркером не соответствующим.
Т.е. вызов fab update_settings:mode=test
пробежится по файлам /project_root/settings.py
и /project_root/module/settings.py
комментируя строки, заканчивающиеся на '#-D' и '#-P' и раскомментируя заканчивающиеся на '#-T'.
Что позволяет писать конфигурации типа:
DATABASES = {
'default': {
'ENGINE': 'django.db.backends.mysql',
'NAME': 'dvl', # #-D
# 'NAME': 'prd', # #-P
# 'NAME': 'tst', # #-T
'USER': 'ruutt',
'PASSWORD': 'gigopasswort',
'CHARSET': 'UTF8',
},
}
…разделяя их на стадии коммита:
def deploy(branch):
env.test_branch =branch # заменили тестовый бранч на нужный
commit(False) # коммитим и мержим в нужный бранч, оставаясь в нём
update_settings(branch) # в нужном бранче меняем настройки на нужные
# тут можно ещё покольдовать, закоммитить, запушить и т.д.
local('git checkout %s' % env.dev_branch) # возвращаемся в бранч разработки
prompt("OK. Press any <Enter> to exit.") # если вдруг из IDE раскрывается окно с консолью -
# эта строчка не даст ему закрыться и унести с собой результаты успешного исполнения.
А воспользоваться всей это мешаниной можно так fab deploy:branch=test
. Считать сколько команд в консоли и времени на них потраченного будет сэкономлено я оставляю Вам.
Вот такой вот наработкой решил поделиться. А то как-то fabric уж очень вскользь упоминается на страницах нашего любимого журнала…
Автор: qnub