24 марта 2010, 19:07

Процесс приёма правок в проекте с открытыми исходниками

Темы: git, syntax

opensource

Введение

Для работы в проекте с открытыми исходниками весьма удобна распределённая система контроля версий. Я использую git. Понятно, что есть процесс с использованием патча, высылаемого по почте, но этот процесс не является эксклюзивным для распределённой системы контроля версий. Поэтому я опишу процесс с так называемым pull request.

Постановка задачи

Пишет мне некто Tallak Tveide, сообщая, что он сделал копию моего проекта у себя на github и внёс несколько правок, которые ему были необходимы, и от которых другие ребята, пользующиеся этой библиотекой только выиграют. Ветка, в которой находятся нужные мне правки, называется eos_40D_bugs. Это довольно кстати, что нашёлся человек с Кэноном, потому что я испытываю всё на Никонах :)

Каковы же мои действия?

Решение

Заходим в наш локальный рабочий репозиторий и добавляем новый источник правок:

git remote add tallakt git://github.com/tallakt/gphoto4ruby

Теперь рассмотрим правки:

git fetch tallakt eos_40D_bugs:develop

Эта команда заберёт из репозитория tallakt с ветки eos_40D_bugs исправления и создаст локальную версию в локальной ветке develop. Чтобы увидеть исправления:

git diff develop

Что выдаст нам исправления относительно текущей ветки.

git checkout develop

Чтобы работать с правками и тестировать то, что получилось.

Если я пока не готов сливать исправления с основной веткой master, но хочу ещё поработать с этим из разных мест, то мне нужно создать ветку develop в моём центральном репозитории на github, который относительно локальной копии у меня обычно называется origin.

git push origin develop

Это создаст ветку develop на удалённом репозитории, с которой я потом смогу работать из другого локального репозитория, выполнив:

git pull origin develop

После того, как я доволен изменениями и хочу сделать официальный релиз:

git merge master
git branch -d develop
git push origin master
git push origin :develop

Первая команда, предполагая, что текущая ветка — develop, сливает её в master. Вторая команда удаляет локальную ветку develop. Третья команда отправляет изменения в ветку master на центральном репозитории. Четвёртая команда удаляет ветку develop на центральном репозитории.

Материалы для самостоятельного изучения

  1. Несколько шпаргалок от github
  2. Дельная документация по git

Послесловие

Как вы заметили, в этом году мои статьи сопровождаются прекраснейшими тематическими картинками авторства Ирины Троицкой — моей прекрасной супруги. Её перу также принадлежит дизайн сайта и логотипа.

Комментарии 2 >>

26 февраля 2010, 10:47

Вернулся

Темы: notice

back from holidays

Давненько я не обновлял этот блог :)

Всё дело в том, что где-то там был Новый Год, в который я торжественно посетил родителей. До и после Нового Года была сдача панорам Санкт-Петербурга и ещё одного пока не скажу какого города.

Когда съёмки 2009 года были сданы, выяснилось, что полным ходом идёт зима. А у нас не так много городов, которые можно красиво снимать зимой. Тогда мы отправились всем составом в тёплые края, в месячный отпуск.

Теперь, когда я снова в Москве, этот блог вернётся к своему обычному режиму. Спасибо всем, кто был со мной в прошлом году. Этот год обещает быть очень интересным.

Комментарии 1 >>

15 декабря 2009, 13:46

Одновременное использование двух версий руби на одной системе

Темы: ruby, ruby1.9, bash

Введение

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

Поэтому необходимо найти удобный для себя способ (а лучше несколько) чтобы начать использовать руби 1.9.

Постановка задачи

Сейчас практически панацеей для использования более одной версии руби является rvm. Очень удобно в использовании, полностью прозрачно, и позволяет иметь разные версии руби в разных окнах терминала.

Но недавно мне понадобилось скомпилировать wxRuby под свою систему (kubuntu 9.10 amd64), и rvm не справилась с этой задачей. По какой-то причине в момент компилляции были недоступны заголовки руби. Поэтому я решил поставить две версии руби более явно: одна системная (1.8.7) и одна в папке /opt (1.9.1). Причем все команды, связанные с руби 1.9 будут вызываться с суффиксом: ruby1.9, irb1.9, gem1.9, rake1.9.

Возможно, подобных инструкций уже полно, но мне будет удобнее, если я точно буду знать, где находится одна из них :) При всём этом, конечно, rvm продолжает работать. Мы никак ему не помешаем.

Решение

Сначала нужно поставить новый readline. Без него, когда мы будем использовать irb1.9, мы не сможем наслаждаться доступом к истории с помощью стрелок вверх-вниз и перемещаться по введенному тексту с помощью стрелок в стороны.

sudo apt-get install libreadline5-dev

Теперь хорошо бы вписать пути в наше окружение. В конце ~/.bashrc добавим:

export PATH=$PATH:/opt/bin
export LD_LIBRARY_PATH=$LD_LIBRARY_PATH:/opt/lib

Теперь следует скачать и разархивировать последнюю версию руби. Зайдя в папку скомпилировать и установить:

./configure --prefix=/opt --enable-shared --program-suffix=1.9
make
sudo make install

Теперь у нас есть две отдельных установки руби и сопутствующих инструментов. Единственное, что обе установки используют общие конфигурационные файлы: ~/.gemrc, ~/.irbrc и т.п., что вполне удобно. Также для обеих систем общей директорией джемов будет ~/.gem, куда будут устанавливаться библиотеки, запусти мы их установку без sudo (в случае с sudo, конечно же, директории установки различаются).

