Cum să peticești un rpm (patch rpm)

Monday, November 30, 2009

O să vă descriu cum am aplicat un petec pentru unul dintre pachetele pentru care sunt responsabil la fedora: calibre, în timp ce așteptam să-mi vină pizza http://www.fedoraproject.ro/am-lansat-fedora-12-avans . Petecul este răspunsul la un bug report: https://bugzilla.redhat.com/show_bug.cgi?id=537525 . Calibre verifică de fiecare dată când este pornit dacă pe situl oficial a apărut o nouă versiune și dacă a apărut, îl anunță pe utilizator printr-un pop-up că trebuie să actualizeze aplicația. Cum fedora are propriul management al pachetelor și deci și al actualizărilor, este recomandat ca pachetele noi să fie instalate folosind yum; deci mesajul trebuie eliminat.

Mai întâi trebuie să descărcăm sursele actuale ale rpm-ului (în momentul în care am scris patchul, în repo-uri cea mai recentă versiune era 0.6.21-1, acum ar trebui să fie una cu patchul deja aplicat):

  $ yumdownloader --source calibre

și să le despachetăm:

  $ rpm -ivh calibre-0.6.21-1.fc12.src.rpm

Comanda va crea un nou director rpmbuild, cu subdirectoarele SPECS și SOURCES. În SPECS avem fișierul care ține toate informațiile despre cum se va construi pachetul: calibre.spec, iar în SOURCES avem sursele pachetului și toate patchurile pe care le-am creat până acum:

  $ tree rpmbuild/
  rpmbuild/
  |-- SOURCES
  |   |-- calibre-0.6.21-nofonts.tar.gz
  |   |-- calibre-cssprofiles.patch
  |   |-- calibre-manpages.patch
  |   `-- generate-tarball.sh
  `-- SPECS
  `-- calibre.spec

Mai avem de făcut un pas, ca să putem umbla prin sursele programului. Trebuie să dezarhivăm arhiva calibre-0.6.21-nofonts.tar.gz. Următoarea comandă dezarhivează și aplică patchurile pe care le avem deja:

  $ cd rpmbuild/SPECS
  $ rpmbuild -bp calibre.spec

Au apărut mai multe directoare după comanda asta:

  $ ls rpmbuild/
  BUILD  BUILDROOT  RPMS  SOURCES  SPECS  SRPMS

Cel care ne interesează este BUILD, în care au apărut sursele peticite ale programului.

Atunci când e pornit, dacă există o versiune mai nouă, calibre va afișa următorul mesaj în fereastra pop-up:

calibre has been updated to version 0.6.24. See the new features. Visit the download page?

Ca să aflăm din ce fișier vine fereastra de pop-up putem să căutăm pur și simplu o parte din textul de mai sus în sursele calibre:

  $ cd rpmbuild/BUILD/calibre/
  $ find .|xargs grep "has been updated"

Dacă ignorăm fișierele de localizare, vom afla sursa pop-up-ului:

  ./calibre/src/calibre/gui2/main.py:                    _('%s has been updated to version %s. '

Mergând în fișierul respectiv vedem că acel cod face parte dintr-o funcție numită update_found:

 
  def update_found(self, version):
  os = 'windows’ if iswindows else 'osx’ if isosx else 'linux’
  url = 'http://%s.kovidgoyal.net/download_%s’%(__appname__, os)
  self.latest_version = '<br />' + _(&#8217;<span style="color:red; font-weight:bold">'
    'Latest version: <a href="%s"><span>s</span></a></span>')(url, version)
  self.vanity.setText(self.vanity_template%\
  (dict(version=self.latest_version,
  device=self.device_info)))
  self.vanity.update()
  if config.get('new_version_notification&#8217;) and \
  dynamic.get('update to version %s&#8217;%version, True):
  if question_dialog(self, _('Update available&#8217;),
  <em class="”’%s" has="has" been="been" updated="updated" to="to" version="version"><a href="“http://calibre.kovidgoyal.net/wiki/’">new features</a>. Visit the download pa&#8217;
  'ge?&#8217;&#8221;>%(</em>_appname__, version)):
  url = 'http://calibre.kovidgoyal.net/download_&#8217;+\
  ('windows&#8217; if iswindows else 'osx&#8217; if isosx else 'linux&#8217;)
  QDesktopServices.openUrl(QUrl(url))
  dynamic.set('update to version %s&#8217;%version, False)

Ne interesează ca modificarea pe care o vom aduce să fie cât mai lizibilă pentru cei care vor modifica pachetul nostru mai târziu și să fie cât mai ușor de revenit la versiunea nemodificată. Dacă ne uităm mai atent în main, găsim următorul cod:

  if not opts.no_update_check:
  self.update_checker = CheckForUpdates()
  QObject.connect(self.update_checker,
  SIGNAL('update_found(PyQt_PyObject)'), self.update_found)
  self.update_checker.start()

Codul verifică dacă programul a fost pornit cu opțiunea no_update_check. Ar complica prea mult lucrurile dacă am modifica programul în așa fel încât să pornească de fiecare dată cu opțiunea asta așa că mai bine comentăm codul aici, ca să nu mai verifice opțiunea și deci să nu mai caute niciodată update-uri. E soluția cea mai simplă.

Ca să facem un petec ca la carte, vom face așa:

Facem o copie a fișierului main.py:

  $ cd ~/rpmbuild/BUILD/calibre/src/calibre/gui2/
  $ cp main.py main.py.no_update
  După care modificăm *fișierul inițial* și comentăm codul respectiv așa:
  # if not opts.no_update_check:
  #     self.update_checker = CheckForUpdates()
  #     QObject.connect(self.update_checker,
  #             SIGNAL('update_found(PyQt_PyObject)'), self.update_found)
  #     self.update_checker.start()

Ca să generăm petecul vom folosi gendiff din directorul de deasupra directorului rădăcină:

    $ cd ~/rpmbuild/BUILD
    $ gendiff calibre .no_update
    diff -up calibre/src/calibre/gui2/main.py.no_update calibre/src/calibre/gui2/main.py
    --- calibre/src/calibre/gui2/main.py.no_update	2009-11-16 14:21:55.200387171 +0200
    +++ calibre/src/calibre/gui2/main.py	2009-11-16 14:22:10.400510757 +0200
     -221,11 +221,11  class Main(MainWindow, Ui_MainWindow, De
    self.latest_version = ' '
    self.vanity.setText(self.vanity_template%dict(version=' ', device=' '))
    self.device_info = ' '
    -        if not opts.no_update_check:
    -            self.update_checker = CheckForUpdates()
    -            QObject.connect(self.update_checker,
    -                    SIGNAL('update_found(PyQt_PyObject)'), self.update_found)
    -            self.update_checker.start()
    +        # if not opts.no_update_check:
    +        #     self.update_checker = CheckForUpdates()
    +        #     QObject.connect(self.update_checker,
    +        #             SIGNAL('update_found(PyQt_PyObject)'), self.update_found)
    +        #     self.update_checker.start()
    ####################### Status Bar #####################
    self.status_bar = StatusBar(self.jobs_dialog, self.system_tray_icon)
    self.setStatusBar(self.status_bar)

Totul arată bine, deci putem să-l punem în surse:

  $ gendiff calibre .no_update > ~/rpmbuild/SOURCES/calibre-no-update.patch
  

Acum trebuie să modificăm spec-ul, adăugând un nou petec, incrementând release-ul, menționând motivul pentru petec și scriind modificarea în Changelog:

   -1,6 +1,6 
  Name:           calibre
  Version:        0.6.21
  -Release:        1%{?dist}
  +Release:        2%{?dist}
  Summary:        E-book converter and library management
  Group:          Applications/Multimedia
  License:        GPLv3
   -18,6 +18,7 
  Source1:        generate-tarball.sh
  Patch0:         %{name}-cssprofiles.patch
  Patch1:         %{name}-manpages.patch
  +Patch2:         %{name}-no-update.patch
  BuildRoot:      /{name/del>{releaseroot({__id_u} -n)
  BuildRequires:  python >= 2.6
   -72,6 +73,9 
  # don’t append calibre1 to the name of the manpages. No need to compress either
  %patch1 -p1 -b .manpages

+# don’t check for new upstream version (that’s what packagers do) +%patch2 -p1 -b .no-update + # dos2unix newline conversion %{__sed} -i 's/\r//’ src/calibre/web/feeds/recipes/* -239,6 +243,9 %{_mandir}/man1/* %changelog +* Sat Nov 29 2009 Ionuț C. Arțăriși – 0.6.21-2 +- patch to stop checking for new upstream version + * Sat Nov 6 2009 Ionuț C. Arțăriși – 0.6.21-1 – new upstream version: http://calibre.kovidgoyal.net/wiki/Changelog#Version0.6.2106Nov2009 – added python-BeautifulSoup requirement

Gata. Asta a fost tot :). Acum putem reconstrui pachetul cu noile patchuri:

  $ cd ~/rpmbuild/SPECS/
  $ rpmbuild -ba calibre.spec

Și putem reinstala noul pachet:

  $ su -c "yum localinstall -y --nogpgcheck ~/rpmbuild/RPMS/x86_64/calibre-0.6.21-2.fc12.x86_64.rpm"
  
View Comments post separator

Fedora Business Cards

Friday, April 24, 2009

A few days ago, me and a few friends from Fedora Romania decided we’d like some fedora business cards for the upcoming eLiberatica conference. Ian Weller had already developed an official template and even created a cool python generator script and packaged it.

The problem, however, was that it only supported US-style business cards which are a bit smaller than the Romanian/Central European ones. Live and learn‌ It seems that there are a lot of different sizes actually.

So I got my hacking hat and dived in. The code was quite nice to look at and easy to understand. The XML in the svg templates is quite easy to hack, too. Especially when using tools like python’s minidom . It makes working with python and XML taste like javascript dom manipulation which is quite nice.

Everything went smooth, I renamed a few tags, made some modifiable (for height and width), but then I had to make the blue strip on the right of the front of the business card extendable1 . There is no way in XML to align an element to the right so I spent about an hour coming up with a sweet solution. Instead of having a big white background on which I would apply the blue band, I made a big blue background and made the white background just a little narrower. Because the white background was on top of the blue one, it could get aligned to the left (x=0, y=0 in XML) and cover just the part that needed to be white, and left a blue band at the right. Problem solved. Hoo-grah!

Now I’m waiting for an answer to the patch that I sent to bugzilla. Hopefully it’ll be accepted and will be available in Fedora, soon, so that others may enjoy and cherish the coolness that it be!

View Comments post separator
Powered by pyblee