Go get and Fork – script helper workaround

Why

If you write some Golang code, from my point of view, one of biggest pitfall of this language is dependency management.

At the beginning, get library directly from git repository seems a good idea, but between package rules, versions, your pull requests, it becomes a mess quickly.

Some sources on this problem:
Article: Forking Golang repositories on GitHub and managing the import path

StackOverflow : Using forked package import in Go

My workaround

Then, why not automate this procedure ?
In your .bashrc add:

function gofork() {
  if [ $# -ne 2 ] || [ -z "$1" ] || [ -z "$2" ]; then
    echo 'Usage: gofork yourFork originalModule'
    echo 'Example: golang github.com/YourName/go-contrib github.com/heirko/go-contrib'
    return
  fi
   echo "Go get fork $1 and replace $2 in GOPATH: $GOPATH"
   go get $1
   go get $2
   currentDir=$PWD
   cd $GOPATH/src/$1
   remote1=$(git config --get remote.origin.url)
   cd $GOPATH/src/$2
   remote2=$(git config --get remote.origin.url)
   cd $currentDir
   rm -rf $GOPATH/src/$2
   mv $GOPATH/src/$1 $GOPATH/src/$2
   cd $GOPATH/src/$2
   git remote add their $remote2
   echo Now in $GOPATH/src/$2 origin remote is $remote1
   echo And in $GOPATH/src/$2 their remote is $remote2
   cd $currentDir
}

export -f gofork

This command do

  • a ‘go get’ on source and fork repositories
  • extract remote urls
  • replace source code by fork
  • add source remote to your fork repository in case you want pull from source

You can call this script from command line or directly from a script like this:

gofork github.com/heralight/baloo gopkg.in/h2non/baloo.v2

DEBIAN: Créer des paquets debian vides pour palier aux problèmes de dépendances

Comme beaucoup, je suis sous Ubuntu.

Cet OS est très bien conçu, par contre certains paquets ont quelques fois des dépendances un peu farfelues, voir qui vous bouffent des ressources inutilement.

Si comme moi, vous n’utilisez pas le bluetooth, le supprimer est difficile.
Il faudrait, entre autre, se priver de unity-desktop…

Bref, fin du Blabla…

Pour forcer la suppression d’un paquet sans désinstaller les paquets en dépendant:

$ sudo dpkg -r --force-depends package

Par exemple:

$ sudo dpkg -r --force-depends rfkill gnome-bluetooth bluez bluez-alsa gnome-orca network-manager-pptp network-manager-pptp-gnome speech-dispatcher indicator-bluetooth

Maintenant vous avez plein de paquets cassés… pas bien Alexandre!

Pour remédier à ce problème, une solution consiste à installer des paquets résolvant ces dépendances perdues, mais ces derniers seront vides, en gros des « dummy packages ».

Pour créer ces paquets, vous devrez par exemple utiliser equivs-control et equivs-build ou mon script.

La commande:

$ ./gen-dummy-package.sh --install|i [packageName]+
# Par exemple:
$ ./gen-dummy-package.sh -i rfkill nome-bluetooth bluez

Le « -i » va effectuer une installation du paquet nouvellement créé.

Le script complet:

Nuget – Bonnes Pratiques

Pourquoi choisir Nuget ?

Prenons une situation classique d’un développement en entreprise…

Contexte:

  • Nombreux projets
  • nombreuses libs communes interdépendantes
  • peu ou pas de stockage partagé ou mal utilisé
  • Svn ou Git

Sans Nuget

  • bibliothèques communes éparpillées sur chaque poste en différentes versions
  • plusieurs répertoires de bibliothèques communes avec leurs dépendances mélangées et incomplètes, avec pour seuls critères le nom du fichier dll et son numéro dans les propriétés du fichier.
  • Chaque développeur va compiler ces bibliothèques sans formalisme particulier à partir du gestionnaire de source, impossible de savoir quel version est réellement utilisée dans le projet, la version a-t’elle bien été incrémentée? …etc.
  • une bibliothèque X dépend de A en version 1.0 seulement, une bibliothèque Y dépend de A en version 2 ou +, le développeur ne sera pas averti du problème, et perdra du temps à comprendre son problème.
  • une bibliothèque X dépend de A en version 1.0 ou +, une bibliothèque Y dépend de A en version 2 ou +, X est installé en premier avec A1.0, Y ensuite, le développeur devra penser à upgrader A, fait non évident.

Résultats

  • Partage entre équipes très compliqué et non interactif
  • difficulté d’installer une lib en version précise et ces dépendances
  • Difficulté de monter en version sur une lib, car impossible de connaître rapidement toute les ramifications
  • Option viable pour un petit projet d’entreprise (un seul produit, très peu de lib, 2-3 développeurs max), mais pas industrialisable sur X projets et X bibliothèques. contre-productif…

Avec Nuget:

  • bibliothèque formalisée dans un paquet avec une version précise
  • paquet centralisé dans un serveur ou espace partagé
  • les dépendances entre lib sont définies au niveau du paquet, l’outil Nuget permet de rapatrier l’ensemble des dépendances d’une lib dans une version compatible.
  • lisibilité du nom de la lib, de la version, de ces dépendances, de son origine, de sa licence, …etc, directement dans Visual Studio.
  • la montée de version des bibliothèques d’une solution est automatisée avec une fonction d’update de Nuget.
  • une bibliothèque X dépend de A en version 1.0 seulement, une bibliothèque Y dépend de A en version 2 ou +, le développeur sera averti du problème.
  • une bibliothèque X dépend de A en version 1.0 ou +, une bibliothèque Y dépend de A en version 2 ou +, X est installé en premier avec A1.0, Y ensuite, Nuget met à jour automatiquement A.
  • partage entre équipes simplifié et synchronisé, toujours accès aux dernières versions sans interventions extérieures.

Relation Nuget / SCM / restauration automatique

Une source de problèmes liés à Nuget est les restaurations des dépendances.
2 politiques s’opposent, l’une consiste à commiter toutes bibliothèques au prix d’une charge de stockage plus grande sur le SCM (git / svn / …) l’autre à restaurer dynamiquement au risque de ne plus retrouver de vieilles version de dépendance aujourd’hui supprimée.
Ce choix dépend de votre infrastructure et de la durée de vie de votre projet…

Pour plus d’informations :

Une description plus complète de cette problématique est faite sur l’article suivant :
http://blog.ploeh.dk/2014/01/29/nuget-package-restore-considered-harmful/

Documentation officiel
http://docs.nuget.org/docs/workflows/migrating-to-automatic-package-restore

Blog d’un mainteneur du projet Nuget :
http://blog.davidebbo.com/2014/01/the-right-way-to-restore-nuget-packages.html

Versionnement des bibliothèques

Nuget se base sur la version de votre paquet pour résoudre les dépendances. L’algorithme de résolution utilise la nomenclature SemVer, un standard en numérotation de version.
Si vous ne respectez pas cette nomenclature, la résolution sera faussée et ça sera l’enfer sur votre solution !

Semantic Versioning (SemVer) en bref

SemVer décrit, pour les auteurs, une manière de définir des versions sémantiquement cohérentes. En un mot, les versions sémantiques ressemblent à MAJEURE.MINEURE.CORRECTIF(optionel=+metaData)), tels que:

  • le numéro de version MAJEUR quand il y a des changements rétro-incompatibles,
  • le numéro de version MINEUR quand il y a des changements rétro-compatibles,
  • le numéro de version de CORRECTIF quand il y a des corrections d’anomalies rétro-compatibles

