четверг, 10 апреля 2008 г.

Ответственность за изменения...

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

Начнем с глобальных мотивов. Если взять большой открытый проект типа linux, то там ситуация такова, что конкретные изменения вносят тысячи людей, Линус не обязан им доверять и может вообще не подозревать об их существовании (нет необходимости импортировать ключи), потому, что эти изменения попадают к нему через доверенных лиц, которые, как бы, берут на себя ответственность за эти изменения. Собственно git и не поддерживает (во всяком случае в стандартной поставке) подписывания каждого изменения, там есть только подписывание меток.

В более ограниченных проектах ситуация с доверием возможна, если бы не несколько но. При единственной ветви разработки никаких проблем нету. (CVCS?) Проблемы начинаются при ветвлениях.

Предположим что существует некая ветвь разработки a. от нее создается ветвь b, и обе ветви некоторое время развиваются независимо... a1 -> a2 -> ... an, b1 -> b2 -> ... bn. Естественно, что каждый набор изменений подписан кем-то.

Теперь ветвь b сливается с ветвью a.

Первый путь (mercurial вроде так поступал), Это когда изменения сливаются в рабочей копии и формируется версия a(n+1), которая потом коммитится в ветви a. Но в этом случае получается что ни подписанные истории изменений, не авторство их не попадает в ветвь a. И этическая сторона в этом месте такова, что нельзя ссылаться на автора изменений (annotate, log), потому что его подписи нигде нету. То есть ситуация ровно как в ядре линукс, автор слияния берет на себя ответственность за все вносимые изменения.

Я, как человек сведующий в криптографии понимаю что любое изменение подписанных данных автоматически приводит к недействительности подписи. Но теоретически, если изменения ветви b производились в файлах не изменяемых в ветви a, то историю изменений можно перенести из b, при этом новая версия (дерево файлов) всеравно подписывается автором слияния, но изменения по конкретным файлам имеют изначальное авторство. Но любой конфликт нарушает эту идиллию коренным образом, поскольку любое постороннее изменение файла исключает возможность применения вливаемых изменений, и ситуация сводится к предыдущей.

файл1: a -> b1 -> ... bn (HEAD of a)
файл2: a -> a1 -> ... an (HEAD of a)

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

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

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

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

К тому же при большом количестве участников необходимо распространять и ключи...

Может я опять чего-то не учитываю? Что-то еще хотел написать да забыл. завтра вспомню.

PS: Вот, спустя неделю, кое что вспомнил. Подписывать надо не наборы изменений, а состояние версии. Но это требует от системы контроля целостности состояний, то есть версия должна фиксировать содержимое всех файлов проекта (как в monotone). Что касается git, то его изменения ИМХО кумулятивны, и вообще не понимаю каким боком туда прикручивают цифровые подписи, а ведь прикручивают же, или я опять ошибаюсь?

среда, 9 апреля 2008 г.

Идеальная система контроля версий...

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

А сам я все написать тоже не могу, но мне ничего не мешает думать об этом.

Собственно к чему это я. Во многом я согласен с Линусом Торвальдсом. Распределенные системы контроля версий удобны. Но немаловажно и то, что система контроля версий должна работать быстро и занимать мало места для хранения истории.

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

Но у monotone есть один серьезный недостаток, о котором я уже упоминал - он медленный. Постановка на контроль 24.5к файлов (ядро линукс - мой любимый тестовый набор) занимает В общей сложности 3 минуты. Хм... что-то изменилось, кажется раньше он был значительно медленнее.

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

И самое гавное - бранчи - это легковесное ветвление. Создание бранчей должно быть возможно даже для минимальных изменений. С последующим слиянием и удалением бранча. Вот какраз с последним у некоторых систем наблюдаются проблемы. Удаление бранчей поддерживают далеко не все. Monotone, mercurial вообще не умеют удалять бранчи (тяжеловесные бранчи?), bazaar вообще всю поддержку бранчей сводит к клонированию - иногда это удобно, иметь доступ к двум ветвям одновременно, но иногда и не нужно. git в этом плане более гибок, только не совсем понимаю зачем при клонировании он создает origin бранчи? Логика разработчиков такая наверное.

Гораздо проще клонировать базу как есть, обратный слив изменений в любом случае должен осуществляться в отдельные ветви (как в monotone)... Можно даже, например, при клонировании указывать название ветви, и клонировать только ее.

Базу данных логично иметь в рабочем каталоге (не как в monotone). Причем всяческие игноры можно так же хранить в базе и не заводить для этого отдельных файлов в проекте, ведь база то и так лежит в корне проекта... :)

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

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

PS: Я вот наивно подумал, что git с помощью rebase мог бы позволить внести в историю предыдущие версии проекта, как бы не так. С удалениями/добавлениями он разобраться не в силах - просит ручками разбирать. Хотя как просто - одно состояние, другое состояние - сделай diff. Ан нет.

