Pages

Saturday, August 31, 2013

Service management utility for Mac OSX (launchctl helper)

Having dealt with services mostly on Linux, I grew accustomed to type service php restart. On Mac, this is more like:

launchctl unload ~/Library/LaunchAgents/homebrew-php.josegonzalez.php55.plist
launchctl load ~/Library/LaunchAgents/homebrew-php.josegonzalez.php55.plist


Which is ugly, hard to remember and launchctl has no way of listing all available services. Plus, those plist can reside in all those directories:
  • /System/Library/LaunchDaemons
  • /System/Library/LaunchAgent
  • /Library/LaunchDaemons
  • /Library/LaunchAgents
  • ~/Library/LaunchAgents
Those in you home directory generally don’t need sudo, while the others do.

This is why I can up with an utility to manage services. It searches in all directories above for your service, prompts for sudo if it is in a system directory and provide goodies like restart, reload and link.

Usage:

service selfupdate
update from the Gist
service php
searches for a plist containing 'php'
service php load|unload|reload
insert or remove a plist from launchctl
service php start|stop|restart
manage a daemon, but leave it in launchctl  (does not work with Agents)
service php link
If you use Homebrew, which you should, it will link the plist of this Formula into ~/Library/LaunchAgents, reloading if needed. Very useful when upgrading.


Manage all optional services at once

If you have several services running, especially if you are a developer, I also recommend to use a script to start/stop all of them at once when you are not working. They may not be using much resources, but having them running keeps the laptop working and can drain you battery very quickly. 

Thursday, August 22, 2013

Hosting a Composer repository for private Gitlab projects

Small script that loops through all branches and tags of all projects in a Gitlab installation and if it contains a composer.json, adds it to an index.

This is very similar to the behaviour of Packagist.org

See example.

Usage

Simply include a composer.json in your project, all branches and tags respecting the formats for versions will be detected.

Only requirement is that the package name must be equal to the path of the project. i.e.: my-group/my-project. This is not a design requirement, it is mostly to prevent common errors when you copy a composer.json from another project without without changing its name.

Caveats

While your projects will be protected through SSH, they will be publicly listed. If you require protection of the package list, I suggest this reading.


Check out the code: https://github.com/wemakecustom/gitlab-composer !

Wordpress MU-Plugins subdirectory loader

Wordpress’s Must Use Plugins are an easy way to include quick pieces of code that will always be included.

While having my way with Composer and Composer Installers, I stumbled upon a Pull Request about adding support for mu-plugins. I already commented saying that I don’t how I works for them, because Wordpress does not load mu-plugins in subdirectories, they must be at the root of /wp-content/mu-plugins/.

After searching a bit, I found that someone had already thought of loading mu-plugins recursively but this solution was not enough for me :
  1. Calling a scandir each request seems wrong (performance-wise), it seems better to cache the results.
  2. It requires that each folder has a file named like "folder.php", which a lot of existing plugins don’t have.
  3. It does not list the included plugins in the admin so it is completely invisible.
The solution below covers all this, any plugin may be simply dropped in mu-plugins and it will be required.

Except normal installation (manually or via Composer), the only other step is to copy or symlink a file in your mu-plugins directory.

https://github.com/wemakecustom/wp-mu-loader


Monday, August 5, 2013

Using Edge Side Includes with Varnish to cache partial pages

Caching full pages with Varnish can be hard, most applications use sessions, which sets a Cookie, which makes Varnish ignore all caching.

When sessions are needed and full page cache is not available, you can resort to ESI (Edge Side Includes).

ESI has a markup language of its own, but the subset that Varnish supports is fairly simple: it is basically a placeholder that gets replaced by the referenced URL. They generate a subrequest that will mimic the original request, but for another URL. Using this system, you can cache parts of your website that do not change frequently or that are hard to generate. Since this is internal to Varnish, it will honour the cache system, including Cache-Control, If-Modified-Since, ETag, etc.

However, since the subrequest is built on top of the original, it will contain the original Cookie header, so we must ignore it.

The solution includes:
  • The original script must add a "X-Esi" header to activate ESI parsing (performance).
  • Cookies are removed from ESI requests unless "esi-cookies=1" is present is the URL.
  • A "X-Esi-Level" header gets added when the current request is a ESI. Otherwise, it is removed.
Various scenarios where this technique can be used:
  • A navigation menu with the current URL in parameter.
  • A footer
  • A user profile box (popup box) with the user id in parameter.
  • Widgets of a sidebar
Since the X-Esi-Level header is enforced to be only present for ESI requests, you can trust it and safely ignore any security check as they would have already been done in the original request.

Here is the VCL used for Varnish and a simple example to illustrate the ?esi-cookies=1 trick.