Thomas Goirand: Supporting 3 init systems in OpenStack packages

Planet Debian - Mon, 15/12/2014 - 09:15

tl;dr: Providing support for all 3 init systems (sysv-rc, Upstart and systemd) isn’t hard, and generating the init scripts / Upstart job / systemd using a template system is a lot easier than I previously thought.

As always, when writing this kind of blog post, I do expect that others will not like what I did. But that’s the point: give me your opinion in a constructive way (please be polite even if you don’t like what you see… I had too many times had to read harsh comments), and I’ll implement your ideas if I find it nice.

History of the implementation: how we came to the idea

I had no plan to do this. I don’t believe what I wrote can be generalized to all of the Debian archive. It’s just that I started doing things, and it made sense when I did it. Let me explain how it happened.

Since it’s clear that many, and especially the most advanced one, may have an opinion about which init system they prefer, and because I also support Ubuntu (at least Trusty), I though it was a good idea to support all the “main” init system: sysv-rc, Upstart and systemd. Though I have counted (for the sake of being exact in this blog) : OpenStack in Debian contains currently 64 init scripts to run daemons in total. That’s quite a lot. A way too much to just write them, all by hand. Though that’s what I was doing for the last years… until this the end of this last summer!

So, doing all by hand, I first started implementing Upstart. Its support was there only when building in Ubuntu (which isn’t the correct thing to do, this is now fixed, read further…). Then we thought about adding support for systemd. Gustavo Panizzo, one of the contributors in the OpenStack packages, started implementing it in Keystone (the auth server for OpenStack) for the Juno release which was released this October. He did that last summer, early enough so we didn’t expect anyone to use the Juno branch Keystone. After some experiments, we had kind of working. What he did was invoking “/etc/init.d/keystone start-systemd”, which was still using start-stop-daemon. Yes, that’s not perfect, and it’s better to use systemd foreground process handling, but at least, we had a unique place where to write the startup scripts, where we check the /etc/default for the logging configuration, configure the log file, and so on.

Then around in october, I took a step backward to see the whole picture with sysv-rc scripts, and saw the mess, with all the tiny, small difference between them. It became clear that I had to do something to make sure they were all the same, with the support for the same things (like which log system to use, where to store the PID, create /var/lib/project, /var/run/project and so on…).

Last, on this month of December, I was able to fix the remaining issues for systemd support, thanks to the awesome contribution of Mikael Cluseau on the Alioth OpenStack packaging list. Now, the systemd unit file is still invoking the init script, but it’s not using start-stop-daemon anymore, no PID file involved, and daemons are used as systemd foreground processes. Finally, daemons service files are also activated on installation (they were not previously).


