segunda-feira, 26 de outubro de 2015

Compilando imagens do Debian Live com Bitbucket, SourceForge e Google Cloud



Recentemente, implantamos Linux em alguns dos computadores da empresa. Para esses usuários, que lidam a maior parte do tempo com o browser, a migração não foi problemática: não havia a necessidade de software específico para eles. Como utilizamos o Google Apps for Work, então não temos nenhum problema de compatibilidade, e podemos contar com backups, colaboração em tempo real, e portabilidade da informação.

Para facilitar a implantação, eu precisava de uma forma de fazer uma seleção de scripts, aplicar algumas customizações e configurações internas para aderir à nossas políticas de software, e foi aí que tive a idéia de criar uma imagem customizada do Debian.

Eu uso a nuvem do Google diariamente, seja em minhas atividades de trabalho ou seja em meus projetos pessoais. Neste post eu vou comentar como eu conectei diferentes serviços à nuvem do Google para viabilizar um desses projetos pessoais e sem fins lucrativos: o ronolinux.

Esse projeto nada mais é do que de uma compilação de imagens live, resultado de uma seleção minimalista de pacotes para facilitar a implantação do Linux em meus casos de uso. Ele também serve como um projeto modelo para quem deseja masterizar seu próprio DVD/USB-live com Debian personalizado.

Debian Live

O projeto que eu utilizei como base no ronolinux foi o Debian Live, agora Live Systems. Este projeto consiste em um conjunto de scripts para a configuração e compilação de imagens live baseadas no Debian e derivados. Este é o projeto que produz as imagens live oficiais do Debian, então tem suporte no repositório e é mantido por um desenvolvedor Debian.

Bom, mas o que tem o Debian Live a ver com a nuvem do Google? Eu tinha um pequeno problema com relação ao ronolinux. Compilar a imagem leva um tempo, requer uma boa conexão com a internet, um bom espaço em disco para cache. Fazer isso no notebook, via wifi, acabava por gerar alguns problemas:
  • Eu tinha que levar meus dados de um lugar para o outro, estava tudo no notebook.
  • Eu tinha que aguardar o build terminar localmente para então desligar o notebook. Isso era ruim, porque eu queria deixar ele rodando no final do dia, pra não adiar uma correção pro dia seguinte.
  • O build consome muita memória e CPU em alguns estágios, e eu não conseguia prosseguir com outras atividades na máquina que estava compilando a imagem.
  • Eu queria iterar no desenvolvimento em momentos nos quais eu não tinha a máquina de build em mãos, ou quando ela não estava ligada.
  • Para testar as imagens, eu tinha que ou copiar em mídia, ou fazer o upload de arquivos de alguns gigabytes.

Nuvem para o resgate!

Não só porque está na moda, no meu caso era a solução perfeita: rodar os builds na nuvem! Para isso eu fiz uma máquina virtual Debian Jessie no Compute Engine e começei a compilar as imagens por lá.

Com isso eu tinha diversas vantagens. Como eu poderia apenas abrir o browser e conectar por SSH na máquina virtual, não precisava mais carregar o notebook pra lá e pra cá. Além disso, eu podia também contar com algumas vantagens do Compute Engine, tais como uma boa conexão de rede para baixar pacotes, e o disco persistente para fazer cache entre uma compilação e otura, além de poder escolher diferentes opções de disco, CPU e memória.

O Compute Engine é tão bem integrado com o Debian que temos até um mirror do repositório acessível de dentro do Google Cloud, otimizando ainda mais o build. Mas eu não parei por aí. Afinal de contas, estamos na era da integração contínua, e compilar as imagens é feito a partir de um código-fonte simples que configura como e quais pacotes vão na ISO.

Push to deploy!

Eu queria implementar um recurso extra: fazer o build ser acionado por um push no repositório. Para isso, o que eu fiz foi implementar um handler HTTP  em Go, utilizando o pacote vmproxy, que eu desenvolvi para permitir executar VMs do Compute Engine a partir do App Engine, sob-demanda, bem como "desligá-las" quando não estão mais em uso.

Desta forma, não só eu pude configurar uma webhook no Bitbucket para automatizar o build, mas também publicar o resultado no SourceForge, que tem um bom espaço para armazenamento e uma integração por rsync para o upload, o que o tornou uma opção exclenente para hospedar o resultado das imagens.

O melhor disso tudo é que eu posso usar máquinas virtuais com disco SSD, bom desempenho de CPU e Memória, e ainda contar com uma redução fantástica de custos: posso usar uma máquina preemptível, que é muito mais barata do que a máquina virtual convencional!

Neste ponto você pergunta: - Mas você não está fazendo imagens live? O problema do upload de imagens ficou resolvido, mas e pra testar, não tem que baixar tudo de novo?

Exatamente! Para resolver isso, eu aprendi uma coisa ao trabalhar como Debian Live. Automaticamente, o sistema gera um arquivo .zsync. O zsync é uma ferramenta ideal para sincronizar arquivos, especialmente nesse caso que são arquivos ISO, alterados frequentemente. O zsync baixa o arquivo de controle, e depois só baixa os pedaços da imagem nova que você ainda não tem. Isso é ótimo, e eu pude comprovar: reaproveitei mais de 85% do arquivo de imagem entre um build e outro!

Meu workflow agora ficou assim:
  1. De qualquer lugar, posso fazer apenas um push para o Bitbucket com uma mudança de configuração: incluir pacote, adicionar hook, etc.
  2. O Bitbucket aciona meu webhook no App Engine, que liga a VM com o script de startup.
  3. O script faz o checkout do Bitbucket, compila as imagens, e publica no SourceForge. No final, desliga a VM e salva um backup dos logs no Cloud Storage.
  4. Eu configurei uma notificação no SourceForge, e sempre que ele recebe uma versão nova do ronolinux, eu recebo um email.
  5. Para testar, eu baixo a versão atualizada do meu ISO com o zsync, reaproveitando o máximo da imagem anterior que eu já tinha na máquina de testes, ou baixando uma nova, pra testar em qualquer lugar.

Conclusão

Utilizando recursos hoje já disponíveis, é possível elaborar mecanismos complexos para resolver problemas de forma simples e prática, e sem pagar muito por isso. O que eu vou ter de custos com o Google Cloud não compra um computador novo, que ainda me custaria energia pra rodar apenas esse projeto simples e sem fins lucrativos que é o ronolinux. Com a nuvem do Google e os serviços Bitbucket e SourceForge, eu pude conectar as peças e obter um workflow que otimiza o meu tempo e torna o build simples e rápido.

