<?xml version="1.0" encoding="UTF-8"?>
<rss version="2.0"
	xmlns:content="http://purl.org/rss/1.0/modules/content/"
	xmlns:wfw="http://wellformedweb.org/CommentAPI/"
	xmlns:dc="http://purl.org/dc/elements/1.1/"
	xmlns:atom="http://www.w3.org/2005/Atom"
	xmlns:sy="http://purl.org/rss/1.0/modules/syndication/"
	xmlns:slash="http://purl.org/rss/1.0/modules/slash/"
	>

<channel>
	<title>DestaqueBlog &#187; configuração</title>
	<atom:link href="http://weblog.destaquenet.com/tag/configuracao/feed/" rel="self" type="application/rss+xml" />
	<link>http://weblog.destaquenet.com</link>
	<description>Blog da equipe Destaquenet.</description>
	<lastBuildDate>Tue, 23 Nov 2010 17:06:50 +0000</lastBuildDate>
	<language>en</language>
	<sy:updatePeriod>hourly</sy:updatePeriod>
	<sy:updateFrequency>1</sy:updateFrequency>
	<generator>http://wordpress.org/?v=3.3</generator>
		<item>
		<title>Django Para Dispositivos Móveis</title>
		<link>http://weblog.destaquenet.com/2010/07/12/django-para-dispositivos-moveis/</link>
		<comments>http://weblog.destaquenet.com/2010/07/12/django-para-dispositivos-moveis/#comments</comments>
		<pubDate>Mon, 12 Jul 2010 11:10:21 +0000</pubDate>
		<dc:creator>Daniel Martins</dc:creator>
				<category><![CDATA[Português]]></category>
		<category><![CDATA[Programação]]></category>
		<category><![CDATA[Tutoriais]]></category>
		<category><![CDATA[apache]]></category>
		<category><![CDATA[configuração]]></category>
		<category><![CDATA[deploy]]></category>
		<category><![CDATA[dispositivo]]></category>
		<category><![CDATA[django]]></category>
		<category><![CDATA[framework]]></category>
		<category><![CDATA[móvel]]></category>
		<category><![CDATA[python]]></category>
		<category><![CDATA[web]]></category>
		<category><![CDATA[wsgi]]></category>

		<guid isPermaLink="false">http://weblog.destaquenet.com/?p=944</guid>
		<description><![CDATA[Estamos vivendo o que alguns chamam de &#8220;explosão mobile&#8221;, um tempo onde um número cada vez maior de dispositivos móveis &#8212; como tablets e smartphones &#8212; se tornam parte significante da Web. Esta é a razão pela qual ter seu &#8230; <a href="http://weblog.destaquenet.com/2010/07/12/django-para-dispositivos-moveis/">Continue lendo <span class="meta-nav">&#8594;</span></a>]]></description>
			<content:encoded><![CDATA[<p>Estamos vivendo o que alguns chamam de &#8220;explosão mobile&#8221;, um tempo onde um número cada vez maior de dispositivos móveis &#8212; como tablets e smartphones &#8212; se tornam parte significante da Web. Esta é a razão pela qual ter seu website preparado para tais dispositivos é cada vez mais importante.</p>
<p>Felizmente, <a href="http://djangoproject.com/">Django</a> é um dos poucos frameworks web que tornam este um problema simples de solucionar.</p>
<p><span id="more-944"></span></p>
<h3>Como resolvemos este problema</h3>
<p>Um jeito simples é criar um módulo <code>settings.py</code> separado para a versão &#8220;mobile&#8221;. Isso nos permite rodar dois sites diferentes reusando a mesma base de código. Além disso, cada versão pode ter seu próprio diretório de templates, configurações de URL, etc.</p>
<p>Vamos fazer isso. No diretório-raíz do projeto, crie um arquivo <code>m_settings.py</code> com o seguinte conteúdo:</p>

<div class="wp_syntax"><div class="code"><pre class="python" style="font-family:monospace;"><span style="color: #808080; font-style: italic;"># Arquivo: myproject/m_settings.py</span>
&nbsp;
<span style="color: #483d8b;">&quot;&quot;&quot;Configurações para a versão &quot;mobile&quot; do website.
&quot;&quot;&quot;</span>
&nbsp;
<span style="color: #808080; font-style: italic;"># Carrega as configurações padrão</span>
<span style="color: #ff7700;font-weight:bold;">from</span> settings <span style="color: #ff7700;font-weight:bold;">import</span> <span style="color: #66cc66;">*</span>
&nbsp;
<span style="color: #808080; font-style: italic;"># Domínio &quot;m.mydomain.com&quot;</span>
SITE_ID = <span style="color: #ff4500;">2</span>
PREPEND_WWW = <span style="color: #008000;">False</span>
&nbsp;
<span style="color: #808080; font-style: italic;"># Usado em outras partes do código para determinar qual versão está rodando</span>
DEFAULT_VERSION = <span style="color: #008000;">False</span>
MOBILE_VERSION  = <span style="color: #008000;">True</span>
&nbsp;
<span style="color: #808080; font-style: italic;"># URLs para a versão mobile</span>
ROOT_URLCONF  = <span style="color: #483d8b;">'myproject.m_urls'</span>
&nbsp;
<span style="color: #808080; font-style: italic;"># Templates para a versão mobile</span>
TEMPLATE_DIRS = <span style="color: black;">&#40;</span>
    <span style="color: #dc143c;">os</span>.<span style="color: black;">path</span>.<span style="color: black;">normpath</span><span style="color: black;">&#40;</span><span style="color: #dc143c;">os</span>.<span style="color: black;">path</span>.<span style="color: black;">dirname</span><span style="color: black;">&#40;</span>__file__<span style="color: black;">&#41;</span> + <span style="color: #483d8b;">'/template/mobile'</span><span style="color: black;">&#41;</span>,
<span style="color: black;">&#41;</span>
&nbsp;
<span style="color: #808080; font-style: italic;"># Outras configurações...</span></pre></div></div>

<p>O fato de os dois sites compartilharem a mesma base de código não significa que eles devem ter as mesmas configurações de URL. Aliás, o normal é que versões próprias para dispositivos móveis sejam mais simples, com uma quantidade reduzida de mapeamentos de URLs.</p>
<p>Para definir as configurações de URL da versão mobile, crie um arquivo <code>m_urls.py</code> com o seguinte conteúdo:</p>

<div class="wp_syntax"><div class="code"><pre class="python" style="font-family:monospace;"><span style="color: #808080; font-style: italic;"># Arquivo: myproject/m_urls.py</span>
&nbsp;
<span style="color: #483d8b;">&quot;&quot;&quot;Mapeamentos de URL para a versão &quot;mobile&quot;.
&quot;&quot;&quot;</span>
&nbsp;
<span style="color: #ff7700;font-weight:bold;">from</span> django.<span style="color: black;">conf</span> <span style="color: #ff7700;font-weight:bold;">import</span> settings
<span style="color: #ff7700;font-weight:bold;">from</span> django.<span style="color: black;">conf</span>.<span style="color: black;">urls</span>.<span style="color: black;">defaults</span> <span style="color: #ff7700;font-weight:bold;">import</span> <span style="color: #66cc66;">*</span>
<span style="color: #808080; font-style: italic;"># from django.contrib import admin</span>
&nbsp;
<span style="color: #808080; font-style: italic;"># admin.autodiscover()</span>
&nbsp;
handler404 = <span style="color: #483d8b;">'website.views.error_404_handler'</span>
handler500 = <span style="color: #483d8b;">'website.views.error_500_handler'</span>
&nbsp;
<span style="color: #808080; font-style: italic;"># URLs</span>
urlpatterns = patterns<span style="color: black;">&#40;</span><span style="color: #483d8b;">''</span>,
    <span style="color: #808080; font-style: italic;"># I18N</span>
    <span style="color: black;">&#40;</span>r<span style="color: #483d8b;">'^i18n/'</span>, include<span style="color: black;">&#40;</span><span style="color: #483d8b;">'django.conf.urls.i18n'</span><span style="color: black;">&#41;</span><span style="color: black;">&#41;</span>,
&nbsp;
    <span style="color: #808080; font-style: italic;"># Apps internas</span>
    <span style="color: black;">&#40;</span>r<span style="color: #483d8b;">'^contact/'</span>, include<span style="color: black;">&#40;</span><span style="color: #483d8b;">'contact.urls'</span><span style="color: black;">&#41;</span><span style="color: black;">&#41;</span>,
&nbsp;
    <span style="color: #808080; font-style: italic;"># (r'^admin/doc/', include('django.contrib.admindocs.urls')),</span>
    <span style="color: #808080; font-style: italic;"># (r'^admin/', include(admin.site.urls)),</span>
&nbsp;
    <span style="color: #808080; font-style: italic;"># Outras configurações...</span>
<span style="color: black;">&#41;</span></pre></div></div>

<p>Perceba que, neste exemplo em particular, a <a href="http://docs.djangoproject.com/en/dev/ref/contrib/admin/">app Admin</a> não é acessível através da versão mobile. Isso apenas serve para mostrar que temos total liberdade para estruturar ambas as versões de diferentes formas, sem muitas dificuldades.</p>
<h3>Desenvolvendo</h3>
<p>Você certamente já sabe como rodar o servidor de desenvolvimento para a versão padrão. O que a maioria dos desenvolvedores desconhece, entretanto, é que é possível escolher qual a porta e/ou módulo <code>settings.py</code> deve ser usado pelo script, o que nos permite rodar um servidor para cada versão do nosso site:</p>

<div class="wp_syntax"><div class="code"><pre class="bash" style="font-family:monospace;"><span style="color: #666666; font-style: italic;"># Terminal 1: versão padrão</span>
$ python manage.py runserver <span style="color: #000000;">8000</span>
&nbsp;
<span style="color: #666666; font-style: italic;"># Terminal 2: versão mobile</span>
$ python manage.py runserver <span style="color: #660033;">--settings</span>=m_settings <span style="color: #000000;">8001</span></pre></div></div>

<p>Pronto, agora é só continuar com o desenvolvimento da forma que você já está acostumado.</p>
<h3>Testando</h3>
<p>Você provavelmente notou que temos duas configurações que podem ser usadas para determinar qual versão do site está rodando, <code>DEFAULT_VERSION</code> e <code>MOBILE_VERSION</code>. </p>
<p>Por isso, é só uma questão de checar tais configurações quando for necessário fazer coisas diferentes em cada uma das versões do site. Isso é particularmente útil quando você tem uma app usada em ambas as versões e quer criar testes para cada uma das versões:</p>

<div class="wp_syntax"><div class="code"><pre class="python" style="font-family:monospace;"><span style="color: #808080; font-style: italic;"># Arquivo: myproject/myapp/tests/__init__.py</span>
&nbsp;
<span style="color: #483d8b;">&quot;&quot;&quot;Testes para MyApp.
&quot;&quot;&quot;</span>
&nbsp;
<span style="color: #ff7700;font-weight:bold;">from</span> django.<span style="color: black;">conf</span> <span style="color: #ff7700;font-weight:bold;">import</span> settings
&nbsp;
<span style="color: #ff7700;font-weight:bold;">if</span> <span style="color: #008000;">getattr</span><span style="color: black;">&#40;</span>settings, <span style="color: #483d8b;">'DEFAULT_VERSION'</span>, <span style="color: #008000;">False</span><span style="color: black;">&#41;</span>:
    <span style="color: #808080; font-style: italic;"># Testa a versão padrão</span>
    <span style="color: #ff7700;font-weight:bold;">from</span> default_models_tests <span style="color: #ff7700;font-weight:bold;">import</span> <span style="color: #66cc66;">*</span>
    <span style="color: #ff7700;font-weight:bold;">from</span> default_navigation_tests <span style="color: #ff7700;font-weight:bold;">import</span> <span style="color: #66cc66;">*</span>
&nbsp;
<span style="color: #ff7700;font-weight:bold;">if</span> <span style="color: #008000;">getattr</span><span style="color: black;">&#40;</span>settings, <span style="color: #483d8b;">'MOBILE_VERSION'</span>, <span style="color: #008000;">False</span><span style="color: black;">&#41;</span>:
    <span style="color: #808080; font-style: italic;"># Testa a versão mobile</span>
    <span style="color: #ff7700;font-weight:bold;">from</span> mobile_models_tests <span style="color: #ff7700;font-weight:bold;">import</span> <span style="color: #66cc66;">*</span>
    <span style="color: #ff7700;font-weight:bold;">from</span> mobile_navigation_tests <span style="color: #ff7700;font-weight:bold;">import</span> <span style="color: #66cc66;">*</span></pre></div></div>

<p>Você pode rodar os testes para cada versão de uma forma semelhante a que fizemos com o comando <code>runserver</code>:</p>

<div class="wp_syntax"><div class="code"><pre class="bash" style="font-family:monospace;"><span style="color: #666666; font-style: italic;"># Versão padrão</span>
$ python manage.py <span style="color: #7a0874; font-weight: bold;">test</span> <span style="color: #7a0874; font-weight: bold;">&#91;</span>appname...<span style="color: #7a0874; font-weight: bold;">&#93;</span>
&nbsp;
<span style="color: #666666; font-style: italic;"># Versão mobile</span>
$ python manage.py <span style="color: #7a0874; font-weight: bold;">test</span> <span style="color: #660033;">--settings</span>=m_settings <span style="color: #7a0874; font-weight: bold;">&#91;</span>appname...<span style="color: #7a0874; font-weight: bold;">&#93;</span></pre></div></div>

<h3>Colocando em produção</h3>
<p>Apesar do que você possa achar, esta é a parte fácil.</p>
<p>Uma vez que a forma recomendada de <a href="http://docs.djangoproject.com/en/dev/howto/deployment/modwsgi/">colocar Django em produção</a> é com <a href="http://apache.org">Apache</a> e <a href="http://code.google.com/p/modwsgi/">mod_wsgi</a>, é possível que você já tenha um arquivo WSGI parecido com o seguinte:</p>

<div class="wp_syntax"><div class="code"><pre class="python" style="font-family:monospace;"><span style="color: #ff7700;font-weight:bold;">import</span> <span style="color: #dc143c;">os</span>, <span style="color: #dc143c;">sys</span>
&nbsp;
APPS_PATH   = <span style="color: #483d8b;">'/home/user/wsgi_apps'</span>
MYPROJECT_PATH = <span style="color: #483d8b;">'%s/myproject'</span> <span style="color: #66cc66;">%</span> APPS_PATH
&nbsp;
<span style="color: #808080; font-style: italic;"># Eggs de terceiros</span>
<span style="color: #ff7700;font-weight:bold;">import</span> <span style="color: #dc143c;">site</span>
<span style="color: #dc143c;">site</span>.<span style="color: black;">addsitedir</span><span style="color: black;">&#40;</span><span style="color: #483d8b;">'/home/user/.python/lib'</span><span style="color: black;">&#41;</span>
&nbsp;
<span style="color: #dc143c;">sys</span>.<span style="color: black;">path</span> += <span style="color: black;">&#91;</span>APPS_PATH, MYPROJECT_PATH<span style="color: black;">&#93;</span>
<span style="color: #dc143c;">os</span>.<span style="color: black;">environ</span><span style="color: black;">&#91;</span><span style="color: #483d8b;">'DJANGO_SETTINGS_MODULE'</span><span style="color: black;">&#93;</span> = <span style="color: #483d8b;">'myproject.settings'</span>
&nbsp;
<span style="color: #ff7700;font-weight:bold;">import</span> django.<span style="color: black;">core</span>.<span style="color: black;">handlers</span>.<span style="color: black;">wsgi</span>
application = django.<span style="color: black;">core</span>.<span style="color: black;">handlers</span>.<span style="color: black;">wsgi</span>.<span style="color: black;">WSGIHandler</span><span style="color: black;">&#40;</span><span style="color: black;">&#41;</span></pre></div></div>

<p>Tudo que precisamos fazer é configurar um outro sub-domínio WSGI no nosso servidor (ex: m.mywebsite.com) que referencia o seguinte arquivo de configurações WSGI:</p>

<div class="wp_syntax"><div class="code"><pre class="python" style="font-family:monospace;"><span style="color: #ff7700;font-weight:bold;">import</span> <span style="color: #dc143c;">os</span>, <span style="color: #dc143c;">sys</span>
&nbsp;
APPS_PATH   = <span style="color: #483d8b;">'/home/user/wsgi_apps'</span>
MYPROJECT_PATH = <span style="color: #483d8b;">'%s/myproject'</span> <span style="color: #66cc66;">%</span> APPS_PATH
&nbsp;
<span style="color: #808080; font-style: italic;"># Eggs de terceiros</span>
<span style="color: #ff7700;font-weight:bold;">import</span> <span style="color: #dc143c;">site</span>
<span style="color: #dc143c;">site</span>.<span style="color: black;">addsitedir</span><span style="color: black;">&#40;</span><span style="color: #483d8b;">'/home/user/.python/lib'</span><span style="color: black;">&#41;</span>
&nbsp;
<span style="color: #dc143c;">sys</span>.<span style="color: black;">path</span> += <span style="color: black;">&#91;</span>APPS_PATH, MYPROJECT_PATH<span style="color: black;">&#93;</span>
<span style="color: #dc143c;">os</span>.<span style="color: black;">environ</span><span style="color: black;">&#91;</span><span style="color: #483d8b;">'DJANGO_SETTINGS_MODULE'</span><span style="color: black;">&#93;</span> = <span style="color: #483d8b;">'myproject.m_settings'</span> <span style="color: #808080; font-style: italic;"># Esta linha</span>
&nbsp;
<span style="color: #ff7700;font-weight:bold;">import</span> django.<span style="color: black;">core</span>.<span style="color: black;">handlers</span>.<span style="color: black;">wsgi</span>
application = django.<span style="color: black;">core</span>.<span style="color: black;">handlers</span>.<span style="color: black;">wsgi</span>.<span style="color: black;">WSGIHandler</span><span style="color: black;">&#40;</span><span style="color: black;">&#41;</span></pre></div></div>

<p>A única diferença entre esses dois arquivos WSGI é que cada um aponta para um módulo <code>settings.py</code> diferente. E não, você não precisa ter uma cópia do site para cada versão, afinal estamos usando a mesma base de código para ambas as versões, lembra? <img src='http://weblog.destaquenet.com/wp-includes/images/smilies/icon_smile.gif' alt=':-)' class='wp-smiley' /> </p>
<h3>Minimizando o tráfego</h3>
<p>Por incrível que pareça, nem todo mundo dispõe de conexões ultra-rápidas. Por isso, é muito importante que você mantenha seus sites tão leves quanto possível.</p>
<p>Existem vários projetos open source que podem ajudar nessa parte. Um deles é o <a href="http://code.google.com/p/django-compress/">django-compress</a>, uma app Django que fornece um sistema automatizado para compressão de arquivos CSS e JavaScript.</p>
<p>Aliás, não importa se seus websites são para dispositivos móveis ou não; você deve <em>sempre</em> tentar minimizar o tráfego.</p>
<h3>O que falta?</h3>
<p>Ainda temos um pequeno problema: quando alguém visita a versão padrão do site através de um dispositivo móvel, ou vice-versa, eles não são redirecionados para a versão apropriada. Mas isso é assunto para um próximo artigo!</p>
]]></content:encoded>
			<wfw:commentRss>http://weblog.destaquenet.com/2010/07/12/django-para-dispositivos-moveis/feed/</wfw:commentRss>
		<slash:comments>5</slash:comments>
		</item>
		<item>
		<title>Servidor De Email Local No Ubuntu Com Exim</title>
		<link>http://weblog.destaquenet.com/2010/06/25/servidor-de-email-local-no-ubuntu-com-exim/</link>
		<comments>http://weblog.destaquenet.com/2010/06/25/servidor-de-email-local-no-ubuntu-com-exim/#comments</comments>
		<pubDate>Fri, 25 Jun 2010 11:10:07 +0000</pubDate>
		<dc:creator>Daniel Martins</dc:creator>
				<category><![CDATA[Português]]></category>
		<category><![CDATA[Tutoriais]]></category>
		<category><![CDATA[ambiente]]></category>
		<category><![CDATA[configuração]]></category>
		<category><![CDATA[desenvolvimento]]></category>
		<category><![CDATA[email]]></category>
		<category><![CDATA[exim]]></category>
		<category><![CDATA[gmail]]></category>
		<category><![CDATA[linux]]></category>
		<category><![CDATA[sendmail]]></category>
		<category><![CDATA[servidor]]></category>
		<category><![CDATA[smtp]]></category>
		<category><![CDATA[telnet]]></category>
		<category><![CDATA[ubuntu]]></category>

		<guid isPermaLink="false">http://weblog.destaquenet.com/?p=981</guid>
		<description><![CDATA[Vimos em um post anterior como criar testes para código Java que envia e-mails. Agora o assunto é outro. Exim é um MTA open source que pode ser usado como alternativa ao Sendmail em sistemas operacionais Unix. Eu não tenho &#8230; <a href="http://weblog.destaquenet.com/2010/06/25/servidor-de-email-local-no-ubuntu-com-exim/">Continue lendo <span class="meta-nav">&#8594;</span></a>]]></description>
			<content:encoded><![CDATA[<p>Vimos em um post anterior como criar testes para <a href="http://weblog.destaquenet.com/2008/09/20/2-boas-formas-de-testar-clientes-javamail/">código Java que envia e-mails</a>. Agora o assunto é outro.</p>
<p><a href="http://www.exim.org/">Exim</a> é um <acronym title="Mail Transfer Agent">MTA</acronym> open source que pode ser usado como alternativa ao <a href="http://www.sendmail.org/">Sendmail</a> em sistemas operacionais Unix. Eu não tenho idéia de qual é a melhor alternativa disponível, mas se você procura por um servidor de relay para instalar na sua configuração de desenvolvimento, Exim é provavelmente a opção mais simples para começar.</p>
<p>Neste artigo, veremos como configurar o Exim para enviar mensagens através do <a href="http://gmail.com/">Gmail</a>.</p>
<p><span id="more-981"></span></p>
<h3>Instalando o Exim</h3>
<p>Primeiro precisamos instalar o Exim e suas dependências, o que é algo bastante trivial em distribuições Linux modernas como <a href="http://www.ubuntu.com/">Ubuntu</a>/<a href="http://www.debian.org/">Debian</a>:</p>

<div class="wp_syntax"><div class="code"><pre class="bash" style="font-family:monospace;">$ <span style="color: #c20cb9; font-weight: bold;">sudo</span> <span style="color: #c20cb9; font-weight: bold;">apt-get</span> <span style="color: #c20cb9; font-weight: bold;">install</span> exim4</pre></div></div>

<h3>Usando Exim como servidor de relay</h3>
<p>Existe um assistente que nos ajuda a fazer as configurações básicas; rode o comando abaixo para abrí-lo e preencha cada tela como segue:</p>

<div class="wp_syntax"><div class="code"><pre class="bash" style="font-family:monospace;">$ <span style="color: #c20cb9; font-weight: bold;">sudo</span> dpkg-reconfigure exim4-config</pre></div></div>

<ol>
<li><strong>General type of mail configuration:</strong> mail sent by smarthost; received via SMTP or fetchmail</li>
<li><strong>System mail name:</strong> seudominio.com</li>
<li><strong>IP-addresses to listen on for incoming connections:</strong> 127.0.0.1 ; ::1</li>
<li><strong>Other destinations for which mail is accepted:</strong> Deixe em branco</li>
<li><strong>Machines to relay mail for:</strong> Deixe em branco</li>
<li><strong>Host name for the outgoing smarthost:</strong> smtp.gmail.com:587</li>
<li><strong>Hide local mail name in outgoing mail:</strong> Yes</strong></li>
<li><strong>Visible domain name for local users:</strong> seudominio.com</li>
<li><strong>Keep number of DNS-queries minimal:</strong> No</li>
<li><strong>Delivery method for local mail:</strong> mbox format in /var/mail/</li>
<li><strong>Split configuration into small files:</strong> Yes</li>
<li><strong>Root and postmaster mail recipient:</strong> Deixe em branco</li>
</ol>
<p>Agora precisamos configurar as credenciais do usuário no arquivo <code>/etc/exim4/passwd.client</code> adicionando a seguinte linha:</p>
<pre>
# Troque [username] e [password] pelos dados corretos
*.google.com:[username]:[password]
</pre>
<p>Agora basta rodar o comando abaixo para terminar as configurações:</p>

<div class="wp_syntax"><div class="code"><pre class="bash" style="font-family:monospace;">$ <span style="color: #c20cb9; font-weight: bold;">sudo</span> update-exim4.conf</pre></div></div>

<h3>Testando o servidor</h3>
<p>Um jeito simples &#8212; e nerd &#8212; de testar se as configurações estão corretas é usar o comando <code>telnet</code>:</p>
<pre>
$ telnet localhost 25
    Trying ::1...
    Connected to localhost.
    Escape character is '^]'.
    220 localhost ESMTP Exim 4.71 Wed, 23 Jun 2010 22:28:56 -0300
HELO localhost
    250 localhost Hello localhost [::1]
MAIL FROM: usuario@seudominio.com
    250 OK
RCPT TO: destino@email.com
    250 Accepted
DATA
    354 Enter message, ending with "." on a line by itself
SUBJECT: Assunto da mensagem
Testando Exim via Telnet. Massa!
.
    250 OK id=1ORbG5-0005uh-EF
QUIT
    221 localhost closing connection
    Connection closed by foreign host.
</pre>
<p>Abra os arquivos de log em <code>/var/log/exim4</code> para ver se a mensagem foi transmitida sem erros. Uma tentativa bem sucedida se parece com o seguinte:</p>
<pre>
2010-06-23 22:29:47 1ORbG5-0005uh-EF <= local@seudominio.com H=localhost [::1] P=smtp S=345
2010-06-23 22:29:50 1ORbG5-0005uh-EF => destino@email.com R=smarthost T=remote_smtp_smarthost H=gmail-smtp-msa.l.google.com [74.125.45.109] ..."
2010-06-23 22:29:50 1ORbG5-0005uh-EF Completed
</pre>
<p>Caso você não receba a mensagem e os logs não acusem nenhum erro, verifique se a mensagem não foi parar na caixa de spam antes que você mude quaisquer configurações.</p>
]]></content:encoded>
			<wfw:commentRss>http://weblog.destaquenet.com/2010/06/25/servidor-de-email-local-no-ubuntu-com-exim/feed/</wfw:commentRss>
		<slash:comments>1</slash:comments>
		</item>
		<item>
		<title>Django e settings.py: dicas e boas práticas</title>
		<link>http://weblog.destaquenet.com/2009/04/13/django-e-settingspy-dicas-e-boas-praticas/</link>
		<comments>http://weblog.destaquenet.com/2009/04/13/django-e-settingspy-dicas-e-boas-praticas/#comments</comments>
		<pubDate>Tue, 14 Apr 2009 01:32:06 +0000</pubDate>
		<dc:creator>Daniel Martins</dc:creator>
				<category><![CDATA[Português]]></category>
		<category><![CDATA[Programação]]></category>
		<category><![CDATA[boas práticas]]></category>
		<category><![CDATA[configuração]]></category>
		<category><![CDATA[design]]></category>
		<category><![CDATA[dicas]]></category>
		<category><![CDATA[django]]></category>
		<category><![CDATA[framework]]></category>
		<category><![CDATA[python]]></category>
		<category><![CDATA[testes]]></category>

		<guid isPermaLink="false">http://weblog.destaquenet.com/?p=415</guid>
		<description><![CDATA[Em vez de ficar rasgando elogios ao Django, como de costume, eu tentarei aproveitar o melhor o meu (e o seu) tempo e mostrar algo que é de fato útil. O assunto em questão envolve o módulo settings.py, cuja função &#8230; <a href="http://weblog.destaquenet.com/2009/04/13/django-e-settingspy-dicas-e-boas-praticas/">Continue lendo <span class="meta-nav">&#8594;</span></a>]]></description>
			<content:encoded><![CDATA[<p>Em vez de ficar rasgando elogios ao <a href="http://djangoproject.com">Django</a>, como de costume, eu tentarei aproveitar o melhor o meu (e o seu) tempo e mostrar algo que é de fato útil. O assunto em questão envolve o módulo <code>settings.py</code>, cuja função é fornecer as configurações necessárias para que o projeto funcione. Apesar deste módulo ser uma peça importante em qualquer projeto Django, pouco se fala sobre ele, ou sobre boas práticas associadas a ele. Por isso, achei que seria interessante mostrar a minha visão pessoal sobre o assunto.</p>
<h3>O poder do Python</h3>
<p>Quem não está acostumado a trabalhar com Django pode estranhar o fato deste utilizar um script <a href="http://python.org">Python</a> para fazer a configuração do projeto: o famoso <code>settings.py</code>. E essa estranheza é justificada, afinal muitos desenvolvedores &#8212; principalmente os que vêm de outras linguagens &#8212; estão acostumados a trabalhar com ferramentas onde tal tarefa é feita com arquivos XML ou coisa assim.</p>
<p>O fato é que utilizar um script Python para tal é uma excelente idéia, pois você deixa de depender de algum tipo de estrutura estática (e muitas vezes inconveniente) para algo mais flexível e poderoso, que, no caso, é a própria linguagem de programação. Isso faz uma grande diferença em situações onde tal flexibilidade é necessária.</p>
<p>Quer exemplos?<span id="more-415"></span></p>
<h3>Ambientes de desenvolvimento/produção</h3>
<p>Eis como fizemos aqui. Primeiramente, defina a variável de ambiente <code>WORKSPACE</code>. No Linux, isso pode ser feito através do arquivo <code>~/.bashrc</code>:</p>

<div class="wp_syntax"><div class="code"><pre class="bash" style="font-family:monospace;"><span style="color: #7a0874; font-weight: bold;">export</span> <span style="color: #007800;">WORKSPACE</span>=<span style="color: #000000;">1</span></pre></div></div>

<p>A idéia é possibilitar a criação de perfis de configuração, cada qual correspondente a um ambiente de execução. A existência ou não da variável de ambiente é o que define o ambiente no qual a aplicação roda.</p>
<p>Continuando com o exemplo, no diretório raíz do seu projeto Django, crie o módulo <code>environment.py</code>, com o seguinte conteúdo:</p>

<div class="wp_syntax"><div class="code"><pre class="python" style="font-family:monospace;"><span style="color: #ff7700;font-weight:bold;">import</span> <span style="color: #dc143c;">os</span>
&nbsp;
<span style="color: #ff7700;font-weight:bold;">def</span> production_mode<span style="color: black;">&#40;</span><span style="color: black;">&#41;</span>:
    <span style="color: #ff7700;font-weight:bold;">return</span> <span style="color: #ff7700;font-weight:bold;">not</span> development_mode<span style="color: black;">&#40;</span><span style="color: black;">&#41;</span>
&nbsp;
<span style="color: #ff7700;font-weight:bold;">def</span> development_mode<span style="color: black;">&#40;</span><span style="color: black;">&#41;</span>:
    <span style="color: #ff7700;font-weight:bold;">return</span> <span style="color: #483d8b;">'WORKSPACE'</span> <span style="color: #ff7700;font-weight:bold;">in</span> <span style="color: #dc143c;">os</span>.<span style="color: black;">environ</span></pre></div></div>

<p>Finalmente, modifique o módulo <code>settings.py</code> para que este utilize tais métodos onde for necessário definir configurações diferentes para ambientes de execução diferentes:</p>

<div class="wp_syntax"><div class="code"><pre class="python" style="font-family:monospace;"><span style="color: #ff7700;font-weight:bold;">from</span> environment <span style="color: #ff7700;font-weight:bold;">import</span> production_mode
&nbsp;
<span style="color: #808080; font-style: italic;"># Configurações padrão</span>
PREPEND_WWW = <span style="color: #008000;">False</span>
DEBUG = <span style="color: #008000;">True</span>
&nbsp;
<span style="color: #808080; font-style: italic;"># Configurações para ambiente de produção</span>
<span style="color: #ff7700;font-weight:bold;">if</span> production_mode<span style="color: black;">&#40;</span><span style="color: black;">&#41;</span>:
    PREPEND_WWW = <span style="color: #008000;">True</span>
    DEBUG = <span style="color: #008000;">False</span>
&nbsp;
MIDDLEWARE_CLASSES = <span style="color: black;">&#40;</span>
    <span style="color: #483d8b;">'django.middleware.common.CommonMiddleware'</span>,
    <span style="color: #483d8b;">'django.contrib.sessions.middleware.SessionMiddleware'</span>,
    <span style="color: #483d8b;">'django.contrib.auth.middleware.AuthenticationMiddleware'</span>,
    <span style="color: #483d8b;">'django.middleware.doc.XViewMiddleware'</span>,
    <span style="color: #483d8b;">'pages.middleware.PageFallbackMiddleware'</span>,
    <span style="color: #483d8b;">'django.contrib.redirects.middleware.RedirectFallbackMiddleware'</span>,
<span style="color: black;">&#41;</span>
&nbsp;
<span style="color: #808080; font-style: italic;"># Habilitando caching em modo de produção</span>
<span style="color: #ff7700;font-weight:bold;">if</span> production_mode<span style="color: black;">&#40;</span><span style="color: black;">&#41;</span>:
    MIDDLEWARE_CLASSES += <span style="color: black;">&#40;</span>
        <span style="color: #483d8b;">'django.middleware.cache.UpdateCacheMiddleware'</span>,
        <span style="color: #483d8b;">'django.middleware.cache.FetchFromCacheMiddleware'</span>,
    <span style="color: black;">&#41;</span></pre></div></div>

<p>Não tenha medo de utilizar os recursos do Python onde eles se fizerem necessários, apenas tomando cuidado para não exagerar e acabar criando acidentalmente um <a href="http://en.wikipedia.org/wiki/Genetic_algorithm">Algoritmo Genético</a> para configurar seu projeto!</p>
<h3>Informações secretas (IPs, usernames, passwords, etc)</h3>
<p>Praticamente não há quem ignore a importância de um bom sistema de controle de revisões (<a href="http://subversion.tigris.org">Subversion</a>, <a href="http://git-scm.org">Git</a>, etc). O problema é que, muitas vezes, não tomamos o devido cuidado com o que colocamos dentro dos nossos repositórios. Sempre que possível, informações secretas &#8212; como endereços de IP, usernames e passwords &#8212; devem ser mantidas fora dos repositórios.</p>
<p>Em um projeto Django, as informações de acesso a servidores de e-mail e bancos de dados devem estar disponíveis através do módulo  <code>settings.py</code>. Felizmente, existe um jeito simples de manter essas informações separadas das outras configurações.</p>
<p>Primeiramente, abra o arquivo <code>settings.py</code> do seu projeto e remova todas as senhas e outras informações que você considere secretas. Em seguida, cole o seguinte trecho de código no final do arquivo:</p>

<div class="wp_syntax"><div class="code"><pre class="python" style="font-family:monospace;"><span style="color: #ff7700;font-weight:bold;">try</span>:
    <span style="color: #ff7700;font-weight:bold;">from</span> private <span style="color: #ff7700;font-weight:bold;">import</span> <span style="color: #66cc66;">*</span>
<span style="color: #ff7700;font-weight:bold;">except</span> <span style="color: #008000;">ImportError</span>:
    <span style="color: #ff7700;font-weight:bold;">pass</span></pre></div></div>

<p>Feito isso, crie o módulo <code>private.py</code> no diretório raíz do seu projeto Django. Coloque nele as configurações que você removeu do <code>settings.py</code> no passo anterior. Exemplo:</p>

<div class="wp_syntax"><div class="code"><pre class="python" style="font-family:monospace;"><span style="color: #ff7700;font-weight:bold;">from</span> environment <span style="color: #ff7700;font-weight:bold;">import</span> production_mode
&nbsp;
SECRET_KEY = <span style="color: #483d8b;">'secret_key_do_seu_projeto'</span>
&nbsp;
EMAIL_HOST = <span style="color: #483d8b;">'localhost'</span>
EMAIL_HOST_PASSWORD = <span style="color: #483d8b;">'senha_email_local'</span>
&nbsp;
DATABASE_HOST = <span style="color: #483d8b;">'localhost'</span>
DATABASE_USER = <span style="color: #483d8b;">'username_db_local'</span>
DATABASE_PASSWORD = <span style="color: #483d8b;">'senha_db_local'</span>
&nbsp;
<span style="color: #ff7700;font-weight:bold;">if</span> production_mode<span style="color: black;">&#40;</span><span style="color: black;">&#41;</span>:
    EMAIL_HOST = <span style="color: #483d8b;">'ip_email_producao'</span>
    EMAIL_HOST_PASSWORD = <span style="color: #483d8b;">'senha_email_producao'</span>
&nbsp;
    DATABASE_HOST = <span style="color: #483d8b;">'ip_db_producao'</span>
    DATABSE_USER = <span style="color: #483d8b;">'username_db_producao'</span>
    DATABASE_PASSWORD = <span style="color: #483d8b;">'senha_db_producao'</span></pre></div></div>

<p>Certifique-se de adicionar o arquivo <code>private.py</code> no <em>ignore</em> (<code>.cvsignore</code> para <a href="http://www.nongnu.org/cvs/">CVS</a>, <code>.gitignore</code> para Git, etc) correspondente ao sistema de controle de revisões sendo utilizado. Faça o commit e pronto.</p>
<p>Para finalizar, se o seu repositório já contém uma versão &#8220;insegura&#8221; do módulo <code>settings.py</code>, mude as senhas dos seus servidores.</p>
<h3>E você, o que recomenda?</h3>
<p>Tem alguma dica útil para compartilhar conosco? Nós adoraríamos ouvir o que você tem a dizer!</p>
]]></content:encoded>
			<wfw:commentRss>http://weblog.destaquenet.com/2009/04/13/django-e-settingspy-dicas-e-boas-praticas/feed/</wfw:commentRss>
		<slash:comments>8</slash:comments>
		</item>
		<item>
		<title>VPN PPTP no Ubuntu Intrepid</title>
		<link>http://weblog.destaquenet.com/2008/12/02/vpn-pptp-no-ubuntu-intrepid/</link>
		<comments>http://weblog.destaquenet.com/2008/12/02/vpn-pptp-no-ubuntu-intrepid/#comments</comments>
		<pubDate>Wed, 03 Dec 2008 02:51:35 +0000</pubDate>
		<dc:creator>Daniel Martins</dc:creator>
				<category><![CDATA[Português]]></category>
		<category><![CDATA[Tutoriais]]></category>
		<category><![CDATA[conectividade]]></category>
		<category><![CDATA[configuração]]></category>
		<category><![CDATA[dicas]]></category>
		<category><![CDATA[linux]]></category>
		<category><![CDATA[network manager]]></category>
		<category><![CDATA[pptp]]></category>
		<category><![CDATA[rede]]></category>
		<category><![CDATA[ubuntu]]></category>
		<category><![CDATA[vpn]]></category>

		<guid isPermaLink="false">http://weblog.destaquenet.com/?p=304</guid>
		<description><![CDATA[Um dia após o lançamento do Intrepid (versão 8.10) do Ubuntu Linux, eu já tinha feito o download e a instalação na minha máquina de trabalho, um notebook Dell. Vou poupar elogios, até porque eu utilizo o Ubuntu diariamente desde &#8230; <a href="http://weblog.destaquenet.com/2008/12/02/vpn-pptp-no-ubuntu-intrepid/">Continue lendo <span class="meta-nav">&#8594;</span></a>]]></description>
			<content:encoded><![CDATA[<p>Um dia após o lançamento do Intrepid (versão 8.10) do <a href="http://www.ubuntu.com/">Ubuntu Linux</a>, eu já tinha feito o <em>download</em> e a instalação na minha máquina de trabalho, um notebook Dell. Vou poupar elogios, até porque eu utilizo o Ubuntu diariamente desde o lançamento da release Dapper Drake (versão 6.06), de Julho de 2006. De lá para cá, muito trabalho vem sendo feito para tornar o Ubuntu o sistema ideal para uso em desktops e laptops.</p>
<p>Um dos aspectos que se encontram em constante evolução é a parte de conectividade. O <a href="http://projects.gnome.org/NetworkManager/">Network Manager</a>, gerenciador de conexões utilizado nas versões mais recentes do Ubuntu, torna simples a tarefa de se conectar com praticamente qualquer tipo de rede, inclusive com as recém chegadas redes 3G.</p>
<p>Apesar de facilitar a vida na maioria dos casos, o Network Manager presente na última versão do Ubuntu parece não funcionar do jeito que deveria, principalmente quando tentamos conectar numa VPN PPTP (Point-to-Point Tunneling Protocol). Na versão anterior do Ubuntu, eu conseguia conectar em VPNs PPTP sem problemas, coisa que deixou de acontecer após a instalação da última versão do Ubuntu.</p>
<p>A boa notícia é que, depois de perder algumas horas pesquisando, eu consegui resolver o meu problema. E é isso que mostrarei a seguir! <span id="more-304"></span></p>
<h3>Atualizando o Network Manager</h3>
<p>A primeira coisa que fiz foi tentar substituir a versão pré-instalada do Network Manager pela <a href="http://launchpad.net/network-manager">versão distribuída</a> pelos próprios desenvolvedores.</p>
<p>Para isso, abra o Synaptic e selecione o menu <em>Settings &#8211; Repositories</em>. Em seguida, selecione a aba <em>Third-Party Software</em> e clique no botão <em>Add</em>. Finalmente, cole a linha abaixo e confirme:</p>
<pre>deb http://ppa.launchpad.net/network-manager/ubuntu intrepid main</pre>
<p>Feche a tela e pressione CTRL+R para baixar as informações atualizadas dos repositórios. Após o término, pressione CTRL+G para iniciar o processo de atualização dos pacotes. Quando a instalação terminar, o Ubuntu irá pedir que você faça o reboot. Obedeça. <img src='http://weblog.destaquenet.com/wp-includes/images/smilies/icon_smile.gif' alt=':)' class='wp-smiley' /> </p>
<h3>Configurando a VPN</h3>
<p>Após o reboot, o sistema já deve estar funcionando com a nova versão do Network Manager. Clique no Applet do Network Manager e selecione o menu <em>VPN Connections &#8211; Configure VPN</em>. Aqui, basta configurar de acordo com as instruções que você deve ter recebido do pessoal responsável pela parte de redes da sua empresa.</p>
<p>Para não terminar o post aqui, eu vou mostrar como eu fiz para configurar a conexão VPN que estou utilizando atualmente. É obvio que cada empresa configura sua VPN de um jeito diferente, por isso o que segue abaixo é apenas um exemplo de configuração.</p>
<h4>Informações básicas</h4>
<p>Na primeira tela você deve informar os dados para conexão com a VPN, como IP do servidor da VPN, usuário e senha:</p>
<div id="attachment_308" class="wp-caption aligncenter" style="width: 230px"><a href="http://weblog.destaquenet.com/wp-content/uploads/2008/12/vpn01.png"><img class="size-medium wp-image-308" title="Informações básicas da VPN" src="http://weblog.destaquenet.com/wp-content/uploads/2008/12/vpn01-220x300.png" alt="Informações básicas" width="220" height="300" /></a><p class="wp-caption-text">Informações básicas</p></div>
<p>Clique no botão <em>Advanced</em> para configurar em detalhes como deverá ser a comunicação entre seu computador e a VPN:</p>
<div id="attachment_309" class="wp-caption aligncenter" style="width: 239px"><a href="http://weblog.destaquenet.com/wp-content/uploads/2008/12/vpn02.png"><img class="size-medium wp-image-309" title="Opções avançadas" src="http://weblog.destaquenet.com/wp-content/uploads/2008/12/vpn02-229x300.png" alt="Opções avançadas" width="229" height="300" /></a><p class="wp-caption-text">Opções avançadas</p></div>
<p>No meu caso, o servidor da VPN foi configurado para fazer autenticação via CHAP; marque ou desmarque as opções disponíveis na tela, se necessário.</p>
<h4>Configurando as rotas</h4>
<p>Prosseguindo, na aba <em>IPv4 Settings</em> você poderá configurar o seu IP na VPN. No meu caso, o IP local, juntamente com o servidor DNS e Gateway, são fornecidos automaticamente pelo servidor. Por isso eu optei por manter a opção <em>Automatic (VPN)</em> no campo <em>Method</em>.</p>
<p>Neste ponto você já deve ter a VPN funcionando, mas com um pequeno inconveniente: pelo menos aqui, a VPN passou a ser acessível através da rota padrão (IP 0.0.0.0). Isso significa que <strong>todo</strong> o tráfego é direcionado para a VPN!</p>
<p>Para solucionar esta questão, é preciso configurar uma rota através da qual a VPN possa ser acessada, mantendo inalterada a rota padrão. Para isso, basta clicar no botão <em>Routes&#8230;</em> e configurar a(s) rota(s):</p>
<div id="attachment_316" class="wp-caption aligncenter" style="width: 310px"><a href="http://weblog.destaquenet.com/wp-content/uploads/2008/12/vpn03.png"><img class="size-medium wp-image-316" title="Declarando rotas" src="http://weblog.destaquenet.com/wp-content/uploads/2008/12/vpn03-300x166.png" alt="Declarando rotas" width="300" height="166" /></a><p class="wp-caption-text">Declarando rotas</p></div>
<p>Aqui, eu substituí as rotas obtidas automaticamente pelas rotas informadas na tabela. No meu caso, a faixa de IP da VPN é 192.168.0.X, por isso o <em>Prefix</em> foi configurado como 24 (<a href="http://linux-ip.net/html/routing-intro.html">aprenda aqui</a> o que esse número significa). O campo <em>Gateway</em> foi configurado para o &#8220;IP remoto virtual&#8221; da VPN, fazendo com que os pacotes destinados a IPs 192.168.0.X sejam redirecionados para a VPN. O campo <em>Metric</em> foi <a href="http://linux.about.com/od/lna_guide/a/gdelna23t04.htm">deixado como zero</a>.</p>
<h3>Feito!</h3>
<p>Isso deve bastar. Tente conectar com a VPN:</p>
<div id="attachment_313" class="wp-caption aligncenter" style="width: 310px"><a href="http://weblog.destaquenet.com/wp-content/uploads/2008/12/vpn04.png"><img class="size-medium wp-image-313" title="Conectando na VPN" src="http://weblog.destaquenet.com/wp-content/uploads/2008/12/vpn04-300x150.png" alt="Conectando na VPN" width="300" height="150" /></a><p class="wp-caption-text">Conectando na VPN</p></div>
<p>Não conectou? Confira os dados de conexão e modifique os parâmetros avançados de conexão (métodos de autentiação, encriptação, etc). Tente encontrar o motivo nos logs <code>/var/log/messages</code> e <code>/var/log/syslog</code>. Conectou? Ótimo, agora faça o seguinte teste:</p>
<ol>
<li>Dispare um ping contra algum computador da VPN;</li>
<li>Dispare um ping contra algum computador da sua rede local;</li>
<li>Dispare um ping contra algum computador da Internet (ex: google.com);</li>
</ol>
<p>O teste falhou? Com certeza tem algo errado com a(s) sua(s) rota(s). Ainda conectado na VPN, utilize os comandos <code>ip route</code> e/ou <code>route -n</code> para ver como ficaram as rotas; faça os ajustes necessários, reze e tente novamente. O teste foi um sucesso? Parabéns, você conseguiu! <img src='http://weblog.destaquenet.com/wp-includes/images/smilies/icon_smile.gif' alt=':)' class='wp-smiley' /> </p>
<p><strong>Update</strong>: Aos usuários do Fedora 10, o procedimento de configuração é praticamente o mesmo. O que muda é a configuração das rotas:</p>
<p style="text-align: center;">
<div id="attachment_343" class="wp-caption aligncenter" style="width: 310px"><img class="size-medium wp-image-343" title="rotas_fedora10" src="http://weblog.destaquenet.com/wp-content/uploads/2008/12/rotas_fedora10-300x182.png" alt="Declarando as rotas (Fedora 10)" width="300" height="182" /><p class="wp-caption-text">Declarando rotas (Fedora 10)</p></div>
]]></content:encoded>
			<wfw:commentRss>http://weblog.destaquenet.com/2008/12/02/vpn-pptp-no-ubuntu-intrepid/feed/</wfw:commentRss>
		<slash:comments>3</slash:comments>
		</item>
		<item>
		<title>Integração Contínua de aplicações Python com Hudson</title>
		<link>http://weblog.destaquenet.com/2008/10/27/integracao-continua-de-aplicacoes-python-com-hudson/</link>
		<comments>http://weblog.destaquenet.com/2008/10/27/integracao-continua-de-aplicacoes-python-com-hudson/#comments</comments>
		<pubDate>Mon, 27 Oct 2008 12:00:24 +0000</pubDate>
		<dc:creator>Daniel Martins</dc:creator>
				<category><![CDATA[Português]]></category>
		<category><![CDATA[Programação]]></category>
		<category><![CDATA[Tutoriais]]></category>
		<category><![CDATA[build]]></category>
		<category><![CDATA[configuração]]></category>
		<category><![CDATA[hudson]]></category>
		<category><![CDATA[integração contínua]]></category>
		<category><![CDATA[java]]></category>
		<category><![CDATA[open source]]></category>
		<category><![CDATA[plugin]]></category>
		<category><![CDATA[projeto]]></category>
		<category><![CDATA[python]]></category>
		<category><![CDATA[testes]]></category>
		<category><![CDATA[tutorial]]></category>
		<category><![CDATA[unittest]]></category>

		<guid isPermaLink="false">http://weblog.destaquenet.com/?p=166</guid>
		<description><![CDATA[No começo deste mês eu dei dicas sobre como usar o Fabric para automatizar o build e o deployment de aplicações Python. Essa automatização por si só já quebra uma árvore, mas ela possibilita ainda o uso de Integração Contínua, &#8230; <a href="http://weblog.destaquenet.com/2008/10/27/integracao-continua-de-aplicacoes-python-com-hudson/">Continue lendo <span class="meta-nav">&#8594;</span></a>]]></description>
			<content:encoded><![CDATA[<p>No começo deste mês <a href="http://weblog.destaquenet.com/2008/10/05/deployment-de-aplicacoes-python-com-fabric/">eu dei dicas</a> sobre como usar o <a href="http://www.nongnu.org/fab/">Fabric</a> para automatizar o <em>build</em> e o <em>deployment</em> de aplicações <a href="http://python.org/">Python</a>.</p>
<p>Essa automatização por si só já quebra uma árvore, mas ela possibilita ainda o uso de Integração Contínua, uma prática extremamente importante que costuma ajudar muitas equipes a manter seus projetos nos trilhos. Para mais informações sobre Integração Contínua, eu recomendo a leitura <a href="http://martinfowler.com/articles/continuousIntegration.html">deste artigo</a>, até porque este <em>post</em> terá um enfoque mais prático.</p>
<p>Neste texto será mostrado como configurar um projeto Python no <a href="http://hudson.dev.java.net/">Hudson</a>, um servidor de Integração Contínua muito simples de configurar e utilizar. O sistema de controle de versões que eu utilizo aqui é o <a href="http://git.or.cz/">Git</a>, mas usuários de outros sistemas também poderão achar este texto útil.<span id="more-166"></span></p>
<h3>Baixando o Hudson</h3>
<p>Acesse o site do <a href="http://hudson.dev.java.net/">Hudson</a> e baixe o arquivo <code>.war</code> através do link disponível na página principal. Quando o download terminar, basta rodar o comando abaixo para subir o servidor na porta <code>8080</code>:</p>

<div class="wp_syntax"><div class="code"><pre class="bash" style="font-family:monospace;">java <span style="color: #660033;">-jar</span> hudson.war</pre></div></div>

<div id="attachment_185" class="wp-caption aligncenter" style="width: 310px"><a href="http://weblog.destaquenet.com/wp-content/uploads/2008/10/hudson01.png"><img src="http://weblog.destaquenet.com/wp-content/uploads/2008/10/hudson01-300x187.png" alt="Tela inicial do Hudson" title="Tela inicial do Hudson" width="300" height="187" class="size-medium wp-image-185" /></a><p class="wp-caption-text">Tela inicial do Hudson</p></div>
<p>Perca uns cinco minutos dando uma navegada no Hudson para ter uma idéia melhor do que é possível de ser feito com ele.</p>
<h3>Hudson e plugins</h3>
<p>O Hudson vem com suporte a <a href="http://maven.apache.org/">Maven</a> e <a href="http://ant.apache.org/">Ant</a>, duas das mais populares ferramentas para <em>build</em> de aplicações Java. Mas não se engane: o Hudson pode ser aproveitado em praticamente qualquer projeto, independente da linguagem e dos <em>frameworks</em> utilizados.</p>
<p>As funcionalidades do Hudson podem ser estendidas através de <em>plugins</em>, sendo que neste artigo utilizaremos dois deles: o <em>Git Plugin</em>, necessário para que o Hudson consiga trabalhar com repositórios Git, e o <em>Violations</em>, que consegue interpretar a saída de diferentes verificadores de código (dentre eles o <a href="http://www.logilab.org/857">pylint</a>, um analisador de código Python!) e exibir informações a respeito da qualidade do código-fonte.</p>
<p>Para instalar esses plugins, basta acessar a tela de gerenciamento de plugins, marcar o <em>Git Plugin</em> e o <em>Violations</em>, e confirmar:</p>
<div id="attachment_186" class="wp-caption aligncenter" style="width: 310px"><a href="http://weblog.destaquenet.com/wp-content/uploads/2008/10/hudson02.png"><img src="http://weblog.destaquenet.com/wp-content/uploads/2008/10/hudson02-300x187.png" alt="Instalando os plugins" title="Instalando os plugins" width="300" height="187" class="size-medium wp-image-186" /></a><p class="wp-caption-text">Instalando os plugins</p></div>
<p>Assim que a instalação terminar, reinicie o Hudson.</p>
<h3>Integrando testes escritos com PyUnit ao Hudson</h3>
<p>Apesar de existirem várias opções para criação e execução de testes unitários para Python, o <a href="http://pyunit.sourceforge.net/">PyUnit</a> costuma ser o mais usado pelo fato de já estar incluído na distribuição padrão do Python.</p>
<p>Quem já fuçou no código do PyUnit sabe que ele define <strong>apenas um</strong> <code>TestRunner</code>, o <a href="http://pyunit.sourceforge.net/pyunit.html#RUNNING_INT"><code>TextTestRunner</code></a>. O que este <code>TestRunner</code> basicamente faz é gerar em um fluxo qualquer (geralmente no <code>sys.stderr</code>) uma saída parecida com a seguinte:</p>
<pre>.....
----------------------------------------------------------------------
Ran 5 tests in 0.067s</pre>
<p>Apesar de eu me contentar com essa saída mais simples, bom, ferramentas como o próprio Hudson <strong>não se contentam</strong>; elas preferem algo como o bom e velho XML, que, convenhamos, é muito mais fácil de parsear.</p>
<p>Perdi algumas horas na Internet procurando por um <code>TestRunner</code> que conseguisse gerar arquivos XML no mesmo formato que os gerados pelo Ant e Maven, mas não encontrei nenhuma opção que fosse minimamente confiável. Por isso, eu tomei a liberdade de escrever meu próprio <code>TestRunner</code>: <a href="http://github.com/danielfm/unittest-xml-reporting/tree">XMLTestRunner</a>. O código deste &#8220;projeto&#8221;, disponibilizado no <a href="http://github.com/">Github</a>, contém instruções de uso e scripts de exemplo. <strong>Clonem e forkem à vontade!</strong></p>
<p>Antes de prosseguirmos, baixe o módulo <code>xmlrunner.py</code> do <a href="http://github.com/danielfm/unittest-xml-reporting/tree">site do projeto</a> e o copie em algum lugar dentro do seu <code>PYTHONPATH</code>.</p>
<h3>Integrando um projeto Python no Hudson</h3>
<p>Para não perdermos tempo criando do zero um projeto de exemplo em Python, eu mostrarei como fazer para integrar o próprio <code>XMLTestRunner</code> com o Hudson.</p>
<p>Abra o console administrativo do Hudson e clique no link <em>New Job</em>:</p>
<div id="attachment_214" class="wp-caption aligncenter" style="width: 310px"><a href="http://weblog.destaquenet.com/wp-content/uploads/2008/10/hudson03.png"><img src="http://weblog.destaquenet.com/wp-content/uploads/2008/10/hudson03-300x172.png" alt="Criando um projeto &quot;free-style&quot;" title="Criando um projeto &quot;free-style&quot;" width="300" height="172" class="size-medium wp-image-214" /></a><p class="wp-caption-text">Criando um projeto &quot;free-style&quot;</p></div>
<p>Na próxima tela, precisamos configurar o Job com os dados necessários:</p>
<div id="attachment_215" class="wp-caption aligncenter" style="width: 310px"><a href="http://weblog.destaquenet.com/wp-content/uploads/2008/10/hudson04.png"><img src="http://weblog.destaquenet.com/wp-content/uploads/2008/10/hudson04-300x172.png" alt="Configuração de projeto" title="Configuração de projeto" width="300" height="172" class="size-medium wp-image-215" /></a><p class="wp-caption-text">Configuração de projeto</p></div>
<div id="attachment_216" class="wp-caption aligncenter" style="width: 310px"><a href="http://weblog.destaquenet.com/wp-content/uploads/2008/10/hudson05.png"><img src="http://weblog.destaquenet.com/wp-content/uploads/2008/10/hudson05-300x172.png" alt="Configuração de projeto" title="Configuração de projeto" width="300" height="172" class="size-medium wp-image-216" /></a><p class="wp-caption-text">Configuração de projeto</p></div>
<p>Isso é tudo! Confirme as alterações e clique no link <em>Build now</em>. Aguarde alguns segundos enquanto o projeto é baixado do repositório Git e testado:</p>
<div id="attachment_220" class="wp-caption aligncenter" style="width: 310px"><a href="http://weblog.destaquenet.com/wp-content/uploads/2008/10/hudson06.png"><img src="http://weblog.destaquenet.com/wp-content/uploads/2008/10/hudson06-300x172.png" alt="Exemplos de builds feitos pelo Hudson" title="Exemplos de builds feitos pelo Hudson" width="300" height="172" class="size-medium wp-image-220" /></a><p class="wp-caption-text">Exemplos de builds feitos pelo Hudson</p></div>
<div id="attachment_238" class="wp-caption aligncenter" style="width: 310px"><a href="http://weblog.destaquenet.com/wp-content/uploads/2008/10/hudson07.png"><img src="http://weblog.destaquenet.com/wp-content/uploads/2008/10/hudson07-300x172.png" alt="Relatório de execução de testes" title="Relatório de execução de testes" width="300" height="172" class="size-medium wp-image-238" /></a><p class="wp-caption-text">Relatório de execução de testes</p></div>
<div id="attachment_239" class="wp-caption aligncenter" style="width: 310px"><a href="http://weblog.destaquenet.com/wp-content/uploads/2008/10/hudson08.png"><img src="http://weblog.destaquenet.com/wp-content/uploads/2008/10/hudson08-300x172.png" alt="Análise de código feita pelo pylint" title="Análise de código feita pelo pylint" width="300" height="172" class="size-medium wp-image-239" /></a><p class="wp-caption-text">Análise de código feita pelo pylint</p></div>
<h3>Como disparar o <em>build</em> de forma automática?</h3>
<p>Uma vez que o projeto tenha sido configurado corretamente, basta um clique do mouse para que o Hudson faça todo o trabalho sujo. O problema agora é lembrar de fazer o <em>build</em> sempre que alguém modificar código no repositório.</p>
<p>Felizmente, temos duas opções para nos livrar de mais essa tarefa manual: a primeira seria configurar, nas propriedades do Job, uma expressão Cron que indique de quanto em quanto tempo o <em>build</em> deve ser feito; a segunda alternativa é apenas disparar o <em>build</em> quando alguém modificar código no repositório.</p>
<p>Como acontece com outros sistemas de controle de revisão, o Git possui <em>hooks</em> que nos permite executar ações em determinados momentos. Esses <em>hooks</em> nada mais são do que scripts executáveis localizados no diretório <code>.git/hooks</code>.</p>
<p>Mas enfim, quando disparar o <em>build</em>? Se o repositório Git e o servidor Hudson não são capazes de se comunicar diretamente, talvez a única alternativa seja disparar o <em>build</em> periodicamente. Para isso, você deve configurar um ou mais <em>Build Triggers</em>, na tela de configuração do Job.</p>
<p>Entretanto,  se você mantém o repositório Git e o servidor Hudson na mesma máquina, ou mesmo em máquinas diferentes mas capazes de se comunicar via rede, podemos considerar a utilização dos <em>hooks</em> como ferramenta de integração entre o repositório Git e o Hudson.</p>
<p>Agora a pergunta que não quer calar: <strong>como integrar o Git e o Hudson?</strong> Bem, isso ficará como exercício para o leitor.</p>
<p>Dicas:</p>
<ul>
<li>O Hudson <a href="http://hudson.gotdns.com/wiki/display/HUDSON/Remote+access+API">disponibiliza uma API</a> através da qual se pode agendar <em>builds</em>, alterar as configurações do Job, criar Jobs, entre outras coisas.</li>
<li>Para conhecer os <em>hooks</em> oferecidos pelo Git, consulte a <a href="http://www.kernel.org/pub/software/scm/git/docs/githooks.html">documentação</a>.</li>
</ul>
<h3>Conclusão</h3>
<p>Já faz algum tempo que eu venho utilizando o Hudson para integrar projetos Java, e esta ferramenta vem se mostrando muito útil no meu dia-a-dia. Só quem pratica Integração Contínua sabe o quanto é complicado não contar com a segurança que ela proporciona ao desenvolvimento.</p>
<p>O problema, no entanto, começou quando eu optei pelo Python em vez do Java em certos projetos. Obviamente, eu queria aproveitar o ambiente de Integração Contínua que eu já utilizava, o que foi bastante complicado já que o PyUnit, <em>framework</em> de testes que eu costumo utilizar, não oferece uma forma de gerar relatórios XML, da mesma forma que Ant e Maven fazem.</p>
<p>Depois de estudar o funcionamento interno do PyUnit, eu decidi implementar um <code>TestRunner</code> que fosse capaz de gerar arquivos XML no formato esperado pelo Hudson. Deu um bocado de trabalho, é verdade, mas pelo menos agora eu consigo utilizar os excelentes relatórios gerados pelo Hudson para acompanhar a execução dos meus testes PyUnit.</p>
<p>Como o Brasil é grande, seria burrice achar que eu fui o único a enfrentar esse tipo de dificuldade. Por esse motivo, eu resolvi escrever este texto e, quem sabe, ajudar àqueles que enfrentam um problema semelhante.</p>
]]></content:encoded>
			<wfw:commentRss>http://weblog.destaquenet.com/2008/10/27/integracao-continua-de-aplicacoes-python-com-hudson/feed/</wfw:commentRss>
		<slash:comments>11</slash:comments>
		</item>
	</channel>
</rss>

