Weekend Website Experiment

As you may know if you read this blog via Planet GNOME, the GNOME project is busy switching to GitLab for its code hosting and bug tracking. I like GitLab! It’s a large step up from Bugzilla, which was what GNOME used for the last 20 years. Compared to GitHub, GitLab is about equal, with a few nicer things and a few less nice things.

The one thing that I miss from Bugzilla is a dashboard showing the overall status of the bugs for your project. I thought it would not be too hard to use the GitLab API to do some simple queries and plop them on a web page. So, last weekend I gave it a try. The final result is here. Click the button to log into GitLab, and you’ll be redirected back to the page where you’ll get the results of the queries.

I’d like to write up what I did because I learned a new thing, and I think more writeups illustrating the trial and error of learning a new thing are always good.

My goals were to write something without being too meticulous, and write something that was not intended to scale. (Both are things that I normally disapprove of. It’s good to try the other side once in a while.) So, I was just going to mix the HTML, CSS, and JS all in one file. I used the base CSS and overall page structure from my personal website.

I decided to use GitHub Pages for hosting. My personal website is already hosted there. GitLab also offers GitLab Pages, which is very similar, but GNOME hasn’t enabled it yet on their GitLab instance. So, I created a fork of GNOME/gjs on GitHub, and created a gh-pages branch. Whatever you commit to that branch shows up as your project’s GitHub Pages site on the web.

The first thing I figured out is that you have to be authenticated to query issues in the API, even if the same information is publicly available on the web. That’s too bad! My little project suddenly went from “easy” to “figuring out something I’ve never done before.” But that’s also exciting.

First, I got the queries running on a local webpage, using a temporary personal GitLab access token. Each item looked kind of like this:

Number of crashers: 16
Number of bugs: 25
etc.

Next, I decided to tackle the authentication problem. I did some searches on variations of “gitlab authentication plugin”, “add gitlab authentication to webpage”, etc., to see if there was something ready-made I could drop in. No such luck. I did find NodeJS modules that I could have used, had I been writing the site using NodeJS. I weighed the unknown cost of implementing the authentication in plain old browser JS against the unknown cost of setting up tools that I was unfamiliar with in order to use the ready-made module (I wasn’t even sure what tools I would have to use — Webpack, I think?) and decided to keep looking.

I next searched for things like “gitlab oauth2 in browser”, “gitlab oauth2 example”, since I knew that the login used the OAuth2 protocol. Eventually I landed on this page and figured out that the magic words I wanted were “implicit flow” or “implicit grant”:

Implicit Flow – This flow is designed for user-agent only apps (e.g. single page web application running on GitLab Pages).

That sounded like exactly my use case, so I read further. You have to send the user to a certain page on the GitLab site, and send a redirect URL which the user will be sent back to with the authorization token in the URL hash. I managed to keep everything on the same webpage. In pseudocode, the flow looks like this:

if we have the authorization token:
    fetch the numbers with the API calls
else if there is a hash in the URL:
    token = get the token from the hash
    store the token
    fetch the numbers with the API calls
else:
    show a button that links to the authorization URL on GitLab

For storing the token so that you don’t have to log in every time, I used localStorage. I have no idea if that’s good practice or not, but from what I could read online it seems that it’s at least not bad practice. It’s quite easy to retrieve the token, but only if you have access to the browser where it is stored. I don’t think localStorage can leak out over the web, but with the recently discovered vulnerabilities who knows…

Last, I made it look nicer. I had a pretty good idea of what I wanted it to look like: I wanted the numbers to be large, in colored boxes with rounded corners and thick borders. I tried a few things with floating <div>s before giving up and using a CSS flex layout. This makes the page probably unviewable on older browsers, but I was seriously done with CSS positioning.

The code is here, or just “View Source” while you’re on the page.

What I would do differently

Writing HTML, CSS, and JS directly for the web is tedious and repetitive. I wish my younger self had used some sort of framework like Bootstrap to make my personal site. Failing that, I wish I had decided not to reuse components from my personal site to do this, and instead started with a fresh site using a framework. Bootstrap or Semantic UI are two that I know of, and maybe should have tried out. The code ended up being 263 lines of HTML, CSS, and JS, much of it just repeated items in order to do the boxes in different colors.

