Blog of Stéphane Épardaud

Ceylon command-line plugins

With Ceylon we try our best to make every developer’s life easier. We do this with a great language, a powerful IDE, a wonderful online module repository, but also with an amazing command-line interface (CLI).

Our command line is built around the idea of discoverability where you get a single executable called ceylon and lots of subcommands that you can discover via --help or completion. We have a number of predefined subcommands, but every so often, we want to be able to write new subcommands.

For example, I want to be able to invoke both Java and JavaScript compilers and generate the API documentation in a single command ceylon all, or I want to be able to invoke the ceylon.formatter module with ceylon format instead of ceylon run ceylon.formatter.

Well, with Ceylon 1.1 we now support custom subcommands, fashioned after the git plugin system. They’re easy to write: just place them in script/your/module/ceylon-foo and package them with ceylon plugin pack your.module, and you can publish them to Herd.

Now every one can install your CLI plugin with ceylon plugin install your.module/1.0 and call them with ceylon foo.

What’s even better is that they will be listed in the ceylon --help and even work with autocompletion.

ceylon.formatter uses one, and I encourage you to install them with ceylon plugin install ceylon.formatter/1.1.0 and format your code at will with ceylon format :)

ceylon.build.engine also defines one and it just feels great being able to build your Ceylon project with ceylon build compile, I have to say. Although, unfortunately that particular module has not yet been published to Herd yet, but hopefully it will be pushed soon.

You can find out all about them in our reference.

First Ceylon Tour in Paris

The Ceylon team recently had its almost yearly face-to-face meeting in Paris. For those not familiar with how the Ceylon team works (and indeed how most of the open-source development teams work in Red Hat), the Ceylon team consists in surprisingly few individuals working remotely, and distributed world-wide. This includes not only developers such as me, paid by Red Hat to work full-time on Ceylon, but also the community of Ceylon enthusiasts who contribute time, code or discussions in their free time, without financial compensation other than the satisfaction of helping Ceylon be that much better that much sooner.

This means that yes, we do all work without seeing each other in person in most cases. Naturally, we communicate a lot in order to work together, but in our case that means via the Ceylon mailing list, or IRC channel, or via our issue tracker. We don't even do voice chats. This is pretty great for the Ceylon community, as 99% of our discussions are thus online and in the open and visible. I say 99% because there's always cases where there are some one-to-one discussions we have over private channels, especially when we want to prepare surprises :)

An interesting consequence of that is that we have met surprisingly few people of the team in person. A few of us met physically during conferences, others by being geographically close, and others yet during our previous face-to-face meeting two years ago in Barcelona, when we were very few. But overall, most of us had never seen each other in person, which is why we try to hold yearly face-to-faces.

The primary purpose of meeting together in my opinion is to have social interactions and talk about something else than work for once. It also allows us to lock people in a room and prevent them from going out before they've looked at something or given their opinion on something, which is something that can't happen so easily when distributed. An example of that is when Loïc (one of our great free-time contributors) came to present us ceylon.build and wanted our opinion, which we had somewhat neglected to give previously, due to poor planning on our part.

We did also discuss things such as language features, roadmap and priorities, but those have already been reflected openly via our mailing list and issue tracker, where the discussion can continue.

The last (pretty big) advantage of being all together at the same place, was that we could take this opportunity to hold our first Ceylon Tour conference!

The first Ceylon Tour conference in Paris

Thanks to the guys from IRILL we were able to secure a very nice room to hold our first Ceylon conference, for free, where I'm glad to say lots of people showed up. We had people from from Slovenia, Germany and Austria, not to mention all over France and yes, even Paris. We were very surprised by the fact that people came from further than Paris, but it shows that Ceylon generates lots of interest.

We held the following talks during the morning :

Ceylon introduction

Ceylon idioms

Cayla and Vert.x in Ceylon

Ceylon SDK

ceylon.build

ceylon.test

Ceylon module repositories

Ceylon/Java interop

Ceylon workshop

And in the afternoon we had a great Ceylon workshop where people got to code in Ceylon, driven and helped by Gavin, and I'm glad to say that after 4 hours of workshop, most people were still not only awake, but engaged and coding, rather than just checking their email :)

The next Ceylon Tour?

All in all, we're very happy with the event, the content, the turnout and to answer the questions we got when we announced the first Ceylon Tour in Paris, yes we will try to plan another round in other locations, such as London, Berlin and the USA. If you think we should hold a Ceylon Tour event in your country/city, let us know and we'll happily discuss it.

Ceylon Tour comes to Paris

A Ceylon conference in Paris in January 2014

We have so many exciting things to talk about in the Ceylon ecosystem that it's impossible for everyone to keep track of everything that is happening, but if you live in Paris or not too far from it, we can help you, because we will organise our first Ceylon Tour conference in Paris in January 2014.

