Canonical Voiceshttp://voices.canonical.com2014-04-04T16:49:40ZMartin Albisetti: On open sourcing Ubuntu One filesync2014-04-04T16:49:40Zbeunonospam@nospam.comhttp://beuno.com.ar/archives/318<p dir="ltr" id="docs-internal-guid-86ea5457-2d6c-f77a-dde1-8033a469816d">This week has been bitter-sweet. On the one hand, we announced that a project many of us had poured our hearts and minds into was going to be shut down. It’s made many of us sad and some of us haven’t even figured out what to do with their files yet <img src="http://beuno.com.ar/wp-includes/images/smilies/icon_smile.gif" alt=":)" class="wp-smiley" /></p>
<p dir="ltr">On the other hand, we’ve been laser-focused on making Ubuntu on phones and tablets a success, our attention has moved to making sure we have a rock-solid, scalable, secure and pleasant to use for developers and users alike. We just didn’t have the time to continue racing against other companies whose only focus is on file syncing, which was very frustrating as we saw a project we were proud of be left behind. It was hard to keep feeling proud of the service, so shutting it down felt like the right thing to do.</p>
<p dir="ltr">
<p dir="ltr">I am, however, very excited about open sourcing the server-side of the file syncing infrastructure. It’s a huge beast that contains many services and has scaled well into the millions of users.</p>
<p dir="ltr">We are proud of the code that is being released and in many ways we feel that the code itself was successful despite the business side of things not turning out the way we hoped for.</p>
<p dir="ltr">This will be a great opportunity to those of you who’ve been itching to have an open source service for personal cloud syncing at scale, the code comes battle-tested and with a wide array of features.</p>
<p dir="ltr">As usual, some people have taken this generous gesture “as an attempt to gain interest in a failing codebase”, which couldn’t be more wrong. The agenda here is to make Ubuntu for phones a runaway success, and in order to do that we need to double down on our efforts and focus on what matters right now.</p>
<p dir="ltr">Instead of storing away those tens of thousands of expensive man-hours of work in an internal repository somewhere, we’ve decided to share that work with the world, allow others to build on top of that work, benefit from it.</p>
<p dir="ltr">It’s hard sometimes to see some people trying to make a career out of trying to make everything that Canonical does as inherently evil, although at the end of the day what matters is making open source available to the masses. That’s what we’ve been doing for a long time and that’s the only thing that will count in the end.</p>
<p>&nbsp;</p>
<p dir="ltr">So in the coming months we’re going to be cleaning things up a bit, trying to release the code in the best shape possible and work out the details on how to best release it to make it useful for others.</p>
<p>All of us who worked on this project for so many years are looking forward to sharing it and look forward to seeing many open source personal cloud syncing services blossoming from it.</p>Canonical Blog: Shutting down Ubuntu One file services2014-04-02T14:10:02ZJane Silbernospam@nospam.comhttp://blog.canonical.com/2014/04/02/shutting-down-ubuntu-one-file-services/<p dir="ltr">Today we are announcing plans to shut down the <a href="https://one.ubuntu.com/">Ubuntu One</a> file services. This is a tough decision, particularly when our users rely so heavily on the functionality that Ubuntu One provides. However, like any company, we want to focus our efforts on our most important strategic initiatives and ensure we are not spread too thin.</p>
<p dir="ltr">Our strategic priority for Ubuntu is making the best converged operating system for phones, tablets, desktops and more. In fact, our user experience, developer tools for apps and scopes, and commercial relationships have been constructed specifically to highlight third party content and services (as opposed to our own); this is one of our many differentiators from our competitors. Additionally, the free storage wars aren’t a sustainable place for us to be, particularly with other services now regularly offering 25GB-50GB free storage. If we offer a service, we want it to compete on a global scale, and for Ubuntu One to continue to do that would require more investment than we are willing to make. We choose instead to invest in making the absolute best, open platform and to highlight the best of our partners’ services and content.</p>
<p dir="ltr">As of today, it will no longer be possible to purchase storage or music from the Ubuntu One store. The Ubuntu One file services will not be included in the upcoming Ubuntu 14.04 LTS release, and the Ubuntu One apps in older versions of Ubuntu and in the Ubuntu, Google, and Apple stores will be updated appropriately. The current services will be unavailable from 1 June 2014; user content will remain available for download until 31 July, at which time it will be deleted.</p>
<p dir="ltr">We will work to ensure that customers have an easy path to download all their content from Ubuntu One to migrate to other personal cloud services. Additionally, we continue to believe in the Ubuntu One file services, the quality of the code, and the user experience, so will release the code as open source software to give others an opportunity to build on this code to create an open source file syncing platform.</p>
<p dir="ltr">Customers who have an active annual subscription will have their unused fees refunded. We will calculate the refund amount from today’s announcement, even though the service will remain available until 1 June and data available for a further two months.</p>
<p dir="ltr">We will contact customers separately with additional information about what to expect. We will also publish further blog posts with advice on how to download content and with details on the open sourcing of the code.</p>
<p dir="ltr">The shutdown will not affect the Ubuntu One single sign on service, the Ubuntu One payment service, or the backend U1DB database service.</p>
<p dir="ltr">We’ve always been inspired by the support, feedback and enthusiasm of our users and want to thank you for the support you’ve shown for Ubuntu One. We hope that you’ll continue to support us as together we bring a revolutionary experience to new devices.</p>
<p dir="ltr">
<p dir="ltr"><em><strong>UPDATE: See <a title="this post" href="http://voices.canonical.com/ubuntuone/2014/06/03/moving-your-content-away-from-ubuntu-one-file-services/">this post</a> for updated information on downloading all your content from Ubuntu One. We are aware that in some rare cases (large amount of content or very large number of files), the bulk download to a single archive is failing. Don&#8217;t worry &#8211; your content is not lost and we&#8217;ll post an updated bulk download tool which generates multiple archives rather than a single large one. We know of no issues with the other options discussed in that post.</strong></em></p>
<p>&nbsp;</p>Ubuntu One Blog: Shutting down Ubuntu One file services2014-04-02T11:15:21ZCristian Parrinonospam@nospam.comhttp://voices.canonical.com/ubuntuone/2014/04/02/shutting-down-ubuntu-one-file-services/<p dir="ltr">Today we are announcing plans to shut down the <a href="https://one.ubuntu.com/">Ubuntu One</a> file services. This is a tough decision, particularly when our users rely so heavily on the functionality that Ubuntu One provides. However, like any company, we want to focus our efforts on our most important strategic initiatives and ensure we are not spread too thin.</p>
<p dir="ltr">Our strategic priority for Ubuntu is making the best converged operating system for phones, tablets, desktops and more. In fact, our user experience, developer tools for apps and scopes, and commercial relationships have been constructed specifically to highlight third party content and services (as opposed to our own); this is one of our many differentiators from our competitors. Additionally, the free storage wars aren’t a sustainable place for us to be, particularly with other services now regularly offering 25GB-50GB free storage. If we offer a service, we want it to compete on a global scale, and for Ubuntu One to continue to do that would require more investment than we are willing to make. We choose instead to invest in making the absolute best, open platform and to highlight the best of our partners’ services and content.</p>
<p dir="ltr">As of today, it will no longer be possible to purchase storage or music from the Ubuntu One store. The Ubuntu One file services will not be included in the upcoming Ubuntu 14.04 LTS release, and the Ubuntu One apps in older versions of Ubuntu and in the Ubuntu, Google, and Apple stores will be updated appropriately. The current services will be unavailable from 1 June 2014; user content will remain available for download until 31 July, at which time it will be deleted.</p>
<p>We will work to ensure that customers have an easy path to download all their content from Ubuntu One to migrate to other personal cloud services. Additionally, we continue to believe in the Ubuntu One file services, the quality of the code, and the user experience, so will release the code as open source software to give others an opportunity to build on this code to create an open source file syncing platform.</p>
<p>Customers who have an active annual subscription will have their unused fees refunded. We will calculate the refund amount from today’s announcement, even though the service will remain available until 1 June and data available for a further two months.</p>
<p dir="ltr">We will contact customers separately with additional information about what to expect. We will also publish further blog posts with advice on how to download content and with details on the open sourcing of the code.</p>
<p dir="ltr">The shutdown will not affect the Ubuntu One single sign on service, the Ubuntu One payment service, or the backend U1DB database service.</p>
<p dir="ltr">We’ve always been inspired by the support, feedback and enthusiasm of our users and want to thank you for the support you’ve shown for Ubuntu One. We hope that you’ll continue to support us as together we bring a revolutionary experience to new devices.</p>
<p>&nbsp;</p>Canonical Blog: Ubuntu phone, tablet at Mobile World Congress2013-02-25T08:30:05Zlogin.ubuntu.com-id-hY4GFhrnospam@nospam.comhttp://blog.canonical.com/2013/02/25/ubuntu-phone-tablet-at-mobile-world-congress/<p><em><strong>Ubuntu Phone OS integrates with Orange and Deutsche Telekom in GSMA OneAPI initiative</strong> </em></p>
<p>Mobile World Congress kicks off today and we’re gearing up to show off Ubuntu running on multiple devices. We’ll be demonstrating phones, tablets and desktops at the stand, have Ubuntu developers flashing spare hardware, as well as be showing integration and interoperability with Orange and Deutsche Telekom through the GSMA’s One API initiative.</p>
<p><a href="http://www.gsma.com/newsroom/gsma-announces-oneapi-exchange">GSMA’s OneAPI initiative</a> aims to provide application programming interfaces (APIs) that enable applications to exploit mobile network capabilities, such as messaging, authentication, payments and location-finding with a cross-operator reach. For example, a payment network API could be used to add an in-app purchase directly to the user’s mobile phone bill.</p>
<p>Ubuntu is the first smartphone operating system to be able to demonstrate integration and interoperability with a carrier&#8217;s authentication and billing systems. Working with Deutsche Telekom and Orange, we’ll show how a single API can be used to instantly log users in with their operator identity and seamlessly link that with Ubuntu One, Ubuntu’s identity and payments services, and provide carrier billing options upon purchase of music and eventually, apps.</p>
<p>This is a massive step forward for the industry as the GSMA and partners such as Canonical, are spearheading an initiative to standardise access to operator facilities via network APIs across all operators. The initiative will benefit operators, developers and consumers:</p>
<ul>
<li>It puts operators in a position to forge stronger relationships with their customers.</li>
<li>For developers, OneAPI reduces the time and effort needed to create applications for and content that is portable across mobile operators, increasing reach and ultimately enhancing the consumer experience.</li>
<li>For consumers, it makes it really quick and easy to make application purchases directly from their phone. It’s also more secure because it’s not necessary to input credit card details for each purchase.</li>
</ul>
<p>Also at Mobile World Congress:</p>
<ul>
<li>Mark Shuttleworth, founder of Ubuntu, will participate in a keynote panel discussion alongside Mozilla and Tizen on Tuesday 26th Feb at 18.00 at the MWC Conference Auditorium and broadcast live on Mobile World Live</li>
<li>We’ll be taking part in the App Developer Day on Tuesday 26th Feb. Stuart Langridge, technical architect at Canonical will be presenting the Ubuntu phone, SDK, HTML5 and native apps as well as discussing app development for Ubuntu on phones and tablets. We’ll also have engineers available at the event to flash spare handsets with Touch Developer Preview of Ubuntu. This will take place from 9.00-9.30 and 11.40-11.55, and 13.30-14.00 in Hall 8.0, Theatre A.</li>
<li>The GSMA Seminar on “Unlocking Value with Network APIs” will run on Thursday 28th from 9am to 10.30 am in Room CC1.1. Canonical’s Stuart Langridge will present and demo the Ubuntu Phone during the session. We’ll also be demonstrating Ubuntu’s OneAPI solution at the GSMA stand daily.</li>
<li>Look out for Ubuntu engineers who will flash spare hardware with developer images for phone and tablet throughout the show close to the Ubuntu stand.</li>
</ul>James Henstridge: u1ftp: a demonstration of the Ubuntu One API2012-07-05T09:19:00ZJames Henstridgenospam@nospam.comhttp://blogs.gnome.org/jamesh/2012/07/05/u1ftp/<p>One of the projects I&#8217;ve been working on has been to improve aspects of the <a href="https://one.ubuntu.com/developer/">Ubuntu One Developer Documentation</a> web site. While there are still some layout problems we are working on, it is now in a state where it is a lot easier for us to update.</p>
<p>I have been working on updating our <a href="https://one.ubuntu.com/developer/account_admin/auth/index">authentication/authorisation</a> documentation and revising some of the <a href="https://one.ubuntu.com/developer/files/store_files/cloud">file storage</a> documentation (the API used by the mobile Ubuntu One clients). To help verify that the documentation was useful, I wrote a small program to exercise those APIs. The result is <a href="https://launchpad.net/u1ftp">u1ftp</a>: a program that exposes a user&#8217;s files via an FTP daemon running on localhost. In conjunction with the OS file manager or a dedicated FTP client, this can be used to conveniently access your files on a system without the full Ubuntu One client installed.</p>
<p>You can download the program from:</p>
<p><a href="https://launchpad.net/u1ftp/trunk/0.1/+download/u1ftp-0.1.zip">https://launchpad.net/u1ftp/trunk/0.1/+download/u1ftp-0.1.zip</a></p>
<p>To make it easy to run on as many systems as possible, I packaged it up as a <a href="http://blogs.gnome.org/jamesh/2012/05/21/python-zip-files/">runnable zip file</a> so can be run directly by the <a href="http://www.python.org/">Python</a> interpreter. As well as a Python interpreter, you will need the following installed to run it:</p>
<ul>
<li>On Linux systems, either the gnomekeyring extension (if you are using a GNOME derived desktop), or PyKDE4 (if you have a KDE derived desktop).</li>
<li>On Windows, you will need <a href="http://sourceforge.net/projects/pywin32/files/pywin32/">pywin32</a>.</li>
<li>On MacOS X, you shouldn&#8217;t need any additional modules.</li>
</ul>
<p>These could not be included in the zip file because they are extension modules rather than pure Python.</p>
<p>Once you&#8217;ve downloaded the program, you can run it with the following command:</p>
<blockquote>
<pre>python u1ftp-0.1.zip</pre>
</blockquote>
<p>This will start the FTP server listening at <tt>ftp://localhost:2121/</tt>. Pointing a file manager at that URL should prompt you to log in, where you can use your standard Ubuntu One credentials and start browsing your files. It will verify the credentials against the Ubuntu SSO service and issue an <a href="http://oauth.net/">OAuth</a> token that it stores in the keyring. The OAuth token is then used to authenticate requests to the file storage REST API.</p>
<p>While I expect this program to be useful on its own, it was also intended to act as an example of how the Ubuntu One API can be used. One way to browse the source is to simply unzip the package and poke around. Alternatively, you can check out the source directly from Launchpad:</p>
<blockquote>
<pre>bzr branch lp:u1ftp</pre>
</blockquote>
<p>If you come up with an interesting extension to u1ftp, feel free to upload your changes as a branch on Launchpad.</p>Manuel de la Pena: Ignoring system folders when doing an os.listdir2011-12-07T19:17:36Zmandelnospam@nospam.comhttp://www.themacaque.com/?p=991<p>Recently a very interesting bug has been reported agains Ubuntu One on Windows. Apparently we try to sync a number of system folders that are present on Windows 7 to be backward compatible.</p>
<h2>The problem</h2>
<p>The actual problem in the code is that we are using os.listdir. While lisdir on python does return system folders (at the end of the day, they are there) os.walk does not, for example, lets imaging hat we have the following scenario:</p>
<pre>
Documents
My Pictures (System folder)
My Videos (System folder)
Random dir
Random Text.txt
</pre>
<p>If we run os.listdir we would have the following:</p>
<div class="wp_syntax"><div class="code"><pre class="python"><span>import</span> <span>os</span>
<span>&gt;&gt;</span> <span>os</span>.<span>listdir</span><span>&#40;</span><span>'Documents'</span><span>&#41;</span>
<span>&#91;</span><span>'My Pictures'</span>, <span>'My Videos'</span>, <span>'Random dir'</span>, <span>'Random Text.txt'</span><span>&#93;</span></pre></div></div>
<p>While if we use os.walk we have:</p>
<div class="wp_syntax"><div class="code"><pre class="python"><span>import</span> <span>os</span>
path, dirs, files = <span>os</span>.<span>walk</span><span>&#40;</span><span>'Documents'</span><span>&#41;</span>
<span>print</span> dirs
<span>&gt;&gt;</span> <span>&#91;</span><span>'Random dir'</span><span>&#93;</span>
<span>print</span> files
<span>&gt;&gt;</span> <span>&#91;</span><span>'Random Text.txt'</span><span>&#93;</span></pre></div></div>
<p>The fix is very simple, simply filter the result from os.listdir using the following function:</p>
<div class="wp_syntax"><div class="code"><pre class="python"><span>import</span> win32file
&nbsp;
INVALID_FILE_ATTRIBUTES = -<span>1</span>
&nbsp;
&nbsp;
<span>def</span> is_system_path<span>&#40;</span>path<span>&#41;</span>:
<span>&quot;&quot;&quot;Return if the function is a system path.&quot;&quot;&quot;</span>
attrs = win32file.<span>GetFileAttributesW</span><span>&#40;</span>path<span>&#41;</span>
<span>if</span> attrs == INVALID_FILE_ATTRIBUTES:
<span>return</span> <span>False</span>
<span>return</span> win32file.<span>FILE_ATTRIBUTE_SYSTEM</span> <span>&amp;</span> attrs ==\
win32file.<span>FILE_ATTRIBUTE_SYSTEM</span></pre></div></div>
<h2>File system events</h2>
<p>An interesting question to ask after the above is, how does ReadDirectoryChangesW work with systen directories? Well, thankfully it works correctly. What does that mean? Well, it means the following:</p>
<ul>
<li>Changes in the system folders do not get notified.</li>
<li>Moves from a watch directory to a system folder is not a MOVE_TO, MOVE_FROM couple but a FILE_DELETED</li>
</ul>
<p>The above means that if you have a system folder in a watch path you do not need to worry since the events will work correctly, which are very very good news.</p>Manuel de la Pena: Performing autoupdates with Bitrock2011-10-17T09:52:09Zmandelnospam@nospam.comhttp://www.themacaque.com/?p=945<p>On Ubuntu One we use BtiRock to create the packages for Windows. One of the new features I&#8217;m working on is to check if there are updates every so often so that the user gets notified. This code on Ubuntu is not needed because the Update Manger takes care of that, but when you work in an inferior OS&#8230; </p>
<h2>Generate the auto-update.exe</h2>
<p>In order to check for updates we use the generated auto-update.exe wizard from BitRock. Generating the wizard is very straight forward first, as with most of the BitRock stuff, we generate the XML to configure the generated .exe.</p>
<pre lang="xml">
&lt;autoUpdateProject&gt;
&lt;fullName&gt;Ubuntu One&lt;/fullName&gt;
&lt;shortName&gt;ubuntuone&lt;/shortName&gt;
&lt;vendor&gt;Canonical&lt;/vendor&gt;
&lt;version&gt;201&lt;/version&gt;
&lt;singleInstanceCheck&gt;1&lt;/singleInstanceCheck&gt;
&lt;requireInstallationByRootUser&gt;0&lt;/requireInstallationByRootUser&gt;
&lt;requestedExecutionLevel&gt;asInvoker&lt;/requestedExecutionLevel&gt;
&lt;/autoUpdateProject&gt;
</pre>
<p>There is just a single thing that is worth mentioning about the above XML. The <strong>requireInstallationByRootUser</strong> is true because we use the generated .exe to check if there are updates present and we do not what the user to have to be root for that, it does not make sense. Once you have the above or similar XML you can execute:</p>
<pre>
{$bitrock_installation$}\autoupdate\bin\customize.exe" build ubuntuone_autoupdate.xml windows
</pre>
<p>Which generates the .exe (the output is in ~\Documents\AutoUpdate\output).</p>
<h2>Putting it together with Twisted</h2>
<p>The following code provides an example of a couple of functions that can be used by the application, first to check for an update, and to perform the actual update.</p>
<div class="wp_syntax"><table><tr><td class="line_numbers"><pre>1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
</pre></td><td class="code"><pre class="python"><span>import</span> <span>os</span>
<span>import</span> <span>sys</span>
&nbsp;
<span># Avoid pylint error on Linux</span>
<span># pylint: disable=F0401</span>
<span>import</span> win32api
<span># pylint: enable=F0401</span>
&nbsp;
<span>from</span> twisted.<span>internet</span> <span>import</span> defer
<span>from</span> twisted.<span>internet</span>.<span>utils</span> <span>import</span> getProcessValue
&nbsp;
AUTOUPDATE_EXE_NAME = <span>'autoupdate-windows.exe'</span>
&nbsp;
<span>def</span> _get_update_path<span>&#40;</span><span>&#41;</span>:
<span>&quot;&quot;&quot;Return the path in which the autoupdate command is found.&quot;&quot;&quot;</span>
<span>if</span> <span>hasattr</span><span>&#40;</span><span>sys</span>, <span>&quot;frozen&quot;</span><span>&#41;</span>:
exec_path = <span>os</span>.<span>path</span>.<span>abspath</span><span>&#40;</span><span>sys</span>.<span>executable</span><span>&#41;</span>
<span>else</span>:
exec_path = <span>os</span>.<span>path</span>.<span>dirname</span><span>&#40;</span>__file__<span>&#41;</span>
folder = <span>os</span>.<span>path</span>.<span>dirname</span><span>&#40;</span>exec_path<span>&#41;</span>
update_path = <span>os</span>.<span>path</span>.<span>join</span><span>&#40;</span>folder, AUTOUPDATE_EXE_NAME<span>&#41;</span>
<span>if</span> <span>os</span>.<span>path</span>.<span>exists</span><span>&#40;</span>update_path<span>&#41;</span>:
<span>return</span> update_path
<span>return</span> <span>None</span>
&nbsp;
&nbsp;
@defer.<span>inlineCallbacks</span>
<span>def</span> are_updates_present<span>&#40;</span>logger<span>&#41;</span>:
<span>&quot;&quot;&quot;Return if there are updates for Ubuntu One.&quot;&quot;&quot;</span>
update_path = _get_update_path<span>&#40;</span><span>&#41;</span>
logger.<span>debug</span><span>&#40;</span><span>'Update path %s'</span>, update_path<span>&#41;</span>
<span>if</span> update_path <span>is</span> <span>not</span> <span>None</span>:
<span># If there is an update present we will get 0 and other number</span>
<span># otherwise</span>
retcode = <span>yield</span> getProcessValue<span>&#40;</span>update_path, args=<span>&#40;</span><span>'--mode'</span>,
<span>'unattended'</span><span>&#41;</span>, path=<span>os</span>.<span>path</span>.<span>dirname</span><span>&#40;</span>update_path<span>&#41;</span><span>&#41;</span>
logger.<span>debug</span><span>&#40;</span><span>'Return code %s'</span>, retcode<span>&#41;</span>
<span>if</span> retcode == <span>0</span>:
logger.<span>debug</span><span>&#40;</span><span>'Returning True'</span><span>&#41;</span>
defer.<span>returnValue</span><span>&#40;</span><span>True</span><span>&#41;</span>
logger.<span>debug</span><span>&#40;</span><span>'Returning False'</span><span>&#41;</span>
defer.<span>returnValue</span><span>&#40;</span><span>False</span><span>&#41;</span>
&nbsp;
&nbsp;
<span>def</span> perform_update<span>&#40;</span><span>&#41;</span>:
<span>&quot;&quot;&quot;Spawn the autoupdate process and call the stop function.&quot;&quot;&quot;</span>
update_path = _get_update_path<span>&#40;</span><span>&#41;</span>
<span>if</span> update_path <span>is</span> <span>not</span> <span>None</span>:
<span># lets call the updater with the commands that are required,</span>
win32api.<span>ShellExecute</span><span>&#40;</span><span>None</span>, <span>'runas'</span>,
update_path,
<span>'--unattendedmodeui none'</span>, <span>''</span>, <span>0</span><span>&#41;</span></pre></td></tr></table></div>
<p>With the above you should be able to easily update the installation of your frozen python app on Windows when using BitRock.</p>Manuel de la Pena: Uninstall a msi from Python2011-09-27T19:27:20Zmandelnospam@nospam.comhttp://www.themacaque.com/?p=938<p>Following my last post regarding how to list all installed applications using python here is the code that one will require to remove an installed msi from a Windows machine using python.</p>
<div class="wp_syntax"><table><tr><td class="line_numbers"><pre>1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
</pre></td><td class="code"><pre class="python"><span>class</span> MsiException<span>&#40;</span><span>Exception</span><span>&#41;</span>:
<span>&quot;&quot;&quot;Raised when there are issues with the msi actions.&quot;&quot;&quot;</span>
&nbsp;
&nbsp;
<span>def</span> uninstall_product<span>&#40;</span>uid<span>&#41;</span>:
<span>&quot;&quot;&quot;Will remove the old beta from the users machine.&quot;&quot;&quot;</span>
<span># we use the msi lib to be able to uninstall apps</span>
property_name = u<span>'LocalPackage'</span>
uninstall_path = get_property_for_product<span>&#40;</span>uid, property_name<span>&#41;</span>
<span>if</span> uninstall_path <span>is</span> <span>not</span> <span>None</span>:
<span># lets remove the package.</span>
command_line = u<span>'REMOVE=ALL'</span>
result = windll.<span>msi</span>.<span>MsiInstallProductW</span><span>&#40;</span>uninstall_path, command_line<span>&#41;</span>
<span>if</span> result <span>!</span>= ERROR_SUCCESS:
<span>raise</span> MsiException<span>&#40;</span><span>'Could not remove product %s'</span> <span>%</span> uid<span>&#41;</span></pre></td></tr></table></div>
<p>The missing functions can be found in the <a href="http://www.themacaque.com/?p=932">last post</a> about the topic.</p>David Planella: Goodbye And Thanks For All the Apps: Ubuntu App Developer Week &#8211; Day 5 And Wrap-Up2011-09-13T16:45:58ZDavidnospam@nospam.comhttp://davidplanella.wordpress.com/2011/09/13/goodbye-and-thanks-for-all-the-apps-ubuntu-app-developer-week-day-5-and-wrap-up/<p><img class="aligncenter size-full wp-image-1308" title="Ubuntu App Developer Week" src="http://davidplanella.files.wordpress.com/2011/09/uadw.png?w=480" alt="" /></p>
<p>Another edition of the Ubuntu App Developer Week and another amazing knowledge sharing fest around everything related to application development in Ubuntu. Brought to you by a range of the best experts in the field, here&#8217;s just a sample of the topics they talked about: <em>App Developer Strategy, Bazaar, Bazaar Explorer, Launchpad, Python, Internationalization, Launchpad Translations, Unity, Unity 2D, Gedit Developer Plugins, the MyApps Portal, the App Review Board, the UbuntuSoftware Centre, Unity Mail, Launchpad Daily Builds, Ubuntu One APIs, Rapid App Development, Quickly, GooCanvas, PyGame, Unity Launcher, Vala, the App Developer Site, Indicators, Python Desktop Integration, Libgrip, Multitouch, Unity Lenses, Ubuntu One Files Integration, The Business Side of Apps, Go, Qt Quick</em>&#8230; and more. Oh my!</p>
<p>And a pick of what they had to say:</p>
<blockquote><p>We believe that to get Ubuntu from 20 million to 200 million users, we need more and better apps on Ubuntu<br />
<a href="https://launchpad.net/~jml">Jonathan Lange</a> on making Ubuntu a target for app developers</p></blockquote>
<blockquote><p>Bazaar is the world&#8217;s finest revision control system<br />
<a href="https://launchpad.net/~jr">Jonathan Riddell</a> on Bazaar</p></blockquote>
<blockquote><p>So you&#8217;ve got your stuff, wherever you are, whichever device you&#8217;re on<br />
<a href="https://launchpad.net/%7Esil">Stuart Langridge</a> on Ubuntu One</p></blockquote>
<blockquote><p>Oneiric&#8217;s EOG and Evince will be gesture-enabled out of the box<br />
<a href="https://launchpad.net/~jpakkane">Jussi Pakkanen</a> on multitouch in Ubuntu 11.10</p></blockquote>
<blockquote><p>I control the upper right corner of your screen <img src="http://s1.wp.com/wp-includes/images/smilies/icon_wink.gif" alt=";-)" class="wp-smiley" /><br />
<a href="https://launchpad.net/~ted">Ted Gould</a> on Indicators</p></blockquote>
<p>If you happened to miss any of the sessions, you’ll find the logs for all of them on the <a href="https://wiki.ubuntu.com/UbuntuAppDeveloperWeek/">Ubuntu App Developer Week page</a>, and the summaries for each day on the links below:</p>
<ul>
<li><a href="http://davidplanella.wordpress.com/2011/09/06/great-is-the-art-of-beginning-ubuntu-app-developer-week-day-1/">Day 1 Summary</a></li>
<li><a href="http://davidplanella.wordpress.com/2011/09/07/ramping-up-ubuntu-app-developer-week-day-2/">Day 2 Summary</a></li>
<li><a href="http://davidplanella.wordpress.com/2011/09/08/knowing-your-destination-is-half-the-journey-ubuntu-app-developer-week-day-3/">Day 3 Summary</a></li>
<li><a href="http://davidplanella.wordpress.com/2011/09/09/all-good-things-come-to-an-end-ubuntu-app-developer-week-day-4/">Day 4 Summary</a></li>
<li>Day 5 Summary (this post)</li>
</ul>
<h2>Ubuntu App Developer Week &#8211; Day 5 Summary</h2>
<p>The last day came with a surprise: an extra session for all of those who wanted to know more about Qt Quick and QML. Here are the summaries:</p>
<h3>Getting A Grip on Your Apps: Multitouch on GTK apps using Libgrip</h3>
<p><em>By <a title="LaunchpadHome" href="https://launchpad.net/%7Ejpakkane">Jussi Pakkanen</a></em></p>
<p><img class="alignleft" title="Jussi Pakkanen" src="http://davidplanella.files.wordpress.com/2011/09/jussipakkanen1.jpg?w=64&h=64" alt="" width="64" height="64" />In his session, Jussi talked about one of the most interesting technologies where Ubuntu is leading the way in the open source world: multitouch. Walking the audience through the <a href="https://wiki.ubuntu.com/Multitouch/GripTutorial">Grip Tutorial</a>, he described how to add gesture support to existing applications based on GTK+ 3. He chose to focus on the higher layer of the uTouch stack, where he explained the concepts on which libgrip, the gesture library, is built upon, such as device types and subscriptions. After having explored in detail the code examples, he then revealed that in Oneiric Eye Of GNOME and Evince, Ubuntu&#8217;s default image viewer and default PDF reader, will be gesture-enabled.</p>
<p>Check out the <a href="https://wiki.ubuntu.com/MeetingLogs/appdevweek1109/MultitouchGtkUsingLibgrip">session log</a>.<em> </em></p>
<h3>Creating a Google Docs Lens</h3>
<p><em>By <a title="LaunchpadHome" href="https://launchpad.net/%7Enjpatel">Neil Patel</a></em></p>
<p><img class="alignleft" title="Neil Patel" src="http://davidplanella.files.wordpress.com/2011/09/njpatel1.jpg?w=64&h=64" alt="" width="64" height="64" />Neil introduced his session explaining the background behind Lenses: a re-architecture effort of the now superseded Places concept to make them more powerful, provide more features and make it easier to add features through a re-engineered API. Lenses create its own instance, add categories, filters and leave the searching to Scopes. The Lenses/Scopes pairs are purely requests for data, independent of the type of UI, and being provided by the libunity library, they can be written in any of the programming languages supported by GObject Introspection (Python, Javascript, C/C++, Vala, etc.). To illustrate all of this concepts, Neil devoted the rest of the session to a real example of creating a Lens for Google Docs.</p>
<p>Check out the <a href="https://wiki.ubuntu.com/MeetingLogs/appdevweek1109/CreatingGoogleDocsLens">session log</a>.<em> </em></p>
<h3>Practical Ubuntu One Files Integration</h3>
<p><em>By <a title="LaunchpadHome" href="https://launchpad.net/%7Emterry">Michael Terry</a><br />
</em></p>
<p><a href="http://davidplanella.files.wordpress.com/2011/09/stuartlangridge.jpg"><img class="alignleft" title="Michael Terry" src="http://davidplanella.files.wordpress.com/2011/09/mterry.png?w=64&h=64" alt="" width="64" height="64" /></a>Another hands-on session from Michael, with a real world example on how to supercharge apps with cloud support. Using his experience in integrating the Ubuntu One Files API to Deja Dup, the default backup application in Ubuntu, he went in detail through the code of a simple program to talk to a user&#8217;s personal Ubuntu One file storage area. We liked Michael&#8217;s session so much that it will very soon be featured as a tutorial on developer.ubuntu.com!</p>
<p>Check out the <a href="https://wiki.ubuntu.com/MeetingLogs/appdevweek1109/UbuntuOneFilesIntegration">session log</a> and Michael&#8217;s <a href="https://wiki.ubuntu.com/mterry/UbuntuOneFilesNotes11.10">awesome notes</a>.</p>
<h3>Publishing Your Apps in the Software Center: The Business Side</h3>
<p><em>By <a title="LaunchpadHome" href="https://launchpad.net/%7Ejpugh">John Pugh</a></em></p>
<p><a href="http://davidplanella.files.wordpress.com/2011/09/johnpugh.jpeg"><img class="alignleft" title="John Pugh" src="http://davidplanella.files.wordpress.com/2011/09/johnpugh.jpeg?w=64&h=64" alt="" width="64" height="64" /></a>Ubuntu directly benefits from Canonical becoming a sustainable business to support its development, and that&#8217;s exactly what John talked about. Being responsible for business development in the Ubuntu Software Centre, he&#8217;s got a privileged insight on how to make it happen. He started off explaining that the main goal is to present Ubuntu users with a large catalog of apps available for purchase, and then continued concentrating on how to submit paid applications to be published in the Software Centre. A simple 5-step process, the behind-the-scenes work can be summarized in: Canonical helps packaging the app, it hosts the app and provides the payment via pay.ubuntu.com, in a 80%/20% split. Other highlights include the facts that only non-DRM, non-licensed apps cannot be submitted right now, but there is ongoing work to implement license key support, and that MyApps, the online app submission portal, can take any nearly any content: apps with adverts, &#8220;free&#8221; online game clients and HTML5 apps.</p>
<p>Check out the <a href="https://wiki.ubuntu.com/MeetingLogs/appdevweek1109/SoftwareCenterTheBusinessSide">session log</a>.</p>
<h3>Writing an App with Go</h3>
<p><em>By <a title="LaunchpadHome" href="https://launchpad.net/%7Eniemeyer">Gustavo Niemeyer</a></em></p>
<p><a href="http://davidplanella.files.wordpress.com/2011/09/lucabruno.png"><img class="alignleft" title="Gustavo Niemeyer" src="http://davidplanella.files.wordpress.com/2011/09/niemeyer.jpeg?w=64&h=64" alt="" width="64" height="64" /></a>Gustavo&#8217;s enthusiasm for <a href="http://golang.org/">Go</a>, the new programming language created by Google shows every time you start a conversation with him on that topic. And it showed as well on this session, in which he created yet another &#8220;Hello world&#8221; application in a new language -you guessed-: Go. Along the way, he had time to describe all of the features of this new addition of the extensive family of programming languages: statically compiled with good reflection capabilities, structural typing, interfaces and more.</p>
<p>Check out the <a href="https://wiki.ubuntu.com/MeetingLogs/appdevweek1109/WritingAnAppWithGo">session log</a>.</p>
<h3>Qt Quick At A Pace</h3>
<p><em>By <a title="LaunchpadHome" href="https://launchpad.net/%7Esirspudd-gmail">Donald Carr</a></em></p>
<p><a href="http://davidplanella.files.wordpress.com/2011/09/lucabruno.png"><img class="alignleft" title="Donald Carr" src="http://davidplanella.files.wordpress.com/2011/09/donaldcarr.png?w=64&h=64" alt="" width="64" height="64" /></a>Closing the week on the last -and surprise- session, we had the luxury of having Donald, from the Nokia Qt team, the makers of Qt itself, to talk about Qt Quick. Using a clear and concise definition, Qt Quick is an umbrella term used to refer to QML and its associated tooling; QML being a declarative markup language with tight bindings to Javascript. A technology equally suited to mobile or to the desktop, QML enables developers to rapidly create animation-rich, pixmap-oriented UIs. Through the <a href="http://gitorious.org/qtmediahub">qtmediahub</a> and <a href="http://qt.nokia.com/learning/online/training/materials/qt-essentials-qt-quick-edition">Qt tutorial examples</a>, he explored QML&#8217;s capabilities and offered good practices for succesfully developing QML-based projects.</p>
<p>Check out the <a href="https://wiki.ubuntu.com/MeetingLogs/appdevweek1109/QtQuickAtAPace">session log</a>.</p>
<h2>Wrapping Up</h2>
<p>Finally, if you&#8217;ve got any feedback on UADW, on how to make it better, things you enjoyed or things you believe should be improved, your comments will be very appreciated and useful to tailor this event to your needs.</p>
<p>Thanks a lot for participating. I hope you enjoyed it as much as I did, and see you again in 6 months time for another week full with app development goodness!<a href="http://webchat.freenode.net/?channels=ubuntu-classroom"><br />
</a></p>
<br /> <a rel="nofollow" href="http://feeds.wordpress.com/1.0/gocomments/davidplanella.wordpress.com/1305/"><img alt="" border="0" src="http://feeds.wordpress.com/1.0/comments/davidplanella.wordpress.com/1305/" /></a> <a rel="nofollow" href="http://feeds.wordpress.com/1.0/godelicious/davidplanella.wordpress.com/1305/"><img alt="" border="0" src="http://feeds.wordpress.com/1.0/delicious/davidplanella.wordpress.com/1305/" /></a> <a rel="nofollow" href="http://feeds.wordpress.com/1.0/gofacebook/davidplanella.wordpress.com/1305/"><img alt="" border="0" src="http://feeds.wordpress.com/1.0/facebook/davidplanella.wordpress.com/1305/" /></a> <a rel="nofollow" href="http://feeds.wordpress.com/1.0/gotwitter/davidplanella.wordpress.com/1305/"><img alt="" border="0" src="http://feeds.wordpress.com/1.0/twitter/davidplanella.wordpress.com/1305/" /></a> <a rel="nofollow" href="http://feeds.wordpress.com/1.0/gostumble/davidplanella.wordpress.com/1305/"><img alt="" border="0" src="http://feeds.wordpress.com/1.0/stumble/davidplanella.wordpress.com/1305/" /></a> <a rel="nofollow" href="http://feeds.wordpress.com/1.0/godigg/davidplanella.wordpress.com/1305/"><img alt="" border="0" src="http://feeds.wordpress.com/1.0/digg/davidplanella.wordpress.com/1305/" /></a> <a rel="nofollow" href="http://feeds.wordpress.com/1.0/goreddit/davidplanella.wordpress.com/1305/"><img alt="" border="0" src="http://feeds.wordpress.com/1.0/reddit/davidplanella.wordpress.com/1305/" /></a> <img alt="" border="0" src="http://stats.wordpress.com/b.gif?host=davidplanella.wordpress.com&blog=1814603&post=1305&subd=davidplanella&ref=&feed=1" width="1" height="1" />David Planella: Knowing Your Destination Is Half The Journey: Ubuntu App Developer Week &#8211; Day 32011-09-08T15:33:57ZDavidnospam@nospam.comhttp://davidplanella.wordpress.com/2011/09/08/knowing-your-destination-is-half-the-journey-ubuntu-app-developer-week-day-3/<h2>Ubuntu App Developer Week &#8211; Day 3 Summary</h2>
<p>Time flies and we&#8217;re already halfway through UADW, but there is still much to come! Here&#8217;s yesterday report for your reading pleasure:</p>
<h3>Unity Mail: Webmail Notification on Your Desktop</h3>
<p><em>By <a title="LaunchpadHome" href="https://launchpad.net/%7Emitya57">Dmitry Shachnev</a></em></p>
<p><img class="alignleft" title="Dmitry Shachnev" src="http://davidplanella.files.wordpress.com/2011/09/mitya1.jpg?w=64&h=64" alt="" width="64" height="64" />Starting off with a description of the features of <a href="https://launchpad.net/unity-mail">Unity Mail</a>, such as displaying webmail unread message count, notifications and mail subjects, we then learned more about how it was developed and the technologies that were used to create it. It&#8217;s written in Python, using GObject introspection (PyGI) and integrates with Ubuntu through the Unity, Notify and Indicate modules. After describing each one in more detail, Dmitry continued talking about how the app can be translated using Launchpad, and how he uses the Bazaar source revision control system to work with code history. Wrapping up, he went through the plans for the future: more configuration options, marking all messages as read and the need for a new icon. Any takers? <img src="http://s1.wp.com/wp-includes/images/smilies/icon_wink.gif" alt=";)" class="wp-smiley" /> </p>
<p>Check out the session log <a href="https://wiki.ubuntu.com/MeetingLogs/appdevweek1109/UnityMailWebMailNotification">here</a>.<em> </em></p>
<h3>Launchpad Daily Builds and Rapid Feedback: Writing Recipe Builds</h3>
<p><em>By <a title="LaunchpadHome" href="https://launchpad.net/%7Ejelmer">Jelmer Vernooij</a></em></p>
<p><img class="alignleft" title="Jelmer Vernooij" src="http://davidplanella.files.wordpress.com/2011/09/jelmervernooij.jpg?w=64&h=64" alt="" width="64" height="64" />Assuming some previous knowledge on Debian packaging, in his session Jelmer walked the audience through a practical example of a basic recipe build for a small project: pydoctor. Drawing the cooking recipe analogy, package recipes are a description of the ingredients (source code branches) and how to put them together, ending up with a delicious Debian package for users to enjoy. Launchpad can build packages from recipes once or automatically on a daily basis provided the code has changed, conveniently placing the result in a <a href="https://launchpad.net/ubuntu/+ppas">PPA</a>. In the last part of the session, he described in detail the contents of an existing recipe and added some notes on best practices when building from a recipe.</p>
<p>Check out the session log <a href="https://wiki.ubuntu.com/MeetingLogs/appdevweek1109/LaunchpadDailyBuildsRapidFeedback">here</a>.<em> </em></p>
<h3>Using the Ubuntu One APIs for Your Apps: An Overview</h3>
<p><em>By <a title="LaunchpadHome" href="https://launchpad.net/%7Esil">Stuart Langridge</a></em></p>
<p><a href="http://davidplanella.files.wordpress.com/2011/09/stuartlangridge.jpg"><img class="alignleft" title="Stuart Langridge" src="http://davidplanella.files.wordpress.com/2011/09/stuartlangridge.jpg?w=64&h=64" alt="" width="64" height="64" /></a>The idea bahind the Ubuntu One developer programme is to make it easy to add the cloud to your apps and make new apps for the cloud. With this opening line, Stuart delivered a talk about a high-level overview on the cool things you can do as an app developer adding Ubuntu One support. One aspect it data: for example building applications that work on the desktop, on mobile phones and on the web, securely sharing data among users. Another is music: streaming, streaming music and sharing playlists on the desktop, on mobile and from the web, all through a simple REST HTTP API. He also mentioned some examples of cloud enabled applications: Shutter and Deja-Dup, and many other interesting ways to use Ubuntu One to do exciting thigs with data. And you can get started already using the <a href="https://one.ubuntu.com/developer">available documentation</a>.</p>
<p>Check out the session log <a href="https://wiki.ubuntu.com/MeetingLogs/appdevweek1109/UsingUbuntuOneApis">here</a>.</p>
<h3>Supercharging Your Apps with Unity Launcher Integration</h3>
<p><em>By <a title="LaunchpadHome" href="https://launchpad.net/%7Ejassmith">Jason Smith</a></em></p>
<p><a href="http://davidplanella.files.wordpress.com/2011/09/jasonsmith.jpg"><img class="alignleft" title="Jason Smith" src="http://davidplanella.files.wordpress.com/2011/09/jasonsmith.jpg?w=64&h=64" alt="" width="64" height="64" /></a>In his talk, Jason first went through the terminology that covers the elements related to the Unity Launcher, and the bachground behind the Launcher API, implemented in the libunity library. Libunity can be used in many programming languages: Python, C, Vala and others supported by GObject Introspection. Going through what you can do with the Launcher (marking/unmarking apps as urgent, setting object counts, setting progress on objects and adding quicklist menu items to the object), he used Vala snippets to illustrate each feature with code.</p>
<p>Check out the session log <a href="https://wiki.ubuntu.com/MeetingLogs/appdevweek1109/UnityLauncherIntegration">here</a>.</p>
<h3>Hello Vala: An Introduction to the Vala Language</h3>
<p><em>By <a href="http://lethalman.blogspot.com/">Luca Bruno</a></em></p>
<p><a href="http://davidplanella.files.wordpress.com/2011/09/lucabruno.png"><img class="alignleft" title="Luca Bruno" src="http://davidplanella.files.wordpress.com/2011/09/lucabruno.png?w=64&h=64" alt="" width="64" height="64" /></a><a href="http://live.gnome.org/Vala">Vala</a>, a new programming language with C#-like syntax that compiles to C and targets the GObject type system: with a clear statement of what Vala is and what it can do, Luca, a contributor to the project introduced one by one the mostkey features of the language through his &#8220;Hello world&#8221; example: namespaces, types, classes, properties, keywords and more. As a highlight he mentioned Vala&#8217;s automatic memory management using reference counting, andits interoperability with other languages, most notably C, but it can also work with many others supported by GObject Introspection. Other cool featuresto note were also error handling on top of GError, support for async operations, closures and DBus client/server, on each of which he elaborated before finishing the session.</p>
<p>Check out the session log <a href="https://wiki.ubuntu.com/MeetingLogs/appdevweek1109/HelloValaIntroduction">here</a>.</p>
<h2>The Day Ahead: Upcoming Sessions for Day 3</h2>
<p>Another day, another awesome set of sessions coming up:</p>
<p><a href="http://www.timeanddate.com/worldclock/fixedtime.html?month=9&day=8&year=2011&hour=16&min=0&sec=0&p1=0">16.00 UTC</a> &#8211; <strong>Creating an App Developer Website: developer.ubuntu.com</strong><strong><em></em></strong></p>
<p><img class="alignleft size-full wp-image-1269" title="John Oxton" src="http://davidplanella.files.wordpress.com/2011/09/johnoxton.jpeg?w=480" alt="" /><img class="alignleft" title="David Planella" src="http://davidplanella.files.wordpress.com/2011/09/468171231f740a6eaf57b763b726594f.jpeg?w=64&h=64" alt="" width="64" height="64" /> Ubuntu 11.10 will not only bring new features to the OS itself. In time for the release we&#8217;ll be launching the new Ubuntu App Developer site, a place for developers to find all the infromation and the resources they need to get started creating, submitting and publishing their apps in Ubuntu. <a href="https://launchpad.net/~johnoxton">John Oxton</a>, <a href="https://launchpad.net/~dpm">David Planella</a> and many other people have worked to make the next developer.ubuntu.com possible and will tell you all about it.</p>
<p><a href="http://www.timeanddate.com/worldclock/fixedtime.html?month=9&day=8&year=2011&hour=17&min=0&sec=0&p1=0">17:00 UTC</a> &#8211; <strong>Rapid App Development with Quickly<em></em></strong></p>
<p><img class="alignleft size-full wp-image-1270" title="Michael Terry" src="http://davidplanella.files.wordpress.com/2011/09/mterry.png?w=480" alt="" /><a href="https://wiki.ubuntu.com/Quickly">Quickly</a> is a wrapper that pulls together all the recommended tools and technologies to bring apps from creation and through their whole life cycle in Ubuntu. With an easy set of commands that hide all the complexity for your, it effectively enables developers to follow rapid development principles and worry only about writing code. <a href="https://launchpad.net/~mterry">Michael Terry</a>, from the Quickly development team will be looking forward to guide you through the first steps with this awesome tool.</p>
<p><a href="http://www.timeanddate.com/worldclock/fixedtime.html?month=9&day=87&year=2011&hour=18&min=0&sec=0&p1=0">18:00 UTC</a><strong> &#8211; <em></em>Developing with Freeform Design Surfaces: GooCanvas and PyGame</strong></p>
<p><a href="http://davidplanella.files.wordpress.com/2011/09/stuartlangridge.jpg"><img class="alignleft size-full wp-image-1271" title="Rick Spencer" src="http://davidplanella.files.wordpress.com/2011/09/rickspencer.jpg?w=480" alt="" /></a>Have you ever wondered what freeform design surfaces, or canvases are? You probably have now. Well, lucky you then, because <a href="https://launchpad.net/~rick-rickspencer3">Rick Spencer</a> will be here to tell you what they&#8217;re good for and how to get started with them <img src="http://s1.wp.com/wp-includes/images/smilies/icon_wink.gif" alt=";)" class="wp-smiley" /> </p>
<p><a href="http://www.timeanddate.com/worldclock/fixedtime.html?month=9&day=8&year=2011&hour=19&min=0&sec=0&p1=0">19:00 UTC</a> &#8211; <strong><em></em>Making your app appear in the Indicators</strong></p>
<p><a href="http://davidplanella.files.wordpress.com/2011/09/jasonsmith.jpg"><img class="alignleft size-full wp-image-1272" title="Ted Gould" src="http://davidplanella.files.wordpress.com/2011/09/tedgould.jpg?w=480" alt="" /></a>In another session on how to integrate with the platform, <a href="https://launchpad.net/~ted">Ted Gould</a>, the man who knows most about them, will describe how to add <a href="https://wiki.ubuntu.com/DesktopExperienceTeam/ApplicationIndicators">indicator</a> features to your apps, both in terms of panel indicators and messaging menu support.</p>
<p><a href="http://www.timeanddate.com/worldclock/fixedtime.html?month=9&day=8&year=2011&hour=20&min=0&sec=0&p1=0">20:00 UTC</a><strong><em></em> &#8211; Will it Blend? Python Libraries for Desktop Integration</strong></p>
<p><a href="http://davidplanella.files.wordpress.com/2011/09/lucabruno.png"><img class="alignleft size-full wp-image-1273" title="person-logo" src="http://davidplanella.files.wordpress.com/2011/09/person-logo.png?w=480" alt="" /></a>You certainly will want your app to have that familiar look and feel at home in the OS it&#8217;s running on, but you&#8217;ll also want it to use all the backend technologies to integrate even deeper and provide a great user experience. Well, fear not, for <a href="https://launchpad.net/~conscioususer">Marcelo Hashimot</a>o is here to tell you exactly how to do that!</p>
<p>Looking forward to seeing you all there in a few hours!</p>
<p><a href="http://webchat.freenode.net/?channels=ubuntu-classroom"><img class="aligncenter" title="Join Ubuntu App Developer Week" src="http://davidplanella.files.wordpress.com/2011/04/rect3827.png?w=154&h=42" alt="" width="154" height="42" /></a></p>
<br /> <a rel="nofollow" href="http://feeds.wordpress.com/1.0/gocomments/davidplanella.wordpress.com/1268/"><img alt="" border="0" src="http://feeds.wordpress.com/1.0/comments/davidplanella.wordpress.com/1268/" /></a> <a rel="nofollow" href="http://feeds.wordpress.com/1.0/godelicious/davidplanella.wordpress.com/1268/"><img alt="" border="0" src="http://feeds.wordpress.com/1.0/delicious/davidplanella.wordpress.com/1268/" /></a> <a rel="nofollow" href="http://feeds.wordpress.com/1.0/gofacebook/davidplanella.wordpress.com/1268/"><img alt="" border="0" src="http://feeds.wordpress.com/1.0/facebook/davidplanella.wordpress.com/1268/" /></a> <a rel="nofollow" href="http://feeds.wordpress.com/1.0/gotwitter/davidplanella.wordpress.com/1268/"><img alt="" border="0" src="http://feeds.wordpress.com/1.0/twitter/davidplanella.wordpress.com/1268/" /></a> <a rel="nofollow" href="http://feeds.wordpress.com/1.0/gostumble/davidplanella.wordpress.com/1268/"><img alt="" border="0" src="http://feeds.wordpress.com/1.0/stumble/davidplanella.wordpress.com/1268/" /></a> <a rel="nofollow" href="http://feeds.wordpress.com/1.0/godigg/davidplanella.wordpress.com/1268/"><img alt="" border="0" src="http://feeds.wordpress.com/1.0/digg/davidplanella.wordpress.com/1268/" /></a> <a rel="nofollow" href="http://feeds.wordpress.com/1.0/goreddit/davidplanella.wordpress.com/1268/"><img alt="" border="0" src="http://feeds.wordpress.com/1.0/reddit/davidplanella.wordpress.com/1268/" /></a> <img alt="" border="0" src="http://stats.wordpress.com/b.gif?host=davidplanella.wordpress.com&blog=1814603&post=1268&subd=davidplanella&ref=&feed=1" width="1" height="1" />Manuel de la Pena: Ubuntu One in Manchester2011-08-23T17:30:53Zmandelnospam@nospam.comhttp://www.themacaque.com/?p=928<p>In a few days (well, if I find some kind person to take care of Iron) I will be attending the <a href="http://www.eventbrite.com/event/1981804631">Ubuntu One Developer evening</a> in which we should be able to hear Stuart will be talking about the bunch of crazy ideas he has for developers to use or infrastructure to do cool stuff. I&#8217;ll be there for two reason:</p>
<ul>
<li>Hear what <a href="http://www.kryogenix.org/days/2011/08/12/app-developer-evening-in-manchester-for-ubuntu-one">Stuart</a> has been planning. I&#8217;ve got to recognized I should know a lot more of the Ubuntu One developer program but unfortunately I have been in the working in the Windows port too much and I have ignored the rests of the teams&#8230; mea culpa <img src="http://www.themacaque.com/wp-includes/images/smilies/icon_sad.gif" alt=":(" class="wp-smiley" /> .</li>
<li>Learn a few more things of the APIs so that I can find my little Chrome extension that uses Ubuntu One (no, it is not bookmark sync, I cannot be less interested in that!).</li>
<li>See a bunch of developers and learn about there ideas and what they are doing.</li>
<li>Drinks, drinks, drinks! I&#8217;m a University of Manchester alumni and a bloody miss Manchester, I don&#8217;t care what people say, it is a great city.</li>
</ul>
<p>If you are going to be in Manchester you should join us, the event is FREE and trust me Stuart is a great guy to go out for drinks with (I&#8217;m not bad either, but I always get in trouble <img src="http://www.themacaque.com/wp-includes/images/smilies/icon_razz.gif" alt=":P" class="wp-smiley" /> ).</p>Martin Albisetti: Ubuntu One Files for Android released!2011-06-29T23:12:00Zbeunonospam@nospam.comhttp://beuno.com.ar/archives/254<p><img class="alignright" title="Ubuntu One Files for Android" src="http://voices.canonical.com/ubuntuone/wp-content/uploads//2011/06/img.php_.png" alt="" width="128" height="128" />After a long and interesting journey, today we've released <a href="http://market.android.com/details?id=com.ubuntuone.android.files">Ubuntu One Files for Android</a>.</p>
<p>The app started being developed by <a href="https://twitter.com/#!/mkarnicki">Micha? Karnicki</a> as a Google Summer of Code project, and he did such a fantastic job at it that we hired him on full time and teamed him up <a href="https://twitter.com/#!/chadmiller">Chad Miller</a> to end up releasing a fantastically polished app. It got immediately <a href="http://www.pocket-lint.com/news/40800/ubuntu-one-files-android-app">featured in the press</a>!<br />
It was built on top of our public APIs, documented here: <a href="https://one.ubuntu.com/developer/">https://one.ubuntu.com/developer/</a></p>
<p>Besides it letting you access all your files stored in Ubuntu One, it has a very cool feature to auto-sync all the pictures on your phone, having an instant backup of them, and a convenient place to share them!</p>
<p>I'm super proud of the work we put out.</p>
<p>Also, as with all the rest of our clients, it's open source and you can <a href="https://launchpad.net/ubuntuone-android-files/">get it in Launchpad</a></p>Manuel de la Pena: Txnamedpipes: using Windows namedpipes with twisted2011-06-27T11:21:56Zmandelnospam@nospam.comhttp://www.themacaque.com/?p=893<p>At Ubuntu One we required to be able to use named pipes on windows for IPC. This is a ver normal process in multi-process applications like the one we are going to provide, but in our case we had a twist, we are using twisted. As some of you may know there is not default reactor that would allow you to write a protocol in twisted and allows to use named pipes as the transport of the protocol. Well this was until very recently.</p>
<p>Txnamedpipes (<a href="https://launchpad.net/txnamedpipes">lp:txnamedpipes</a>) is a project that provides a ICOP based reactor that allows to use namedpipes for the transport of your protocol. At the moment we are confident that the implementation would allow you to use spred.pb or a custom protocol on twisted 10 and later on Windows 7 (we have been able to find a number of issues on Windows XP). The following is a small example of a spread.pb service and client that uses a named pipe for communication.</p>
<div class="wp_syntax"><div class="code"><pre class="python"><span>from</span> txnamedpipes.<span>reactor</span> <span>import</span> install
install<span>&#40;</span><span>&#41;</span>
<span>from</span> twisted.<span>spread</span> <span>import</span> pb
<span>from</span> twisted.<span>internet</span> <span>import</span> reactor
&nbsp;
<span>class</span> Echoer<span>&#40;</span>pb.<span>Root</span><span>&#41;</span>:
<span>def</span> remote_echo<span>&#40;</span><span>self</span>, st<span>&#41;</span>:
<span>print</span> <span>'echoing:'</span>, st
<span>return</span> st
&nbsp;
<span>if</span> __name__ == <span>'__main__'</span>:
reactor.<span>listenPipe</span><span>&#40;</span><span>'<span>\\</span><span>\\</span>.<span>\\</span>pipe<span>\\</span>test_pipe'</span>,
pb.<span>PBServerFactory</span><span>&#40;</span>Echoer<span>&#40;</span><span>&#41;</span><span>&#41;</span><span>&#41;</span>
reactor.<span>run</span><span>&#40;</span><span>&#41;</span></pre></div></div>
<div class="wp_syntax"><div class="code"><pre class="python"><span>from</span> txnamedpipes.<span>reactor</span> <span>import</span> install
install<span>&#40;</span><span>&#41;</span>
<span>from</span> twisted.<span>spread</span> <span>import</span> pb
<span>from</span> twisted.<span>internet</span> <span>import</span> reactor
<span>from</span> twisted.<span>python</span> <span>import</span> util
&nbsp;
factory = pb.<span>PBClientFactory</span><span>&#40;</span><span>&#41;</span>
reactor.<span>connectPipe</span><span>&#40;</span><span>'<span>\\</span><span>\\</span>.<span>\\</span>pipe<span>\\</span>test_pipe'</span>, factory<span>&#41;</span>
d = factory.<span>getRootObject</span><span>&#40;</span><span>&#41;</span>
d.<span>addCallback</span><span>&#40;</span><span>lambda</span> <span>object</span>: <span>object</span>.<span>callRemote</span><span>&#40;</span><span>&quot;echo&quot;</span>,
<span>&quot;hello network&quot;</span><span>&#41;</span><span>&#41;</span>
d.<span>addCallback</span><span>&#40;</span><span>lambda</span> echo: <span>'server echoed: '</span>+echo<span>&#41;</span>
d.<span>addErrback</span><span>&#40;</span><span>lambda</span> reason: <span>'error: '</span>+<span>str</span><span>&#40;</span>reason.<span>value</span><span>&#41;</span><span>&#41;</span>
d.<span>addCallback</span><span>&#40;</span>util.<span>println</span><span>&#41;</span>
d.<span>addCallback</span><span>&#40;</span><span>lambda</span> _: reactor.<span>stop</span><span>&#40;</span><span>&#41;</span><span>&#41;</span>
reactor.<span>run</span><span>&#40;</span><span>&#41;</span></pre></div></div>
</p>
<p>The code has the MIT license and we hope that other people find it useful.</p>Martin Albisetti: Thunderbird will be default in Oneiric (11.10), maybe2011-05-12T11:20:47Zbeunonospam@nospam.comhttp://beuno.com.ar/archives/250<p>A very healthy and civilised session about switching to Thunderbird by default just ended here in the Ubuntu Developer Summit, and the outcome was that if the Thunderbird developers manage to do some needed work (to be defined) by a certain time in our cycle (to be defined), we will ship Oneiric and more importantly, the 12.04 LTS with Thunderbird by default.</p>
<p>The bits I can remember that need to be done are:<br />
- Evolution data server integration<br />
- Tighter integration with Unity<br />
- Shrink the size of the overall application so it fits in the CD<br />
- A good upgrade story<br />
- Migration plan for Evolution users</p>
<p>We will also make sure it ships with integration with contacts in Ubuntu One, thanks to <a href="http://identi.ca/jamestait">James Tait's</a> head start with the <a href="https://launchpad.net/hedera">Hedera</a> project.</p>
<p>I'm a big fan of Thunderbird, so I'll be doing my best to help them achieve their goals <img src="http://beuno.com.ar/wp-includes/images/smilies/icon_smile.gif" alt=":)" class="wp-smiley" /> </p>Manuel de la Pena: Exasperated by the Windows filesystem2011-04-26T14:37:08Zmandelnospam@nospam.comhttp://www.themacaque.com/?p=867<p>At the moment some of the tests (and I cannot point out which ones) of ubuntuone-client fail when they are ran on Windows. The reason for this is due to the way in which we get the notifications out of the file system and the way the tests are written. Before I blame the OS or the tests, let me explain a number of facts about the Windows filesystem and the possible ways to interact with it. </p>
<p>To be able to get file system changes from the OS the Win32 API provides the following:</p>
<h2><a href="http://msdn.microsoft.com/en-us/library/bb762120(v=vs.85).aspx">SHChangedNotifyRegister</a></h2>
<p>This function was broken up to Vista when it was fixed, Unfortunately AFAIK we also support Windows XP which means that we cannot trust this function. On top of that taking this path means that we can have a performance issue. Because the function is build on top of Windows messages, if too many changes occur the sync daemon would start receiving roll up messages that just state that something changed and it would be up to the sync daemon to decide what really happened. Therefore we can all agree that this is a no no, right?</p>
<h2><a href="http://msdn.microsoft.com/en-us/library/aa364417%28VS.85%29.aspx">FindFirstChangeNotification</a></h2>
<p>This is a really easy function to use which is based on ReadDirectoryChangesW (I think is a simple wrapper around it) that lets you know that something changed but gives no information about what changed. Because if is based on ReadDirectoryChangesW it suffers from the same issues.</p>
<h2><a href="http://msdn.microsoft.com/en-us/library/aa365465(v=vs.85).aspx">ReadDirectoryChangesW</a></h2>
<p>This is by far the most common way to get the notification changes from the system. Now, in theory there are two possible cases which can go wrong that would affect the events raised by this function:</p>
<ol>
<li>There are too many events and the buffer gets overloaded and we start loosing events. A simple way to solve this issues is to process the events in a diff thread asap so that we can keep reading the changes.</li>
<li>We use the sync version of the function which means that we could have the following issues:
<ul>
<li>Blue screen of death because we used too much memory from the kernel space.</li>
<li>We cannot close the handles used to watch the changes in the directories. This makes the threads to end up blocked.</li>
</ol>
<p>As I mentioned this is the theory and therefore makes perfect sense to choose this option as the way to get notified by the changes until&#8230; you hit a great little feature of Windows called write-behind caching. The idea of write-behind caching is the following one:</p>
<blockquote><p>When you attempt to write a new file on your HD Windows does not directly modify the HD. Instead it makes a not of the fact that your intention is to write on disk and saves your changes in memory. Ins&#8217;t that smart?</p></blockquote>
<p>Well, that lovely feature does come set as default AFAIK from XP onwards. Any smart person would wonder how does that interact with FindFirstChangeNotification/ReadDirectoryChangesW, well after some work here is what I have managed to find out:</p>
<p>The IO Manager (internal to the kernel) is queueing up disk-write requests in an internal buffer, and the actual changes are not physically committed until some condition is met which I believe is for the &#8220;write-behind caching&#8221; feature. The problem appears to be that the user-space callback via FileSystemWatcher/ReadDirectoryChanges does not occur when disk-write requests are inserted into the queue, but rather occurs when they are leaving the queue and being physically committed to disk. For what I have been able to manage through observation, the life time of a queue is based on:</p>
<ol>
<li>Whether more writes are being inserted in the q.</li>
<li>Is another app request a read from an item in the q.</li>
</ol>
<p>This means that when using FileSystemWatcher/ReadDirectoryChanges the events are fired only when the changes are actually committed and as for a user-space program this follows a non-deterministic process (insert spanish swearing here). a way to work around this issue is to use the <a href="http://msdn.microsoft.com/en-us/library/aa364439(v=vs.85).aspx">FluxhFileBuffers</a> function on the volume, which does need admin rights, yeah!</p>
<h2><a href="http://msdn.microsoft.com/en-us/library/aa363803%28VS.85%29.aspx">Change Journal records</a></h2>
<p>Well, this allows to track the changes that have been committed in an NTFS system (that means that we do not have support to FAT). This technique allows to keep track of the changes using an update sequence number that keeps track of changes in an interesting manner. At first look, although parsing the data is hard, this solution seems to be very similar to the one used by pyinotify and therefore someone will say, hey, let just ell twisted to do a select on that file and read the changes. Well, no, is not that easy, files do not provide the functionality used for select, just sockets (http://msdn.microsoft.com/en-us/library/aa363803%28VS.85%29.aspx) /me jumps of happiness </p>
<h2><a href="http://msdn.microsoft.com/en-us/library/ff548202.aspx">File system filter</a>r</h2>
<p>Well, this is an easy one to summarize, you have to write a driver like piece of code. Means C, COM and being able to crash the entire system with a nice blue screen (although I can change the color to aubergine before we crash)</p>
<h2>Conclusion</h2>
<p>At this point I hope I have convinced a few to believe that ReadDirectoryChangesW is the best option to take but might be wondering why I mentioned the write-behind caching feature, well here comes my complain towards the tests. We do use the real file system notifications for testing and the trial test cases do have a timeout! Those two facts plus the lovely write-behind caching feature mean that the tests on Windows fail just because the bloody evens are not raise until the leave the q from the IO manager. </p>Martin Albisetti: Looking for a CSS/HTML guru to work on Ubuntu One2011-04-26T02:20:02Zbeunonospam@nospam.comhttp://beuno.com.ar/archives/245<p>In the last few months, I've been lucky enough to be able to hire some exceptional people that were contributing to Ubuntu One in their free time. Every time someone comes in from the community, filled with excitement about being able to work on their pet project full time my job gets that much better.<br />
So, everyone say hello to <a href="http://identi.ca/jamestait">James Tait</a> and <a href="http://twitter.com/#!/mkarnicki">Micha? Karnicki</a>!</p>
<p>Now we're looking for a new team member to help us make the Ubuntu One website awesome. Someone who knows CSS and HTML inside out, cares deeply about doing things the best way possible and is passionate about their work.</p>
<p>If you're interested or know anyone who may, the <a href="https://tbe.taleo.net/NA3/ats/careers/requisition.jsp?org=CANONICAL&cws=1&rid=229">job posting</a> is up on Canonical's website.</p>David Planella: Ubuntu App Developer Week &#8211; Day 32011-04-14T22:14:37ZDavidnospam@nospam.comhttp://davidplanella.wordpress.com/2011/04/14/ubuntu-app-developer-week-day-3/<h2>Ubuntu App Developer Week &#8211; Day 3 Summary</h2>
<p>Right into the middle of the week and still delivering the most diverse set of sessions from the most interesting technologies. QML, Cloud, D-Bus, Multitouch, Unity, Bazaar&#8230; Wednesday had a bit of everything. Most importantly, this sessions are for you all, so I was really glad to hear feedback on how people liked the content of App Developer Week! So here&#8217;s a new summary for all of those who couldn&#8217;t attend.</p>
<h3>Qt Quick: QML the Language</h3>
<p><em>By Jürgen Bocklage-Ryannel</em></p>
<p>In his first session, Jürgen gave a short intro to Qt Quick&#8217;s QML language and how to use it. The first steps were to install Qt and Qt Creator, followed by a description of what Qt Quick is and how developers came up with a declarative way, similar to CSS or JSON to write in the language. All that clear, he then started with the Qt Quick tutorial and code examples that could be run with qmlviewer, the qml interpreter. Onto the second part, he focused on the QML languate, and going into the detail on how to create custom QML components. There were also lots of pointers to the excellent Qt documentation.</p>
<p><em>Check out the session log <a href="https://wiki.ubuntu.com/MeetingLogs/appdevweek1104/QML">here</a>.</em></p>
<h3>Make your applications work in the cloud with Ubuntu One</h3>
<p><em>By <a title="LaunchpadHome" href="https://launchpad.net/%7Esil">Stuart Langridge</a></em></p>
<p>Stuart gave a great overview on how to add the cloud to existing apps and how to make new apps for the cloud, letting Ubuntu One do all the hard work for you: from managing identities, password renewal to sharing data between applications. And all that on the web, the desktop, mobile&#8230; all your stuff everywhere! He then showed us some simple code to sync playlists on the cloud, ready for streaming. File sync is also an important Ubuntu One feature apps can make use of for sharing, and he also went through a couple of the many cool ways you can use it. The last mention was on API documentation, something Stuart is working on in this cycle.</p>
<p><em>Check out the session log <a href="https://wiki.ubuntu.com/MeetingLogs/appdevweek1104/UbuntuOneCloudApps">here</a>.</em></p>
<h3>Take control of your desktop easily with DBus</h3>
<p><em>By <a title="LaunchpadHome" href="https://launchpad.net/%7Ealecu">Alejandro J. Cura</a></em></p>
<p>In this session Alejandro showed us in a hands-on and easy to follow way different bits and pieces of D-Bus, and how applications in the desktop can communicate through it. He went through real life examples to show how to do simple tasks and explained how they can be achieved with D-Bus.<em></em></p>
<p><em>Check out the session log <a href="https://wiki.ubuntu.com/MeetingLogs/appdevweek1104/DBus">here</a>.</em></p>
<h3>Touchégg: Bringing Multitouch Gestures to your Desktop</h3>
<p>In the second multitouch session of the week, app developer José Expósito started showcasing Touchégg, how it works and its features: recognizing multitouch gestures and getting the most of multitouch devices. He then went on describing which gestures it supports, such as tap, drag, pinch or tap &amp; hold, and the different actions that can be associated to gestures, showing us a really <a href="http://www.youtube.com/watch?v=1Ek4QaFQ1qo">cool video of Touchégg in action</a>. The second part of the talk focused on describing the technologies used to develop Touchégg: uTouch-GEIS, through its simplified interface, and Qt.</p>
<p><em>By <a title="LaunchpadHome" href="https://launchpad.net/%7Ejose-exposito89">José Expósito</a></em></p>
<p><em>Check out the session log <a href="https://wiki.ubuntu.com/MeetingLogs/appdevweek1104/Touchegg">here</a>.</em></p>
<h3>Unity: Integrating with Launcher and Places</h3>
<p><em>By <a title="LaunchpadHome" href="https://launchpad.net/%7Ekamstrup">Mikkel Kamstrup Erlandsen</a></em></p>
<p>Mikkel used the intro of the talk to set a couple of things straight: &#8220;Places&#8221; are going to be called &#8220;Lenses&#8221; in the next cycle, and libunity does not yet guarantee API or ABI stability. He then followed with the Unity Launcher integration, and how applications can use static quicklists, and more advanced features such as count, progress bar, window flashing and dynamic quicklists. The second part were Places: remote databases that provide data for Unity to render. Through a Python code example he showed us in detail all the aspects of creating a Unity Place.<em></em></p>
<p><em>Check out the session log <a href="https://wiki.ubuntu.com/MeetingLogs/appdevweek1104/UnityAPI">here</a>.</em></p>
<h3>Tracking Source Code History with Bazaar</h3>
<p><em>By <a title="LaunchpadHome" href="https://launchpad.net/%7Ejelmer">Jelmer Vernooij</a></em></p>
<p>Jelmer, in his experience of seasoned Bazaar hacker started off introducing what bzr is: a modern distributed version control system. He then went on with the basics with a hands-on example, going through the creation of a branch, the first commit, and describing several of the most handy bzr commands. As a wrap-up, he showcased more advanced features such as source recipes: scripts that combine branches and build daily Debian packages from them.<em></em></p>
<p><em>Check out the session log <a href="https://wiki.ubuntu.com/MeetingLogs/appdevweek1104/Bazaar">here</a>.</em></p>
<h2>The Day Ahead: Upcoming Sessions for Day 4</h2>
<p>We&#8217;re featuring a Qt Quick Marathon today: 2 sessions in a row. Following that, how to do RAD with yet another framework: Quickly, how to get your applications in Ubuntu, and how to get them translated in Launchpad. Enjoy!</p>
<p><a href="http://www.timeanddate.com/worldclock/fixedtime.html?month=4&day=14&year=2011&hour=16&min=0&sec=0&p1=0">16:00 UTC</a><br />
<strong>Qt Quick: Elements/Animations/States</strong> &#8211; Jürgen Bocklage-Ryannel<br />
Another day and more featured Qt content: this time Jürgen will take us through different elements/animations and states Qt Quick provides, and will show us through examples how to make use of them.</p>
<p><a href="http://www.timeanddate.com/worldclock/fixedtime.html?month=4&day=14&year=2011&hour=17&min=0&sec=0&p1=0">17:00 UTC</a><br />
<strong>Qt Quick: Rapid Prototyping</strong> &#8211; Jürgen Bocklage-Ryannel<br />
If one session weren&#8217;t enough, here&#8217;s the continuation: more Qt goodness, this time a hands-on session to develop a small application from start to finish and experience the whole process from the front row.</p>
<p><a href="http://www.timeanddate.com/worldclock/fixedtime.html?month=4&day=14&year=2011&hour=18&min=0&sec=0&p1=0">18:00 UTC</a><br />
<strong>Rapid App Development with Quickly</strong> &#8211; <a title="LaunchpadHome" href="https://launchpad.net/%7Emterry">Michael Terry</a><br />
Mike will show you how to write applications in no time with the power of Python and Quickly: bringing back the fun in programming.</p>
<p><a href="http://www.timeanddate.com/worldclock/fixedtime.html?month=4&day=14&year=2011&hour=19&min=0&sec=0&p1=0">19:00 UTC</a><br />
<strong>Getting Your App in the Distro: the Application Review Process</strong> &#8211; <a title="LaunchpadHome" href="https://launchpad.net/%7Eallison">Allison Randal</a><br />
A while back we created an easy process defining how to get applications into Ubuntu, so in order to be able to add them in a matter of weeks, rather than waiting for the next release. Allison, in her Ubuntu Technical Architect and Application Review Board member hat, will walk you through the <a href="https://wiki.ubuntu.com/PostReleaseApps/Process">Application Review Process</a></p>
<p><a href="http://www.timeanddate.com/worldclock/fixedtime.html?month=4&day=14&year=2011&hour=20&min=0&sec=0&p1=0">20:00 UTC</a><br />
<strong>Adding Indicator Support to your Apps</strong> &#8211; <a title="LaunchpadHome" href="https://launchpad.net/%7Eted">Ted Gould</a><br />
Join the man who knows most about indicators in a session that will teach you how to integrate your application even more into Ubuntu. They&#8217;re slick, robust and consistent: bringing indicator support to your apps.</p>
<p><a href="http://www.timeanddate.com/worldclock/fixedtime.html?month=4&day=14&year=2011&hour=21&min=0&sec=0&p1=0">21:00 UTC</a><br />
<strong>Using Launchpad to get your application translated</strong> &#8211; <a title="LaunchpadHome" href="https://launchpad.net/%7Ehenninge">Henning Eggers</a><br />
One of the coolest features of Launchpad is that it helps growing a translation community around your project. You can make your application translatable in Launchpad and be able to deliver it into almost any language. Henning will teach you how to do this, picking up where the <a href="http://davidplanella.wordpress.com/2011/04/12/off-to-a-great-start-ubuntu-app-developer-week-day-1/">previous session on translations</a> left.</p>
<p>Looking forward to seeing you all there!</p>
<p><a href="http://webchat.freenode.net/?channels=ubuntu-classroom"><img class="aligncenter" title="Join Ubuntu App Developer Week" src="http://davidplanella.files.wordpress.com/2011/04/rect3827.png?w=154&h=42" alt="" width="154" height="42" /></a></p>
<br /> <a rel="nofollow" href="http://feeds.wordpress.com/1.0/gocomments/davidplanella.wordpress.com/1091/"><img alt="" border="0" src="http://feeds.wordpress.com/1.0/comments/davidplanella.wordpress.com/1091/" /></a> <a rel="nofollow" href="http://feeds.wordpress.com/1.0/godelicious/davidplanella.wordpress.com/1091/"><img alt="" border="0" src="http://feeds.wordpress.com/1.0/delicious/davidplanella.wordpress.com/1091/" /></a> <a rel="nofollow" href="http://feeds.wordpress.com/1.0/gofacebook/davidplanella.wordpress.com/1091/"><img alt="" border="0" src="http://feeds.wordpress.com/1.0/facebook/davidplanella.wordpress.com/1091/" /></a> <a rel="nofollow" href="http://feeds.wordpress.com/1.0/gotwitter/davidplanella.wordpress.com/1091/"><img alt="" border="0" src="http://feeds.wordpress.com/1.0/twitter/davidplanella.wordpress.com/1091/" /></a> <a rel="nofollow" href="http://feeds.wordpress.com/1.0/gostumble/davidplanella.wordpress.com/1091/"><img alt="" border="0" src="http://feeds.wordpress.com/1.0/stumble/davidplanella.wordpress.com/1091/" /></a> <a rel="nofollow" href="http://feeds.wordpress.com/1.0/godigg/davidplanella.wordpress.com/1091/"><img alt="" border="0" src="http://feeds.wordpress.com/1.0/digg/davidplanella.wordpress.com/1091/" /></a> <a rel="nofollow" href="http://feeds.wordpress.com/1.0/goreddit/davidplanella.wordpress.com/1091/"><img alt="" border="0" src="http://feeds.wordpress.com/1.0/reddit/davidplanella.wordpress.com/1091/" /></a> <img alt="" border="0" src="http://stats.wordpress.com/b.gif?host=davidplanella.wordpress.com&blog=1814603&post=1091&subd=davidplanella&ref=&feed=1" width="1" height="1" />Martin Albisetti: Ubuntu, Natty and Unity2011-03-07T22:21:57Zbeunonospam@nospam.comhttp://beuno.com.ar/archives/241<p>I have to confess, after I heard I found out we where shipping Unity in Ubuntu by default I was nervous. I got asked many times what my feelings were, and I think I generally dodged the question. This was a pretty risky move, which we are still a few months away from finding out how well the risk pays off.<br />
Given that a lot of the design behind Unity wasn't done in the open and hadn't had a long time to mature, I've been sceptical of whether we (as in, the Ubuntu project) could pull of such a massive change in a such a short period of time, and still have happy users.</p>
<p>I've been using Unity on and off on my netbook (which is my secondary computer), but while enjoying a long weekend I've spent the last few days using it a lot, and my feeling towards the it have changed quite a bit.</p>
<p>I think it was the right decision. Overall, it feels like an overall improved experience, even with its current rough edges. Exactly what I think we need to win over a wider audience and have them fall in love with Ubuntu head over heels. Everything is starting to feel much more tightly integrated and with a purpose, as well as some eye-candy sprinkled in a lot of the right places.<br />
I'm really glad Canonical decided to invest to heavily in such a risky and insanely complicated task, Natty is probably one of the most exciting releases I can remember.</p>
<p>There are still a few key challenges ahead, most notably to me is making the design process more open and inclusive, but still being able to deliver something that feels polished and not a pile of consensus between people who have gotten good at arguing. The Ayatana community does seem to be slowly growing, though, so the future looks pretty bright. Getting the right balance between Canonical and a community around design feels like one of the hardest problems to solve, luckily, Canonical continues to hire the brightest and most enthusiastic minds around, so I'm sure it will eventually feel like a solved problem.</p>
<p>I think it's been almost 6 years since I landed in the Ubuntu world, I've done all kinds of things in the community ranging from starting and building the Argentine LoCo to editing the Ubuntu Weekly Newsletter, to evaluating new Ubuntu members in the Americas region. With its ups and down, great press and wild controversies, it still feels like the best place to be.</p>Manuel de la Pena: Pykeyring2011-03-02T10:44:45Zmandelnospam@nospam.comhttp://www.themacaque.com/?p=811<p>For those that do not what is the keyring module here is the official description:</p>
<blockquote><p>The Python keyring lib provides a easy way to access the system keyring service from python. It can be used in any application that needs safe password storage.</p></blockquote>
<p>The module is a very nice idea and has been rather useful during the Ubuntu One port. I just have a problem with it which is the lack of a method to delete a password.</p>
<p>I have forked the project in <a href="http://bitbucket.org/mandel/pykeyring-delete-password">bitbucket</a> and added the missing methods. Of course I have requested a pull from the original project, so unless there are problems the new code should be &#8216;landable&#8217; (is landable even a word?) in trunk and usable.</p>
<p>For those that cannot wait for that, you can grab the code by doing:</p>
<div class="wp_syntax"><div class="code"><pre class="sh">hg clone https://bitbucket.org/mandel/pykeyring-delete-password</pre></div></div>Manuel de la Pena: A look alike pyinotify for Windows2011-01-28T10:56:02Zmandelnospam@nospam.comhttp://www.themacaque.com/?p=803<blockquote><p>Before I introduce the code, let me say that this is not a 100% exact implementation of the interfaces that can be found in pyinotify but the implementation of a subset that matches my needs. The main idea of creating this post is to give an example of the implementation of such a library for Windows trying to reuse the code that can be found in pyinotify.</p></blockquote>
<p>Once I have excused my self, let get into the code. First of all, there are a number of classes from pyinotify that we can use in our code. That subset of classes is the below code which I grabbed from pyinotify git:</p>
<div class="wp_syntax"><div class="code"><pre class="python"><span>#!/usr/bin/env python</span>
&nbsp;
<span># pyinotify.py - python interface to inotify</span>
<span># Copyright (c) 2010 Sebastien Martini &lt;seb@dbzteam.org&gt;</span>
<span>#</span>
<span># Permission is hereby granted, free of charge, to any person obtaining a copy</span>
<span># of this software and associated documentation files (the &quot;Software&quot;), to deal</span>
<span># in the Software without restriction, including without limitation the rights</span>
<span># to use, copy, modify, merge, publish, distribute, sublicense, and/or sell</span>
<span># copies of the Software, and to permit persons to whom the Software is</span>
<span># furnished to do so, subject to the following conditions:</span>
<span>#</span>
<span># The above copyright notice and this permission notice shall be included in</span>
<span># all copies or substantial portions of the Software.</span>
<span>#</span>
<span># THE SOFTWARE IS PROVIDED &quot;AS IS&quot;, WITHOUT WARRANTY OF ANY KIND, EXPRESS OR</span>
<span># IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,</span>
<span># FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE</span>
<span># AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER</span>
<span># LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,</span>
<span># OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN</span>
<span># THE SOFTWARE.</span>
<span>&quot;&quot;&quot;Platform agnostic code grabed from pyinotify.&quot;&quot;&quot;</span>
<span>import</span> <span>logging</span>
<span>import</span> <span>os</span>
&nbsp;
COMPATIBILITY_MODE = <span>False</span>
&nbsp;
&nbsp;
<span>class</span> RawOutputFormat:
<span>&quot;&quot;&quot;
Format string representations.
&quot;&quot;&quot;</span>
<span>def</span> <span>__init__</span><span>&#40;</span><span>self</span>, format=<span>None</span><span>&#41;</span>:
<span>self</span>.<span>format</span> = format <span>or</span> <span>&#123;</span><span>&#125;</span>
&nbsp;
<span>def</span> simple<span>&#40;</span><span>self</span>, s, attribute<span>&#41;</span>:
<span>if</span> <span>not</span> <span>isinstance</span><span>&#40;</span>s, <span>str</span><span>&#41;</span>:
s = <span>str</span><span>&#40;</span>s<span>&#41;</span>
<span>return</span> <span>&#40;</span><span>self</span>.<span>format</span>.<span>get</span><span>&#40;</span>attribute, <span>''</span><span>&#41;</span> + s +
<span>self</span>.<span>format</span>.<span>get</span><span>&#40;</span><span>'normal'</span>, <span>''</span><span>&#41;</span><span>&#41;</span>
&nbsp;
<span>def</span> punctuation<span>&#40;</span><span>self</span>, s<span>&#41;</span>:
<span>&quot;&quot;&quot;Punctuation color.&quot;&quot;&quot;</span>
<span>return</span> <span>self</span>.<span>simple</span><span>&#40;</span>s, <span>'normal'</span><span>&#41;</span>
&nbsp;
<span>def</span> field_value<span>&#40;</span><span>self</span>, s<span>&#41;</span>:
<span>&quot;&quot;&quot;Field value color.&quot;&quot;&quot;</span>
<span>return</span> <span>self</span>.<span>simple</span><span>&#40;</span>s, <span>'purple'</span><span>&#41;</span>
&nbsp;
<span>def</span> field_name<span>&#40;</span><span>self</span>, s<span>&#41;</span>:
<span>&quot;&quot;&quot;Field name color.&quot;&quot;&quot;</span>
<span>return</span> <span>self</span>.<span>simple</span><span>&#40;</span>s, <span>'blue'</span><span>&#41;</span>
&nbsp;
<span>def</span> class_name<span>&#40;</span><span>self</span>, s<span>&#41;</span>:
<span>&quot;&quot;&quot;Class name color.&quot;&quot;&quot;</span>
<span>return</span> <span>self</span>.<span>format</span>.<span>get</span><span>&#40;</span><span>'red'</span>, <span>''</span><span>&#41;</span> + <span>self</span>.<span>simple</span><span>&#40;</span>s, <span>'bold'</span><span>&#41;</span>
&nbsp;
output_format = RawOutputFormat<span>&#40;</span><span>&#41;</span>
&nbsp;
&nbsp;
<span>class</span> EventsCodes:
<span>&quot;&quot;&quot;
Set of codes corresponding to each kind of events.
Some of these flags are used to communicate with inotify, whereas
the others are sent to userspace by inotify notifying some events.
&nbsp;
@cvar IN_ACCESS: File was accessed.
@type IN_ACCESS: int
@cvar IN_MODIFY: File was modified.
@type IN_MODIFY: int
@cvar IN_ATTRIB: Metadata changed.
@type IN_ATTRIB: int
@cvar IN_CLOSE_WRITE: Writtable file was closed.
@type IN_CLOSE_WRITE: int
@cvar IN_CLOSE_NOWRITE: Unwrittable file closed.
@type IN_CLOSE_NOWRITE: int
@cvar IN_OPEN: File was opened.
@type IN_OPEN: int
@cvar IN_MOVED_FROM: File was moved from X.
@type IN_MOVED_FROM: int
@cvar IN_MOVED_TO: File was moved to Y.
@type IN_MOVED_TO: int
@cvar IN_CREATE: Subfile was created.
@type IN_CREATE: int
@cvar IN_DELETE: Subfile was deleted.
@type IN_DELETE: int
@cvar IN_DELETE_SELF: Self (watched item itself) was deleted.
@type IN_DELETE_SELF: int
@cvar IN_MOVE_SELF: Self (watched item itself) was moved.
@type IN_MOVE_SELF: int
@cvar IN_UNMOUNT: Backing fs was unmounted.
@type IN_UNMOUNT: int
@cvar IN_Q_OVERFLOW: Event queued overflowed.
@type IN_Q_OVERFLOW: int
@cvar IN_IGNORED: File was ignored.
@type IN_IGNORED: int
@cvar IN_ONLYDIR: only watch the path if it is a directory (new
in kernel 2.6.15).
@type IN_ONLYDIR: int
@cvar IN_DONT_FOLLOW: don't follow a symlink (new in kernel 2.6.15).
IN_ONLYDIR we can make sure that we don't watch
the target of symlinks.
@type IN_DONT_FOLLOW: int
@cvar IN_MASK_ADD: add to the mask of an already existing watch (new
in kernel 2.6.14).
@type IN_MASK_ADD: int
@cvar IN_ISDIR: Event occurred against dir.
@type IN_ISDIR: int
@cvar IN_ONESHOT: Only send event once.
@type IN_ONESHOT: int
@cvar ALL_EVENTS: Alias for considering all of the events.
@type ALL_EVENTS: int
&quot;&quot;&quot;</span>
&nbsp;
<span># The idea here is 'configuration-as-code' - this way, we get</span>
<span># our nice class constants, but we also get nice human-friendly text</span>
<span># mappings to do lookups against as well, for free:</span>
FLAG_COLLECTIONS = <span>&#123;</span><span>'OP_FLAGS'</span>: <span>&#123;</span>
<span>'IN_ACCESS'</span> : 0x00000001, <span># File was accessed</span>
<span>'IN_MODIFY'</span> : 0x00000002, <span># File was modified</span>
<span>'IN_ATTRIB'</span> : 0x00000004, <span># Metadata changed</span>
<span>'IN_CLOSE_WRITE'</span> : 0x00000008, <span># Writable file was closed</span>
<span>'IN_CLOSE_NOWRITE'</span> : 0x00000010, <span># Unwritable file closed</span>
<span>'IN_OPEN'</span> : 0x00000020, <span># File was opened</span>
<span>'IN_MOVED_FROM'</span> : 0x00000040, <span># File was moved from X</span>
<span>'IN_MOVED_TO'</span> : 0x00000080, <span># File was moved to Y</span>
<span>'IN_CREATE'</span> : 0x00000100, <span># Subfile was created</span>
<span>'IN_DELETE'</span> : 0x00000200, <span># Subfile was deleted</span>
<span>'IN_DELETE_SELF'</span> : 0x00000400, <span># Self (watched item itself)</span>
<span># was deleted</span>
<span>'IN_MOVE_SELF'</span> : 0x00000800, <span># Self(watched item itself) was moved</span>
<span>&#125;</span>,
<span>'EVENT_FLAGS'</span>: <span>&#123;</span>
<span>'IN_UNMOUNT'</span> : 0x00002000, <span># Backing fs was unmounted</span>
<span>'IN_Q_OVERFLOW'</span> : 0x00004000, <span># Event queued overflowed</span>
<span>'IN_IGNORED'</span> : 0x00008000, <span># File was ignored</span>
<span>&#125;</span>,
<span>'SPECIAL_FLAGS'</span>: <span>&#123;</span>
<span>'IN_ONLYDIR'</span> : 0x01000000, <span># only watch the path if it is a</span>
<span># directory</span>
<span>'IN_DONT_FOLLOW'</span> : 0x02000000, <span># don't follow a symlink</span>
<span>'IN_MASK_ADD'</span> : 0x20000000, <span># add to the mask of an already</span>
<span># existing watch</span>
<span>'IN_ISDIR'</span> : 0x40000000, <span># event occurred against dir</span>
<span>'IN_ONESHOT'</span> : 0x80000000, <span># only send event once</span>
<span>&#125;</span>,
<span>&#125;</span>
&nbsp;
<span>def</span> maskname<span>&#40;</span>mask<span>&#41;</span>:
<span>&quot;&quot;&quot;
Returns the event name associated to mask. IN_ISDIR is appended to
the result when appropriate. Note: only one event is returned, because
only one event can be raised at a given time.
&nbsp;
@param mask: mask.
@type mask: int
@return: event name.
@rtype: str
&quot;&quot;&quot;</span>
ms = mask
name = <span>'%s'</span>
<span>if</span> mask <span>&amp;</span> IN_ISDIR:
ms = mask - IN_ISDIR
name = <span>'%s|IN_ISDIR'</span>
<span>return</span> name <span>%</span> EventsCodes.<span>ALL_VALUES</span><span>&#91;</span>ms<span>&#93;</span>
&nbsp;
maskname = <span>staticmethod</span><span>&#40;</span>maskname<span>&#41;</span>
&nbsp;
&nbsp;
<span># So let's now turn the configuration into code</span>
EventsCodes.<span>ALL_FLAGS</span> = <span>&#123;</span><span>&#125;</span>
EventsCodes.<span>ALL_VALUES</span> = <span>&#123;</span><span>&#125;</span>
<span>for</span> flagc, valc <span>in</span> EventsCodes.<span>FLAG_COLLECTIONS</span>.<span>items</span><span>&#40;</span><span>&#41;</span>:
<span># Make the collections' members directly accessible through the</span>
<span># class dictionary</span>
<span>setattr</span><span>&#40;</span>EventsCodes, flagc, valc<span>&#41;</span>
&nbsp;
<span># Collect all the flags under a common umbrella</span>
EventsCodes.<span>ALL_FLAGS</span>.<span>update</span><span>&#40;</span>valc<span>&#41;</span>
&nbsp;
<span># Make the individual masks accessible as 'constants' at globals() scope</span>
<span># and masknames accessible by values.</span>
<span>for</span> name, val <span>in</span> valc.<span>items</span><span>&#40;</span><span>&#41;</span>:
<span>globals</span><span>&#40;</span><span>&#41;</span><span>&#91;</span>name<span>&#93;</span> = val
EventsCodes.<span>ALL_VALUES</span><span>&#91;</span>val<span>&#93;</span> = name
&nbsp;
&nbsp;
<span># all 'normal' events</span>
ALL_EVENTS = <span>reduce</span><span>&#40;</span><span>lambda</span> x, y: x | y, EventsCodes.<span>OP_FLAGS</span>.<span>values</span><span>&#40;</span><span>&#41;</span><span>&#41;</span>
EventsCodes.<span>ALL_FLAGS</span><span>&#91;</span><span>'ALL_EVENTS'</span><span>&#93;</span> = ALL_EVENTS
EventsCodes.<span>ALL_VALUES</span><span>&#91;</span>ALL_EVENTS<span>&#93;</span> = <span>'ALL_EVENTS'</span>
&nbsp;
&nbsp;
<span>class</span> _Event:
<span>&quot;&quot;&quot;
Event structure, represent events raised by the system. This
is the base class and should be subclassed.
&nbsp;
&quot;&quot;&quot;</span>
<span>def</span> <span>__init__</span><span>&#40;</span><span>self</span>, dict_<span>&#41;</span>:
<span>&quot;&quot;&quot;
Attach attributes (contained in dict_) to self.
&nbsp;
@param dict_: Set of attributes.
@type dict_: dictionary
&quot;&quot;&quot;</span>
<span>for</span> tpl <span>in</span> dict_.<span>items</span><span>&#40;</span><span>&#41;</span>:
<span>setattr</span><span>&#40;</span><span>self</span>, <span>*</span>tpl<span>&#41;</span>
&nbsp;
<span>def</span> <span>__repr__</span><span>&#40;</span><span>self</span><span>&#41;</span>:
<span>&quot;&quot;&quot;
@return: Generic event string representation.
@rtype: str
&quot;&quot;&quot;</span>
s = <span>''</span>
<span>for</span> attr, value <span>in</span> <span>sorted</span><span>&#40;</span><span>self</span>.<span>__dict__</span>.<span>items</span><span>&#40;</span><span>&#41;</span>, key=<span>lambda</span> x: x<span>&#91;</span><span>0</span><span>&#93;</span><span>&#41;</span>:
<span>if</span> attr.<span>startswith</span><span>&#40;</span><span>'_'</span><span>&#41;</span>:
<span>continue</span>
<span>if</span> attr == <span>'mask'</span>:
value = <span>hex</span><span>&#40;</span><span>getattr</span><span>&#40;</span><span>self</span>, attr<span>&#41;</span><span>&#41;</span>
<span>elif</span> <span>isinstance</span><span>&#40;</span>value, <span>basestring</span><span>&#41;</span> <span>and</span> <span>not</span> value:
value = <span>&quot;''&quot;</span>
s += <span>' %s%s%s'</span> <span>%</span> <span>&#40;</span>output_format.<span>field_name</span><span>&#40;</span>attr<span>&#41;</span>,
output_format.<span>punctuation</span><span>&#40;</span><span>'='</span><span>&#41;</span>,
output_format.<span>field_value</span><span>&#40;</span>value<span>&#41;</span><span>&#41;</span>
&nbsp;
s = <span>'%s%s%s %s'</span> <span>%</span> <span>&#40;</span>output_format.<span>punctuation</span><span>&#40;</span><span>'&lt;'</span><span>&#41;</span>,
output_format.<span>class_name</span><span>&#40;</span><span>self</span>.__class__.__name__<span>&#41;</span>,
s,
output_format.<span>punctuation</span><span>&#40;</span><span>'&gt;'</span><span>&#41;</span><span>&#41;</span>
<span>return</span> s
&nbsp;
<span>def</span> <span>__str__</span><span>&#40;</span><span>self</span><span>&#41;</span>:
<span>return</span> <span>repr</span><span>&#40;</span><span>self</span><span>&#41;</span>
&nbsp;
&nbsp;
<span>class</span> _RawEvent<span>&#40;</span>_Event<span>&#41;</span>:
<span>&quot;&quot;&quot;
Raw event, it contains only the informations provided by the system.
It doesn't infer anything.
&quot;&quot;&quot;</span>
<span>def</span> <span>__init__</span><span>&#40;</span><span>self</span>, wd, mask, cookie, name<span>&#41;</span>:
<span>&quot;&quot;&quot;
@param wd: Watch Descriptor.
@type wd: int
@param mask: Bitmask of events.
@type mask: int
@param cookie: Cookie.
@type cookie: int
@param name: Basename of the file or directory against which the
event was raised in case where the watched directory
is the parent directory. None if the event was raised
on the watched item itself.
@type name: string or None
&quot;&quot;&quot;</span>
<span># Use this variable to cache the result of str(self), this object</span>
<span># is immutable.</span>
<span>self</span>._str = <span>None</span>
<span># name: remove trailing '\0'</span>
d = <span>&#123;</span><span>'wd'</span>: wd,
<span>'mask'</span>: mask,
<span>'cookie'</span>: cookie,
<span>'name'</span>: name.<span>rstrip</span><span>&#40;</span><span>'<span>\0</span>'</span><span>&#41;</span><span>&#125;</span>
_Event.<span>__init__</span><span>&#40;</span><span>self</span>, d<span>&#41;</span>
<span>logging</span>.<span>debug</span><span>&#40;</span><span>str</span><span>&#40;</span><span>self</span><span>&#41;</span><span>&#41;</span>
&nbsp;
<span>def</span> <span>__str__</span><span>&#40;</span><span>self</span><span>&#41;</span>:
<span>if</span> <span>self</span>._str <span>is</span> <span>None</span>:
<span>self</span>._str = _Event.<span>__str__</span><span>&#40;</span><span>self</span><span>&#41;</span>
<span>return</span> <span>self</span>._str
&nbsp;
&nbsp;
<span>class</span> Event<span>&#40;</span>_Event<span>&#41;</span>:
<span>&quot;&quot;&quot;
This class contains all the useful informations about the observed
event. However, the presence of each field is not guaranteed and
depends on the type of event. In effect, some fields are irrelevant
for some kind of event (for example 'cookie' is meaningless for
IN_CREATE whereas it is mandatory for IN_MOVE_TO).
&nbsp;
The possible fields are:
- wd (int): Watch Descriptor.
- mask (int): Mask.
- maskname (str): Readable event name.
- path (str): path of the file or directory being watched.
- name (str): Basename of the file or directory against which the
event was raised in case where the watched directory
is the parent directory. None if the event was raised
on the watched item itself. This field is always provided
even if the string is ''.
- pathname (str): Concatenation of 'path' and 'name'.
- src_pathname (str): Only present for IN_MOVED_TO events and only in
the case where IN_MOVED_FROM events are watched too. Holds the
source pathname from where pathname was moved from.
- cookie (int): Cookie.
- dir (bool): True if the event was raised against a directory.
&nbsp;
&quot;&quot;&quot;</span>
<span>def</span> <span>__init__</span><span>&#40;</span><span>self</span>, raw<span>&#41;</span>:
<span>&quot;&quot;&quot;
Concretely, this is the raw event plus inferred infos.
&quot;&quot;&quot;</span>
_Event.<span>__init__</span><span>&#40;</span><span>self</span>, raw<span>&#41;</span>
<span>self</span>.<span>maskname</span> = EventsCodes.<span>maskname</span><span>&#40;</span><span>self</span>.<span>mask</span><span>&#41;</span>
<span>if</span> COMPATIBILITY_MODE:
<span>self</span>.<span>event_name</span> = <span>self</span>.<span>maskname</span>
<span>try</span>:
<span>if</span> <span>self</span>.<span>name</span>:
<span>self</span>.<span>pathname</span> = <span>os</span>.<span>path</span>.<span>abspath</span><span>&#40;</span><span>os</span>.<span>path</span>.<span>join</span><span>&#40;</span><span>self</span>.<span>path</span>,
<span>self</span>.<span>name</span><span>&#41;</span><span>&#41;</span>
<span>else</span>:
<span>self</span>.<span>pathname</span> = <span>os</span>.<span>path</span>.<span>abspath</span><span>&#40;</span><span>self</span>.<span>path</span><span>&#41;</span>
<span>except</span> <span>AttributeError</span>, err:
<span># Usually it is not an error some events are perfectly valids</span>
<span># despite the lack of these attributes.</span>
<span>logging</span>.<span>debug</span><span>&#40;</span>err<span>&#41;</span>
&nbsp;
&nbsp;
<span>class</span> _ProcessEvent:
<span>&quot;&quot;&quot;
Abstract processing event class.
&quot;&quot;&quot;</span>
<span>def</span> <span>__call__</span><span>&#40;</span><span>self</span>, event<span>&#41;</span>:
<span>&quot;&quot;&quot;
To behave like a functor the object must be callable.
This method is a dispatch method. Its lookup order is:
1. process_MASKNAME method
2. process_FAMILY_NAME method
3. otherwise calls process_default
&nbsp;
@param event: Event to be processed.
@type event: Event object
@return: By convention when used from the ProcessEvent class:
- Returning False or None (default value) means keep on
executing next chained functors (see chain.py example).
- Returning True instead means do not execute next
processing functions.
@rtype: bool
@raise ProcessEventError: Event object undispatchable,
unknown event.
&quot;&quot;&quot;</span>
stripped_mask = event.<span>mask</span> - <span>&#40;</span>event.<span>mask</span> <span>&amp;</span> IN_ISDIR<span>&#41;</span>
maskname = EventsCodes.<span>ALL_VALUES</span>.<span>get</span><span>&#40;</span>stripped_mask<span>&#41;</span>
<span>if</span> maskname <span>is</span> <span>None</span>:
<span>raise</span> ProcessEventError<span>&#40;</span><span>&quot;Unknown mask 0x%08x&quot;</span> <span>%</span> stripped_mask<span>&#41;</span>
&nbsp;
<span># 1- look for process_MASKNAME</span>
meth = <span>getattr</span><span>&#40;</span><span>self</span>, <span>'process_'</span> + maskname, <span>None</span><span>&#41;</span>
<span>if</span> meth <span>is</span> <span>not</span> <span>None</span>:
<span>return</span> meth<span>&#40;</span>event<span>&#41;</span>
<span># 2- look for process_FAMILY_NAME</span>
meth = <span>getattr</span><span>&#40;</span><span>self</span>, <span>'process_IN_'</span> + maskname.<span>split</span><span>&#40;</span><span>'_'</span><span>&#41;</span><span>&#91;</span><span>1</span><span>&#93;</span>, <span>None</span><span>&#41;</span>
<span>if</span> meth <span>is</span> <span>not</span> <span>None</span>:
<span>return</span> meth<span>&#40;</span>event<span>&#41;</span>
<span># 3- default call method process_default</span>
<span>return</span> <span>self</span>.<span>process_default</span><span>&#40;</span>event<span>&#41;</span>
&nbsp;
<span>def</span> <span>__repr__</span><span>&#40;</span><span>self</span><span>&#41;</span>:
<span>return</span> <span>'&lt;%s&gt;'</span> <span>%</span> <span>self</span>.__class__.__name__
&nbsp;
&nbsp;
<span>class</span> ProcessEvent<span>&#40;</span>_ProcessEvent<span>&#41;</span>:
<span>&quot;&quot;&quot;
Process events objects, can be specialized via subclassing, thus its
behavior can be overriden:
&nbsp;
Note: you should not override __init__ in your subclass instead define
a my_init() method, this method will be called automatically from the
constructor of this class with its optionals parameters.
&nbsp;
1. Provide specialized individual methods, e.g. process_IN_DELETE for
processing a precise type of event (e.g. IN_DELETE in this case).
2. Or/and provide methods for processing events by 'family', e.g.
process_IN_CLOSE method will process both IN_CLOSE_WRITE and
IN_CLOSE_NOWRITE events (if process_IN_CLOSE_WRITE and
process_IN_CLOSE_NOWRITE aren't defined though).
3. Or/and override process_default for catching and processing all
the remaining types of events.
&quot;&quot;&quot;</span>
pevent = <span>None</span>
&nbsp;
<span>def</span> <span>__init__</span><span>&#40;</span><span>self</span>, pevent=<span>None</span>, <span>**</span>kargs<span>&#41;</span>:
<span>&quot;&quot;&quot;
Enable chaining of ProcessEvent instances.
&nbsp;
@param pevent: Optional callable object, will be called on event
processing (before self).
@type pevent: callable
@param kargs: This constructor is implemented as a template method
delegating its optionals keyworded arguments to the
method my_init().
@type kargs: dict
&quot;&quot;&quot;</span>
<span>self</span>.<span>pevent</span> = pevent
<span>self</span>.<span>my_init</span><span>&#40;</span><span>**</span>kargs<span>&#41;</span>
&nbsp;
<span>def</span> my_init<span>&#40;</span><span>self</span>, <span>**</span>kargs<span>&#41;</span>:
<span>&quot;&quot;&quot;
This method is called from ProcessEvent.__init__(). This method is
empty here and must be redefined to be useful. In effect, if you
need to specifically initialize your subclass' instance then you
just have to override this method in your subclass. Then all the
keyworded arguments passed to ProcessEvent.__init__() will be
transmitted as parameters to this method. Beware you MUST pass
keyword arguments though.
&nbsp;
@param kargs: optional delegated arguments from __init__().
@type kargs: dict
&quot;&quot;&quot;</span>
<span>pass</span>
&nbsp;
<span>def</span> <span>__call__</span><span>&#40;</span><span>self</span>, event<span>&#41;</span>:
stop_chaining = <span>False</span>
<span>if</span> <span>self</span>.<span>pevent</span> <span>is</span> <span>not</span> <span>None</span>:
<span># By default methods return None so we set as guideline</span>
<span># that methods asking for stop chaining must explicitely</span>
<span># return non None or non False values, otherwise the default</span>
<span># behavior will be to accept chain call to the corresponding</span>
<span># local method.</span>
stop_chaining = <span>self</span>.<span>pevent</span><span>&#40;</span>event<span>&#41;</span>
<span>if</span> <span>not</span> stop_chaining:
<span>return</span> _ProcessEvent.<span>__call__</span><span>&#40;</span><span>self</span>, event<span>&#41;</span>
&nbsp;
<span>def</span> nested_pevent<span>&#40;</span><span>self</span><span>&#41;</span>:
<span>return</span> <span>self</span>.<span>pevent</span>
&nbsp;
<span>def</span> process_IN_Q_OVERFLOW<span>&#40;</span><span>self</span>, event<span>&#41;</span>:
<span>&quot;&quot;&quot;
By default this method only reports warning messages, you can
overredide it by subclassing ProcessEvent and implement your own
process_IN_Q_OVERFLOW method. The actions you can take on receiving
this event is either to update the variable max_queued_events in order
to handle more simultaneous events or to modify your code in order to
accomplish a better filtering diminishing the number of raised events.
Because this method is defined, IN_Q_OVERFLOW will never get
transmitted as arguments to process_default calls.
&nbsp;
@param event: IN_Q_OVERFLOW event.
@type event: dict
&quot;&quot;&quot;</span>
log.<span>warning</span><span>&#40;</span><span>'Event queue overflowed.'</span><span>&#41;</span>
&nbsp;
<span>def</span> process_default<span>&#40;</span><span>self</span>, event<span>&#41;</span>:
<span>&quot;&quot;&quot;
Default processing event method. By default does nothing. Subclass
ProcessEvent and redefine this method in order to modify its behavior.
&nbsp;
@param event: Event to be processed. Can be of any type of events but
IN_Q_OVERFLOW events (see method process_IN_Q_OVERFLOW).
@type event: Event instance
&quot;&quot;&quot;</span>
<span>pass</span>
&nbsp;
&nbsp;
<span>class</span> PrintAllEvents<span>&#40;</span>ProcessEvent<span>&#41;</span>:
<span>&quot;&quot;&quot;
Dummy class used to print events strings representations. For instance this
class is used from command line to print all received events to stdout.
&quot;&quot;&quot;</span>
<span>def</span> my_init<span>&#40;</span><span>self</span>, out=<span>None</span><span>&#41;</span>:
<span>&quot;&quot;&quot;
@param out: Where events will be written.
@type out: Object providing a valid file object interface.
&quot;&quot;&quot;</span>
<span>if</span> out <span>is</span> <span>None</span>:
out = <span>sys</span>.<span>stdout</span>
<span>self</span>._out = out
&nbsp;
<span>def</span> process_default<span>&#40;</span><span>self</span>, event<span>&#41;</span>:
<span>&quot;&quot;&quot;
Writes event string representation to file object provided to
my_init().
&nbsp;
@param event: Event to be processed. Can be of any type of events but
IN_Q_OVERFLOW events (see method process_IN_Q_OVERFLOW).
@type event: Event instance
&quot;&quot;&quot;</span>
<span>self</span>._out.<span>write</span><span>&#40;</span><span>str</span><span>&#40;</span>event<span>&#41;</span><span>&#41;</span>
<span>self</span>._out.<span>write</span><span>&#40;</span><span>'<span>\n</span>'</span><span>&#41;</span>
<span>self</span>._out.<span>flush</span><span>&#40;</span><span>&#41;</span>
&nbsp;
&nbsp;
<span>class</span> WatchManagerError<span>&#40;</span><span>Exception</span><span>&#41;</span>:
<span>&quot;&quot;&quot;
WatchManager Exception. Raised on error encountered on watches
operations.
&nbsp;
&quot;&quot;&quot;</span>
<span>def</span> <span>__init__</span><span>&#40;</span><span>self</span>, msg, wmd<span>&#41;</span>:
<span>&quot;&quot;&quot;
@param msg: Exception string's description.
@type msg: string
@param wmd: This dictionary contains the wd assigned to paths of the
same call for which watches were successfully added.
@type wmd: dict
&quot;&quot;&quot;</span>
<span>self</span>.<span>wmd</span> = wmd
<span>Exception</span>.<span>__init__</span><span>&#40;</span><span>self</span>, msg<span>&#41;</span></pre></div></div>
<p>Unfortunatly we need to implement the code that talks with the Win32 API to be able to retrieve the events in the file system. In my design this is done by the Watch class that looks like this:</p>
<div class="wp_syntax"><div class="code"><pre class="python"><span># Author: Manuel de la Pena &lt;manuel@canonical.com&gt;</span>
<span>#</span>
<span># Copyright 2011 Canonical Ltd.</span>
<span>#</span>
<span># This program is free software: you can redistribute it and/or modify it</span>
<span># under the terms of the GNU General Public License version 3, as published</span>
<span># by the Free Software Foundation.</span>
<span>#</span>
<span># This program is distributed in the hope that it will be useful, but</span>
<span># WITHOUT ANY WARRANTY; without even the implied warranties of</span>
<span># MERCHANTABILITY, SATISFACTORY QUALITY, or FITNESS FOR A PARTICULAR</span>
<span># PURPOSE. See the GNU General Public License for more details.</span>
<span>#</span>
<span># You should have received a copy of the GNU General Public License along</span>
<span># with this program. If not, see &lt;http://www.gnu.org/licenses/&gt;.</span>
<span>&quot;&quot;&quot;File notifications on windows.&quot;&quot;&quot;</span>
&nbsp;
<span>import</span> <span>logging</span>
<span>import</span> <span>os</span>
<span>import</span> <span>re</span>
&nbsp;
<span>import</span> winerror
&nbsp;
<span>from</span> <span>Queue</span> <span>import</span> <span>Queue</span>, Empty
<span>from</span> <span>threading</span> <span>import</span> Thread
<span>from</span> uuid <span>import</span> uuid4
<span>from</span> twisted.<span>internet</span> <span>import</span> task, reactor
<span>from</span> win32con <span>import</span> <span>&#40;</span>
FILE_SHARE_READ,
FILE_SHARE_WRITE,
FILE_FLAG_BACKUP_SEMANTICS,
FILE_NOTIFY_CHANGE_FILE_NAME,
FILE_NOTIFY_CHANGE_DIR_NAME,
FILE_NOTIFY_CHANGE_ATTRIBUTES,
FILE_NOTIFY_CHANGE_SIZE,
FILE_NOTIFY_CHANGE_LAST_WRITE,
FILE_NOTIFY_CHANGE_SECURITY,
OPEN_EXISTING
<span>&#41;</span>
<span>from</span> win32file <span>import</span> CreateFile, ReadDirectoryChangesW
<span>from</span> ubuntuone.<span>platform</span>.<span>windows</span>.<span>pyinotify</span> <span>import</span> <span>&#40;</span>
Event,
WatchManagerError,
ProcessEvent,
PrintAllEvents,
IN_OPEN,
IN_CLOSE_NOWRITE,
IN_CLOSE_WRITE,
IN_CREATE,
IN_ISDIR,
IN_DELETE,
IN_MOVED_FROM,
IN_MOVED_TO,
IN_MODIFY,
IN_IGNORED
<span>&#41;</span>
<span>from</span> ubuntuone.<span>syncdaemon</span>.<span>filesystem_notifications</span> <span>import</span> <span>&#40;</span>
GeneralINotifyProcessor
<span>&#41;</span>
<span>from</span> ubuntuone.<span>platform</span>.<span>windows</span>.<span>os_helper</span> <span>import</span> <span>&#40;</span>
LONG_PATH_PREFIX,
abspath,
listdir
<span>&#41;</span>
&nbsp;
<span># constant found in the msdn documentation:</span>
<span># http://msdn.microsoft.com/en-us/library/ff538834(v=vs.85).aspx</span>
FILE_LIST_DIRECTORY = 0x0001
FILE_NOTIFY_CHANGE_LAST_ACCESS = 0x00000020
FILE_NOTIFY_CHANGE_CREATION = 0x00000040
&nbsp;
<span># a map between the few events that we have on windows and those</span>
<span># found in pyinotify</span>
WINDOWS_ACTIONS = <span>&#123;</span>
<span>1</span>: IN_CREATE,
<span>2</span>: IN_DELETE,
<span>3</span>: IN_MODIFY,
<span>4</span>: IN_MOVED_FROM,
<span>5</span>: IN_MOVED_TO
<span>&#125;</span>
&nbsp;
<span># translates quickly the event and it's is_dir state to our standard events</span>
NAME_TRANSLATIONS = <span>&#123;</span>
IN_OPEN: <span>'FS_FILE_OPEN'</span>,
IN_CLOSE_NOWRITE: <span>'FS_FILE_CLOSE_NOWRITE'</span>,
IN_CLOSE_WRITE: <span>'FS_FILE_CLOSE_WRITE'</span>,
IN_CREATE: <span>'FS_FILE_CREATE'</span>,
IN_CREATE | IN_ISDIR: <span>'FS_DIR_CREATE'</span>,
IN_DELETE: <span>'FS_FILE_DELETE'</span>,
IN_DELETE | IN_ISDIR: <span>'FS_DIR_DELETE'</span>,
IN_MOVED_FROM: <span>'FS_FILE_DELETE'</span>,
IN_MOVED_FROM | IN_ISDIR: <span>'FS_DIR_DELETE'</span>,
IN_MOVED_TO: <span>'FS_FILE_CREATE'</span>,
IN_MOVED_TO | IN_ISDIR: <span>'FS_DIR_CREATE'</span>,
<span>&#125;</span>
&nbsp;
<span># the default mask to be used in the watches added by the FilesystemMonitor</span>
<span># class</span>
FILESYSTEM_MONITOR_MASK = FILE_NOTIFY_CHANGE_FILE_NAME | \
FILE_NOTIFY_CHANGE_DIR_NAME | \
FILE_NOTIFY_CHANGE_ATTRIBUTES | \
FILE_NOTIFY_CHANGE_SIZE | \
FILE_NOTIFY_CHANGE_LAST_WRITE | \
FILE_NOTIFY_CHANGE_SECURITY | \
FILE_NOTIFY_CHANGE_LAST_ACCESS
&nbsp;
&nbsp;
<span># The implementation of the code that is provided as the pyinotify</span>
<span># substitute</span>
<span>class</span> Watch<span>&#40;</span><span>object</span><span>&#41;</span>:
<span>&quot;&quot;&quot;Implement the same functions as pyinotify.Watch.&quot;&quot;&quot;</span>
&nbsp;
<span>def</span> <span>__init__</span><span>&#40;</span><span>self</span>, watch_descriptor, path, mask, auto_add,
events_queue=<span>None</span>, exclude_filter=<span>None</span>, proc_fun=<span>None</span><span>&#41;</span>:
<span>super</span><span>&#40;</span>Watch, <span>self</span><span>&#41;</span>.<span>__init__</span><span>&#40;</span><span>&#41;</span>
<span>self</span>.<span>log</span> = <span>logging</span>.<span>getLogger</span><span>&#40;</span><span>'ubuntuone.platform.windows.'</span> +
<span>'filesystem_notifications.Watch'</span><span>&#41;</span>
<span>self</span>._watching = <span>False</span>
<span>self</span>._descriptor = watch_descriptor
<span>self</span>._auto_add = auto_add
<span>self</span>.<span>exclude_filter</span> = <span>None</span>
<span>self</span>._proc_fun = proc_fun
<span>self</span>._cookie = <span>None</span>
<span>self</span>._source_pathname = <span>None</span>
<span># remember the subdirs we have so that when we have a delete we can</span>
<span># check if it was a remove</span>
<span>self</span>._subdirs = <span>&#91;</span><span>&#93;</span>
<span># ensure that we work with an abspath and that we can deal with</span>
<span># long paths over 260 chars.</span>
<span>self</span>._path = <span>os</span>.<span>path</span>.<span>abspath</span><span>&#40;</span>path<span>&#41;</span>
<span>if</span> <span>not</span> <span>self</span>._path.<span>startswith</span><span>&#40;</span>LONG_PATH_PREFIX<span>&#41;</span>:
<span>self</span>._path = LONG_PATH_PREFIX + <span>self</span>._path
<span>self</span>._mask = mask
<span># lets make the q as big as possible</span>
<span>self</span>._raw_events_queue = <span>Queue</span><span>&#40;</span><span>&#41;</span>
<span>if</span> <span>not</span> events_queue:
events_queue = <span>Queue</span><span>&#40;</span><span>&#41;</span>
<span>self</span>.<span>events_queue</span> = events_queue
&nbsp;
<span>def</span> _path_is_dir<span>&#40;</span><span>self</span>, path<span>&#41;</span>:
<span>&quot;&quot;&quot;&quot;Check if the path is a dir and update the local subdir list.&quot;&quot;&quot;</span>
<span>self</span>.<span>log</span>.<span>debug</span><span>&#40;</span><span>'Testing if path &quot;%s&quot; is a dir'</span>, path<span>&#41;</span>
is_dir = <span>False</span>
<span>if</span> <span>os</span>.<span>path</span>.<span>exists</span><span>&#40;</span>path<span>&#41;</span>:
is_dir = <span>os</span>.<span>path</span>.<span>isdir</span><span>&#40;</span>path<span>&#41;</span>
<span>else</span>:
<span>self</span>.<span>log</span>.<span>debug</span><span>&#40;</span><span>'Path &quot;%s&quot; was deleted subdirs are %s.'</span>,
path, <span>self</span>._subdirs<span>&#41;</span>
<span># we removed the path, we look in the internal list</span>
<span>if</span> path <span>in</span> <span>self</span>._subdirs:
is_dir = <span>True</span>
<span>self</span>._subdirs.<span>remove</span><span>&#40;</span>path<span>&#41;</span>
<span>if</span> is_dir:
<span>self</span>.<span>log</span>.<span>debug</span><span>&#40;</span><span>'Adding %s to subdirs %s'</span>, path, <span>self</span>._subdirs<span>&#41;</span>
<span>self</span>._subdirs.<span>append</span><span>&#40;</span>path<span>&#41;</span>
<span>return</span> is_dir
&nbsp;
<span>def</span> _process_events<span>&#40;</span><span>self</span><span>&#41;</span>:
<span>&quot;&quot;&quot;Process the events form the queue.&quot;&quot;&quot;</span>
<span># we transform the events to be the same as the one in pyinotify</span>
<span># and then use the proc_fun</span>
<span>while</span> <span>self</span>._watching <span>or</span> <span>not</span> <span>self</span>._raw_events_queue.<span>empty</span><span>&#40;</span><span>&#41;</span>:
file_name, action = <span>self</span>._raw_events_queue.<span>get</span><span>&#40;</span><span>&#41;</span>
<span># map the windows events to the pyinotify ones, tis is dirty but</span>
<span># makes the multiplatform better, linux was first :P</span>
is_dir = <span>self</span>._path_is_dir<span>&#40;</span>file_name<span>&#41;</span>
<span>if</span> <span>os</span>.<span>path</span>.<span>exists</span><span>&#40;</span>file_name<span>&#41;</span>:
is_dir = <span>os</span>.<span>path</span>.<span>isdir</span><span>&#40;</span>file_name<span>&#41;</span>
<span>else</span>:
<span># we removed the path, we look in the internal list</span>
<span>if</span> file_name <span>in</span> <span>self</span>._subdirs:
is_dir = <span>True</span>
<span>self</span>._subdirs.<span>remove</span><span>&#40;</span>file_name<span>&#41;</span>
<span>if</span> is_dir:
<span>self</span>._subdirs.<span>append</span><span>&#40;</span>file_name<span>&#41;</span>
mask = WINDOWS_ACTIONS<span>&#91;</span>action<span>&#93;</span>
head, tail = <span>os</span>.<span>path</span>.<span>split</span><span>&#40;</span>file_name<span>&#41;</span>
<span>if</span> is_dir:
mask |= IN_ISDIR
event_raw_data = <span>&#123;</span>
<span>'wd'</span>: <span>self</span>._descriptor,
<span>'dir'</span>: is_dir,
<span>'mask'</span>: mask,
<span>'name'</span>: tail,
<span>'path'</span>: head.<span>replace</span><span>&#40;</span><span>self</span>.<span>path</span>, <span>'.'</span><span>&#41;</span>
<span>&#125;</span>
<span># by the way in which the win api fires the events we know for</span>
<span># sure that no move events will be added in the wrong order, this</span>
<span># is kind of hacky, I dont like it too much</span>
<span>if</span> WINDOWS_ACTIONS<span>&#91;</span>action<span>&#93;</span> == IN_MOVED_FROM:
<span>self</span>._cookie = <span>str</span><span>&#40;</span>uuid4<span>&#40;</span><span>&#41;</span><span>&#41;</span>
<span>self</span>._source_pathname = tail
event_raw_data<span>&#91;</span><span>'cookie'</span><span>&#93;</span> = <span>self</span>._cookie
<span>if</span> WINDOWS_ACTIONS<span>&#91;</span>action<span>&#93;</span> == IN_MOVED_TO:
event_raw_data<span>&#91;</span><span>'src_pathname'</span><span>&#93;</span> = <span>self</span>._source_pathname
event_raw_data<span>&#91;</span><span>'cookie'</span><span>&#93;</span> = <span>self</span>._cookie
event = Event<span>&#40;</span>event_raw_data<span>&#41;</span>
<span># FIXME: event deduces the pathname wrong and we need manually</span>
<span># set it</span>
event.<span>pathname</span> = file_name
<span># add the event only if we do not have an exclude filter or</span>
<span># the exclude filter returns False, that is, the event will not</span>
<span># be excluded</span>
<span>if</span> <span>not</span> <span>self</span>.<span>exclude_filter</span> <span>or</span> <span>not</span> <span>self</span>.<span>exclude_filter</span><span>&#40;</span>event<span>&#41;</span>:
<span>self</span>.<span>log</span>.<span>debug</span><span>&#40;</span><span>'Addding event %s to queue.'</span>, event<span>&#41;</span>
<span>self</span>.<span>events_queue</span>.<span>put</span><span>&#40;</span>event<span>&#41;</span>
&nbsp;
<span>def</span> _watch<span>&#40;</span><span>self</span><span>&#41;</span>:
<span>&quot;&quot;&quot;Watch a path that is a directory.&quot;&quot;&quot;</span>
<span># we are going to be using the ReadDirectoryChangesW whihc requires</span>
<span># a direcotry handle and the mask to be used.</span>
handle = CreateFile<span>&#40;</span>
<span>self</span>._path,
FILE_LIST_DIRECTORY,
FILE_SHARE_READ | FILE_SHARE_WRITE,
<span>None</span>,
OPEN_EXISTING,
FILE_FLAG_BACKUP_SEMANTICS,
<span>None</span>
<span>&#41;</span>
<span>self</span>.<span>log</span>.<span>debug</span><span>&#40;</span><span>'Watchng path %s.'</span>, <span>self</span>._path<span>&#41;</span>
<span>while</span> <span>self</span>._watching:
<span># important information to know about the parameters:</span>
<span># param 1: the handle to the dir</span>
<span># param 2: the size to be used in the kernel to store events</span>
<span># that might be lost whilw the call is being performed. This</span>
<span># is complicates to fine tune since if you make lots of watcher</span>
<span># you migh used to much memory and make your OS to BSOD</span>
results = ReadDirectoryChangesW<span>&#40;</span>
handle,
<span>1024</span>,
<span>self</span>._auto_add,
<span>self</span>._mask,
<span>None</span>,
<span>None</span>
<span>&#41;</span>
<span># add the diff events to the q so that the can be processed no</span>
<span># matter the speed.</span>
<span>for</span> action, <span>file</span> <span>in</span> results:
full_filename = <span>os</span>.<span>path</span>.<span>join</span><span>&#40;</span><span>self</span>._path, <span>file</span><span>&#41;</span>
<span>self</span>._raw_events_queue.<span>put</span><span>&#40;</span><span>&#40;</span>full_filename, action<span>&#41;</span><span>&#41;</span>
<span>self</span>.<span>log</span>.<span>debug</span><span>&#40;</span><span>'Added %s to raw events queue.'</span>,
<span>&#40;</span>full_filename, action<span>&#41;</span><span>&#41;</span>
&nbsp;
<span>def</span> start_watching<span>&#40;</span><span>self</span><span>&#41;</span>:
<span>&quot;&quot;&quot;Tell the watch to start processing events.&quot;&quot;&quot;</span>
<span># get the diff dirs in the path</span>
<span>for</span> current_child <span>in</span> listdir<span>&#40;</span><span>self</span>._path<span>&#41;</span>:
full_child_path = <span>os</span>.<span>path</span>.<span>join</span><span>&#40;</span><span>self</span>._path, current_child<span>&#41;</span>
<span>if</span> <span>os</span>.<span>path</span>.<span>isdir</span><span>&#40;</span>full_child_path<span>&#41;</span>:
<span>self</span>._subdirs.<span>append</span><span>&#40;</span>full_child_path<span>&#41;</span>
<span># start to diff threads, one to watch the path, the other to</span>
<span># process the events.</span>
<span>self</span>.<span>log</span>.<span>debug</span><span>&#40;</span><span>'Sart watching path.'</span><span>&#41;</span>
<span>self</span>._watching = <span>True</span>
watch_thread = Thread<span>&#40;</span>target=<span>self</span>._watch,
name=<span>'Watch(%s)'</span> <span>%</span> <span>self</span>._path<span>&#41;</span>
process_thread = Thread<span>&#40;</span>target=<span>self</span>._process_events,
name=<span>'Process(%s)'</span> <span>%</span> <span>self</span>._path<span>&#41;</span>
process_thread.<span>start</span><span>&#40;</span><span>&#41;</span>
watch_thread.<span>start</span><span>&#40;</span><span>&#41;</span>
&nbsp;
<span>def</span> stop_watching<span>&#40;</span><span>self</span><span>&#41;</span>:
<span>&quot;&quot;&quot;Tell the watch to stop processing events.&quot;&quot;&quot;</span>
<span>self</span>._watching = <span>False</span>
<span>self</span>._subdirs = <span>&#91;</span><span>&#93;</span>
&nbsp;
<span>def</span> update<span>&#40;</span><span>self</span>, mask, proc_fun=<span>None</span>, auto_add=<span>False</span><span>&#41;</span>:
<span>&quot;&quot;&quot;Update the info used by the watcher.&quot;&quot;&quot;</span>
<span>self</span>.<span>log</span>.<span>debug</span><span>&#40;</span><span>'update(%s, %s, %s)'</span>, mask, proc_fun, auto_add<span>&#41;</span>
<span>self</span>._mask = mask
<span>self</span>._proc_fun = proc_fun
<span>self</span>._auto_add = auto_add
&nbsp;
@<span>property</span>
<span>def</span> path<span>&#40;</span><span>self</span><span>&#41;</span>:
<span>&quot;&quot;&quot;Return the patch watched.&quot;&quot;&quot;</span>
<span>return</span> <span>self</span>._path
&nbsp;
@<span>property</span>
<span>def</span> auto_add<span>&#40;</span><span>self</span><span>&#41;</span>:
<span>return</span> <span>self</span>._auto_add
&nbsp;
@<span>property</span>
<span>def</span> proc_fun<span>&#40;</span><span>self</span><span>&#41;</span>:
<span>return</span> <span>self</span>._proc_fun
&nbsp;
&nbsp;
<span>class</span> WatchManager<span>&#40;</span><span>object</span><span>&#41;</span>:
<span>&quot;&quot;&quot;Implement the same functions as pyinotify.WatchManager.&quot;&quot;&quot;</span>
&nbsp;
<span>def</span> <span>__init__</span><span>&#40;</span><span>self</span>, exclude_filter=<span>lambda</span> path: <span>False</span><span>&#41;</span>:
<span>&quot;&quot;&quot;Init the manager to keep trak of the different watches.&quot;&quot;&quot;</span>
<span>super</span><span>&#40;</span>WatchManager, <span>self</span><span>&#41;</span>.<span>__init__</span><span>&#40;</span><span>&#41;</span>
<span>self</span>.<span>log</span> = <span>logging</span>.<span>getLogger</span><span>&#40;</span><span>'ubuntuone.platform.windows.'</span>
+ <span>'filesystem_notifications.WatchManager'</span><span>&#41;</span>
<span>self</span>._wdm = <span>&#123;</span><span>&#125;</span>
<span>self</span>._wd_count = <span>0</span>
<span>self</span>._exclude_filter = exclude_filter
<span>self</span>._events_queue = <span>Queue</span><span>&#40;</span><span>&#41;</span>
<span>self</span>._ignored_paths = <span>&#91;</span><span>&#93;</span>
&nbsp;
<span>def</span> stop<span>&#40;</span><span>self</span><span>&#41;</span>:
<span>&quot;&quot;&quot;Close the manager and stop all watches.&quot;&quot;&quot;</span>
<span>self</span>.<span>log</span>.<span>debug</span><span>&#40;</span><span>'Stopping watches.'</span><span>&#41;</span>
<span>for</span> current_wd <span>in</span> <span>self</span>._wdm:
<span>self</span>._wdm<span>&#91;</span>current_wd<span>&#93;</span>.<span>stop_watching</span><span>&#40;</span><span>&#41;</span>
<span>self</span>.<span>log</span>.<span>debug</span><span>&#40;</span><span>'Watch for %s stopped.'</span>, <span>self</span>._wdm<span>&#91;</span>current_wd<span>&#93;</span>.<span>path</span><span>&#41;</span>
&nbsp;
<span>def</span> get_watch<span>&#40;</span><span>self</span>, wd<span>&#41;</span>:
<span>&quot;&quot;&quot;Return the watch with the given descriptor.&quot;&quot;&quot;</span>
<span>return</span> <span>self</span>._wdm<span>&#91;</span>wd<span>&#93;</span>
&nbsp;
<span>def</span> del_watch<span>&#40;</span><span>self</span>, wd<span>&#41;</span>:
<span>&quot;&quot;&quot;Delete the watch with the given descriptor.&quot;&quot;&quot;</span>
<span>try</span>:
watch = <span>self</span>._wdm<span>&#91;</span>wd<span>&#93;</span>
watch.<span>stop_watching</span><span>&#40;</span><span>&#41;</span>
<span>del</span> <span>self</span>._wdm<span>&#91;</span>wd<span>&#93;</span>
<span>self</span>.<span>log</span>.<span>debug</span><span>&#40;</span><span>'Watch %s removed.'</span>, wd<span>&#41;</span>
<span>except</span> <span>KeyError</span>, e:
<span>logging</span>.<span>error</span><span>&#40;</span><span>str</span><span>&#40;</span>e<span>&#41;</span><span>&#41;</span>
&nbsp;
<span>def</span> _add_single_watch<span>&#40;</span><span>self</span>, path, mask, proc_fun=<span>None</span>, auto_add=<span>False</span>,
quiet=<span>True</span>, exclude_filter=<span>None</span><span>&#41;</span>:
<span>self</span>.<span>log</span>.<span>debug</span><span>&#40;</span><span>'add_single_watch(%s, %s, %s, %s, %s, %s)'</span>, path, mask,
proc_fun, auto_add, quiet, exclude_filter<span>&#41;</span>
<span>self</span>._wdm<span>&#91;</span><span>self</span>._wd_count<span>&#93;</span> = Watch<span>&#40;</span><span>self</span>._wd_count, path, mask,
auto_add, events_queue=<span>self</span>._events_queue,
exclude_filter=exclude_filter, proc_fun=proc_fun<span>&#41;</span>
<span>self</span>._wdm<span>&#91;</span><span>self</span>._wd_count<span>&#93;</span>.<span>start_watching</span><span>&#40;</span><span>&#41;</span>
<span>self</span>._wd_count += <span>1</span>
<span>self</span>.<span>log</span>.<span>debug</span><span>&#40;</span><span>'Watch count increased to %s'</span>, <span>self</span>._wd_count<span>&#41;</span>
&nbsp;
<span>def</span> add_watch<span>&#40;</span><span>self</span>, path, mask, proc_fun=<span>None</span>, auto_add=<span>False</span>,
quiet=<span>True</span>, exclude_filter=<span>None</span><span>&#41;</span>:
<span>if</span> <span>hasattr</span><span>&#40;</span>path, <span>'__iter__'</span><span>&#41;</span>:
<span>self</span>.<span>log</span>.<span>debug</span><span>&#40;</span><span>'Added collection of watches.'</span><span>&#41;</span>
<span># we are dealing with a collection of paths</span>
<span>for</span> current_path <span>in</span> path:
<span>if</span> <span>not</span> <span>self</span>.<span>get_wd</span><span>&#40;</span>current_path<span>&#41;</span>:
<span>self</span>._add_single_watch<span>&#40;</span>current_path, mask, proc_fun,
auto_add, quiet, exclude_filter<span>&#41;</span>
<span>elif</span> <span>not</span> <span>self</span>.<span>get_wd</span><span>&#40;</span>path<span>&#41;</span>:
<span>self</span>.<span>log</span>.<span>debug</span><span>&#40;</span><span>'Adding single watch.'</span><span>&#41;</span>
<span>self</span>._add_single_watch<span>&#40;</span>path, mask, proc_fun, auto_add,
quiet, exclude_filter<span>&#41;</span>
&nbsp;
<span>def</span> update_watch<span>&#40;</span><span>self</span>, wd, mask=<span>None</span>, proc_fun=<span>None</span>, rec=<span>False</span>,
auto_add=<span>False</span>, quiet=<span>True</span><span>&#41;</span>:
<span>try</span>:
watch = <span>self</span>._wdm<span>&#91;</span>wd<span>&#93;</span>
watch.<span>stop_watching</span><span>&#40;</span><span>&#41;</span>
<span>self</span>.<span>log</span>.<span>debug</span><span>&#40;</span><span>'Stopped watch on %s for update.'</span>, watch.<span>path</span><span>&#41;</span>
<span># update the data and restart watching</span>
auto_add = auto_add <span>or</span> rec
watch.<span>update</span><span>&#40;</span>mask, proc_fun=proc_fun, auto_add=auto_add<span>&#41;</span>
<span># only start the watcher again if the mask was given, otherwhise</span>
<span># we are not watchng and therefore do not care</span>
<span>if</span> mask:
watch.<span>start_watching</span><span>&#40;</span><span>&#41;</span>
<span>except</span> <span>KeyError</span>, e:
<span>self</span>.<span>log</span>.<span>error</span><span>&#40;</span><span>str</span><span>&#40;</span>e<span>&#41;</span><span>&#41;</span>
<span>if</span> <span>not</span> quiet:
<span>raise</span> WatchManagerError<span>&#40;</span><span>'Watch %s was not found'</span> <span>%</span> wd, <span>&#123;</span><span>&#125;</span><span>&#41;</span>
&nbsp;
<span>def</span> get_wd<span>&#40;</span><span>self</span>, path<span>&#41;</span>:
<span>&quot;&quot;&quot;Return the watcher that is used to watch the given path.&quot;&quot;&quot;</span>
<span>for</span> current_wd <span>in</span> <span>self</span>._wdm:
<span>if</span> <span>self</span>._wdm<span>&#91;</span>current_wd<span>&#93;</span>.<span>path</span> <span>in</span> path <span>and</span> \
<span>self</span>._wdm<span>&#91;</span>current_wd<span>&#93;</span>.<span>auto_add</span>:
<span>return</span> current_wd
&nbsp;
<span>def</span> get_path<span>&#40;</span><span>self</span>, wd<span>&#41;</span>:
<span>&quot;&quot;&quot;Return the path watched by the wath with the given wd.&quot;&quot;&quot;</span>
watch_ = <span>self</span>._wmd.<span>get</span><span>&#40;</span>wd<span>&#41;</span>
<span>if</span> watch:
<span>return</span> watch.<span>path</span>
&nbsp;
<span>def</span> rm_watch<span>&#40;</span><span>self</span>, wd, rec=<span>False</span>, quiet=<span>True</span><span>&#41;</span>:
<span>&quot;&quot;&quot;Remove the the watch with the given wd.&quot;&quot;&quot;</span>
<span>try</span>:
watch = <span>self</span>._wdm<span>&#91;</span>wd<span>&#93;</span>
watch.<span>stop_watching</span><span>&#40;</span><span>&#41;</span>
<span>del</span> <span>self</span>._wdm<span>&#91;</span>wd<span>&#93;</span>
<span>except</span> KeyrError, err:
<span>self</span>.<span>log</span>.<span>error</span><span>&#40;</span><span>str</span><span>&#40;</span>err<span>&#41;</span><span>&#41;</span>
<span>if</span> <span>not</span> quiet:
<span>raise</span> WatchManagerError<span>&#40;</span><span>'Watch %s was not found'</span> <span>%</span> wd, <span>&#123;</span><span>&#125;</span><span>&#41;</span>
&nbsp;
<span>def</span> rm_path<span>&#40;</span><span>self</span>, path<span>&#41;</span>:
<span>&quot;&quot;&quot;Remove a watch to the given path.&quot;&quot;&quot;</span>
<span># it would be very tricky to remove a subpath from a watcher that is</span>
<span># looking at changes in ther kids. To make it simpler and less error</span>
<span># prone (and even better performant since we use less threads) we will</span>
<span># add a filter to the events in the watcher so that the events from</span>
<span># that child are not received :)</span>
<span>def</span> ignore_path<span>&#40;</span>event<span>&#41;</span>:
<span>&quot;&quot;&quot;Ignore an event if it has a given path.&quot;&quot;&quot;</span>
is_ignored = <span>False</span>
<span>for</span> ignored_path <span>in</span> <span>self</span>._ignored_paths:
<span>if</span> ignore_path <span>in</span> event.<span>pathname</span>:
<span>return</span> <span>True</span>
<span>return</span> <span>False</span>
&nbsp;
wd = <span>self</span>.<span>get_wd</span><span>&#40;</span>path<span>&#41;</span>
<span>if</span> wd:
<span>if</span> <span>self</span>._wdm<span>&#91;</span>wd<span>&#93;</span>.<span>path</span> == path:
<span>self</span>.<span>log</span>.<span>debug</span><span>&#40;</span><span>'Removing watch for path &quot;%s&quot;'</span>, path<span>&#41;</span>
<span>self</span>.<span>rm_watch</span><span>&#40;</span>wd<span>&#41;</span>
<span>else</span>:
<span>self</span>.<span>log</span>.<span>debug</span><span>&#40;</span><span>'Adding exclude filter for &quot;%s&quot;'</span>, path<span>&#41;</span>
<span># we have a watch that cotains the path as a child path</span>
<span>if</span> <span>not</span> path <span>in</span> <span>self</span>._ignored_paths:
<span>self</span>._ignored_paths.<span>append</span><span>&#40;</span>path<span>&#41;</span>
<span># FIXME: This assumes that we do not have other function</span>
<span># which in our usecase is correct, but what is we move this</span>
<span># to other projects evet?!? Maybe using the manager</span>
<span># exclude_filter is better</span>
<span>if</span> <span>not</span> <span>self</span>._wdm<span>&#91;</span>wd<span>&#93;</span>.<span>exclude_filter</span>:
<span>self</span>._wdm<span>&#91;</span>wd<span>&#93;</span>.<span>exclude_filter</span> = ignore_path
&nbsp;
@<span>property</span>
<span>def</span> watches<span>&#40;</span><span>self</span><span>&#41;</span>:
<span>&quot;&quot;&quot;Return a reference to the dictionary that contains the watches.&quot;&quot;&quot;</span>
<span>return</span> <span>self</span>._wdm
&nbsp;
@<span>property</span>
<span>def</span> events_queue<span>&#40;</span><span>self</span><span>&#41;</span>:
<span>&quot;&quot;&quot;Return the queue with the events that the manager contains.&quot;&quot;&quot;</span>
<span>return</span> <span>self</span>._events_queue
&nbsp;
&nbsp;
<span>class</span> Notifier<span>&#40;</span><span>object</span><span>&#41;</span>:
<span>&quot;&quot;&quot;
Read notifications, process events. Inspired by the pyinotify.Notifier
&quot;&quot;&quot;</span>
&nbsp;
<span>def</span> <span>__init__</span><span>&#40;</span><span>self</span>, watch_manager, default_proc_fun=<span>None</span>, read_freq=<span>0</span>,
threshold=<span>10</span>, timeout=-<span>1</span><span>&#41;</span>:
<span>&quot;&quot;&quot;Init to process event according to the given timeout &amp; threshold.&quot;&quot;&quot;</span>
<span>super</span><span>&#40;</span>Notifier, <span>self</span><span>&#41;</span>.<span>__init__</span><span>&#40;</span><span>&#41;</span>
<span>self</span>.<span>log</span> = <span>logging</span>.<span>getLogger</span><span>&#40;</span><span>'ubuntuone.platform.windows.'</span>
+ <span>'filesystem_notifications.Notifier'</span><span>&#41;</span>
<span># Watch Manager instance</span>
<span>self</span>._watch_manager = watch_manager
<span># Default processing method</span>
<span>self</span>._default_proc_fun = default_proc_fun
<span>if</span> default_proc_fun <span>is</span> <span>None</span>:
<span>self</span>._default_proc_fun = PrintAllEvents<span>&#40;</span><span>&#41;</span>
<span># Loop parameters</span>
<span>self</span>._read_freq = read_freq
<span>self</span>._threshold = threshold
<span>self</span>._timeout = timeout
&nbsp;
<span>def</span> proc_fun<span>&#40;</span><span>self</span><span>&#41;</span>:
<span>return</span> <span>self</span>._default_proc_fun
&nbsp;
<span>def</span> process_events<span>&#40;</span><span>self</span><span>&#41;</span>:
<span>&quot;&quot;&quot;
Process the event given the threshold and the timeout.
&quot;&quot;&quot;</span>
<span>self</span>.<span>log</span>.<span>debug</span><span>&#40;</span><span>'Processing events with threashold: %s and timeout: %s'</span>,
<span>self</span>._threshold, <span>self</span>._timeout<span>&#41;</span>
<span># we will process an amount of events equal to the threshold of</span>
<span># the notifier and will block for the amount given by the timeout</span>
processed_events = <span>0</span>
<span>while</span> processed_events <span>&lt;</span> <span>self</span>._threshold:
<span>try</span>:
raw_event = <span>None</span>
<span>if</span> <span>not</span> <span>self</span>._timeout <span>or</span> <span>self</span>._timeout <span>&lt;</span> <span>0</span>:
raw_event = <span>self</span>._watch_manager.<span>events_queue</span>.<span>get</span><span>&#40;</span>
block=<span>False</span><span>&#41;</span>
<span>else</span>:
raw_event = <span>self</span>._watch_manager.<span>events_queue</span>.<span>get</span><span>&#40;</span>
timeout=<span>self</span>._timeout<span>&#41;</span>
watch = <span>self</span>._watch_manager.<span>get_watch</span><span>&#40;</span>raw_event.<span>wd</span><span>&#41;</span>
<span>if</span> watch <span>is</span> <span>None</span>:
<span># Not really sure how we ended up here, nor how we should</span>
<span># handle these types of events and if it is appropriate to</span>
<span># completly skip them (like we are doing here).</span>
<span>self</span>.<span>log</span>.<span>warning</span><span>&#40;</span><span>'Unable to retrieve Watch object '</span>
+ <span>'associated to %s'</span>, raw_event<span>&#41;</span>
processed_events += <span>1</span>
<span>continue</span>
<span>if</span> watch <span>and</span> watch.<span>proc_fun</span>:
<span>self</span>.<span>log</span>.<span>debug</span><span>&#40;</span><span>'Executing proc_fun from watch.'</span><span>&#41;</span>
watch.<span>proc_fun</span><span>&#40;</span>raw_event<span>&#41;</span> <span># user processings</span>
<span>else</span>:
<span>self</span>.<span>log</span>.<span>debug</span><span>&#40;</span><span>'Executing default_proc_fun'</span><span>&#41;</span>
<span>self</span>._default_proc_fun<span>&#40;</span>raw_event<span>&#41;</span>
processed_events += <span>1</span>
<span>except</span> Empty:
<span># increase the number of processed events, and continue</span>
processed_events += <span>1</span>
<span>continue</span>
&nbsp;
<span>def</span> stop<span>&#40;</span><span>self</span><span>&#41;</span>:
<span>&quot;&quot;&quot;Stop processing events and the watch manager.&quot;&quot;&quot;</span>
<span>self</span>._watch_manager.<span>stop</span><span>&#40;</span><span>&#41;</span></pre></div></div>
<p>While one of the threads is retrieving the events from the file system, the second one process them so that the will be exposed as pyinotify events. I have done so because I did not want to deal with OVERLAP structures for asyn operations in Win32 and because I wanted to use pyinotify events so that if someone with experience in pyinotify looks at the output, he can easily understand it. I really like this approach because it allowed me to reuse a fair amount of logic hat we had in the Ubuntu client and to approach the port in a very TDD way since the tests I&#8217;ve used are the same ones as the ones found on Ubuntu <img src="http://www.themacaque.com/wp-includes/images/smilies/icon_smile.gif" alt=":)" class="wp-smiley" /> </p>