Reuse of this code

You may notice I did not release this code under an open source license. That’s because it’s probably full of bad practices, so I don’t want people to copy it. If you can convince me that it’s done right or tell me what I did wrong, then I’ll (fix it and) open-source it, and other GitLab maintainers might find it useful.

Advertisements

Geek tip: g_object_new and constructors

tl;dr Don’t put any code in your foo_label_new() function other than g_object_new(), and watch out with Vala.

From this GJS bug report I realized there’s a trap that GObject library writers can fall into,

Avoid code at your construction site.

Avoid code at your construction site.

that I don’t think is documented anywhere. So I’m writing a blog post about it. I hope readers from Planet GNOME can help figure out where it needs to be documented.

For an object (let’s call it FooLabel) that’s part of the public API of a library (let’s call it libfoo), creating the object via its foo_label_new() constructor function should be equivalent to creating it via g_object_new().

If foo_label_new() takes no arguments then it should literally be only this:

FooLabel *
foo_label_new(void)
{
    return g_object_new(FOO_TYPE_LABEL, NULL);
}

If it does take arguments, then they should correspond to construct properties, and they should get set in the g_object_new() call. (It’s customary to at least put all construct-only properties as arguments to the constructor function.) For example:

FooLabel *
foo_label_new(const char *text)
{
    return g_object_new(FOO_TYPE_LABEL,
        "text", text,
        NULL);
}

Do not put any other code in foo_label_new(). That is, don’t do this:

FooLabel *
foo_label_new(void)
{
    FooLabel *retval = g_object_new(FOO_TYPE_LABEL, NULL);
    retval->priv->some_variable = 5;  /* Don't do this! */
    return retval;
}

The reason for that is because callers of your library will expect to be able to create FooLabels using g_object_new() in many situations. This is done when creating a FooLabel in JS and Python, but also when creating one from a Glade file, and also in plain old C when you need to set construct properties. In all those situations, the private field some_variable will not get initialized to 5!

Instead, put the code in foo_label_init(). That way, it will be executed regardless of how the object is constructed. And if you need to write code in the constructor that depends on construct properties that have been set, use the constructed virtual function. There’s a code example here.

If you want more details about what function is called when, Allison Lortie has a really useful blog post.

This trap can be easy to fall into in Vala. Using a construct block is the right way to do it:

namespace Foo {
public class Label : GLib.Object {
    private int some_variable;

    construct {
        some_variable = 5;
    }
}
}

This is the wrong way to do it:

namespace Foo {
public class Label : GLib.Object {
    private int some_variable;

    public Label() {
        some_variable = 5;  // Don't do this!
    }
}
}

This is tricky because the wrong way seems like the most obvious way to me!

This has been a public service announcement for the GNOME community, but here’s where you come in! Please help figure out where this should be documented, and whether it’s possible to enforce it through automated tools.

For example, the Writing Bindable APIs page seems like a good place to warn about it, and I’ve already added it there. But this should probably go into Vala documentation in the appropriate place. I have no idea if this is a problem with Rust’s gobject_gen! macro, but if it is then it should be documented as well.

Documented pitfalls are better than undocumented pitfalls, but removing the pitfall altogether is better. Is there a way we can check this automatically?

Wrapping up GUADEC 2017

I’m now back home after attending GUADEC 2017 in Manchester, followed by a week of half-vacation traveling around the Netherlands and visiting old friends. It was a fantastic opportunity to meet others in the GNOME community once again; having gone to a few hackfests and conferences in the past two years, I now recognize many friendly faces that I am happy to get a chance to see from time to time.

Talks