Estou agora considerando reduzir o tempo de 1h pra gerar as duas "edições" do ronolinux, desktop e developer, em paralelo, o que deve deixar tudo em torno de 30min depois do commit.

Você pode encontrar o código-fonte, incluindo os scripts de build do Compute Engine no meu projeto do Bitbucket. As imagens que estou produzindo ainda estão em fase prelimitar de testes, mas caso queira conferir estão aqui no SourceForge.

:happy hacking!


terça-feira, 1 de setembro de 2015

Olá, Gopher!


O Google desenvolveu uma nova linguagem de programação, chamada Go, que tem uma proposta moderna e inovadora. Go é uma linguagem compilada, estaticamente tipada, e que foi inicialmente projetada para ser um substitudo de C. Com uma sintaxe simples e concisa, recursos de programação concorrente avançados, e com uma runtime e garbage collector, Go possui recursos avançados de programação.

Neste artigo nós vamos dar os primeiros passos em Go, instalando o compilador em ambiente Linux e escrevendo nosso primeiro programa. Neste artigo vamos explorar também algumas das características do Go que o tornam atrativo para o programador de hoje em dia.

Obtendo o compilador Go

Como é uma linguagem compilada, você vai precisar de um compilador Go. Existem aqui duas opções: você pode utilizar o GCC, se já está acostumado, pois o gccgo já faz parte das edições mais recentes do compilador Gnu. Eu recomendo a segunda opção: utilizar a compilador e a coleção de ferramentas do próprio Go. Além de vários recursos extras, o compilador oficial recebe os recursos novos primeiro.

Para obter o compilador Go, faça o download no site oficial da linguagem em https://golang.org/dl/. No site você pode escolher a versão correta para seu sistema operacional e arquitetura, e então seguir as instruções para instalar em seu sistema Operacional. Em sistemas Linux, basta extrair o arquivo baixado (.tar.gz) em sua pasta /usr/local. Em seguida, você pode então configurar a variável PATH para incluir a pasta onde o Go foi instalado.

Se você utilizar Linux, e seu computador for de 64 bits, pode utilizar estes comandos:

$ curl https://storage.googleapis.com/golang/go1.5.linux-amd64.tar.gz | sudo tar -C /usr/local -xzf -
$ echo 'export PATH=$PATH:/usr/local/go/bin' >> .bashrc

Desta forma, basta você recarregar seu shell e confirmar que o Go está instalado:

$ go version
go version go1.5 linux/amd64


Agora vamos a uma etapa da isntalação que é importante. O Go assume que você vai guardar seus arquivos em uma pasta especial, chamada GOPATH. O compilador vai usar essa variável para encontrar seu código, bem como as dependências de terceiros que você utilizar. Imagine que isso é o equivalente à dezenas de milhares de -I e -L para compilar código C, ou configurar o CLASSPATH do compilador Java. Em Go, sempre preferimos convenção a configuração, e isso traz benefícios logo de início!

Escolha uma pasta onde você vai guardar seus projetos Go. Se estiver com dúvidas, você pode fazer a sua pasta principal ser a pasta do GOPATH:

$ echo 'export GOPATH=$HOME' >> .bashrc
$ echo 'export PATH=$PATH:$GOPATH/bin' >> .bashrc

Note que na segunda linha, eu adicionei mais um diretório ao PATH: o GOPATH/bin, que é onde o Go instala os programas. Isso faz com que logo depois de compilar e instalar localmente seus programas Go, eles já estão prontos para uso!

Seu primeiro programa Go

Agora que você já tem o comando go instalado, vamos usá-lo para criar nosso primeiro programa. O programa deve ser salvo na pasta src/hello de seu $GOPATH.

Vamos criar o arquivo hello.go com o seguinte conteúdo:

package main

import (
    "fmt"
)

func main() {
    fmt.Println("Hello, world!")
}

Salve o arquivo e em seguida, execute o comando go build:

~/src/hello$ go build
~/src/hello$ ls
hello  hello.go


Agora vamos executar nosso programa:

~/src/hello$ ./hello
Hello, world!


Pronto! Você acaba de criar seu primeiro programa em Go. O comando go build executa o processo de compilar e linkar seu programa, ou seja, ele irá transformar seu código fonte em um arquivo binário executável, estaticamente linkado. Isso significa que você pode simplesmente copiá-lo e executá-lo em outro computador com a mesma arquitetura/sistema operacional, as biblitoecas, a Runtime do Go e o Garbage collector são todos inclusos em seu programa.

Neste artigo não vamos entrar em detalhes sobre a sintaxe, mas como você pode notar no exemplo acima, ela é simples e elegante, direto ao ponto. Eu vou começar aqui uma série de posts sobre como programar em Go, todos com a tag golang, então fique de olho!

Poste nos comentários o que gostaria de aprender sobre Go, ou se você já utiliza, compartlhe o que achou da linguagem!

Happy Hacking!

The Go Gopher is a creation of Renee French, under Creative Commons 3.0.

segunda-feira, 24 de agosto de 2015

Primeiros passos com o Raspberry Pi


O Raspberry Pi é um mini computador desenvolvido por pesquisadores da Universidade de Cambridge, com o objetivo de oferecer aos estudantes uma ferramenta de baixo custo, com o intuito de incentivar os estudos em programação de computadores. O Pi é um computador pessoal, como o que você compra em lojas, com alguns recursos limitados, tamanho reduzido e preço acessível: $35.

O Pi é um computador completo: processador, memória RAM, portas USB, saída de vídeo componente e HDMI, saída de áudio, plug RJ45 para rede cabeada (ethernet). O setup básico consiste em você plugá-lo em sua TV pelo HDMI ou vídeo componente (RCA), plugar na porta USB um teclado e ligá-lo. O Pi não possui um gabinete, mas existem cases para protegê-lo.

Propositalmente, ele possui alguns circuitos e pinos para conexão, os chamados GPIOs (General-pourpose Input/Output - entrada e saída de propósito geral), permitindo usar o Pi em projetos de eletrônica diversos, conectando-o a componentes customizados, proto-boards, sensores, e outros.