So I took the simplistic approach to use always the same template for the sysv-rc switch/case, and the start and stop functions, happening it at the end of all debian/*.init.in scripts. I started to try to reduce the number of variables, and I was surprised of the result: only a very small part of the init scripts need to change from daemon to daemon. For example, for nova-api, here’s the init script (LSB header stripped-out):


That is it: only 3 lines, defining only the name of the daemon, the name of the project it attaches (eg: nova, cinder, etc.), and a long description. There’s of course much more complicated init scripts (see the one for neutron-server in the Debian archive for example), but the vast majority only needs the above.

Here’s the sysv-rc init script template that I currently use:

#!/bin/sh # The content after this line comes from openstack-pkg-tools # and has been automatically added to a .init.in script, which # contains only the descriptive part for the daemon. Everything # else is standardized as a single unique script. # Author: Thomas Goirand <zigo@debian.org> # PATH should only include /usr/* if it runs after the mountnfs.sh script PATH=/sbin:/usr/sbin:/bin:/usr/bin if [ -z "${DAEMON}" ] ; then DAEMON=/usr/bin/${NAME} fi PIDFILE=/var/run/${PROJECT_NAME}/${NAME}.pid if [ -z "${SCRIPTNAME}" ] ; then SCRIPTNAME=/etc/init.d/${NAME} fi if [ -z "${SYSTEM_USER}" ] ; then SYSTEM_USER=${PROJECT_NAME} fi if [ -z "${SYSTEM_USER}" ] ; then SYSTEM_GROUP=${PROJECT_NAME} fi if [ "${SYSTEM_USER}" != "root" ] ; then STARTDAEMON_CHUID="--chuid ${SYSTEM_USER}:${SYSTEM_GROUP}" fi if [ -z "${CONFIG_FILE}" ] ; then CONFIG_FILE=/etc/${PROJECT_NAME}/${PROJECT_NAME}.conf fi LOGFILE=/var/log/${PROJECT_NAME}/${NAME}.log if [ -z "${NO_OPENSTACK_CONFIG_FILE_DAEMON_ARG}" ] ; then DAEMON_ARGS="${DAEMON_ARGS} --config-file=${CONFIG_FILE}" fi # Exit if the package is not installed [ -x $DAEMON ] || exit 0 # If ran as root, create /var/lock/X, /var/run/X, /var/lib/X and /var/log/X as needed if [ "x$USER" = "xroot" ] ; then for i in lock run log lib ; do mkdir -p /var/$i/${PROJECT_NAME} chown ${SYSTEM_USER} /var/$i/${PROJECT_NAME} done fi # This defines init_is_upstart which we use later on (+ more...) . /lib/lsb/init-functions # Manage log options: logfile and/or syslog, depending on user's choosing [ -r /etc/default/openstack ] && . /etc/default/openstack [ -r /etc/default/$NAME ] && . /etc/default/$NAME [ "x$USE_SYSLOG" = "xyes" ] && DAEMON_ARGS="$DAEMON_ARGS --use-syslog" [ "x$USE_LOGFILE" != "xno" ] && DAEMON_ARGS="$DAEMON_ARGS --log-file=$LOGFILE" do_start() { start-stop-daemon --start --quiet --background ${STARTDAEMON_CHUID} --make-pidfile --pidfile ${PIDFILE} --chdir /var/lib/${PROJECT_NAME} --startas $DAEMON \ --test > /dev/null || return 1 start-stop-daemon --start --quiet --background ${STARTDAEMON_CHUID} --make-pidfile --pidfile ${PIDFILE} --chdir /var/lib/${PROJECT_NAME} --startas $DAEMON \ -- $DAEMON_ARGS || return 2 } do_stop() { start-stop-daemon --stop --quiet --retry=TERM/30/KILL/5 --pidfile $PIDFILE RETVAL=$? rm -f $PIDFILE return "$RETVAL" } do_systemd_start() { exec $DAEMON $DAEMON_ARGS } case "$1" in start) init_is_upstart > /dev/null 2>&1 && exit 1 log_daemon_msg "Starting $DESC" "$NAME" do_start case $? in 0|1) log_end_msg 0 ;; 2) log_end_msg 1 ;; esac ;; stop) init_is_upstart > /dev/null 2>&1 && exit 0 log_daemon_msg "Stopping $DESC" "$NAME" do_stop case $? in 0|1) log_end_msg 0 ;; 2) log_end_msg 1 ;; esac ;; status) status_of_proc "$DAEMON" "$NAME" && exit 0 || exit $? ;; systemd-start) do_systemd_start ;; restart|force-reload) init_is_upstart > /dev/null 2>&1 && exit 1 log_daemon_msg "Restarting $DESC" "$NAME" do_stop case $? in 0|1) do_start case $? in 0) log_end_msg 0 ;; 1) log_end_msg 1 ;; # Old process is still running *) log_end_msg 1 ;; # Failed to start esac ;; *) log_end_msg 1 ;; # Failed to stop esac ;; *) echo "Usage: $SCRIPTNAME {start|stop|status|restart|force-reload|systemd-start}" >&2 exit 3 ;; esac exit 0

Nothing particularly fancy here… You’ll noticed that it’s really OpenStack centric (see the LOGFILE and CONFIGFILE things…). You may have also noticed the call to “init_is_upstart” which is needed for upstart support. I’m not sure if it’s at the correct place in the init script. Should I put that on top of the script? Was I right with the exit values for it? Please send me your comments…

Then I thought about generalizing all of this. Because not only the sysv-rc scripts needed to be squared-up, but also Upstart. The approach here was to source the sysv-rc script in debian/*.init.in, and then generate the Upstart job accordingly, using the above 3 variables (or more as needed). Here, the fun is that, instead of taking the approach of calculating everything at runtime with the sysv-rc, for Upstart jobs, many things are calculated at build time. For each debian/*.init.in script that the debian/rules finds, pkgos-gen-upstart-job is called. Here’s pkgos-gen-upstart-job:

#!/bin/sh INIT_TEMPLATE=${1} UPSTART_FILE=`echo ${INIT_TEMPLATE} | sed 's/.init.in/.upstart/'` # Get the variables defined in the init template . ${INIT_TEMPLATE} ## Find out what should go in After= #SHOULD_START=`cat ${INIT_TEMPLATE} | grep "# Should-Start:" | sed 's/# Should-Start://'` # #if [ -n "${SHOULD_START}" ] ; then # AFTER="After=" # for i in ${SHOULD_START} ; do # AFTER="${AFTER}${i}.service " # done #fi if [ -z "${DAEMON}" ] ; then DAEMON=/usr/bin/${NAME} fi PIDFILE=/var/run/${PROJECT_NAME}/${NAME}.pid if [ -z "${SCRIPTNAME}" ] ; then SCRIPTNAME=/etc/init.d/${NAME} fi if [ -z "${SYSTEM_USER}" ] ; then SYSTEM_USER=${PROJECT_NAME} fi if [ -z "${SYSTEM_GROUP}" ] ; then SYSTEM_GROUP=${PROJECT_NAME} fi if [ "${SYSTEM_USER}" != "root" ] ; then STARTDAEMON_CHUID="--chuid ${SYSTEM_USER}:${SYSTEM_GROUP}" fi if [ -z "${CONFIG_FILE}" ] ; then CONFIG_FILE=/etc/${PROJECT_NAME}/${PROJECT_NAME}.conf fi LOGFILE=/var/log/${PROJECT_NAME}/${NAME}.log DAEMON_ARGS="${DAEMON_ARGS} --config-file=${CONFIG_FILE}" echo "description \"${DESC}\" author \"Thomas Goirand <zigo@debian.org>\" start on runlevel [2345] stop on runlevel [!2345] chdir /var/run pre-start script for i in lock run log lib ; do mkdir -p /var/\$i/${PROJECT_NAME} chown ${SYSTEM_USER} /var/\$i/${PROJECT_NAME} done end script script [ -x \"${DAEMON}\" ] || exit 0 DAEMON_ARGS=\"${DAEMON_ARGS}\" [ -r /etc/default/openstack ] && . /etc/default/openstack [ -r /etc/default/\$UPSTART_JOB ] && . /etc/default/\$UPSTART_JOB [ \"x\$USE_SYSLOG\" = \"xyes\" ] && DAEMON_ARGS=\"\$DAEMON_ARGS --use-syslog\" [ \"x\$USE_LOGFILE\" != \"xno\" ] && DAEMON_ARGS=\"\$DAEMON_ARGS --log-file=${LOGFILE}\" exec start-stop-daemon --start --chdir /var/lib/${PROJECT_NAME} \\ ${STARTDAEMON_CHUID} --make-pidfile --pidfile ${PIDFILE} \\ --exec ${DAEMON} -- --config-file=${CONFIG_FILE} \${DAEMON_ARGS} end script " >${UPSTART_FILE}

The only thing which I don’t know how to do, is how to implement the Should-Start / Should-Stop in an Upstart job. Can anyone shoot me a mail and tell me the solution?

Then, I wanted to add support for systemd. Here, we cheated, since we only just called the sysv-rc script from the systemd unit, however, the systemd-start target uses exec, so the process stays in the foreground. It’s also much smaller than the Upstart thing. However, here, I could implement the “After” thing, corresponding to the Should-Start:

#!/bin/sh INIT_TEMPLATE=${1} SERVICE_FILE=`echo ${INIT_TEMPLATE} | sed 's/.init.in/.service/'` # Get the variables defined in the init template . ${INIT_TEMPLATE} if [ -z "${SCRIPTNAME}" ] ; then SCRIPTNAME=/etc/init.d/${NAME} fi if [ -z "${SYSTEM_USER}" ] ; then SYSTEM_USER=${PROJECT_NAME} fi if [ -z "${SYSTEM_GROUP}" ] ; then SYSTEM_GROUP=${PROJECT_NAME} fi # Find out what should go in After= SHOULD_START=`cat ${INIT_TEMPLATE} | grep "# Should-Start:" | sed 's/# Should-Start://'` if [ -n "${SHOULD_START}" ] ; then AFTER="After=" for i in ${SHOULD_START} ; do AFTER="${AFTER}${i}.service " done fi echo "[Unit] Description=${DESC} $AFTER [Service] User=${SYSTEM_USER} Group=${SYSTEM_GROUP} WorkingDirectory=/var/lib/${PROJECT_NAME} PermissionsStartOnly=true ExecStartPre=/bin/mkdir -p /var/lock/${PROJECT_NAME} /var/log/${PROJECT_NAME} /var/lib/${PROJECT_NAME} ExecStartPre=/bin/chown ${SYSTEM_USER}:${SYSTEM_GROUP} /var/lock/${PROJECT_NAME} /var/log/${PROJECT_NAME} /var/lib/${PROJECT_NAME} ExecStart=${SCRIPTNAME} systemd-start Restart=on-failure [Install] WantedBy=multi-user.target " >${SERVICE_FILE}

As you can see, it’s calling /etc/init.d/${SCRIPTNAME} sytemd-start, which isn’t great. I’d be happy to have comments from systemd user / maintainers on how to fix it to make it better.

Integrating in debian/rules

To integrate with the Debian package build system, we only need had to write this:

override_dh_installinit: # Create the init scripts from the template for i in `ls -1 debian/*.init.in` ; do \ MYINIT=`echo $$i | sed s/.init.in//` ; \ cp $$i $$MYINIT.init ; \ cat /usr/share/openstack-pkg-tools/init-script-template >>$$MYINIT.init ; \ pkgos-gen-systemd-unit $$i ; \ done # If there's an upstart.in file, use that one instead of the generated one for i in `ls -1 debian/*.upstart.in` ; do \ MYPKG=`echo $$i | sed s/.upstart.in//` ; \ cp $$MYPKG.upstart.in $$MYPKG.upstart ; \ done # Generate the upstart job if there's no already existing .upstart.in for i in `ls debian/*.init.in` ; do \ MYINIT=`echo $$i | sed s/.init.in/.upstart.in/` ; \ if ! [ -e $$MYINIT ] ; then \ pkgos-gen-upstart-job $$i ; \ fi \ done dh_installinit --error-handler=true # Generate the systemd unit file # Note: because dh_systemd_enable is called by the # dh sequencer *before* dh_installinit, we have # to process it manually. for i in `ls debian/*.init.in` ; do \ pkgos-gen-systemd-unit $$i ; \ MYSERVICE=`echo $$i | sed 's/debian\///'` ; \ MYSERVICE=`echo $$MYSERVICE | sed 's/.init.in/.service/'` ; \ dh_systemd_enable $$MYSERVICE ; \ done

As you can see, it’s possible to use a debian/*.upstart.in and not use the templating system, in the more complicated case (I needed it mostly for neutron-server and neutron-plugin-openvswitch-agent).


I do not pretend that what I wrote in the openstack-pkg-tools is the ultimate solution. But I’m convince that it answers our own need as the OpenStack maintainers in Debian. There’s a lot of room for improvements (like implementing the Should-Start in Upstart jobs, or stop calling the sysv-rc script in the systemd units), but that this is a very good move that we did to use templates and generated scripts, as the init scripts are a way more easy to maintain now, in a much more unified way. As I’m not completely satisfied for the systemd and Upstart implementation, I’m sure that there’s already a huge improvements on the sysv-rc script maintainability.

Last and again: please send your comments and help improving the above! :)

Categories: Elsewhere

Liran Tal's Enginx: Drupal Performance Tip – “I’m too young to die” – know your DB engines

Planet Drupal - Mon, 15/12/2014 - 08:16
This entry is part 4 of 4 in the series Drupal Performance Tips

In the spirit of the computer video game Doom and its skill levels, we’ll review a few ways you can improve  your Drupal speed performance     and optimize for better results and server response time. These tips that we’ll cover may be at times specific to Drupal 6 versions, although     you can always learn the best practices from these examples and apply them on your own code base.

Doom skill levels: (easiest first)

1. I’m too young to die

2. Hey, not too rough

3. Hurt me plenty

4. Ultra-violence

5. Nightmare!

  This post is rated “I’m too young too die” difficulty level.


Drupal 6 shipped with all tables being MyISAM, and then Drupal 7 changed all that and shipped with all of its tables using the InnoDB database engine. Each one with its own strengths and weaknesses but it’s quite clear that InnoDB will probably perform better for your Drupal site (though it has quite a bit of fine tuning configuration to be tweaked on my.cnf).

Some modules, whether on Drupal 6, or those on Drupal 7 that simply upgraded but didn’t quite review all of their code, might ship with queries like SELECT COUNT() which if you have migrated your tables to InnoDB (or simply using Drupal 7) then this will hinder on database performance. That’s mainly because InnoDB and MyISAM work differently, and where-as this proved as quite a fast responding query being executed on a MyISAM database which uses the main index to store this information, for InnoDB the situation is different and will result in doing a full table scan for the count. Obviously, on an InnoDB configuration running such queries on large tables will result in very poor performance

Note to ponder upon – what about the Views module which uses similar type of COUNT() queries to create the pagination for its views?

(adsbygoogle = window.adsbygoogle || []).push({});

The post Drupal Performance Tip – “I’m too young to die” – know your DB engines appeared first on Liran Tal's Enginx.

Categories: Elsewhere

Drupal core announcements: Drupal core security release window on Wednesday, December 17

Planet Drupal - Mon, 15/12/2014 - 00:15
Start:  2014-12-17 (All day) America/New_York Online meeting (eg. IRC meeting) Organizers:  David_Rothstein

The monthly security release window for Drupal 6 and Drupal 7 core will take place on Wednesday, December 17.

This does not mean that a Drupal core security release will necessarily take place on that date for either the Drupal 6 or Drupal 7 branches, only that you should prepare to look out for one (and be ready to update your Drupal sites in the event that the Drupal security team decides to make a release).

There will be no bug fix release on this date; the next window for a Drupal core bug fix release is Wednesday, January 7.

For more information on Drupal core release windows, see the documentation on release timing and security releases, and the discussion that led to this policy being implemented.

Categories: Elsewhere

Gregor Herrmann: GDAC 2014/14

Planet Debian - Sun, 14/12/2014 - 22:27

I just got a couple of mails from the BTS. like almost every day, several times per day. now it made me realize how much I like the BTS, & how happy I am that it works so well & even gets new features. – thanks to the BTS maintainers for their continuous work!

this posting is part of GDAC (gregoa's debian advent calendar), a project to show the bright side of debian & why it's fun for me to contribute.

Categories: Elsewhere

Mario Lang: Data-binding MusicXML

Planet Debian - Sun, 14/12/2014 - 21:30

My long-term free software project (Braille Music Compiler) just produced some offspring! xsdcxx-musicxml is now available on GitHub.

I used CodeSynthesis XSD to generate a rather complete object model for MusicXML 3.0 documents. Some of the classes needed a bit of manual adjustment, to make the client API really nice and tidy.

During the process, I have learnt (as is almost always the case when programming) quite a lot. I have to say, once you got the hang of it, CodeSynthesis XSD is really a very powerful tool. I definitely prefer having these 100k lines of code auto-generated from a XML Schema, instead of having to implement small parts of it by hand.

If you are into MusicXML for any reason, and you like C++, give this library a whirl. At least to me, it is what I was always looking for: Rather type-safe, with a quite self-explanatory API.

For added ease of integration, xsdcxx-musicxml is sub-project friendly. In other words, if your project uses CMake and Git, adding xsdcxx-musicxml as a subproject is as easy as using git submodule add and putting add_subdirectory(xsdcxx-musicxml) into your CMakeLists.txt.

Categories: Elsewhere

Drupal Association News: Introducing the Drupal.org User Personas

Planet Drupal - Sun, 14/12/2014 - 20:15

As part of our mission to reinvent Drupal.org, we’ve been digging deep to understand who uses the website and how. At DrupalCon Austin, we began the process of discovering the personas of users who visit Drupal.org: to do so, we interviewed numerous Drupal.org users and asked questions about how frequently they use Drupal.org, how they use the website, their frustrations with Drupal.org, the things they enjoy about the site, and how we can make it easier for people to learn, use, and connect on Drupal.org.

Once we had that data, we set about looking for patterns and common themes. We built categories where we grouped people's similar experiences and frustrations together, and at the end of the process we had come up with five distinct personas that can apply to everyone who visits Drupal.org. These personas detail our users’ familiarity with Drupal software and Drupal community, how they use Drupal.org, how they contribute (or don’t), and more.

The five personas that we drew up are based on proficiency in Drupal and the Drupal ecosystem. They are:

  • Newcomer: This person has heard of Drupal, but has never built a Drupal site and doesn’t know where to start.
  • Learner: This person knows a bit about Drupal and the general Drupal ecosystem. He or she may have built a Drupal website, but likely has used only a few contrib modules and hasn’t made any customizations.
  • Skilled: This person understands and is fluent in Drupal-specific terminology, can build a Drupal website themselves using contributed modules, themes or distributions, or with the help of Drupal service providers. She or he has spent a decent amount of time working with Drupal, and is lightly engaged with the community, often not directly, via some sort of liaison.
  • Expert: This person has a deep understanding of Drupal and the Drupal ecosystem, knows how to build advanced websites with Drupal. Expert typically has been working with Drupal for at least a couple of years, is actively engaged with the community online and via local/national events, and actively contributes back in a variety of ways.
  • Master: This person has pervasive knowledge of Drupal and the Drupal ecosystem. He or she knows how to build Drupal websites of great complexity, is deeply engaged in the Drupal community, knows and has access to other Masters. Usually this person has been using Drupal and been around the Drupal community for a long time.

Proficiency-based personas are a new facet through which we can look at our community. It’s important to note that these personas are NOT only about developers. All kinds of roles can be on different levels of this ladder — UX designers, project managers, and business owners can be Experts and Masters, just like developers and themers. Simultaneously, people can have different backgrounds and be experts in other areas, but when it comes to fluency in Drupal and Drupal ecosystem, they would be represented as Newcomers, or Learners, or any of the other personas.

How will we use personas?

User personas will guide feature prioritization and feature development for Drupal.org, as we improve the site to make it easier for our users to progress from Newcomers to Masters. There are a variety of different ways we can go about it, but since our resources are limited, we will focus on just a few critical areas that will have the biggest impact on the overall user experience. So, to start our work, we’ll be focused on removing barriers and helping our users move more easily from Learners to Skilled. We found that our users have great success moving from Newcomer to Learner today, whereas moving from Learner to Skilled is much more difficult, since so much of the project is focused on doing things “the Drupal way” and learning the processes. Our secondary focus will be on moving users from Skilled to Expert.

Growing our pool of Skilled users is crucial, because by doing so we grow the number of people who own and/or build websites using Drupal, thus grow Drupal adoption. On the path from Skilled to Expert is when our users begin to give back by contributing patches, writing documentation, building and sharing modules and themes, helping others in the issue queues, and bringing in their friends. By growing the number of Skilled and Expert users on Drupal.org, we’ll directly grow our community. It’s a win-win.

By growing Drupal adoption and growing our community, we directly support our mission and goals as an organization (you can read more about those in our 2015 Leadership plan and budget), and that’s why improving Drupal.org is one of our organizational imperatives in the coming year. The 2015 Drupal.org roadmap outlines the numerous ways we’re planning to do it.

As we use personas in our work, you may hear us refer to our “Primary” (Learner and Skilled), “Secondary” (Expert), and “Tertiary” (Master and Newcomer) personas — these distinctions correspond to the order of conversions we look to make easier, not to the users’ importance. Every Drupal.org user is important to us!

As we modify Drupal.org, we’ll be using the personas to help us make the experience for the whole community better. After all, that’s what these personas are — a representation of the entire Drupal community. To help bring our personas to life, we talked to five different community members, each representing one user persona. Over the next few days we’ll share the stories of each person’s unique Drupal journey so that we can see how they got to where they are now. We’d like to say a big thank you to each of our volunteers for sharing their personal stories — as always, they’ve reminded us how fantastic our community really is.

At the end of the series, we’ll close it all off with interviews with several prominent community members who will share their views on how personas can be used outside of Drupal.org development.

We enjoyed working on the user research project and are excited to share user personas with the Drupal community. As a reminder, you can view and download the full report. Take them, use them, go out and make great things!

Personal blog tags: drupal.org user research
Categories: Elsewhere

Friendly Machine: Drupal 8 and Backdrop CMS - A Brief Comparison

Planet Drupal - Sun, 14/12/2014 - 18:28

I recently had the opportunity to see Nate Haug deliver a presentation about the Backdrop CMS project and it's upcoming 1.0.0 release (Jan. 15). It had been a while since I had taken a look at Backdrop and I came away quite impressed with both its progress and direction.

Many of you reading this will be familiar with Backdrop, but for those of you who haven't heard of the project, it is the first fork of the Drupal project, and the source of a great deal of controversy and angst in the Drupal community.

Backdrop has been perceived as a threat by many Drupalists, but I think as we step through the features and approaches of the two projects, those fears will be at least somewhat allayed. My own take is that the two systems seem complementary instead of competitive.

As a bit of background for the origin of Backdrop CMS, Nate told the story of his reaction to the massive changes in Drupal 8. He realized that his own business, Webform.com, was going to have major issues with the upgrade path.

It was going to take a huge effort to upgrade his site - we're talking many, many months - to simply replicate the work he had already done in Drupal 7. He didn't want to throw away the huge investment he had already made in his business and start over. His solution to the problem was forking Drupal to create Backdrop CMS.

And then...all hell broke loose.

Feature Comparison

I'll set the controversy behind Backdrop aside and get straight into a comparison of the features. Keep in mind, however, I'm using the term "features" here a bit loosely. That's because I also want to talk about how Backdrop is managed as well as other differences between the two projects. This list is not exhaustive. It just has some of the things that seem to me the most significant or interesting.

Target Market

I know many will squirm uncomfortably when I say this, but the target market for Drupal 8 is large enterprises. By contrast, the target for Backdrop is small to medium size businesses and non-profits - really the original market of the Drupal project. As we go through this list, you'll see how this targeting plays out in some of the decisions the two projects have made.

Configuration Management

This has been widely touted as the killer feature of Drupal 8. If you've dreamed of having all the cool configuration management features in D8 available for Drupal 7, then Backdrop may be tempting because that is essentially what it offers. Instead of using YAML files to store configuration data, however, Backdrop uses JSON. Otherwise, it's pretty much the same.


Another one of the major additions to Drupal 8 is the Twig template engine. This is a big plus for many front-end folks and it's something that is not available in Backdrop at this time - and I'm not sure I would look for it in the near future. Backdrop currently uses the Drupal 7 PHPTemplate theme engine.

Responsive Images

As a front-end developer, I have a particular interest in this one. Drupal 8 includes the Responsive Image module, which is essentially a reworking of the Picture module in D7.

At this writing, Backdrop doesn't have a responsive image solution. I asked Nate about this and he's not a fan of the Picture module approach (he favors using srcset, something that may possibly be added in versions 1.1 or 1.2 of Backdrop), so if that is something you require, it will need to be added as either a custom or contributed module.

Contributed Modules

Speaking of contrib, most of you reading this will be familiar with Drupal's massive collection of contributed modules. The contributed modules for Backdrop CMS will be hosted on GitHub and managed similar to how the jQuery project organizes its plugin registry. I don't think there have been any ports as of yet (all the energy is going to the 1.0.0 release), so this is pending.

Some of you may have heard that Drupal 7 modules will be compatible with Backdrop. This isn't true, primarily due to modules needing to be rewritten to support configuration management. Porting a Drupal 7 module should be fairly straightforward, however. Instead of storing config in the variables table, it needs to be in JSON files. Here's a video that will help get you started.

As a quick aside, having Backdrop (and eventually the contrib modules) hosted on GitHub seems like it will be a more familiar and friendly environment for potential project contributors.

Project Organization

The "do-ocracy" that is the Drupal project has been much discussed lately. Nate has organized the Backdrop CMS project along the same lines as the Project Management Committee of the Apache project. That was very wise in my opinion. It bodes well for the project.


Another really nice thing in Drupal 8 is the inclusion of a default WYSIWYG editor. Love them or hate them, virtually every client wants one, so now with D8 you won't have to add one yourself for every project. As of version 1.0.0, Backdrop doesn't have this functionality, but look for it in version 1.1 or 1.2.

I remember Nate saying something about it being ironic that Backdrop was launching both without Twig or a WYSIWYG since he and Backdrop co-founder Jen Lampton had been instrumental in bringing those to Drupal 8.

I suppose I should mention that Backdrop minor versions - from 1.0 to 1.1, for example - will occur regularly at an interval of about three or four months. So for the features mentioned that may be in version 1.1 or 1.2, it means they can be expected in either late spring or late summer.

Panels and Views

How about Panels and Views in core? Yeah, I like it! And that's what you get with Backdrop. Drupal 8 provides Views in core, but not Panels. It may be a while before Panels is ready for D8, but it may also be a while before D8 is ready, so I guess that's not a problem.

System Requirements and Backwards Compatibility

It may seem odd to group these two, but this is one point where the intended audiences (enterprise vs small organizations) are put into stark contrast. For example, Backdrop is intentionally friendly to cheap hosting. Drupal 8, by contrast, is almost certainly going to use more server resources than Drupal 7, potentially causing issues for those on shared hosting plans. 

For large organizations, the cost of hosting is not a big deal, but for some small organizations, it can be. So a solution architected to work well with limited resources may be attractive and also serves to highlight the different approaches between the two projects.

With backwards compatibility, we see the same philosophical divergence. Drupal has never focused much on backwards compatibility, making it a pain in the ass (and often expensive) to upgrade across major versions. The benefit of that approach is that Drupal has been able to innovate without being constrained by past decisions.

Backdrop, however, places a lot of value on carefully managing change so that existing sites can be upgraded affordably. I would recommend looking at Backdrop's philosophy, because it's there where you really find the motivations for the project and how it differs (and will differ more in the future) from the Drupal project. From system requirements, to upgrade path, to reaching out to hear voices not found in the issue queue, Backdrop CMS is consistently friendly to the needs of the little guy.

Wrap Up

Again, this isn't a comprehensive list of all the features or differences between the two systems. There is an issue on GitHub that might be of some help in learning more as well as this Drupal 8 feature list.

To me, these two projects don't compete with one another. Sure, some enterprises may use Backdrop and many small organizations may use Drupal 8. But really, the changes in Drupal 8 are a move toward the enterprise and the talk around Drupal 8 has reinforced that message. Having an alternative for small organizations on a budget and with a need to preserve software investments isn't a bad thing.

You may politely leave any comments below.

Categories: Elsewhere

Gregor Herrmann: RC bugs 2014/49-50

Planet Debian - Sun, 14/12/2014 - 17:01

it's getting harder to find "nice" RC bugs, due to the efforts of various bug hunters & the awesome auto-removal-from-testing feature. – anyway, here's the list of bugs I worked on in the last 2 weeks:

  • #766740 – gamera: "gamera FTBFS on arm64, testsuite failure."
    sponsor maintainer upload
  • #766773 – irssi-plugin-xmpp: "irssi-plugin-xmpp: /query <JID> fails with "Irssi: critical query_init: assertion 'query->name != NULL' failed""
    add some speculation to the bug report, request binNMU after submitter's confirmation, close this bug afterwards
  • #768127 – dhelp: "Fails to build the index when invalid UTF-8 is met"
    apply patch from Daniel Getz, upload to DELAYED/5
  • #770672 – src:gnome-packagekit: "gnome-packagekit: FTBFS without docbook: reference to entity "REFENTRY" for which no system identifier could be generated"
    provide information, ask for clarification, severity lowered by maintainer
  • #771496 – dpkg-cross: "overwrites user changes to configuration file /etc/dpkg-cross/cross-compile on upgrade (violates 10.7.3)"
    tag confirmed and add information, later downgraded by maintainer, then set back to RC by submitter …
  • #771500 – darcsweb: "darcsweb: postinst uses /usr/share/doc content (Policy 12.3): /usr/share/doc/darcsweb/examples/darcsweb.conf"
    install config sample into /usr/share/<package>, upload to DELAYED/5
  • #771501 – pygopherd: "pygopherd: postinst uses /usr/share/doc content (Policy 12.3): /usr/share/doc/pygopherd/examples/gophermap"
    sponsor NMU from Cameron Norman, upload to DELAYED/5
  • #771727 – fex: "fex: postinst uses /usr/share/doc content (Policy 12.3)"
    propose patch, installing config templates under /usr/share/<package>, upload to DELAYED/5 later
  • #772005 – libdevice-cdio-perl: "libdevice-cdio-perl: Debian patch causes Perl crashes in Device::Cdio::ISO9660::IFS's readdir: "Error in `/usr/bin/perl': realloc(): invalid next size: 0x0000000001f05850""
    reproduce the bug (pkg-perl)
  • #772159 – ruby-moneta: "ruby-moneta: leaves mysqld running after build"
    apply patch from Colin Watson, upload to DELAYED/2
Categories: Elsewhere

Enrico Zini: html5-sse

Planet Debian - Sun, 14/12/2014 - 16:32
HTML5 Server-sent events

I have a Django view that runs a slow script server-side, and streams the script output to Javascript. This is the bit of code that runs the script and turns the output into a stream of events:

def stream_output(proc): ''' Take a subprocess.Popen object and generate its output, line by line, annotated with "stdout" or "stderr". At process termination it generates one last element: ("result", return_code) with the return code of the process. ''' fds = [proc.stdout, proc.stderr] bufs = [b"", b""] types = ["stdout", "stderr"] # Set both pipes as non-blocking for fd in fds: fcntl.fcntl(fd, fcntl.F_SETFL, os.O_NONBLOCK) # Multiplex stdout and stderr with different prefixes while len(fds) > 0: s = select.select(fds, (), ()) for fd in s[0]: idx = fds.index(fd) buf = fd.read() if len(buf) == 0: fds.pop(idx) if len(bufs[idx]) != 0: yield types[idx], bufs.pop(idx) types.pop(idx) else: bufs[idx] += buf lines = bufs[idx].split(b"\n") bufs[idx] = lines.pop() for l in lines: yield types[idx], l res = proc.wait() yield "result", res

I used to just serialize its output and stream it to JavaScript, then monitor onreadystatechange on the XMLHttpRequest object browser-side, but then it started failing on Chrome, which won't trigger onreadystatechange until something like a kilobyte of data has been received.

I didn't want to stream a kilobyte of padding just to work-around this, so it was time to try out Server-sent events. See also this.

This is the Django view that sends the events:

class HookRun(View): def get(self, request): proc = run_script(request) def make_events(): for evtype, data in utils.stream_output(proc): if evtype == "result": yield "event: {}\ndata: {}\n\n".format(evtype, data) else: yield "event: {}\ndata: {}\n\n".format(evtype, data.decode("utf-8", "replace")) return http.StreamingHttpResponse(make_events(), content_type='text/event-stream') @method_decorator(never_cache) def dispatch(self, *args, **kwargs): return super().dispatch(*args, **kwargs)

And this is the template that renders it:

{% extends "base.html" %} {% load i18n %} {% block head_resources %} {{block.super}} <style type="text/css"> .out { font-family: monospace; padding: 0; margin: 0; } .stdout {} .stderr { color: red; } .result {} .ok { color: green; } .ko { color: red; } </style> {# Polyfill for IE, typical... https://github.com/remy/polyfills/blob/master/EventSource.js #} <script src="{{ STATIC_URL }}js/EventSource.js"></script> <script type="text/javascript"> $(function() { // Manage spinners and other ajax-related feedback $(document).nav(); $(document).nav("ajax_start"); var out = $("#output"); var event_source = new EventSource("{% url 'session_hookrun' name=name %}"); event_source.addEventListener("open", function(e) { //console.log("EventSource open:", arguments); }); event_source.addEventListener("stdout", function(e) { out.append($("<p>").attr("class", "out stdout").text(e.data)); }); event_source.addEventListener("stderr", function(e) { out.append($("<p>").attr("class", "out stderr").text(e.data)); }); event_source.addEventListener("result", function(e) { if (+e.data == 0) out.append($("<p>").attr("class", "result ok").text("{% trans 'Success' %}")); else out.append($("<p>").attr("class", "result ko").text("{% trans 'Script failed with code' %} " + e.data)); event_source.close(); $(document).nav("ajax_end"); }); event_source.addEventListener("error", function(e) { // There is an annoyance here: e does not contain any kind of error // message. out.append($("<p>").attr("class", "result ko").text("{% trans 'Error receiving script output from the server' %}")); console.error("EventSource error:", arguments); event_source.close(); $(document).nav("ajax_end"); }); }); </script> {% endblock %} {% block content %} <h1>{% trans "Processing..." %}</h1> <div id="output"> </div> {% endblock %}

It's simple enough, it seems reasonably well supported besides needing a polyfill for IE and, astonishingly, it even works!

Categories: Elsewhere

Paul Booker: Updating a user role when a class (group) is flagged as finished

Planet Drupal - Sun, 14/12/2014 - 14:38
function mymodule_training_class_node_form_submit($form, &$form_state) { if ($form_state['input']['field_class_is_finished']['und'] == 1) { $nid = $form_state['values']['nid']; $query = db_select('og_membership', 'ogm') ->condition('ogm.gid', $nid, '=') ->fields('ogm', array('etid')); $result = $query->execute(); foreach ($result as $record) { $uid = $record->etid; _mymodule_training_class_assign_alumni_role($uid); } } } function _mymodule_training_class_assign_alumni_role($uid){ $rid = db_select("users_roles", "ur") ->fields("ur", array("rid")) ->condition('ur.uid', $uid, '=') ->execute() ->fetchField(); if (empty($rid)) { db_insert('users_roles') ->fields(array( 'uid' => $uid, 'rid' => ALUMNI, )) ->execute(); } } mysql> describe field_data_field_class_is_finished -> ; +-------------------------------+------------------+------+-----+---------+-------+ | Field | Type | Null | Key | Default | Extra | +-------------------------------+------------------+------+-----+---------+-------+ | entity_type | varchar(128) | NO | PRI | | | | bundle | varchar(128) | NO | MUL | | | | deleted | tinyint(4) | NO | PRI | 0 | | | entity_id | int(10) unsigned | NO | PRI | NULL | | | revision_id | int(10) unsigned | YES | MUL | NULL | | | language | varchar(32) | NO | PRI | | | | delta | int(10) unsigned | NO | PRI | NULL | | | field_class_is_finished_value | int(11) | YES | MUL | NULL | | +-------------------------------+------------------+------+-----+---------+-------+ 8 rows in set (0.00 sec) mysql> mysql> describe og_membership; +-------------+------------------+------+-----+---------+----------------+ | Field | Type | Null | Key | Default | Extra | +-------------+------------------+------+-----+---------+----------------+ | id | int(10) unsigned | NO | PRI | NULL | auto_increment | | type | varchar(255) | NO | | | | | etid | int(10) unsigned | NO | MUL | 0 | | | entity_type | varchar(32) | NO | | | | | gid | int(11) | NO | MUL | NULL | | | group_type | varchar(32) | NO | MUL | | | | state | varchar(255) | YES | | | | | created | int(11) | NO | | 0 | | | field_name | varchar(255) | NO | | | | | language | varchar(12) | NO | | | | +-------------+------------------+------+-----+---------+----------------+ 10 rows in set (0.00 sec) mysql> select * from og_membership where gid=1304; +------+----------------------------+-------+-------------+------+------------+-------+------------+--------------+----------+ | id | type | etid | entity_type | gid | group_type | state | created | field_name | language | +------+----------------------------+-------+-------------+------+------------+-------+------------+--------------+----------+ | 8275 | og_membership_type_default | 1 | user | 1304 | node | 1 | 1402485115 | og_user_node | en | | 8276 | og_membership_type_default | 10106 | user | 1304 | node | 1 | 1402485280 | og_user_node | en | | 8277 | og_membership_type_default | 10113 | user | 1304 | node | 1 | 1402485286 | og_user_node | en | | 8278 | og_membership_type_default | 10114 | user | 1304 | node | 1 | 1402485292 | og_user_node | en | +------+----------------------------+-------+-------------+------+------------+-------+------------+--------------+----------+ 4 rows in set (0.00 sec) mysql> describe users; +------------------+------------------+------+-----+---------+-------+ | Field | Type | Null | Key | Default | Extra | +------------------+------------------+------+-----+---------+-------+ | uid | int(10) unsigned | NO | PRI | 0 | | | name | varchar(60) | NO | UNI | | | | pass | varchar(128) | NO | | | | | mail | varchar(254) | YES | MUL | | | | theme | varchar(255) | NO | | | | | signature | varchar(255) | NO | | | | | signature_format | varchar(255) | YES | | NULL | | | created | int(11) | NO | MUL | 0 | | | access | int(11) | NO | MUL | 0 | | | login | int(11) | NO | | 0 | | | status | tinyint(4) | NO | | 0 | | | timezone | varchar(32) | YES | | NULL | | | language | varchar(12) | NO | | | | | picture | int(11) | NO | MUL | 0 | | | init | varchar(254) | YES | | | | | data | longblob | YES | | NULL | | +------------------+------------------+------+-----+---------+-------+ 16 rows in set (0.01 sec) mysql> select * from users where uid=10106; +-------+----------------------+---------------------------------------------------------+------------------------------------------------+-------+-----------+------------------+------------+------------+-------+--------+------------------+----------+---------+------------------------------------------------+------+ | uid | name | pass | mail | theme | signature | signature_format | created | access | login | status | timezone | language | picture | init | data | +-------+----------------------+---------------------------------------------------------+------------------------------------------------+-------+-----------+------------------+------------+------------+-------+--------+------------------+----------+---------+------------------------------------------------+------+ | 10106 | user_authenticated_1 | $S$DBGDqh770IDr09aztKD8Ey8aNGxwx8iiCaYo/rGCcBpa5XzNKnDF | identity+user_authenticated_1@paulbooker.co.uk | | | full_html | 1401792983 | 1401794533 | 0 | 1 | America/New_York | | 0 | identity+user_authenticated_1@paulbooker.co.uk | NULL | +-------+----------------------+---------------------------------------------------------+------------------------------------------------+-------+-----------+------------------+------------+------------+-------+--------+------------------+----------+---------+------------------------------------------------+------+ 1 row in set (0.00 sec) mysql> select * from users where uid=10113; +-------+----------------------+---------------------------------------------------------+------------------------------------------------+-------+-----------+------------------+------------+--------+-------+--------+------------------+----------+---------+------------------------------------------------+------+ | uid | name | pass | mail | theme | signature | signature_format | created | access | login | status | timezone | language | picture | init | data | +-------+----------------------+---------------------------------------------------------+------------------------------------------------+-------+-----------+------------------+------------+--------+-------+--------+------------------+----------+---------+------------------------------------------------+------+ | 10113 | user_authenticated_2 | $S$DeG84e0QP/H2h2rGv6cw93krL3CDoQ6CZOzhiSQCZa4OpZOAeP21 | identity+user_authenticated_2@paulbooker.co.uk | | | full_html | 1402485227 | 0 | 0 | 1 | America/New_York | | 0 | identity+user_authenticated_2@paulbooker.co.uk | NULL | +-------+----------------------+---------------------------------------------------------+------------------------------------------------+-------+-----------+------------------+------------+--------+-------+--------+------------------+----------+---------+------------------------------------------------+------+ 1 row in set (0.00 sec) mysql> select * from users where uid=10114; +-------+----------------------+---------------------------------------------------------+------------------------------------------------+-------+-----------+------------------+------------+--------+-------+--------+------------------+----------+---------+------------------------------------------------+------+ | uid | name | pass | mail | theme | signature | signature_format | created | access | login | status | timezone | language | picture | init | data | +-------+----------------------+---------------------------------------------------------+------------------------------------------------+-------+-----------+------------------+------------+--------+-------+--------+------------------+----------+---------+------------------------------------------------+------+ | 10114 | user_authenticated_3 | $S$D4xWR53hWUcyoZmIuZOLv7K8oasOsPCmqWaQGT.kpMQiX9k7XpfD | identity+user_authenticated_3@paulbooker.co.uk | | | full_html | 1402485256 | 0 | 0 | 1 | America/New_York | | 0 | identity+user_authenticated_3@paulbooker.co.uk | NULL | +-------+----------------------+---------------------------------------------------------+------------------------------------------------+-------+-----------+------------------+------------+--------+-------+--------+------------------+----------+---------+------------------------------------------------+------+ 1 row in set (0.00 sec) mysql> select rid from users_roles where uid=10106; +-----+ | rid | +-----+ | 7 | +-----+ 1 row in set (0.00 sec) Tags:
Categories: Elsewhere

Dirk Eddelbuettel: rfoaas

Planet Debian - Sun, 14/12/2014 - 01:20

A new version of rfoaas is now on CRAN. The rfoaas package provides an interface for R to the most excellent FOAAS service -- which provides a modern, scalable and RESTful web service for the frequent need to tell someone to eff off.

The FOAAS backend gets updated in spurts, and yesterday a few pull requests were integrated, including one from yours truly. So with that it was time for an update to rfoaas. As the version number upstream did not change (bad, bad, practice) I appended the date the version number.

CRANberries also provides a diff to the previous release. Questions, comments etc should go to the GitHub issue tracker off the GitHub repo.

This post by Dirk Eddelbuettel originated on his Thinking inside the box blog. Please report excessive re-aggregation in third-party for-profit settings.

Categories: Elsewhere

Gregor Herrmann: GDAC 2014/13

Planet Debian - Sat, 13/12/2014 - 21:48

not sure if it it's me or debian but today was a quiet day. time to look back & see what has happened this year … & this brings up memories of this year's & earlier debconfs, with their pkg-perl BOFs & their outdoor hacklabs. – looking through these photos of past events makes me grateful, both to the tireless organizers of debconf, & to the people who can share a bench with me for hours :)

this posting is part of GDAC (gregoa's debian advent calendar), a project to show the bright side of debian & why it's fun for me to contribute.

Categories: Elsewhere

Holger Levsen: 20141213-on-having-fun-in-debian

Planet Debian - Sat, 13/12/2014 - 17:11
On having fun in Debian

(Thanks to cardboard-crack.com for this awesome comic!)

Categories: Elsewhere

nielsdefeyter.nl: Setup Entity Translation the right way

Planet Drupal - Sat, 13/12/2014 - 14:36

This article contains a detailed instruction on how to setup the Entity Translation module for Drupal 7 websites.
Entity Translation is part of Drupal 8 core and its approach is to translate fields instead of full nodes/entities.

Goal of this tutorial is to set up a multilingual website that can be navigated in multiple languages by visitors and to enable the content to be easily manageable by editors / cms administrators.
To get multilingual right, it’s critical that you configure your content-types and fields with care and precision and upfront, because if content is already in your database it is almost impossible to change these configurations.
So let's go.

Categories: Elsewhere

Keith Packard: present-compositor

Planet Debian - Sat, 13/12/2014 - 09:28
Present and Compositors

The current Present extension is pretty unfriendly to compositing managers, causing an extra frame of latency between the applications operation and the scanout buffer. Here's how I'm fixing that.

An extra frame of lag

When an application uses PresentPixmap, that operation is generally delayed until the next vblank interval. When using X without composting, this ensures that the operation will get started in the vblank interval, and, if the rendering operation is quick enough, you'll get the frame presented without any tearing.

When using a compositing manager, the operation is still delayed until the vblank interval. That means that the CopyArea and subsequent Damage event generation don't occur until the display has already started the next frame. The compositing manager receives the damage event and constructs a new frame, but it also wants to avoid tearing, so that frame won't get displayed immediately, instead it'll get delayed until the next frame, introducing the lag.

Copy now, complete later

While away from the keyboard this morning, I had a sudden idea -- what if we performed the CopyArea and generated Damage right when the PresentPixmap request was executed but delayed the PresentComplete event until vblank happened.

With the contents updated and damage delivered, the compositing manager can immediately start constructing a new scene for the upcoming frame. When that is complete, it can also use PresentPixmap (either directly or through OpenGL) to queue the screen update.

If it's fast enough, that will all happen before vblank and the application contents will actually appear at the desired time.

Now, at the appointed vblank time, the PresentComplete event will get delivered to the client, telling it that the operation has finished and that its contents are now on the screen. If the compositing manager was quick, this event won't even be a lie.

We'll be lying less often

Right now, the CopyArea, Damage and PresentComplete operations all happen after the vblank has passed. As the compositing manager delays the screen update until the next vblank, then every single PresentComplete event will have the wrong UST/MSC values in it.

With the CopyArea happening immediately, we've a pretty good chance that the compositing manager will get the application contents up on the screen at the target time. When this happens, the PresentComplete event will have the correct values in it.

How can we do better?

The only way to do better is to have the PresentComplete event generated when the compositing manager displays the frame. I've talked about how that should work, but it's a bit twisty, and will require changes in the compositing manager to report the association between their PresentPixmap request and the applications' PresentPixmap requests.

Where's the code

I've got a set of three patches, two of which restructure the existing code without changing any behavior and a final patch which adds this improvement. Comments and review are encouraged, as always!

git://people.freedesktop.org/~keithp/xserver.git present-compositor
Categories: Elsewhere

Pixelite: Adding Apple and Android favicons to Drupal

Planet Drupal - Sat, 13/12/2014 - 01:00

As you end up building more and more websites that target mobile devices (e.g. iPhone, iPad, Android, Windows), you need to supply an ever increasing amount of favicons. This process can be complex if done by hand, luckily there is an easy way to introduce these into your Drupal site.

What you will need

Before we start you will need a high quality icon to begin with, the icon should be:

  • 260x260px (i.e. square)
  • a PNG with transparency as needed
  • recognizable when shrunk right done to your browser favicon (so don’t use your entire logo complete with words).
Generating the favicons

This is where the really handy realfavicongenerator.net website comes into play. I have used many other websites that offer similar functionality, but this seems to be the best, and is dead simple to use.

You will need to upload the 260x260px PNG file, and also select a hex color for the Windows 8 tile, but this should be straight forward.

I also opt for the option “I will place favicon files (favicon.ico, apple-touch-icon.png, etc.) at the root of my web site.” as this seems the most sensible place for them anyway.

When you complete the process, you will be able to download a zip file containing a whole bunch of icons and XML files, this is fine, extract them to your docroot for Drupal.

Adding the favicons to Drupal

You now will need to edit your html.tpl.php inside your theme, and add the code that the generator provides. The code should resemble something like this:

1 <link rel="apple-touch-icon" sizes="57x57" href="/apple-touch-icon-57x57.png"> 2 <link rel="apple-touch-icon" sizes="114x114" href="/apple-touch-icon-114x114.png"> 3 <link rel="apple-touch-icon" sizes="72x72" href="/apple-touch-icon-72x72.png"> 4 <link rel="apple-touch-icon" sizes="144x144" href="/apple-touch-icon-144x144.png"> 5 <link rel="apple-touch-icon" sizes="60x60" href="/apple-touch-icon-60x60.png"> 6 <link rel="apple-touch-icon" sizes="120x120" href="/apple-touch-icon-120x120.png"> 7 <link rel="apple-touch-icon" sizes="76x76" href="/apple-touch-icon-76x76.png"> 8 <link rel="apple-touch-icon" sizes="152x152" href="/apple-touch-icon-152x152.png"> 9 <link rel="apple-touch-icon" sizes="180x180" href="/apple-touch-icon-180x180.png"> 10 <link rel="icon" type="image/png" href="/favicon-192x192.png" sizes="192x192"> 11 <link rel="icon" type="image/png" href="/favicon-160x160.png" sizes="160x160"> 12 <link rel="icon" type="image/png" href="/favicon-96x96.png" sizes="96x96"> 13 <link rel="icon" type="image/png" href="/favicon-16x16.png" sizes="16x16"> 14 <link rel="icon" type="image/png" href="/favicon-32x32.png" sizes="32x32"> 15 <meta name="msapplication-TileColor" content="#b91d47"> 16 <meta name="msapplication-TileImage" content="/mstile-144x144.png">

You will notice though that Drupal likes to place it’s default favicon into the <head> section of the page, we need to remove this in order for it not to mess up the above code you inserted.

<link rel="shortcut icon" href="http://[YOURSITE]/misc/favicon.ico" type="image/vnd.microsoft.icon" />

The following code below can be inserted into your template.php file for your theme to remove the default favicon from Drupal:

1 <?php 2 /** 3 * Remove the unneeded favicon from the head section. 4 */ 5 function YOURTHEME_html_head_alter(&$head_elements) { 6 foreach ($head_elements as $key => $element) { 7 if (!empty($element['#attributes'])) { 8 if (array_key_exists('href', $element['#attributes'])) { 9 if (strpos($element['#attributes']['href'], 'misc/favicon.ico') > 0) { 10 unset($head_elements[$key]); 11 } 12 } 13 } 14 } 15 } 16 ?>

