Publicaciones sobre linux

2012-08-07 16:17

El Server Mínimo

Fuí sysadmin bastatnte tiempo. Lo hacía para vivir así que no tenía muchas ganas de hacer lo mismo en mi tiempo libre, lo que llevó a un caso fuerte de cuchillos de palo en casa de herrero.

Entonces hoy en la hora del almuerzo me puse a limpiar la basura. Este post describe con qué terminé, que es el server mínimo que me sirve para algo.

Hosting

Es un VPS barato provisto por los amigos de burst.net que no me pagan para decir cosas buenas de su servicio. Sin embargo, las digo igual:

  • Muy barato (U$S 5.50 pero tengo 20% de descuento para siempre)
  • Bastante transferencia cada mes
  • Mucho espacio
  • Buen uptime
  • Red rápida
  • Muy barato
  • Performance decente
  • Barato

Distribución

Ya tenía CentOS 5, y sigue ahí. Si burst alguna vez ofrece Ubuntu Precise, capaz que cambio. O, ya que esto anda, capaz que no.

Lo bueno de CentOS: estable y aburrido.

Lo malo de CentOS: es un poco demasiado aburrido. Montones de cosas simplemente no están empaquetadas.

Web Server

Tengo que servir una cantidad de dominios, pero con una peculiaridad: son todos sitios estáticos. Lo que quiero es:

  • Bajo uso de recursos
  • Performance decente (con rangos y negociación de contenidos)
  • Estable
  • Con índices de directorio
  • Fácil de configurar
  • Dominios virtuales por nombre

Casi cualquier servidor anda para esto. Hasta Apache, excepto por eso de la configuración sencilla. Terminé con gatling porque cumple esos criterios bastante bien.

  • Usa alrededor de 1.4MB de RAM que está bueno en un VPS.
  • Es bastante rápido
  • Lleva horas sin caerse
  • Genera índices
  • Esta es la configuración: "-c /srv/www -P 2M -d -v -p 80 -F -S" (no, no hay archivo de configuración)
  • Los dominios virtuales son carpetas y symlinks adentro de /srv/www que es lo más fácil posible.
  • Soporta proxy inverso para cuando quiero probar una webapp python en la que estoy trabajando.

Mail Server

No quiero un mail server. Tengo gmail y un server de verdad para eso. Lo que quiero son los mails de cron. Para eso usé ssmtp y una cuenta extra de gmail. Funciona, y esta es toda la configuración:

[email protected]
mailhub=smtp.gmail.com:587
UseTLS=YES
UseSTARTTLS=YES
AuthMethod=LOGIN
[email protected]
AuthPass=notputtingthetrueoneheredude

Lo mejor que puedo decir es que funciona, y no involucra correr un server.

Misc

Para cuando tengo que estar en dos lugares al mismo tiempo: OpenVPN es lo más, y no se aceptan discusiones. Tengo un squid corriendo a veces, y hay un Quassel core para IRC. Instalé mosh para que el ssh sea menos doloroso, rsync hace deployments y guarda backups, cron ejecuta cosas, y nada más.

Status

Montones de RAM y CPU libres (sí, esa es la lista completa de procesos):

[[email protected] ~]# ps aux
USER       PID %CPU %MEM    VSZ   RSS TTY      STAT START   TIME COMMAND
root         1  0.0  0.1   2156   664 ?        Ss   22:01   0:00 init [3]
root      1135  0.0  0.1   2260   576 ?        S<s  22:01   0:00 /sbin/udevd -d
root      1518  0.0  0.1   1812   572 ?        Ss   22:01   0:00 syslogd -m 0
root      1594  0.0  0.1   7240  1032 ?        Ss   22:01   0:00 /usr/sbin/sshd
root      1602  0.0  0.2   4492  1112 ?        Ss   22:01   0:00 crond
root      1630  0.0  0.1   5684   716 ?        Ss   22:01   0:00 /usr/sbin/saslauthd -m /var/run/saslauthd -a pam -n 2
root      1631  0.0  0.0   5684   444 ?        S    22:01   0:00 /usr/sbin/saslauthd -m /var/run/saslauthd -a pam -n 2
root      1636  0.0  0.2   3852  1372 ?        S    22:01   0:01 /opt/diet/bin/gatling -c /srv/www -P 2M -d -v -p 80 -F -S
root      1677  0.0  0.2   4284  1232 ?        Ss   22:02   0:00 SCREEN /root/quasselcore-static-0.7.1
root      1678  0.0  2.1  36688 11148 pts/0    Ssl+ 22:02   0:03 /root/quasselcore-static-0.7.1
root      3228  1.0  0.7  12916  4196 ?        Ss   23:28   0:13 mosh-server new -s -c 8
root      3229  0.0  0.3   3848  1588 pts/2    Ss   23:28   0:00 -bash
root      3275  0.0  0.1   2532   908 pts/2    R+   23:48   0:00 ps aux
[[email protected] ~]# w
 23:49:03 up  1:47,  1 user,  load average: 0.00, 0.01, 0.00