Here’s what I attended during the conference; I’ll link to the videos and provide a sentence or two of commentary.

  • The GNOME Way, Allan Day (video) — for me, one of the two highlights of the conference, a great statement of what makes GNOME tick, and a great opener for its 20th birthday.
  • Limited Connectivity, Endless Apps, Joaquim Rocha (video) — although already familiar to me, it was a nice overview of the product that I work on at Endless.
  • State of the Builder, Christian Hergert — one of these days I will start using Builder as soon as I can find some time to get it to learn my preferred keybindings.
  • The Battle over Our Technology, Karen Sandler (video) — the second of the two conference highlights, a timely reminder of why free software is important.
  • Seamless Integration to Hack Desktop Applications, Simon Schampijer (video) — my coworker and fellow-person-whose-last-name-gets-pronounced-wrong Simon showed off one of the most empowering features that I have ever seen.
  • Progressive Web Apps: an Opportunity for GNOME, Stephen Pearce (video) — I have been reading a lot about progressive web apps recently and am both excited and skeptical. (Stephen also made a webkit game in GJS in just one day.)
  • Different Ways of Outreaching Newcomers, Julita Inca (video) — it was fantastic to see this legendary GNOME mentor and organizer speak in person.
  • Lightning talks by the GSoC and Outreachy interns (video) — I always admire the intern sessions because I would have soiled myself had I had to speak to a 300-person conference room back when I was an intern. Hopefully next year the interns will have a session earlier in the day so their audience is fresher though! Also a shout out to my coworkers Kate Lasalle-Klein and Robin Tafel who are not interns but also gave a lightning talk during this session about working together with the GNOME design team. (If you’re looking for it in the other lightning talk video, you’re not finding it because it was in this session.)
  • Fantastic Layouts and Where to Find Them, Martin Abente Lahaye (video) — a great introduction to Emeus, the constraint layout manager, with a surprise appearance from an airplane hack.
  • Replacing C Library Code with Rust: What I Learned, Federico Mena Quintero (slides) — I am mentoring a Summer of Code student, Luke, who is doing some investigation into converting parts of GJS into Rust, and this talk really helped me understand some things from his work that I’ve been struggling with.
  • Continuous: Past, Present, Future, Emmanuele Bassi (video) — this talk made me want to help out on that lonely, lonely build sheriff mountain.
  • A Brief History of GNOME, Jonathan Blandford (video) — I had seen it before, but an hour well spent.
  • GNOME to 2020 and Beyond, Neil McGovern (video) — by turns optimistic and pessimistic, the new GNOME executive director talked about the future.
  • What’s Coverity Static Analysis Ever Done for Us?, Philip Withnall (video) — my coworker and fellow-person-with-an-excellent-first-name Philip talked about static analysis, which I cannot wait to start using on GJS.
  • Building a Secure Desktop with GNOME Technologies, Matthew Garrett (video) — the excellent “raise your hand if your system is bugging you to install an update right now” line made this talk for me.
  • GNOME Build Strategies and BuildStream, Tristan Van Berkom (video) — not quite what I expected, but luckily I got a better idea of what BuildStream does from the unconference session.
  • Bringing GNOME Home to Ubuntu, Tim Lunn (video) — it was a pleasure to meet Tim in person, who did the SpiderMonkey porting work on GJS before me, and whose commits I have often referred to.
  • GitLab, Carlos Soriano — I’m really excited to kick Bugzilla out of my workflow as soon as I can.
  • Microsoft ❤️ Linux, Julian Atanasoae — If nothing else Julian is brave to get up in front of this audience and sing the praises of Microsoft. I am skeptically optimistic; sure, Microsoft is doing some great things for open source, I even had a slide about some Microsoft tools in my talk, but on the other hand let’s not forget they were still trying to undermine and destroy our community not too long ago.
  • How to Get Better Mileage out of Glade, Juan Pablo Ugarte (video) — Slides created in Glade, what more could you ask for?
  • Lightning talks (video) —The highlight for me of the second lightning talk session was Sri’s self-described “rant.” There were a few talks in the lineup that I felt it was too bad didn’t get any time.

There were also so many talks that were programmed opposite the talks that I decided to go see. It seemed like that happened more often than last year! (Either my interests have broadened, or the quality of the talks is increasing…) I will be watching many videos in the coming days, now that they have been released, but I was especially sad not to see the two talks on animations by Jakub Steiner and Tobias Bernard because they were opposite (and immediately after, respectively) my own talk!

And the video of my talk is now published as well, although like many people I find it excruciating to watch myself on video; the rest of you can watch it, I’ll watch this instead.

Unconference

