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

Linux - After install work

Friday, December 19, 2008

It’s distro-hopping season again and I chose debian this time. I might explain my reasons for that somewhere else. Here’s a list of stuff I need to do on every install in order to get comfy with my new distro. (There’s a sort of meme floating around).
I use gnome!

  • Get 6 virtual desktops.
  • Set some basic can’t-live-without-keybindings Ctrl+_number_ for switching between desktops and Alt+T for launching a gnome-terminal.
  • Clean up my desktop. I really hate every kind of clutter on my desktop, so I delete everything. Almost everything can just be deleted, except for the Home, Trash and Computer icons. Fire up gconf-editor and go to apps>nautilus>desktop to uncheck everything. While we’re at it, let’s also enabling deleting in nautilus (it normally only lets you send stuff to Trash), by checking enable_delete in nautilus>preferences. Nautilus>Edit>Preferences>Behaviour – always open in browser windows – so it doesn’t spam me with 1000 windows to the world.
  • Next is <package manager> install bash-completion and adding this to my .bashrc: . /etc/bash_completion.
  • Time to get my .vimrc from wherever i happen to be keeping it at the time. you can check it out now here.
  • Nowadays, as I’ve got really lazy, I also set up automatic login (you can do that from System>Administration>Login Window. That basically bypasses gdm.
  • Get myself into some better groups like: wheel/admin/sudo, storage/disk(so nautilus can mount disks), by editing /etc/group.
  • You might also want to take a look at http://art.gnome.org if you’re the type. I know it’s a bit outdated, but the interface is a whole lot better than *-look.org
  • Here’s a list of apps I use regularly: Firefox, gnome-terminal, vim, ipython, git, xchat, evolution, pidgin, deluge, banshee/amarok, gnome-mplayer.
View Comments post separator
Powered by pyblee