USER     TTY      FROM              [email protected]   IDLE   JCPU   PCPU WHAT
root     pts/2    186.153.52.253   23:28    0.00s  0.01s  0.00s w
[[email protected] ~]# free
             total       used       free     shared    buffers     cached
Mem:        524800      49100     475700          0          0          0
-/+ buffers/cache:      49100     475700
Swap:            0          0          0

Teniendo en cuenta todo, bastante contento con el resultado.

2012-03-13 02:17

APIs de Ubuntu One en Ejemplos (parte 1)

Una de las cosas lindas de trabajar en Canonical es que producimos software open source. Yo, específicamente, trabajo en el equipo que hace los clientes de escritorio de Ubuntu One que es un trabajo muy copado, y un software muy copado también. Sin embargo, una cosa que no se sabe lo suficiente es que tenemos unas excelentes APIs para terceros. Las necesitamos, ya que es lo que usamos nosotros!

Así que acá va un pequeño tutorial acerca de como usar algunas de esas APIs. Lo hice usando Python y PyQt por varios motivos:

  • Son excelentes herramientas para prototipos
  • Tienen excelente soporte para las cosas que necesito (DBus, HTTP, OAuth)
  • Es lo que sé y me gusta. Lo hice un domingo, no lo pienso hacer en PHP y Gtk.

Dicho eso, no hay nada específico de python o de Qt en este código. Donde hago un request HTTP usando QtNetwork, podés usar libsoup o lo que fuere.

Vayamos a los bifes entonces. Las piezas más importantes de Ubuntu One, desde el punto de vista de infraestructura, son Ubuntu SSO Client, que se encarga de login, registración, etc, y SyncDaemos que maneja la sincronización de archivos.

Para interactuar con ellas, en Linux, ofrecen interfaces DBus. Así que, por ejemplo, este es un fragmento mostrando como obtener las credenciales de Ubuntu One (esto normalmente sería parte del __init__ de un objeto):

# Get the session bus
bus = dbus.SessionBus()

:
:
:

# Get the credentials proxy and interface
self.creds_proxy = bus.get_object("com.ubuntuone.Credentials",
                        "/credentials",
                        follow_name_owner_changes=True)

# Connect to signals so you get a call when something
# credential-related happens
self.creds_iface = dbus.Interface(self.creds_proxy,
    "com.ubuntuone.CredentialsManagement")
self.creds_proxy.connect_to_signal('CredentialsFound',
    self.creds_found)
self.creds_proxy.connect_to_signal('CredentialsNotFound',
    self.creds_not_found)
self.creds_proxy.connect_to_signal('CredentialsError',
    self.creds_error)

# Call for credentials
self._credentials = None
self.get_credentials()

Tal vez notaste que get_credentials no devuelve las credenciales. Lo que hace es, le dice a SyncDaemon que las obtenga, y entonces, si/cuando aparecen, se emite una de esas señales, y uno de los métodos conectados se llama. Esto está bueno porque no tenemos que preocuparnos de que se nos bloquee la aplicación mientras SyncDaemon está buscando las credenciales.

¿Y qué hay en esos métodos? ¡No mucho!

def get_credentials(self):
    # Do we have them already? If not, get'em
    if not self._credentials:
        self.creds_proxy.find_credentials()
    # Return what we've got, could be None
    return self._credentials

def creds_found(self, data):
    # Received credentials, save them.
    print "creds_found", data
    self._credentials = data
    # Don't worry about get_quota yet ;-)
    if not self._quota_info:
        self.get_quota()

def creds_not_found(self, data):
    # No credentials, remove old ones.
    print "creds_not_found", data
    self._credentials = None

def creds_error(self, data):
    # No credentials, remove old ones.
    print "creds_error", data
    self._credentials = None

Así que básicamente, self._credentials contiene unas credenciales, o None. Felicitaciones, ya entramos a Ubuntu One.