Ceylon Tour Paris 2014 logo

The whole Ceylon team will be there, there will be many short talks, discussions and a workshop. The conference is free, but availability is limited so we advise you to reserve your ticket as soon as possible, but only if you're sure to come (it wouldn't be fair to others to reserve a ticket and not come).

Registration, as well as all the info about this conference is detailed on the conference page.

If you live near Paris, any excuse is good to visit Paris, especially a free Ceylon conference :)

If you don't live near Paris, hopefully this is only the start and we will visit your country soon!

Command-line interface: attention to details

About the Ceylon command-line interface

We’re programmers, so let’s face it, we spend lots of time in those small obscure windows with tiny text, preferably with a green or black background, that Hollywood movies often display scrolling a lot, really fast, you know? Terminals.

While good IDEs are required, and the Ceylon IDE is a must-have for Ceylon developers, they can never replace a good terminal session with the proper command-line interface (CLI) tools.

Oh, I know Eclipse has good Git support and I know a few colleagues who use it for committing and branching and other daily, nay, hourly push/pull command. But I really love my CLI when it comes to using Git, I never use Eclipse for that, so I spend a lot of time in my terminal.

Also, it’s essential to be able to build a Ceylon project from the command-line, and not just from the IDE. Imagine trying to build your project in a remote machine using an IDE with a remote X session? No, that doesn’t cut it, sorry.

So from the start, Ceylon had a CLI. Actually, we had a CLI before we had an IDE, but that didn’t last long. And in the beginning we copied Java and had a few commands such as ceylonc to compile, and ceylon to run. Then we added the API generator tool called ceylondoc, and very soon after that we figured we were doing something horribly wrong.

Back when Java came out in 1995 it was sorta cute and useful that all its commands started with the java prefix, but after you got around to remembering what javac and javadoc stood for, you started to wonder what the hell javap or javah could possibly mean.

Then Git came around and revolutionised not only distributed version-control, it also revolutionised command-line interfaces. Suddenly you could start with remembering a single command called git and find out from here what the full list of subcommands would be. You add --help and it spits out a man page. You have completion out of the box. And everyone can write plugins very easily in just a few lines of shell script. Not only that, but most options can be stored and retrieved in a really straightforward config file, with useful and logical lookup in your project, then home.

It’s really a treasure trove of good ideas, and much more modern than the Java CLI we started copying. So we stopped and rewrote our CLI to copy the Git CLI, and I have to say I’m really glad we did, because we really have a great CLI now.

Discovery

One Command to rule them all, One Command to find them, One Command to bring them all and in the CLI bind them In the Land of Terminal where the Shell lie.

We have a single command called ceylon, and if you do ceylon help or ceylon --help you will get the following:

NAME

        'ceylon' - The top level Ceylon tool is used to execute other Ceylon tools


SYNOPSIS

        ceylon --version
        ceylon [--stacktraces] [--] <command> [<command‑options...>] [<command‑args...>]


DESCRIPTION

        If '--version' is present, print version information and exit. Otherwise '<tool-arguments>' should 
        begin with the name of a ceylon tool. The named tool is loaded and configured with the remaining
        command line arguments and control passes to that tool.

        * 'all' - Compiles ceylon modules for JVM and JS and documents them

        * 'compile' - Compiles Ceylon and Java source code and directly produces module and source archives 
                      in a module repository.

        * 'compile-js' - Compiles Ceylon source code to JavaScript and directly produces module and source 
                         archives in a module repository

        * 'config' - Manages Ceylon configuration files

        * 'doc' - Generates Ceylon API documentation from Ceylon source files

        * 'doc-tool' - Generates documentation about a tool

        * 'help' - Displays help information about other Ceylon tools

        * 'import-jar' - Imports a jar file into a Ceylon module repository

        * 'info' - Prints information about modules in repositories

        * 'new' - Generates a new Ceylon project

        * 'run' - Executes a Ceylon program

        * 'run-js' - Executes a Ceylon program

        * 'src' - Fetches source archives from a repository and extracts their contents into a source directory

        * 'test' - Executes tests

        * 'version' - Shows and updates version numbers in module descriptors

        See 'ceylon help <command>' for more information about a particular subcommand.


OPTIONS

        --stacktraces
            If an error propagates to the top level tool, print its stack trace.


        --version
            Print version information and exit, ignoring all other options and arguments.

Yes it’s a man page, this is what is useful and will help you find your way out of the many ceylon subcommands we have.

A similar thing will happen if you type ceylon compile --help or ceylon help compile.

Completion

We ship with completion support for bash:

$ . /usr/share/ceylon/1.0.0/contrib/scripts/ceylon-completion.bash 
$ ceylon [TAB]
all         compile-js  doc         help        info        run         src         version     
compile     config      doc-tool    import-jar  new         run-js      test        
$ ceylon compile[TAB]
compile     compile-js  
$ ceylon compile --re[TAB]
--rep\=       --resource\=  

As you can see, it’s quite useful, and again, that’s what you expect in this day and age.

Documentation

The tool system that we wrote (well, mostly that Tom Bentley wrote) even allows us to generate HTML, XML and text documentation automatically, for example, the tool documentation pages are entirely generated, and the man pages that we ship in the Ceylon CLI distribution are also generated.

Plugins, plugins

You may not have noticed it but if you type ceylon help on your system, it will likely not include that line:

[...]
DESCRIPTION

        [...]

        * 'all' - Compiles ceylon modules for JVM and JS and documents them

And that’s because, like Git, we support CLI plugins, and ceylon all is a plugin I wrote for myself, that aggregates a bunch of subcommands in a single one.

Ceylon CLI plugins are as straightforward as Git CLI plugins: any executable in your path which starts with ceylon- will be picked up to be a plugin. It will be listed and documented too. If you add documentation in your plugin it will be used.

Here’s my ceylon-all shell script for example:

#!/bin/sh

USAGE='[generic options] module...'
DESCRIPTION='Compiles ceylon modules for JVM and JS and documents them'
LONG_USAGE='ceylon-all allows you to build the specified ceylon modules for the
JVM and JS backends, and generates the API documentation in a single command.'

. $CEYLON_HOME/bin/ceylon-sh-setup

$CEYLON_HOME/bin/ceylon compile $@
$CEYLON_HOME/bin/ceylon compile-js $@
$CEYLON_HOME/bin/ceylon doc $@

As you can see, our CLI will use the USAGE, DESCRIPTION and LONG_USAGE environment variables for completion and documentation. You only have to source the provided $CEYLON_HOME/bin/ceylon-sh-setup shell script to benefit from this. Then you can run whatever you want.

Configuration

There are a lot of options the CLI and IDE have good defaults for, such as the source path, or the output module repository, or the list of module repositories. But when you need something different it gets tiring really fast to have to specify them for every command, so we support configuration files just like Git, in the form of INI files located in your project at .ceylon/config. If that file does not exist or a particular configuration option is not defined in it, we will also try the user’s config in $HOME/.ceylon/config as a fallback.

The syntax is straightforward, take for example the .ceylon/config for the Ceylon SDK:

[repositories]
output=./modules
lookup=./test-deps

[defaults]
encoding=UTF-8

It just specifies that the output repository is modules, the additional lookup repository is test-deps (for test dependencies) and the source encoding is UTF-8.

There’s a ceylon config command which allows you to edit this file if you don’t want to fire up vim for that, and the best part is that this config file is actually used and edited by the IDE too! So no more hassle to keep the CLI and IDE settings in sync.

Welcome to the future! :)

Ceylon IDE performance improvements

Ceylon already has a very complete IDE, based on Eclipse, with many features, that we're very happy with. And considering how young it is, it's quite amazing that it already has all these features, but in the race to create the IDE and add all the features we needed to it, we have always pushed back any work in making it work faster. As a result, we're now to the point where the IDE is mostly complete in terms of features, but pretty slow for large projects.

Luckily, pushing back the work on performance doesn't mean we didn't have ideas for how to improve it, and in fact we have a lot of ideas, and today I'm glad to announce that in collaboration with Serli (one of the companies sponsoring Ceylon), David Festal is going to spend the next six months working on fixing all the speed and memory issues we have with the Ceylon IDE. David is already behind a lot of work that went in the Ceylon IDE and has experience with not just the Eclipse APIs and the Ceylon plugin, but also all the Ceylon sub-systems that the IDE integrates, such as the type-checker, the backends and the module system.

Here are the major points David will be working on for the IDE:

  • Opening a Ceylon project should only generate Ceylon binaries if their source has changed.
  • Load module dependencies using their binaries if it turns out to be faster than using their sources.
  • Make the backend compiler use the already parsed and typechecked AST that is available in the IDE.
  • Beef up the automated test suite.
  • Share the loaded models for the Ceylon language module and the JDK modules across every project.
  • Research performance bottlenecks in the typechecker and backend if required.
  • Research and fix memory consumption on some architectures.
  • Improve incremental build when editing module files.
  • Add visual progress reporting of the module system.
  • Improve build visual progress reporting.

We believe that with David's availability and experience, all of these issues will be obliterated and we will have an incredibly fast Ceylon IDE even for large projects, at the latest for January 2014. The good news is that David will start this performance run as early as next week, and we will release new versions of the Ceylon IDE as soon as each improvement is stable enough to ship, so we can expect faster releases really soon.

Go David!