Mise

Mise est un "tooling version management", il permet d'installer la plupart des outils nécessaire au bon fonctionnement d'un development environment. Il permet de "pin" les versions précises de ces outils.

Avec direnv et Docker, Mise fait parti des briques de fondactions que j'utilise pour créer mes development kit.

Site officiel : https://mise.jdx.dev

Alternative à Asdf et aqua


Journaux liées à cette note :

Journal du mardi 25 février 2025 à 14:20 #JaiDécouvert, #OnMaPartagé, #mise, #asdf, #dev-kit

Alexandre vient de partager ce thread : « Asdf Version Manager Has Been Re-Written in Golang »

Je découvre que Asdf n'est pas mort ! La version 0.16.0 publié le 30 janvier 2025 a été réécrite en Golang !

La raison principale semble être une volonté d'amélioration de la vitesse de Asdf :

With improvements ranging from 2x-7x faster than asdf version 0.15.0!

source

Depuis cette date, Mise a publié un benchmark qui compare la vitesse d'exécution de Asdf et Mise : https://mise.jdx.dev/dev-tools/comparison-to-asdf.html#asdf-in-go-0-16.

Comme mon ami Alexandre, certains utilisateurs sont inquiets de voir Mise faire trop de choses :

I tried mise a while back, and the main reason I went away from it is like you said, it does too much. It tries to be asdf, direnv and a task runner. I just want a tool manager, and is the reason why I switched to aquaproj/aqua.

source

J'ai migré de Asdf vers Mise en novembre 2023 et pour le moment, je n'ai pas envie, ni de raison pratique particulière pour retourner à Asdf.
De plus, je suis plutôt satisfait d'avoir remplacé direnv par Mise, voir Je pense pouvoir maintenant remplacer Direnv par Mise 🤞.

Je découvre Fastlane #JaiDécouvert, #iOS, #Android, #MobileDev, #InfrastructureAsCode

Je viens de découvrir le projet Fastlane (https://fastlane.tools/).

fastlane is the easiest way to automate beta deployments and releases for your iOS and Android apps. 🚀 It handles all tedious tasks, like generating screenshots, dealing with code signing, and releasing your application.

source

Je pense que c'est l'outil qui me manquait pour suivre le paradigme configuration as code dans mon "Projet 17 - Créer un POC de création d'une app smartphone avec Capacitor".

Il supporte Android et iOS.

Ce projet a commencé en 2014 par Felix Krause et repris par Google en 2017 : « fastlane is joining Google - Felix Krause ».

Mais, je découvre que Google semble avoir arrêter de financer le développement du projet en 2023 : Google is no longer sponsoring Fastlane | Hacker News.

Depuis, le projet semble être toujours actif avec de nombreuses release : https://github.com/fastlane/fastlane/releases.

Fonctionnalités de Fastlane qui m'intéressent tout particulièrement :

Fastlane permet aussi d'automatiser de nombreuses autres tâches que je n'ai pas encore pris le temps d'explorer : https://docs.fastlane.tools/actions/.


Installation de Fastlane avec Mise que j'ai testée sous Fedora et MacOS :

[tools]
ruby = '3.1.6' # for fastlane
fastlane = "2.226.0"

[alias]
fastlane = "https://github.com/mollyIV/asdf-fastlane.git"

(Toujours aussi pénibles ces outils développés en Ruby 😔)

À noter que sous MacOS j'ai dû lancer :

$ mise install -f fastlane

Parce que lors du premier lancement de mise install, j'ai l'impression qu'il a essayé d'installer fastlane avec l'instance ruby native de l'OS.

J'ai cherché s'il existe une option pour préciser que fastlane doit utiliser ruby installé par Mise, mais je n'ai pas trouvé.


17:05 - Solution pour contourner le problème mentionné ci-dessus :

$ mise install ruby
$ mise install

Journal du mercredi 05 février 2025 à 18:32 #OnMaPartagé, #JaiDécouvert, #python, #package, #mise

Un ami m'a fait découvrir uv (https://github.com/astral-sh/uv).

An extremely fast Python package and project manager, written in Rust.

source

Je trouve cela amusant de constater que Rust prend en charge de plus en plus d'outils pour différents langages 😉.

Le projet a commencé fin 2023.

Voici un thread Hacker News de 200 commentaires à ce sujet qui date de février 2024 : Uv: Python packaging in Rust .

L'article de ce thread contient beaucoup d'éléments intéressants : https://astral.sh/blog/uv

Son nom uv semble être une référence à uvloop.

J'en ai profité pour migrer le playground mise-python-flask-playground de pip vers uv : https://github.com/stephane-klein/mise-python-flask-playground/commit/2f1678798cfc6749dcfdb514a8fe4a3e54739844.

J'ai lancé une installation et effectivement, sa rapidité est très impressionnante :

$ uv pip install -r requirements.txt
Resolved 15 packages in 245ms
Prepared 15 packages in 176ms
Installed 15 packages in 37ms
 + alembic==1.14.1
 + blinker==1.9.0
 + click==8.1.8
 + flask==3.1.0
 + flask-migrate==4.1.0
 + flask-sqlalchemy==3.1.1
 + greenlet==3.1.1
 + itsdangerous==2.2.0
 + jinja2==3.1.5
 + mako==1.3.9
 + markupsafe==3.0.2
 + psycopg2-binary==2.9.10
 + sqlalchemy==2.0.37
 + typing-extensions==4.12.2
 + werkzeug==3.1.3

uv ne propose pas seulement une amélioration de l'installation de packages Python, mais propose beaucoup d'autres choses comme :

Pour cette partie, dans un but d'unification, je continuerai à utiliser Mise pour installer une version précise de Python. De plus, Mise intègre nativement UV : https://mise.jdx.dev/mise-cookbook/python.html#mise-uv

Exemple :

$ uv run example.py

Je pense avoir compris que cela lance ce script avec les dépendances du virtual environment du projet. Un peu comme fonctionne npm, yarn ou pnpm qui permet aux scripts d'utiliser les packages présents dans ./node_modules/.

Par exemple, le linter Python ruff, exemple :

$ uv tool run ruff

J'ai un peu parcouru la documentation de pyproject.toml : https://packaging.python.org/en/latest/guides/writing-pyproject-toml/.

J'ai lu aussi la section uv - Locking environments.

Suite à ces lectures, j'ai migré le playground mise-python-flask-playground vers pyproject.toml : https://github.com/stephane-klein/mise-python-flask-playground/commit/c17216464778df4bc00bf782d5a889cb3f198051.

Je ne suis pas certain que ces commandes soient une bonne pratique :

$ uv pip compile requirements.in -o requirements.txt
$ uv pip install -r requirements.txt

Playground qui présente comment je setup un projet Python Flask en 2025 #dev-kit, #python, #mise, #docker, #WSL, #playground, #software-engineering

Je pense que cela doit faire depuis 2015 que je n'ai pas développé une application en Python Flask !

Entre 2008 et 2015, j'ai beaucoup itéré dans mes méthodes d'installation et de setup de mes environnements de développement Python.

D'après mes souvenirs, si je devais dresser la liste des différentes étapes, ça donnerai ceci :

  • 2006 : aucune méthode, j'installe Python 🙂
  • 2007 : je me bats avec setuptools et distutils (mais ça va, c'était plus mature que ce que je pouvais trouver dans le monde PHP qui n'avait pas encore imaginé composer)
  • 2008 : je trouve la paie avec virtualenv
  • 2010 : j'ai peur d'écrire des scripts en Bash alors à la place, j'écris un script bootstrap.py dans lequel j'essaie d'automatiser au maximum l'installation du projet
  • 2012 : je me bats avec buildout pour essayer d'automatiser des éléments d'installation. Avec le recul, je réalise que je n'ai jamais rien compris à buildout
  • 2012 : j'utilise Vagrant pour fixer les éléments d'installation, je suis plutôt satisfait
  • 2015 : je suis radicale, j'enferme tout l'environnement de dev Python dans un container de développement, je monte un path volume pour exposer le code source du projet dans le container. Je bricole en entrypoint avec la commande "sleep".

Des choses ont changé depuis 2015.

Mais, une chose que je n'ai pas changée, c'est que je continue à suivre le modèle The Twelve-Factors App et je continue à déployer tous mes projets packagé dans des images Docker. Généralement avec un simple docker-compose.yml sur le serveur, ou alors Kubernetes pour des projets de plus grande envergure… mais cela ne m'arrive jamais en pratique, je travaille toujours sur des petits projets.

Choses qui ont changé : depuis fin 2018, j'ai décidé de ne plus utiliser Docker dans mes environnements de développement pour les projets codés en NodeJS, Golang, Python

Au départ, cela a commencé par uniquement les projets en NodeJS pour des raisons de performance.

J'ai ensuite découvert Asdf et plus récemment Mise. À partir de cela, tout est devenu plus facilement pour moi.
Avec Asdf, je n'ai plus besoin "d'enfermer" mes projets dans des containers Docker pour fixer l'environnement de développement, les versions…

Cette introduction est un peu longue, je n'ai pas abordé le sujet principal de cette note 🙂.

Je viens de publier un playground d'un exemple de projet minimaliste Python Flask suivant mes pratiques de 2025.

Voici son repository : mise-python-flask-playground

Ce playground est "propulsé" par Docker et Mise.

J'ai documenté la méthode d'installation pour :

Je précise que je n'ai pas eu l'occasion de tester l'installation sous Windows, hier j'ai essayé, mais je n'ai pas réussi à installer WSL2 sous Windows dans un Virtualbox lancé sous Fedora. Je suis à la recherche d'une personne pour tester si mes instructions d'installation sont valides ou non.

Briques technologiques présentes dans le playground :

Voici quelques petites subtilités.

Dans le fichier alembic.ini j'ai modifié le paramètre file_template parce que j'aime que les fichiers de migration soient classés par ordre chronologique :

[alembic]
# template used to generate migration files
file_template = %%(year)d%%(month).2d%%(day).2d_%%(hour).2d%%(minute).2d%%(second).2d_%%(slug)s

Ce qui donne par exemple :

20250205_124639_users.py
20250205_125437_add_user_lastname.py

Ici le port de PostgreSQL est généré dynamiquement par docker compose :

  postgres:
    image: postgres:17
	...
	ports:
      - 5432 # <= ici

Avec cela, fini les conflits de port quand je lance plusieurs projets en même temps sur ma workstation.

L'URL vers le serveur PostgreSQL est générée dynamiquement par le script get_postgres_url.sh qui est appelé par le fichier .envrc. Tout cela se passe de manière transparente.

J'initialise ici les extensions PostgreSQL :

def init_db():
    db.drop_all()
    db.session.execute(db.text('CREATE EXTENSION IF NOT EXISTS "uuid-ossp"'))
    db.session.execute(db.text('CREATE EXTENSION IF NOT EXISTS "unaccent"'))
    db.session.commit()
    db.create_all()

et ici dans la première migration :

def upgrade():
    op.execute('CREATE EXTENSION IF NOT EXISTS "uuid-ossp";')
    op.execute('CREATE EXTENSION IF NOT EXISTS "unaccent";')
    op.create_table('users',
        sa.Column('id', sa.Integer(), autoincrement=True, nullable=False),
        sa.Column('firstname', sa.String(), nullable=False),
        sa.PrimaryKeyConstraint('id')
    )

Journal du mardi 04 février 2025 à 16:46 #windows, #VirtualBox, #WSL, #JaiDécouvert

Je souhaite créer un playground d'un development kit pour Python + PostgreSQL (via Docker) + Flask + Flask-Migrate, basé sur Mise.

J'ai la contrainte suivante : le development kit doit fonctionner sous MS Windows !

Je me dis que c'est une bonne occasion pour moi de tester Windows Subsystem for Linux 🙂.

Problème : je ne possède pas d'instance MS Windows.

#JaiDécouvert que depuis 2015, Microsoft met à disposition des ISOs officiels de MS Windows :

J'ai testé dans ce playground le lancement d'une Virtual machine MS Windows avec Vagrant : https://github.com/stephane-klein/vagrant-windows-playground.

Cela a bien fonctionné 🙂.

J'ai aussi découvert le repository windows-vagrant qui semble permettre de construire différents types d'images MS Windows avec Packer. Je n'ai pas essayé d'en construire une.

Journal du jeudi 30 janvier 2025 à 12:02 ##JaiDécouvert, #DevOps, #linux, #aide-mémoire, #aide

Note de type #aide-mémoire : contrairement à ~/.zprofile, .zshenv est chargé même lors de l'exécution d'une session ssh en mode non interactif, par exemple :

$ ssh user@host 'echo "Hello, world!"'

Je me suis intéressé à ce sujet parce que mes scripts exécutés par ssh dans le cadre du projet /poc-capacitor/ n'avaient pas accès aux outils mis à disposition par Homebrew et Mise.

J'ai creusé le sujet et j'ai découvert que .zprofile était chargé seulement dans les cas suivants :

  • « login shell »
  • « interactive shell »

Un login shell est un shell qui est lancé lors d'une connexion utilisateur. C'est le type de shell qui exécute des fichiers de configuration spécifiques pour préparer l'environnement utilisateur. Un login shell se comporte comme si tu te connectais physiquement à une machine ou à un serveur.

Un shell interactif est un shell dans lequel tu peux entrer des commandes de manière active, et il attend des entrées de ta part. Un shell interactif est conçu pour interagir avec l'utilisateur et permet de saisir des commandes, d'exécuter des programmes, de lancer des scripts, etc.

ChatGPT

Suite à cela, dans ce commit "Move zsh config from .zprofile to .zshenv", j'ai déplacé la configuration de Homebrew et Mise de ~/.zprofile vers .zshenv.

Cela donne ceci une fois configuré :

$ cat .zshenv
eval "$(/opt/homebrew/bin/brew shellenv)"
eval "$(mise activate zsh)"

Mais, attention, « As /etc/zshenv is run for all instances of zsh ». Je pense que ce n'est pas forcément une bonne idée d'appliquer cette configuration sur une workstation, parce que cela peut "ralentir" légèrement le système en lançant inutilement ces commandes.

ChatGPT me conseille cette configuration pour éviter cela :

# Ne charge Brew et Mise que si on est dans un shell interactif ou SSH
if [[ -t 1 || -n "$SSH_CONNECTION" ]]; then
  eval "$(/opt/homebrew/bin/brew shellenv)"
  eval "$(mise activate zsh)"
fi

Journal du mardi 14 janvier 2025 à 15:08 #JaiDécouvert, #mise

Je viens de découvrir une nouvelle option de configuration Mise :

# .mise.toml
[tools]
node = "20.18.1"
"npm:typescript" = "5.7.3"

Comment l'indique la documentation de Mise, "npm:...." = "..." permet d'installer n'importe quel package npm dans un projet géré par Mise.

Concrètement, ici tsc est accessible directement dans le PATH dans le dossier où est placé .mise.toml.

Journal du jeudi 09 janvier 2025 à 13:13 #iteration, #devlog, #capacitor, #POC

Nouvelle #iteration sur le Projet 17 - Créer un POC de création d'une app smartphone avec Capacitor.

Je viens de push le commit feat(android): implemented webview and configured deeplinks. J'ai passé en tout, 11 heures sur cette itération.

Je souhaite, dans cette note de type DevLog, présenter les difficultés et les erreurs rencontrées dans cette itération.


Étape 1 : mise en place d'un dummy website totalement statique

The Capacitor application in this POC displays the content of a demonstration website, with the HTML content located in the ./dummy-website/ folder.
This website is served by an HTTP Nginx server, launched using docker-compose.yml.

source

Pour faire très simple, j'ai choisi de créer un faux site totalement statique, qui sera affiché dans une webview de l'application smartphone.

Ce site contient juste 2 pages HTML ; celui-ci est exposé par un serveur HTTP nginx, lancé via un docker-compose.yml.


Étape 2 : Expose dummy website on Internet

En première étape, j'ai dû mettre en place une méthode pour facilement exposer sur Internet un dummy website lancé localement :

Expose dummy website on Internet

Why?
The Android and iOS emulators do not have direct and easy access to the HTTP service (dummy website) exposed on http://localhost:8080.

To overcome this issue, I use "cloudflared tunnel". You can also use other solutions, such as sish or ngrok Developer Preview. For more information, you can refer to the following note (in French): 2025-01-06_2105

source

Comme expliqué ci-dessus, cette contrainte est nécessaire afin de permettre à l'émulateur Android et à l'émulateur iOS (lancé sur une instance Scaleway Apple Silicon) aussi bien que sur mon smartphone physique personnel, d'accéder aux dummy website avec un support https.

Ceci était d'autant plus nécessaire, pour remplir les contraintes de configuration de la fonctionnalité Deep Linking with Universal and App Links.

C'est pour cela que j'ai dernièrement publié les notes suivantes : 2024-12-28_1621, 2024-12-28_1710, 2024-12-31_1853 et Alternatives managées à ngrok Developer Preview.

Pour simplifier la configuration de ce projet (poc-capacitor), j'ai décidé d'utiliser "cloudflared tunnel" en mode non connecté.

J'ai installé cloudflared avec Mise (voir la configuration ici).

Pour rendre plus pratique le lancement et l'arrêt du tunnel cloudflare, j'ai implémenté deux scripts :

Voici ce que cela donne à l'usage :

$ ./scripts/start-cloudflare-http-tunnel.sh
Starting the tunnel...
…wait… …wait… …wait…
Tunnel started successfully: https://moral-clause-interesting-broadway.trycloudflare.com

To stop the tunnel, you can execute:

$ ./scripts/stop-cloudflare-http-tunnel.sh
Stopping the tunnel (PID: 673143)...
Tunnel stopped successfully.

source


Étape 3 : configuration de la webview Capacitor

En réalité, par erreur, j'ai configuré la webview Capacitor après l'implémentation de la partie App links.

Au départ, je pensais qu'un simple window.location.href = process.env.START_URL; était suffisant pour afficher le site web dans l'application. En réalité, cette commande a pour effet d'ouvrir la page HTML dans le browser par défaut du smartphone. Je ne m'en étais pas tout de suite rendu compte.

Dans Capacitor, pour créer une webview dans une application, il est nécessaire l'utiliser la fonction InAppBrowser.openInWebView(... du package @capacitor/inappbrowser.

Voici l'implémentation dans le fichier /src/js/online-webview.js :

window.Capacitor.Plugins.InAppBrowser.openInWebView({
	url: startUrl,
	options: {
		// See https://github.com/ionic-team/capacitor-os-inappbrowser/blob/e5bee40e9b942da0d4dad872892f5e7007d87e75/src/defaults.ts#L33
		// Constant values are in https://github.com/ionic-team/capacitor-os-inappbrowser/blob/e5bee40e9b942da0d4dad872892f5e7007d87e75/src/definitions.ts
		showToolbar: false,
		showURL: false,

		clearCache: true,
		clearSessionCache: true,
		mediaPlaybackRequiresUserAction: false,

		// closeButtonText: 'Close',
		// toolbarPosition: 'TOP', // ToolbarPosition.TOP

		// showNavigationButtons: true,
		// leftToRight: false,
		customWebViewUserAgent: 'capacitor webview',

		android: {
			showTitle: false,
			hideToolbarOnScroll: false,
			viewStyle: 'BOTTOM_SHEET', // AndroidViewStyle.BOTTOM_SHEET

			startAnimation: 'FADE_IN', // AndroidAnimation.FADE_IN
			exitAnimation: 'FADE_OUT', // AndroidAnimation.FADE_OUT
			allowZoom: false
		},
		iOS: {
			closeButtonText: 'DONE',           // DismissStyle.DONE
			viewStyle: 'FULL_SCREEN',          // iOSViewStyle.FULL_SCREEN
			animationEffect: 'COVER_VERTICAL', // iOSAnimation.COVER_VERTICAL
			enableBarsCollapsing: true,
			enableReadersMode: false
		}
	}
});

source

Les paramètres dans options permettent de configurer la webview. J'ai choisi de désactiver un maximum de fonctionnalités.

En implémentant cette partie, j'ai rencontré trois difficultés :

  • Avec la version 1.0.2 du packages, j'ai rencontré ce bug "Bug- Android App crashing after adding this plugin, j'ai perdu presque 1 heure avant de le découvrir, pour fixer cela, j'ai choisi le QuickWin d'installer la version 1.0.1.
  • J'ai mis un peu de temps pour trouver les paramètres passés dans options
  • J'ai trouvé allowZoom: false pour supprimer l'affichage des boutons de zoom dans la webview

Étape 4 : setup de la partie App Links

Après avoir lu la page "Deep Linking with Universal and App Links", c'était la partie que je trouvais la plus difficile, mais en pratique, ce n'est pas très compliqué.

J'ai passé 5h30 sur cette partie, mais j'ai fait plusieurs erreurs.

Cette configuration se passe en 3 étapes.

Génération du fichier .well-known/assetlinks.json

La première consiste à générer le fichier le fichier dummy-website/.well-known/assetlinks.json qui est exposé par le serveur HTTP du dummy website.

Cette opération est documentée dans la partie "Create Site Association File".

Son contenu ressemble à ceci :

[
  {
    "relation": [
        "delegate_permission/common.handle_all_urls"
    ],
    "target": {
      "namespace": "android_app",
      "package_name": "$PACKAGE_NAME",
      "sha256_cert_fingerprints": ["$SHA256_FINGERPRINT"]
    }
  }
]

Il a une fonction de sécurité, il permet d'éviter de créer des applications malveillantes qui s'ouvriraient automatiquement sur des URLs sans lien avec l'application.

Il permet de dire « l'URL de ce site web peut automatiquement ouvrir l'application $PACKAGE_NAME » qui est signée avec la clé publique $SHA256_FINGERPRINT.

J'ai implémenté le script /scripts/generate-dev-assetlinks.sh qui permet automatiquement de générer ce fichier.

Lorsque j'ai travaillé sur cette partie, j'ai fait l'erreur de générer un certificat (voir le script /scripts/generate-dev-assetlinks.sh). Or, ce n'est pas la bonne méthode en mode développement.
Par défaut, Android met à disposition un certificat de développement dans ${HOME}/.android/debug.keystore.

La commande suivante me permet d'extraire la clé publique :

SHA256_FINGERPRINT=$(keytool -list -v \
  -keystore "${HOME}/.android/debug.keystore" \
  -alias "androiddebugkey" \ # password par défaut
  -storepass "android" 2>/dev/null | grep "SHA256:" | awk '{print $2}')

source

Configuration de AndroidManifest.xml

Comme indiqué ici, voici les lignes que j'ai ajoutées dans /android/app/src/main/AndroidManifest.xml.tmpl :

<intent-filter android:autoVerify="true">
   <action android:name="android.intent.action.VIEW" />
   <category android:name="android.intent.category.DEFAULT" />
   <category android:name="android.intent.category.BROWSABLE" />
   <data android:scheme="https" />
   <data android:host="{{ .Env.ALLOW_NAVIGATION }}" />
</intent-filter>

source

Petite digression sur mon usage des templates dans ce projet.

J'utilise gomplate pour générer des fichiers dynamiquement à partir de 4 templates (.tmpl) et des variables d'environnement configurées entre autres dans .envrc.

La génération des fichiers se trouve ici :

gomplate -f capacitor.config.json.tmpl -o capacitor.config.json
gomplate -f android/app/build.gradle.tmpl -o android/app/build.gradle
gomplate -f android/app/src/main/AndroidManifest.xml.tmpl -o android/app/src/main/AndroidManifest.xml
gomplate -f android/app/src/main/strings.xml.tmpl -o android/app/src/main/res/values/strings.xml

source

Les principaux éléments dynamiques sont :

export APP_NAME=myapp
export PACKAGE_NAME="xyz.sklein.myapp"
export START_URL=$(cat .cloudflared_tunnel_url)
export ALLOW_NAVIGATION=$(echo "$START_URL" | sed -E 's#https://([^/]+).*#\1#')

START_URL contient l'URL publique générée par cloudflared tunnel qui change à chaque lancement du tunnel.

Support deep links via l'interception de l'événement appUrlOpen

Troisième étape de la configuration de App links.

let timeoutId = setTimeout(() => {
	openInWebView(process.env.START_URL);
}, 200);

window.Capacitor.Plugins.App.addListener('appUrlOpen', (event) => {
	clearTimeout(timeoutId);
	openInWebView(event.url);
});

source

Cela permet d'implémenter la fonction deep links. Exemple : si l'utilisateur du smartphone clique sur l'URL https://dummysite/deep/ alors l'application va directement s'ouvrir sur la page /deep/ du dummy website.

Commandes utiles

La commande suivante permet de demander à l'OS Android de lancer une nouvelle "vérification" du fichier dummy-website/.well-known/assetlinks.json :

$ adb shell pm verify-app-links --re-verify ${PACKAGE_NAME}

source

Note : le fichier .cloudflared_tunnel_url contient l'URL du tunnel cloudflare qui expose le dummy website.

La commande suivante permet d'afficher la configuration actuelle App Link d'une application :

$ adb shell pm get-app-links ${PACKAGE_NAME}
  xyz.sklein.myapp:
    ID: 100ba7e3-b978-49ac-926c-8e6ec6810f5c
    Signatures: [AF:AE:25:7F:ED:98:49:A3:E0:23:B3:BE:92:08:84:A5:82:D1:80:AA:E0:A4:A3:D3:A0:E2:18:D6:70:05:67:ED]
    Domain verification state:
      association-pending-belt-acute.trycloudflare.com: verified

source

La commande suivante permet de tester le lancement de l'application à partir d'une URL passée en paramètre :

$ adb shell am start -W -a android.intent.action.VIEW -d "$(cat .cloudflared_tunnel_url)"
Starting: Intent { act=android.intent.action.VIEW dat=https://sc-lo-welsh-injury.trycloudflare.com/... }
Status: ok
LaunchState: COLD
Activity: xyz.sklein.myapp/.MainActivity
TotalTime: 1258
WaitTime: 1266
Complete

source

Cela fonctionne aussi avec une sous-page, par exemple : "$(cat .cloudflared_tunnel_url)/deep/?query=foobar".

Dans l'émulateur, Chrome ne lance pas les App Link !

Je pense que ce piège m'a fait perdre 2 h (sur les 5 h passées sur cette implémentation) !

Si j'ouvre l'URL du dummy website dans Chrome, l'application n'est pas lancée.

Mais, si j'ouvre l'URL dans l'application qui se nomme "Google", celle accessible via la barre de recherche en bas ce ce screenshot, l'App Link est bien pris en compte.

Problème : je testais mon application seulement dans Chrome. Et la fonctionnalité App Links ne fonctionnait pas. C'est seulement quand j'ai installé l'application sur mon smartphone physique personnel que j'ai constaté que App Links fonctionnait sous "Firefox Android".

J'ai constaté aussi que sur mon smartphone, Chrome n'ouvrait aucune application sur les URLs youtube.com, reddit.com, github.com

D'après ce que je pense avoir compris, la liste des applications qui peuvent ouvrir les App Links est listée dans la section "Settings => Apps => Default apps" :

J'ai fait des expériences sur 3 différents smartphones Android d'amis et à ce jour, je n'ai pas encore compris comment cela fonctionne. J'ai l'impression que c'est lié au browser par défaut configuré, mais j'ai trouvé des exceptions.

En tout cas, ce piège m'a fait perdre beaucoup de temps !


Note finale

Pour le moment, je n'ai pas eu besoin de configurer @capacitor/app-launcher, mais je pense que cela sera utile pour permettre à l'application d'ouvrir d'autres applications à partir d'une URL.

J'ai scripté pratiquement toutes les actions de ce projet.

ChatGPT m'a bien servi tout au long de cette implémentation.

Je pense pouvoir maintenant remplacer Direnv par Mise 🤞 #dev-kit, #DevOps, #direnv, #mise, #diff

Le 6 novembre 2024, j'ai publié la note "Le support des variables d'environments de Mise est limité, je continue à utiliser direnv".

L'issue indiquée dans cette note a été cloturée il y a 3 jours : Use mise tools in env template · Issue #1982.

Voici le contenu de changement de la documentation : https://github.com/jdx/mise/pull/3598/files#diff-e8cfa8083d0343d5a04e010a9348083f7b64035c407faa971074c6f0e8d0d940

Ce qui signifie que je vais pouvoir maintenant utiliser terraform installé via Mise dans le fichier .envrc :

[env]
_.source = { value = "./.envrc.sh", tools = true }

[tools]
terraform="1.9.8"

Après avoir installé la dernière version de Mise, j'ai testé cette configuration dans repository suivant : install-and-configure-mise-skeleton.

Le fichier .envrc suivant a fonctionné :

export HELLO_WORLD=foo3
export NOW=$(date)
export TERRAFORM_VERSION=$(terraform --version | head -n1)

Exemple :

$ mise trust
$ echo $TERRAFORM_VERSION
Terraform v1.9.8

Je n'ai pas trouvé de commande Mise pour recharger les variables d'environnement du dossier courant, sans quitter le dossier. Avec direnv, pour effectuer un rechargement je lançais : direnv allow.

À la place, j'ai trouvé la méthode suivante :

$ source .envrc

Je pense pouvoir maintenant remplacer Direnv par Mise 🤞.

Journal du mercredi 04 décembre 2024 à 14:56 #dev-kit, #software-engineering

Alexandre a eu un breaking change avec Mise : https://github.com/jdx/mise/issues/3338.

Suite à cela, j'ai découvert que Mise va prévilégier l'utilisation du backend aqua plutôt que Asdf :

we are actively moving tools in the registry away from asdf where possible to backends like aqua and ubi which don't require plugins.

source

J'ai découvert au passage que Mise supporte de plus en plus de backend, par exemple Ubi et vfox.

Je constate qu'il commence à y avoir une profusion de "tooling version management" : Asdf,Mise, aqua, Ubi, vfox !
Je pense bien qu'ils ont chacun leurs histoires, leurs forces, leurs faiblesses… mais j'ai peur que cela me complique mon affaire : comment arriver à un consensus de choix de l'un de ces outils dans une équipe 🫣 ! Chaque développeur aura de bons arguments pour utiliser l'un ou l'autre de ces outils.

Constatant plusieurs fois que le développeur de Mise a fait des breaking changes qui font perdre du temps aux équipes, mon ami et moi nous sommes posés la question si, au final, il ne serait pas judicieux de revenir à Asdf.

D'autre part, au départ, Mise était une simple alternative plus rapide à Asdf, mais avec le temps, Mise prend en charge de plus en plus de fonctionnalités, comme une alternative à direnv , un système d'exécution de tâches, ou mise watch.
Souvent, avec des petits défauts très pénibles, voir par exemple, ma note "Le support des variables d'environments de Mise est limité, je continue à utiliser direnv".

Alexandre s'est ensuite posé la question d'utiliser un jour le projet devenv, un outil qui va encore plus loin, basé sur le système de package Nix.

Le projet devenv me fait un peu peur au premier abord, il gère "tout" :

Il fait énormément de choses et je crains que la barrière à l'entrée soit trop haute et fasse fuir beaucoup de développeurs 🤔.

Tout cela me fait un peu penser à Bazel (utilisé par Google), Pants (utilisé par Twitter), Buck (utilisé par Facebook) et Please.
Tous ces outils sont puissants, je les ai étudiés en 2018 sans arrivée à les adopter.

Pour le moment, mes development kit nécessitent les compétences suivantes :

  • Comprendre les rudiments d'un terminal Bash ;
  • Arriver à installer et à utiliser Mise et direnv ;
  • Maitriser Docker ;
  • Savoir lire et écrire des scripts Bash de niveau débutant.

Déjà, ces quatre prérequis posent quelques fois des difficultés d'adoption.