Optionnellement un numéro de build ou de révision peut être ajouté en méta-données comme par exemple 1.0.0-beta+exp.sha.5114f85. Cette extension est ignoré pour le calcul des releases mais pris en compte avec l’argument « -Pre ».
Règle de dépendances entre paquet

Algorithm de résolution

  • 1.0 = 1.0 ≤ x
  • (,1.0] = x ≤ 1.0
  • (,1.0) = x < 1.0
  • [1.0] = x == 1.0
  • (1.0) = invalide
  • (1.0,) = 1.0 < x
  • (1.0,2.0) = 1.0 < x < 2.0
  • [1.0,2.0] = 1.0 ≤ x ≤ 2.0
  • vide = dernière version.

Avoir une règle de versionnement n’est que la moitié du puzzle. L’autre moitié est d’être en mesure de choisir la meilleure version parmi tous les candidats qui sont disponibles.
Un scénario:

  • A dépend de X 1.1 (qui signifie « >= 1.1 » comme indiqué ci-dessus)
  • B dépend de X 1.2
  • C dépend de X 2.0.1
  • X a des versions 1.0, 1.1, 1.2, 2.0 , 2.0.1+alpha, 2.0.1, 3.0, 3.0.1, 3.0.2+beta et 4.0 disponible.

La résolution de la version utilisée par NuGet est de toujours choisir la version la plus basse d’une dépendance.