The unconference part of the conference (where people propose topics, get together with like-minded attendees in a conference room, and talk or work together) was held in a nice workspace. I had one session on GJS on Monday where we first discussed how the Ubuntu desktop team (I got to meet Ken VanDine, Iain Lane, and Chris Coulson, as well as connect with Tim Lunn again) was going to deploy Mozilla’s security updates to Javascript (and therefore GJS and GNOME Shell) in Ubuntu’s long-term support releases. Then Stephen Pearce joined and suggested a GJS working group in order to make development more visible.

Later I joined the GNOME Shell performance session where I rebased Christian Hergert’s GJS profiler code and showed Jonas Adahl how it worked; we profiled opening and closing the overview.

On the second day I joined the Continuous and Builder sessions. Builder was looking good on a giant TV set!

On the third day I attended the BuildStream session and I’m quite excited about trying it out for a development workflow while hacking on a component of a Flatpak runtime, which is a shaky task at best using the current Flatpak tools.

In the afternoon I technically “had another GJS session” though it’s my experience on the third unconference day that all the sessions melt into one. This time many people went on a hike in the afternoon. I was very sad to have missed it, since I love hiking, but I was having an allergy attack at the time which made it difficult for me to be outside. However, I spent the afternoon working on the GObject class stuff for GJS instead, and chatting with people.

Social events

This GUADEC conference had the best social event on Saturday night: a GNOME 20th birthday party, complete with cake, old farts Q&A panel, trivia quiz, raffle, and a blast from the past dance floor with music from back when GNOME started. There was even an afterparty way into the small hours … which I did not go to because my talk was in the first slot on Sunday morning!

Apart from that there were many opportunities to connect with people, from day 1 through 6. One thing I like about GUADEC is that the days are not stuffed full of talks and there is plenty of time to have casual conversations with people. One “hallway session” that I had, for example, was a conversation with Marco Barisione, talking about the reverse debuggers RR and UndoDB. Another was with with Sri Ramkrishna, following on from his lightning “rant” on Sunday, about what kind of help beginning app writers are looking for, whether they can get it from tutorials or Stack Overflow, and what kinds of things get in their way.

Thanks

Many thanks to the GNOME Foundation for sponsoring my attendance. I’m really glad to have been able to join in this year.

sponsored-badge-shadow

Modern Javascript in GNOME – GUADEC 2017 talk

I gave a presentation at GUADEC 2017 this morning on modern Javascript in GNOME, the topic of the last few posts on this blog. As I promised during the talk, here are the slides. There is a beefy appendix after the questions slide, with details about all the new language features, that you are welcome to use as a reference.

Thanks to the GNOME Foundation for the travel sponsorship, to my employer Endless for paying for some of this work, and especially to Rob McQueen for the last-minute loan of a USB-C video adapter!

Official badge from the GUADEC website: "I'm going to The GNOME Conference GUADEC Manchester, United Kingdom"

Inventing GObject ES6 classes

Hello again! If you’re a GJS user, I’d like your opinion and ideas. After my last post where I talked about new features coming in GNOME 3.26 to GJS, GNOME’s Javascript engine, I’m happy to say that the patches are nearly ready to be landed. We just need to figure out how to build SpiderMonkey 52 consistently even though Mozilla hasn’t made an official standalone release of it yet.

A top view of a latte next to a notebook with a pen, with coffee beans strewed artfully around.

A better literal depiction of JAVA SCRIPT I could not ask for… (Public domain image courtesy of Engin_Akyurt)

As I reported last time:

After that is done, I will refactor GJS’s class system (Lang.Class and GObject.Class). I believe this needs to be done before GNOME 3.26. That’s because [we will] gain ES6 classes, and I want to avoid the situation where we have two competing, and possibly incompatible, ways to write classes.

That’s what I’m busy doing now, in the run-up to GUADEC later this month, and I wanted to think out loud in this blog post, and give GJS users a chance to comment.

First of all, the legacy Lang.Class classes will continue to work. You will be able to write ES6 classes that inherit from legacy classes, so you can start using ES6 classes without refactoring all of your code at once.

That was the good news, now the bad

However, there is not an obvious way to carry over the ability to create GObject classes and interfaces from legacy classes to ES6 classes. The main problem is that Lang.Class and its subclasses formed a metaclass framework. This was used to carry out certain activities at the time the class object itself was constructed, such as registering with the GType system.