O primeiro passo é comprar um Pi. Se você estiver em uma viagem para os EUA (como foi o meu caso no Google I/O 2014), basta encomendar um pela Amazon. Se você não for viajar, pode também importar um dos resellers que possuem international shipping, mas leve em conta que o imposto a ser pago na alfândega é o de um computador. Aqui no Brasil você encontra ele a um preço um pouco mais salgado do que a proposta inglesa. O Pi deve sair em torno de R$ 120,00 a R$ 180,00, pesquise no Mercado Livre ou em lojas de eletrônica.

Existem duas gerações de raspberry Pi. Na primeira geração, temos dois modelos, o Pi 1 Model A+, Pi 1 Model B+. Recentemente foi lançada a segunda geração, o Pi 2 Model B+. O Model Pi 1 A+ possui o menor consumo de energia dos três, mas um baixo poder de processamento e memória RAM, e o Pi 2 Model B+ é o que possui mais recursos.

De posse do seu Pi, você primeiro deve instalar ou configurar o cartão de memória para boot com um sistema operacional. O Pi funciona geralmente com alguma versão do Linux, já que o kernel, módulos e o tamanho do sistema instalado podem ser otimizados para o hardware do Pi. No meu caso, eu comprei um Kit da Amazon, em uma viagem ao exterior, e o meu cartão de memória já veio formatado com o software para a instalação de diversos sabores de sistemas que funcionam no Pi. Ao ligar, o setup já lhe pergunta qual o sistema você quer instalar e faz o processo todo sozinho. Você também encontra tutoriais sobre como configurar o Raspbian, versão do Debian para o Raspberry Pi, ou até locais que vendem o Raspbian pré-instalado no SD-Card. Recomendo comprar o cartão já instalado se você quiser ir direto para a implementação de algo útil.

Com o cartão de memória configurado, basta plugar os componentes. Eu utilizei uma TV, com entrada HDMI, e um teclado USB sem fio da Logitec, que já vem com um Touch Pad (é, eu voltei dos EUA cheio de bugingangas...). O Pi, diferente de um computador convencional, não tem um botão liga/desliga: a fonte de alimentação já inicia o boot. Com ele ligado, basta seguir as orientações on-screen. Eu escolhi o Raspbian, a versão do Debian GNU/Linux compilada para o Pi. Eu gosto muito do Debian, já tenho vários anos de experiência e hoje ele está no meu computador de casa, trabalho e notebook. A instalação é bem simples a partir do SD card já formatado para o Pi, então basta esperar pela mensagem de que o SO foi instalado com sucesso.

Depois de instalado, o sistema faz o boot. É um boot de Linux tradicional: mensagens de log ao carregar os módulos do kernel e inicializar os serviços. O primeiro boot tem algumas opções de configuração inicial, como expandir o cartão de memória para ter espaço de armazenamento, alterar a senha do usuário padrão (recomendado!), entre outros. Você pode voltar nesta tela novamente mais tarde usando os seguintes comando:

sudo raspi-config

Eu utilizei as opções de atualização de senha e habilitar a câmera, já que eu também comprei o módulo de câmera compatível com o Pi, bem como a de configurar opções locais, e ajustei o fuso horário e relógio do Pi, mas mantive o idioma em inglês. Eu também entrei nas opções avançadas, para habilitar o SSH, assim eu poderia usá-lo sem um monitor, pela rede, bem como configurar o hostname, nome como ele é visível na rede.

Ao concluir as configurações do primeiro boot, eu recomendo reiniciar o Pi, quando ele lhe pergunta se você quer fazer isso, assim as suas configurações podem ser validadas logo no início. Minha recomendação é para que você já teste se os ajustes feitos entrão em efeito da forma correta.

Depois de reiniciar o Pi, ele está pronto para uso. Ao ligar o Pi, ele inicializará em modo texto, ou seja, você não vai ver uma tela gráfica logo de início. Ele vai mostrar um prompt pedindo o nome de usuário. O Raspbian já vem com um usuário pi e a senha que você configurou no primeiro boot. Depios de digitar o usuário e senha, você pode digirar o comando

startx

Para carregar a interface gráfica do sistema, que é o LXDE, já com vários softwares e configurações para o Pi disponíveis: o manual do Debian, IDLE, uma IDE para o Python, documentação sobre o desenvolvimento de jogos com PyGame, link para a loja do Pi, configuração de rede sem fio (se você tiver um wifi usb), e muito mais. Um item interessante é o Scratch, um aplicativo desenvolvido para o Pi, para ensinar programação para crianças. Você monta um algoritmo de forma visual, e executa ele no Scratch.

O que fazer com ele?

Por ser um computador completo, o céu é o limite! O seu tamanho pequeno e baixo consumo de energia proporcionam diversas aplicações onde um computador convencional não seria adequado. Eu já postei aqui no blog um tutorial de como usá-lo pra transformar uma impressora convencional em uma impressora do Cloud Printer (na verdade, uma impressora de rede local também, via Cups).

Eu tenho alguns projetos em mente para implementar, incluindo:
  • Um vídeo-game com motion detection para controles.
  • Um roteador customizado com modens.
  • Ser a central de controle de um sistema de automação/monitoramento residencial.
E você, o que gostaria de implementar com um Pi? Poste aqui nos comentários!

Happy hacking!

Referências

[1] Richardson, Matt, and Shawn P. Wallace. Getting started with Raspberry Pi. Sebastopol, CA: O'Reilly Media, 2012.
[2] Raspberry Pi Hardware - https://www.raspberrypi.org/documentation/hardware/raspberrypi/

sexta-feira, 12 de junho de 2015

Conectando sua impressora convencional ao Google Cloud Print com Raspberry PI e Debian

O Google Cloud Print é um serviço do Google que possibilita realizar impressão de documentos, fotos e outros tipos de arquivo utilizando a internet. Isso significa que você pode conectar suas impressoras em qualquer dispositivo compatível, como tablets e telefones, e realizar impressões diretamente deles. O mais bacana: é possível configurar tudo via software!

Neste post nós vamos aprender como configurar o Google Cloud Print no Linux, utilizando o Raspberry PI. O motivo de eu utilizar este equipamento é que ele pode ficar ligado o tempo todo, gastando bem menos energia do que um computador convencional. Além disso, o Pi pode ser usado para outras tarefas, como servir arquivos de mídia ou rodar alguns joguinhos, ou servir de equipamento de vigilância com câmera. Isso ficará para os próximos posts :)

Você vai precisar de:

  • Uma impressora
  • Um Raspberry PI (com Raspbian) ou um Computador (com Debian/Ubuntu)
  • Conhecimentos básicos de comandos do Linux
  • Uma conta do Google

Conecte o Pi à internet

Estou assumindo que você já possui o Pi funcional ou um computador com Linux. Eu recomendo usar no Pi o Raspbian e em um computador convencional o Debian.

O primeiro passo é ligar e acessar seu Raspberry, e conectá-lo com a sua rede de internet. Você pode ligar o Pi e conectar nele um teclado, e ligar ele na TV pela saída HDMI. Se você possui um Wifi USB, pode deixar a conexão sem fio, senão, pode conectá-lo via rede cabeada mesmo. Com ele na rede, você também pode usar um computador para conectar-se via SSH no Pi.

Importante: o seu Pi precisa estar conectado à internet, caso contrário o Cloud Print não vai funcionar.

Instale o software necessário

Importante: neste tutorial iremos executar diferentes comandos, como diferentes usuários: isso serve para garantir a adequada execução do Cloud Print Proxy. Eu vou assinalar os comandos a serem executados como o usuário padrão (geralmente pi) que possui o sudo habilitado, bem como os comandos que iremos executar com a conta dedicada ao Cloud Print (googlecloudprint). A parte em cinza serve apenas para isso, os comandos são apenas a parte em negrito.

Primeiro, faça um upgrade para obter as atualizações de segurança:

pi@pi$ sudo apt-get update && sudo apt-get upgrade

Em seguida, vamos instalar o Chromium, que é a versão do Google Chrome para o Debian, e o servidor de impressão chamado CUPS:

pi@pi$ sudo apt-get install chromium cups unzip
pi@pi$ sudo apt-get clean

Adicione sua Impressora ao Pi

Agora que temos o software necessário, vamos à configuração. Primeiro, vamos criar uma conta dedicada à impressão, chamaremos o usuário de googlecloudprint e vamos dar a ele acesso à gestão de impressoras, pelo grupo lpadmin.

Para isso, execute o comando abaixo e preencha os campos para criar o usuário. Você definirá um senha para este usuário que iremos precisar logo em seguida, tome nota da mesma e não deixe essa ser uma senha fraca.

pi@pi$ sudo adduser --ingroup lpadmin googlecloudprint

Agora, vamos configurar o CUPs para que possamos adicionar impressoras ao Pi, que serão depois configuradas como impressoras do Cloud Print. O CUPS possui uma interface web que permite gerenciar as impressoras, e nós vamos ativar esta interface web na rede local, assim podemos fazer a gestão das impressoras de outros computadores e o Pi não precisa ficar conectado a teclado ou monitor.

Para isso nós vamos editar o arquivo de configuração do CUPS que está na pasta /etc/cups:

pi@pi$ sudo nano /etc/cups/cupsd.conf

A primeira modificação é no parâmetro Listen, que está restrito ao próprio computador, e nós vamos modificar para não restringir apenas à maquina local. No arquivo, procure por:

# Only listen for connections from the local machine.
Listen localhost:631
Listen /var/run/cups/cups.sock

E modifique para:

# Only listen for connections from the local machine.
# Listen localhost:631
Listen /var/run/cups/cups.sock
Port 631

Agora, mais abaixo no mesmo arquivo, vamos ajustar as configurações de segurança. Procure pelas linhas abaixo, e inclua Allow @local, semelhante ao que está destacado em negrito:

< Location / >

# Restrict access to the server...
Order allow,deny
Allow @local
< /Location >

< Location /admin >
# Restrict access to the admin pages...
Order allow,deny
Allow @local
< /Location >

< Location /admin/conf >
AuthType Default
Require user @SYSTEM

# Restrict access to the configuration files...
Order allow,deny
Allow @local
< /Location >

Depois de salvar as alterações no arquivo (no nano, utilize CTRL+X depois Y ENTER), reinicie o CUPS:

pi@pi$ sudo service cups restart

Agora que está tudo configurado, tente acessar o CUPS pelo endereço IP do seu Raspberry, na porta 631, a partir de qualquer outro computador na rede ou mesmo de se seu smartphone, se ele estiver conectado à mesma rede que o Pi: https://ip-do-seu-raspberry:631/.  Dica: conecte-se via HTTPS, e confirme a exceção de segurança se o navegador exibir essa pergunta.

Uma vez conectado ao CUPS, clique em Administration:


E em seguida, no botão Add Printer:


O CUPS vai pedir uma usuário e senha. Informe o usuário e senha que criamos antereiormente: googlecloudprint. Escolha a impressora na lista. Você pode adicionar impressoras de rede que estiverem acessíveis ao Pi, ou a impressora conectada por USB. Em seguida, clique em Continue.

Informe um nome para sua impressora, sem espaços, informe uma descrição, que pode ter espaços, e uma localização, com "Casa" ou "Escritório". Clique em ContinueDica: ao marcar Share this printer, sua impressora ficará visível para outros computadores da rede local, assim você poderá utilizá-la como impressora de rede, mesmo sem o Cloud Print.

Escolha o modelo, normalmente ele estará pré-selecionado, dê um nome para ela e em seguida clique em Add Printer.

Pode ser que o CUPS exiba também uma página para configurar alguns valores padrão, como orientação de papel, etc. Faça as escolhas que julgar necessário e clique em Set Default Options.

Eu sugiro que você imprima uma página de testes via CUPS, só para ter certeza que está tudo OK e que o Pi consegue enviar a impressão corretamente.

Configure o serviço do Google Cloud Print

Agora, para por nossa impressora na núvem, vamos utilizar o Chromium. As etapas para configurar o Cloud Print em modo servidor podem ser obtidas na documentação oficial, mas eu traduzi e adicionei algumas etapas para a configuração ficar mais robusta.

Primeiro, vamos trocar de usuário para o que criamos anteriormente. Observe que no seu shell, o nome do usuário vai mudar de pi para googlecloudprint:

pi@pi$ sudo su googlecloudprint
googlecloudprint@pi$ cd ~/

Agora, faça o download do arquivo generate_cloudprint_config.py.zip:

googlecloudprint@pi$ wget http://www.google.com/support/enterprise/static/chromeos/docs/admin/en/generate_cloudprint_config.py.zip
googlecloudprint@pi$ unzip generate_cloudprint_config.py.zip
googlecloudprint@pi$ chmod +x generate_cloudprint_config.py

Agora, para concluir, nós vamos utilizar este script para configurar nossa conta do Google para nosso servidor de impressão:

googlecloudprint@pi$ ./generate_cloudprint_config.py

Dica: se você utiliza Two Factor Authentication, vai ter que definir uma Senha de Aplicativo para utilizar. Não se engane: ao por a sua senha do Google o script acima termina sem erros, mas não gera tokens de acesso.

Siga os passos apresentados pelo script. Informe seu usuário e senha do Google, ou senha de aplicativo se tiver two factor authentication ativo. A sua saída será algo mais ou menos assim:

Email Address: ******@gmail.com
Password for ******@gmail.com
Connector Id: raspberrypi
Printserver URL with port (keep empty to skip): http://localhost:631/
Config file raspberrypi.conf generated for proxy raspberrypi

É importante que você informe o nome do conector raspberrypi e a URL do servidor de impressão CUPS na configuração. Depois que o comando terminar, você terá um arquivo chamado raspberrypi.conf, que deve ser renomeado para Service State:

googlecloudprint@pi$ mv raspberrypi.conf 'Service State'

Agora, vamos criar um script de configuração para o serviço iniciar automaticamente quando ligarmos o Pi.

Dica: Você pode usar o comando: googlecloudprint@pi$  cat > google-cloud-print  e em seguida colar o conteúdo e pressionar CTRL+D para salvar. 

Salve o arquivo abaixo com o nome google-cloud-print na pasta /home/googlecloudprint:

#!/bin/bash

### BEGIN INIT INFO
# Provides:          google-cloud-print
# Required-Start:    $remote_fs $syslog $networking
# Required-Stop:     $remote_fs $syslog $networking
# Default-Start:     2 3 4 5
# Default-Stop:      0 1 6
# Short-Description: Google Cloud Print Service
# Description:       This service launches a Google Cloud Print.
### END INIT INFO

export HOME="/home/googlecloudprint/"
unset DISPLAY

start_service() {
        echo "Starting service ..."
        cd $HOME
        start-stop-daemon --start \
                --chuid googlecloudprint \
                --chdir /home/googlecloudprint \
                --background --verbose \
                -x /usr/lib/chromium/chromium -- \
                        --type=service \
                        --enable-cloud-print-proxy \
                        --no-service-autorun \
                        --noerrdialogs \
                        --user-data-dir=/home/googlecloudprint/ \
                        --enable-logging --v=1
}

find_pid() {
        ps fax | grep enable-cloud-print-proxy |\
                grep -v grep | awk '{print $1}'
}

stop_service() {
        echo "Stopping service ..."
        PID="$(find_pid)"
        case "$PID" in
                [0-9]*)
                        echo "Killing $PID ..."
                        kill -9 $PID 2>/dev/null
                ;;
                *)
                        echo "Not running ..."
                ;;
        esac
}

case $1 in
        start)
                start_service
        ;;
        stop)
                stop_service
        ;;
        restart)
                stop_service
                start_service
        ;;
esac

Agora, vamos instalar este script que criamos como um serviço no sistema:

googlecloudprint@pi$ chmod +x google-cloud-print
googlecloudprint@pi$ exit #para retornar ao usuário que possui acesso sudo (pi no meu caso)
pi@pi$ sudo ln -s /home/googlecloudprint/google-cloud-print /etc/init.d/google-cloud-print
pi@pi$ sudo update-rc.d google-cloud-print defaults
pi@pi$ sudo service google-cloud-print start

Agora, navegue até a página do Google Cloud Print e confirme se a impressora está disponível e online:


Veja nos detalhes avançados da impressora, e note que o campo Proxy será o mesmo nome que definimos em nossa configuração.

Prontinho, agora você pode enviar trabalhos de impressão a partir de qualquer programa ou equipamento compatível com o Google Cloud Print, e eles são encaminhados à sua impressora via internet.

Happy hacking!

quarta-feira, 10 de abril de 2013

Transformando o VIM em uma IDE completa.



O VIM (Vi IMproved) é o meu editor favorito para inúmeras tarefas. Ele é a combinação perfeita entre robustez e eficiência. Em outras palavras, ele é simplesmente meu canivete suiço.

Muito provavelmente, o seu primeiro contato com o Vim será aterrorizante. Felizmente, depois de entender alguns dos conceitos básicos, você perceberá com detalhes que ele é, como diria minha mãe: pau pra toda obra.

Se você já estudou em algum curso superior em informática, provavelmente já passou por alguma disciplina em que teve de implementar um editor de texto. Foi implementando o meu próprio editor de texto na faculdade que percebi o quão poderoso o Vim pode ser.

Se o Vim é algo muito novo para você, eu recomendo executar o tutorial que já vem nos pacotes das distribuições mais novas. É um excelente tutorial interativo, utilizando a própria ajuda do vim.

Instalação

Se você usa alguma distribuição baseada em Debian, como o Ubuntu, basta instalar o vim com o apt-get:

$ apt-get install vim vim-gnome

Se você for apenas utilizar o Vim pelo terminal, não precisa do vim-gnome. Eu recomendo o Vim-gnome porque ele lhe permite utilizar algumas integrações com o ambiente gráfico, além de ter uma barra de ferramentas e uma boa integração com o mouse, ideal para principiantes. Se você ainda não encontrou a luz, e ainda está usando Windows, pode instalar o Vim no seu computador, baixando diretamente do site do projeto [0].

Um pouco do básico

O ideal para você iniciar é seguir o passo a passo do vimtutor. Depios de instalar o Vim, você poderá iiciar o vimtutor do terminal por meio do comando:

$ vimtutor

De qualquer forma, seguem algumas dicas importantes para começar:

  1. O vim possui uma "barra de status", no rodapé da janela. Ela também é a barra na qual você digita os "comandos" do editor. Pense nestes comandos como o equivalente a uma dezena de botões e menus que normalmente você encontra nos programas: eles lhe dão acesso aos recursos do software, a única diferença é que você vai digitá-los ao invés de clicar neles.
  2. O vim possui modos, e isso é, muitas vezes o primeiro obstáculo. O modo normal pode ser entendido como um modo de somente leitura, no qual você digita instruções na barra de comandos. O modo de inserção é o modo que você usa para editar o conteúdo do arquivo e o modo visual é o modo que você poderá fazer seleções no texto para copiar ou recortar partes do mesmo.
  3. Ao entrar no vim, você terá acesso ao modo normal, e se começar a digitar pode acionar acidentalmente comandos indesejados. Pressionando a letra i ou o botão INSERT, você entra no modo de inserção, e pressionando v no modo visual. Estando nos modos de inserção ou visual, pressionando ESC você retorna para o modo normal.
  4. Os comandos do vim são, normalmente, digitados no modo normal, prefixados pelo caractere dois pontos: :. Por exemplo, para encerrar o vim utilize o comando :q. Para salvar o texto atual (muitas vezes chamado de buffer na documentação do Vim) utilize o comando :w. Um atalho para sair do vim, já salvando, é o comando :x. Lembre-se que, normalmente, você vai apertar um ESC antes de digitar os comandos, já que assim garante que está no modo normal.
  5. O vim possui um manual de ajuda embutido, que dá detalhes completos sobre o programa. Para abrir o manual, utilize o comando :help. Também é possível ler um tópico específico do manual utilizando o comando help seguido do tópico, comando ou função desejado. Experimente ler os tópicos :help q, :help w e :help x
Essas dicas simples servem para ajudara a entender o funcionamento básico, apenas para que você fique mais familiarizado com o Vim. Utilize o vimtutor para aprender mais sobre a ferramenta se você está apenas iniciando.

Mais do que um editor de textos

O vim não é apenas um simples editor de buffers de texto. Por exemplo, você pode fazer coisas como:

  • Executar comandos no prompt.
  • Abrir abas, dividir a tela em janelas horizontal e verticalmente, e tudo isso combinado diversas vezes.
  • Compilar o código fonte.
  • Criar scripts e funções.
  • Mapear atalhos do teclado para comandos do editor.
  • Visualizar diretórios, arquivos .zip, .tar.gz, e arquivos binários (se você souber o que está fazendo, é muito útil).
  • Pesquisar / substituir utilizando expressões regulares.
  • Auto-completar código (assim como nas IDEs mais famosas).
  • Utilizar (e customizar!) o syntax highlight de todo e qualquer tipo de arquivo.
  • Navegar pelo código fonte (com o auxílio de um arquivo de tags).
  • ... e muito, muito mais!
Combinando uma boa seleção de plugins, mapeamentos confortáveis no teclado, e entendendo a dinâmicda do Vim, você poderá utilizá-lo como um substituto excelente para programar em diversas linguagens.


Personalizando

Você pode customizar o Vim por meio do arquivo .vimrc, salvo em seu diretório pessoal (~/.vimrc no *nix). Este arquivo consiste, basicamente, em comandos que você poderia digitar diretamente na barra de status do Vim, combinados na forma de um pequeno vimscript. Neste arquivo, assim como em qualquer outro script do Vim, uma linha iniciada por aspas é um comentário.

Neste post, vou lhes mostar algumas configurações que eu geralmente uso para tornar o Vim mais agradável.

syntax on
Ativa a sintaxe por padrão, ao carregar o vim. O recurso vem desabilitado porque pode demorar para carregar arquivos grandes. É útil ele estar ativo já que nos arquivos muito grandes, você pode pressionar CTRL+C para interromper o parser do hilight, e depois desabilitar com syntax off.

set number
Ativa a numeração das linhas. Muito interessante especialmente para edição de código-fonte. Por padrão desabilitado, e você também pode desligar com o comando :set nonumber

set mouse=a
Ativa (mesmo em conexões por SSH!) as funcionalidades do mouse para a sua sessão do Vim.

set hlsearch
Ativa o hilight das pesquisas. Basicamente, quando você efetua uma busca, busca e substituição, o vim irá deixar as ocorrências em destaque, parecido ao amarelão do Gedit/Kwrite quando você pesquisa por algo.

set nomousehide
Não sei porque, mas tem horas que o mouse no Gvim dá uma sumida, e parece que você está ficando doido. Não tem efeito se você abrir o vim no terminal.

set sw=8 ts=8 st=8 noet si ai
Esta sequência "mágica", configura a tabulação para o equivalente a 8 espaços, sem expandir o tab, ou seja, sem substituir tudo por espaços. Na prática, cada comando separado por um espaço faz uma coisa. Fica como uma tarefa para o leitor consultar o manual de cada um. Todos juntos são úteis para que as quebras de linha no código já identem corretamente. Troque o 8 por 4 ou 2 se você preferir visualizar as tabulações com menos espaços, e troque noet por et para inserir espaços quando você pressionar a tecla tab (não faça isso em Makefiles!).

au
Aqui começa um pouco de "mágica" na sua configuração. O au ou autocommand permite que eventos sejam mapeados para comandos do editor que permite que a customização seja dinâmica, conforme o tipo de arquivo que você está editando, por exemplo. Vamos supor que você queira utilizar espaços no lugar de tabulações, e que sejam 4 espaços ao invés de 8 para a maior parte dos arquivos, mas quando você estiver editando um Makefile, você quer que a configuração seja para usar as tabulações mesmo, e queira visualizar com 8 espaços. Para atingir este objetivo, basta usar as linhas abaixo em seu vimrc:

set sw=4 ts=4 st=4 et si ai
au BufRead,BufNewFile Makefile set sw=8 ts=8 st=8 noet si ai

A primeira linha configura como padrão a tabulação de 4 espaços, e a segunda, configura um autocommand, para toda vez que um arquivo for lido ou aberto, com o nome Makefile, configurar a tabulação normal. Veja mais detalhes em :help au.

Em seu vimrc, além de comandos como os acima, você também poderá criar funções (que são executadas com o comando :call) e criar comandos personalizados, que basicamente agrupam outros comandos ou chamam outras funções. Comandos definidos pelo usuário devem ser iniciados por uma letra maiúscula.

Criando funções

Vamos supor que você queira criar uma função para fazer o pull de seu repositório mercurial, sem deixar o editor. Para isso, você pode incluir o seguinte em seu vimrc:

function HgPull()
  echo "Trazendo revisões do servidor remoto ..."
  !hg pull
endfunction

