From mboxrd@z Thu Jan 1 00:00:00 1970 Return-Path: X-Spam-Checker-Version: SpamAssassin 3.2.5 (2008-06-10) on sa.int.altlinux.org X-Spam-Level: X-Spam-Status: No, score=-1.8 required=5.0 tests=AWL,BAYES_00, RCVD_IN_SORBS_WEB,SPF_PASS autolearn=no version=3.2.5 Date: Sat, 5 Nov 2011 21:18:43 +0200 From: Igor Vlasenko To: devel@lists.altlinux.org Message-ID: <20111105191843.GA15650@dad.imath.kiev.ua> MIME-Version: 1.0 Content-Type: text/plain; charset=utf-8 Content-Disposition: inline Content-Transfer-Encoding: 8bit User-Agent: Mutt/1.5.21 (2010-09-15) X-imath-kiev-ua-MailScanner-Information: Please contact the ISP for more information X-imath-kiev-ua-MailScanner-ID: CF3D64B02A8.AB8B2 X-imath-kiev-ua-MailScanner: Found to be clean X-imath-kiev-ua-MailScanner-From: vlasenko@imath.kiev.ua Subject: [devel] I: embedded language for src.rpm/spec file editing (part II). X-BeenThere: devel@lists.altlinux.org X-Mailman-Version: 2.1.12 Precedence: list Reply-To: ALT Linux Team development discussions List-Id: ALT Linux Team development discussions List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , X-List-Received-Date: Sat, 05 Nov 2011 19:18:53 -0000 Archived-At: List-Archive: List-Post: Уважаемые коллеги, продолжение вводной документации. == программирование на языке манипуляций spec-файлом == === Загрузка полезного кода опциями --hook === начнем знакомство с файла template.pl, содержащего шаблон для наиболее частых правок, которые приходится вносить в спек-файлы при импорте из Fedora. На основе такого шаблона при необходимости удобно создавать личный hook пакета с именем %{name}.pl, который в дальнейшем будет автоматически использоваться при импорте следующих версий этого пакета в системе fedoraimport. #!/usr/bin/perl -w Итак, файл: push @SPECHOOKS, sub { my ($spec, $parent) = @_; $spec->add_patch('',STRIP=>1); $spec->get_section('package','')->subst_body(qr'',''); $spec->get_section('package','')->subst_body_if(qr'','',qr'Requires:'); $spec->get_section('prep')->push_body(q!!."\n"); $spec->get_section('package','')->unshift_body('BuildRequires: '."\n"); }; Собственно, минимально необходимая обвязка - это push @SPECHOOKS, sub { my ($spec, $parent) = @_; }; Мы видим, что в наш код утилита передает 2 объекта perl: $spec, который соответствует текущему редактируемому spec-файлу или src.rpm пакету, и $parent, который соответствует предку редактируемого пакета - например, предыдущей версии этого пакета в Сизифе при импорте или старой версии пакета при обновлении. $spec определен всегда, $parent может и не быть определен. В наших простых примерах $parent не понадобится. Методы объекта $spec делятся на методы, применяемые ко всему spec-файлу, и методы, применяемые к отдельным секциям spec-файла. Примером методов на уровне spec-файла является метод add_patch. push @SPECHOOKS, sub { my ($spec, $parent) = @_; $spec->add_patch('foo-1.2-alt-fix-something.patch',STRIP=>3); }; Этот код скопирует файл foo-1.2-alt-fix-something.patch из ./patches в %_sourcedir данного пакета (возможно, временный каталог, созданный утилитой srpmnmu или ей родственной); Добавит в спек тег PatchXX: foo-1.2-alt-fix-something.patch, где XX -- некоторый незанятый номер, и добавит в секцию %prep строку %patchXX -p3 где 3 указано через параметр STRIP=>3. Другой пример -- метод add_source. Допустим, мы хотим провести NMU -- добавить в пакеты файлы .service для systemd. Насобираем коллекцию .service файлов, названных по имени пакета (вида %name.service), в папке ./patches. Создадим файл add_systemd_service.pl push @SPECHOOKS, sub { my ($spec, $parent) = @_; my $sourcenum=$spec->add_source('%name.service'); $spec->get_section('install')->push_body( 'install -Dm644 %{SOURCE'.$sourcenum.'} %buildroot%_systemd/%name.service'."n"); $spec->get_section('files')->push_body('%_systemd/%name.service'."n"); }; Передадим этот файл в утилиту girar-nmu-prepare --hook add_systemd_service.pl ... Метод add_source разворачивает '%name.service' в момент выполнения, поэтому наш код будет работать для каждого пакета, обрабатываемого с помощью girar-nmu utils, для которого найдется ./patches/%name.service. Метод add_source скопирует файл, добавит в спек тег SourceXX: %name.service Метод add_source возвращает число XX, которое позднее использовано в коде для добавления в секцию %install строки install -Dm644 %{SOURCEXX} %buildroot%_systemd/%name.service === Методы редактирования на уровне секции. === В предыдущем примере использовался метод редактирования на уровне секции push_body. В действительности, использовалась связка $spec->get_section('...'[,'...'])->push_body('some text'."\n"); Этот код можно еще переписать my $section = $spec->get_section('install'); $section->push_body('some text'."\n"); Т.е. сначала получаем объект секции %install, затем добавляем в конец секции строку 'some text'."\n" . Это отражает дизайн: сначала находим в spec-файлe нужную секцию, затем редактируем ее. === Получаем секции === Как получить секцию? примеры с get_section: # одна и та же главная секция (секция, # с которой начинается любой spec-файл) $spec->get_section('package',''); $spec->get_section('package'); # выделенный метод специально для главной секции $spec->get_main_section; # разные извращения, которые тоже работают # и возвращают главную секцию (Name: foo) $spec->get_section('package','-n foo'); $spec->get_section('package','-n %name'); # секция package для подпакета doc $spec->get_section('package','doc'); $spec->get_section('package','-n foo-doc'); $spec->get_section('package','-n %name-doc'); # секция files для подпакета doc $spec->get_section('files','doc'); Секции можно найти и по-другому. Переберем всевозможные У объекта $section есть методы get_type, get_canonical_package. Для секции files подпакета doc get_type равно 'files', get_canonical_package равно 'doc'. Пример: сосчитаем число секций %changelog. Наш rpm не допускает больше одной секции %changelog, но в сети можно найти всякое. push @SPECHOOKS, sub { my ($spec, $parent) = @_; my $count_changelog=0; foreach my $section ($spec->get_sections()) { $count_changelog++ if $section->get_type() eq 'changelog'; } print "What a horrible spec! $count_changelog changelogs." if $count_changelog>1; }; Заметим, что метод get_sections создает временный массив. и не годится для некоторых специальных случаев, когда мы в цикле удаляем секции, которых еще не посетили. Для таких особых случаев лучше использовать итератор: my $section = $spec->get_main_section; do { ... } while ($section=$section->next); Продолжение в части III: ==== Работа с телом секции ==== -- Dr. Igor Vlasenko -------------------- Topology Department Institute of Math Kiev, Ukraine -- This message has been scanned for viruses and dangerous content by MailScanner, and is believed to be clean.