ES6 classes don’t have a syntax for that, so we’ll have to get a bit creative. My goals are to invent something (1) that’s concise and pleasant to use, and (2) that doesn’t get in the way when classes gain more features in future ES releases; that is, not too magical. (Lang.Class is pretty magical, but then again, there wasn’t really an alternative at the time.)

Here is how the legacy classes worked, with illustrations of all the possible bells and whistles:

The metaclass magic in Lang.Class notices that the class extends GObject.Object, and redirects the construction of the class object to GObject.Class. There, the other magic properties such as Properties and Signals are processed and removed from the prototype, and it calls a C function to register the type with the GObject type system.

Without metaclasses, it’s not possible to automatically carry out magic like that at the time a class object is constructed. However, that is exactly the time when we need to register the type with GObject. So, you pretty much need to remember to call a function after the class declaration to do the registering.

The most straightforwardly translated (fictional) implementation might look something like this:

The fictional GObject.registerClass() function would take the role of the metaclass’s constructor.

This is a step backwards in a few ways compared to the legacy classes, and very unsatisfying. ES6 classes don’t yet have syntax for fields, only properties with getters, and the resulting static get syntax is quite unwieldy. Having to call the fictional registerClass() function separately from the class is unpleasant, because you can easily forget it.

On the other hand, if we had decorators in the language we’d be able to make something much more satisfying. If you’re familiar with Python’s decorators, these are much the same thing: the decorator is a function which takes the object that it decorates as input, performs some action on the object, and returns it. There is a proposed decorator syntax for Javascript that allows you to decorate classes and class properties. This would be an example, with some more fictional API:

This is a lot more concise and natural, and the property decorators are similar to the equivalent in PyGObject, but unfortunately it doesn’t exist. Decorators are still only a proposal, and none of the major browser engines implement them yet. Nonetheless, we can take the above syntax as an inspiration, use a class expression, and move the registerClass() function around it and the GObject stuff outside of it:

Here, the body of the class is almost identical to what it would be with the decorator syntax. All the extra stuff for GObject is contained at the top of the class like it would be with the decorators. We don’t have the elegance of the property decorator, but this is quite an improvement on the first iteration. It’s not overly magical, it even acts like a decorator: it takes a class expression, and gives back a GObject-ized class. And when decorators eventually make it into standard Javascript, the basic idea is the same, so converting your code will be easy enough. (Or those who use transpiling tools can already go ahead and implement the decorator-based API.)

This is the best API I’ve been able to come up with so far. What do you think? Would you want to use it? Reply to this post or come talk to me in #javascript on GNOME IRC.

Next steps

Note first of all that none of this code exists yet. Depending on what feedback I get here, I hope to have a draft version working before GUADEC, and around the same time I’ll post a more detailed proposal to the javascript-list mailing list.

In addition, I will be speaking about this and more at GUADEC in my talk, “Modern Javascript in GNOME“. If you are attending, come talk to me there! Thanks to the GNOME Foundation for sponsoring my travel and accommodations.

Official badge from the GUADEC website: "I'm going to The GNOME Conference GUADEC Manchester, United Kingdom"

The GJS documentation is back

Aside

We have once again a set of accurate, up-to-date documentation for GJS. Find it at devdocs.baznga.org!

Many thanks are due to Everaldo Canuto, Patrick Griffis, and Dustin Falgout for helping get the website back online, and to Nuveo for sponsoring the hosting.

In addition, thanks to Patrick’s lead, we have a docker image if you want to run the documentation site yourself.

If you find any inaccuracies in the documentation, please report a bug at this issue tracker.

GJS: What’s next?

In my last post, I went into detail about all the new stuff that GJS brought to GNOME 3.24. Now, it’s time to talk about the near future: what GJS will bring to GNOME 3.26.

Javascript engine

The highest priority is to keep upgrading the Javascript engine. At the time of writing, I’ve got SpiderMonkey 45 almost, but not quite, working, and Mozilla is on the verge of releasing the standalone version of SpiderMonkey 52. If we can get there, then we’ll finally be on a supported release which means we can have a closer collaboration with the Mozilla team. (During the past six months, they’ve been patient with me asking questions about old, unsupported releases, but it’s not fair to ask them to continue doing that.)

