Showing posts with label svn. Show all posts
Showing posts with label svn. Show all posts

Thursday, February 5, 2009

перенос svn репозитория.

Три раза менял vds. Было жалко свой svn репозиторий, и озадачился вопросом его переноса на другую машину.
Оказалось все просто как всегда.

Сначала скидываем репозиторий в dump file.

#svnadmin dump /home/svn/repo/ > /tmp/mysvn.dump


Т.е. svnadmin dump выплевывает dumpfile-formatted строки в stdout, который перенаправляется в наш файл /tmp/mysvn.dump


На другой машине

#scp login@host:/tmp/mysvn.dump /tmp
#svnadmin create /new/repo/path
#svnadmin load /new/repo/path < /tmp/mysvn.dump


Копируем при помощи scp файл себе локально, затем создаем новый репозиторий при помощи svnadmin create , далее командой svnadmin load, которая как раз читает из stdin dumpfile-formatted строки, переносим сдампленные данные.

Хотя в последнее время все чаще смотрю на mercurial, и даже начинаю использовать, пока нравится, но интересно посмотреть на это когда буду работать не один. В случае hg перенос был бы обычным бранчем, который он умеет делать через ssh (Как я думаю, могу и ошибаться).

Wednesday, January 28, 2009

svn+ssh на другом порту

поломали хостинг по моей безалаберности, сижу перенастраиваю.

В работе часто использую svn, т.к. по сути он на 90% single мне хватает svn+ssh протокола (++ в том, что не нужно ничего настраивать).

Перенес sshd порт с дефолтного на другой, svn+ssh://host:port/path не работает. Решение нашел достаточно быстро вот здесь

Ниже копипаст одного из решений.



Существуют два варианта решения. Первый - добавить в конфигурационный файл ~/.subversion/config строчки:
[tunnels]
tunnel_name = /usr/bin/ssh -p port

И в дальнейшем использовать вызов svn co snv+tunnel_name://hostname/path. Например,
[tunnels]
foobar = /usr/bin/ssh -p 8022

Тогда вызов будет выглядеть как:
svn co snv+foobar://hostname/path

Tuesday, October 21, 2008

hook pre-commit в svn. Реализация на питоне.

Задача : при коммите в svn, хочется чего то делать, например закрывать тикет в trac.

Для этого в svn есть механизм хуков. Далее по шагам как я это делал я.

Создание репозитория, начальный checkout

директория для тестов
cd@cd-laptop:~$ mkdir tests
cd@cd-laptop:~$ cd tests
директория для репозитория
cd@cd-laptop:~/tests$ mkdir repo
создание репозитория
cd@cd-laptop:~/tests$ svnadmin create repo
директория для чекаутов
cd@cd-laptop:~/tests$ mkdir checkout-dir
первый чекаут
cd@cd-laptop:~/tests$ svn checkout file:///home/cd/tests/repo/ checkout-dir/
Checked out revision 0.
создаем, добавляем, коммитим файл.
cd@cd-laptop:~/tests$ touch checkout-dir/x.txt
cd@cd-laptop:~/tests$ svn add checkout-dir/x.txt
checkout-dir/x.txt
cd@cd-laptop:~/tests$ svn ci checkout-dir/x.txt -m'first commit'
Adding checkout-dir/x.txt
Transmitting file data .
Committed revision 1.
cd@cd-laptop:~/tests$




Репозиторий создан, для теста сделал один коммит.

Теперь собственно создаем хук.


Заходим в папку репозитоия
cd@cd-laptop:~/tests$ cd repo/
смотрим чего есть. Интересует папка hooks
cd@cd-laptop:~/tests/repo$ ls
conf dav db format hooks locks README.txt
cd@cd-laptop:~/tests/repo$ cd hooks/
Заходим в нее.
cd@cd-laptop:~/tests/repo/hooks$ ls
post-commit.tmpl post-revprop-change.tmpl pre-commit.tmpl pre-revprop-change.tmpl start-commit.tmpl
post-lock.tmpl post-unlock.tmpl pre-lock.tmpl pre-unlock.tmpl
Создаем, делаем права на запуск, заполняем
cd@cd-laptop:~/tests/repo/hooks$ touch pre-commit
cd@cd-laptop:~/tests/repo/hooks$ chmod +x pre-commit
cd@cd-laptop:~/tests/repo/hooks$ cat > pre-commit
#!/usr/bin/python

