Last active
September 26, 2015 18:37
-
-
Save magnunleno/1141065 to your computer and use it in GitHub Desktop.
vabs-tool from MindBending (http://mindbending.org/pt/criando-uma-ferramenta-cli-para-uso-do-vabs)
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
#!/usr/bin/env python2 | |
# -*- coding: utf-8 -*- | |
from platform import architecture | |
from BeautifulSoup import BeautifulSoup | |
import urllib2 | |
from sys import argv | |
BASE_URL = "http://vabs.archlinux-br.org/" | |
if '64bit' == architecture(): | |
BASE_URL += "x86_64/" | |
else: | |
BASE_URL += "i686/" | |
REPOS = ( | |
'community-testing', | |
'community', | |
'core', | |
'extra', | |
'kde-unstable', | |
'multilib', | |
'testing', | |
) | |
def valida_args(): | |
if len(argv) <= 2 or len(argv) > 3: | |
# Argumentos de menos ou de mais | |
print "Por favor informe os argumentos corretamente" | |
print "Utilização: vabs-tool [-s|-d] <nome_do_pacote>\n" | |
exit(1) | |
if argv[1] not in ("-d", "-s"): | |
# Argumento desconhecido | |
print "Por favor informe uma das seguintes opções: -d ou -s\n" | |
exit(1) | |
if argv[1] == "-d": | |
# Função a ser criada | |
baixa_pacote(argv[2]) | |
else: | |
# Função a ser criada | |
busca_pacote(argv[2]) | |
def busca_pacote_em(repo, nome_pkt): | |
''' | |
Função repensável por buscar e imprimir todos os pacotes que coincidem | |
com o nome informado pelo usuário. | |
''' | |
# URL é $BASE_URL/$repo/$letra_M/ | |
url = BASE_URL + repo + "/" + nome_pkt[0].upper() + "/" | |
# onde: | |
# -BASE_URL: vabs.archlinux-br.org/ seguido pela arquitetura | |
# que pode ser x86_64 ou i686 | |
# -repo: É o nome do repositório (valores da tupla REPO) | |
# -letra_M: Primeira letra do nome do pacote em Maiúsculo | |
# Baixa a página indicada pela variável url | |
try: | |
# A página pode não ser encontrada (404) uma vez que nem todas as | |
# letras constam em todos os repos. | |
resposta = urllib2.urlopen(url) | |
except urllib2.HTTPError as err: | |
# Se o erro for diferente de 404 (não encontrado) mostra a exceção | |
if '404' not in str(err): | |
raise err | |
# Finaliza a execução da função. | |
return | |
# Processa a resposta com a biblioteca BeautifulSoup | |
html = resposta.read() | |
soup = BeautifulSoup(html) | |
# Busca todos os elementos do tipo a | |
# Isto porque (se você olhar o código fonte da página do vABS | |
# verá que) todo pacote esta dentro de uma tag <a href=""></a> | |
for line in soup.findAll('a'): | |
# Converte o objeto para string | |
line = str(line) | |
if '[DIR]' not in line: | |
# Descarta todas as linhas que não tenham o texto [DIR]. | |
# Esse texto faz parte do elemento alt dos links dos pacotes | |
continue | |
if 'parent' in line: | |
# Descarta o 'parent folder' que também é identificado por [DIR] | |
continue | |
# Retira o somente o texto entre aspas (") da linha encontrada | |
line = line[line.index('"')+1:] | |
line = line[:line.index('"')] | |
if nome_pkt in line: | |
# Imprime os pacotes encontrados no formato "nome_repo/nome_pkt" | |
print repo+"/"+line[:-1] | |
def busca_pacote(nome_pkt): | |
for repo in REPOS: | |
busca_pacote_em(repo, nome_pkt) | |
def valida_url(url): | |
''' | |
Requisita uma página e retorna True caso ela exista e | |
Fale caso não exista. | |
''' | |
try: | |
urllib2.urlopen(urllib2.Request(url)) | |
return True | |
except: | |
return False | |
def baixa(url): | |
''' | |
Responsável por tentar baixar um arquivo do vABS para o diretório corrente. | |
''' | |
# Inicia a variável resposta | |
resposta = None | |
# Separa o nome do arquivo para utilizar na criação do arquivo de destino | |
nome = url.split("/")[-1] | |
# Instrução try utilizada para "captar" qualquer erro de página | |
# Uma página pode não ser encontrada (404) uma vez que nem todas as | |
# letras constam em todos os repos. | |
try: | |
# Solicita a página através do módulo urllib2 | |
resposta = urllib2.urlopen(url) | |
except urllib2.HTTPError as err: | |
if '404' not in str(err): | |
# Se o erro for diferente de 404 (não encontrado) mostra uma | |
# exceção não tratada | |
raise err | |
# Finaliza a execução da função caso o erro seja 404 | |
print "Pacote não encontrado:", nome | |
print "URL buscada:",url | |
return | |
# Cria uma arquivo vazio (em modo binário) no diretório corrente | |
f = open(nome, 'wb') | |
# Obtêm metadados da página para deduzir a porcentagem do download | |
meta = resposta.info() | |
# Converte para int o tamanho do arquivo | |
tamanho = int(meta.getheaders("Content-Length")[0]) | |
print "Realizando Download: %s Bytes: %s" % (nome, tamanho) | |
# Inicia a variável que indica quantos bytes já foram baixados | |
tamanho_baixado = 0 | |
# Tamanho do bloco (8 KBytes) | |
tamanho_bloco = 8192 | |
while True: | |
# Lê 8 KBytes do servidor | |
buffer = resposta.read(tamanho_bloco) | |
# Caso a resposta esteja vazia, significa que o download acabou | |
if not buffer: | |
# fim do download | |
break | |
# Incrementa o tamanho baixado com o tamanho de buffer | |
tamanho_baixado += len(buffer) | |
# Escreve o conteúdo baixado no arquivo | |
f.write(buffer) | |
# Cria linha de status | |
status = r"%10d [%3.2f%%]" % \ | |
(tamanho_baixado, tamanho_baixado * 100.0/tamanho) | |
# Adiciona à linha de status alguns caracteres de backspace | |
# (0x8 na tabela ASCII). Isso faz com que ele volte para o | |
# início da linha, assim criamos uma "barra de progresso" | |
status = status + chr(8)*(len(status)+1) | |
print status, | |
f.close() | |
def baixa_pacote(nome_pkt): | |
''' | |
Função utilizada para solicitar a verificação de links e o download | |
do pacote tgz. | |
Ela é dividida em 2 pelo primeiro if: | |
- A parte do if é executada quando o usuário informa um pacote com | |
seu respectivo repositório: "nome_repo/nome_pkt". Essa parte é | |
responsável por separar o nome do repositório e do pacote e chamar | |
a função "baixa". | |
- Já a parte do else é executada quando o usuário não informa o nome | |
do repositório e força a aplicação a buscar o pacote em todos os | |
repositórios. A função joga todas as ocorrência exatas do pacote | |
e adiciona-o em uma lista. Ao final é verificado se essa lista possui: | |
- uma ocorrência: baixa essa única ocorrência | |
- nenhuma ocorrência: emite uma mensagem de erro | |
- mais de uma: e emite uma mensagem de inconsistência. | |
''' | |
if '/' in nome_pkt: | |
#Nome do pacote inclui o repositório | |
repo, nome_pkt = nome_pkt.split("/") | |
# Cria a URL | |
url = BASE_URL + repo + "/" + nome_pkt[0].upper() + "/" + nome_pkt + \ | |
"/" + nome_pkt + ".tgz" | |
# Solicita o Download | |
baixa(url) | |
else: | |
print "Repositório não especificado" | |
print "Buscando pacote nos repositórios..." | |
repos_encontrados = [] | |
for repo in REPOS: | |
# Cria URL para o repo/pacote desta interação | |
url = BASE_URL + repo +"/"+ nome_pkt[0].upper() +\ | |
"/" + nome_pkt + "/" + nome_pkt + ".tgz" | |
# Solicita verificação da URL | |
if valida_url(url): | |
# Se ela existir insere na lista | |
repos_encontrados.append(repo) | |
# Pacote não encontrado em nenhum repositório | |
if len(repos_encontrados) == 0: | |
print "\nNão foi possível encontrar o pacote em nenhum repositório.\n" | |
return | |
# Pacote encontrado em mais de um repositório | |
if len(repos_encontrados) != 1: | |
print "\nNão foi possível baixar o pacote pois ele existe em mais "+\ | |
"de um repositório." | |
print "Repositorios encontrados:", ", ".join(repos_encontrados) | |
return | |
# Apenas um pacote encontrado. Extrai o nome e adiciona a barra | |
repo = repos_encontrados[0] + "/" | |
# Monta a URL | |
url = BASE_URL + repo + nome_pkt[0].upper() + "/" + nome_pkt + "/" + nome_pkt + ".tgz" | |
# Solicita o download do pacote | |
baixa(url) | |
if __name__ == '__main__': | |
valida_args() | |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment