Gentoo: utiliser le Portage Overlay pour patcher des ebuilds

Dans un article précédent, j’expliquais comment patcher un package Gentoo via le répertoire /etc/portage/patches/. Cependant, pour utiliser cette méthode, il faut que l’ebuild appelle la fonction epatch_user dans le src_prepare.

Lorsque ce n’est pas le cas, vous ne pouvez donc pas utiliser cette méthode. Pour cela, vous pouvez créer votre propre ebuild à partir du tree officiel dans votre portage overlay.

Configurer le portage overlay

Pour configurer le portage overlay, il vous suffit d’ajouter la ligne suivante dans le fichier /etc/make.conf:

PORTDIR_OVERLAY="/usr/local/portage"

Ainsi, votre overlay est situé dans le dossier /usr/local/portage.

Modifier un ebuild

Si par exemple, vous voulez modifier le package dev-php/xdebug, il vous suffit de copier le fichier ebuild dans votre package overlay:

mkdir -p /usr/local/portage/dev-php/xdebug/
cp /usr/portage/dev-php/xdebug/xdebug-2.1.2.ebuild /usr/local/portage/dev-php/xdebug/xdebug-2.1.2.ebuild

Il vous suffit d’ajouter la fonction post_src_prepare pour y appeler la fonction epatch_user comme ceci:

post_src_prepare () {
    epatch_user
}

Ensuite, il faut générer le fichier Manifest grâce à l’outil ebuild:

cd /usr/local/portage/dev-php/xdebug/
ebuild xdebug-2.1.2.ebuild manifest

Maintenant, emerge va tout d’abord récupérer le package depuis vote overlay, et va donc appliquer les patches de votre dossier /etc/portage/patches/dev-php/xdebug/.

Python 2.X, TypeError: must be type, not classobj avec super()

Si vous tombez sur l’erreur TypeError: must be type, not classobj en Python en essayant d’appeler la méthode super(), c’est très probablement que vous avez oublié de définir vos classes en new-styled.

En effet, si vous avez défini vos classes de cette manière, vous aurez l’erreur:

class X:
   def a(self):
     print "a"
 
class Y(X):
   def a(self):
     super(Y,self).a()
     print "b"

Pour les définir en new-styled, il vous suffit d’ajouter object comme classe parent de la première. Ainsi, votre code corrigé est:

class X(object):
   def a(self):
     print "a"
 
class Y(X):
   def a(self):
     super(Y,self).a()
     print "b"

Et tout fonctionne! :)

Gentoo: utiliser des patches maison avec emerge

Il n’y a pas (ou très peu) de documentation sur comment utiliser vos propres patches sur des packages que vous installez avec emerge sous Gentoo, mais sachez que l’on peut le faire!
En théorie, il suffit d’ajouter votre patch au bon endroit, et emerge va le lire et l’appliquer lors de l’éxécution du src_prepare(). Il y a cependant des exceptions.

La fonction epatch_user

C’est la fonction epatch_user (déclarée dans /usr/portage/eclass/eutils.eclass) qui fait tout le travail. Elle doit être appelée dans le ebuild durant l’exécution du src_prepare.
Elle parcours le dossier /etc/portage/{category}/{package}/ et lance epatch pour appliquer tous les patches (ie tous les fichiers) qui s’y trouvent!
Par conséquent, pour que vous puissiez utiliser cette fonctionnalité, l’ebuild doit être configuré de telle sorte qu’il appelle la fonction epatch_user

Ajouter notre patch

Il suffit d’ajouter le patch dans le répertoire /etc/portage/patches/{category}/{package}, où category est la catégorie de votre package (dev-lang pour PHP par exemple) et package le nom de votre package, avec ou sans numéro de version.
Par exemple, si vous avez un patch xxx.patch pour PHP, copiez-le simplement dans le répertoire /etc/portage/patches/dev-lang/php/, et lorsque emerge préparera la source du ebuild, il appliquera votre patch automatiquement!

:)

jQuery: Le scroll est-il à la fin de l’élément ?

Je vous présente un petit tip pour jQuery qui peut intéresser: comment savoir si le scroll est à la fin de l’élément? L’élément peut être un div ou tout simplement la page (document).

// L'élément peut être un div...
var element = $('div#scroll');
// Ou le document complet
var element = $(document);
 
// La variable suivante vaut vrai si le scroll est en bas
var isScrollBottom = $(element).scrollTop() + $(element).innerHeight() >= $(element)[0].scrollHeight;

Application Android “Les-Horaires”

Je vous présente l’application Android Les-Horaires, qui permet de trouver des points d’intérêts (commerces, bars, postes, …) à proximité d’un lieu ou de vous, et de connaître les horaires d’ouverture!

 

Vous trouverez une description sur la page du projet et vous pouvez télécharger Les-Horaires sur le Google Play Store.

Plugin jQuery VInlinEdit: Inline Edit with VI (Command Line) style

Pour les besoins de MyOnlineSSH, j’ai développé un plugin jQuery qui permet l’édition d’un <span> (ou autre) avec un style à la vi, ou plutôt à la ligne de commande.

Exemple

Vous pourrez trouver deux exemples d’utilisation dans le répertoire examples du dépôt GitHub. Voici une copie d’écran de l’exemple proposant une implémentation ultra-light d’une saisie de commandes.

Téléchager

La librairie se trouve sur GitHub, le README sert, pour le moment, de documentation. N’hésitez pas à forker et soumettre des pull requests !

https://github.com/sroze/jquery-plugin-vinlinedit

JavaScript: Synchroniser des événements asynchrones

Un des problèmes récurrents du développement événementiel est que l’on a parfois besoin de synchroniser l’exécution d’une fonction. En effet, il est parfois important qu’une fonction finisse avant d’en appeler une autre, ou bien elle-même une nouvelle fois. Dans mon cas, je vais vous montrer comment synchroniser un événement JavaScript (en l’occurrence un keydown) pour que le trigger que vous lui avez affecté ne s’exécute pas deux fois en parallèle, grâce à une librairie à l’heure actuelle peu connue: jsAsyncQueue.

Le problème

Prenons comme exemple le code JavaScript suivant (utilisant la librairie jQuery):

$('input[type=text]').keydown(function(e){
    var value = $(this).val();
 
    // De nombreuses et longues opérations sur la variable "value"
    // plus tard...
 
    $(this).val(value);
});

Dans cet exemple, on récupère la valeur actuelle d’un input pour la traiter puis mettre à jour la valeur du champ de texte. C’est un exemple un peu bête mais qui résume bien le problème… Si j’appuie rapidement sur mes touches, on comprend bien qu’on peut avoir plusieurs exécutions de la fonction de trigger en parallèle. Ainsi, la valeur que l’on a récupéré au début de notre fonction n’est plus valable à un certain moment parce qu’une autre exécution du trigger l’as modifié en parallèle.

Continue reading

Webistrano: Net::SSH::AuthenticationFailed error

Si vous avez une erreur Net::SSH::AuthenticationFailed avec Webistrano (ou Capistrano), vous êtes peut-être en présence du bug de Net::SSH que je vais vous présenter. Avant, vérifiez ces points-ci:

  • Le nom du serveur (et l’IP qui va derrière) est bon.
  • Le nom d’utilisateur est bon.
  • Vous pouvez vous connecter à votre serveur en utilisant ssh user@server.example.com en tant que l’utilisateur qui exécute Webistrano (ie la configuration runner) ou bien l’utilisateur qui lance le cap.
 ** [deploy:update_code] exception while rolling back: Capistrano::ConnectionError, connection failed for: ks2.so.d-sites.com (Net::SSH::AuthenticationFailed: webistrano)

