Skip to main content

the avatar of Federico Mena-Quintero

Librsvg moves to Gitlab

Librsvg now lives in GNOME's Gitlab instance. You can access it here.

Gitlab allows workflows similar to Github: you can create an account there, fork the librsvg repository, file bug reports, create merge requests... Hopefully this will make it nicer for contributors.

In the meantime, feel free to take a look!

This is a huge improvement for GNOME's development infrastructure. Thanks to Carlos Soriano, Andrea Veri, Philip Chimento, Alberto Ruiz, and all the people that made the move to Gitlab possible.

the avatar of Federico Mena-Quintero

A mini-rant on the lack of string slices in C

Porting of librsvg to Rust goes on. Yesterday I started porting the C code that implements SVG's <text> family of elements. I have also been replacing the little parsers in librsvg with Rust code.

And these days, the lack of string slices in C is bothering me a lot.

What if...

It feels like it should be easy to just write something like

typedef struct {
    const char *ptr;
    size_t len;
} StringSlice;

And then a whole family of functions. The starting point, where you slice a whole string:

StringSlice
make_slice_from_string (const char *s)
{
    StringSlice slice;

    assert (s != NULL);

    slice.ptr = s;
    slice.len = strlen (s);
    return slice;
}

But that wouldn't keep track of the lifetime of the original string. Okay, this is C, so you are used to keeping track of that yourself.

Onwards. Substrings?

StringSlice
make_sub_slice(StringSlice slice, size_t start, size_t len)
{
    StringSlice sub;

    assert (len <= slice.len);
    assert (start <= slice.len - len);  /* Not "start + len <= slice.len" or it can overflow. */
                                        /* The subtraction can't underflow because of the previous assert */
    sub.ptr = slice.ptr + start;
    sub.len = len;
    return sub;
}