Para executar esta função, basta digitar o comando :call HgPull()A primeira linha inicia uma função, a segunda e terciera contêm o corpo da função e a quarta, encerra a função. Um atalho para as palavras chaves function e endfunction são, respectivamente fu e endfu. O comando ! é um comando do vim que executa uma função no shell (ou prompt), e por padrão exibe a saída do comando que o segue.

Plugins

Os plugins são instalados em seu diretório ~/.vim/plugins. Para plugins que nem sempre são utilizados, você poderá instalá-los no ~/.vim/autoload, desde que o script do plugin tenha suporte para isso. Uma lista interessante de plugins para você ir brincando pode ser encontrada em [3].

Um vimrc que já está quase virando plugin

Eu e outros amigos usuários do Vim estamos montando um vimrc que compartilhamos no Bitbucket. Tive esta iniciativa para uniformizar o meu vimrc de casa, do notebook e do trabalho, e também para tornar o trabalho de programar em Java com o Vim um pouco menos laborioso. Como efeito colateral, à medida em que fui utilizando o vim para programar e fui incrementando o vimrc com vários recursos, fui aprendendo cada vez mais sobre vimscript.

Nom momento em que escrevo, o vimrc está hospedado junto com outros scripts bem interessantes que eu estou publicando no projeto https://bitbucket.org/ronoaldo/ronoaldo-utils. Atualmente, ele traz as configurações acima, uma coletânea com pequenas funções que eu uso diariamente, e alguns mapeamentos de teclado interessantes, como o CTRL+S para salvar o arquivo. Também inclui ma seleção de plugins instaláveis facilmente por funções definidas no próprio vimrc por meio do script pathogen.vim, e uma configuração especial para projetos Java/Maven em ~/workspace/projeto.

Com esta configuração, você pode:

  • Instalar a coletânea de plugins com o comando :call InstallAllPlugins.
  • Utilizar o CTRL+F12 para abrir um navegador de arquivos (plugin NERDTree).
  • Salvar pressionando CTRL+S.
  • Utilizar o comando :IndexWorkspace para indexar todos os arquivos .java de sua workspace (requer exuberant-ctags).
  • Utilizar CTRL+P para fazer pull e CTRL+U para fazer push no Mercurial.
  • Executar testes de projetos Maven em sua workspace com o comando :Junit
  • Compilar um projeto Maven utilizando CTRL+F8, ou arquivos Java standalone utilizando o mesmo atalho.
  • Utilizar templates de código estilo os do Textmate (plugin snipmate).
  • Criar atalhos de forma bem simples, com o comando :call KeyMap("atalho", "ação")
  • E mais está por vir ...

O script está crescendo em funcionalidades e eu estou considerando a possibilidade de que ele seja, por si só, um plugin. Estou recebendo patches ;)

Conclusão

Se você está procurando por uma alternative eficiente e leve, mas sem perder a robustez, o Vim pode ser uma excelente escolha, depois que você quebrar a barreira do como eu começo a digitar nesta coisa?.

:echo "Happy hacking!"

Referencias


[0] Site oficial: http://www.vim.org/
[1] Vim Tips Wiki: http://vim.wikia.com/wiki/Vim_Tips_Wiki
[2] Ótimo tutorial sobre Vimscript: http://learnvimscriptthehardway.stevelosh.com/
[3] Lista com plugins úteis: http://www.catonmat.net/series/vim-plugins-you-should-know-about

quarta-feira, 21 de dezembro de 2011

Instalando features do Eclipse via linha de comando com Provision Platform, p2

O Eclipse é a minha IDE favorita, por algumas razões:
  • OpenSource: sendo uma ferramenta de código livre, além de ser possível contribuir, analisar, reutilizar o código-fonte e aprender com o mesmo, a comunidade de desenvolvedores ao redor do mundo pode ampliar os horizontes da plataforma com suas contribuições.
  • Multi-plataforma: assim como a maior parte das ferramentas open-source, o Eclipse também é multi-plataforma, oferecendo assim ainda mais liberdade para que você trabalhe no ambiente que lhe proporciona mais segurança e mais recursos.
  • Multi-linguagem: como todo bom programador, eu não sou viciado em uma única linguagem, e procuro sempre utilizar a linguagem apenas como ferramenta. Apesar de ter trabalhando recentemente mais com a linguagem Java, Python, C e C++, PHP são outros sabores que eu aprecio. Claro, um pouco de shell script para automatizar tarefas corriqueiras são uma boa pedida. O Eclipse lhe oferece um ambiente uniforme para trabalhar com as linguagens, o que para mim é um fator importante, evitando atritos ao programar em mais de uma linguagem em curtos intervalos de tempo.
Por estes e outros motivos, me tornei um Amigo do Eclipse, e fiz uma modesta contribuição para o projeto. Recentemente, descobri um recurso da plataforma que facilita automatizar a instalação de plugins via linha de comando. Este recurso permite que você faça a instalação de uma série de plugins de uma única vez, realize deploys ou até mesmo, construa a partir de sua própria seleção de plugins, uma versão customizada da IDE.

Background
O processo faz uso de um recurso da plataforma do Eclipse chamado Provisioning Platform (p2). Especificamente, uma aplicação do p2 chamada Director [1]. Com esta aplicação, é possível automatizar o processo via linha de comando.

Basicamente, tudo que você tem a fazer é executar a aplicação org.eclipse.equinox.p2.director, e informar as features a serem instaladas, bem como os repositórios a serem consultados para resolução de dependências.

Tecnicamente, este é o mesmo processo que a interface gráfica realiza, com exceção de que você está automaticamente concordando com as licenças dos softwares que está instalando, uma vez que a tela de confirmação não é exibida.

Passo a passo
Terminologia básica para o processo de instalação:
  • Director: a aplicação do Eclipse que está realizando a instalação ou remoção de software. Ela está no bundle org.eclipse.equinox.p2.director.app.
  • Builder: uma aplicação baseada na plataforma do Eclipse que contém o bundle do Director e suas dependências. Pode ser utilizado, por exemplo, para criar uma nova instalação de plugins (modo shared) ou da IDE completa em um diretório diferente.
  • Produto alvo: uma aplicação alvo onde o software será instalado. Pode ser o mesmo do Builder, quando você quer instalar plugins e features em uma versão da IDE, como o Java EE.