I plan to upgrade to 45 but not merge it, and then immediately continue upgrading to 52 on the same branch, then merge it all in at the same time. That way, we won’t have an interregnum where everyone has to build SpiderMonkey 45 in JHBuild and Continuous and the Flatpak SDK. Subscribe to bug 781429 and its offshoots if you want to follow along.

The main language features that this will bring in are: classes (45) and ES7 async/await statements (52). At that point, the only major ES6 feature that we will still be missing is modules.

ES6 Classes

After that is done, I will refactor GJS’s class system (Lang.Class and GObject.Class). I believe this needs to be done before GNOME 3.26. That’s because in SpiderMonkey 45, we gain ES6 classes, and I want to avoid the situation where we have two competing, and possibly incompatible, ways to write classes.

ES6 Modules

Full ES6 module support is still missing in SpiderMonkey 52, but at least some parts of it are implemented. I’ll need to investigate if it’s possible to enable them in GJS already. Although, we will definitely not enable them yet if there’s no way to keep the existing modules working; we don’t want to break everyone’s code.

Developer tools

Next comes a debugger. There are not one, not two, but three existing implementations of a GJS debugger sitting unattended in Bugzilla or a Git branch. None of them will apply to the codebase as is, so my task will be to fix them up, evaluate the merits of each one, and hopefully come up with one patchset to rule them all.

Christian Hergert is planning to add a profiler, so that you can profile your Javascript code with Sysprof, inside Builder.

Documentation

I would very much like to get the GJS documentation browser back online. I hosted it on EC2, but I have run out of free hosting. If you have a server where it can be parked, let me know! (It’s a web app, not static pages, so I can’t just put it on GitHub Pages.) If you want to run the web app locally yourself, you can find instructions here for how I set it up on EC2, on a RHEL 7 box.

Misc.

All that is probably more than I’ll have time for, but here are some of the things that I’d like to get done after that:

  • Update the tutorials on developer.gnome.org to use more modern GJS
  • Better integration with Builder
  • Use structured logging to clean up the “debug topics” mechanism
  • Reduce the list of unreviewed patches in Bugzilla down to 0
  • Find ways to bring in some of the conveniences that Node developers are used to

Chun-wei Fan is working on converting some of the codebase to use C++ smart pointers so that we get the memory leak safety advantages of g_autoptr without losing portability to MSVC.

Build system

The question is inevitable: are we going to switch the build system to Meson? I’m looking forward to it, but no, not until Meson is more mature and some of the open questions about distribution and autobuilding have been answered.

Help!

I think it’s great that once I started contributing, other people soon started contributing too. The 1.48.0 release had way more patches and contributors than 1.46.0, even if you don’t count all the stale patches that I souped up. GNOME’s #javascript IRC channel is starting to be a lively place, compared to how deserted it was last year.

What I’d most like to encourage is for more people to contribute major features so that the above list doesn’t read like a to-do list that’s mostly for me. I’m happy to provide guidance. I think it would be great for GJS to become a more competitive development language for apps using the GNOME technology stack1 and we won’t get there with just me.

Another way you can help is by using the development version of GJS while developing your apps or GNOME Shell, thereby helping to try out the new features. We had some serious bugs up to, or even past, the last minute in GNOME 3.24, and this seems like the best way to prevent that.

Finally, you can help by sharing your experiences with GJS: good and bad. Talk on the mailing list or IRC, or file a bug on bugzilla.gnome.org if there’s something wrong.


[1] In that regard I’d love to prove wrong Michael Catanzaro’s opinion about using GJS: “there’s no way to change the reality that JavaScript is a terrible language. It has close to zero redeeming features, and many confusing ones.” There is a way! In my opinion ES6 and ES7 have gone a long way towards filling in those potholes. To name just a few, arrow functions mean you can almost always stop caring about the pitfall of what this refers to, and the prospect of doing asynchronous I/O with Promises instead of callbacks actually makes me want to use JS. Of course, in-browser JS is still a terrible language because it has to support the lowest common denominator of Javascripts so that people who haven’t upgraded their browser since Internet Explorer 8 can still visit your website, and that’s why modern web developers preprocess and transpile it to high heaven. But we don’t have to care about all those browser users!