¡Hagamos algo útil! ¿Que tal preguntar cuánto espacio libre hay en la cuenta? Para eso, no podemos usar las APIs locales, si no conectarnos a los servers, que son los que saben si estás excedido de quota o no.

El acceso se controla via OAuth, por lo que para acceder a esa API necesitamos firmar nuestros pedidos. Aquí se ve como se hace. No es particularmente iluminador, yo no lo escribí, solamente lo uso:

def sign_uri(self, uri, parameters=None):
    # Without credentials, return unsigned URL
    if not self._credentials:
        return uri
    if isinstance(uri, unicode):
        uri = bytes(iri2uri(uri))
    print "uri:", uri
    method = "GET"
    credentials = self._credentials
    consumer = oauth.OAuthConsumer(credentials["consumer_key"],
                                   credentials["consumer_secret"])
    token = oauth.OAuthToken(credentials["token"],
                             credentials["token_secret"])
    if not parameters:
        _, _, _, _, query, _ = urlparse(uri)
        parameters = dict(cgi.parse_qsl(query))
    request = oauth.OAuthRequest.from_consumer_and_token(
                                        http_url=uri,
                                        http_method=method,
                                        parameters=parameters,
                                        oauth_consumer=consumer,
                                        token=token)
    sig_method = oauth.OAuthSignatureMethod_HMAC_SHA1()
    request.sign_request(sig_method, consumer, token)
    print "SIGNED:", repr(request.to_url())
    return request.to_url()

¿Y cómo pedimos el estado de quota? Accediendo al punto de entrada https://one.ubuntu.com/api/quota/ con la autorización adecuada, se obtiene un diccionario JSON con el espacio total y el usado. Acá hay una muestra de como hacerlo:

    # This is on __init__
    self.nam = QtNetwork.QNetworkAccessManager(self,
        finished=self.reply_finished)

:
:
:

def get_quota(self):
    """Launch quota info request."""
    uri = self.sign_uri(QUOTA_API)
    url = QtCore.QUrl()
    url.setEncodedUrl(uri)
    self.nam.get(QtNetwork.QNetworkRequest(url))

De nuevo: get_quota no devuelve la quota. Sólo lanza un pedido HTTP a los servers de Ubuntu One, que (eventualmente) responden con los datos. No querés que tu app se quede ahí trabada mientras tanto, por eso QNetworkAccessManager va a llamar a self.reply_finished cuando tenga la respuesta:

def reply_finished(self, reply):
    if unicode(reply.url().path()) == u'/api/quota/':
        # Handle quota responses
        self._quota_info = json.loads(unicode(reply.readAll()))
        print "Got quota: ", self._quota_info
        # Again, don't worry about update_menu yet ;-)
        self.update_menu()

¿Qué más queremos? ¿Qué tal notificación cuando cambia el status de SyncDaemon? Por ejemplo, cuando la sincronización está al día, o cuando te desconecta. De nuevo, esas son señales DBus a las que uno se conecta en __init__:

self.status_proxy = bus.get_object(
    'com.ubuntuone.SyncDaemon', '/status')
self.status_iface = dbus.Interface(self.status_proxy,
    dbus_interface='com.ubuntuone.SyncDaemon.Status')
self.status_iface.connect_to_signal(
    'StatusChanged', self.status_changed)

# Get the status as of right now
self._last_status = self.process_status(
    self.status_proxy.current_status())

Y esta es status_changed:

def status_changed(self, status):
    print "New status:", status
    self._last_status = self.process_status(status)
    self.update_menu()

la función process_status is código aburrido para convertir la info de status de syncdaemon en una cosa legible como "Sync is up-to-date", así que guardamos eso en self._last_status y actualizamos el menú.

¿Qué menú? ¡Un menú contextual de un QSystemTrayIcon! Lo que leyeron son las piezas principales que se necesitan para crear algo útil: una aplicación de SystemTray para Ubuntu One que se puede usar en KDE, XFCE u Openbox. O, si estás en unity y tenés sni-qt instalado, un app indicator.

http://ubuntuone.com/7iXTbysoMM9PIUS9Ai4TNn

El indicador en acción.

El código fuente del ejemplo completo está en mi proyecto u1-toys en launchpad y éste es el código fuente completo (excepto los iconos, bajense el repo, mejor)

Viniendo pronto (espero), más apps de ejemplo, y cosas copadas que se pueden hacer con nuestras APIs.

2012-02-02 22:00

$HOME is where .bashrc is

Tengo una confesión. El último año, mi sistema operativo principal fue Windows 7.Sí, ya sé es terrible, sobre todo si leíste esto que es probablemente mi post mas popular en 11 años.