Si vous pouvez vous connecter au serveur avec une paire de clé (ou un mot de passe) depuis votre runner, vous pouvez essayer ce correctif. Sinon, cherchez ailleurs, ça n’est sûrement pas la solution de votre problème. En fait, le problème vient de la librairie Net::SSH de Ruby, qui n’arrive pas à se connecter si on ne lui passe pas l’option de configuration auth_methods.

Pour tester

Pour être sur que le correctif que je vous propose résoudra votre problème, nous allons tester le déploiement en utilisant le fichier CAP directement. En fait, c’est le fichier que Webistrano génère pour que Capistrano déploie votre application.
Ainsi, dans Webistrano, cliquez sur le stage de votre projet, puis Export CAP file. Copiez le contenu de ce fichier dans le répertoire de travail du runner de votre stage. Pour moi, le runner est webistrano, le fichier sera donc ici: /home/webistrano/tmp/test-webistrano.cap.

Ajoutez à votre fichier cap la ligne de configuration suivante, avec la section “TEMPLATE TASKS”.

ssh_options[:auth_methods] = "publickey"

Note: si vous utilisez une autre méthode d’authentification, changez donc le nom… Vous pourrez trouver une liste exhaustive dans la documentation de Net::SSH.

Ensuite, testez le déploiement avec Capistrano, qui est dans le répertoire des librairies de Webistrano. Dans mon exemple, (où la racine de Webistrano est /home/webistrano), je lance le déploiement comme ceci:

/home/webistrano/vendor/bundler/ruby/1.8/gems/capistrano-2.6.0/bin/cap -v -f /home/webistrano/tmp/test-webistrano.cap deploy

Pour résoudre

Continue reading

Gentoo: Pas de fichier de log avec Postfix

Après avoir mis en place Postfix avec Postfixadmin sur un système Gentoo, je me suis rendu compte qu’aucun fichier de log n’était créé par Postfix. En réalité, je n’avais simplement pas installé rsyslog. Vous pouvez l’installer comme ceci:

# emerge -av rsyslog

Éditez maintenant le fichier /etc/rsyslog.conf, et si vous n’avez pas cette ligne, ajoutez-la:

mail.*                                                  -/var/log/maillog

Le fichier de log /var/log/maillog est créé un contiendra maintenant les logs de Postfix.

