Etiqueta: gnu

  • CONQUER: Una Odisea de 20 Años en Arqueología Digital

    CONQUER: Una Odisea de 20 Años en Arqueología Digital

    Cómo rescaté un juego de USENET de 1987, rastreé a sus creadores a través del tiempo y lo llevé a la era moderna

    Autor: Juan Méndez (vejeta) | Septiembre 2025


    PRÓLOGO: El Eco de un Mundo Perdido

    «I heard news of the request to release the code. I grant permission to release the code under GPL.»
    — Adam Bryant, 23 de febrero de 2011

    «I enjoyed the article and liked seeing the map images in particular. It definitely brought back very fond memories! If only working a job to pay the bills hadn’t gotten in the way…»
    — Adam Bryant, septiembre de 2025

    Catorce años separan estos dos mensajes. El primero rescató un proyecto estancado; el segundo reveló la profundidad emocional de una era digital que ya no existe. Esta es la historia de cómo una obsesión de dos décadas devolvió la voz a los pioneros del software y tendió un puente entre dos Internet irreconciliables.


    CAPÍTULO 1: La Cápsula del Tiempo Digital (1987)

    Imagen: Captura completa del posting original de «conquest» mostrando el código shar.

    26 de octubre de 1987. Mientras la mayoría del mundo ni siquiera imaginaba Internet, en los servidores de USENET un usuario llamado ihnp4!mhuxd!smile (Edward Barlow) publicaba en comp.sources.games:

    v02i058: conquest – middle earth multi-player game, Part01/05

    Este mensaje era más que un anuncio; era un artefacto de una filosofía que definiría una era.

    La Logística del shar: Cuando el Software Viajaba en Fragmentos

    Descargar Conquer en 1987 no era un clic. Era un rito de iniciación técnica:

    bash

    #! /bin/sh

    # This is a shell archive. Remove anything before this line, then unpack

    # it by saving it into a file and typing «sh file».

    Cada una de las 5 partes era un script que contenía el código codificado como texto. El proceso requería:

    1. Descargar manualmente cada parte desde USENET
    2. Ejecutar sh parte01 para reconstruir los archivos
    3. Repetir para las partes 2-5
    4. Compilar manualmente con cc -o conquer *.c -lcurses

    Si fallaba la parte 3, el proceso se detenía. No había resume download. Se esperaba días o semanas hasta que reapareciera en el feed.

    El Acto de Fe Colectivo

    Publicar en comp.sources.games era enviar tu trabajo al escrutinio de miles de los mejores ingenieros del mundo. No había tiendas curadas ni revisiones previas. La comunidad era el control de calidad.

    Ed Barlow incluía esta nota en el README:

    «What you have here is a copyrighted beta test version of CONQUEST.»

    No existían las «betas cerradas». Se confiaba en que usuarios anónimos en universidades de todo el mundo probarían, reportarían errores y mejorarían el código. Era el open source antes de que el término existiera.


    CAPÍTULO 2: Días Universitarios – El Descubrimiento (1990s)


    The Red Building, also known as El Edificio Rojo, was where the Computer Labs for Computer Sciences was hosted during the 90s in Sevilla, Spain
    Algunos amigos en las puertas del edificio rojo, año 95, estudiantes de la facultad de informática y estadística, adictos al CdC

    Fotografía de los laboratorios Unix de la Universidad de Sevilla en los años 90.

    A mediados de los 90, siendo estudiante en Sevilla, pasé incontables horas en los laboratorios Unix explorando un mundo digital emergente: terminales verdes, USENET, links, news, msgs – y, por supuesto, Conquer.

    El juego era revolucionario. Como líder de una nación, controlabas tu reino élfico, imperio orco o ejércitos humanos a través de un mapa renderizado en caracteres ASCII. La profundidad era asombrosa:

    • Gestión económica detallada por sectores
    • Sistemas diplomáticos complejos entre razas
    • Magia y hechizos con efectos en el mundo
    • Exploración de territorios desconocidos

    El Ritual Social del Juego

    No era un juego solitario. El ritual era profundamente social:

    1. Conectar por SSH a una máquina Unix compartida
    2. Hacer movimientos durante el día entre clases
    3. Esperar el conqrun nocturno que procesaba los turnos
    4. Recibir emails con los resultados cada mañana

    Organizamos partidas que duraban semanas, con turnos diarios o semanales. La lentitud era una característica, no un defecto. Permitía la estrategia profunda y creaba comunidad alrededor del texto.

    No he encontrado fotos de la época de la sala, pero he encontrado su descripción en las antiguas páginas de la facultad:


    CAPÍTULO 3: La Búsqueda Comienza – Detective Digital (2006)

    Imagen: Captura completa del hilo en debian-legal mostrando la consulta inicial.

    Para 2006, esta pieza de historia computacional estaba atrapada en un limbo legal. Comencé lo que pensé que sería un proyecto simple: obtener permiso para relicenciar el código bajo GPL y empaquetarlo para distribuciones Linux modernas.

    Encontrar a los autores originales fue arqueología digital. Los emails de los 80 llevaban años muertos. Examiné directorios universitarios antiguos, seguí migas de pan digitales y eventualmente contacté a Ed Barlow.

    La Filosofía del «Hazlo y Ve Qué Pasa»

    Nuestra conversación por mensajería en 2006 reveló la mentalidad de la era:

    (18:08:58) vejeta: Sorry if I catch you busy. While trying to investigate if I could relicense old conquer as free software I discovered it was complex.
    (18:14:00) Ed Barlow: i personally would say that you should do it and nobody will know the difference
    (18:18:52) vejeta: Indeed, I feel like a detective 🙂
    (18:21:23) Ed Barlow: v4 was both of ours… i wrote v4 he wrote v5…

    Cuando pregunté sobre arreglos comerciales previos, su respuesta fue reveladora:

    «i dont know… i dont have adams mail address at all… dunno if they did anythign with the license tho»

    Esta actitud encapsulaba la era pre-comercial de Internet: construir por pasión, compartir por defecto.

    Pero Adam Bryant había desaparecido en el éter digital. Documenté todo en las listas de Debian Legal y creé la tarea GNU Savannah #5945. El proyecto se estancó.


    CAPÍTULO 4: La Larga Espera y el Avance Inesperado (2006-2011)

    Imagen: Captura del email de Adam Bryant de 2011 llegando espontáneamente.

    Pasaron años. Entonces, el 23 de febrero de 2011, ocurrió la magia. Mi teléfono vibró con un envío de formulario de contacto:

    «I heard news of the request to release the code. I grant permission to release the code under GPL.» – Adam Bryant

    Había encontrado uno de mis artículos en línea y contactó espontáneamente. Después de cinco años de búsqueda, la barrera principal había desaparecido.

    La Comunidad como Memoria Colectiva

    Mientras tanto, conversaciones informales mantuvieron viva la llama. En 2011, mientras explicaba el proyecto a un amigo, su entusiasmo fue contagioso:

    kike: killo me has dejao to intringao con el conquer no le puedes hacer eso a un puto ludópata como yo XDDD
    vejeta: …Esto fue la epoca pre-internet. Y nos entreteniamos con otras cosas: saltarnos las protecciones, juegos como el conquer, dominion, el arte ascii :). El irc acabó con todo eso.
    kike: si necesitas mano de obra barata para algo del conquer, cueneta conmigo…

    Estos diálogos muestran que el proyecto nunca fue un fin en sí mismo, sino un vehículo para revivir una forma de entender la tecnología.


    CAPÍTULO 5: La Trama se Complica – Versión 5 Emerge (2025)

    Imagen: Comparación lado a lado de las interfaces de Conquer v4 y v5.

    Justo cuando la historia parecía completa, Stephen Smoogen me contactó en 2025 sobre mis esfuerzos de relicenciamiento de 2006. Estaba particularmente interesado en Conquer Versión 5 – la reescritura completa de Adam Bryant con características avanzadas:

    • Conversión automática de datos entre versiones
    • Estabilidad mejorada y herramientas administrativas
    • Sistemas de eventos sofisticados
    • Interfaz de administración expandida

    Pero V5 tenía una historia legal diferente, incluyendo arreglos comerciales de los 90. ¿Aceptaría Adam licenciar GPL esta versión también?

    Su respuesta: «I have no issues with applying a new GPL license to Version 5 as well.»

    El Arco de 14 Años

    El viaje de Adam entre sus dos mensajes cuenta una historia universal:

    2011: «I grant permission to release the code under GPL.»
    2025: «If only working a job to pay the bills hadn’t gotten in the way…»

    Este arco de 14 años revela la tensión eterna entre pasión y responsabilidad que todo creador enfrenta.


    CAPÍTULO 6: Las Piezas Perdidas – Magia PostScript y una Pérdida Trágica

    Imagen: Ejemplo de salida PostScript de las utilidades de MaF.

    La red de contribuyentes se expandió. Descubrí a MaF (Martin Forssen), quien creó utilidades PostScript para generar mapas imprimibles del juego – crucial en la era pre-GUI cuando los jugadores necesitaban copias físicas para estrategizar.

    Rastrear a MaF en 2025 me llevó a su nueva dirección de correo electrónico. Su respuesta fue inmediata y generosa: «Oh, that was a long time ago. But yes, that was me. And I have no problem with relicensing it to GPL.»

    Richard Caley: No Solo un Pie de Página Legal

    Captura de la página principal de Richard Caley preservada mostrando el anuncio.

    Pero no todas las búsquedas terminan con una respuesta. Algunas terminan con silencio.

    Mi investigación sobre Richard Caley siguió las mismas migas de pan digitales. Lo tracé hasta la Universidad de Edimburgo, donde trabajó en síntesis de voz. Encontré sus contribuciones técnicas a FreeBSD. Pero el rastro se enfrió alrededor de 2005.

    Entonces lo encontré – no en un archivo de USENET, sino en la portada de su propio sitio web, preservado exactamente como lo dejó:

    «Richard Caley suffered a fatal heart attack on the 22nd of April, 2005. He was only 41, but had been an undiagnosed diabetic, probably for some considerable time. His web pages remain as he left them.»

    Leer esas palabras se sintió diferente a encontrar un registro histórico. Esto no era investigación archivística – era entrar a la casa de alguien años después de que se hubiera ido y encontrar una nota en la mesa.

    La página continuaba:

    «Over and above his tremendous ability with computers and programming, Richard had a keen mind and knowledge of an extraordinary range of topics, both of which he used in frequent contributions to on-line discussions. Despite his unique approach to speling, his prolific contributions to various news group debates informed and amused many over the years.»

    Los «Caleyisms» – El Hombre Detrás del Código



    Captura de la página «Caleyisms» mostrando sus respuestas ingeniosas.

    Y entonces descubrí sus «Caleyisms» – una colección curada de sus respuestas más brillantes en USENET que revelaban no solo a un programador, sino a una persona:

    What’s a shell suit?
    «Oil company executive.»

    How do you prepare for a pyroclastic flow hitting Edinburgh?
    «Hang 1000 battered Mars bars on strings and stand back?»

    On his book addiction:
    «I never got the hang of libraries, they keep wanting the things back and get upset when they need a crowbar to force it out of my hands.»

    Su humor era seco, inteligente y únicamente británico. En discusiones técnicas, podía ser brutalmente preciso:

    «Lack of proper punctuation, spacing, line breaks, capitalisation etc. is like bad handwriting, it doesn’t make it impossible to read what was written, just harder. But you probably write in green crayon anyway.»*

    El Oficina Digital Preservada

    Explorar su sitio web preservado se sintió como caminar por su oficina digital. La estructura de directorios revelaba sus pasiones: how-tos de FreeBSD, experimentos con POVRAY, imágenes de fondo, proyectos técnicos. Su humor auto-despreciativo brillaba en su sección «About»:

    «Thankfully I don’t have a photograph to inflict on you. Just use the picture of Iman Bowie to the left and then imagine someone who looks exactly the opposite in every possible way. This probably explains why she is married to David Bowie and I’m not.»*

    Aquí había una persona completa – director técnico en Interactive Information Ltd, investigador de síntesis de voz, entusiasta de FreeBSD, fan de Kate Bush, y un ingenio que alegró incontables discusiones en línea.

    La realidad legal era dura: las contribuciones de Richard a Conquer no podían ser relicenciadas. La universidad no pudo ayudar a contactar herederos debido a leyes de privacidad.

    Imagen: El arte ASCII RIP de la página de Richard.

    Sus amigos habían preservado su memoria con un simple tributo ASCII al final de su página:

    text

          ^_^
    (O O)
    \_/@@\
    \\~~/
    ~~
    - RJC RIP

    En la documentación del proyecto Conquer, Richard Caley no es recordado como un «caso problemático» o «código no liberable». Es honrado como la persona vibrante que fue – la mente brillante detrás de los «Caleyisms», el investigador que contribuyó a la síntesis de voz, el defensor de FreeBSD, y el participante ingenioso en comunidades en línea tempranas cuyas palabras continúan divirtiendo e informando, décadas después de que las escribiera.


    CAPÍTULO 7: Renacimiento Técnico – Del USENET al CI/CD

    Imagen: Comparación lado a lado mostrando el archivo shar de 1987 y la configuración de GitHub Actions de 2025.

    La transformación técnica ha sido notable. Modernizar código de 1987 presenta desafíos únicos que requieren tanto respeto por el original como adopción de tecnologías modernas.

    Arqueología del Makefile

    # Original 1987 - Dependencias hardcodeadas
    conquer: conquer.c utils.c
        cc -o conquer conquer.c utils.c -lcurses -ltermcap
    # Moderno 2025 - Autotools y detección automática
    AC_INIT([conquer], [4.6])
    AC_PROG_CC
    AC_CHECK_LIB([ncurses], [initscr])

    Tuve que reemplazar assumptions de sistemas antiguos con detección automática de bibliotecas. Los Makefiles originales asumían versiones específicas de curses y ubicaciones de bibliotecas que ya no existen.

    La Magia de ttyd – Terminales en la Web

    # Dockerfile fragment - Puente tecnológico perfecto
    FROM alpine:latest
    RUN apk add ttyd ncurses
    COPY conquer /usr/local/bin/
    CMD ["ttyd", "-p", "7681", "conquer"]

    Esta configuración permite que la interfaz de curses original se renderice en navegadores modernos sin modificar una línea del código de 1987. Es un puente tecnológico que respeta el original mientras permite acceso moderno.

    Melange y el Empaquetado Reproducible

    # conquer.yaml - Construcción reproducible APK
    package:
      name: conquer
      version: 4.6
      description: "1987 USENET multiplayer strategy game"
    environment:
      contents:
        packages:
          - ncurses-dev
          - gcc

    El mismo juego que viajaba en 5 partes de USENET ahora genera paquetes binarios con hashes criptográficos y procedencia verificable. La ironía: descubrí Melange cuando un amigo empezó a trabajar para la empresa que lo creó.

    Flujo CI/CD Completo

    yaml

    # GitHub Actions workflow
    - name: Build APK package
      run: melange build conquer.yaml
    - name: Build Debian package  
      run: dpkg-buildpackage -b
    - name: Docker build
      run: docker build -t conquer:latest .

    Logros Técnicos Clave:

    • Relicenciamiento GPLv3 para ambas v4 y v5
    • Sistema de construcción moderno con autotools
    • Base de código C actualizada para soportar ANSI C99 moderno
    • Empaquetado Debian integración
    • Empaquetado APK con Melange para Alpine Linux
    • Contenedores Docker con emulación de terminal via WebSockets

    CAPÍTULO 8: Contexto Histórico – Conquer en el Ecosistema de Juegos Unix

    Imagen: Fragmento de la lista «versions of empire» de 1989 mostrando a Conquer entre otros juegos.

    Conquer no existía en el vacío. La lista «versions of empire» de 1989 revela un ecosistema floreciente de juegos de estrategia multiplayer:

    • Empire (PSL, UCB, UCSD): Diferentes variantes mantenidas por universidades
    • Galactic Bloodshed: Enfocado en exploración y terraformación
    • xconq: Uno de los primeros en ofrecer interfaz X Window
    • Buck Empire: Mejoras y debugging de una versión de PSL Empire

    ¿Por qué Conquer Sobrevivió Cuando Otros Desaparecieron?

    • Arquitectura Modular: Fácil de extender con nuevas razas y hechizos
    • Documentación Completa: Incluía guías de administración y formato de datos
    • Comunidad Activa: Adam Bryant mantuvo parches durante años
    • Portabilidad: Escrito en C estándar, sin dependencias exóticas

    Mientras juegos comerciales de la misma época desaparecieron con sus plataformas, Conquer sobrevivió porque era texto plano y código abierto antes de que el término existiera.

    La lista de 1989 presentaba a Conquer así:

    «A multiplayer fantasy wargame written from scratch by Ed Barlow… Not really empire, but close enough to be easily understood by those used to empire. Currently supported by co-author Adam Bryant.»

    Esto revela una cultura donde los «competidores» se listaban unos a otros en un espíritu de comunidad. El valor no estaba en la propiedad intelectual, sino en la contribución a un ecosistema común.


    CAPÍTULO 9: El Elemento Humano – Por Qué Esta Odisea de 20 Años Importa

    Imagen: Collage mostrando el código original de Ed Barlow, el email de Adam Bryant de 2011, y la conversación del equipo de 2025.

    Esto no es solo sobre preservar juegos. Es sobre preservar la historia misma de la computación.

    Los Pioneros del Software

    Ed Barlow y Adam Bryant construyeron experiencias multiplayer sofisticadas cuando la mayoría de la gente nunca había oído hablar de Internet. Distribuyeron software a través de USENET porque eso era lo que se hacía – compartías cosas geniales con la comunidad.

    Martin Forssen y sus utilidades PostScript representan el ingenio de los desarrolladores tempranos que resolvían problemas con las herramientas disponibles. ¿Querías visualizar el estado del juego? ¡Escribías un generador PostScript!

    Comunidad y Continuidad

    El esfuerzo de relicenciamiento de 20 años demuestra algo crucial sobre el open source: no es solo sobre código, es sobre comunidad y continuidad. Cada vez que alguien mantiene un proyecto legacy, documenta su historia, o rastrea contribuidores perdidos, está tejiendo los hilos que conectan el pasado computacional con su futuro.

    El viaje de Adam entre sus dos mensajes – desde el permiso técnico hasta la reflexión emocional – encapsula por qué la preservación importa: el código sobrevive, pero las historias humanas se pierden si no las capturamos.


    EPÍLOGO: Lecciones de la Arqueología de Software

    1. Documenta Todo
    Esos posts casuales de USENET se convirtieron en evidencia legal crucial décadas después.

    2. Licencia Claramente
    El comentario de Ed de que «copyleft didnt exist when i wrote it» resalta cómo los panoramas de licencias evolucionan.

    3. La Comunidad es Todo
    Adam encontró mis artículos porque la comunidad de preservación estaba hablando del proyecto.

    4. Las Herramientas Modernas Pueden Revivir Código Antiguo
    Melange y CI/CD le dieron al software de 1987 un renacimiento en 2025.

    5. La Deuda Técnica es Temporal
    Lo que parece tecnología legacy hoy podría ser el tesoro arqueológico de mañana.

    6. Preserva las Historias, No Solo el Código
    Los «Caleyisms» de Richard son tan valiosos como sus contribuciones técnicas.


    LA HISTORIA CONTINÚA

    Ambos juegos Conquer están ahora completamente licenciados bajo GPLv3 con empaquetado moderno. No son solo software jugable, sino un caso de estudio completo en:

    • Arqueología de software
    • Marcos legales para preservación
    • Evolución de prácticas de desarrollo a través de cuatro décadas

    Los repositorios cuentan la historia en curso:

    El próximo capítulo: enseñar estos juegos de estrategia clásicos a una nueva generación de desarrolladores y jugadores, mientras demostramos que los marcos legales apropiados y las herramientas modernas pueden dar una segunda vida a cualquier software histórico.

    A veces la mejor manera de aprender tecnología de vanguardia es aplicándola para preservar la historia computacional.


    ¿Qué software histórico merece preservación en tu campo? ¿Has rastreado alguna vez el linaje del código hasta sus creadores originales?

    #SoftwareLibre #CodigoAbierto #PreservacionDeSoftware #Unix #GNU #Linux #Empaquetado #Melange #HistoriaTecnologica #DesarrolloDeJuegos #USENET #GPL #FSF #Debian #ncurses #terminal


    Read this article in English / Lee este artículo en inglés: 

    https://vejeta.com/reviving-classic-unix-games-a-20-year-journey-through-software-archaeology/
  • Reviving Classic Unix Games: A 20-Year Journey Through Software Archaeology

    Reviving Classic Unix Games: A 20-Year Journey Through Software Archaeology


    How I spent two decades tracking down the creators of a 1987 USENET game and learned modern packaging tools in the process.

    The Discovery: A Digital Time Capsule from 1987

    Picture this: October 26, 1987. The Berlin Wall still stands, the World Wide Web is just text, and software is distributed through USENET newsgroups in text files split across multiple posts. On that day, Edward Barlow posted something special to comp.sources.games:

    «conquest – middle earth multi-player game, Part01/05»

    That’s how Ed Barlow announced it at the time, before quickly changed the name to Conquer.

    This was Conquer – a sophisticated multi-player strategy game that would influence countless others. Players controlled nations in Middle Earth, managing resources, armies, magic systems, and diplomatic relations. What made it remarkable wasn’t just the gameplay, but how it was built and distributed in an era when «open source» wasn’t even a term yet.

    Chapter 0: University Days.

    It was during these days, in the middle of the 90s, that my fellow students and I spent hours experimenting with terminals in the Computer Unix Labs, USENET, links, news, msgs, and of course: conquer. That game was a gem that required to be the leader of a country, and with a map representing as characters each player could control their elven kingdom, orcish empire, or human armies to fight each other while controlling all the details of the economy.

    But by 2006, this piece of computing history was trapped in legal limbo.

    Chapter 1: The Quest Begins (2006)

    As a university student in Spain in the early ’90s, I’d encountered Conquer in the Unix labs. Fast forward to 2006, and I realized this pioneering game was at risk of being lost forever. The source code existed, scattered across ancient USENET archives, but its licensing was unclear – typical of the «post it and see what happens» era of early internet software distribution.

    I started what I thought would be a simple project: get permission from the original authors to relicense the code under GPL so it could be properly preserved and packaged for modern Linux distributions.

    Simple, right?

    Chapter 2: Digital Detective Work

    Finding Edward Barlow and Adam Bryant in 2006 was like archaeological work. Email addresses from the 1980s were long dead. USENET posts provided few clues. I scoured old university directories, googled fragments of names, and followed digital breadcrumbs across decades-old forums.

    The breakthrough came through pure persistence and a bit of luck. After months of searching, I managed to contact Ed Barlow. His response was refreshingly casual: «Yes i delegated it all to adam aeons ago. Im easy on it all…. copyleft didnt exist when i wrote it and it was all for fun so…»

    But there was a catch – I needed permission from Adam Bryant too, and he seemed to have vanished into the digital ether.

    Chapter 3: The Long Wait (2006-2011)

    I documented everything on the Debian Legal mailing lists, created a GNU Savannah task (#5945), and even wrote blog posts hoping Adam would find them. The legal experts were clear: I needed explicit written permission from both copyright holders.

    Years passed. The project stalled.

    Then, on February 23, 2011, something magical happened. My phone buzzed with a contact form submission:

    «I heard news of the request to release the code. I grant permission to release the code under GPL.» – Adam Bryant

    He had found one of my articles online and reached out on his own.

    Chapter 4: The Plot Twist – Version 5 Emerges (2025)

    Fast forward to 2025, and Stephen Smoogen contacts me about my relicesing efforts in 2006 and how he was particularly interested in reviving: Conquer Version 5 – a complete rewrite by Adam with advanced features like automatic data conversion, enhanced stability, and sophisticated administrative tools. This wasn’t just an update; it was a complete reimagining of the game.

    But V5 had a different legal history. In the ’90s, there had been commercial arrangements. Would Adam agree to GPL this version too?

    His response: «I have no issues with applying a new GPL license to Version 5 as well.»

    Chapter 5: The Missing Piece – PostScript Magic

    Just when I thought the story was complete, I discovered another contributor: MaF (Martin Forssen), who had created PostScript utilities for generating printable game maps – a crucial feature in the pre-GUI era when players needed physical printouts to strategize.

    Tracking down MaF in 2025 led me to his new email. His response: «Oh, that was a long time ago. But yes, that was me. And I have no problem with relicensing it to GPL.»

    Richard Caley: More Than Just a Legal Footnote

    But not all searches end with an answer. Some end with silence.

    My investigation of Richard Caley followed the same digital breadcrumbs. I traced him to the University of Edinburgh, where he worked on speech synthesis. I found his technical contributions to FreeBSD. But the trail went cold around 2005.

    Then I found him – not in a USENET archive, but on the front page of his own website, preserved exactly as he left it in web.archive.org.

    «Richard Caley suffered a fatal heart attack on the 22nd of April, 2005. He was only 41, but had been an undiagnosed diabetic, probably for some considerable time. His web pages remain as he left them.»

    Reading those words felt different from finding a historical record. This wasn’t archival research – this was walking into someone’s house years after they’d gone and finding a note on the table.

    The page continued:

    «Over and above his tremendous ability with computers and programming, Richard had a keen mind and knowledge of an extraordinary range of topics, both of which he used in frequent contributions to on-line discussions. Despite his unique approach to speling, his prolific contributions to various news group debates informed and amused many over the years.»

    The «Caleyisms» – The Man Behind the Code

    And then I discovered his «Caleyisms» – a curated collection of his most brilliant USENET responses that revealed not just a programmer, but a person:

    What’s a shell suit?

    «Oil company executive.»

    How do you prepare for a pyroclastic flow hitting Edinburgh?

    «Hang 1000 battered Mars bars on strings and stand back?»

    On his book addiction:

    «I never got the hang of libraries, they keep wanting the things back and get upset when they need a crowbar to force it out of my hands.»

    His humor was dry, intelligent, and uniquely British. In technical discussions, he could be brutally precise:

    «Lack of proper punctuation, spacing, line breaks, capitalisation etc. is like bad handwriting, it doesn’t make it impossible to read what was written, just harder. But you probably write in green crayon anyway.»

    A Digital Office Preserved

    Exploring his preserved website felt like walking through his digital office. The directory structure revealed his passions: FreeBSD how-tos, POVRAY experiments, wallpaper images, technical projects. His self-deprecating humor shone through in his «About» section:

    «Thankfully I don’t have a photograph to inflict on you. Just use the picture of Iman Bowie to the left and then imagine someone who looks exactly the opposite in every possible way. This probably explains why she is married to David Bowie and I’m not.»

    Here was a complete person – technical director at Interactive Information Ltd, speech synthesis researcher, FreeBSD enthusiast, Kate Bush fan, and a wit who brightened countless online discussions.

    The legal reality was harsh: Richard’s contributions to Conquer couldn’t be relicensed. The university couldn’t help contact heirs due to privacy laws.

    His friends had preserved his memory with a simple ASCII tribute at the end of his page:

          ^_^
    (O O)
    \_/@@\
    \\~~/
    ~~
    - RJC RIP

    In the Conquer project documentation, Richard Caley isn’t remembered as a «problem case» or «unlicensable code.» He’s honored as the vibrant person he was – the brilliant mind behind the «Caleyisms,» the researcher who contributed to speech synthesis, the FreeBSD advocate, and the witty participant in early online communities whose words continue to amuse and inform, decades after he wrote them.

    Chapter 6: Modern Renaissance – Enter GitHub, CICD and Modern Distributions

    GitHub Actions to publish Debian Packages and Alpine packages (with Melange)

    Here’s where the story gets really interesting. While working on preserving these Unix classics, I decided to learn modern packaging techniques. I chose to implement both APK (Alpine Linux) and Debian packaging for the games.

    For APK packages, I used Melange – a sophisticated build system that creates provenance-tracked, reproducible packages for the Wolfi «undistro». The irony? I discovered this tool when some friend started to work for the company that created it.

    Chapter 7: The Technical Journey: From USENET to Modern CI/CD

    The transformation has been remarkable:

    1987 Original:

    • Distributed as split USENET posts
    • Manual compilation with system-specific Makefiles
    • No version control or automated testing

    2025 Revival:

    # Modern CI/CD with GitHub Actions
    - name: Build APK package
      run: melange build conquer.yaml
    - name: Build Debian package  
      run: dpkg-buildpackage -b
    

    Key Modern Additions:

    • GPLv3 relicensing
    • Make building system modernization
    • C Codebase partially updated to support modern ANSI C99 specification
    • Debian packaging
    • APK packaging with Melange

    You can see the complete transformation in the repositories:

    Original Conquer v4 code, by Ed Barlow and Adam Bryant

    (Conquer running in docker container alongside Apache, Curses to WebSockets output thanks to ttyd. Now we can play through the web!)

    Conquer Version 5 – The evolution of the classical Conquer, by Adam Bryant

    Chapter 8: The Human Element: Why This Matters

    This isn’t just about preserving old games – it’s about preserving the story of computing itself. Ed Barlow and Adam Bryant were pioneers who built sophisticated multiplayer experiences when most people had never heard of the internet. They distributed software through USENET because that’s what you did – you shared cool things with the community.

    Martin Forssen’s PostScript utilities represent the ingenuity of early developers who solved problems with whatever tools were available. Want to visualize your game state? Write a PostScript generator!

    The 20-year relicensing effort demonstrates something crucial about open source: it’s not just about code, it’s about community and continuity. Every time someone maintains a legacy project, documents its history, or tracks down long-lost contributors, they’re weaving the threads that connect computing’s past to its future.

    Lessons for Modern Developers

    1. Document everything: Those casual USENET posts became crucial legal evidence decades later
    2. License clearly: Ed’s comment that «copyleft didnt exist when i wrote it» highlights how licensing landscapes evolve
    3. Community matters: Adam found my articles because the community was talking about preservation
    4. Technical debt is temporal: What seems like legacy tech today might be tomorrow’s archaeological treasure
    5. Modern tools can revive ancient code: Melange and modern CI/CD gave 1987 software a 2025 renaissance

    The Continuing Story

    Both Conquer games are now fully GPL v3 licensed and available with modern packaging. They represent not just playable software, but a complete case study in software archaeology, legal frameworks for preservation, and the evolution of development practices across four decades.

    The next chapter? Teaching these classic strategy games to a new generation of developers and gamers, while demonstrating that proper legal frameworks and modern tooling can give any historical software a second life.

    Sometimes the best way to learn cutting-edge technology is by applying it to preserve computing history.


    What historical software deserves preservation in your field? Have you ever traced the lineage of code back to its original creators?

    #FreeSoftware #OpenSource #SoftwarePreservation #Unix #GNU #Linux #Packaging #Melange #TechHistory #GameDevelopment #Unix #USENET #GPL #FST #Debian #ncurses #terminal #shell

    Read this article in Spanish / Lee este artículo en español:
    https://vejeta.com/conquer-una-odisea-de-20-anos-en-arqueologia-digital/

    This article was originally written in both English and Spanish, with additional insights and cultural context in the Spanish version.

  • Expandiendo las Capacidades de Desarrollo: Proton Drive y Debian GNU/Linux

    Expandiendo las Capacidades de Desarrollo: Proton Drive y Debian GNU/Linux

    Capítulo 3: Mi Travesía Personal como Aspirante a Debian Maintainer

    Expandiendo las Capacidades de Desarrollo: Setup Híbrido con Proton Drive y Debian GNU/Linux

    8 de noviembre, 2025

    Las Limitaciones de Espacio con un ordenador portátil de 13 años

    Como desarrollador con más de 20 años de experiencia en Unix/Linux, he enfrentado un desafío constante: las limitaciones de almacenamiento local versus la necesidad de mantener múltiples proyectos activos, especialmente cuando trabajo en empaquetado complejo como Chromium Embedded Framework (CEF) para Debian. Recientemente, desarrollé una solución elegante que combina Proton Drive con automatización Linux para crear un ecosistema de desarrollo verdaderamente híbrido.

    El Problema: Limitaciones de Hardware Legacy

    Mi setup principal incluye un MacBook Pro 11,1 ejecutando Debian, con apenas 100GB de almacenamiento SSD. Con solo 15GB libres después de instalar las herramientas de desarrollo esenciales, cada proyecto de empaquetado se convierte en un juego de tetris de espacio en disco. Los builds de CEF pueden generar varios gigabytes de datos, y mantener múltiples iteraciones para debugging se vuelve imposible.

    Además, trabajo desde múltiples máquinas – la principal en casa y una laptop de viaje – lo que requiere sincronización manual constante de archivos de configuración, documentación técnica y progreso de desarrollo.

    La Solución: Arquitectura Híbrida con Proton Drive

    Componentes del Sistema

    1. Almacenamiento Local (SSD 100GB)

    • Trabajo activo y builds en curso
    • Máxima velocidad para compilación
    • Cache temporal del sistema

    2. Proton Drive (500GB)

    • Storage expandido cifrado end-to-end
    • Backup automático de trabajo
    • Sincronización entre máquinas
    • Archive de builds completados

    3. Storage Externo (SanDisk + CalDigit)

    • Almacenamiento masivo para builds históricos
    • Repositorios de packages grandes
    • Backup de sistemas completos

    Arquitectura de Directorios

    # Estructura local
    ~/development/debian/           # Trabajo activo (local SSD)
    ~/ProtonDrive/                  # Mount automático (Proton Drive)
    ├── cef-builds-archive/         # Builds completados
    ├── documentation-backup/       # Docs técnicas
    ├── config-backup/             # Configuraciones del sistema
    └── temp-builds/               # Storage temporal expandido
    
    # Estructura en Proton Drive
    protondrive:/sync/debian/       # Sync automático trabajo activo
    protondrive:/mount/             # Storage expandido montado
    

    Implementación Técnica

    1. Configuración de RClone

    RClone actúa como el puente entre el sistema local y Proton Drive, proporcionando tanto capacidades de sincronización como montaje de filesystem.

    # Instalación desde repositorios Debian
    sudo apt update
    sudo apt install rclone
    
    # Verificar instalación
    rclone --version
    
    # Configuración
    rclone config
    # Seleccionar: protondrive
    # Introducir credenciales de Proton Mail
    # Configurar 2FA si está habilitado
    

    2. Servicio de Sincronización Automática

    Creé un servicio systemd que sincroniza automáticamente el trabajo activo cada 4 horas:

    # ~/.config/systemd/user/proton-sync.service
    [Unit]
    Description=Sync Debian work to Proton Drive
    
    [Service]
    Type=oneshot
    ExecStart=/usr/bin/rclone sync -L %h/development/debian protondrive:/sync/debian \
        --exclude="*.tmp" \
        --exclude="*.lock" \
        --exclude=".git/**" \
        --exclude="build/**" \
        --exclude="*.log" \
        --ignore-existing \
        --transfers=2 \
        --checkers=1 \
        --timeout=300s \
        --retries=3 \
        -q
    
    # ~/.config/systemd/user/proton-sync.timer
    [Unit]
    Description=Sync Debian work every 4 hours
    
    [Timer]
    OnCalendar=*-*-* 00,04,08,12,16,20:00:00
    Persistent=true
    
    [Install]
    WantedBy=timers.target
    

    Activación:

    systemctl --user daemon-reload
    systemctl --user enable --now proton-sync.timer
    

    3. Mount Automático de Storage Expandido

    Para casos donde necesito acceso directo a storage como si fuera un filesystem local:

    # ~/.config/systemd/user/proton-mount.service
    [Unit]
    Description=Mount Proton Drive storage
    After=network-online.target
    Wants=network-online.target
    
    [Service]
    Type=notify
    Environment=PATH=/usr/bin:/bin
    ExecStartPre=/bin/mkdir -p %h/ProtonDrive
    ExecStartPre=/bin/sh -c 'fusermount -u %h/ProtonDrive || true'
    ExecStart=/usr/bin/rclone mount protondrive:/mount %h/ProtonDrive \
        --vfs-cache-mode full \
        --vfs-cache-max-size 20G \
        --vfs-cache-max-age 24h \
        --buffer-size 32M \
        --dir-cache-time 1h \
        --allow-other
    ExecStop=/bin/fusermount -u %h/ProtonDrive
    Restart=on-failure
    RestartSec=15
    
    [Install]
    WantedBy=default.target
    

    Configuración previa necesaria:

    # Habilitar user_allow_other en fuse
    echo 'user_allow_other' | sudo tee -a /etc/fuse.conf
    
    # Habilitar linger para arranque automático
    sudo loginctl enable-linger $USER
    

    4. Scripts de Workflow

    Script de Pull (inicio de sesión de trabajo):

    #!/bin/bash
    # start-work.sh
    echo "Descargando últimos cambios..."
    rclone sync protondrive:/sync/debian $HOME/development/debian --progress -v
    echo "Listo para trabajar"
    

    Script de Push (fin de sesión de trabajo):

    #!/bin/bash
    # end-work.sh
    echo "Subiendo cambios..."
    rclone sync -L $HOME/development/debian protondrive:/sync/debian \
        --exclude="*.tmp" \
        --exclude="*.lock" \
        --exclude=".git/**" \
        --exclude="build/**" \
        --exclude="*.log" \
        --ignore-existing \
        --transfers=2 \
        --checkers=1 \
        --timeout=300s \
        --retries=3 \
        --stats=30s \
        --progress \
        -v
    echo "Trabajo guardado"
    

    Script de Archive para builds CEF:

    #!/bin/bash
    # archive-cef-build.sh
    BUILD_DATE=$(date +%Y%m%d_%H%M%S)
    echo "Archivando build CEF actual..."
    cp -r ~/development/debian/chromium-embedded-framework/build \
        ~/ProtonDrive/cef-builds-archive/cef-build-$BUILD_DATE
    echo "Build archivado en ~/ProtonDrive/cef-builds-archive/cef-build-$BUILD_DATE"
    

    Ventajas del Sistema

    1. Escalabilidad Transparente

    El laptop con 15GB libres ahora puede manejar proyectos de múltiples gigabytes sin impacto en el rendimiento local. Los builds activos permanecen en SSD para velocidad máxima, mientras el archive automático libera espacio continuamente.

    2. Continuidad Entre Máquinas

    El workflow pull/push permite cambiar entre máquina principal y laptop de viaje sin pérdida de contexto. Cada sesión comienza con start-work.sh y termina con end-work.sh, garantizando sincronización perfecta.

    3. Backup Automático Cifrado

    Con timer cada 4 horas, nunca pierdo más de 4 horas de trabajo. El cifrado end-to-end de Proton significa que incluso datos sensibles de clients están protegidos.

    4. Flexibilidad de Storage

    • Local: Máxima velocidad para trabajo activo
    • Mount: Acceso directo como filesystem para casos especiales
    • Sync: Backup automático sin intervención manual
    • Externo: Capacidad masiva para archive de largo plazo

    Casos de Uso Específicos

    Desarrollo CEF (Chromium Embedded Framework)

    Los builds de CEF generan varios GB de artifacts. La configuración permite:

    • Build activo en SSD local (velocidad)
    • Archive automático de builds completados
    • Sincronización de documentación técnica entre iteraciones
    • Backup de scripts de build y patches personalizados

    Trabajo Remoto y Viajes

    Antes del sistema, trabajar desde la laptop de viaje significaba:

    • Sincronización manual propensa a errores
    • Pérdida de contexto entre máquinas
    • Limitaciones de almacenamiento aún más severas

    Ahora es completamente transparente: start-work.sh en cualquier máquina restaura el contexto exacto de la última sesión.

    Monitoreo y Mantenimiento

    Verificación de Servicios

    # Ver estado de servicios
    systemctl --user status proton-sync.service
    systemctl --user status proton-mount.service
    
    # Ver próximas ejecuciones del timer
    systemctl --user list-timers proton-sync.timer
    
    # Logs detallados
    journalctl --user -u proton-sync.service --since today
    

    Scripts de Diagnóstico

    #!/bin/bash
    # check-proton-setup.sh
    echo "=== Estado del Sistema Proton Drive ==="
    
    # Verificar mount
    if mountpoint -q ~/ProtonDrive; then
        echo "✅ Storage expandido montado correctamente"
        df -h ~/ProtonDrive
    else
        echo "❌ Mount no disponible"
    fi
    
    # Verificar timer de sync
    if systemctl --user is-active proton-sync.timer >/dev/null; then
        echo "✅ Timer de sync activo"
        systemctl --user list-timers proton-sync.timer
    else
        echo "❌ Timer no activo"
    fi
    
    # Verificar conectividad
    if rclone ls protondrive:/sync/ >/dev/null 2>&1; then
        echo "✅ Conectividad con Proton Drive OK"
    else
        echo "❌ Problema de conectividad"
    fi
    

    Consideraciones de Rendimiento

    Red y Latencia

    • Upload: ~30-80 Mbps después de overhead de encriptación
    • Download: Near line speed con cache local activo
    • Latencia: Imperceptible para acceso a archivos cacheados

    Optimizaciones Implementadas

    • VFS cache full: 20GB cache local para acceso rápido
    • Transfers limitados: 2 transferencias concurrentes para estabilidad
    • Exclusiones inteligentes: Archivos temporales y logs excluidos del sync
    • Ignore existing: Evita conflictos en sincronización bidireccional

    Impacto en Productividad

    Métricas de Mejora

    • Storage efectivo: De 15GB a 515GB disponibles
    • Tiempo de setup entre máquinas: De 30+ minutos a <2 minutos
    • Pérdida máxima de trabajo: De días potenciales a máximo 4 horas
    • Flexibilidad de proyecto: Múltiples builds CEF simultáneos posibles

    Casos de Recuperación

    Durante el desarrollo, experimenté una desconexión inesperada que habría resultado en pérdida significativa de trabajo. El sistema automático había sincronizado el progreso 2 horas antes, permitiendo recuperación completa en minutos.

    Lecciones Aprendidas

    1. Automatización vs Control

    El balance entre timer automático (cada 4h) y scripts manuales (pull/push) proporciona tanto protección continua como control granular cuando es necesario.

    2. Exclusiones son Críticas

    La configuración inicial incluía logs de build (35MB cada uno), saturando la red. Las exclusiones inteligentes mejoraron el rendimiento dramáticamente.

    3. Systemd User Services

    Los servicios de usuario proporcionan automatización robusta sin requerir privilegios root, ideal para entornos de desarrollo personal.

    Conclusión

    Esta configuración híbrida resuelve múltiples limitaciones simultáneamente: espacio de almacenamiento, continuidad entre máquinas, backup automático y escalabilidad de proyectos. Para desarrolladores trabajando con proyectos complejos como empaquetado Debian o builds de software extensos, representa una solución elegante que combina lo mejor de storage local rápido con la flexibilidad y seguridad del cloud storage cifrado.

    Ventajas Clave del Sistema

    • Zero downtime por pérdida de trabajo
    • Escalabilidad transparente de almacenamiento
    • Continuidad perfecta entre múltiples máquinas
    • Backup automático cifrado sin intervención manual
    • Flexibilidad de storage adaptada a diferentes necesidades

    Próximos Pasos

    Este setup forma la base para expansiones futuras:

    • Integración con CI/CD para builds automáticos
    • Monitoreo avanzado con métricas de uso
    • Sincronización selectiva por proyectos
    • Archive automático basado en políticas de tiempo

    Para desarrolladores que enfrentan limitaciones similares de hardware legacy pero necesitan mantener productividad en proyectos modernos complejos, esta arquitectura híbrida proporciona una solución práctica y escalable.

    El código completo de configuración y scripts están disponibles en mi repositorio de dotfiles, y continuaré documentando mejoras y optimizaciones a medida que evolucione el sistema.


    Referencias Técnicas

  • Packaging Stremio for Debian: A Journey to 100% System Library Integration

    Packaging Stremio for Debian: A Journey to 100% System Library Integration

    Stremio for Debian: A Journey to 100% System Library Integration

    How I replaced every bundled dependency in a complex Qt5 application—and what I learned about patch development, threading bugs, and the art of debugging runtime crashes

    By Juan Manuel Méndez Rey

    Last Updated: October 3, 2025

    Tags: #debian #packaging #qt5 #technical-writing #system-libraries #debugging #free-software


    TL;DR

    I packaged Stremio for Debian by replacing 100% of its bundled dependencies (libmpv, Qt libraries, OpenSSL) with system libraries. Along the way, I debugged five critical issues: QtWebEngine initialization order, threading conflicts with SingleApplication, missing QML modules, Node.js environment variables in QProcess, and debhelper install file pitfalls. The real lesson? I repeated patch creation 5+ times because I tested against modified sources instead of clean upstream. This article shares both the technical solutions and the meta-lesson about efficient patch development workflow that could have saved me 70% of development time.

    Key Takeaway: When packaging complex applications, test your patches against pristine upstream at each step, not at the end.


    Package Status (October 2025)

    This article documents the technical work behind packaging Stremio for Debian. The package has achieved 100% system library integration and is currently:

    • Technical work: Complete and validated
    • ITP submitted: Under review by Debian Developer sponsor
    • Status: Awaiting upload approval
    • Repository: salsa.debian.org/mendezr/stremio

    This is a technical deep-dive into the challenges and solutions, not an announcement of package availability. The work continues through the Debian review process.


    Introduction

    When I set out to package Stremio—a popular media center application—for Debian, I had one clear goal: achieve 100% system library integration. No bundled dependencies, no git submodules, just clean integration with Debian’s ecosystem. What seemed like a straightforward build system migration turned into a deep dive into Qt5 threading models, runtime initialization order, and the subtle art of creating minimal, maintainable patches.

    This is the story of that journey, the technical challenges I faced, and—perhaps most importantly—the lessons I learned about efficient patch development that could have saved me days of rework.

    The Challenge: System Libraries or Bust

    Stremio’s upstream repository arrived with several bundled dependencies as git submodules:

    • libmpv for video playback
    • qthelper for Qt utilities
    • singleapplication for single-instance behavior
    • OpenSSL libraries

    The Debian way is clear: use system-provided libraries. This isn’t just philosophical purity—it’s about security updates, dependency management, and integration with the broader ecosystem.

    The goal: Replace every bundled dependency with its Debian system library equivalent.

    The result: A working .deb package with a 293KB optimized binary using 100% system libraries.

    The journey: Five major technical hurdles, each revealing deeper insights into Qt5 application architecture.

    The First Victory (That Wasn’t)

    Initial packaging seemed straightforward. I modified CMakeLists.txt to use system libraries:

    find_package(PkgConfig REQUIRED)
    pkg_check_modules(MPV REQUIRED mpv)
    find_package(Qt5 REQUIRED COMPONENTS Core Gui Qml Quick WebEngine)
    find_package(OpenSSL REQUIRED)

    The build succeeded. Dependencies looked perfect:

    $ ldd build/stremio | head -5
        libQt5WebEngine.so.5 => /lib/x86_64-linux-gnu/libQt5WebEngine.so.5
        libQt5DBus.so.5 => /lib/x86_64-linux-gnu/libQt5DBus.so.5
        libcrypto.so.3 => /lib/x86_64-linux-gnu/libcrypto.so.3
        libmpv.so.2 => /lib/x86_64-linux-gnu/libmpv.so.2

    Perfect! Ship it, right?

    Wrong. When I actually ran the application:

    Segmentation fault (core dumped)

    Thus began the real work.

    Challenge 1: The QtWebEngine Initialization Bug

    Symptom: Immediate segmentation fault when launching the application.

    First debugging attempt: Run with gdb, examine the stack trace:

    Program received signal SIGSEGV, Segmentation fault.
    0x00007ffff5a2b3c4 in QQmlApplicationEngine::QQmlApplicationEngine() ()

    The crash occurred during QQmlApplicationEngine construction. But why? The same code worked fine with bundled libraries.

    The investigation: After examining Qt5 WebEngine documentation and several failed attempts to reorganize the code, I discovered a critical initialization requirement buried in the QtWebEngine documentation:

    QtWebEngine::initialize() must be called before the QApplication constructor when using QML.

    The bundled library setup happened to satisfy this ordering by accident. With system libraries, the default main() function violated it:

    // WRONG - causes crashes
    int main(int argc, char *argv[]) {
        QApplication app(argc, argv);  // QApplication created first
        // QtWebEngine::initialize() never called!
        QQmlApplicationEngine engine;  // CRASH
    }

    The fix (patch 0007-add-qtwebengine-initialize-fix.patch):

    // CORRECT - initialize QtWebEngine before QApplication
    int main(int argc, char *argv[]) {
        QtWebEngine::initialize();     // CRITICAL: Must be first!
        QApplication app(argc, argv);
        QQmlApplicationEngine engine;  // Now works
    }

    Lesson: When replacing bundled libraries with system ones, initialization order assumptions may change. Always verify startup sequence requirements.

    Challenge 2: The SingleApplication Threading Nightmare

    Symptom: After fixing QtWebEngine initialization, the application launched but immediately crashed with:

    QObject: Cannot create children for a parent that is in a different thread.

    The culprit: System library libsingleapplication-dev version 3.3.4.

    Stremio needs single-instance behavior—when you launch it a second time, it should activate the existing window rather than start a new process. The upstream code used a bundled singleapplication library. The Debian system provides libsingleapplication-dev. Perfect replacement, right?

    Wrong again.

    The investigation: The system SingleApplication library sets up a threading context that conflicts with QQmlApplicationEngine. Specifically:

    1. System SingleApplication creates its IPC mechanism in a worker thread
    2. QQmlApplicationEngine expects to be created in the main thread
    3. Qt5’s threading model doesn’t allow cross-thread parent-child relationships for certain QML objects

    The bundled version used a different threading approach that happened to work with QML.

    The false starts: I tried:

    • Patching SingleApplication to use main thread (broke IPC)
    • Deferring QML engine creation (broke startup sequence)
    • Various Qt thread affinity hacks (broke other things)

    The solution: Write a custom CompatibleSingleApp class that provides identical functionality without threading conflicts:

    // compatible_singleapp.h
    class CompatibleSingleApp : public QApplication {
        Q_OBJECT
    public:
        CompatibleSingleApp(int &argc, char **argv);
        bool isPrimary() const;
        bool isSecondary() const;
    
    signals:
        void instanceStarted();
    
    private:
        QLocalServer *m_server;
        QString m_serverName;
        bool m_isPrimary;
    };

    Implementation highlights (patch 0008-add-compatible-singleapp-implementation.patch):

    CompatibleSingleApp::CompatibleSingleApp(int &argc, char **argv)
        : QApplication(argc, argv), m_isPrimary(false) {
    
        m_serverName = "stremio-" + QString(qgetenv("USER"));
    
        // Try to connect to existing instance
        QLocalSocket socket;
        socket.connectToServer(m_serverName);
    
        if (socket.waitForConnected(500)) {
            // Secondary instance - notify primary and exit
            m_isPrimary = false;
            socket.write("ACTIVATE");
            socket.waitForBytesWritten();
            return;
        }
    
        // Primary instance - create server
        m_isPrimary = true;
        m_server = new QLocalServer(this);
        m_server->listen(m_serverName);
    
        connect(m_server, &QLocalServer::newConnection, this, [this]() {
            QLocalSocket *client = m_server->nextPendingConnection();
            connect(client, &QLocalSocket::readyRead, [this, client]() {
                QByteArray data = client->readAll();
                if (data == "ACTIVATE") {
                    emit instanceStarted();
                }
                client->deleteLater();
            });
        });
    }

    Result: Perfect single-instance behavior using pure QApplication (no threading conflicts) with QLocalSocket/QLocalServer for IPC.

    Binary size: 424KB debug vs 293KB release—both using 100% system libraries.

    Key lesson: System libraries may have different implementation details (like threading models) even when providing the same API. Sometimes a custom minimal implementation is cleaner than patching around incompatibilities.

    Challenge 3: The Missing QML Modules

    Symptom: After fixing both initialization and threading issues, the application launched but showed a black screen with console errors:

    module "QtWebEngine" is not installed
    module "QtWebChannel" is not installed
    module "Qt.labs.platform" is not installed

    The problem: Qt5 QML modules are separate runtime packages in Debian, not automatically pulled in by qtdeclarative5-dev.

    The investigation: Stremio’s QML code imports numerous Qt modules:

    import QtQuick 2.12
    import QtQuick.Controls 2.12
    import QtWebEngine 1.10
    import QtWebChannel 1.0
    import Qt.labs.platform 1.1
    import Qt.labs.settings 1.0

    Each requires a separate Debian package.

    The solution: Comprehensive dependency mapping in debian/control:

    Depends: ${shlibs:Depends}, ${misc:Depends},
             qml-module-qtwebengine,
             qml-module-qtwebchannel,
             qml-module-qt-labs-platform,
             qml-module-qtquick-controls,
             qml-module-qtquick-dialogs,
             qml-module-qt-labs-settings,
             qml-module-qt-labs-folderlistmodel,
             qtbase5-dev-tools

    Lesson: When packaging Qt QML applications, trace every QML import statement to its corresponding Debian package. apt-file search is your friend:

    $ apt-file search QtWebEngine.qml
    qml-module-qtwebengine: /usr/lib/x86_64-linux-gnu/qt5/qml/QtWebEngine/...

    Challenge 4: The Streaming Server Mystery

    Symptom: GUI loads perfectly, but when trying to play media:

    Error while starting streaming server
    tcp: Connection to tcp://127.0.0.1:11470 failed: Connection refused

    The investigation: Stremio includes a Node.js server component (server.js) for streaming. The shell process log showed:

    TypeError [ERR_INVALID_ARG_TYPE]: The "path" argument must be of type string. Received undefined
        at Object.join (node:path:1292:7)

    The root cause: Qt’s QProcess doesn’t inherit environment variables by default. The Node.js server expected HOME, USER, and PWD to be available, but they weren’t.

    The fix (patch 0011-fix-qprocess-environment-for-server-launch.patch):

    // stremioprocess.cpp
    void Process::start() {
        // Set up environment variables for Node.js server
        QProcessEnvironment env = QProcessEnvironment::systemEnvironment();
    
        if (!env.contains("HOME")) {
            env.insert("HOME",
                QStandardPaths::writableLocation(QStandardPaths::HomeLocation));
        }
        if (!env.contains("USER")) {
            env.insert("USER", qgetenv("USER"));
        }
        if (!env.contains("PWD")) {
            env.insert("PWD", QDir::currentPath());
        }
    
        this->setProcessEnvironment(env);
        QProcess::start();
    }

    Result: Server starts successfully:

    hls executables located -> { ffmpeg: '/usr/bin/ffmpeg', ffsplit: null }
    Using app path -> /home/user/.stremio-server
    EngineFS server started at http://127.0.0.1:11470

    Lesson: When spawning processes from Qt applications, explicitly configure the environment. Don’t assume child processes inherit the parent’s environment variables.

    Challenge 5: Debian Packaging Structure Pitfalls

    Symptom: Package builds successfully, but files install to wrong locations or with wrong names.

    The problem: Misunderstanding debhelper’s .install file behavior.

    What I thought:

    # debian/stremio.install
    build/stremio usr/bin/stremio-bin    # Install as /usr/bin/stremio-bin

    What actually happened:

    /usr/bin/stremio-bin/stremio    # Created DIRECTORY, file inside!

    The revelation: In debhelper .install files:

    • Path ending with / → Install files INTO that directory using original names
    • Path WITHOUT / → Create directory with that name and install files inside

    The correct solution (actual implementation):

    # debian/stremio.install
    # Binary installed to /usr/libexec (FHS 3.0 compliance for helper executables)
    build/stremio usr/libexec/stremio/
    
    # Wrapper script becomes the primary user-facing command
    debian/stremio-wrapper usr/bin/
    
    # Desktop file for application menu integration
    debian/stremio.desktop usr/share/applications/
    
    # Application icons (multiple resolutions for different contexts)
    icons/smartcode-stremio_16.png usr/share/icons/hicolor/16x16/apps/
    icons/smartcode-stremio_64.png usr/share/icons/hicolor/64x64/apps/
    # ... (additional icon sizes)

    Why this structure?

    1. /usr/libexec/stremio/: Modern FHS 3.0 location for internal executables not meant to be called directly by users
    2. Wrapper script at /usr/bin/stremio: Sets environment variables (like QTWEBENGINE_DISABLE_SANDBOX=1) before launching the actual binary
    3. Trailing slashes: Install files INTO directories using original filenames—critical for correct placement

    Lesson: Read debhelper documentation carefully. Small syntax details (trailing slashes!) have big consequences. Modern Debian packaging also follows FHS 3.0 standards, placing helper binaries in /usr/libexec/ rather than /usr/bin/.

    The Meta-Lesson: Efficient Patch Development

    The technical challenges were difficult, but I made them harder through inefficient workflow. I created patches, tested them, found they failed on clean upstream, then reworked them—five times.

    The problem: I was testing patches against already-modified sources, not pristine upstream.

    Build System Strategy: Patch CMakeLists.txt First

    Critical principle: Always prioritize build system patches over source code modifications.

    When replacing bundled dependencies with system libraries, the first patches should target CMakeLists.txt:

    # Patch 0005-cmake-system-libraries-v4.4.169.patch
    find_package(PkgConfig REQUIRED)
    pkg_check_modules(MPV REQUIRED mpv)
    find_package(Qt5 REQUIRED COMPONENTS Core Gui Qml Quick WebEngine DBus)
    find_package(OpenSSL REQUIRED)

    Why this matters: Smaller, focused patches that address build system integration separately from source code changes are easier to maintain and review.

    Build system preference: We used qmake to generate makefiles first (Stremio’s traditional build system), then ensured CMake compatibility. The stremio.pro file and release.makefile workflow took precedence for package builds.

    The Anti-Pattern

    1. Modify source files directly to fix issue
    2. Generate patches from modified state
    3. Try to apply patches to clean upstream
    4. Patches fail (missing context, wrong line numbers, missing dependencies)
    5. Repeat

    The Efficient Workflow I Should Have Used

    # 1. Start with clean upstream
    git checkout v4.4.169
    
    # 2. Create isolated test environment
    cp -r . /tmp/patch-test/
    cd /tmp/patch-test/
    
    # 3. Fix ONE issue, test, generate patch
    # (fix QtWebEngine initialization)
    mkdir build && cd build && cmake .. && make    # Test build
    cd .. && git diff > 0001-qtwebengine-init.patch
    
    # 4. Apply patch to clean upstream, fix next issue
    git checkout v4.4.169
    patch -p1 < 0001-qtwebengine-init.patch
    # (fix next issue)
    git diff > 0002-next-fix.patch
    
    # 5. Final validation: apply all patches to clean upstream
    git checkout v4.4.169
    for patch in *.patch; do
        patch -p1 < $patch || exit 1
    done
    mkdir build && cd build && cmake .. && make

    Dependency analysis checklist I wish I’d used from the start:

    ## Pre-Patch Analysis Template
    
    ### Files to Modify:
    - [ ] main.cpp - entry point changes
    - [ ] mainapplication.h - class definitions, includes
    - [ ] CMakeLists.txt - build system
    - [ ] compatible_singleapp.h/cpp - new files
    
    ### Dependency Chain:
    1. main.cpp includes → mainapplication.h
    2. mainapplication.h includes → singleapplication.h (to replace)
    3. CMakeLists.txt references → SingleApplication library
    4. Qt MOC will process → Q_OBJECT classes (check conflicts!)
    
    ### Build Test Plan:
    - [ ] Clean cmake build
    - [ ] ldd dependency verification
    - [ ] Runtime basic functionality

    Time saved if I’d done this from the start: ~70% reduction in patch development time.

    Key insight: Understand file dependencies and build system BEFORE making changes. Test patches against clean upstream at each step, not just at the end.

    The Complete Patch Set

    The final working solution consists of 11 patches:

    1. 0001-Fix-server.js-path-for-FHS-compliance.patch – Server location
    2. 0002-disable-server-download.patch – Use system Node.js
    3. 0004-minimal-qthelper-integration.patch – System Qt utilities
    4. 0005-cmake-system-libraries-v4.4.169.patch – MPV, OpenSSL integration
    5. 0007-add-qtwebengine-initialize-fix.patchCritical: QtWebEngine initialization
    6. 0008-add-compatible-singleapp-implementation.patchCritical: Custom single-instance
    7. 0009-remove-system-singleapplication-add-compatible.patch – Build integration
    8. 0010-fix-qmake-install-paths.patch – Install location fixes
    9. 0011-fix-qprocess-environment-for-server-launch.patchCritical: Server environment

    Validation Workflow

    The final validation workflow ensures patches work on clean upstream, using the GBP (git-buildpackage) import workflow for proper Debian package building:

    # Step 1: Create pristine test environment with GBP structure
    git clone --branch v4.4.169 https://github.com/Stremio/stremio-shell.git /tmp/validation
    cd /tmp/validation
    cp -r /path/to/debian .
    
    # Step 2: Apply all patches using quilt
    export QUILT_PATCHES=debian/patches
    quilt push -a
    
    # Step 3: Test local build first (fastest iteration)
    QT_DEFAULT_MAJOR_VERSION=5 dpkg-buildpackage -us -uc
    
    # Step 4: Verify dependencies
    ldd debian/stremio/usr/libexec/stremio/stremio | head -5
    # Should show: libQt5WebEngine.so.5, libcrypto.so.3, libmpv.so.2
    
    # Step 5: Test with pbuilder (clean chroot environment)
    sudo pbuilder update
    sudo pbuilder build ../*.dsc
    
    # Step 6: Test with sbuild (production-grade build)
    # WARNING: Qt5/WebEngine packages consume significant space
    # Typical requirement: 4-6GB build space (overlayfs in tmpfs)
    # Solution: Use machine with 16GB+ RAM or configure sbuild on disk
    
    sbuild -d unstable ../*.dsc
    # If sbuild fails with "No space left on device":
    # - Switch to larger machine (16GB+ RAM recommended)
    # - Or configure sbuild to use disk instead of tmpfs

    Build Environment Considerations

    Memory requirements for Qt5 applications:

    • dpkg-buildpackage: ~2GB RAM
    • pbuilder: ~4GB RAM
    • sbuild with overlayfs in tmpfs: 6-8GB RAM (Qt5WebEngine is memory-intensive)

    Our solution: After encountering space exhaustion on 8GB machines during sbuild, we migrated to a 32GB machine. This is typical for Qt5/WebEngine applications—always test sbuild capacity before committing to build infrastructure.

    Result: 293KB optimized binary, 100% system libraries, full functionality including streaming.

    Lessons for Other Packagers

    Technical Takeaways

    1. Initialization order matters: System libraries may have different startup requirements than bundled ones. Always verify initialization sequences.
    2. Threading models vary: Even libraries with identical APIs may use different threading approaches. Watch for cross-thread object creation errors.
    3. Environment variables aren’t automatic: QProcess and similar mechanisms need explicit environment setup.
    4. QML modules are separate packages: Trace every QML import to its Debian package dependency.
    5. Custom implementations beat complex patches: Sometimes writing 100 lines of clean code is better than a 500-line patch to an incompatible library.

    Process Takeaways

    1. Always test patches against clean upstream: Never generate patches from already-modified sources.
    2. Map dependencies before coding: Understand file relationships and build system before making changes.
    3. One fix, one patch, one test: Incremental development prevents cascading failures.
    4. Document assumptions: What works «by accident» with bundled libraries may fail with system ones.
    5. Validate completely: Test patches in isolated environments before declaring them «ready».

    Conclusion

    Packaging Stremio for Debian taught me far more than Qt5 internals and build system integration. It revealed how easily we fall into inefficient workflows when we don’t step back to examine our process.

    The technical achievement: A fully functional Debian package using 100% system libraries where the upstream used bundled dependencies—293KB binary, zero submodules, complete feature parity.

    The real achievement: Learning that the how of problem-solving matters as much as the what. Efficient patch development isn’t just about technical skill—it’s about disciplined workflow, systematic thinking, and honest self-assessment.

    Would I do anything differently? Absolutely. I’d use the validation workflow from day one, map dependencies before coding, and test each patch against clean upstream immediately.

    But would I have learned these lessons without making the mistakes? Probably not.

    Acknowledgments

    Thanks to the Stremio team for creating great software, the Debian community for maintaining high standards, my friend Arturo (a Debian Developer) that knowing my passion for Debian encouraged me to start working as a Debian Maintainer, and to every packager who has documented their struggles—your war stories make ours easier.


    Project Status (as of October 3, 2025)

    Note: This article documents the technical process and challenges. Package acceptance is pending Debian review. Status updates will be posted as the review process continues.


    This article is part of my journey toward becoming a Debian Developer. If you’re interested in Debian packaging or have questions about the technical details, feel free to reach out.

  • Emacs Meeting Reloaded

    Emacs Meeting Reloaded

    Tras una charla sobre MongoDB en Sevilla, me entero a través del canal #emacs-es de Freenode que vamos a organizar otro Emacs Meeting en Madrid!

    Más información en: http://atlacaba.net/node/12

    ¡No teníamos uno de estos desde el 2008! ¡Casi 6 años ya! He aquí una foto como memento de aquel día.

    2008-12-16-emacs-es

     

     

    Artículo relacionado: Anuncio del Emacs Meeting #1 en el año 2008 en Sevilla
    https://vejeta.com/encuentro-de-usuarios-de-emacs-en-el-hacklab-de-sevilla/

Creative Commons License
Except where otherwise noted, the content on this site is licensed under a Creative Commons Attribution-NonCommercial-ShareAlike 4.0 International License.