Then you could write a million wrappers for g_strsplit() and friends, or equivalents to them, to give you slices instead of C strings. But then:

  • You have to keep track of lifetimes yourself.

  • You have to wrap every function that returns a plain "char *"...

  • ... and every function that takes a plain "char *" as an argument, without a length parameter, because...

  • You CANNOT take slice.ptr and pass it to a function that just expects a plain "char *", because your slice does not include a nul terminator (the '\0 byte at the end of a C string). This is what kills the whole plan.

Even if you had a helper library that implements C string slices like that, you would have a mismatch every time you needed to call a C function that expects a conventional C string in the form of a "char *". You need to put a nul terminator somewhere, and if you only have a slice, you need to allocate memory, copy the slice into it, and slap a 0 byte at the end. Then you can pass that to a function that expects a normal C string.

There is hacky C code that needs to pass a substring to another function, so it overwrites the byte after the substring with a 0, passes the substring, and overwrites the byte back. This is horrible, and doesn't work with strings that live in read-only memory. But that's the best that C lets you do.

I'm very happy with string slices in Rust, which work exactly like the StringSlice above, but &str is actually at the language level and everything knows how to handle it.

The glib-rs crate has conversion traits to go from Rust strings or slices into C, and vice-versa. We alredy saw some of those in the blog post about conversions in Glib-rs.

Sizes of things

Rust uses usize to specify the size of things; it's an unsigned integer; 32 bits on 32-bit machines, and 64 bits on 64-bit machines; it's like C's size_t.

In the Glib/C world, we have an assortment of types to represent the sizes of things:

  • gsize, the same as size_t. This is an unsigned integer; it's okay.

  • gssize, a signed integer of the same size as gsize. This is okay if used to represent a negative offset, and really funky in the Glib functions like g_string_new_len (const char *str, gssize len), where len == -1 means "call strlen(str) for me because I'm too lazy to compute the length myself".

  • int - broken, as in libxml2, but we can't change the API. On 64-bit machines, an int to specify a length means you can't pass objects bigger than 2 GB.

  • long - marginally better than int, since it has a better chance of actually being the same size as size_t, but still funky. Probably okay for negative offsets; problematic for sizes which should really be unsigned.

  • etc.

I'm not sure how old size_t is in the C standard library, but it can't have been there since the beginning of time — otherwise people wouldn't have been using int to specify the sizes of things.

a silhouette of a person's head and shoulders, used as a default avatar

Hackweek 16 - The YaST Integration Tests II.

Hackweek 16 (0x10)

I spent the previous Hackweek with Cucumber and YaST. It worked quite well but it turned out to be too big step forward and focused on one specific testing framework.

This time I decided to make a smaller step, but make the solution more generic. So instead of having direct Cucumber support in the UI I proposed implementing a generic REST API. The API can be then used by any framework (Cucumber, RSpec…) or it can be used directly by any script or tool.

See also the Hackweek project page.

Implementation

The current solution is based on these two key libraries:

Both libraries are already included in the openSUSE distributions so it is easy to use them.

Installation

After compiling and installing new libyui, libyui-qt and recompiling yast2-ycp-ui-bindings (because of ABI changes) you can run any YaST module with YUI_HTTP_SERVER=14155 environment variable set. Then you can access the REST API via the port 14115 using curl command. (You can use a different port number.)

Using the REST API

Run the YaST repository manager (as root):

YUI_HTTP_PORT=14155 yast2 repositories

Embedded help

This will start the YaST module as usually, there is no visible change. You can normally use the module, the only change is that the UI now listens on the port 14155 for incoming HTTP requests.

You can access the REST API (root not required) from command line like this:

> # dump the current dialog as a tree
> curl 'http://localhost:14155/dialog'
{
  "class" : "YDialog",
  "hstretch" : true,
  "type" : "wizard",
  "vstretch" : true,
  "widgets" : 
  [
    {
      "class" : "YWizard",
      "debug_label" : "Configured Software Repositories",
      "hstretch" : true,
      "id" : "wizard",
      "vstretch" : true,
      "widgets" : 
      [
...
> # dump the current dialog as a simple list (easier iteration, search)
> curl 'http://localhost:14155/widgets'
[
  {
    "class" : "YDialog",
    "hstretch" : true,
    "type" : "wizard",
    "vstretch" : true
  },
  {
    "class" : "YWizard",
    "debug_label" : "Configured Software Repositories",
    "hstretch" : true,
    "id" : "wizard",
    "vstretch" : true
  },
...
> # filter widgets by ID
> curl 'http://localhost:14155/widgets?id=enable'
[
  {
    "class" : "YCheckBox",
    "debug_label" : "Enabled",
    "id" : "enable",
    "label" : "E&nabled",
    "notify" : true,
    "value" : true
  }
]
> # filter widgets by label (as displayed, might be translated!)
> curl 'http://localhost:14155/widgets?label=Priority'
[
  {
    "class" : "YIntField",
    "debug_label" : "Priority",
    "hstretch" : true,
    "id" : "priority",
    "label" : "&Priority",
    "max_value" : 200,
    "min_value" : 0,
    "notify" : true,
    "value" : 99
  }
]
> # filter widgets by type (all check boxes in this case)
> curl 'http://localhost:14155/widgets?type=YCheckBox'
[
  {
    "class" : "YCheckBox",
    "debug_label" : "Enabled",
    "id" : "enable",
    "label" : "E&nabled",
    "notify" : true,
    "value" : true
  },
  {
    "class" : "YCheckBox",
    "debug_label" : "Automatically Refresh",
    "id" : "autorefresh",
    "label" : "Automatically &Refresh",
    "notify" : true,
    "value" : true
  },
  {
    "class" : "YCheckBox",
    "debug_label" : "Keep Downloaded Packages",
    "id" : "keeppackages",
    "label" : "&Keep Downloaded Packages",
    "notify" : true,
    "value" : false
  }
]
> # and finally do some action - press the [Abort] button and close the module,
> # you can use the same filters as in the queries above
> curl -X POST 'http://localhost:14155/widgets?id=abort&action=press'

To make it cool I have included some inline documentation or help, just open http://localhost:14155 URL in your browser:

Embedded help

Running a Cucumber Test

I have also written a simple set of step definitions for the Cucumber framework. This allows using the REST API in Cucumber integration tests.

Let’s have this example Cucumber test:

Feature: To install the 3rd party packages I must be able to add a new package
  repository to the package management.

  Background:

    # make sure the tested repository does not already exist
    When I run `zypper repos --uri`
    Then the output should not contain "https://download.opensuse.org/tumbleweed/repo/oss/"

  Scenario: Aborting the repository manager keeps the old settings

    Given I start the "/usr/sbin/yast2 repositories" application
    Then the dialog heading should be "Configured Software Repositories"

    When I click button "Add"
    Then the dialog heading should be "Add On Product"

    When I click button "Next"
    Then the dialog heading should be "Repository URL"

    When I enter "Tumbleweed OSS" into input field "Repository Name"
    And I enter "https://download.opensuse.org/tumbleweed/repo/oss/" into input field "URL"
    And I click button "Next"
    Then the dialog heading should be "Tumbleweed OSS License Agreement" in 60 seconds

    When I click button "Next"
    Then the dialog heading should be "Configured Software Repositories"

    When I click button "Cancel"
    Then a popup should be displayed
    And a label including "Abort the repository configuration?" should be displayed

    Then I click button "Yes"
    And I wait for the application to finish

    # verify that the tested repository was NOT added
    When I run `zypper repos --uri`
    Then the output should not contain "https://download.opensuse.org/tumbleweed/repo/oss/"

If you run it the result would look like this:

Adding a Repository in YaST

Pretty nice isn’t it?

Generic Usage

Because the REST API is implemented on the UI (libyui) level it means that any application using the library can be tested the same way, it is not limited only to YaST. For example it should be very easy to write tests also for the Mageia tools included in the Megeia distribution.

TODO

There are lots of missing features, mainly:

  • Return more details in the response, add missing attributes
  • Support more actions besides clicking a button or filling an InputField
  • Support more UI calls (e.g. UI.PollInput)
  • Support the other UIs (ncurses, maybe GTK)
  • Support for the package manager widget (implemented in the libyui-*-pkg subpackages)
  • Packaging - make the feature optional (if you do not want to include the web server for security reasons)
  • Add more step definitions in the Cucumber wrapper

Optional Features

  • User authentication (unauthenticated access is a security hole, but it might be OK when running tests in a sandboxed environment in a trusted network)
  • SSL support (securely transfer the current values and set the new values, e.g. the root password)
  • IPv6 support (it’s the future, isn’t it?)
  • Unix socket support (another kind of user authorization)

Conclusion

The feature is far from being production ready, it is still rather a proof of concept. But it shows that it works well and we can continue in this direction in the future.

a silhouette of a person's head and shoulders, used as a default avatar
a silhouette of a person's head and shoulders, used as a default avatar
darix posted in English at

Making Rails packaging easier - Part1

One step at a time. Today: Requires

You might have seen that we package rails apps for a while now. We have discourse, gitlab-ce, errbit and our own open build service. I probably forgot an app or 2 here. Anyway if you look at all the spec files e.g. this one. You notice we have to specify the Requires manually.

BuildRequires:  %{rubygem rails:5 >= 5.1}
Requires:       %{rubygem rails:5 >= 5.1}

This comes with a few problems actually.

the avatar of Sebastian Kügler

KDE’s Goal: Privacy

by Banksy
by Banksy
At Akademy 2016, the KDE community started a long-term project to invigorate its development (both, technically and organizationally) with more focus. This process of soul-searching has already yielded some very useful results, the most important one so far being agreement of a common community-wide vision:

A world in which everyone has control over their digital life and enjoys freedom and privacy.

This presents a very high-level vision, so a logical follow-up question has been how this influences KDE’s activities and actions in practice. KDE, being a fairly loose community with many separate sub-communities and products, is not an easy target to align to a common goal. A common goal may have very different on each of KDE’s products, for an email and groupware client, that may be very straight-forward (e.g. support high-end crypto, work very well with privacy-respecting and/or self-hosted services), for others, it may be mostly irrelevant (a natural painting app such as Krita simply doesn’t have a lot of privacy exposure), yet for a product such as Plasma, the implications may be fundamental and varied.
So in the pursuit of the common ground and a common goal, we had to concentrate on what unites us. There’s of course Software Freedom, but that is somewhat vague as well, and also it’s already entrenched in KDE’s DNA. It’s not a very useful goal since it doesn’t give us something to strive for, but something we maintain anyway. A “good goal” has to be more specific, yet it should have a clear connection to Free Software, since that is probably the single most important thing that unites us. Almost two years ago, I posed that privacy is Free Software’s new milestone, trying to set a new goal post for us to head for. Now the point where these streams join has come, and KDE has chosen privacy as one of its primary goals for the next 3 to 4 years. The full proposal can be read here.
“In 5 years, KDE software enables and promotes privacy”

Privacy, being a vague concept, especially given the diversity in the KDE community needs some explanation, some operationalization to make it specific and to know how we can create software that enables privacy. There are three general focus areas we will concentrate on: Security, privacy-respecting defaults and offering the right tools in the first place.

Security

Improving security means improving our processes to make it easier to spot and fix security problems and avoiding single points of failure in both software and development processes. This entails code review, quick turnaround times for security fixes.

Privacy-respecting defaults

Defaulting to encrypted connections where possible and storing sensible data in a secure way. The user should be able to expect the KDE software Does The Right Thing and protect his or her data in the best possible way. Surprises should be avoided as much as possible, and reasonable expectations should be met with best effort.

Offering the right tools

KDE prides itself for providing a very wide range of useful software. From a privacy point of view, some functions are more important than others, of course. We want to offer the tools that most users need in a way that allows them to lead their life privately, so the toolset needs to be comprehensive and cover as many needs as possible. The tools itself should make it easy and straight-forward to achieve privacy. Some examples:

  • An email client allowing encrypted communication
  • Chat and instant messenging with state-of-the art protocol security
  • Support for online services that can be operated as private instance, not depending on a 3rd party provider

Of course, this is only a small part, and the needs of our userbase varies wildly.

Onwards from here…

In the past, KDE software has come a long way in providing privacy tools, but the tool-set is neither comprehensive, nor is privacy its implications widely seen as critical to our success in this area. Setting privacy as a central goal for KDE means that we will put more focus on this topic and lead to improved tools that allow users to increase their level of privacy. Moreover, it will set an example for others to follow and hopefully increase standards across the whole software ecosystem. There is much work to do, and we’re excited to put our shoulder under it and work on it.

the avatar of Just Another Tech Blog

Group Policy Management Console for Linux

I’m working on a YaST module that imitates the behavior of the Group Policy Management Console in linux.

You can install it on openSUSE Tumbleweed via:
sudo zypper in yast2-python-bindings
sudo zypper ar https://download.opensuse.org/repositories/network:/samba:/STABLE/openSUSE_Tumbleweed/ samba
sudo zypper ref && sudo zypper in yast-gpmc

Then run it with:
yast2 gpmc

It requires yast2-python-bindings version 4.0+, which is only available in openSUSE Tumbleweed at the moment (although it’ll be in the next version of SLE).

the avatar of Just Another Tech Blog

YaST and Python, the new bindings

YaST has had python bindings for about 10 years, but there has been no maintainer for the last 4 years, and they’ve slowly gone kaput.

That has changed. Python+YaST is back. The syntax is (or should be) backwards compatible with <= 3.x of the yast-python-bindings, but you can now write python yast via code very similar to the ruby code.
There are also lots of examples now (thanks to noelp and his hackweek project).

We’re working on a couple of yast modules via the yast-python-bindings:
https://github.com/dmulder/yast-gpmc
https://github.com/noelpower/yast-aduc/tree/wip-aduc

a silhouette of a person's head and shoulders, used as a default avatar

London UX Hackfest

Thanks to the GNOME Foundation, a handful of designers and developers got together last week in London to refocus on the core element of the GNOME experience, the shell. Allan and Cassidy have already summed up everything in their well written blog posts, so I'd like to point to some pretty pictures and the video above.

Stay tuned for some higher fidelity proposals in the areas of app switching & launching and the lock/login experience.

the avatar of Sebastian Kügler

IKEA Trådfri first impressions

Warm white lights
Warm white lights
Since I’ve been playing with various home automation technologies for some time already, I thought I’d also start writing about it. Be prepared for some blogs about smart lighting, smart home and related technologies.

Most recently, I’ve gotten myself a few items from IKEA new product range of smartlight. It’s called trådfri (Swedish for wireless). These lights can be remote-controlled using a smartphone app or other kinds of switches. These products are still fairly young, so I thought I’d give them a try. Overall. the system seems well thought-through and feels fairly high-end. I didn’t notice any major annoyances.

First Impressions

Trådfri hub and dimmer
Trådfri hub and dimmer

My first impressions are actually pretty good. Initially, I bought a hub which is used to control the lights centrally. This hub is required to be able to use the smartphone app or update the firmware of any component (more on that later!). If you just want to use one of the switches or dimmers that come separately, you won’t need the hub.
Setting everything up is straight-forward, the documentation is fine and no special skills are needed to install these smartlights. Unpacking unfortunately means the usual fight with blister packaging (will it ever stop?), but after that, a few handy surprises awaited me. What I liked:
Hub hides cables
Hub hides cables

  • The light is nice and warm. The GU10 bulbs i got give 400 lumens and are dimmable. For my taste, they could be a bit darker at the lower end of the scale, but overall, the light feels comfy warm and not too cold, but not too yellow either. The GU10 bulbs I got are spec’ed at 2700 Kelvin. No visible flickering either.
  • Trådfri components are relatively inexpensive. A hub, dimmer and 4 warm-white GU10 bulbs set me back about 75€. It is way cheaper than comparable smartlights, for example Philips Hue. As needs are fairly individual exact prices are best looked up on IKEA’s website by yourself.
  • The hub has a handy cable storage function, you can roll up excessive cable inside the hub — a godsend if you want to have the slightest chance of preventing a spaghetti situation.
  • The hub is USB-powered, 1A power supply suffices, so you may be able to plug it into the USB port of some other device, or share a power supply.
  • The dimmer can be removed from the cradle. The cradle can be stuck on any flat surface, it doesn’t need additional cabling, and you can easily take out the dimmer and carry it around.
  • The wireless technology used is ZigBee, which is a standard thing and also used by other smarthome technologies, most notably, Philips Hue. I already own (and love) some Philips Hue lights, so in theory I should be able to pair up the Trådfri lights with my already existing Hue lights. (This is a big thing for me, I don’t want to have different lighting networks around in my house, but rather concert the whole lighting centrally.)

Pairing IKEA Trådfri with Philips Hue

Let’s call this “work in progress”, meaning, I haven’t yet been able to pair a Trådfri bulb with my Hue system. I’ll dig some more into it, and I’m pretty sure I’ll make it work at some point. If you’re interested in combining Hue and Trådfri bulbs, I’ll suffice with a couple of pointers:

If you want to try this yourself, make sure you get the most recent lights from the store (the clerk was helpful to me and knowledgable, good advice there!). You’ll also likely need a hub at least for updating the firmware. If you’re just planning to use the bulbs together with a Hue system, you won’t need the hub later on, so that may seem like 30€ down the drain. Bit of a bummer, but depending on how many lights you’ll be buying, given the difference in price between IKEA and Philips, it may well be worth it.

\edit: After a few more tries, the bulb is now paired to the Philips Hue system. More testing will ensue, and I’ll either update this post, or write a new one.

the avatar of Sebastian Kügler