There you have it all done.

Extra for experts - Google’s theme-color meta tag

Google recently announced that from Chrome 39 onwards on Android Lollipop (5.0+), a new meta tag will be supported

<meta name="theme-color" content="#b91d47" />

This is what your site’s title bar now looks like (instead of boring and grey).

This meta tag can be added to your html.tpl.php file as above.


Let me know if this has helped you, and also if you have any other tips and tricks when it comes to favicons on your mobile devices.

Categories: Elsewhere

Thorsten Glaser: WTF is Jessie; PA4 paper size

Planet Debian - Sat, 13/12/2014 - 00:56

My personal APT repository now has a jessie suite – currently just a clone of the sid suite, but so, people can get on the correct “upgrade channel” already.

Besides that, the usual small updates to my metapackages, bugfixes, etc. – You might have noticed that it’s now on a (hopefully permanent) location. I’ve put a donated eee-pc from my father to good use and am now running a Debian system at home. (Fun, as I’m emeritus now, officially, and haven’t had one during my time as active uploading DD.) I’ve created a coupld of cowbuilder chroots (pbuilderrc to achieve that included in the repo) and can build packages, but for i386 only (amd64 is still done on the x32 desktop at work), but, more importantly, I can build, sign and publish the repo, so it may grow. (popcon data is interesting. More than double the amount of machines I have installed that stuff on.)

