svn:externals и django - дружба на век

Со временем роста количества проектов, понимаешь как дорого строит их поддержка. Когда проектов мало, то что-то править и дописывать не трудно и почти не раздражает. А вот когда количество проектов переваливает за некоторое критическое число, то становится мучительно сложно что-то менять и обновлять. А особенно, когда эти проекты зависят от некоторой единой базы кода, т.е. грубо говоря от одних библиотек.

Я всегда использую транк джанги, поскольку релизится она не часто, а для примера можете сравнить насколько отличается текущая её версия от последнего релиза. Ага, как-будто вообще разные фреймворки в некоторых местах:)

Ну транк, так транк. Все хорошо, проект пишется какое-то время со свежим транком. Потом к счастью проект релизится и выходит в продакшн. И вот через некоторое время нужно либо что-то дописать, либо что-то исправить. Ну а почему бы и джангу не обновить под шумок и ещё несколько очередных плюшек новых использовать. Не проблема, обновили, код подправили и живем дальше. Но!

Обычно я устанавливаю джангу в общедоступный PYTHONPATH, например /usr/lib/python/site-packages/ и все проекты используют именно этот, один инстанс. И тут ключевое слово все. Когда на одном хосте расположены несколько проектов, то сценарий описанный мною ранее, перестает радовать и практически не возможен.

В чем же дело? Да очень просто, обновишь один проект, а следовательно и джангу, а должен обновить и подогнать под новый срез и все остальные проекты, которые пользуются одним инстансом джанги. Засада, правда?

А как удобно, сделал ln -s в site-packages и джанга установлена. Но не практично!

Причем это касается любой библиотеки, которая имеет не очень стабильный интерфейс и подвержена периодическим изменения. Я лично имею два пакета вспомогательных библиотек, которые постоянно улучшаются и вычищаются параллельно обрастанию джанги всё новыми возможностями. Установлены они в системе по схеме аналогичной джанговской.

Первая же идея - это иметь разные версии джанги для каждого проекта. А где их лучше хранить так чтобы не было конфликта? Да прям в самом проект! Может быть для многих это очевидно и этим пользуются, но я так раньше не делал. Мне казалось, что это не удобно и ведет к рассинхронизации и хаосу. Но есть решение.

Этими же мыслями я поделился и на конференции, и после уже в кулуарной беседе Вячеслав Буханцов рассказал, как они в своей компании решают схожую проблему - они активно применяют svn:externals и "кладут" джангу рядом с проектом, чтобы он цеплял именно "свою" версию. Спасибо Вячеслав за наводку!

Суть заключается в том, что svn может сам подгружать в рабочую копию код из другого репозитория или из другой иерархии каталогов одного. Надо только прописать откуда и куда что класть. Причем очень важной особенностью является возможность указать ревизию "стороннего" кода, которая нужна.

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

После недолгих экспериментов я понял, что использование svn:externals достаточно удобно и решает большинство проблем синхронизации версий различного кода.

Расскажу как получилось у меня.

Что такое свойства svn и как их устанавливать я думаю вызнаете (если нет, то прочтите). Для удобства я создал файл externals в корне джанговского проекта, где описал нужные мне ссылки на библиотеки. Вот:

django -r7210 http://code.djangoproject.com/svn/django/trunk/django
lib1 -r1401 http://path/to/lib1/repo
lib2 -r1390 http://path/to/lib2/repo

Вначале идет имя директории, куда будет выполнен чекаут, далее номер ревизии и путь в репозитории. Потом я этот файл использую для установки свойства svn:externals корня рабочей копии вот так:

$ svn propset svn:externals -F externals .

Далее обычные:

$ svn up && svn commit -m "adding externals property to project"

И мы видим как svn делают чекаут нужных ревизии. В итоге получается что-то вроде такой схемы каталогов:

- project
  - app1
  - app2
  ...
  - django
  - lib1
  - lib2
  ...
  - __init__.py
  - manage.py
  - settings.py
  - urls.py

Поскольку директория, где лежит проект идет первой в sys.path, то именно локальные версии джанги и других библиотек будут использованы. Теперь можно это проект размещать где угодно и всегда он будет находится в правильном "своём" окружении.

Ура, теперь я могу окончательно почистить свои библиотеки и свежие проекты уже начинать на актуальной базе.

Для новых проектов, я предпочитаю эту операцию проводить в сомом конце, когда уже на носу выпуск в продакшн и когда я точно знаю, что именно эти версии библиотек используются.

В последствии если требуется изменения, то обновляются номера ревизий на актуальные на данный момент, и проводится операция ещё раз, чтобы svn подгрузил обновления джанги и библиотек.

Этот способ конечно же подходит не только для джанги, а для любого комплексного проекта, который использует сторонние развивающиеся компоненты. Просто для джанги на данный момент это очень актуально, поскольку она очень часто обновляется, и не всегда обратно совместимо.

А вы используете подобную технику в вашем процессе разработки?

