Existem vários casos de uso em que você desejaria trocar a lista de repositórios para um repositório local mais próximo de você.
Em uma instalação padrão, o Ubuntu vai utilizar o país selecionado para pré-fixar um “country code” a url no /etc/apt/sources.list
, no entanto esse comportamento não é ideal. Ao utilizar máquinas virtuais localmente com imagens já prontas, por exemplo usando o Vagrant, o problema se torna ainda pior, pois nesses casos, você provavelmente vai estar usando um repositório fora do país.
Estava tentando automatizar a alteração dos repositórios, e pelo fato de ser um projeto distribuído onde usuários de outros países iriam se beneficiar daquela configuração do Vagrant, não podia simplesmente fixar um país específico ou um repositório local.
O arquivo com a listagem de repositórios padrão da maioria das imagens do Ubuntu no Vagrant se parecem com a seguinte:
deb http://archive.ubuntu.com/ubuntu trusty universe deb-src http://archive.ubuntu.com/ubuntu trusty universe deb http://archive.ubuntu.com/ubuntu trusty-updates universe deb-src http://archive.ubuntu.com/ubuntu trusty-updates universe ## N.B. software from this repository is ENTIRELY UNSUPPORTED by the Ubuntu ## team, and may not be under a free licence. Please satisfy yourself as to ## your rights to use the software. Also, please note that software in ## multiverse WILL NOT receive any review or updates from the Ubuntu ## security team. # deb http://archive.ubuntu.com/ubuntu trusty multiverse # deb-src http://archive.ubuntu.com/ubuntu trusty multiverse # deb http://archive.ubuntu.com/ubuntu trusty-updates multiverse # deb-src http://archive.ubuntu.com/ubuntu trusty-updates multiverse ## Uncomment the following two lines to add software from the 'backports' ## repository. ## N.B. software from this repository may not have been tested as ## extensively as that contained in the main release, although it includes ## newer versions of some applications which may provide useful features. ## Also, please note that software in backports WILL NOT receive any review ## or updates from the Ubuntu security team. # deb http://archive.ubuntu.com/ubuntu trusty-backports main restricted universe multiverse # deb-src http://archive.ubuntu.com/ubuntu trusty-backports main restricted universe multiverse ## Uncomment the following two lines to add software from Canonical's ## 'partner' repository. ## This software is not part of Ubuntu, but is offered by Canonical and the ## respective vendors as a service to Ubuntu users. # deb http://archive.canonical.com/ubuntu trusty partner # deb-src http://archive.canonical.com/ubuntu trusty partner deb http://security.ubuntu.com/ubuntu trusty-security main deb-src http://security.ubuntu.com/ubuntu trusty-security main deb http://security.ubuntu.com/ubuntu trusty-security universe deb-src http://security.ubuntu.com/ubuntu trusty-security universe # deb http://security.ubuntu.com/ubuntu trusty-security multiverse # deb-src http://security.ubuntu.com/ubuntu trusty-security multiverse
Pesquisando pela internet, inicialmente me deparei com o um artigo do AskUbuntu, onde ele sugere duas abordagens possíveis:
1. Apontar no sources.list
uma listagem de mirrors, como exemplo abaixo:
deb mirror://mirrors.ubuntu.com/mirrors.txt trusty main restricted universe multiverse deb mirror://mirrors.ubuntu.com/mirrors.txt trusty-updates main restricted universe multiverse deb mirror://mirrors.ubuntu.com/mirrors.txt trusty-backports main restricted universe multiverse deb mirror://mirrors.ubuntu.com/mirrors.txt trusty-security main restricted universe multiverse
2. Utilizar a ferramenta netselect
para verificar uma listagem de mirrors e alterar o sources.list
usando sed
.
Ambas abordagens tem problemas. Na primeira, existem relatos de falhas ocasionais, tornando a abordagem não confiável e portanto descartada. Já no caso da segunda, ele leva em consideração apenas a latência, sendo que no caso dos mirrors existem outros parâmetros úteis (banda, quão atrasado em relação ao oficial, etc).
Durante a minha pesquisa, haviam críticas sobre lugares onde o mirror selecionado que era mais perto não era o mais rápido, etc.
No final do artigo, um script em Python que leva em consideração as informações de status dos mirrors contidas na listagem oficial, acabou sendo a melhor opção.
O problema agora era como automatizar isso dentro do meu Vagrantfile
. A primeira tentativa envolvia atualizar o apt, instalar as dependências, instalar o git, clonar o repositório e então rodar na mão.
O problema é que esse procedimento seria executado com o mirror original, e por isso ainda não era ideal. A alternativa correta seria empacotar a ferramenta, baixar o pacote e instalar como primeiro procedimento.
Foi exatamente isso que fiz.
Criando pacotes Debian
Criar pacotes Debian (.deb) na mão é um dos processos mais chatos que alguém pode fazer, pois é extremamente burocrático. Existe uma infinidade de arquivos e pastas que precisam ser criadas com conteúdos específicos seguindo um formato específico, e pra ajudar a documentação é extensa, complexa e em muitos casos desatualizada.
Por sorte existem dois projetos que podem nos ajudar aqui, o primeiro é o FPM: “Effing package management! Build packages for multiple platforms (deb, rpm, etc) with great ease and sanity”.
O FPM surgiu da frustração, do trabalho repetitivo que o autor original dele passava ao ter que criar pacotes, para mais de uma distribuição linux. Ele torna possível, com um comando simples e poucos parâmetros, gerar pacote para qualquer distribuição e mais alguns outros formatos.
O segundo projeto é um “syntax sugar” em cima do FPM, que se parece muito com receitas do Homebrew, o FPM Cookery.
Este é um exemplo simplificado da receita que escrevi, com o mínimo para que seja empacotado:
class AptSelect < FPM::Cookery::Recipe name 'apt-select' version '0.1.0' revision 0 homepage 'https://github.com/jblakeman/apt-select' license 'MIT' description 'Choose a fast, up to date Ubuntu apt mirror' maintainer 'Gabriel Mazetto <brodock@gmail.com>' source './', :with => :local_path arch 'all' platforms [:ubuntu] do depends 'python-bs4' end def build end def install share('apt-select').mkdir share('apt-select/bin').mkdir Dir["#{workdir}/*"].each { |f| share('apt-select').install f if allowed_file?(f) } Dir["#{workdir}/bin/*"].each { |f| share('apt-select/bin').install f } end private def allowed_file?(file) allowed_formats = %w(.py .md .sh) allowed_formats.include? File.extname(file) end end
As primeiras informações da receita são os metadados do pacote, além da origem dos arquivos (eu optei por uma receita auto-contida no repositório, mas poderia baixar um tarball, clonar um repositório etc).
Como se trata de um código Python, não existe a necessidade de compilação, por isso a etapa de build
está vazia.
O install
é onde ocorre a criação de pastas e selecionamos pra onde os arquivos vão. Neste exemplo criei também um helper method allowed_file?
pra selecionar programaticamente os arquivos de interesse.
O código final pode ser visto nesse pull-request, e quem quiser pegar o arquivo já empacotado, pode encontrar aqui.
Utilizando o apt-select
Com o pacote baixado e instalado, ao rodar o comando apt-select
, ele vai pesquisar na lista de mirrors e nas informações de status, para determinar qual o melhor, e gerar um arquivo sources.list na pasta onde você executou o comando inicialmente.
Existe um segundo comando no pacote que é o apt-select-update
, este deve ser executado após o primeiro, usando sudo, e ele será responsável por trocar o oficial do sistema, fazer um backup e substituir pela versão otimizada.
Com os comandos a seguir, podemos fazer a instalação a busca pelo melhor mirror e substituir o atual do sistema:
curl -s -L -O https://github.com/brodock/apt-select/releases/download/0.1.0/apt-select_0.1.0-0_all.deb && sudo dpkg -i apt-select_0.1.0-0_all.deb apt-select && sudo apt-select-update
Os pacotes funcionam tanto em i386 (32 bits) quanto amd64 (64 bits), e foram testados no Ubuntu 12.04 e 14.04, mas devem funcionar em outras versões também.