where Mailman and Launchpad memberships meet

Around the time of OSCON this year, it came to my attention (thanks belkinsa!) that Ubuntu Oregon was in need of leadership. They were one of many Local Communities (or to adapt the more common parlance, LoCo) around the world seeking to spread the word of Ubuntu on a local scale. I didn't even know they existed in Oregon or otherwise, so I naturally jumped at the opportunity.

There were some challenges, many of which I discussed at our Ubuntu Online Summit (UOS) session, but I feel like we've got some good momentum going at this point. I think that being the only LoCo worldwide to have a UOS session helped quite a bit.

Much thanks is due to the LoCo Council who have been very friendly and encouraging. They even recently accepted our re-verification which, like Ubuntu Membership, is a recognition of sustained contribution.

After going through the process, it became apparent to me that metrics are good to have. Launchpad provided easy tools to figure out membership numbers and a script existed to use its API to cross reference group membership with Ubuntu Membership. Additionally, Launchpad mailing lists allowed one to easiliy figure out how many of its members were on the list.

However, using Launchpad lists is pretty darn deprecated. Instead, Ubuntu hosts its own series of lists, all using the ever-popular GNU Mailman. A much more full-featured set of tools exists for handling your mailing list this way, so it's a good thing. Additionally, it allows non-members to subscribe, which is not a bad thing.

So this leaves us with one problem: how do you equate Mailman membership to Launchpad membership? Well, your answer can be found in the mailgroupxref repo I created in the ubuntu-locoteams project (which is technically a pseudo-project, but it seemed the most fitting place). It uses a script by Mark Sapiro (included in the repo for your convenience) that can get Mailman subscriber lists and the rest of the code builds upon the aforementioned membership cross referencing script.

It turns out the Launchpad API (in the package python-launchpadlib) is very useful and easy to use. The meat of the code is pretty simple:

from launchpadlib.launchpad import Launchpad

teamemails = []

# login
lp = Launchpad.login_with('testing', 'staging')

# get the people objects of the team
team = lp.people['ubuntu-us-or']

# iterate through people objects
for member in team.members:
if member.hide_email_addresses is False:
teamemails.append(member.preferred_email_address)

# this function just calls mailman-subscribers.py, so nothing exciting
listemails = get_list_emails(hostname, listname)

for email in teamemails:
if email in listemails:
print email

Some things to note:

  • Technically there is no preferred_email_address attribute. It's actually preferred_email_address_link but that needs to be converted from Unicode and parsed. I wanted to avoid these technicalities to show how easy it is to get information from Launchpad.
  • You can login with anything instead of 'testing', but you will get a request for your personal credentials.
  • 'staging' may be down during periodic maintainence, but you can use 'qastaging' if need be.
  • If you get SSL errors, you might look to see if you installed httplib2 from outside the repos.
  • I'm not a Python wizard. Feel free to offer constructive advice, but don't lambast me for not being 'pythonic.' Someday I'll reach enlightenment.

So what is the end result of this? I found that the feature that allows Launchpad users to hide their email address is a bigger problem than I thought. Even my own email address is hidden I discovered! ☺

I think in the future I may have to look at using the name attribute and searching for it within email addresses. If you guys have any suggestions, patches are welcome. Meanwhile, I hope this is useful for your LoCo and/or Launchpad group.

Read and Post Comments

git your blog

So I deleted my whole website by accident.

Yep, it wasn't very fun. Luckily, Linode's Backup Service saved the day. Though they backup the whole machine, it was easy to restore to the linode, change the configuration to use the required partition as a block device, reboot, and then manually mount the block device. At that point, restoration was a cp away.

The reason why this all happened is because I was working on the final piece to my ideal blogging workflow: putting everything under version control.

The problem came when I tried to initialize my current web folder. I mean, it worked, and I could clone the repo on my computer, but I couldn't push. Worse yet, I got something scary back:

remote: error: refusing to update checked out branch: refs/heads/master
remote: error: By default, updating the current branch in a non-bare repository
remote: error: is denied, because it will make the index and work tree inconsistent
remote: error: with what you pushed, and will require 'git reset --hard' to match
remote: error: the work tree to HEAD.
remote: error:
remote: error: You can set 'receive.denyCurrentBranch' configuration variable to
remote: error: 'ignore' or 'warn' in the remote repository to allow pushing into
remote: error: its current branch; however, this is not recommended unless you
remote: error: arranged to update its work tree to match what you pushed in some
remote: error: other way.
remote: error:
remote: error: To squelch this message and still keep the default behaviour, set
remote: error: 'receive.denyCurrentBranch' configuration variable to 'refuse'.

So in the process of struggling with this back and forth between local and remote, I killed my files. Don't you usually panic when you get some long error message that doesn't make a darn bit of sense?

Yeah, well, I guess I kind of got the idea, but it wasn't entirely clear. The key point is that we're trying to push to a non-bare folder— i.e. one that includes all the tracked files— and it's on a main branch.

Why is this bad? Well, what if you had uncommited changes on the remote repo and you pushed changes from the local repo? Data loss. So Git now won't let you do it unless you specifically allow it in your remote config in the receive.denyCurrentBranch variable.

So let's move to the solution: don't do this. You should either push to a different branch and then manually merge on remote, but merges aren't always guaranteed. Why not do something entirely different? Something more proper.

First, start with the remote:

# important: make a new folder!
git init --bare ~/path/to/some/new/folder

Then local:

git clone user@server:path/to/the/aforementioned/folder
cd folder
# make some changes
git add -A
git commit -am "initial commit or whatever you want to say"
git push

If you check out what's in that folder on remote you'll find it has no tracked files. Basically, a bare repo is basically just an index. It's a place to pull and push to. You're not goinng to go there and start changing files and getting git all confused.

Now here's the magic part: in the hooks subfolder of your folder, create a new executable file called post-receive containing the following:

#!/usr/bin/env sh
export GIT_WORK_TREE=/path/to/your/final/live/folder
git checkout -f master
# add any other commands that need to happen to rebuild your site, e.g.:
# blogofile build

Assuming you've already committed some changes, go ahead and run it and check your website.

Pretty cool, huh? Well, it gets even better. Next push you do will automatically update your website for you. So now for me, an update to the website is just a local push away. No need to even login to the server anymore.

There are other solutions to this problem but this one seems to be the most consistent and easy.

Read and Post Comments

happy Ubuntu Community Appreciation Day, phillw!

I swear, I find out about some new event Ubuntu does every day. How is it that I've been around Ubuntu for as long as I have and I've only now heard about this?

Well, in any case, today is Ubuntu Community Appreciation Day, where we give thanks to the humans (remember, ubuntu means humanity!) that have so graciously donated their time to make Ubuntu a reality.

I have a lot of people to thank in the community. We have some really exceptional people about. I really feel like I could make the world's longest blog post just trying to list them all. Several folks already have!

Instead, I'll point out a major player in the community who is pretty unseen these days.

Phill Westside was a major contributor to Lubuntu. He was there when I first came to #lubuntu so many moons ago. His friendly, inviting demeanour was one of the things that kept me sticking around after my support request was met. Phill took it upon himself to encourage me just as he had with others and slowly I came to contribute more and more.

Sadly, some people in high rankings in the community failed to see Phill's value for whatever reason. I'm not sure I totally understand but I think the barrage of opinions that came from Jono Bacon's call for reform in Ubuntu governance may offer some hint. Phill's no longer an Ubuntu member and is rarely seen in the typical places in the community.

Yet he still helps out on #lubuntu, still helps with Lubuntu ISO testing, still reposts Lubuntu news on Facebook, still contributes to the Lubuntu mailing lists, still tries to help herd the cats as it were, though he's handed off titles to others (that's how I'm the Release Manager and Head of QA!). tl;dr, Phill is still a major contributor to Ubuntu.

Did I mention he's a great guy to hang out with, too? I've never met him face to face, but I'm sure if I did, I'd give him one heck of a big ole hug.

Thanks, Phill!

Read and Post Comments

fullscreen slides in Hangouts workaround

More to come on the Ubuntu Online Summit soon but in the interim, I wanted to bring up something I learned a little too late.

Google Hangouts is handy little tool. Outside of providing an alternative to the likes of Skype, it also features some useful apps for using with a virtual tech conference like UOS really is. One of them is called Hangout Toolbox and has a feature called "Lower Third" that will allow you a pretty logo-ized tag line.

But the thing really useful to something like UOS is the default Screenshare app. Clicking on it, you get the option of either sharing the entire screen or one of your windows. So logically, you open the window with your presentation and start the full screen slide show, right?

Yeah, not exactly. I did that and I was going along talking away for my first presentation and no one could see anything beyond the first slide. I was manually advancing and it looked good on my side, but to everyone else, it was just frozen on the title. Since I was in full screen mode and no one had yet joined the Hangout, I had no idea what was going on though people were trying to get my attention on IRC.

I discovered a solution rather quickly: a windowized presentation. That is what I ended up doing, but things can look kind of tiny. Still, there are hoardes of posts out there on people doing similar things in PowerPoint and Keynote.

This is not the right way, though. We want full screen. So how do we do that?

It's simple, really. You share the full screen— not a window— then navigate to your presentation and start the slide show.

I guess that Hangouts thinks that the full screen window is not the same as the app window itself. Which is strange because, according to xprop -root | grep ^_NET_CLIENT_LIST, it's not a different window.

Unfortunately, unlike a lot of the other tools that the community uses, Google Hangouts is not open source. We can't just file a bug report and get to work on it (though you can file a bug report). This is really contrary to the spirit of Ubuntu. In fact, there's already a bug report for this very problem, the proprietary nature of Hangouts (not the first such issue, either).

It seems that especially for this public gathering of Ubuntu contributors and users, that this would be the most important place to put our best open source foot forward. That being said, I encourage you to confirm the bug and participate in helping to find a cure (rather than a mere treatment) to the malady of copyright.

Read and Post Comments

« Previous Page