import sys

sys.stderr.write('Test error')
sys.exit(1)

cd@cd-laptop:~/tests/repo/hooks$ cd ../..
cd@cd-laptop:~/tests$ echo '1' >> checkout-dir/x.txt
cd@cd-laptop:~/tests$ svn ci checkout-dir/x.txt -m'test'
Sending checkout-dir/x.txt
Transmitting file data .svn: Commit failed (details follow):
svn: 'pre-commit' hook failed with error output:
Test error
cd@cd-laptop:~/tests$



В папке репозитория в подпапке hoosk был создан файл pre-commit и ему поставлены права на запуск.
Теперь когда свн его увидит, будет запускать после получения данных непосредственно перед коммитом. При коде возврата не 0, commit не пройдет. Собственно сам скрипт можно писать на любом скриптовом языке, главное чтобы была шибанг строка.

Подробнее о коде pre-commit

#!/usr/bin/python

import sys

#пишем в STDERR
sys.stderr.write('Test error')
#выходим с кодом возврата 1
sys.exit(1)



Т.е. сам хук создан, он запускается, не дает нам сделать коммит, теперь хочется уметь работать с информацией, которая приходит перед коммитом. Нас интересуют такие вещи как
автор,
текст комментария,
содержимое файлов и т.д.


Здесь я маленько не разобрался, в основном попробовал методом тыка, поэтому напишу как я понял. Не факт что будет совсем правильно, но пользуясь тем как я это понял, у меня чего то получается делать.


Для получения информации о предстоящем коммите, полезна утилита

svnlook


Формат запуска следующий

svnlook SUBCOMMAND REPOS_PATH [ARGS & OPTIONS ...]

Где subcommand одна из следующего списка

author
cat
changed
date
diff
dirs-changed
help (?, h)
history
info
lock
log
propget (pget, pg)
proplist (plist, pl)
tree
uuid
youngest



REPOS_PATH путь до репозитория, аргументы и опции могут зависеть от subcommand нас интересуют только две

any subcommand which takes the '--revision' and '--transaction'


--revision понятно, выполняет subcommand по определенной ревизии
--transaction интереснее, выполняет subcommand по транзакции, с этим я не разобрался, но понял так.

Если взглянуть на pre-commit.tpl (файл созданные в репозитории по умолчанию) увидим там следующее


REPOS="$1"
TXN="$2"

# Make sure that the log message contains some text.
SVNLOOK=/usr/bin/svnlook
$SVNLOOK log -t "$TXN" "$REPOS" | grep "[a-zA-Z0-9]" > /dev/null || exit 1


Где видно что параметр --transaction он же -t используется с переменной TXN, которая является вторым аргументом передаваемым в pre-commit. Т.е. эта штука у нас на руках, и svnlook умеет с ней работать.

Итак при обработке pre-commit у нас нет ревизии (мы ее создаем ) зато есть транзакция. Теперь что мы можем из этого получить.

Пример pre-commit который выводит автора и не дает закоммититься.


#!/usr/bin/python

import sys
import os

#обертка над svnlook для запуска любой команды
def cmd_out(subcommand, transaction, repo) :
cmd = '/usr/local/bin/svnlook %s -t "%s" "%s"' % (subcommand, transaction, repo)
str = os.popen(cmd, 'r').read()
return str.strip('\n')

#вызвает нашу оберку, для подкомманды author
def look_author(transaction, repo) :
return cmd_out('author', transaction, repo )

#читаем репозиторий, транзакцию
repos = sys.argv[1]
txn = sys.argv[2]

#получаем автора
author = look_author(txn, repos)

#пишем автора в STDERR
sys.stderr.write('Author :%s:' % author )
#выходим с ошибкой, запрещая коммит
sys.exit(1)


Единственное нужно указать правильный путь до svnlook

Ну теперь собственно все. Т.е. при помощи svnlook можно получить очень много информации о предстоящем коммите :)

Например получения текста лога для данного коммита.


def look_log (transaction, repo) :
return cmd_out('log', transaction, repo)


И так далее. Ну а наконец, скрипт который просматривает лог, ищет в определенном формате номер тикета, и пишет комментарий в трак к тикету, и закрывает тикет по необходимости.


#!/usr/bin/python

import sys, os, string, re

# return true or false if this passed string is a valid comment

php_devs = ('xx', 'xxx', 'yy', 'yyy', 'zz', 'zzz') #only for this dev's rules allowed