¿Cómo pasó esto? ¿Qué me pasó? ¿Qué estaba pensando? Es una historia aburrida y poco interesante.

Entré a trabajar a Canonical. A mi notebook vieja no le daba el cuero. La nueva no quería que le instalara Ubuntu. Dije "ma sí, me voy a vivir a una VM". La VM era más lenta que el Checho Batista. Tenía que desarrollar cosas en Windows (sí). Algunas cosas no funcionaban bien en la VM. Y de a poquito, las cosas y los archivos se juntaban en windows, en el hardware real, Windows 7 Home Premium.

En general, Windows 7 es no horrible. La mayoría de las cosas andan. Lo que sí, para un programador, es cultivar en el desierto. Podés hacer que crezcan cosas, pero hay que ponerle muchas ganas.

Así que hoy instalé Kubuntu Oneiric (¡ningún problema!), junté todos los datos de la notebook vieja, de la Vm, de windows, borré windows, y me mudé a Linux, y ahora Windows es la VM.

Extrañaba.

2010-04-10 14:51

Android

Dado que espero que Android en tablets sea una cosa importante en el 2010, estoy experimentando con lo más parecido que puedo conseguir: Android en my eee 701 Surf 4G:

SDC14690

Conswguí la imagen de testing de Android 2.0 de http://android-x86.org. Probé la "estable" 1.6 "stable" pero... era horrible, la mitad de las teclas o opciones de menú hacían que se colgara, reiniciara o se prendiera fuego.

Entonces... ¿cómo va? ¡Lento, pero con potencial!

Lo malo:

  • Arranca rápido... pero mi Arch Linux arranca más rápido.

  • Es leeeeento, podés ver cada letra individaual cuando escribís en el coso de búsqueda. Leí que es temporal. Ojalá!

  • Estoy con una experiencia limitada en aplicaciones porque los "android stores" libres no están tan provistos como el "android marketplace" oficial (¿y porqué corno no puedo bajar apps gratis de ahí????)

    Veo agujeros obvios en el panorama de aplicaciones que supongo están bien cubiertos en el marketplace (como, ¿hay un reemplazo para RadioTray?)

    ¿No hay editor de texto?

    ¿No hay un procesador de texto semi-decente? ¿Ni siquiera uno que genere HTML?

  • El web browser es patético. Tal vez esté bien para un teléfono, pero ¿para un sistema "real"? Es horrible. Te da la versión móbil de todos los sitios (obvio) y muchos no te dejan pasar a la "real" (hasta google con el Google Reader), y por supuesto, no hay flash.

  • El cliente de correo es terrible. No podés no hacer top-posting!!!! "In-Reply-To" está roto!

  • Las opciones de WiFi están demasiado escondidas. Deberían poderse sacar del icono de wifi.

Lo bueno:

  • Se apaga muy rápido.
  • Algunas apps están buenas, especialmente el Aldiko book reader es buenísimo (y puedo compartir los ePub con el fbReader del lado de arch.
  • El cliemte SSH tiene buenas ideas.
  • Me gusta mucho el enfoque de "todas tus cosas están en el SD". Hago exactamente lo mismo en Linux. De hecho tengo exactamente la misma organización en los dos sistemas operativos.
  • La pantalla home con el cajón deslizante de aplicaciones: lindo
  • La barra de notificaciones "agarrable": muy lindo
  • Lo de "apretá la tecla menú para ver el menú"? Genio ;-)
  • Lo de "todo fullscreen todo el tiempo"? Funciona en esta pantalla.
  • La instalación de aplicaciones es un problema solucionado.
  • Sé que voy a tener Qt nativo y no puedo esperar!

Todavía no estoy convenciso, Arch es mucho más rápido por ahora, y hace muchas más cosas pero...

  • Me encargué una pantalla táctil para tener la experiencia como se supone que hay que tenerla.
  • Lo uso mucho para leer de noche en la cama (Recién terminé Makers, léanlo, está bueno!).
  • Lo estoy usando para leer correo de vez en cuando (me niego a responder con esa porquería)
  • Es un despertador bastabte bueno, así que ahora es mi sistema operativo de mesa de luz.

Voy a escribir otro reporte una vez que tenga la pantalla táctil y/o una versión nueva (y ojalá que más rápida).

2010-03-24 17:27

The day we saw the dinosaur (an Ada Lovelace Day story)

