Thursday, 29 January 2015

My CPAN Pull Request Challenge for January: Fuse

So! Back in December I subscribed to Neil Bowers' CPAN Pull Request Challenge. In a nutshell, throughout 2015 every participant will get an email in the first days of each month with a CPAN module that needs a little bit of love, and we have until the end of the month to submit at least one pull request for that module's Github repository.

The module I got was "Fuse".

What is Fuse?

I must admit to my ignorance as I have never heard of Fuse before. So the first thing I did was jump to Fuse's page on MetaCPAN and have a look. Fuse is a Perl interface to the FUSE library (Filesystem in USErspace), and lets you implement filesystems in Perl. Wow! That's pretty cool, right?!

Where to start

If Neil was pointing me to Fuse, it means there's probably work for me to do. So what I did was read the documentation, CPAN Testers reports, open issues and the Github page. Then I downloaded the source code and grep'd for tags like "FIXME" and "TODO". In the end it was a very well-thought distribution and I think the authors did - and are still doing - a pretty nice job. Still, this is what I thought I could help with:
  • The (external) FUSE kernel/lib doesn't seem to be linked anywhere in the main doc, just on the README;
  • The SYNOPSIS and DESCRIPTION could be a bit more verbose - maybe I'm just not used to the FUSE library, but I felt a lot was being taken for granted;
  • The README (displayed on github) doesn't point to a lot of useful places in the Perl-sphere (other than the examples and how to install);
  • There is no license information on the main pod - though it's there on the META resources;
  • The latest version is not indexed for some reason;
  • There are a lot of FAIL and UNKNOWN reports on CPAN Testers.

First things first

There were several small things for me to attempt here, so rather than making a huge bundled Pull Request for Fuse, I chose to compartmentalize them into smaller, separate, PRs. This way the authors'd probably be more comfortable reviewing my changes and I wouldn't depend on all of them being accepted. This is super easy with git and github: just create a branch from master and make the pull request from your specific branch to the author's master. This will let you easily go back to their master (instead of to the one you might have changed) and work on something else independently.

1. Doc fixes

Since I was really short of free time this month, I decided to start with the lowest hanging fruit. So I created a "garu/doc_patches" branch and tried my best to improve on the existing documentation. I expanded the SYNOPSIS, put external links whenever I missed them, and did some minor tweaks here and there with the pod formatting to improve readability. I also moved the README to markdown so it looks awesome on Github while still being nice to read on the console. When I was satisfied, I sent out the pull request.

This was great and really helped me understand what Fuse was all about and how to use it. I recommend anyone trying to learn and contribute to a project to first read the docs and try to improve them whenever you find something you don't quite understand. Most of the time the ones writing the documentation are too familiar with the code and API so they can take a lot of it for granted.


There was an open ticket saying 0.16.1 was not indexed. Upon further investigation, I saw versions 0.16_01 and 0.16.1 were in fact indexed, but available as if they were older releases. Why weren't they showing up as the latest? I went to #metacpan on and asked around.

As haarg++ pointed out, Fuse inadvertently mixed single dotted and double dotted version formats, releasing '0.16' (instead of '0.16.0') and '0.16.1'. When the CPAN indexer compares version numbers, 0.16.1 becomes 0.016001 and plain 0.16 becomes 0.160000, and as such, "0.16" is indeed greater than "0.16.1".

While I believe version numbers should be boring, I understand why some people go for the major.minor.revision semantic versioning format. So I went ahead and filed a pull request bumping up the version to 0.160.2, and another one that bumps it to 0.17. Both numbers are greater than 0.16 so they'll definitely show as latest, and the authors can just pick whichever format they prefer and discard the other PR.

3. Making tests pass

Finally, I noticed that all the UNKNOWN tags on CPAN Testers were there because FUSE was not installed. Implementing an Alien::FUSE module seems like a good idea, but it is a bit out of scope for the PR Challenge and the limited free time I had. So I went on and installed FUSE for OS X using homebrew. For my surprise, the Makefile.PL was still not finding it:

    $ perl Makefile.PL
    Cannot build for platform: darwin
    Please install OSXFUSE from

I checked Makefile.PL's source and found out what was wrong: it's trying to find libfuse using the "pkg-config" tool. Although "pkg-tool" is rather ubiquitous in major Linux systems, my OS X did not have it. So a made another PR that checks for the existence of either 'pkg-config' or 'ppkg-config' (a Pure-Perl alternative to 'pkg-config' available with the excellent PkgConfig CPAN module) early on the Makefile.PL, dying with an explanatory message if none are available. There's even an opportunity here to simply depend on PkgConfig and use the module version of the commands instead of relying on external "(p)pkg-config" tools, but I thought I rather wait a bit and see how well received this change is first.

Now the module compiles on OSX, but I still can't make the tests pass. I dug a bit and found some commands like read_buf and write_buf are required for testing, but are only available in libfuse versions 2.9.0 and above. However, osxfuse seems to use a different version equivalence and the latest version (released just a month ago) is still 2.7.4. I couldn't find an osxfuse <=> libfuse version equivalence, and because of this, the Fuse module doesn't create the proper bindings for such functions and the tests fail. There might be other issues still, but I stopped there, filing a ticket and hoping someone else will pick it up where I left off.

Wrapping up

I had a lot of fun finding out about Fuse and playing with it. By the end of January I was able to file 4 pull requests and 1 RT ticket to the main repo. I'm sad I wasn't able to get the tests to pass on OS X, but hopefully someone else will read this and be inspired :)

I'd like to thank Neil for this awesome PR Challenge idea, Graham "plicease" Ollis for the great PkgConfig module and for quickly replying to and merging the small changes I proposed that allowed me to use it on Fuse, and Graham "haarg" Knop and everybody from #metacpan for their amazing support.

Also, of course, a huge thank you to Dobrica Pavlinušić, Derrik Pates, Mark Glines and the entire Fuse team for such a great module, and for allowing me the opportunity to be a part of it.

Can't wait to see which module I'll get next month! :)