Voyons donc ce qui se passera dans les différents scénarios :

  • Si vous venez d’installer A, vous aurez X 1.1
  • Si vous installez juste B, vous aurez X 1.2
  • Si vous venez d’installer C, vous aurez X 2.0.1

Si vous installez d’abord A, puis B , puis C

  • Vous obtenez d’abord X 1.1 lorsque vous installez A
  • X sera mis à jour en 1.2 lorsque vous installez B
  • X sera mis à jour en 2.0.1 lorsque vous installez C

Remarque : X.Y.Z+meta sera toujours inférieur à X.Y.Z et sera pris en compte qu’avec l’option « Prerelease ».

Mise à jour de dépendance après installation de paquet

Avant NuGet 2.5, quand un paquet à installé dépend d’un paquet déjà installé dans le projet, la dépendance sera mis à jour dans le cadre de la nouvelle installation, même si la version existante satisfait la dépendance. Cette mise à jour se limitera aux versions rétro compatibles.

À partir de NuGet 2.5, si une version de la dépendance est déjà satisfaite, la dépendance ne sera pas mis à jour lors d’autres installations de paquets.

Le scénario :

Le référentiel source contient le paquet B avec la version 1.0.0 et 1.0.2 . Il contient également un paquet qui a une dépendance sur B ( > = 1.0.0 ).
Supposons que le projet actuel a déjà la version du paquet B 1.0.0 installé . Maintenant, vous voulez installer le paquet A.

En NuGet 2.2 et plus:
Lors de l’installation du paquet A, NuGet mettra à mise à jour automatique B à 1.0.2, même si la version existante 1.0.0 satisfait déjà la contrainte de dépendance qui est > = 1.0.0.

En NuGet 2.5 et plus récent:
NuGet ne mettra plus mettre à jour B, car il détecte que la version existante 1.0.0 satisfait la contrainte de dépendance de version.
Pour plus de détails :

Documentation officiel
http://blog.davidebbo.com/2011/01/nuget-versioning-part-2-core-algorithm.html

Génération de paquet

Génération initiale du descriptif

Pour créer un descriptif de paquet, utilisez la commande ci-dessous à la racine de votre solution :

$> Nuget spec

Compléter ce fichier avec l’information dont vous disposez (licence, description,…). Vous pouvez laisser les token $xxx$ intact, ils seront rempli automatiquement par les informations de AssemblyInfo.cs

Générer le paquet

Remplissez le fichier AssemblyInfo.cs comme vous le feriez pour produire votre release.

Compilez en release ou exécutez la commande suivante :

$> msbuild votre-projet-ou-solution /target:Rebuild /property:Configuration=Release

Créez le paquet avec ces symbols de débogage :

$> nuget pack votre-projet-ou-solution -Symbols -Prop Configuration=Release

Uploader sur le serveur Nuget les 2 fichiers générés en même temps, le xxxx.nupkg et le xxxx.symbols.nupkg.

Bibliothèques interdépendantes

Ajouter le flag –IncludeReferencedProjects si votre projet a pour dépendance d’autre projet locaux à la solution qui vont être également converti en paquet Nuget.

Débugger avec les paquets Nuget

Le paquet symbols.nupkg contient les symboles et le code source de votre paquet, il vous permet de débugger votre application en ayant accès au code de ces dépendances.

Ces symboles sont stockés sur le serveur Nuget de symbole.

Pour configurer Visual Studio afin qu’il utilise ces symboles, suivez le tutorial en lien