Today, March 24th is Ada Lovelace day, a day of blogging to celebrate the achievements of women in technology and science.. I am taking the liberty to tag this as python so it appears in the right planets, but that's just to promote Ada Lovelace day. Sorry 'bout that.

I will write about the only person who ever taught me programming, Claudia. I was young, so the earth was still lukewarm, the day we saw the dinosaur.

I was just a green sophomore in the School of Chemical Engineering where, paradoxically I would never take a chemistry class, being an applied math student and all that, and at the time "personal computers" were a novelty, a toy of the upper middle class.

We had spent the first two months of the semester learning how to program the obvious way: writing assembler for a fictional machine on paper by hand, when Claudia broke the news, we were going to see a real computer.

No, not a PC, not even an XT, but a real computer, the one real computer in all the university, and you could hear the type switching to bold as she spoke about it. Sadly it was not as real as the one at the research facility (A MiniVAX!) but it was a real enough PDP.

We would not be allowed to actually use it until the following year, but ... well, it was still something special.

I had been programming for years, even for a year before I saw my first (seriosuly not real) computer, I had followed BASIC programs in my head for days, imagining the space invaders float on the screen of my mind, and stepped into writing machine code inside REM statements in my Timex Sinclair 1000 onto the luxury of a C64, but never noone had taught me anything.

Our small class (maybe 10 students) spent endless hours doing things like traverse a matrix, first by rows, thn by columns, then in a spiral from the top-left, writing programs that followed our endless source of algorithms, the numerical solutions guide.

First assembler, then Fortran, we learned.

She was my Mr. Miyagi, I was a heterosexual Ralph Macchio, and I figured out the most important thing about programming: I was awful at it.

Over the next 20 years that situation has been slowly improving, but I never again had someone teach me programming. Claudia had already taught me everything I needed to know, that code can always improve, that there's more than one way to skin a cat.

