Analisa um nome de RPM em seus componentes

17

Existe uma ferramenta de análise de nomes que faz parte do pacote de ferramentas oficiais do RPM?

Eu tenho uma lista de nomes de arquivos. Cada um é o nome do arquivo de um pacote RPM. Eu não tenho os pacotes reais, apenas os nomes dos arquivos. Para cada um eu preciso extrair o nome e a versão do pacote ($ NAME e $ VERSION). A razão pela qual eu preciso disso é que estou escrevendo um script que, então, garante que "yum install $ VERSION" instale $ VERSION. Isso faz parte de um sistema que cria pacotes e verifica se eles são carregados corretamente.

A lista de nomes de arquivos se parece com:

$ 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

Eu encontrei o o seguinte código que é uma função BASH que executa a tarefa:

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

Funciona. Na maioria das vezes. Existem algumas exceções:

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

Observe que ele não obteve a versão correta (deve ser de 1,0 a 99)

Eu estou querendo saber (1) se existe uma ferramenta no pacote rpmdev que faz isso corretamente. (2) Se não, existe um regex oficial que eu poderia usar. (3) Qual é o equivalente python dessa regex?

Obrigado antecipadamente!

    
por TomOnTime 25.11.2013 / 21:02

7 respostas

10

Já me disseram que a maneira oficial de fazer o que estou procurando é em Python:

from rpmUtils.miscutils import splitFilename

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

Eu escrevi um pequeno programa em Python que faz o que eu preciso. Eu vou oferecer o script para o projeto rpmdev para inclusão.

    
por 04.12.2013 / 04:55
22

Você não precisa fazer nada disso; O RPM possui um argumento de formato de consulta que permite especificar exatamente os dados que você deseja receber. Ele irá até produzir sem terminações de linha se você não especificá-las.

Por exemplo:

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

A lista completa de variáveis que você pode usar pode ser obtida com:

rpm --querytags

Observe que, no caso de RELEASE , a saída como 84.el6 é normal e esperada, pois é, na verdade, como os pacotes RPM são versionados quando empacotados por ou para uma distribuição.

    
por 25.11.2013 / 21:05
3

Eu trabalhei com expressões regulares que se encaixam em todos os dados com os quais eu pude testá-las. Eu tive que usar uma mistura de jogos gananciosos e não gananciosos. Dito isto, aqui estão as minhas versões em perl e python:

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";
}

Python:

#! /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)

Eu prefiro ter um regex que venha do projeto RPM. O que eu inventei acima terá que fazer por enquanto.

    
por 26.11.2013 / 16:07
1

Arquivos RPM podem ter alguns nomes de arquivos em casos extremos, mas geralmente você pode dividir o NVR nos hífens. A captura é a parte N (nome) do NVR pode conter hífens e sublinhados, mas o V (versão) e R (lançamento) são garantidos para não ter nenhum hífen externo. Então você pode começar aparando a parte VR para derivar um nome.

$ 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

Com base nisso, você pode isolar a parte da versão e da versão.

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

Basta dividir o hífen novamente para isolar a parte que você precisa. E, obviamente, limpe as strings de extensão de arquivo arch e rpm, o que é um fato. Apenas dando uma ideia de como isso poderia ser abordado no bash.

    
por 14.11.2014 / 06:08
1

Use as opções -q --queryformat do rpm como dito anteriormente, se você quiser fazer isso em um pacote não instalado, você pode especificar o rpm com a opção -p , assim:

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

por exemplo,

$ 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

me dá

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

, então apenas dividir o nome do arquivo está errado!

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')

então preste atenção , isso não é os detalhes corretos do rpm, por exemplo. 1.fedora é, na verdade, 1.fc10 na rpm.

    
por 03.12.2013 / 12:13
0

Se você estiver familiarizado com Expressões regulares e / ou Perl, isso é muito fácil.

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

ou apenas a regex:

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

Se você dividir isso é:

  • nada além de um hífen, pelo menos um caractere: [^\-]+ (escapou porque o hífen tem um significado especial nos grupos de caracteres)
  • interrompa a correspondência após o primeiro hífen (e não o último): [^\-]+?
  • adicione isso a um grupo de captura: ([^\-]+?)
  • Em seguida, um hífen: ([^\-]+?)-
  • em seguida, qualquer outra coisa em outro grupo de captura (mas o trailing .rpm ): ([^\-]+?)-(.*).rpm$ (o dólar significa "fim de linha")
  • coloque em um formato prático correspondente: m#([^\-]+?)-(.*).rpm$#

Feito! Basta pegar ambas as partes nas variáveis $1 e $2

Comente sobre o primeiro one-liner:

Eu estava em um diretório com muitos arquivos rpm, daí o ls .

perl -p é equivalente a;

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

O que explica que eu tive que colocar uma string nula em $_ para evitar que perl imprimisse de volta a linha depois que eu a extraíra e a imprimia sob encomenda. Note que eu poderia ter usado substituições para fazer este pequeno 'hack'.

    
por 26.11.2013 / 09:27
0

IMHO a maneira mais simples de shell é:

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

Isto é: inverta cada linha, usando o corte de barra apenas a primeira parte ( emanelif ), então usando hífen cortado, exceto as duas primeiras partes (ou seja, deixar incluindo emanelif eth fo tser e NOISREV ) e inverta o enil de volta.

Com o seu arquivo de exemplo:

$ 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
$

Para obter outras partes é o exercício de leitura cut (1) .

    
por 05.03.2016 / 11:07

Tags