Комментарии 12

  1. Dyadya Zed написал:

    Самое интересное, что я стоял рядом на Exception и слышал именно это обсуждение :) Наверное, стоило только ради этого ехать в Киев :))

    Может подскажете, как такое сделать в Mercurial?

    Спасибо

    Оставлен 20 Апрель 2008 в 03:05
  2. Александр Кошелев написал:

    Может подскажете, как такое сделать в Mercurial?

    Во-во. Мне тоже интересно как такая техника реализуется в других VCS

    Оставлен 20 Апрель 2008 в 03:18
  3. Glader написал:

    Отличная идея. Смущает только, что код библиотек будет многократно дублироваться на диске. (я понимаю, что это не приведет к бардаку в разработке библиотек :) )

    Оставлен 20 Апрель 2008 в 09:29
  4. Муркт написал:

    Дублируются и дублируются, проблема небольшая. Не по пятьсот же мегабайт они размером :-)

    Оставлен 20 Апрель 2008 в 09:31
  5. Иван Сагалаев написал:

    А у меня прямо противоположные наблюдения. Когда у проекта стоит своя версия Джанги, это ведет к тому, что инициатива ее обновлять пропадает совсем. Причем не только из-за лени. Когда твой проект крутится в продакшне Яндекса, лишний раз экспериментировать не хочется :-). В итоге, каждый сидит на чем-то своем древнем, у каждого, по сути, свой фреймворк, как ты правильно заметил. Это значит, что

    1. Трудно делиться знаниями:

    2. а как у вас это сделано?

    3. через ModelForm
    4. а черт, у нас этого нет...

    5. При реально нужных обновлениях (тот же autoescape, который устранял потенциальные XSS уязвимости), чем старее код, с которого обновляешь, тем сложнее и дольше это происходит.

    В итоге, в Яндексе, я, как главный Джангист, настаиваю на том, чтобы Джанга была одна на всех. Обновления проходят с разной степенью негладкости, но я уверен, что если этого не делать, проблемы в итоге были бы хуже.

    А источник этой разницы в подходах, я думаю, как раз в том, что фриланс и работа в коллективе -- разные вещи. Фрилансер один отвечает за все проекты, и у него нет вариантов, кроме как апдейтить все самому. В коллективе проекты распределяются между несколькими людьми, и там, когда человек контролирует больше двух проектов -- это верный повод передать хотя бы один кому-нибудь еще. Поэтому проблемы постоянно увеличивающейся нагрузки на обслуживание просто не возникает.

    Оставлен 20 Апрель 2008 в 10:31
  6. Dyadya Zed написал:

    Иван, я думаю для фрилансера, кроме увеличивающейся нагрузки от количества проектов есть еще один фактор. Обновил Джангу, часть проектов сломалась, надо чинить. Заказчик, как правило, не платит за обновление кода проекта до транка. Фрилансеру приходится делать это бесплатно, только чтобы проект продолжал работать. Получается неоплаченное время, которое фрилансер мог бы продать. Когда человек на зарплате, то его больше волнует стабильность, расширяемость кода. И ему за это платят. Даже если он просто правит ошибки, возникшие при обновлении Джанги.

    Оставлен 20 Апрель 2008 в 10:49
  7. Александр Кошелев написал:

    А источник этой разницы в подходах, я думаю, как раз в том, что фриланс и работа в коллективе -- разные вещи. Фрилансер один отвечает за все проекты, и у него нет вариантов, кроме как апдейтить все самому. В коллективе проекты распределяются между несколькими людьми,

    Ага. У компании больше ресурсов, чем у отдельного программиста, поэтому другие приоритеты и заботы. Мне просто не хочется трогать работающий сайт, когда хочу обновить другой. От добра, добра не ищут. А вот если понадобиться дальнейшее его развитие, то я и под свежий срез всё подгоню заодно.

    Оставлен 20 Апрель 2008 в 15:37
  8. Александр Кошелев написал:

    Смущает только, что код библиотек будет многократно дублироваться на диске

    Да. Это особенность. Но не критичная.

    Оставлен 20 Апрель 2008 в 18:33
  9. scarfacer написал:

    А по-моему в случае Ивана дело в том что есть несколько комманд которые должны общаться, обмениваться идеями и т.д. и для по-моему для них важнее этот момент нежели время потраченное не доработку до новой версии. Да и поправить один проект команде проще чем поправить допустим 5 проектов одному человеку.

    Оставлен 14 Май 2008 в 12:52
  10. Алексей написал:

    Спасибо за статью!

    Столкнулся с тем, что если создаю файл externals в Eclipse (в Windows), а потом импортирую его, то commit выполнить не удается. Говорит: svn cannot accept non-LF line endings

    То есть в этом файле нужно сначала сделать правильные - LF line endings. File - Convert Line Delimiters To - Unix. Причем финт в том, что сделать это можно только для файлов .txt. Так что переименовал файл в externals.txt

    И еще вопрос: Правильно я делаю, что ссылку пишу не, например, http://django-page-cms.googlecode.com/svn/trunk а http://django-page-cms.googlecode.com/svn/trunk/pages Ведь мне нужно только само приложение.

    Оставлен 21 Октябрь 2009 в 10:32
  11. Александр Кошелев написал:

    Правильно я делаю, что ссылку пишу не, например, http://django-page-cms.googlecode.com/svn/trunk а http://django-page-cms.googlecode.com/svn/trunk/pages Ведь мне нужно только само приложение.

    Конечно, из репозитория имеет смысл тянуть только то что вам действительно нужно.

    Оставлен 22 Октябрь 2009 в 01:03
  12. Алексей написал:

    А как можно добавить комментарий в этот файл? Я хотел бы там указывать, какие версии использовал раньше и до какой даты. Чтоб была информация для отката, если что.

    Оставлен 28 Октябрь 2009 в 13:50