That the dinosaur was real and that some day soon my computer would be faster and nicer than the dinosaur was then, and that programming was cool, and that if I could find a way to draw a polynomial graph horizontally on a printer without ever having the whole graph in memory (it didn't fit), those future computers would do awesome things, and that I was one of the many who would help bring that to reality.

That talking about code was fun in itself, that you could make a modest living and be happy about it, that you could in any case make jigsaw puzzles in your spare time and keep on teaching or whatever.

And later the dinosaur's bones were scavenged into a line of racks holding routers, and its glass terminals are destroyed, and the gold in its teeth was stolen and the rare bus cables sold, and its circuits scrapped, but I saw the dinosaur alive, and Claudia taught me how to make it jump, and for that, I will always be grateful.

2010-02-12 22:25

Marave 0.5 publicado

Acabo de subir Marave 0.5 al lugar habitual. Marave es un editor de texto relajado, a pantalla completa, que trata de no distraerte.

¡Hasta incluye un pequeño reproductor musical para que no tengas que pensar en otra aplicación!

Esta versión tiene varios bugs arreglados, y se ve un poco más bonita.

El nuevo feature es... internacionalización. Por ahora sólo una traducción al castellano, pero si alguien quiere ayudar traduciéndolo a otro idioma, por favor, adelante!

Hay sólo unas 60 frases, por lo que no debería ser más de una hora de trabajo.

Aquí hay una captura de pantalla de esta versión:

.. raw:: html marave7

Marave es software libre bajo la GPLv2, y debería funcionar en cualquier plataforma donde funcione PyQt, lo que quiere decir Mac, Windows, y sistemas operativos tipo unix, por lo menos.

2010-02-11 14:00

Empaquetar es DIFÍCIL

Vengo trabajando muy duro en Marave, un editor a pantalla completa al estilo de ommwriter, DarkRoom, WriteRoom, pyRoom, etc. Vengo trabajando duro, y quiero que sea usado.

O ni siquiera eso, quiero que la gente tenga la oportunidad de usarlo.

Eso significa que quiero que funcione en Windows (y tal vez en OSX algún día, si alguien me da una mano). Lo que significa que tengo que hacer una versión para Windows.

hagamos una comparación rápida desde el punto de vista del usuario y del desarrollador.

El usuario, en Linux

Esto es en Arch Linux, que es lo que yo uso, en otras variantes es más o menos lo mismo una vez que Marave sea mas conocido.

yaourt -S marave-svn --noconfirm

Eso obtiene el código de SVN (por ahora es lo mejor, más adelante empaquetaré releases), todas las dependencias, y lo instala. Tarda unos 15 segundos en mi notebook.

Después de eso, tenés un Marave funcionando.

En caso de que no esté en tu distro, tenés que instalar PyQt (que seguro si está) y correr:

easy_install marave

El usuario, en windows

Vas a http://marave.googlecode.com, click en "Marave-0.5.win32.exe" (No lo busques, todavía no está) bajás un programa de 10MB. Eso es un programa de 10MB porque windows no cree en paquetes y en dependencias. En Linux un paquete de Marave sería 1MB (casi todo imágenes), y sería datos, no ejecutable.

Por supuesto hoy en día un browser no te ejecuta un programa que bajaste, asi que... hagamos una galería!

110111105613-My-Desktop

Sí, guardar.

11011111220-My-Desktop

Doble click para abrir.

11011111417-My-Desktop

Sí, estoy de acuerdo.

11011111514-My-Desktop

Hmmm, bueno.

1101111167-My-Desktop

Bárbaro...

11011111750-My-Desktop

Genial!

Ahora este Marave puede funcionar o no pero eso es para más adelante...

El desarrollador, en Linux

Primero, este es el mayor problema un "empaquetador" puede tener en Linux:

Como Marave es una aplicación nueva, y la desarrollo en Arch Linux que es medio cutting edge, usa features que sólo están en versiones nuevas de PyQt. De hecho no funciona con PyQt < 4.6, que no está en algunas distros "lentas" o en un Ubuntu que no es el último.

Solución? Bueno, podría ignorarlo, pero que tanto, vamos a arreglarlo!

Graias a PyInstaller ni siquiera es tan difícil, este es el archivo spec:

a = Analysis([os.path.join(HOMEPATH,'support/_mountzlib.py'), os.path.join(HOMEPATH,'support/useUnicode.py'), 'marave/main.py'],
            pathex=['/home/ralsina/trunk/trunk'])

pyz = PYZ(a.pure)
exe = EXE(pyz,
        a.scripts,
        exclude_binaries=1,
        name=os.path.join('build/pyi.linux2/main', 'marave.exe'),
        debug=False,
        strip=False,
        upx=True,
        console=0 )

coll = COLLECT( exe,
            a.binaries,
            [('radios.txt','marave/radios.txt','DATA')],
            Tree('marave/icons','icons'),
            Tree('marave/backgrounds','backgrounds'),
            Tree('marave/clicks','clicks'),
            Tree('marave/stylesheets','stylesheets'),
            Tree('marave/themes','themes'),
            a.zipfiles,
            a.datas,
            strip=False,
            upx=True,
            name=os.path.join('dist', 'marave'))

Usando esto, PyInstaller produce una linda carpeta llena de todo lo que Marave necesita para funcionar en cualquier Linux.

Por otro lado, si se puede contar con que haya un PyQt reciente disponible, también es fácil. Éste es el archivo de configuración para un paquete similar en Arch Linux (todavía no hice uno para Marave). Para otros Linux es más o menos lo mismo, y normalmente alguien te lo hace:

# Contributor: Roberto Alsina <[email protected]>
pkgname=python-rst2pdf
pkgver=0.12.1
pkgrel=4
pkgdesc="Create PDFs from simple text markup, no LaTeX required."
arch=('i686' 'x86_64')
url="http://rst2pdf.googlecode.com"
license=('custom')
depends=('python' 'setuptools' 'docutils' 'pygments' 'python-reportlab' 'python-simplejson' 'pil')
source=(http://rst2pdf.googlecode.com/files/rst2pdf-$pkgver.tar.gz LICENSE.txt)
optdepends=('uniconvertor: vector images support'
            'python-svglib: SVG support'
            'python-wordaxe: hyphenation'
            'pythonmagick: PDF images support')
build() {
cd $startdir/src/rst2pdf-$pkgver
python setup.py install --root=$startdir/pkg || return 1
install -D ../LICENSE.txt $startdir/pkg/usr/share/licenses/python-rst2pdf/COPYING
install -D doc/rst2pdf.1 $startdir/pkg/usr/share/man/man1/rst2pdf.1
}
md5sums=('ea6beda9a46f34ba42c4c94d48cc607a'
        '416f8046c66b9476cdbacda69a673afe')

Y eso es todo lo que hay que saber del proceso de empaquetar tu aplicación para Linux, es fácil de hacer, y la mayor parte del tiempo, fácil de hacer bien.

Ahora, la sección final...

Windows para el desarrollador

¿Primero, te acordás de eso de depender de la versión de sistema de Qt? Olvídalo, no hay versión de sistema. Tampoco hay Python, así que no importa. Y nadie los va a instalar para tu aplicación, así que tenemos que meter todo nosotros, o nada.

Pero lo bueno es que PyInstaller funciona para Windows! Entonces, usando el mismo spec funciona, no?

Bueno, hay dos problemas...

Problema 1: El instalador

Los usuarios de Windows no van a abrir un zip y conectar el binario con el menú de inicio ni nada parecido, así que hay que hacer un instalador.

Esto es lo que hice para NSIS, un creador de instaladores gratuito:

;--------------------------------
;Include Modern UI

!include "MUI2.nsh"

;--------------------------------
;General

;Name and file
Name "Marave"
OutFile "Marave-0.5.win32.exe"

;Default installation folder
InstallDir "$LOCALAPPDATA\Marave"

;Get installation folder from registry if available
InstallDirRegKey HKCU "Software\Marave" ""

;Request application privileges for Windows Vista
RequestExecutionLevel user

;--------------------------------
;Interface Settings

!define MUI_ABORTWARNING

;--------------------------------
;Pages

!insertmacro MUI_PAGE_LICENSE "LICENSE"
!insertmacro MUI_PAGE_DIRECTORY
!insertmacro MUI_PAGE_INSTFILES

!insertmacro MUI_UNPAGE_CONFIRM
!insertmacro MUI_UNPAGE_INSTFILES

;--------------------------------
;Languages

!insertmacro MUI_LANGUAGE "English"

;--------------------------------
;Installer Sections

Section "Install"

SetOutPath "$INSTDIR"
File /r "dist\marave"


;Store installation folder
WriteRegStr HKCU "Software\Marave" "" $INSTDIR

;Create uninstaller
WriteUninstaller "$INSTDIR\Uninstall.exe"

;Create shortcuts
CreateDirectory $SMPROGRAMS\Marave
CreateShortCut "$SMPROGRAMS\Marave\Marave.lnk" "$INSTDIR\marave\marave.exe" ; use defaults for parameters, icon, etc.
CreateShortCut "$SMPROGRAMS\Marave\Uninstall Marave.lnk" "$INSTDIR\Uninstall.exe" ; use defaults for parameters, icon, etc.

SectionEnd


;--------------------------------
;Uninstaller Section

Section "Uninstall"

Delete "$INSTDIR\Uninstall.exe"
RMDir /r "$INSTDIR"

DeleteRegKey /ifempty HKCU "Software\Marave"

SectionEnd

Es comparable al esfuerzo de hacer un arhivo de empaquetado, excepto que cada vez que lo querés probar... lo instalás. No hay manera (que yo vea) de saber qué hay adentro del instalador excepto correrlo.

Cuando las cosas fallan, no hay mensajes de error, por lo menos no del tipo que es útil para un desarrollador, el que necesita saber que salió mal.

Después de que termina, tal vez no funcione porque...

Problema 2: bibliotecas de sistema. Ja!

Los binarios de Python 2.6 están compilados con Visual Studio. Eso quiere decir que necesitan el Visual Studio Runtime, específicamente MSVCR90.DLL. Ésta contiene cosas que en Linux serían considerado parte de la libc (linuxero: imaginate aplicaciones que dependen de una libc específica... ¡no es fácil!)

En Linux eso es parte del sistema. Más aún, si lo necesitas, lo redistribuís. En Windows... es diferente.

  1. Es parte del "Visual C++ redistributables"

  2. Instalarlo no es garantía de que ande (sí, lo probé)

  3. La licencia de esos 'redistributables' dice que no lo podés hacer disponible para descarga.

    Me han dicho que incluírlo en tu instalador es legal, pero a mí me parece que eso es hacerlo disponible para descarga!

¿Qué se hace cuando necesitás una biblioteca, no la podés distribuir y el usuario no la va a instalar?

Bueno, por algo no hay binarios de Marave para Windows todavía ;-) Por supuesto si alguien lo puede resolver, me encantaría!

2010-01-19 14:12

Feliz cumpleblog para mí!

Desde ayer este blog tiene 10 años así que es un buen momento para hacer historia.

Todo empezó en advogato donde se lo puede leer aún hoy! (Por favor léanlo acá ;-)

Después cambió a PyDS, una plataforma de blog python de escritorio con interface web, y hosteado en PyCS, un servicio gratuito.

Entonces PyCS se murió, y empecé a generar un blog estático hosteado en el hosting gratis de mi ISP. Eso era una bazofia.

Después fundé mi propia compañía, tuve mis propios servers, y empecé a hostearlo allí (¡Aún hoy este blog es HTML completamente estático! ¿No se nota, no?)

Entonces PyDS empezó a funcionar mal, y escribí mi propio software, que es una porquería, tal vez 25% terminado pero hace las cosas exactamente como yo quiero.

Hoy, este blog está agregado en Planeta PyAr, Planet Python, Planet Qt, Planeta LUGLI, Y algún otro lugar.

Este año decidí hacer que sea bilingüe (inglés y español) pero odio traducirlo (lo escribo primero en inglés).

De acuerdo a las estadísticas disponibles, es, en promedio, más popular que nunca (pero mis posts mas populares son viejos).

stats

Éstas son las páginas más populares del último año:

Lecciones:

  1. Necesito escribir más sobre Qt y/o empezar flames con gente que escribe sobre IT.
  2. Necesito buscar el material obsoleto y poner notas.
  3. Tener tu propio hosting y soft es mejor.
  4. 10 años es mucho tiempo: 860 posts (o 913, depende como los cuente)

2009-12-23 15:32

Con iterpipes, python puede reemplacar a bash para scripting. En serio.

Esto me molesta hace mucho: programar scripts de shell es horrible. Son feos y llenos de errores. ¿El único motivo por el cual se sigue haciendo? Porque no hay alternativa.

O al menos así era hasta que hoy me encontré con iterpipes en python.reddit.com

Iterpipes es "una biblioteca para usar pipelines de shell usando sintaxis parecida al shell" y ¿sabés qué? Es brillante.

Acá hay un ejemplo de su página de PYPI:

# Total lines in *.py files under /path/to/dir,
# use safe shell parameters formatting:

>>> total = cmd(
...     'find {} -name {} -print0 | xargs -0 wc -l | tail -1 | awk {}',
...     '/path/to/dir', '\*.py', '{print $1}')
>>> run(total | strip() | join | int)
315

Así sería en shell:

find /path/to/dir -name '*.py' -print0 | xargs -0 wc -l | tail -1 | awk '{print $1}'

Tal vez digas que la versión de shell es más sencilla. Eso es una ilusión causada por la densidad del campo malico del shell: esa versión tiene bugs.

Porqué tiene bugs? Porque si controlo qué hay adentro de /path/to/dir puedo hacer que falle [1], pero en python puedo manejar el error.

También en la mayoría de los intentos de escribir ese comando sería inseguro porque las reglas de comillas y caracteres de escape de shell son dementes.

La versión de iterpipes usa el equivalente de prepared statements de SQL que debería ser más seguro.

Es casi imposible hacer ese comando en puro shell y estar seguro de que es seguro.

Además la versión en shell produce un string en vez de un entero, que es una bazofia si lo necesitás usar para algo.

Y el beneficio más importante es, por supuesto, no cuando tratás de hacer que python funcione como un shell, sino cuando podés dejar de hacer como que el shell es un lenguaje de verdad.

Comsideremos esta gema del script /etc/rc.shutdown en Arch Linux. DAEMONS es una lista de cosas que se arrancaron al inicio, y este script intenta detenerlas en orden inverso, a menos que el nombre empiece con "!":

# Shutdown daemons in reverse order
let i=${#DAEMONS[@]}-1
while [ $i -ge 0 ]; do
        if [ "${DAEMONS[$i]:0:1}" != '!' ]; then
                ck_daemon ${DAEMONS[$i]#@} || stop_daemon ${DAEMONS[$i]#@}
        fi
        let i=i-1
done

¿No es lindo?

¿Y cómo se vería en python? (tal vez haya invertido el significado de ck_daemon):

# Shutdown daemons in reverse order
for daemon in reversed(DAEMONS):
    if daemon[0]=='!':
        continue
    if ck_daemon(daemon):
        stop_daemon(daemon)

Mientras que stop_daemon solía ser esto:

stop_daemon() {
    /etc/rc.d/$1 stop
}

Ahora será esto:

.. code-block:: python
def stop_daemon(daemon):
run(cmd('/etc/rc.d/{} stop',daemon))

Vamos gente, estamos en pleno siglo 21, y el shell scripting ya era feo en el 20.

[1] Ejercicio para el lector.

2009-12-03 15:04

DBUS-reactor, o AsusOSD debe morir!

Cómo escribir una pequeña aplicación python (menos de 50 líneas) que reacciona a eventos DBUS. Por ejemplo, mostrando una notificación cuando se presiona una de las teclas 'especiales' en el teclado de una notebook.

Léalo aquí

Contents © 2000-2019 Roberto Alsina