Installing gimp and inkscape, I’m asked for a default paper size by libpaper1. PA4 is still not an option, I wonder why. I also haven’t managed to get MirPorts GNU groff and Artifex Ghostscript to use that paper size, so the various PDF manpages I produce are still using DIN ISO A4, rendering e.g. Mexicans unable to print them. Help welcome.

Categories: Elsewhere

Daniel Kahn Gillmor: a10n for l10n

Planet Debian - Sat, 13/12/2014 - 00:00
The abbreviated title above means "Appreciation for Localization" :)

I wanted to say a word of thanks for the awesome work done by debian localization teams. I speak English, and my other language skills are weak. I'm lucky: most software I use is written by default in a language that I can already understand.

The debian localization teams do great work in making sure that packages in debian gets translated into many other languages, so that many more people around the world can take advantage of free software.

I was reminded of this work recently (again) with the great patches submitted to GnuPG and related packages. The changes were made by many different people, and coordinated with the debian GnuPG packaging team by David Prévot.

This work doesn't just help debian and its users. These localizations make their way back upstream to the original projects, which in turn are available to many other people.

If you use debian, and you speak a language other than english, and you want to give back to the community, please consider joining one of the localization teams. They are a great way to help out our project's top priorities: our users and free software.

Thank you to all the localizers!

(this post was inspired by gregoa's debian advent calendar. i won't be posting public words of thanks as frequently or as diligently as he does, any more than i'll be fixing the number of RC bugs that he fixes. This are just two of the ways that gregoa consistently leads the community by example. He's an inspiration, even if living up to his example is a daunting challenge.)

Categories: Elsewhere

Mediacurrent: Protect thyself! Don&#039;t send TESTING emails to REAL users

Planet Drupal - Fri, 12/12/2014 - 22:05

Have you ever accidentally triggered emails to real users while working in a development environment? Or how about accidentally pushed data to a "live" third party service from a development environment?

Categories: Elsewhere


Subscribe to jfhovinne aggregator - Elsewhere