KDE PIM in Randa 2017

Randa Meetings is an annual meeting of KDE developers in a small village in Swiss Alps. The Randa Meetings is the most productive event I ever attended (since there's nothing much else to do but hack from morning until night and eat Mario's chocolate :-)) and it's very focused - this year main topic is making KDE more accessible.

Several KDE PIM developers will be present as well - and while we will certainly want to hear other's input regarding accessibility of Kontact, our main goal in Randa will be to port away from KDateTime (the KDE4 way of handling date and time in software) to QDateTime (the Qt way of handling date and time). This does not sound very interesting, but it's a very important step for us, as afterward, we will finally be free of all legacy KDE4 code. It is no simple task, but we are confident we can finish the port during the hackfest. If everything goes smoothly, we might even have time for some more cool improvements and fixes in Kontact ;-)

I will also close the KMail User Survey right before the Randa meetings so that we can go over the results and analyze them. So, if you haven't answered the KMail User Survey yet, please do so now and help spread the word! There are still 3 more weeks left to collect as many answers as possible. After Randa, I will be posting a series of blog posts regarding results of the survey.

And finally, please support the Randa Meetings by contributing to our fundraiser - the hackfest can only happen thanks to your support!

Konqi can't wait to go to Randa again!

You can read reports from my previous adventures in Randa Meetings in 2014 and 2015 here:

KDE PIM on Akademy

Akademy is over and so here's a short summary of what the PIMsters have worked on during the past week.

Wiki Cleanup

Me and Volker sat down and went through all KDE PIM wikipages on community.kde.org, userbase.kde.org and techbase.kde.org. Most of our wiki pages are horribly outdated, so we tried to clean them up, remove pages that are no longer relevant or useful. With fewer pages to take care of and better overview of what all content we have, we should be able to keep them more up-to-date than we did in the past years.

Developer Story

Contributing to KDE PIM is hard and we know that. Getting all the dependencies and environment set up correctly is not trivial, and you can't run stable and development Kontact alongside each other easily.

We decided to address all those issues and make contributing to KDE PIM substantially easier. We are working on a Docker image that has all the dependencies and environment set up, so developers just need to run a single command to build entire KDE PIM. And thanks to the containerization, it's also possible to use the development version of Kontact in parallel with the stable version.

We hope that having ready-made development environment it will be easier for new contributors to get involved with KDE PIM. We will post a more details once the Docker image is ready.

Kontact Homepage

Right now kontact.kde.org and kontact.org just redirect to our page on the Userbase wiki. We decided that we want a simple, but professionally-looking web site to market Kontact as an actual product so that it appears more attractive to new users, especially those who will be coming from Windows in the future and contains comprehensive information for both users and developers.

KMail User Survey

During QtCon 2016 we started working on KMail user survey to get a better idea of what our user base is like, how they use KMail and what their impressions of it are. And now the survey is finally live, so please go and fill it if you haven't done so yet.

Wayland Support

Volker has finished porting Kontact to Wayland, so if you have Qt 5.9, you can now run Kontact natively on Wayland. Our main limitation was Wayland support in QWebEngine, which we use to render emails, but that has been resolved in Qt 5.9.

Merging Exchange Support

Krzysztof Nowicki has been working on Microsoft Exchange support for Kontact for a while now. We now have plans to merge his code into kdepim-runtime repository, so if everything goes right the Exchange support will be available out-of-the-box to all our users starting with the December release of KDE Applications.

Next Sprint

We will be meeting soon again in Randa. Our main plan for the sprint is to continue with removal of KDateTime from our code, and thus making KDE PIM free of kdelibs4support.

 

There's some more that I did not mention here, you can check the full notes for details.

Facebook Events in KOrganizer

Sounds like déjà vu? You are right! We used to have Facebook Event sync in KOrganizer back in KDE 4 days thanks to Martin Klapetek. The Facebook Akonadi resource, unfortunately, did not survive through Facebook API changes and our switch to KF5/Qt5.