Tudo que precisamos é do p2 Director para começar. O modo mais fácil é você já ter baixado o Eclipse para Java, Java EE ou qualquer outro de sua preferência, e começar a adicionar um conjunto de plugins. Você também pode, por exemplo, criar também uma aplicação mínima do eclipse que tenha apenas o Director e então, criar um instalador para baixar um pacote completo.

Vamos supor que você tenha baixado o Eclipse for Java EE Developers, e queira adicionar o Mobile Tools For Java (MTJ). Para isso, você precisará utilizar o seguinte comando (supondo que o binário ou script launcher do Eclipse esteja em seu PATH):


$ eclipse -nosplash -application org.eclipse.equinox.p2.director -repository http://download.eclipse.org/releases/indigo/ -installIU org.eclipse.mtj.feature.group -tag “Added-org.eclipse.mtj.feature.group”

O parâmetro -nosplash evita que a tela de splash seja exibida e fique congelada, já que não precisamos de interface gráfica. Com o parâmetro -application indicamos que o Director deve ser iniciado e não a Workbench. Os parâmetros seguintes, -repository e -installIU, permitem configurar, respectivamente, de onde os plugins e features serão baixados e quais instalation units devem ser adicionadas (plugins, features ou feature-groups). Esses dois parâmetros recebem uma lista separada por vírgulas, o que permite instalar vários plugins de diferentes fontes ao mesmo tempo. O parãmetro -tag permite marcar o que foi feito nesta operação, assim fica fácil “reverter” pela itnerface gráfica do Eclipse (ou mesmo pelo director) para uma tag mais antiga caso a instalação falhe.

Depois de rodar este comando, você vai ver algumas linhas no prompt:

Installing org.eclipse.mtj.feature.group 1.1.2.201109111413.
Operation completed in 337201 ms.

Ao iniciar novamente o Eclipse, você vai poder confirmar que o MTJ foi adicionado com sucesso ao sistema:

Você pdoe conferir nossa tag clicando em Help → About Eclipse, depois no botão Instalation Details. Na aba Instalation History, você vai ver:


Apesar dos parâmetros -repository e -feature aceitarem multiplas opções separadas por vírgula, eu notei que ao tentar instalar muitos plugins em uma única vez pode resultar em conflitos. Eu acredito que o resolvedor de dependências começa a ficar confuso. Eu também notei isso na própria interface gráfica, via Eclipse Marketplace ao tentar instalar o Google Plugin + SDKs, Apache Ivy e Pydev ao mesmo tempo.

p2-install
O que me motivou a descobrir este recurso foi ter que, nas últimas semanas, configurar várias vezes uma mesma instalação do Eclipse padrão com as ferramentas do Google Plugin for Eclipse, SDKs do AppEngine e Google Webtoolkit, Apache Ivy e IvyDE, e o MercurialEclipse. Este conjunto de ferramentas é o mínimo  essencial no meu emprego atual. Como erros intermitentes ao baixar todas de uma vez só pelo Eclipse Marketplace, tive que procurar uma alternativa.

O trabalho rendeu até um pequeno script que eu compartilhei no Bitbucket no projeto ronoaldo-utils. O script já facilita um pouco com alguns defaults, prevê multiplas instalações do Eclipse e permite que você faça também um “discover” pelos feature-groups disponíveis.

Veja o código-fonte aqui. Se tiver alguma sugestão ou melhoria, crie um fork e submita um patch!

Próximos Passos
Além de instalar plugins e feature groups (Uma feature ou grupo de features composta por vários plugins), o Director permite que você instale em um outro diretório: ou seja, instale a partir de uma aplicação, tendo uma aplicação diferente como alvo. O interessante é que você pode baixar e construir a IDE inteira com este recurso. Outra ferramenta interessante do p2 é que você pode também fazer mirror e gerenciar repositório com os plugins. Ao ler isso, imaginei uma forma bem interessante de realizar o deploy de versões já pré-configuradas do Eclipse via linha de comando, para diversas máquinas, como em um laboratório ou departamento de TI. Mas, isso é assunto para outro post...

Happy hacking!

Referências

sábado, 17 de setembro de 2011

Calculando MD5 e SHA1 em Java

Hashes são extremamente úteis para representar em uma pequena cadeia de bits uma outra cadeia de bits que pode ser bem maior. Podemos considerá-lo uma forma de criptografia assimétrica, uma vez que não é possível (a não ser por meio de algoritmos de força bruta) recuperar a cadeia original a partir do hash.

Existem diversos algoritmos para o cálculo de hashes, e em Java utilizamos a classe MessageDigest para recuperar a implementação desejada. Por exemplo, para calcular o MD5 de uma string, podemos utilizar:

MessageDigest md5 = MessageDigest.getInstance("MD5");
md5.update("string original".getBytes());
byte[] digest = md5.digest();

Para exibir os dados como string, recurso util quando você pretende utilizar o MD5 para conferir se todos os bytes de um arquivo foram baixados, basta formatá-lo com:

String.format("%1$032x", new BigInteger(1, digest));

O resultado é exatamente o hash MD5 da string:

~$ echo "string original" | md5sum
3ced9d1f470cd18f06a8b6492d3ea94e  -

Neste exemplo, utilizamos a string de formatação "%1$032x", porque queremos o resultado em hexadecimal, alinhado em 32 casas à esquerda. Construímos um BigInteger positivo, com os bits resultantes da soma, e isso nos permite converter os bytes do array para hexadecimal de forma simples.

Podemos fazer de forma semelhante ao calcular o SHA1:

MessageDigest sha1 = MessageDigest.getInstance("SHA-1");
sha1.update("string original".getBytes());
byte[] digest = sha1.digest();
String.format("%1$040x", new BigInteger(1, digest));

Generalizando, você pode também utilizar os seguinte métodos:

public static String computeHash(String data, String algoritm,
        Integer resultSize) {
    try {
        MessageDigest digest = MessageDigest.getInstance(algoritm);
        digest.update(data.getBytes());
        return hexdigits(digest.digest(), resultSize);
    } catch (NoSuchAlgorithmException e) {
        throw new RuntimeException("Unable to hash with " + algoritm);
    }
}

public static String hexdigits(byte[] data, Integer resultSize) {
    return String
            .format("%1$0" + resultSize + "x", new BigInteger(1, data));
}

Até a próxima dica!