Redmine (Ruby) `load_missing_constant’: Object is not missing constant Issue! (ArgumentError)

Lors de l’installation conjointe de Webistrano (voir Installer Webistrano avec nginx et PostgreSQL sous Gentoo) et de Redmine (voir Installer Redmine avec PostgreSQL) sur un même serveur, Redmine m’as quelque peut surpris on me sortant cette erreur:

/usr/lib64/ruby/gems/1.8/gems/activesupport-2.3.14/lib/active_support/dependencies.rb:443:in `load_missing_constant': Object is not missing constant Issue! (ArgumentError)
	from /usr/lib64/ruby/gems/1.8/gems/activesupport-2.3.14/lib/active_support/dependencies.rb:106:in `const_missing'
	from /usr/lib64/ruby/gems/1.8/gems/activesupport-2.3.14/lib/active_support/dependencies.rb:118:in `const_missing'
	from /usr/lib64/ruby/gems/1.8/gems/activesupport-2.3.14/lib/active_support/dependencies.rb:124:in `send'
	from /usr/lib64/ruby/gems/1.8/gems/activesupport-2.3.14/lib/active_support/dependencies.rb:124:in `const_missing'
	from /home/redmine/app/models/project.rb:40
	from /usr/lib64/ruby/site_ruby/1.8/rubygems/custom_require.rb:36:in `gem_original_require'
	from /usr/lib64/ruby/site_ruby/1.8/rubygems/custom_require.rb:36:in `require'
	from /usr/lib64/ruby/gems/1.8/gems/activesupport-2.3.14/lib/active_support/dependencies.rb:184:in `require'
	from /usr/lib64/ruby/gems/1.8/gems/activesupport-2.3.14/lib/active_support/dependencies.rb:291:in `require_or_load'
	from /usr/lib64/ruby/gems/1.8/gems/activesupport-2.3.14/lib/active_support/dependencies.rb:451:in `load_missing_constant'
	from /usr/lib64/ruby/gems/1.8/gems/activesupport-2.3.14/lib/active_support/dependencies.rb:106:in `const_missing'
	from /usr/lib64/ruby/gems/1.8/gems/activesupport-2.3.14/lib/active_support/dependencies.rb:118:in `const_missing'
	from /usr/lib64/ruby/gems/1.8/gems/activesupport-2.3.14/lib/active_support/dependencies.rb:463:in `load_missing_constant'
	from /usr/lib64/ruby/gems/1.8/gems/activesupport-2.3.14/lib/active_support/dependencies.rb:122:in `const_missing'
	from /home/redmine/app/models/principal.rb:22
	from /usr/lib64/ruby/site_ruby/1.8/rubygems/custom_require.rb:36:in `gem_original_require'
	from /usr/lib64/ruby/site_ruby/1.8/rubygems/custom_require.rb:36:in `require'
	from /usr/lib64/ruby/gems/1.8/gems/activesupport-2.3.14/lib/active_support/dependencies.rb:184:in `require'
	from /usr/lib64/ruby/gems/1.8/gems/activesupport-2.3.14/lib/active_support/dependencies.rb:291:in `require_or_load'
	from /usr/lib64/ruby/gems/1.8/gems/activesupport-2.3.14/lib/active_support/dependencies.rb:250:in `depend_on'
	from /usr/lib64/ruby/gems/1.8/gems/activesupport-2.3.14/lib/active_support/dependencies.rb:162:in `require_dependency'
	from /home/redmine/vendor/plugins/redmine-gitolite/init.rb:2:in `evaluate_init_rb'
	from /usr/lib64/ruby/gems/1.8/gems/rails-2.3.14/lib/rails/plugin.rb:158:in `evaluate_init_rb'
	from /usr/lib64/ruby/gems/1.8/gems/activesupport-2.3.14/lib/active_support/core_ext/kernel/reporting.rb:11:in `silence_warnings'
	from /usr/lib64/ruby/gems/1.8/gems/rails-2.3.14/lib/rails/plugin.rb:154:in `evaluate_init_rb'
	from /usr/lib64/ruby/gems/1.8/gems/rails-2.3.14/lib/rails/plugin.rb:48:in `load'
	from /home/redmine/config/../vendor/plugins/engines/lib/engines/plugin.rb:44:in `load'
	from /usr/lib64/ruby/gems/1.8/gems/rails-2.3.14/lib/rails/plugin/loader.rb:38:in `load_plugins'
	from /usr/lib64/ruby/gems/1.8/gems/rails-2.3.14/lib/rails/plugin/loader.rb:37:in `each'
	from /usr/lib64/ruby/gems/1.8/gems/rails-2.3.14/lib/rails/plugin/loader.rb:37:in `load_plugins'
	from /usr/lib64/ruby/gems/1.8/gems/rails-2.3.14/lib/initializer.rb:369:in `load_plugins'
	from /usr/lib64/ruby/gems/1.8/gems/rails-2.3.14/lib/initializer.rb:165:in `process'
	from /usr/lib64/ruby/gems/1.8/gems/rails-2.3.14/lib/initializer.rb:113:in `send'
	from /usr/lib64/ruby/gems/1.8/gems/rails-2.3.14/lib/initializer.rb:113:in `run'
	from /home/redmine/config/environment.rb:24
[...]

Après de nombreuses recherches, j’ai résolu le problème en ajoutant une petite ligne au fichier config/environnement.rb de Redmine:

  config.gem 'pg'

Après la ligne suivante:

  config.gem 'coderay', :version => '~>1.0.0'

:)