I'm using a Facebook event sync app on my Android phone, which is very convenient as I get to see all events I am attending, interested in or just invited to directly in my phone's calendar and I can schedule my other events with those in mind. Now I finally grew tired of having to check my phone or Facebook whenever I wanted to schedule event through KOrganizer and I spent a few evenings writing a brand new Facebook Event resource.

Inspired by the Android app the new resource creates several calendars - for events you are attending, events you are interested in, events you have declined and invitations you have not responded to yet. You can configure if you want to receive reminders for each of those.

Additionally, the resource fetches a list of all your friend's birthdays (at least of those who have their birthday visible to their friends) and puts them into a Birthday calendar. You can also configure reminders for those separately.

Facebook Resource Configuration dialog Facebook events in KOrganizer

The Facebook Sync resource will be available in the next KDE Applications feature release in August.

Git trick #481: Prevent accidentally pushing into git instead of Gerrit

Some while ago I wrote about a little [git hook that automatically sets up your commit author identity][1]  after git clone based on the remote origin address. Recently I learned that in git 2.8 a new pre-push hook was introduced, and I immediately knew it will fix my second biggest pain point: accidentally pushing directly into git instead of Gerrit.

If you often switch between different projects where some use Gerrit for code review and some don’t, it’s very easy to just mistakenly do

git push master

when in fact you wanted to

git push HEAD:refs/for/master

There are some tricks how to make it harder for you to accidentally do this, like creating a “gpush” alias that pushes to refs/for/master and disabling pushing into the ‘origin’ remote by changing the push URL to something invalid. That, however, is not perfect because there are still ways how to by-pass it. And it becomes complicated if you use more than one remote and it’s clumsy if you sometimes do want to push directly into git (for example to submit a large patch series).

With a custom pre-push hook, we can check if the remote that we are pushing into is a Gerrit instance and then check if the remote ref that we are pushing into is a “Gerrit ref” (refs/for/foo) instead of a regular branch and we can have a nice “Are you sure you want to do this?” prompt:

#!/usr/bin/python3
# -*- coding: utf-8 -*-
#
# (C) 2017 Daniel Vrátil <dvratil@kde.org>
# License: GPL

import os
import sys

def remoteIsGerrit(remoteName, remoteUrl):
    # if the remote is called "gerrit", assume it's Gerrit
    if 'gerrit' in remoteName:
        return True
    # if the remote URL contains the default Gerrit port, assume it's Gerrit
    if ':29418/' in remoteUrl:
        return True

    # TODO: Add custom checks to match your non-standard Gerrit configuration
    return False
def main():
    # name and URL of the remote we are pushing into is passed as arguments
    if not remoteIsGerrit(sys.argv[1], sys.argv[2]):
        # If we are not pushing into gerrit, then simply allow the push
        return
    # The pushed refs are passed in via stdin
    for line in sys.stdin:
        # line = "localRef localRev remoteRef remoteRev"
        remoteRef = line.split(' ')[2]
        # Check if the remoteRef contains the typical Gerrit 'refs/for/foo'.
        if not remoteRef.startswith('refs/for/'):
            print('!!')
            print('!! You are pushing directly into git instead of Gerrit !!')
            print('!! Do you want to continue? [y/N] ', end = '', flush = True)
            if open('/dev/tty', 'rb').readline().decode().strip().lower() == 'y':
                return
            else:
                sys.exit(1)

if __name__ == "__main__":
    main()

Save this a file as “pre-push” and move it into .git/hooks/ folder in your local repository clone. Remember to make the script executable.

Here is how it works: trying to push into “gerrit” remote to branch “5.9” directly gets intercepted by our new hook and if you press ‘n’ the push gets aborted. If I would’ve pressed ‘y’, then the push would proceed.