def cmd_out(subcommand, transaction, repo) :
cmd = '/usr/local/bin/svnlook %s -t "%s" "%s"' % (subcommand, transaction, repo)
str = os.popen(cmd, 'r').read()
return str.strip('\n')

def look_info(trans, repo) :
return cmd_out('tree --full-paths', trans, repo)

def look_author(transaction, repo) :
return cmd_out('author', transaction, repo )

def look_log (transaction, repo) :
return cmd_out('log', transaction, repo)

def check_comments(comment ):#return ticket id if find in comment
p = re.compile('\s*ticket:(\d+)(:close)?\s+(.*)$', re.MULTILINE)
res = p.match(comment)
try:
ticket_id = res.group(1)
except:
ticket_id = None
return ticket_id

def need_close(comment) : #i know it's copy paste, but i had choice, write into blog, or rewrite it ...
p = re.compile('\s*ticket:(\d+)(:(close))?\s+(.*)$', re.MULTILINE)
res = p.match(comment)
try:
is_closed = res.group(3)
except:
is_closed = ''
return is_closed == 'close'


def update_ticket_in_trac(ticket, author, comment, data ) :
import xmlrpclib
s = xmlrpclib.ServerProxy('http://tracuser:tracpast@domain.com:port/path_to_Trac/login/xmlrpc')#create service
try:
ticketInfo = s.ticket.get(ticket)#try get ticket
status = ticketInfo[3]['status']
if status == 'closed' :
sys.stderr.write("Ticket already closed, need reopen it first !!!")
return 1
except: #can catch here protocol err, it mean no rights
sys.stderr.write("No ticket found in trac for id %s" % ticket )
return 1
comment = comment.replace(':close','')
s.ticket.update(ticket,comment.replace("ticket:%s" % ticket, '%s killed himself with message : \n' % author , data) , data)
return 0


def main(repos, txn):
comment = look_log(txn, repos)
author = look_author(txn,repos)
if not (author in php_devs) :
return 0
ticket = check_comments(comment)
if ticket == None :
sys.stderr.write("\nticket:num must be at the comment begin where num is ticket id, if not exists create it please!")
return 1
data = dict()
if ( need_close(comment) ) :
data['status'] = 'closed'
return update_ticket_in_truck(ticket, author,comment, data )

if __name__ == '__main__':
if len(sys.argv) < 3 :
sys.stderr.write("Usage: %s REPOS TXN\n" % (sys.argv[0]))
else:
sys.exit(main(sys.argv[1], sys.argv[2]))


Sunday, July 20, 2008

Распределённые системы управления версиями

Давным давно читал похвальные отзывы об mercurial, bazaar и иже с ними.
В силу природного любопытства нашел таки время прочитать про них подробнее - понравилось.
Очень порадовала возможность забирать себе изменения с какого то конкретного бранча, причем делается это легко и непринужденно.
Прочитав - забыл. Т.к. основной проект на svn и проблема в том чтобы обучить дизайнеров и flash программистов новой софтине (на svn то с трудом заставили их переходить).
Тут возникает новый проект, ни с чем не связанный, отказываемся от php (устал я от него) в пользу python + django (интересно, удобно) заодно решили и репозиторий сменить.
Из консоли вдвоем поделали тесты (я bazaar, другой сотрудник mercurial) в общем простейшие операции прошли на ура. Все просто. (Для базаар пришлось пару модулей питоновских поставить только)

В чем же жопа? В плагинах к эклипсу. Я давным давно пришел ко мнению что ide должно быть ide а не редактором, и eclipse (полюбился он мне тем, что есть поддержка многих языков) плагины к двум вышеперечисленным клиентам убогие. mercurial плагин отмел сразу, три кнопки и в тех не разобраться. С bazaar ковырялся чуть подольше в надежде на чудо, сам плагин нормальный, в плане локальный commit, diff etc... . Танцы с бубном начались на push, и заявленная поддержка (только sftp) у меня не работала.
Осталось впечатление крайней сырости и недоделанности.

В общем как ни грустно, буду сидеть на svn + через полгодика попробую опять.

P.S. В голове еще крутится идея чтобы испльзовать bzr-svn, но крайне боюсь глюков, что может быть черевато на основном проекте, хотя может через некоторое время попробую, хотя бы из интереса.
 
Каталог сайтов, Добавить сайт