Analizuj nazwę RPM w jej komponentach

19

Czy istnieje narzędzie do analizy nazw, które jest częścią oficjalnego pakietu narzędzi RPM?

Mam listę nazw plików. Każda to nazwa pliku pakietu RPM. Nie mam rzeczywistych pakietów, tylko nazwy plików. Dla każdego muszę wyodrębnić nazwę i wersję pakietu ($ NAME i $ VERSION). Potrzebuję tego, dlatego, że piszę skrypt, który następnie upewnia się, że „yum install $ VERSION” instaluje $ VERSION. Jest to część systemu, który buduje pakiety i sprawdza, czy zostały poprawnie przesłane.

Lista nazw plików wygląda następująco:

$ cat /tmp/packages.txt
/home/builder/packages/testing-dev/CentOS/6/x86_64/emacs-mercurial-2.8-3.el6.x86_64.rpm
/home/builder/packages/testing-dev/CentOS/6/x86_64/emacs-mercurial-el-2.8-3.el6.x86_64.rpm
/home/builder/packages/testing-dev/CentOS/6/x86_64/mercurial-2.8-3.el6.x86_64.rpm
/home/builder/packages/testing-dev/CentOS/6/x86_64/mercurial-hgk-2.8-3.el6.x86_64.rpm
/home/builder/packages/testing-dev/CentOS/6/x86_64/python-redis-2.8.0-2.el6.noarch.rpm
/home/builder/packages/testing-dev/CentOS/6/x86_64/redis-2.6.16-1.el6.1.x86_64.rpm
/home/builder/packages/testing-dev/CentOS/6/x86_64/sei_dnsmaster-1.0-99.el6.x86_64.rpm

Znalazłem następujący kod, który jest funkcją BASH wykonującą zadanie:

function parse_rpm() { RPM=$1;B=${RPM##*/};B=${B%.rpm};A=${B##*.};B=${B%.*};R=${B##*-};B=${B%-*};V=${B##*-};B=${B%-*};N=$B;echo "$N $V $R $A"; }

for i in $(</tmp/packages.txt) ; do
    parse_rpm $i
done

To działa. Przeważnie. Istnieją pewne wyjątki:

$ parse_rpm CentOS/6/x86_64/sei_dnsmaster-1.0-99.el6.x86_64.rpm
sei_dnsmaster 1.0 99.el6 x86_64

Zauważ, że wersja nie otrzymała poprawnie (powinna być 1.0-99)

Zastanawiam się (1), czy w pakiecie rpmdev znajduje się narzędzie, które robi to poprawnie. (2) Jeśli nie, czy istnieje oficjalne wyrażenie, którego mógłbym użyć. (3) Jaki jest odpowiednik tego wyrażenia regularnego w Pythonie?

Z góry dziękuję!

TomOnTime
źródło
Czy możesz wyjaśnić, skąd bierzesz dane wejściowe i format, jaki przyjmuje.
user9517 obsługiwany GoFundMonica

Odpowiedzi:

25

Nie musisz tego robić; RPM ma argument formatu zapytania, który pozwala dokładnie określić dane, które chcesz otrzymać. Wyprowadzi nawet bez zakończeń linii, jeśli ich nie określisz.

Na przykład:

rpm --queryformat "%{NAME} %{VERSION} %{RELEASE} %{ARCH}" -q coreutils
rpm --queryformat "The version of %{NAME} is %{VERSION}\n" -q coreutils

rpm --queryformat "%{NAME} %{VERSION} %{RELEASE} %{ARCH}" -qp file.rpm

Pełną listę zmiennych, których można użyć, można uzyskać za pomocą:

rpm --querytags

Zauważ, że w przypadku RELEASEwyjścia typu like 84.el6jest normalne i oczekiwane, ponieważ tak właśnie są wersje pakietów RPM, gdy są pakowane przez lub dla dystrybucji.

Michael Hampton
źródło
2
Działa to tylko z zainstalowanymi pakietami. Chcę manipulować nazwami plików. $ rpm --queryformat "%{NAME} %{VERSION} %{RELEASE} %{ARCH}" -q CentOS/6/x86_64/sei_dnsmaster-1.0-84.el6.x86_64.rpm package CentOS/6/x86_64/sei_dnsmaster-1.0-84.el6.x86_64.rpm is not installed
TomOnTime,
@TomOnTime Poczekaj chwilę ... Więc nie obchodzi Cię, co tak naprawdę jest w paczce?
Michael Hampton
4
Chciałbym wiedzieć o tym wcześniej. Narzędzia RPM zajmują się tylko zawartością pakietu; nazwa pliku jest całkowicie nieistotna (i ta odpowiedź nie zadziała).
Michael Hampton
1
Baw się dobrze parsując, na przykład:libopenssl0_9_8-32bit-0.9.8j-0.26.1_0.50.1.x86_64.delta.rpm
MikeyB
5
@TomOnTime - „To działa tylko z zainstalowanymi pakietami” Nieprawda - w trzecim przykładzie pominięto opcję -p: rpm --queryformat "% {NAME}% {VERSION}% {RELEASE}% {ARCH}" -qp plik .rpm
Sam Elstob
14

Powiedziano mi, że oficjalnym sposobem robienia tego, czego szukam, jest Python:

from rpmUtils.miscutils import splitFilename

(n, v, r, e, a) = splitFilename(filename)

Napisałem krótki program w języku Python, który robi to, czego potrzebuję. Oferuję skrypt do projektu rpmdev w celu włączenia.

TomOnTime
źródło
1
Zasady nazewnictwa pakietów Debiana są tak proste i niejednoznaczne - nie wiem, jak świat rpm skończył w takim bałaganie. Czy mógłbyś wkleić tutaj swój skrypt do odpowiedzi?
Paul Hedderly,
3

Opracowałem wyrażenia regularne, które pasują do wszystkich danych, z którymi mogłem je przetestować. Musiałem użyć mieszanki chciwych i niechcianych zapałek. To powiedziawszy, oto moje wersje Perla i Pythona:

Perl:

#! /usr/bin/perl

foreach (@ARGV) {
    ($path, $name, $version, $release, $platform,
      @junk) = m#(.*/)*(.*)-(.*)-(.*?)\.(.*)(\.rpm)#;
    $verrel = $version . '-' . $release;

    print join("\t", $path, $name, $verrel, $version, $rev, $platform), "\n";
}

Pyton:

#! /usr/bin/python

import sys
import re

for x in sys.argv[1:]:
    m = re.search(r'(.*/)*(.*)-(.*)-(.*?)\.(.*)(\.rpm)', x)
    if m:
        (path, name, version, release, platform, _) = m.groups()
        path = path or ''
        verrel = version + '-' + release
        print "\t".join([path, name, verrel, version, release, platform])
    else:
        sys.stderr.write('ERROR: Invalid name: %s\n' % x)
        sys.exit(1)

Wolę mieć wyrażenie regularne, które pochodzi z projektu RPM. Ten, który wymyśliłem powyżej, będzie musiał zrobić na razie.

TomOnTime
źródło
Jest to w większości podobne do mojego rozwiązania (ale unikaj, .*chyba że NAPRAWDĘ chcesz coś dopasować). Miło widzieć, że znalazłeś sam!
mveroone
2
Nazwa pliku wydaje mi się złym sposobem na uzyskanie tych informacji. Może działać dla określonego zestawu RPM dostarczonych przez dostawcę (więc możesz być OK, o ile twój sprzedawca standaryzuje rzeczy innych firm i nigdy nie zmienia formatu nazewnictwa), ale widziałem wiele kreatywnych plików RPM. Acrobat Reader, który wziąłem z Adobe kilka sekund temu, to AdbeRdr9.5.5-1_i486linux_enu.rpm), który łamie twoją analizę wyrażeń regularnych powyżej.
voretaq7,
Prawdziwe. Ale Adbe nie działałby w przypadku żadnego rozwiązania, ponieważ łamie standardowy mniam plik nazw. (Technicznie pytanie powinno dotyczyć nazw plików yum, a nie nazw plików RPM).
TomOnTime,
1

Pliki Rpm mogą mieć w niektórych przypadkach nazwy funky, ale ogólnie można podzielić NVR na łączniki. Haczyk to część N (nazwa) NVR może zawierać łączniki i znaki podkreślenia, ale gwarantuje się, że V (wersja) i R (wydanie) nie będą miały żadnych łączników zewnętrznych. Możesz więc zacząć od przycięcia części VR, aby uzyskać nazwę.

$ RPM=/home/builder/packages/testing-dev/CentOS/6/x86_64/emacs-mercurial-2.8-3.el6.x86_64.rpm
$ echo ${RPM%-*-*}
/home/builder/packages/testing-dev/CentOS/6/x86_64/emacs-mercurial

Na tej podstawie możesz wyizolować część Wersja i wydanie.

echo ${RPM#${RPM%-*-*}-*}
2.8-3.el6.x86_64.rpm

Po prostu ponownie podziel łącznik, aby wyizolować potrzebną część. I oczywiście oczyść ciągi rozszerzeń plików arch i rpm, co jest dane. Po prostu daje wyobrażenie o tym, jak można do tego podejść w bash.

masta
źródło
1

Użyj opcji -q --queryformat z rpm, jak powiedziano wcześniej, jeśli chcesz to zrobić w niezainstalowanym pakiecie, możesz określić rpm za pomocą -popcji, jak poniżej:

rpm -q -p ./Downloads/polysh-0.4-1.noarch.rpm --queryformat "%{NAME} %{VERSION} %{RELEASE} %{ARCH}\n"
polysh 0.4 1 noarch

na przykład

$ ls ./Downloads/*.rpm
./Downloads/adobe-release-x86_64-1.0-1.noarch.rpm
./Downloads/nautilus-dropbox-1.6.0-1.fedora.x86_64.rpm
./Downloads/playonlinux-yum-4-1.noarch.rpm
./Downloads/skype-4.2.0.11-fedora.i586.rpm
./Downloads/dbview-1.0.4-2.1.x86_64.rpm
./Downloads/openmotif22-libs-2.2.4-192.1.3.x86_64.rpm
./Downloads/polysh-0.4-1.noarch.rpm

daje mi

adobe-release-x86_64 1.0 1 noarch
dbview 1.0.4 2.1 x86_64
nautilus-dropbox 1.6.0 1.fc10 x86_64
openmotif22-libs 2.2.4 192.1.3 x86_64
playonlinux-yum 4 1 noarch
polysh 0.4 1 noarch
skype 4.2.0.11 fc16 i586

więc dzielenie nazwy pliku jest nieprawidłowe!

for filename in """<paste list here>""".split():
    print splitFilename(filename)

('./Downloads/adobe-release-x86_64', '1.0', '1', '', 'noarch')
('./Downloads/nautilus-dropbox', '1.6.0', '1.fedora', '', 'x86_64')
('./Downloads/playonlinux-yum', '4', '1', '', 'noarch')
('./Downloads/skype', '4.2.0.11', 'fedora', '', 'i586')
('./Downloads/dbview', '1.0.4', '2.1', '', 'x86_64')
('./Downloads/openmotif22-libs', '2.2.4', '192.1.3', '', 'x86_64')
('./Downloads/polysh', '0.4', '1', '', 'noarch')

więc zwróć uwagę , to nie są prawidłowe szczegóły rpm, np. 1.fedorafaktycznie jest 1.fc10w rpm.

Jens Timmerman
źródło
Widzę zamieszanie. RPM nie tylko nie jest zainstalowany, ale nie mam go na tym komputerze. Przetwarzam listy nazw pakietów i plików. Dotyczy to czegoś, co zarządza zapasami repo; nie ma rzeczywistych pakietów.
TomOnTime,
0

Jeśli znasz Wyrażenia regularne i / lub Perl, to całkiem proste.

 ls | head | perl -p -e 'm#([^\-]+?)-(.*).rpm$#; print "$1 $2\n";$_=""' 

lub sam regex:

m#([^\-]+?)-(.*).rpm$#

Jeśli podzielisz to:

  • cokolwiek innego niż [^\-]+łącznik , przynajmniej jedna postać: (ucieka, ponieważ łącznik ma specjalne znaczenie w grupach znaków)
  • zatrzymaj dopasowanie po pierwszym łączniku (i nie ostatnim): [^\-]+?
  • dodaj to do grupy przechwytywania: ([^\-]+?)
  • Następnie łącznik: ([^\-]+?)-
  • następnie cokolwiek innego w innej grupie przechwytywania (oprócz końcowego .rpm): ([^\-]+?)-(.*).rpm$ (dolar oznacza „koniec linii”)
  • dołącz niż w praktycznym formacie dopasowania: m#([^\-]+?)-(.*).rpm$#

Gotowy ! Po prostu weź obie części do zmiennych $1i$2

Komentarz do pierwszego linijki:

Byłem w katalogu z wieloma plikami rpm, stąd ls.

perl -p jest równa ;

perl -e 'while(<STDIN>){ chomp($_);  [YOUR CODE HERE] ; print($_); }' 

Które wyjaśniają, że musiałem wstawić łańcuch zerowy, $_aby uniknąć drukowania przez Perla linii po wyodrębnieniu i wydrukowaniu na zamówienie. Zwróć uwagę, że mogłem użyć substytucji, aby uniknąć tego małego „hacka”.

mveroone
źródło
To nie działa w ogóle na setkach nazw RPM, np module-init-tools-3.9-21.el6_4.x86_64.rpm.
Nemo,
0

IMHO najprostszym sposobem powłoki jest:

ls | rev | cut -d/ -f1 | cut -d- -f3- | rev

To znaczy: odwróć każdą linię, używając cięcia przecinającego tylko pierwszą część ( emanelif ), a następnie za pomocą cięcia łącznikiem wszystkie oprócz pierwszych dwóch części (tj. Zostaw ESAELER włącznie z emanelif et foserser i NOISREV ) i odwróć enil z powrotem.

Z twoim przykładowym plikiem:

$ cat /tmp/packages.txt | rev | cut -d/ -f1 | cut -d- -f3- | rev
emacs-mercurial
emacs-mercurial-el
mercurial
mercurial-hgk
python-redis
redis
sei_dnsmaster
$

Aby zdobyć inne części, należy poćwiczyć na czytaniu cięcia (1) .

Alois Mahdal
źródło
0

Możesz wykorzystać dnf info. Oto przykładowy skrypt Bash, aby uzyskać wartości i ustawić jako zmienną:

function dnfinfo() {
   dnf info "$(echo "${1}" | sed 's/\.rpm$//g')"
}

function splitname() {
   eval $(
     dnfinfo "${1}" | \
     grep "^Arch\|^Name\|^Release\|^Version" | \
     sort | \
     awk -F": " {'print "\""$2"\""'} | \
     tr "\n" " " | \
     awk {'print "xarch="$1"~xname="$2"~xrel="$3"~xver="$4'} | \
     tr "~" "\n"
   )
}

splitname "tcpdump-4.9.2-5.el8.x86_64.rpm"
echo "${xname} ${xver} ${xrel} ${xarch}"

Daje wynik, nawet jeśli pakiet nie jest zainstalowany.

uboreas
źródło