$ git push gerrit 5.9
Enter passphrase for key '/home/dvratil/.ssh/id_rsa.qt':  
!! 
!! You are pushing directly into git instead of Gerrit !! 
!! Do you want to continue? [y/N] n
error: failed to push some refs to 'ssh://dvratil@codereview.qt-project.org:29418/qt/qtbase.git'</pre>
<p>Now when we try to push to the correct ref (`refs/for/5.9`) the hook accepts the push without any complaints:</p>
<pre>$ git push gerrit HEAD:refs/for/5.9
Counting objects: 6, done.
Delta compression using up to 2 threads.
Compressing objects: 100% (3/3), done.
Writing objects: 100% (4/4), 407 bytes, done.
Total 4 (delta 2), reused 0 (delta 0)
remote: Resolving deltas: 100% (2/2)
remote: Processing changes: new: 1, refs: 1, done    
remote: 
remote: New Changes:
remote:   https://codereview.qt-project.org/......
remote: 
To ssh://dvratil@codereview.qt-project.org:29418/qt/qtbase
 * [new branch] HEAD -&gt; refs/for/5.9

To have the hook automatically copied into every new repository that you clone, save it as “pre-push” into .git-templates/hooks/ and run the following command:

git config --global init.templatedir ~/.git-templates

Git will automatically copy everything from the ‘templatedir’ into the .git directory after every new git clone, so you don’t need to bother with doing that manually. Unfortunately for all your existing checkouts, you have to copy the hook manually

[1] /2015/12/git-trick-628-automatically-set-commit-author-based-on-repo-url

KMail: "Multiple Merge Candidates" error and how to fix it

If you can't synchronize a folder in KMail and you are seeing "Multiple Merge Candidates" error after the synchronization fails, here's a how to fix the folder to make it synchronize again - basically you force KMail to forget and re-sync the folder again.

 

  1. Open Akonadi Console.
  2. Go to the Browser tab.
  3. Right-click the broken folder and select "Clear Akonadi Cache" - this will remove all emails from the folder in Akonadi. This will NOT delete your emails on the server.
  4. Akonadi Console will freeze for a while, wait until it unfreezes (sorry, it's just a developer tool, we don't have a very good UX there :-)).
  5. Logout and login to make sure all PIM components are restarted.

After login start KMail (or Kontact) and hit "Check mail". KMail will now re-download all emails from the previously broken folder. This may take a while depending on how large the folder is and how fast your internet connection is. After that the synchronization should work as expected.

In the upcoming KDE Applications 16.12.1 release Akonadi will have a fix that fixes the reason why the "Multiple Merge Candidates" error occurs, so hopefully in the future you should not see this error anymore.

Akademy 2016 is over :(

It's actually been over for two days, but I'm still sitting in Berlin and only now got to write something.

As every year, it was great to see all my friends and fellow hackers again. Thanks everyone for being so awesome, I enjoyed every day of QtCon and Akademy with you. Can't wait to meet everyone again next year :-)

In the terms of KDE PIM, this year's Akademy was very productive. We had our KDE PIM BoF session on Monday afternoon, where we spent most of the time discussing KDE PIM User Survey - a plan of mine to get more information about our users and their use cases. The results will help us, the KDE PIM devs, to better understand how our users use our software and thus prioritize our focus. We ended up with an initial set of questions we intend to ask our users and next week I'll meet with some more KDE PIM hackers that could not attend Akademy and we will finalize the set of questions so that we can publish the survey later this month.

We also talked about some other topics on the meeting, like releasing of some of our libraries that Kube wants to use and so on.

You can read the mostly complete meeting notes on the KDE PIM wiki.

Outside of the BoF session we touched the topic of KDE PIM sprints and meetings. We want them to be more focused in the future, i.e. having a specific topic for each meeting that we will all work on together. We hope to do one meeting in Autumn this year to finish porting KCalCore away from KDateTime and KDELibs4Support, then a Spring meeting in Toulouse (which has become our new regular place for Spring sprints), then Randaaaaaaaaaaa (which gives us full 6 days of uninterrupted hacking with only small breaks to eat Mario's chocolate :-)) and then it's Akademy time again!

Oh and I can't forget to mention that the KDE PIM team was awarded the Akademy Award for our work on, well, KDE PIM :-). It was a great feeling to stand on the stage knowing that people appreciate our work.

---

Regarding my PIM work during Akademy, I think this year was pretty good. I did my share of partying during QtCon, so I could spent most of Akademy days hacking from morning until they kicked us out from the venue, and then continuing with some more hacking in the KDAB office until late night. Already before the event I merged a big change that improves the Akonadi change notification system. I managed to polish it during Akademy and fix several crashes and bugs.

Another big change was to our test-suite. It contains among other things integration tests, where we run an actual Akonadi server in an isolated environment (so that it does not touch any real data) and test whether clients interact with it as they are supposed to do. For these integration tests we've been only using the SQLite database until now, but I have now enabled MySQL and PostgreSQL too, so we run each test three times - once for each of the backends. This has revealed several corner-case issues that we weren't aware of until now. The test still run into some issues on the CI on build.kde.org but locally they pass for me (with only one exception). Addressing those issues is on the top of my todo list now.

I also started working on an experimental XML->C++ generator, which would allow me to get rid of some 12,000 lines of hand-written C++ code that implements the communication protocol between Akonadi server and the clients. Instead I will generate the code from a simple XML. So far I managed to get it to generate a code that compiles, but there's still a lot of work ahead to make it generate an optimal and correct code.

I'll spend the next week meeting all my colleagues from KDAB, which I'm really looking forward to. Although I know many of them from KDE, there are lots of people I haven't met yet, so it will be great to attach faces to the names. After that, it's back to Prague and to regular work (and some more Akonadi hacking ;-)).

Oh and if you haven't heard yet, KDE is celebrating 20th birthday. Go check out the timeline of KDE and get the amazing "20 Years of KDE" book!

I'm going to Akademy 2016!

If you want to know what we did in KDE PIM in the last year and what we are planning to do and achieve in the next one come to my KDE PIM Status Report talk on Sunday at 1 PM. If you want to get into more technical details and discussions about KDE PIM there will also be a KDE PIM BoF session on Monday afternoon.

I'm going to Akademy 2016!See you in Berlin!

 

Plasma 5.6 beta available on Fedora

Plasma 5.6 will be out in two weeks but the Plasma team has just released Plasma 5.6 beta which already features all the new yummy things and improvements as well as bunch of bug fixes that will be available in the 5.6 release.

Among other things Plasma 5.6 brings improved color scheme support, task manager on steroids, some new applets as well as further progress on the Wayland front. Two completely new things come as a tech preview: GRUB2 and Plymouth themes to make your system look fancy from the first second you power it up (see instructions below how to enable them).

You can ready the release announcement with more detailed descriptions and screenshots here.

The Fedora KDE SIG team has updated the Plasma 5 Unstable Copr repository so you can get a taste of Plasma 5.6 on Fedora 23 now (sorry for the lack of F22 builds). Rawhide will probably get the beta update some time next week.

$ dnf copr enable @kdesig/plasma-5-unstable
$ dnf update

Due to some changes in upstream releases of KActivities it is possible that you will get package conflict between kactivitymanagerd-debuginfo and kf5-kactivities-debuginfo. In that case please uninstall the kf5-kactivities-debuginfo package. This will be fixed properly once we roll out KDE Frameworks 5.20.

 

If you want to try the new GRUB and Plymouth themes, install the new packages

$ dnf install grub2-breeze-theme plymouth-theme-breeze

To enable the GRUB theme, edit /etc/default/grub:

GRUB_TERMINAL_OUTPUT="gfxterm"
GRUB_THEME=/boot/grub2/themes/breeze/theme.txt

and generate new GRUB configuration:

$ grub2-mkconfig -o /boot/grub2/grub.cfg

To enable the Plymouth theme, run

plymouth-set-default-theme breeze --rebuild-initrd

 

If you run into any packaging issues, please talk to us on #fedora-kde on IRC or kde@lists.fedoraproject.org. If you find any bugs or crashes, please report them to bugs.kde.org so that Plasma developers can fix them before the final 5.6 release.

Akonadi - still alive and rocking

It's been a while since I wrote anything about Akonadi but that does not mean I was slacking all the time ;) The KDE PIM team has ported PIM to KDE Frameworks 5 and Qt 5 and released the first KF5-based version in August 2015 and even before that we already did some major changes under the hood that were not possible in the KDE4 version due to API and ABI freezes of kdepimlibs. The KF5-based version of Akonadi libraries (and all the other KDE PIM libraries for that matter) have no guarantees of stable API yet, so we can bend and twist the libraries to our needs to improve stability and performance. Here's an overview of what has happened (mostly in Akonadi) since we started porting to KDE Frameworks 5. It is slightly more technical than I originally intended to, sorry about that.

Human-readable formats are overrated

As you probably know Akonadi has two parts: the Server (that manages the data and resources) and client libraries (that applications use to access the data managed by the server). The libraries need to talk to the Server somehow. In KDE4 we were using a text-based protocol very similar to IMAP (it started as RFC-compliant IMAP implementation, but over the time we diverged a bit). The problem with text-based protocol and large amount of data is that serializing everything into string representation and then deserializing it again on the other end is not very effective. The performance penalty is negligible when talking to IMAP servers over network because the network latency hides it. It however shows when everything is happening locally. So we switched from a text-based protocol to a binary protocol. That means we take the actual representation of the data in the memory (bit by bit) and write it to the socket. The other side then just takes the binary data and directly interprets them as values (numbers or strings or whatever). This means we spent almost zero time on serialization and we are able to transmit large chunks of data between the server and the applications very, very efficiently.

Let's abuse the new cool stuff we have for things we did not originally designed it for

The communication between clients and server needs to work in two directions. It's not just the clients sending requests to server (and server sending back replice), we also need a mechanism for the server to notify the clients that something has changed (new event in a calendar, email marked as read, etc.). For this we were using DBus signals. The clients could connect to a DBus signal provided by the Akonadi Server and when something changed, the server notified the clients via the signal. However during initial synchronization or during intensive mail checks the amount of the messages sent over DBus by Akonadi was just too high. We were clogging the DBus daemon and the transmission of messages via DBus is not cheap either. But hey, we have an awesome and super-fast binary protocol, why not use that? And so we switched from using DBus for change notifications to sending those notifications through the same mechanism that we use for all other communication with the server. In the future it will also allow us tu even more customize the content of the notification thus further improving performance.

Pfff, who needs database indexes?

We do! Once we switched to the binary protocol we found that we are no longer waiting for the data from database to be serialized and sent over to client, but that we are waiting for the database itself! I sat down and look at EXPLAIN ANALYZE results of our biggest queries. Turns out we were doing some unnecessary JOINs (usually to get data that we already had in in-memory cache inside the Server) that we could get rid of. SQL planners and optimizers are extremely efficient nowadays, but JOINing large tables still takes time, so getting rid of those JOINs made the queries up to twice faster.

One unexpected issue I found was that the database was spending large amount of time on "ORDER BY ... DESC" on our main table (yes, we query results in descending order - this way we can show the newest (= usually most relevant) emails in KMail first, while still retrieving the rest). PostgreSQL users will be happy to know that adding a special descending index sped up the queries massively. MySQL users are out of luck - although MySQL allows to create a descending index on a column, it does not really do anything about it.

Splitting libraries is too mainstream, we merge stuff!

One of the things that I've been looking forward to for a very long time was making the Akonadi server a private part (an implementation detail) of the Akonadi client libraries. In KDE4 versions we had to maintain a backwards compatibility of the Akonadi protocol (the text-based one I mentioned earlier) as it was considered a part of public API. This was extremely limiting and annoying for me as a maintainer, as it was making fixing certain bugs and adding new features unnecessarily hard. Historically Akonadi server was a standalone project and it was expected that 3rd party developers would write their own client libraries in their own toolkits/languages. Unfortunately that never happened and the KDE Akonadi client libraries were the only client libraries out there that were actively developed and used (there were some proof-of-concept GLib/Gtk client libraries, but never used seriously).

So, since KDE Applications 15.08 the Akonadi server has no public API and writing custom client libraries is not officially supported. The only official way to talk to the server is through the KDE Akonadi client libraries, which is now the only public API for Akonadi. This may sound like a bad decision, like closing ourselves down from the world, like if we don't care about anyone else but KDE and Qt. And it's sort of true - we were waiting for almost a decade for someone else to start writing their client libraries, but nobody did. So why bother? On the other hand the only actual and real user of Akonadi - KDE - benefits much more now - for example the binary protocol is optimized so that (de)serializing Qt types (like QString or QDateTime) is very efficient because we can use the format that Qt uses internally. If we were to be "toolkit agnostic", we would have to waste time on converting the data to some more standard representation and nobody would win.

To finally get to the point: today I took the Akonadi client libraries (that lived in kdepimlibs.git) and merged them to akonadi.git repository, where the Akonadi server is - at least locally on my machine, still need to fix some build issues before actually pushing this, but I expect to do it tomorrow. In other words the entire Akonadi Framework now lives in a single self-contained git repository. This brings even more benefits, mostly from maintainer point of view. For instance we can now share more code between the server and the libraries that we previously had to duplicate or expose via some private shared library.

The kdepimlibs.git will still contain some libraries for now that we yet have to figure out what to do with, but I guess that eventually kdepimlibs.git will meet the same fate as kdelibs.git - being locked down and preserved only for historical reference.

The Cheese Dependency

In September last year the KDE PIM team also met in Randa in Swiss Alps. I was totally going to blog about it, but then other things got into way and I kept delaying it further and further until now. So with an awkward 5 months delay: huge thanks and hugs to the entire Randa meetings staff and one more hug to Mario just for being Mario. In Randa we met to discuss where KDE PIM should go next and how to get there. After several days on intensive talking we outlined the path into future - you probably read about it already in some of the blogs about AkonadiNext from Christian and Aaron, so I won't go much into that.

To list some of the visible and practical results - we now use Phabricator to coordinate the work in the PIM team and to better communicate what is happening and who's working on what. There's a nice backlog of tasks waiting to be done, so if you want to help us make PIM better feel free to pick up some task and get to work! Furthermore we looked into cleaning up some of the old code and optimizing some critical code-paths - basically a continuation of an effort that started already during Akademy in A Coruña. Some of the changes were already implemented, some are still pending.

Lord of the PIM: The Return of The KJots

One of the major complaints we heard about the new KF5-based KDE PIM was the disappearance of KJots, our note-taking app. Earlier last year, on a PIM sprint in Toulouse, we decided that we need to reduce the size of the code base to keep it maintainable given the current manpower (or rather lack thereof). KJots was one of the projects we decided to kill. What we did not realize back then was that we will effectively prevent people from accessing their notes, since we don't have any other app for that! I apologize for that to all our users, and to restore the balance in the Force I decided to bring KJots back. Not as a part of the main KDE PIM suite but as a standalone app. I have yet to make a first release that packagers can package, but it already builds and is reasonably usable. I'm not planning on developing the application very actively - I'll keep it breathing, but that's about it. That's all I can afford. If there's anyone who would be interesting in maintaining the application and developing it further (it's a rather small and simple application), feel free to step up! When the app reaches certain quality level, we can start thinking about merging it back to KDE PIM.

Is that all?

Yes. No. Well, it's all for today. There is much much more happening in KDE PIM - Laurent did tons of work on of refactoring and splitting the monolithic kdepim.git repository into smaller, better reusable pieces and now seems to be messing around Akregator, and Sandro is actively working on refactoring the email rendering code and calendaring. But I'll leave it up to them to report on their work :) And of course there's much more planned for the future (as always), but this blog post already got a bit out of hand, I'll report on the rest maybe next time I "accidentally" have an energy drink at 11 PM.

And as always: we need help. Like, lots of it. KDE PIM might look huge and scary and hard to work on, but in fact it's all rainbows and unicorns. Hacking on PIM is fun (and we are fun too sometimes!), so if you like KDE (PIM) and would like to help us, let's talk!

Git trick #628: automatically set commit author based on repo URL

If you have more than one email identity that you use to commit to different projects you have to remember to change it in .git/config every time you git clone a new repository. I suck at remembering things and it’s been annoying me for a long time that I kept pushing commits with wrong email addresses to wrong repositories.

I can’t believe I am the only one having this problem, but I could not find anything on the interwebs so I just fixed it myself and I’m posting it here so that maybe hopefuly someone else will find it useful too :).

The trick is very simple: we create a post-checkout hook that will check the value of user.email in .git/config and set it to whatever we want based on URL of the “origin” remote.  Why post-checkout? Because there’s no post-clone hook, but git automatically checkouts master after clone so the hook gets executed. It also gets executed every time you run git checkout by hand but the overhead is minimal and we have a guard against overwriting the identity in case it’s already set.

#!/usr/bin/python
# -*- coding: utf-8 -*-
#
# (C) 2015 Daniel Vrátil &lt;dvratil@kde.org&gt;
# License: GPL
#
# Requires: Python 2 or 3 and compatible GitPython
#
# https://github.com/gitpython-developers/GitPython
import git
import ConfigParser
import os
import sys

repo = git.Repo(os.getcwd())

# Don't do anything if an identity is already configured in this
# repo's .git/config
config = repo.config_reader(config_level = 'repository')
try:
    # The value of user.email is non-empty, stop here
    if config.get_value('user', 'email'):
        sys.exit(0)
except (ConfigParser.NoSectionError, ConfigParser.NoOptionError):
    # Section or option does not exist, continue
    pass
origin = repo.remote('origin')
if not origin:
    print('** Failed to detect remote origin, identity not updated! **')
    sys.exit(0)
# This is where you adjust the code to fit your needs
if 'kde.org' in origin.url or origin.url.startswith('kde:'):
    email = 'dvratil@kde.org'