PPS: тот же git по умолчанию считает что каждый файлик на коммит надо добавлять индивидуально (логика ориентирована на патчи, опять таки). Хотя мне что-то подсказывает что если я говорю commit - все изменения надо вносить, если мне что-то не надо вносить, я исключу руками. но это конечно определяется подходом.

PPS: Как в git посмотреть список игнорируемых файлов? 'git ls-files --ignored' требует exclude pattern... не понимаю смысла.

Хотя может быть я просто что-то не понимаю? :)

вторник, 1 апреля 2008 г.

arm-iwmmxt-linux-gnueabi toolchain.

Долго ли коротко боролся я с glibc, но вот появилась новая плата Colibri Toradex PXA270, соответственно новая цель arm-iwmmxt-linux-gnueabi, и дело с glibc заладилось...

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

Не буду сильно усложнять - как распределить каталоги каждый решит для себя.

Использованы следующие компоненты: binutils-2.18, gcc-4.2.2, glibc-2.7, ядро какое есть.
Для систем без MMU можно использовать тот же elf2flt-20060506, но его функционирование я не тестировал (Мы пока забили на LPC2468, она плохо подходит для наших целей - слишком медленная).

binutils configure: --prefix=$(PREFIX) --target=$(TARGET) --disable-nls
ядро: make header_install INSTALL_HDR_PATH=$(PREFIX)$(TARGET)/
gcc stage1 configure: --prefix=$(PREFIX) --target=$(TARGET) --enable-languages=c --with-arch=iwmmxt --with-tune=iwmmxt --disable-shared --disable-nls --without-mudflap
glibc configure: --prefix=$(PREFIX)$(TARGET)/ --host=$(TARGET) --target=$(TARGET) --with-headers=$(PREFIX)$(TARGET)/include --with-tls --with-__thread --enable-kernel=2.6.23 --disable-nls
gcc stage2 configure: --prefix=$(PREFIX) --target=$(TARGET) --enable-languages=c,c++ --with-arch=iwmmxt --with-tune=iwmmxt --disable-nls

elf2flt как и раньше, nls наверное можно наверное и разрешить.

Чтобы glibc нормально собрался - надо наложить на него пару патчей:

glibc-nptl-crosscompile.patch:

--- glibc-2.4/nptl/sysdeps/pthread/configure.in.ark 2006-03-12 00:41:40.000000000 +0100
+++ glibc-2.4/nptl/sysdeps/pthread/configure.in 2006-03-12 00:44:08.000000000 +0100
@@ -45,5 +45,6 @@
AC_MSG_ERROR([the compiler must support C cleanup handling])
fi
else
- AC_MSG_ERROR(forced unwind support is required)
+ AC_MSG_WARN([forced unwind support is required, can't be verified while crosscompiling])
+ AC_DEFINE(HAVE_FORCED_UNWIND)
fi
--- glibc-2.4/nptl/sysdeps/pthread/configure.ark 2006-03-12 00:42:47.000000000 +0100
+++ glibc-2.4/nptl/sysdeps/pthread/configure 2006-03-12 00:44:08.000000000 +0100
@@ -153,7 +153,10 @@
{ (exit 1); exit 1; }; }
fi
else
- { { echo "$as_me:$LINENO: error: forced unwind support is required" >&5
-echo "$as_me: error: forced unwind support is required" >&2;}
- { (exit 1); exit 1; }; }
+ { echo "$as_me:$LINENO: WARNING: forced unwind support is required, can't be verified while crosscompiling" >&5
+echo "$as_me: WARNING: forced unwind support is required, can't be verified while crosscompiling" >&2;}
+ cat >>confdefs.h <<\_ACEOF
+#define HAVE_FORCED_UNWIND 1
+_ACEOF
+
fi


glibc-libeh.patch:

Submitted By: Jim Gifford (patches at jg555 dot com)
Date: 2005-07-20
Initial Package Version: 2.3.5
Origin: Rene Rebe
Upstream Status: Unknown
Description: Removes dependency for libgcc_eh

--- glibc-2.3.5/Makeconfig.orig 2005-07-21 04:53:30.000000000 +0000
+++ glibc-2.3.5/Makeconfig 2005-07-21 04:53:49.000000000 +0000
@@ -503,12 +503,12 @@
libunwind = -lunwind
endif
ifneq ($(have-as-needed),yes)
- libgcc_eh := -lgcc_eh $(libunwind)
+ libgcc_eh := $(libunwind)
else
libgcc_eh := -Wl,--as-needed -lgcc_s$(libgcc_s_suffix) $(libunwind) -Wl,--no-as-needed
endif
gnulib := -lgcc $(libgcc_eh)
-static-gnulib := -lgcc -lgcc_eh $(libunwind)
+static-gnulib := -lgcc $(libunwind)
libc.so-gnulib := -lgcc
endif
ifeq ($(elf),yes)


Да, чуть не забыл.. для glibc еще необходим glibc-ports-2.7, который надо распаковать в каталог glibc-2.7.

Если что-то не получается - пишите, подскажу.