Так же я не нашёл быстрого способа добавить /opt/bin в переменную PATH для sudo. Поэтому в таких случаях пока использую полный путь. Например, первая команда, которую следует выполнить:

sudo /opt/bin/gem1.9 update --system

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

Материалы для самостоятельного изучения

  1. Всё об установке нескольких версий руби на одной системе
  2. Проект «Используй руби 1.9 или вали!»

Комментарии 8 >>

09 декабря 2009, 16:43

Забота о неблокировании потоков в руби

Темы: ruby, ruby1.9, syntax, extension

Введение

Сегодня будет блиц-молния, которой место, скорее в твиттере. Однако, мне необходимо развеять тучи, которые я сам же и нагнал. :)

Постановка задачи

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

Решение

Если мы имеем чуть больше контроля над участками кода на си, которые выполняются долго (обычно в цикле), то можно добавить спасительный код в тело цикла:

if (!rb_thread_alone()) rb_thread_schedule();

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

То есть, если мы сделаем точную копию функции из той статьи и добавим наш спасительный код внутрь for, то в выводе такой программы:

# coding: utf-8
require "block_thread.so"

t1 = Thread.new do
  10.times { |i| puts i; sleep 0.1 }
end

t2 = Thread.new do
  puts "Блокируем"
  BlockThread.cycle
  puts "Разблокируем"
end

t3 = Thread.new do
  puts "Стараемся не блокировать"
  BlockThread.cycle_with_schedule
  puts "Закончили стараться"
end
t1.join
t2.join
t3.join

Будет картина гораздо приятнее:

Блокируем
0
Стараемся не блокировать
Разблокируем
1
2
3
4
5
Закончили стараться
6
7
8
9

Заметьте, кстати, что два лишних вывода между «Блокируем» и «Разблокируем» благодаря передаче управления соседнимпотокам между cycle и puts.

Понятно, что соседние потоки тормозятся. Но теперь не на всё время, а только на исполнение одного витка цикла.

Материалы для самостоятельного изучения

Полный код статьи на github

Комментарии 0 >>

18 ноября 2009, 23:16

Сборка руби-билиотеки в заданной среде

Темы: ruby, extension, syntax, bash

Постановка задачи

Как разработчику gphoto4ruby мне приходится сталкиваться с особыми задачами. Связано это с тем, что этот gem является оболочкой поверх ещё одной библиотеки. И как у всякой более-менее развитой сторонней библиотеки, у libgphoto2 есть версия, распространяемая через системные репозитории и порты и есть, так сказать, последний писк моды (bleeding edge).

    Отсюда вытекает необходимость:
  1. Иметь разные версии библиотеки не конфликтующие между собой, установленные не одной системе,
  2. Компилировать свою руби-библиотеку под любую из версий.

Установка двух gphoto2 :)

Проделаю весь путь с самого начала. Для пущей целостности. Для начала установка из системного репозитория:

sudo apt-get install libgphoto2-2-dev gphoto2
gphoto2 --version

Теперь можно скачать нужную версию и установить её отдельно. Поскольку я в основном использую две версии, то версию из исходников нужно установить в /opt. Предположим, что исходники libgphoto2 и gphoto2 скачаны:

tar zxvf libgphoto2-x.x.x.tar.gz
cd libgphoto2-x.x.x.tar.gz
./configure --prefix=/opt
make
sudo make install
tar zxvf gphoto2-x.x.x.tar.gz
cd gphoto2-x.x.x.tar.gz
./configure --prefix=/opt --with-libgphoto2=/opt
make
sudo make install
/opt/bin/gphoto2 --version

Теперь мы имеем две библиотеки и две утилиты командной строки, поставленные раздельно и правильно залинкованные. Каждая утилита командной строки знает, где искать свою библиотеку. Надо, чтобы это же умел и gem

Компиляция джема

Если скачать исходник библиотеки, то можно проделать руками то, что делает команда gem install. Для создания Makefile используется утилита mkmf, которая входит в ruby-dev и с которой работает файл extconf.rb. В моём случае последовательность действий установщика такая:

cd ext
ruby extconf.rb
make

Теперь в папке ext мы имеем скомпилированную библиотеку (*.so или *.bundle в зависимости от системы). Установщик потом копирует её в папку lib, но мы пока остановимся. Мы можем посмотреть, какие другие библиотеки использует эта:

ldd gphoto4ruby.so

По выводу этой команды видно, что используется библиотека установленная из центрального репозитория. Теперь попробуем скомпилировать под версию «по последней моде». Поскольку я написал в extconf.rb

dir_config("gphoto2")

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

ruby extconf.rb --with-gphoto2-dir=/opt
make
ldd gphoto4ruby.so

Но что это? Вывод показывает нам, что библиотека привязалась опять к тому, что установлено из репозиториев, а не тому, что в /opt. То есть компилятор, конечно, находит нужные ему заголовки (*.h), но ничего в них не говорит о том, где искать соответствующие им библиотеки. Об этом ему должны сказать мы:

ruby extconf.rb --with-gphoto2-dir=/opt --with-dldflags="-Wl,-rpath,/opt/lib"
make
ldd gphoto4ruby.so

Вуаля!

Теперь, собственно, главное. Как это сделать при установке джема. Чтобы передать ключи для extconf нужно задать их после дополнительного «--»:

sudo gem i gphoto4ruby -- --with-gphoto2-dir=/opt --with-dldflags="-Wl,-rpath,/opt/lib"

Вот такой экскурс в жизнь разработчиков библиотек. Как это звучало в школьные времена: «Спэтсыално дла джэма».

Материалы для самостоятельного изучения

Руководство по расширению руби с помощью C (см. главу про extconf.rb)

Комментарии 0 >>