elif 'fedoraproject.org' in origin.url:
    email = 'dvratil@fedoraproject.org'
elif 'kdab.com' in origin.url:
    email = 'daniel.vratil@kdab.com'
else:
    print('** Failed to detect identity! **')
    sys.exit(0)
# Write the option to .git/config
config = repo.config_writer()
config.set_value('user', 'email', email)
config.release()
print('** User identity for this repository set to \'%s\' **' % email)

To install it, just copy the script above to ~/.git-templates/hooks/post-checkout, make it executable and run

git config --global init.templatedir ~/.git-templates

All hooks from templatedir are automatically copied into .git/hooks when a new repository is created (git init or git clone) - this way the hook will get automatically deployed to every new repo.

And here’s a proof that it works :-)

[dvratil@Odin ~/devel/KDE]
$ git clone kde:kasync
Cloning into 'kasync'...
remote: Counting objects: 450, done.
remote: Compressing objects: 100% (173/173), done.
remote: Total 450 (delta 285), reused 431 (delta 273)
Receiving objects: 100% (450/450), 116.44 KiB | 0 bytes/s, done.
Resolving deltas: 100% (285/285), done.
Checking connectivity... done.
** User identity for this repository set to 'dvratil@kde.org' **

[dvratil@Odin ~/packaging/fedpkg]
$ git clone ssh://dvratil@pkgs.fedoraproject.org/gammaray
Cloning into 'gammaray'...
remote: Counting objects: 287, done.
remote: Compressing objects: 100% (286/286), done.
remote: Total 287 (delta 113), reused 0 (delta 0)
Receiving objects: 100% (287/287), 57.24 KiB | 0 bytes/s, done.
Resolving deltas: 100% (113/113), done.
Checking connectivity... done.
** User identity for this repository set to 'dvratil@fedoraproject.org' **

Update 1: added utf-8 coding (thanks, Andrea) Update 2: changed shebang to more common /usr/bin/python (/bin/python is rather Fedora-specific), added “Requires” comment to top of the script (thanks, Derek)