jjacky.com2023-07-26T07:56:08+00:00http://jjacky.comAs the moon goes down...2023-07-26T00:00:00+00:00http://jjacky.com/2023-07-26-as-the-moon-goes-down<p>Pardon a brief interruption of the ongoing silence but; <em>Guess what?</em></p>
<p>Turns out, this place isn't quite dead just yet! :-)</p>
<p>It has been quite a while since I posted around here, or anywhere to be fair,
but after some time away from the keyboard here I am again. Now I haven't fully
resumed all that I had going "before" and I'll be honest, there are things I
haven't dared looking at so far. This means there's no update for anything at
the moment, although I do intend to get back to it <em>at some point</em>.</p>
</p>
<h1>side project</h1>
<p>In the meantime, I've started some new projects - because that old todo list of
mine <s>wasn't long enough</s> was too scary for now - and for some reason I did that
on a separate place, <a href="https://lila.oss">lila.oss</a></p>
<p>There might be a few posts over there(!), maybe even a project or two shaping
up. But that's a domain name only available for those who have their DNS
resolution under <a href="https://www.opennic.org">OpenNIC</a>, so here's a more globally accessible mirror of
sorts: <a href="https://lila.oss.jjacky.com">lila.oss.jjacky.com</a></p>
<p>Thank you for listening, goodbye.</p>
kalu 4.3.0 is out2018-06-04T00:00:00+00:00http://jjacky.com/2018-06-04-kalu-4.3.0-is-out<p>As I'm sure you have noticed by now, a new version of pacman (5.1) has been
released, and with it API changes to ALPM requiring some compatibility changes.</p>
<p>Nothing big, but it needed to be done of course, so here's a new version of kalu
with the required changes, a fix to actually be suspend-aware, and a small
addition in form of a context menu to the "Mark Watched (AUR)" windows.</p>
</p>
<h3>Downloads and whatnot</h3>
<p>See <a href="/kalu" title="kalu: Keep Arch Linux Up-to-date">kalu</a> for a description & all the links you should need.</p>
<p>And of course, as always, new bug reports, suggestions or any other form of
constructive criticism is very much welcome.</p>
<h3>A note about pacdep & PkgClip re: pacman 5.1</h3>
<p>Both <a href="/pacdep" title="pacdep: Easily list package dependencies">pacdep</a> and <a href="/pkgclip" title="PkgClip: Cached Packages Trimmer Utility">PkgClip</a> are also affected by the pacman update, only they
don't actually need any changes. In other words, only a rebuild (to link the
latest libalpm) is needed, nothing else. Hence, no new versions there.</p>
<p>Of course, as usual, if you happen to catch a bug (related to the pacman 5.1 or
not), let me know!</p>
kalu 4.2.0 is out, speaks Spanish2018-02-10T00:00:00+00:00http://jjacky.com/2018-02-10-kalu-4.2.0-is-out-speaks-spanish<p>About time a new release of kalu was made, so here it is! Apart from a few bugs
being fixed, this release sees a couple of command-line options mainly useful
for CLI use, and the addition of Spanish to the list of languages supported by
kalu thanks to pepecuis!</p>
</p>
<p>Main changes since last version:</p>
<ul>
<li>kalu: Add --tmp-dbpath and --keep-tmp-dbpath</li>
</ul>
<p>Mainly useful for CLI use (or not?), to be able to keep & re-use the tmp dbs
over time, much like the GUI does during its run.</p>
<ul>
<li><p>Support disabling auto-checks (via Interval = 0)</p></li>
<li><p>news: Fix issue if title needs trimming..</p></li>
</ul>
<p>..that is, if a news title (used to determine whether it has been read
or not) could be trimmedg, there was an issue because titles read from
news.conf are trimmed, so the two wouldn't match, and the news
incorrectly considered unread.</p>
<p>To fix this we trim the titles read from the XML (RSS feed) as well.</p>
<p>Thanks to Ada Joule; Also adam777 for the report.</p>
<ul>
<li><p>Update French translation</p></li>
<li><p>doc: Adjust example path about custom icons</p></li>
<li><p>doc: List options in alphabetical order</p></li>
<li><p>Some other fixes (see git log for details)</p></li>
</ul>
<h3>Downloads and whatnot</h3>
<p>See <a href="/kalu" title="kalu: Keep Arch Linux Up-to-date">kalu</a> for a description & all the links you should need.</p>
<p>And of course, as always, new bug reports, suggestions or any other form of
constructive criticism is very much welcome.</p>
anopa 0.5.0 released2017-06-20T00:00:00+00:00http://jjacky.com/2017-06-20-anopa-0.5.0-released<p>A new version of anopa - init system/service manager built around s6 supervision
suite - has been released. Main changes since 0.4.0 are :</p>
<ul>
<li><p>tty: Fix when multiple devices are listed as console. Thanks to linsam.</p></li>
<li><p>status: Report "Up; Getting ready..." as needed. Longruns that are up (i.e.
not (yet) ready) but do support readiness will be announced as such, making it
obvious they support readiness and therefore aren't yet in their "final"
state.</p></li>
<li><p>enable: Add <code>--alarm-s6</code> When adding new servicedirs to an active repodir
(i.e. its scandir has a running s6-svscan), for new longruns to be properly
set/usable we need to "alarm" s6-svscan, so it rescans the scandir.</p>
<p>This had to be done manually via <code>s6-svscanctl -a $REPODIR/.scandir</code> but can
now be done automatically from aa-enable.</p></li>
</ul>
</p>
<ul>
<li><p>start/stop: Fix issues on 32bit systems. Thanks to John O'M.</p></li>
<li><p>stage0: Fix stderr not on console upon break</p></li>
<li><p>stage4: Open a shell if aa-terminate fails</p></li>
<li><p>stage3: Tweak wait-ing post TERM/KILL: After TERM we give processes ~4s to end
instead of immediately trying to KILL them; After KILL we only wait up to ~2s,
then move on (instead of blocking should there be a process in uninterruptible
sleep)</p></li>
<li><p>stop: Wait for longruns to be Down & Ready (not just Down)</p></li>
<li><p>stop: In stop-all, default timeout becomes a maximum. So any timeout defined
in a file timeout in servicedir will be ignored if more than the default (or 0
for infinite).</p></li>
<li><p>stage3: Set default/max timeout to 20s</p></li>
<li><p>Deprecate aa-command</p></li>
<li><p>Remove deprecated aa-mvlog</p></li>
<li><p>Bump dependencies to skalibs 2.5.0.0; execline 2.3.0.1 and s6 2.5.0.0</p></li>
</ul>
<p>A few other changes & fixes as well, see HISTORY or the git log for
more.</p>
<h3>Downloads and whatnot</h3>
<p>See <a href="/anopa" title="anopa: init system/service manager built around s6 supervision suite">anopa</a> for longer description & all the links you should need. If you've
never used anopa and are wondering about how to go at it, you can check out this
example about <a href="/2015-11-14-making-anopa-powered-bootable-iso" title="Making an anopa-powered bootable ISO @ jjacky.com">making an anopa-powered bootable
ISO</a></p>
<p>And of course, as always, new bug reports, suggestions or any other form of
constructive criticism is very much welcome.</p>
StatusNotifier v1.0.0 released !2017-03-10T00:00:00+00:00http://jjacky.com/2017-03-10-statusnotifier-1.0.0-released<p>As long last, a new version of statusnotifier is out! This has been due for a
(very) long time, and it's finally arrived. Many thanks to everyone who helped,
especially contributors Bradley Xu and Vladimir Perepechin, and apologies it
took so long for a release to happen.</p>
<p>As you've no doubt noticed, this is version 1.0.0 -- Two reasons for that: one,
it's indeed considered stable; And two, it comes with a soname bump and
incompatibility with the previous version.</p>
</p>
<h3>First off, the (breaking) bad</h3>
<p>Unfortunately in order to follow more closely the GObject conventions when it
comes to naming things, some renaming had to be done. And because those
conventions become pretty much requirements for introspection to work nicely,
and e.g. provide a way to use statusnotifier from other languages (e.g. Perl),
it was needed to break things.</p>
<p>Mainly, the main typedef - <code>StatusNotifier</code> - was renamed to
<code>StatusNotifierItem</code> and alongside every single function was renamed from
<code>status_notifier_XXX</code> to <code>status_notifier_item_XXX</code> (Typical GObject macros
were also renamed, notably <code>TYPE_STATUS_NOTIFIER</code> became
<code>STATUS_NOTIFIER_TYPE_ITEM</code>.)</p>
<p>There was no other change, only typedef/functions/macros renamed, so fixing
code written for previous version is only a matter or search&replace.</p>
<p>Note that a <code>statusnotifier-compat.h</code> is provided, that defines a bunch of
macros and should allow old code to keep working without any changes required,
only this extra include. As a transitional aid of sorts.</p>
<h3>Then some good, too</h3>
<p>This wasn't all for nothing though, and a new configure option
<code>--enable-introspection</code> will generate the needed filed to allow the use of
statusnotifier from other languages, which is nice. And thanks to Frédéric
Buclin for his help.</p>
<p>Unrelated to all this, but still good news: there is now optional support for
DBus menu (via libdbusmenu), which means when enabled that you can simply
provide a <code>GtkMenu</code> to statusnotifier, and it'll be passed via DBus to the
StatusNotifierHost which will then handle showing the menu upon user
interaction.</p>
<p>Lastly, a new property <code>item-is-menu</code> has been added, as it was added to the
specifications, to let the StatusNotifierHost know that it should prefer showing
the menu (when set via DBus) or trigger <code>context-menu</code> instead of <code>activate</code>.</p>
<p>Of course a few bugs were fixed here & there, notibaly possibly using wrong
scroll orientation and getting/setting property window-id; See git log for more.</p>
<h3>Downloads and whatnot</h3>
<p>See <a href="/statusnotifier" title="statusnotifier: KDE's Status Notifier Item as GObject">statusnotifier</a> for longer description & all the links you should need.</p>
<p>And of course, as always, new bug reports, suggestions or any other form of
constructive criticism is very much welcome.</p>
New version of slicd, a simple lightweight Linux cron daemon2016-11-01T00:00:00+00:00http://jjacky.com/2016-11-01-new-version-of-slicd-simple-lightweight-linux-cron-daemon<p>Time for a new release of <a href="/slicd" title="slicd - simple lightweight Linux cron daemon">slicd</a> - a simple lightweight Linux cron daemon -
with fixes regarding DST handling and the addition of a new per-job "special
DST" mode, amongst other things.</p>
</p>
<h3>DST handling</h3>
<p>By default, slicd handles DST in the simplest way, and one that (I believe)
makes most sense: by doing nothing special at all. For example, if time jumps
backwards an hour going from 02:59 to 02:00, and a job is meant to run at minute
30 of every hour, it'll run "again" at 02:30 - as it is meant to.</p>
<p>However, there might be case where one wants a special handling, to not "repeat"
a job when DST gets deactivated (i.e. time jumps backwards), or to run jobs
"missed" on activation, during the jump forward.</p>
<p>This may now be enabled in slicd as well, on a per-job basis, either for
deactivation only, activation only, or both, via a simple prefix of the hour
field.</p>
<p>Refer to <strong>slicd-parser</strong>(1) and <strong>slicd-sched</strong>(1) for more.</p>
<h3>Non-DST related</h3>
<p><strong>slicd-parser</strong> now also supports, for every time-and-date field, prefix <code>!</code> to
invert matching values E.g. using <code>!15,20</code> for day of the month means every day
of the month but the 15th and 20th; Or <code>!Mon</code> as day of the week means every day
of the week but Mondays.</p>
<p>Lastly, a new tool - <strong>slicd-dump</strong> - was added to print in human-readable
fashion the content of compiled crontabs.</p>
<h3>Downloads and whatnot</h3>
<p>See <a href="/slicd" title="slicd - simple lightweight Linux cron daemon">slicd</a> for a description & all the links you should need.</p>
<p>Please note that obviously the internal format of compiled crontabs changed, so
make sure to re-compile them (i.e. run <strong>slicd-parser</strong> again) before you
restart <strong>slicd-sched</strong> (and don't use <strong>slicd-dump</strong> on old ones, as you'd get
incorrect data).</p>
<p>And of course, as always, new bug reports, suggestions or any other form of
constructive criticism is very much welcome.</p>
journal-triggerd 0.2.1 released2016-08-28T00:00:00+00:00http://jjacky.com/2016-08-28-journal-triggerd-0.2.1-released<p>This is a "minor" bugfix release, mainly affecting building of journal-triggerd;
though there was an important issue since <code>configure</code> was still looking for
<code>libsystemd-journal</code> even though it has been removed & merged into <code>libsystemd</code>
since v230.</p>
</p>
<p>This, and a failure on non-existing <code>build-aux</code>, is now fixed with 0.2.1 No
other changes.</p>
<p>And thanks to maxime1986 for the report, as I totally missed this, obviously.</p>
<h3>Downloads and whatnot</h3>
<p>See <a href="/journal-triggerd" title="journal-triggerd: Run triggers on systemd's journal message">journal-triggerd</a> for a description & all the links you should need.</p>
<p>And of course, as always, new bug reports, suggestions or any other form of
constructive criticism is very much welcome.</p>
kalu 4.1.0 is out, speaks Norwegian2016-05-12T00:00:00+00:00http://jjacky.com/2016-05-12-kalu-4.1.0-is-out-speaks-norwegian<p>Time for a new release of kalu. Mostly a bugfix release, though thanks to
AdmiringWorm kalu now speaks Norwegian Bokmål!</p>
<p>Note that there was a bug in the updater, where <code>/etc/pacmand.d/hooks</code> was not
set as default <code>HookDir</code> if none were specified in <code>pacman.conf</code> - which means
unless you set it there, any custom hooks were not used.</p>
</p>
<p>Other changes since last version include:</p>
<ul>
<li><p>Update AUR URL to work with new version; Thanks to Yen Chi Hsuan.</p></li>
<li><p>With the new template UI, the combo-boxes for template sources (Default,
Fall back, etc) were not translatable, as they should have been; Fixed.
Thanks to Kim Nordmo.</p></li>
<li><p>updater: Fix color glitch when a download fails & resumes; Thanks to jghodd.</p></li>
<li><p>Some other fixes (see git log for details)</p></li>
</ul>
<h3>Downloads and whatnot</h3>
<p>See <a href="/kalu" title="kalu: Keep Arch Linux Up-to-date">kalu</a> for a description & all the links you should need.</p>
<p>And of course, as always, new bug reports, suggestions or any other form of
constructive criticism is very much welcome.</p>
What does it mean when 'alsactl restore' talks invalid sysfs?2016-03-11T00:00:00+00:00http://jjacky.com/2016-03-11-what-does-it-means-when-alsactl-restore-talks-invalid-sysfs<p> </p>
<pre><code>alsactl: sysfs_init:48: sysfs path '/sys' is invalid
Found hardware: "HDA-Intel" "Analog Devices AD1989B" "HDA:11d4989b,10438311,00100300" "0x1043" "0x8311"
Hardware is initialized using a generic method
</code></pre>
<p>This is what I could read on boot after a recent kernel upgrade (4.4.1-2 ->
4.4.3-1, to be exact), as a result of running <code>alsactl restore</code> Now, the good
thing is my audio didn't stop working, but that's still not right (and my
settings (e.g. volume levels) weren't restored as they should have been).</p>
</p>
<p>So, what does this cryptic mention of an invalid sysfs path mean? No clue, and
doing some research didn't really provide much information to be honest. After
looking in the source code, as others had done, all that was found out was that
it seemed to be somehow related to a missing file: <code>/sys/kernel/uevent_helper</code></p>
<p>No idea what that file is supposed to be, or why it matters so much to
<code>alsactl</code>, but indeed I don't have such a file. Here's the interesting part
though: I did not have it either back with the previous 4.4.1 kernel. What
gives?</p>
<h3>Invalid sysfs path, or just non-matching state?</h3>
<p>This is what led me to believe that maybe this weird error wasn't directly the
source of the problem, but occurred as a new code path was executed for some
reason. I thought, maybe my audio card is now identified with a different ID or
something, so the content of the <code>asound.state</code> file doesn't match, thus (with a
bit of black magic) an invalid sysfs path.</p>
<p>So I tried:</p>
<pre><code>mv /var/lib/alsa/asound.state{,-}
alsactl store
alsactl restore
</code></pre>
<p>And guess what? No more errors. And running a diff on the old & new state file
led not to a different id, but the addition of a new MIXER ("Loopback Mixing"),
which also resulted in a shift of all subsequent indices.</p>
<p>Here's a sample of the diff, to give you an idea of what I mean:</p>
<p><ol class="diff"><li class="li1"><div class="de1"><span class="re3">--- /var/lib/alsa/asound.state- 2016-03-04 20:28:06.959665756 +0100</span></div></li>
<li class="li1"><div class="de1"><span class="re4">+++ /var/lib/alsa/asound.state 2016-03-11 14:18:18.450834147 +0100</span></div></li>
<li class="li1"><div class="de1"><span class="re6">@@ -169,6 +169,18 @@</span></div></li>
<li class="li1"><div class="de1"> <span class="br0">}</span></div></li>
<li class="li1"><div class="de1"> control.14 <span class="br0">{</span></div></li>
<li class="li1"><div class="de1"> iface MIXER</div></li>
<li class="li1"><div class="de1"><span class="re8">+ name 'Loopback Mixing'</span></div></li>
<li class="li1"><div class="de1"><span class="re8">+ value Enabled</span></div></li>
<li class="li1"><div class="de1"><span class="re8">+ comment <span class="br0">{</span></span></div></li>
<li class="li1"><div class="de1"><span class="re8">+ access 'read write'</span></div></li>
<li class="li1"><div class="de1"><span class="re8">+ type ENUMERATED</span></div></li>
<li class="li1"><div class="de1"><span class="re8">+ count 1</span></div></li>
<li class="li1"><div class="de1"><span class="re8">+ item.0 Disabled</span></div></li>
<li class="li1"><div class="de1"><span class="re8">+ item.1 Enabled</span></div></li>
<li class="li1"><div class="de1"><span class="re8">+ <span class="br0">}</span></span></div></li>
<li class="li1"><div class="de1"><span class="re8">+ <span class="br0">}</span></span></div></li>
<li class="li1"><div class="de1"><span class="re8">+ control.15 <span class="br0">{</span></span></div></li>
<li class="li1"><div class="de1"><span class="re8">+ iface MIXER</span></div></li>
<li class="li1"><div class="de1"> name 'Front Mic Playback Volume'</div></li>
<li class="li1"><div class="de1"> value.0 <span class="nu0">0</span></div></li>
<li class="li1"><div class="de1"> value.1 <span class="nu0">0</span></div></li>
<li class="li1"><div class="de1"><span class="re6">@@ -183,7 +195,7 @@</span></div></li>
<li class="li1"><div class="de1"> dbvalue.1 -<span class="nu0">3450</span></div></li>
<li class="li1"><div class="de1"> <span class="br0">}</span></div></li>
<li class="li1"><div class="de1"> <span class="br0">}</span></div></li>
<li class="li1"><div class="de1"><span class="re7">- control.15 <span class="br0">{</span></span></div></li>
<li class="li1"><div class="de1"><span class="re8">+ control.16 <span class="br0">{</span></span></div></li>
<li class="li1"><div class="de1"> iface MIXER</div></li>
<li class="li1"><div class="de1"> name 'Front Mic Playback Switch'</div></li>
<li class="li1"><div class="de1"> value.0 false</div></li>
<li class="li1"><div class="de1"><span class="re6">@@ -194,7 +206,7 @@</span></div></li>
<li class="li1"><div class="de1"> count <span class="nu0">2</span></div></li>
<li class="li1"><div class="de1"> <span class="br0">}</span></div></li>
<li class="li1"><div class="de1"> <span class="br0">}</span></div></li>
<li class="li1"><div class="de1"><span class="re7">- control.16 <span class="br0">{</span></span></div></li>
<li class="li1"><div class="de1"><span class="re8">+ control.17 <span class="br0">{</span></span></div></li>
<li class="li1"><div class="de1"> iface MIXER</div></li>
<li class="li1"><div class="de1"> name 'Rear Mic Playback Volume'</div></li>
<li class="li1"><div class="de1"> value.0 <span class="nu0">0</span></div></li>
</ol></p>
<p>So then we're in a classic merge situation: simply update the new <code>asound.state</code>
file to get all the actual values back under the new indices, and now <code>alcactl
restore</code> works again as expected. Simple as that.</p>
<h3>So what does the invalid sysfs mean?</h3>
<p>Oh, right. Well, turns out the title of this post might be a bit misleading,
because I still have no idea what that cryptic error message means, or why the
<code>/sys/kernel/uevent_helper</code> file matters (or if I ever had such a file on my
system).</p>
<p>But if you're in a similar situation as mine, this post might give you a hint as
to how to get everything working again. And as far as the meaning of an invalid
sysfs path, the mystery remains...</p>
kalu 4.0.2 released2016-02-04T00:00:00+00:00http://jjacky.com/2016-02-04-kalu-4.0.2-released<p>"Release often" they say, right? Yet another release of kalu, since a stupid
mistake on my part led to notifications being empty in 4.0.1, making them much
less useful indeed.</p>
<p>This is now fixed; Thanks to adam777 for the report. Hopefully this is the last
release for this week :p</p>
</p>
<h3>Downloads and whatnot</h3>
<p>See <a href="/kalu" title="kalu: Keep Arch Linux Up-to-date">kalu</a> for a description & all the links you should need.</p>
<p>And of course, as always, new bug reports, suggestions or any other form of
constructive criticism is very much welcome.</p>
kalu 4.0.1 released2016-02-03T00:00:00+00:00http://jjacky.com/2016-02-03-kalu-4.0.1-released<p>2016 <u>will</u> be different, and there's already a new release of kalu! Nothing to
be pleased about though, as I let slip a bad bug with the templates reworking,
and kalu would segfault when running and no configuration has been loaded.</p>
<p>In other words, news users - or anyone without an existing <code>kalu.conf</code> - would
see a segfault as soon as the first checks were ran. Not good.</p>
</p>
<p>This is now fixed; Thanks to Adrien Jacquet for the original report & helping
tracking this down.</p>
<h3>Downloads and whatnot</h3>
<p>See <a href="/kalu" title="kalu: Keep Arch Linux Up-to-date">kalu</a> for a description & all the links you should need.</p>
<p>And of course, as always, new bug reports, suggestions or any other form of
constructive criticism is very much welcome.</p>
kalu 4.0.0, PkgClip 1.3.0 released2016-02-01T00:00:00+00:00http://jjacky.com/2016-02-01-kalu-4.0.0-pkgclip-1.3.0-released<p>As I don't doubt you're aware, pacman 5.0 is out. I managed to take some time
and here we go with new releases for kalu & PkgClip -- though, really, only the
former has a link to the new pacman, since as said before PkgClip wasn't
actually affected by the API changes.</p>
<p>(For pacdep: API changes aren't relevant, so a simple rebuild will do the trick.
No new version coming as of yet.)</p>
</p>
<h3>PkgClip 1.3.0</h3>
<p>A new version of <a href="/pkgclip" title="PkgClip: Cached Packages Trimmer Utility">pkgclip</a> was in order for a while, and this seemed a good
excuse to finally get to it. If you've been building from branch <code>next</code> on
github then there's likely nothing new for you, but main changes since the last
version are :</p>
<ul>
<li>Reset ALPM on reload (in case of config/DB update)</li>
</ul>
<p>E.g. after a sysupgrade it's no longer needed to restart PkgClip to have it use
the latest DB.</p>
<ul>
<li><p>Fix possible memory leak</p></li>
<li><p>Add option to remove matching .sig files (enabled by default)</p></li>
<li><p>Fix scrolling on going prev/next package w/ GTK+3.14</p></li>
<li><p>Fix possible segfault</p></li>
</ul>
<h3>kalu 4.0.0</h3>
<p>As for <a href="/kalu" title="kalu: Keep Arch Linux Up-to-date">kalu</a>, a new version was also due -- I somehow managed to not release
a single version in 2015, even though a few things were done along that year.
I'll try to do better in the future... Anyhow, main changes since 3.0.0 are :</p>
<ul>
<li><p>Major version bump for compatibility with API changes of pacman 5.0</p></li>
<li><p>Fix possible double-free memory when parsing config</p></li>
</ul>
<p>When processing "Include" directives from pacman.conf with multiple
matches there was a risk of double-free memory attempt.</p>
<ul>
<li>updater: Show download progress for deltas; Support multiple downloads
(deltas) for one package</li>
</ul>
<p>It is possible that the download size for a package upgrade isn't that
of one file, but multiple - in case of deltas.</p>
<p>Make sure the progress bar reflect the actual size of the current
download, and only toggle the color once all downloads are done.</p>
<ul>
<li><p>Add AutoShowLog tweak for kalu's updater</p></li>
<li><p>Fix nb of sync dbs in tooltip</p></li>
<li><p>Watched AUR: Fix segfault when no description (Thanks to 0strodamus)</p></li>
<li><p>watched: Add support for repo/package</p></li>
</ul>
<p>This allows to have kalu watch for a given package in a specific repo, instead
of using the usual "first repo where package is found" logic.</p>
<p>This could be useful when e.g. one has a repo like testing enabled, but wants
to watch packages from core.</p>
<p>Note that the package name (i.e. $PKG) will be kept as "repo/package" to
indicate the "restriction" that was in effect.</p>
<ul>
<li>Rework how templates are saved/shown in preferences</li>
</ul>
<p>Couple things happened here. First off, the way things worked wasn't
how things were happening in the preferences window:</p>
<ul>
<li><ul>
<li>in kalu.conf, no option meant default, or fallback if there's none; an
option w/out value meant fallback; and an option w/ a value to use
said custom value.</li>
</ul></li>
<li><ul>
<li>However, in Prefs. it was only a custom value, or fallback. Any default
being saved as custom value instead.</li>
</ul></li>
</ul>
<p>This was fixed, making the Prefs. window actually reflect how things actually
work in the conf file.</p>
<p>Also, we now introduce for each field a new "source" option (e.g. TitleSce) that
can be DEFAULT or CUSTOM for titles, because titles do not have fallbacks
anymore (it never really made sense anyways) and always have a default (for that
same reason).</p>
<p>For other fields (Package & Sep) it can be DEFAULT, FALLBACK, CUSTOM or
NONE. (Noting that they all have a default and/or a fallback, i.e. not always
both.)</p>
<p>Setting Package to NONE will mean the notification is only a title.</p>
<ul>
<li>Handle SIGINT/SIGTERM to cleanly exit</li>
</ul>
<p>Gives us a chance to e.g. remove FIFO</p>
<p>Thanks to 0strodamus for the report.</p>
<ul>
<li>Some other fixes (see git log for details)</li>
</ul>
<h3>Downloads and whatnot</h3>
<p>Thanks to all those who reported bugs or suggested features.</p>
<p>See <a href="/pkgclip" title="PkgClip: Cached Packages Trimmer Utility">pkgclip</a> and/or <a href="/kalu" title="kalu: Keep Arch Linux Up-to-date">kalu</a> for longer descriptions & all the links you should
need.</p>
<p>And of course, as always, new bug reports, suggestions or any other form of
constructive criticism is very much welcome.</p>
How to use kalu, PkgClip & pacdep with pacman 52016-01-30T00:00:00+00:00http://jjacky.com/2016-01-30-how-to-use-kalu-pkgclip-and-pacdep-with-pacman-5<p>As you may know, pacman 5.0 was just released (and is available in <code>testing</code>) so
you might want to give it a try (and play with hooks) !</p>
<p>To do so, here's what you need to know wrt my tools:</p>
</p>
<ul>
<li><p><a href="/kalu" title="kalu: Keep Arch Linux Up-to-date">kalu</a> : if you build it without the updater (<code>--disable-updater</code>) (or without
GUI altogether, of course) then a simple rebuild should be enough. With the
updater however, a few changes are in order and a branch <code>pacman-5</code> has been
pushed to github. Simply use the <a href="https://github.com/jjk-jacky/abs/tree/master/kalu-git">PKGBUILD for
kalu-git</a>, making sure
to update the branch name - and the dependencies (to pacman>=5.0 and
pacman<5.1) - and you're good.</p></li>
<li><p><a href="/pkgclip" title="PkgClip: Cached Packages Trimmer Utility">PkgClip</a> : isn't affected by the API changes, so a simple rebuild to link
against the new libalpm is enough. Though a new version is due, and I recommend
using the <a href="https://github.com/jjk-jacky/abs/tree/master/pkgclip-git">PKGBUILD for pkgclip-git</a>
to build from branch <code>next</code> to get the latest bugfixes.</p></li>
<li><p><a href="/pacdep" title="pacdep: Easily list package dependencies">pacdep</a> : same as PkgClip, a simple rebuild against the new libalpm will do the
trick.</p></li>
</ul>
slicd: a new Linux cron daemon2016-01-12T00:00:00+00:00http://jjacky.com/2016-01-12-slicd-a-new-linux-cron-daemon<p>There are already many cron daemons out there, and I honestly don't remember how
I came about looking into such tools, but as I did I realized I wasn't too happy
with the way most worked.</p>
<p>For instance, they all seem to operate on the same model: wake up at the top of
every minute, to check if there's any job to run or not. Many also include some
operations other than dropping privileges to the right user, such as setting up
the environment, sometimes via definitions inside the cron tables...</p>
<p>I wanted something simpler. Small, simple, that does as little as possible.</p>
</p>
<p>And so slicd was born. slicd is a Linux cron daemon aiming to be small, simple
and lightweight. It doesn't try to support every possible feature under the sun,
and while not a requirement is perfectly fitted to run under a supervision
suite.</p>
<p>It comes as a few modules :</p>
<ul>
<li><p><strong>slicd-parser</strong> : to parse crontabs into one "compiled" file</p>
<p>The parser's job is to process all system & user crontabs and compile them
into a single file, in a ready-to-use format for the scheduler.</p></li>
<li><p><strong>slicd-sched</strong> : the scheduler, aka the actual cron daemon</p>
<p>The scheduler simply loads the compiled crontabs, determines the next time a
job needs to run and simply waits for it. It doesn't need to wake up every
minute (as most cron daemons do) and handles time changes (manual, NTP,
DST...) fine.</p>
<p>It also doesn't actually run anything, but simply prints on its stdout one
line for each job to run, in the form <code>USERNAME:COMMAND LINE</code></p></li>
<li><p><strong>slicd-exec</strong> : the exec daemon, to actually run jobs</p>
<p>The scheduler's stdout is aimed to be piped into this daemon's stdin, which
will handle forking and executing the command line. It will report all forks
& reaped children on its stdout, as well as anything printed on a child's
stdout or stderr.</p>
<p>It is important to note that it doesn't do any drop of privileges or
environment changes, instead you're supposed to do this making sure it execs
into the right tools; such as one to drop privileges to a specific user, one
to set up the correct environment, etc</p></li>
</ul>
<p>In addition, a few extra tools are provided, meant to be used alongside
slicd-exec(1) :</p>
<ul>
<li><strong>setuid</strong> : drop privileges to the specified user</li>
<li><strong>miniexec</strong> : minimal parsing & execing of command-line</li>
</ul>
<h3>More info, Download links...</h3>
<p>You'll find more information about slicd and its different modules, as well as
download links & such, on the <a href="/slicd" title="slicd - simple lightweight Linux cron daemon">slicd</a> page.</p>
Introducing pam_rundir2016-01-10T00:00:00+00:00http://jjacky.com/2016-01-10-introducing-pam_rundir<p>As a user of a Linux system, you should have a runtime directory available for
applications. Such a thing is even defined in the <a href="http://standards.freedesktop.org/basedir-spec/basedir-spec-latest.html">XDG Base Directory
Specifications</a>,
as <code>$XDG_RUNTIME_DIR</code> -- and it is quite likely that you do have one set up.</p>
<p>You may have a session manager or some other component of your system handling
this directory for you, in which case the following likely won't be of much
interest to you.
If you do not have a <code>$XDG_RUNTIME_DIR</code> however, let me introduce a little PAM
module to take care of it.</p>
</p>
<p>I'm running Arch Linux, as under Arch one would usually use <code>systemd-logind</code> as
session manager, which takes care of <code>$XDG_RUNTIME_DIR</code> for you. I do not run
systemd however, and as such I was left without anything to handle it for me.</p>
<p>So after looking for a solution, as that's a nice thing to have, and failing to
find one, I wrote myself a little PAM module to do just that: <strong><a href="/pam_rundir" title="pam_rundir: Provide user runtime directory">pam_rundir</a></strong></p>
<p>It's a small PAM module that can be used to provide user runtime directory, as
per the previously mentioned specs. It will create the directory (with correct
ownership/permissions) on login, and remove it on log out (unless there's
another session active, of course). And it'll set the environment variable
<code>$XDG_RUNTIME_DIR</code> to its full path, as you'd expect.</p>
<p>That's it, but when you don't have something handling it, that's all you need.
As usual all the links (download, source code, etc) can be found on the
<a href="/pam_rundir" title="pam_rundir: Provide user runtime directory">pam_rundir</a> page.</p>
anopa 0.4.0 released2016-01-10T00:00:00+00:00http://jjacky.com/2016-01-10-anopa-0.4.0-released<p>A new version of anopa - init system/service manager built around s6 supervision
suite - has been released. Main changes since 0.3.0 are :</p>
<ul>
<li><p>Change how the logging works: instead of logging into
<code>/run/initramfs/boot.log</code> in stage 1 & 2, and using <code>aa-mvlog</code> to move said
file to <code>/var/log/boot</code> at the end of stage 2, now stage 1 & 2 (much like
stage 3) log directly into <code>/var/log/boot/current</code></p>
<p>As a special treat however, stage 1 will first check for a file
<code>/run/initramfs/boot.log</code> and import its content into <code>/var/log/boot/current</code>
if found.</p>
<p>That way everything from stage 1 is logged into persistent storage, and the
whole process is simpler.</p></li>
</ul>
</p>
<ul>
<li><p>status: Longrun services now have a "Mode" w/ "Automatic restart (want up)" or
"Once (want down)" when they're up (doesn't make sense when they're not).
In list mode, only show "Once" next to the PID when needed.</p>
<p>Also add mention "To be restarted" for down services that s6-supervise shall
be restarting soon, after finish is done and/or the 1sec delay. Useful to see
when e.g. a service keeps failing to start/be restarted.</p></li>
<li><p>stop: Fix unable to stop service that keeps crashing.</p></li>
<li><p>stop: Change how <code>--all</code> works: Now it only means stopping all up services,
nothing else. When specified a second time, then mode "stop-all" is enabled,
which means:</p>
<ul>
<li>for all down services, send 'x' to their s6-supervise</li>
<li>send 'dx' instead of 'd' to the s6-supervise of up services</li>
<li>ignore dependency error (i.e. always stop everything)</li>
</ul>
<p>So same as before, only with stopping s6-supervise of down services, to
properly bring the entire supervised tree down (assuming s6-svscan is down
already, ofc).</p></li>
</ul>
<p>A few other changes & fixes as well, see HISTORY or the git log for more.</p>
<p>Note that s6 dependency was bumped to s6 2.2.4.3 for the ftrigrd fix.</p>
<h3>Downloads and whatnot</h3>
<p>See <a href="/anopa" title="anopa: init system/service manager built around s6 supervision suite">anopa</a> for longer description & all the links you should need. If you've
never used anopa and are wondering about how to go at it, you can check out this
example about <a href="/2015-11-14-making-anopa-powered-bootable-iso" title="Making an anopa-powered bootable ISO @ jjacky.com">making an anopa-powered bootable
ISO</a></p>
<p>And of course, as always, new bug reports, suggestions or any other form of
constructive criticism is very much welcome.</p>
Making an anopa-powered bootable ISO2015-11-14T00:00:00+00:00http://jjacky.com/2015-11-14-making-anopa-powered-bootable-iso<p>There is something I've been meaning to do for some time now, I really should
have, yet haven't found some time to: writing some sort of proper/actual
introduction to <a href="/anopa" title="anopa: init system/service manager built around s6 supervision suite">anopa</a>.</p>
<p>So let's try to do this now, with an actual example. A little while back, I
explained <a href="/2015-04-10-has-arch-lost-its-way/" title="Has Arch lost its way?">why I was looking for another init
system</a>, and since
I couldn't find what I was looking for, I started working on my own. That's how
anopa, an init system/service manager based on the supervision suite s6, came to
be.</p>
</p>
<h3>Introducing anopa</h3>
<p>I like to think of <a href="/anopa" title="anopa: init system/service manager built around s6 supervision suite">anopa</a> as a toolbox, a collection of tools and scripts aimed
to provide what you need to build your own init system and service manager for
Linux system, based around the <a href="http://skarnet.org/software/s6/" title="s6 - skarnet's small supervision suite">supervision suite
s6</a>.</p>
<p>Notably, anopa provides some scripts that can be used for the different stages
of the init process/PID1. That is to say, there's basically 3 stages:</p>
<ul>
<li><p>Stage 1: booting up: prepare the system, mount file systems, etc</p></li>
<li><p>Stage 2: supervision: keep an eye an long-running processes/daemons and
restart them should they fail. (Also reap orphaned zombies.)</p></li>
<li><p>Stage 3: shutting down: stop/kill everything and "undo" what was done during
stage 1</p></li>
</ul>
<p><strong>s6-svscan</strong> is perfectly suited for and designed to be used as init (PID1)
during phase 2. That leaves the other two up for anopa. At this point it would
be a good idea to have a read of <a href="/anopa" title="anopa: init system/service manager built around s6 supervision suite">anopa</a> to be a bit familiar with its concepts
of services, dependencies and whatnot.</p>
<p>Done? Okay, good. So as you should know, the init process (PID 1) launched by
the kernel is quite special, and cannot die. It has to exist from start to
finish, but it can actually execute <u>into</u> another binary, which allows us to
have separate tool for separate phases quite easily.</p>
<p>anopa provides a few execline scripts that can be used for this purpose. First
we have <code>aa-stage1</code> which can be used as initial init process, and will simply
create the runtime repository <code>/run/services</code> using <strong>aa-enable</strong>(1), then exec
into <strong>s6-svscan</strong>; But not before having launched the <code>aa-stage2</code> script.</p>
<p>As you can notice here, we're not quite sticking to the initial description of
the different stages. Our initial script didn't do much, and certainly didn't
prepare the system. This will be the job of <code>aa-stage2</code> by calling
<strong>aa-start</strong>(1), leaving the actual stage 2 task up to <strong>s6-svscan</strong>, the new
PID1.</p>
<p>Some time later when shutting down the system, we'll simply instruct
<strong>s6-svscan</strong> to exec into <code>aa-stage3</code>, which will use <strong>aa-stop</strong>(1) to stop
all services. As a last step, it will pivot into <code>/run/initramfs</code> (putting the
old root filesystem into <code>/root-fs</code>) and exec into <code>/shutdown</code> with the same
argument it received from <strong>s6-svscan</strong> ("halt", "reboot" or "poweroff").</p>
<p>This last script's job is to make sure everything is down, umount the old root
filesystem and properly do the expected action (e.g. trigger the reboot).</p>
<p>This could be done by e.g. having a oneshot service with only a <code>stop</code> script,
that populates <code>/run/initramfs</code> with what's needed to properly perform the last
operations, such as umounting <code>/root-fs</code>. In fact, <strong>aa-terminate</strong>(1) would be
pretty useful in such cases, to close/umount all that can be.</p>
<p>Or; -- A couple more scripts are actually provided by anopa, namely <code>aa-stage0</code>
and <code>aa-stage4</code>, which are intended to be used as <code>init</code> and <code>shutdown</code> inside
the initramfs, should you want to do that.</p>
<p>That way your initramfs works quite similarly to the actual system, with a call
to <strong>aa-start</strong>(1) on boot to set thing up (though there can only be oneshots,
obviously), and a matching call to <strong>aa-stop</strong>(1) when shutting down to properly
shut down/close things.</p>
<p>This means the rootfs from the initramfs should be kept around, so we can
actually pivot back into it at the end of <code>aa-stage3</code> -- then we can properly
stop everything. (Note that <code>aa-stage4</code> actually does call <strong>aa-terminate</strong>(1)
after <strong>aa-stop</strong>(1) to handle the unexpected.)</p>
<h3>Real-life example: a bootable ISO</h3>
<p>As a way to show how a system can be set up and work using anopa, let's build a
bootable ISO, using anopa in the initramfs as well. To make this work, this is
what will need to happen:</p>
<p>In the initramfs, our init (<code>aa-stage0</code>) will be tasked to mount the root
filesystem. Since we'll likely need <code>/dev</code>, <code>/proc</code> and <code>/sys</code> to be mounted
so everything works fine, we'll do that, and right before being done - and
switching to the new root - we'll move them into <code>/root-fs</code> -- This mean they'll
already be mounted when the system's init (our <code>aa-stage1</code>) starts, so we won't
have to (re)do it then.</p>
<p>We will also mount <code>/run</code> and move it similarly, to make things simpler. For
instance, doing so will allow us to mount bind the rootfs (from the initramfs)
into <code>/run/initramfs</code> so we can pivot back into it when shutting down.</p>
<p>Now, mounting the root file system: This will be done by mounting the "boot
partition" where we'll find a <code>root-fs.squashfs</code> file. This file will then be
mounted (ro) on <code>/run/squashfs</code>, a tmpfs will be mounted on <code>/run/overlay</code> and
an overlay (overlayfs) will be mounted as <code>/root-fs</code> using the <code>/run/squashfs</code>
as lower end and <code>/run/overlay</code> as upper end, thus providing us with a rw file
system.</p>
<p>Again, mouting the "internals" into <code>/run</code> will allow us to get them back when
shutting down, so we can umount everything properly.</p>
<p>We'll then exec into the main init, our <code>aa-stage1</code> script, which will start
<code>aa-stage2</code> and exec into <strong>s6-svscan</strong>. The former will then start the actual
system initialization (via <strong>aa-start</strong>(1)), assuming all the virtual APIs are
already mounted, as they should be. And in this case, so will be <code>/boot</code> since
we had to in order to access our squashfs file, so we'll just move it (under
<code>/root-fs</code>) so that's already taken care of as well.</p>
<p>And as said before when shutting down, our <code>aa-stage3</code> will stop all services
via <strong>aa-stop</strong>(1) and eventually pivot into <code>/run/initramfs</code> -- where
<code>aa-stage4</code> will find back everything (notably in <code>/run</code>) so calling
<strong>aa-stop</strong>(1) can properly umount/close everything as needed (including
<code>/boot</code>)</p>
<p>Similar setup could be used on an "actual" system (as opposed to live ISO) to
e.g. luksOpen and mount the encrypted root fs during stage 0, and umount & close
during stage 4. (Though in such cases, <code>/boot</code> is likely to be (u)mounted in the
system, stages 1 & 3, not the initramfs.)</p>
<h3>Unusual system configuration</h3>
<p>anopa starts & stops services, and those services can be scripts or even
binaries. It's all up to you, but in my case I'm going for execline scripts
mostly, so that's what we'll use here.</p>
<p>Similarly, I've decided to make my systems, including this one, use an
"uncommon" scheme for some system configuration, notably there's no <code>/etc/fstab</code>
nor <code>/etc/crypttab</code> (because parsing), and instead things are set up via small
text files.</p>
<p>Specifically, definitions of file systems is done via files <code>device</code>,
<code>mountpoint</code>, <code>fstype</code> and optionally <code>options</code> to be found in
<code>/etc/mount/$INSTANCE</code> where $INSTANCE is meant to be a name, used as instance
of services such as <code>mount@</code></p>
<p>For example, to have e.g. <code>/dev/disk/by-label/foobar</code> be mounted as ext4 in
<code>/boot</code> one would use a service <code>mount@boot</code> and set up a few files like so:</p>
<pre><code>mkdir -p /etc/mount/boot
cd /etc/mount/boot
echo /dev/disk/by-label/foobar > device
echo ext4 > fstype
echo /boot > mountpoint
</code></pre>
<p>Similarly, for the use of encrypted devices a service <code>crypt@</code> can be used, and
configuration done via files <code>device</code> and optionally <code>type</code>, <code>name</code>, <code>offset</code>
and <code>keyfile</code> in <code>/etc/crypt/$INSTANCE</code> (where $INSTANCE would usually be the
same as used for <code>mount@</code>, to make things clear & simple).</p>
<p><code>type</code> must be a valid type for <code>cryptsetup</code>, defaulting to "luks". <code>name</code> must
contain the name to be used, else "luks-$INSTANCE" will be used. <code>offset</code> can
be used to specify an offset (i.e. <code>--offset $OFFSET</code> where $OFFSET is the
file's content, will be given to <code>cryptsetup</code>) Lastly <code>keyfile</code> must be the path
to the keyfile to be used (via <code>--key-file</code> option) else you'll be prompted for
a passphrase.</p>
<p>The <code>offset</code> option can be notably useful for encrypted swap partitions, when
you create a LUKS container first, then remove all keys; Point being to give
that partition a valid header and therefore a UUID, so it can be reliably used.
Then using an offset of 4040 allows to preserve said header (with type "plain"
and keyfile "/dev/urandom" as usual for encrypted swap partitions).</p>
<p>Again, none of this is part of anopa, but services I've made for my own needs,
and will be sharing & using here (well, <code>mount@</code> at least, our ISO won't have
any encrypted devices). You could very well stick to using <code>/etc/{fs,crypt}tab</code>
with appropriate services instead, or do things completely differently, this is
merely an example of how things can be done.</p>
<h3>Order, order, order</h3>
<p>As mentioned elsewhere, anopa handles dependencies and will order services as
needed. Of course, "as needed" means as you've told it to do, via service
definitions. What I like to try to do is have most services be ordered against a
service <code>sysinit</code>.</p>
<p>This service is an empty one, i.e. a oneshot service with no scripts at all, and
is therefore only used for ordering other services. If all services have either
<code>before/sysinit</code> or <code>after/sysinit</code> then it can help ensuring a bunch of
essential services are run first, and then the rest. Just make sure to ask the
service (sysinit) to be started on boot, as ordering directives for unneeded
(i.e. not started/stopped) services are obviously ignored.</p>
<h3>Creating an initramfs</h3>
<p>Another thing that's not part of anopa per-se, but we'll need here, is creating
an initramfs. Being an Arch user, this will be done using <code>mkinitcpio</code> of
course.</p>
<p>What we'll do is replace the usual hooks such as "base" "keymap" or "udev"
with "busybox" to install our busybox, "aa-base" to install the minimum required
for things to work, and "aa-repo" which will create the runtime repository for
the initramfs and add the needed configuration/binaries/modules.</p>
<p>This is also done by using a file <code>mkinitcpio.hook</code> that must exist in the
service definition directories, and can contain the 2 following functions:</p>
<ul>
<li><p><code>hook_service</code> : ran when the service is used. For services that are
instantiated, ran only once.</p></li>
<li><p><code>hook_instance</code> : ran only for instantiated services, one per instance and
with the instance name as first argument.</p></li>
</ul>
<p>Both of those shall use the usual mkinitcpio's functions (<code>add_binary</code>, etc) to
fill the initramfs as needed. Should the service not need anything to be added
to the initramfs, an empty file will do (absence of the file will generate a
warning during initramfs creation).</p>
<h3>mdev, not udev</h3>
<p>As if to complicate things further, I'm also not gonna use udev. Similar reasons
to why I changed init system have me wishing not to use udev anymore, and
instead of going for one of the forks or similar projects, I've decided to have
to figure out how all this works, and come up with my own helper scripts to
handle things.</p>
<p>So that's what will happen here, with a service <code>devd</code> that connects to the
netlink interface (using <code>s6-devd</code>) and launches an helper program on uevents.
Said helper is no other that busybox's <code>mdev</code> which will be complemented with
some scripts of our own to e.g. create symlinks in
<code>/dev/disk/by-{{uu,}id,label}</code></p>
<p>This is also why we're building our own busybox, because we need mdev (though
not in the initramfs).</p>
<h3>ISO maintenance</h3>
<p>Now that you (hopefully) start to have an idea of what we're trying to do, let's
see how it will actually be done. Truth be told, having a bootable ISO at hand
is something I've always considered pretty useful, and that's why it was one of
the first things I did after installing Arch Linux.</p>
<p>I did so using the <code>archiso</code> scripts and following instructions from the wiki,
and while it worked - I did make myself a bootable ISO with a live system
containing the few extra packages/configuration I wanted - it wasn't the easiest
procedure, I felt.</p>
<p>Not that it was especially complicated, but it had to do with writing a list of
packages to install in a file, and to add extra files, they needed to be all in
one place, then a script needed to be written; A script that would ran on boot,
and whose purpose was to move files to the right places, set permissions, etc</p>
<p>In fact, to have a user account on the system, it also worked via a script
creating said user on boot as well. I'm not sure why things were done this way,
nor did I check whether things changed since then, but I know this is why I made
myself a bootable ISO, and then that was it.</p>
<p>It wasn't maintained/updated, and until a few days ago when I decided to make my
own anopa-powered ISO, that good old ISO from a few years back (and the
pre-systemd era, in fact) was still in use.</p>
<p>All that to say, one of my goal was also to have a "better" system, something
where I could easily work on, maintain, update the ISO without too much trouble.</p>
<h4>How it works</h4>
<p>So this is how it'll work: We'll need a folder with 2 things :</p>
<ul>
<li>a file <code>boot</code> : "raw" block device, partitioned, containing our <code>/boot</code> fs. It
will also have an MBR w/ syslinux installed, so we can use it as disk image
when booting qemu, for testing purposes.</li>
<li>a folder <code>chroot</code> : the root fs of the system, save for <code>/boot</code> This is what
we'll squash into our <code>root-fs.squashfs</code></li>
</ul>
<p>That way we can very simply work on the system: we mount the partition from
<code>boot</code> on <code>chroot/boot</code> and then we use pacman to install/update the system, we
can chroot in there and do whatever we need to, etc</p>
<p>We can also simply start a qemu VM using the <code>boot</code> file as disk to check
things, without the need to make the ISO file (though obviously making the
squashfs file is required).</p>
<h3>3, 2, 1... go!</h3>
<p>Alright, let's do it. As said before, I'm using Arch Linux, and this assumes
you're running one as well. This first part is a basic Arch install procedure,
feel free to adjust/skip as you wish (make sure to check the last bit, though,
regarding boot loader installation).</p>
<p>First, let's create the <code>boot</code> file and set things up:</p>
<pre><code>truncate -s 420M boot
cfdisk boot # and make one bootable partition
sudo losetup -P /dev/loop0 boot
sudo mkfs.ext4 -L THIS-LAND /dev/loop0p1
sudo mkdir -p chroot/boot
sudo mount -B chroot chroot
sudo mount /dev/loop0p1 chroot/boot
</code></pre>
<p>So we will have to use a label, obviously, since that's all we'll have when
booting from a CD to identify our <code>/boot</code> partition. I've decided to call mine
"THIS-LAND" because why not. Of course this isn't right per ISO9660 specs
(because of the dash) and we'll get a warning when making the ISO. I decided I
didn't care, feel free to use any other label, even one compatible with the
specs.</p>
<p>You'll note we mount chroot on itself, this is so later on the root of the
chroot is seen as a mountpoint, helps e.g. with mkinitcpio.</p>
<p>Now on to create some obligatory directories:</p>
<pre><code>sudo mkdir -m 0755 -p chroot/var/{cache/pacman/pkg,lib/pacman,log} chroot/{dev,run,etc}
sudo mkdir -m 1777 -p chroot/tmp
sudo mkdir -m 0555 -p chroot/{sys,proc}
</code></pre>
<p>Mount the apis and let's install some "base system":</p>
<pre><code>sudo mount -B /dev chroot/dev
sudo mount -B /proc chroot/proc
sudo mount -B /sys chroot/sys
sudo mount -t tmpfs -o mode=0755,nosuid,nodev tmpfs chroot/run
sudo mount -t tmpfs -o mode=1777,nosuid tmpfs chroot/tmp
sudo pacman -r chroot -Sy bash bzip2 coreutils cryptsetup device-mapper \
diffutils e2fsprogs file filesystem findutils gawk gcc-libs gettext \
glibc grep gzip inetutils iproute2 iputils less licenses linux \
logrotate man-db man-pages pacman pciutils perl procps-ng psmisc sed \
shadow sysfsutils tar texinfo util-linux which
</code></pre>
<p>This selection of packages is mine, feel free to use one that fits you best, or
just go for the whole "base" group even. Note that this isn't a minimum
required, e.g. it includes cryptsetup which isn't required for what we're doing.
But my systems are encrypted, so I need to be able to access them from the ISO.</p>
<p>In typical install trope, let's copy keyring & mirrorlist:</p>
<pre><code>sudo cp -a /etc/pacman.d/gnupg chroot/etc/pacman.d
sudo cp -a /etc/pacman.d/mirrorlist chroot/etc/pacman.d
</code></pre>
<p>Time to set up some basic config now - feel free to adjust to your needs ofc :</p>
<pre><code>sudo sed -ie 's/^#\(en_US.UTF-8\)/\1/' chroot/etc/locale.gen
sudo chroot chroot locale-gen
echo LANG=en_US.utf8 | sudo tee chroot/etc/locale.conf
echo KEYMAP=fr-latin1 | sudo tee chroot/etc/vconsole.conf
sudo ln -s /usr/share/zoneinfo/Europe/Paris chroot/etc/localtime
echo this-land | sudo tee chroot/etc/hostname
</code></pre>
<p>And install our bootloader, since as mentioned earlier we want the <code>boot</code> file
to be usable as disk in a VM:</p>
<pre><code>sudo pacman -r chroot -S syslinux
sudo chroot chroot sh
cp -r /lib/syslinux/bios/*.c32 /boot/syslinux/ # or just those needed
extlinux -i /boot/syslinux
dd if=/lib/syslinux/bios/mbr.bin of=/dev/loop0 bs=440 count=1
touch /boot/syslinux/SYSLINUX_AUTOUPDATE # for "auto-update"
cp /lib/syslinux/bios/isolinux.bin /boot # for xorrisofs
exit
vim chroot/boot/syslinux/syslinux.cfg # APPEND init=/lib/anopa/aa-stage1
</code></pre>
<h4>Now it gets specific</h4>
<p>At this point we've installed a basic system under <code>chroot</code> -- Time to dive into
our own init system and whatnot.</p>
<p>It starts with a few packages:</p>
<pre><code>sudo pacman -r chroot -S binutils execline-musl-git busybox-musl-jjk \
s6-musl-git s6-devd-musl-git anopa-musl-git
</code></pre>
<p>I'm building my own busybox so it can be statically linked to musl, and also so
it includes mdev since we'll need it (remember: no udev). Other packages are
also built statically against musl, though you could do it differently; All
PKGBUILDs can be found on <a href="https://github.com/jjk-jacky/abs" title="PKGBUILDs - jjk-jacky@github.com">my
github</a>, or
in the AUR (Noting that I don't maintain any s6-* packages there, not that it
should matter).</p>
<p><code>s6-devd</code> is a small package containing only the <code>s6-devd</code> tool I use to connect
to the netlink interface and process uevents (or, send them to mdev). You could
also just use <code>s6-linux-utils</code> if you need/want the other tools.</p>
<p>And of course if you intend to use udev, you don't need it nor to get mdev in
busybox.</p>
<p>Now, to help speed things up, I've made a few extra packages. First off is the
mdev configuration & helpers, then some of those aforementioned services.</p>
<pre><code>sudo pacman -r chroot -S lila-mdev lila-system-services lila-services
</code></pre>
<p>Relevant PKGBUILDs can be found on github as usual. <code>lila-services</code> should only
contain "generic" servicedirs that relate to specific packages/daemons (e.g.
getty, consolekit, dbus, openvpn, nginx, etc), whereas <code>lila-system-services</code>
contains mostly oneshot services for system initialization, and those can be
pretty custom made. This is for example where the previously mentionned <code>mount@</code>
would be found, as well as a few others. It also contains the mkinitcpio hooks
we'll use to build our anopa-based initramfs.</p>
<p>Feel free to look into those and see what services look like. As said earlier,
most of them are execline scripts, all are examples - you can use them, or not.</p>
<p>It should be mentioned that those of course go with s6-devd+mdev and no udev,
but also that there's a <code>log-events</code> service, which comes with a few others it
needs (such as <code>fdholdingd</code>), which are all meant to allow to have loggers send
some data to this <code>log-events</code> service (via writing to their stdout, connected
to the log-events fifo), as done in the default logger <code>log</code>.</p>
<p>This relies not only on using <code>s6-log</code> as logger, but a patched version at that.
(Patch is here) to include prefix when writing on stdout. It might not be of use
to everyone, it certainly won't be for us here, more on that in a minute.</p>
<h4>Configuration time</h4>
<p>Now to keep helping things, I've also made a couple of tarballs that will come
in handy. First off is <a href="./lila-lazy.tar.xz" title="lila-lazy">lila-lazy</a> which
contains a bunch of configuration that I basically use as base on every
anopa-based system I build.</p>
<p>This notably includes everything that should be needed for the initramfs, and
most things for a basic system init. Afterwards, you'll usually only need to go
edit a couple of files - <code>/etc/mount/{boot,root-fs}/device</code> - to set them up
properly. (Maybe also fill things in <code>/etc/crypt/</code> if you were to use encrypted
devices.)</p>
<p>We'll need to make some adjustments from that, and the services from
<code>lila-system-services</code> as well.</p>
<p>Indeed, if our case things are a bit different, and slightly more complicated
when it comes to the initramfs, since we have quite a few specific things to do
there. So here comes <a href="./lila-this-land.tar.xz" title="lila-this-land">lila-this-land</a>
which contains all the adjustments we need to get our configuration ready.</p>
<p>This includes new files, updated files, and a few files whose name starts with a
dash, indicating that the original file must be removed. Those are located in
<code>etc/anopa/{enabled,listdirs/onboot}</code> and require manual attention. As I said,
a file starting with a dash means both it and its no-dash counterpart shall be
removed. There's also a special case with <code>+kmsgd</code>, which means the folder (from
<code>lila-lazy</code>) should be removed, and the (empty) file renamed to <code>kmsgd</code></p>
<p>So extract both tarballs in <code>chroot</code> then take care of the few files to remove
(and the kmsgd case), and that's it. Pretty simple, uh?</p>
<p>You'll notice some extra services, e.g. to mount the squashfs and the overlay.
There's also <code>mdev-sr</code> which is used to run our mdev helper that creates
symlinks on the CD-ROM, so if we're actually booting from a CD, we can find
<code>/boot</code> with our usual symlink in <code>/dev/disk/by-label</code>.</p>
<p>A service <code>boot-fstype</code> is there to get the fstype of said device, before we
mount it on <code>/boot</code>, and update the <code>/etc/mount/boot/fstype</code> file. This is
because while it would be iso9660 when booting a CD/ISO, when using the <code>boot</code>
file as virtual disk, it will be ext4. And because mounting happens with
<code>aa-mount</code> which doesn't have an "auto" mode, we need to do this.</p>
<p>Another extra service is <code>memdisk</code> and it is there to support the case of
booting the ISO file from syslinux. Because that's actually how I'll use the
final ISO in the end myself: booting it from syslinux, via memdisk. And in that
case, we need this service to ensure we can find, and mount, <code>/boot</code></p>
<p>With all that done, a few extra directories need to be created, for our logging
system to work:</p>
<pre><code>sudo chroot chroot
mkdir /var/log/{boot,dbus,devd,kmsgd,syslogd,uncaught-logs}
useradd -r -g log -s /bin/nologin -d /var/log log
chown log:log /var/log/{boot,dbus,devd,kmsgd,syslogd,uncaught-logs}
exit
</code></pre>
<p>After that, we're almost done.</p>
<h4>mkinitcpio time</h4>
<p>Only thing left, to get the system ready at least, is actually build the
initramfs. So we need to edit <code>mkinitcpio.conf</code> to set proper hooks, e.g:</p>
<pre><code>HOOKS="busybox aa-base aa-repo block filesystems keyboard"
</code></pre>
<p>We can also remove the 'fallback' from <code>linux.preset</code> (since we don't use
autodetect), <code>rm chroot/boot/initramfs-linux-fallback.img</code>, then rebuild; and
that's our anopa-powered initramfs.</p>
<h4>Squashing...</h4>
<p>The root filesystem is now ready. Of course, for this whole thing to work, we
need to squash it into a file, so let's do just that, making sure to exclude
<code>/boot</code> of course:</p>
<pre><code>sudo mksquashfs chroot root-fs.squashfs -noappend -wildcards -e boot/'*'
sudo mv -f root-fs.squashfs chroot/boot
</code></pre>
<p>Obviously, we should have umounted the apis <strong>before</strong> squashing:</p>
<pre><code>sudo umount chroot/{dev,proc,sys,run,tmp}
</code></pre>
<h4>It boots!</h4>
<p>At this point, it should be ready to boot. And using qemu and the <code>boot</code> file as
hdd, it should indeed do the trick:</p>
<pre><code>qemu-system-x86_64 -m 1G -drive file=boot,index=0,media=disk,format=raw
</code></pre>
<p>Now all that's left is actually making an ISO.</p>
<h4>Finally, an ISO is brought into the world.</h4>
<p>This final step is actually pretty simple, all it takes is run xorrisofs with
the proper arguments. Make sure to set -volid to whatever the label of your
<code>/boot</code> fs is, otherwise expect breakage.</p>
<pre><code>sudo xorrisofs -output this-land.iso -volid THIS-LAND \
-iso-level 2 -allow-lowercase -omit-period \
-eltorito-boot isolinux.bin -eltorito-catalog boot.cat \
-no-emul-boot -boot-load-size 4 -boot-info-table \
-isohybrid-mbr chroot/lib/syslinux/bios/isohdpfx.bin \
chroot/boot
</code></pre>
<p>Voilà! We now have a bootable ISO, with a system using anopa as init system as
well as in the initramfs.</p>
Has Arch lost its Way?2015-04-10T00:00:00+00:00http://jjacky.com/2015-04-10-has-arch-lost-its-way<p>A few years back, as I wanted to switch OS and enter the world of Linux, I
needed to pick a distribution (or first, figure out what makes a distribution,
what sets one apart from another).</p>
<p>Did some research, downloaded and tried a few ISOs, but quite honestly this
wasn't a deciding factor in the end. No, what really helped me make up my mind
was doing a bunch of reading, learning the "principles" of a distribution.</p>
<p>And the reason I eventually went with Arch Linux, was what's known to Archers
as <a href="https://wiki.archlinux.org/index.php/The_Arch_Way" title="The Arch Way @ ArchWiki">The Arch Way</a>,
which is said to "illustrate the principles and philosophy of Arch Linux."</p>
</p>
<h3>The Arch Way: the principles and philosophy of Arch Linux</h3>
<p>It was what attracted me to Arch, and I certainly haven't regretted it since.
I've been pretty pleased with my experience so far, and as one could have
expected, thanks to those principles & philosophy, Arch is the perfect
distribution for one who wants to learn about his system.</p>
<p>Now I want to talk about certain changes that occurred, and yes, I'll talk about
systemd. But let's preface this right now: this isn't about systemd, it is about
Arch, and whether the two projects are "compatible."</p>
<p>This will not be about what you think of systemd: whether you like it or not,
whether you think it's the greatest thing since sliced bread, or will be the end
of GNU/Linux distributions as we know them, doesn't matter.</p>
<p>systemd is what it is, and I believe what it is isn't a good fit for Arch Linux.
Plenty has been said about systemd, why it is great, or why it is a move in the
wrong direction. My personal opinion is of the later, but I believe this isn't
relevant.</p>
<p>The Arch Way mentions <strong>simplicity</strong> and <strong>code-correctness over convenience</strong>
as some of its core principles, as well as being <strong>user-centric</strong> instead of
user-friendly; And I feel that ideally this wouldn't only apply to how Arch
packages software, but also in the choice made in which softwares to
package.</p>
<p>This is particularly important for core element of the system, especially if
only one will be officially supported. With only one init system to have
official support, picking a solution that shares the same principles seems like
a good thing.</p>
<h3>No questions when you know your system...</h3>
<p>Let's say you install a brand new system. One thing that I liked with Arch, is
that there were questions one needed not to ask oneself. For example, you didn't
need to ask yourself, and research, whether or not there was an sshd running or
not.</p>
<p>Why not? Because you knew already: either you took the time and did the work,
either you installed and configured an sshd, or there wasn't one. Because if you
haven't done the work, certainly no one else has done it for you; it is <u>your</u>
system, you are not just a user, but the administrator. So, you were given
"complete control and <u>responsibility</u> over the system."</p>
<p>You don't need to ask whether there's a firewall active or not, because again
either you set it up, or there isn't any. No question, no uncertainty. This is
the Arch Way.</p>
<p>Now of course systemd isn't gonna install an sshd behind your back, but did you
know that there was a tmpfs mounted on <code>/tmp</code> even though you never asked for
it? It's not in your fstab, you didn't ask for this anywhere, but systemd did
it. Now you can turn it off, I'm sure the systemd enthusiasts will be happy to
explain how easy it is to create an aptly-named symlink to <code>/dev/null</code> to
disable it, but that's missing the point.</p>
<p>And if you put files in there, be aware they might be removed after a while,
because there's a thing called <code>systemd-tmpfiles-clean</code> that will take care of
it. Again, you didn't have to set it up, it's done for you, it's the systemd
way.</p>
<p>I for one am very happy I first came to Arch Linux, and installed it, back when
there was a BSD-like init system still in place. Not because I have some love
for a central <code>rc.conf</code> file, or because I dislike systemd and its symlinks in
half a dozens places or so, but simply because back then it followed the Arch
Way:</p>
<ul>
<li><p>it was <strong>simple</strong>, clean code path that one could look at to figure out what
would happen, when and why. Try to do that with systemd, and you'll see how
much complexity is at play here. And the more it goes, the more it does, the
more complex it grows.</p></li>
<li><p>it was <strong>user-centric</strong>, you had to set something up for it to be. There might
not have been pretty user-friendly tools to list services with colors or the
last lines from related logs, but you were the one to clearly decide what
would run and when. If you didn't asked for dbus to start on boot, it
wouldn't. If you didn't ask for a tmpfs to be mounted on <code>/tmp</code> in your fstab,
there wouldn't be one.</p></li>
</ul>
<p>I mentioned the installer earlier, I mean I didn't really but let's pretend I
did: back in those days of BSD-like init system, Arch had an installer;
Nowadays, it doesn't.</p>
<p>If you're familiar with Arch, you know this wasn't motivated by coming up with a
solution that would be simpler, or more in line with the Arch Way, it was simply
that the project was unmaintained and no one willing to step up and invest the
time & work needed to keep it up-to-date, and a replacement deemed simpler - at
least to maintain - was used instead.</p>
<p>At the time, many complained about the lack of an actual installer, asked for it
to be brought back, and so on. I for one thought it was a positive change. It
surely can be "scarier" to new users, especially if they're not familiar with
Arch or even Linux, but once you've moved past that initial reaction, it's all
good.</p>
<p>The new scripts come, as always, with great documentation on the wiki, and are
exactly aligned with the Arch Way: <strong>providing tools to put <u>you</u> in control</strong>.
And installing your system that way isn't that hard, it's a few commands to type
instead of choices to make in a menu, but it's about the same, only better.</p>
<p>Better because it forces you to know what's going on, and what needs to be done
and set up. I'd say you can't go though an installation now and not know what
pacman is, but I'm sure you could before. I believe it adheres even more to the
Arch Way than the old installer did.</p>
<p>This change, and the change for systemd, are - to me - going in opposite
directions. The former puts the user even more in control, providing tools and
letting one decide and set things up. The later "takes away" control for
providing more user-friendly interfaces, and comes with pre-established choices
that one don't even need to know about, until one finds out about them and need
to disable them.</p>
<h3>Other principles: Openness & Freedom</h3>
<p>The Arch Way also states that "<strong>by keeping the system simple, Arch Linux
provides the freedom to make any choice about the system.</strong> You can use the
bootloader you want, the DE you want, if you even want one.</p>
<p>All of that remains true, except that more and more packages are now
systemd-dependant. So even if you want to use another init system - noting that
unlike with DEs or bootloaders, there will only be one in the official repos -
you'll probably still need to have systemd installed, and some packages might
need to be recompiled to get rid of that dependency altogether.</p>
<p>And it doesn't stop there, because while the systemd developers claim it is
getting adopted by lots, they work hard on <u>forcing</u> it. I don't doubt they have
technical reasons to justify that logind requires systemd as PID1, as they'll
push for other projects to require logind, for technical reasons of course.</p>
<p>But in the end, all it does is reduce choice for most users. It doesn't go along
with the beautiful idea of openness & freedom as described in the Arch Way.</p>
<p>Now imagine you're writing an init system, and you want daemons to have a way to
tell said init system/service manager that they're ready. Because knowing a
service is up is easy (yes, there might be some major over-simplifications here,
but it doesn't matter for what I'm trying to say): process was launched, we have
its PID, it is up; But when will it be ready?</p>
<p>You could create an API specific to your init only, and push on upstream
projects so that they use your API, because you have the man power to do so, and
soon we have, say, PHP that can let systemd know when it's ready. But of course
it's via systemd-specific API so it won't work with any other init system, and
to build PHP you need systemd, even though why such a portable general-purpose
scripting language would have a dependency of any kind of an init system is
beyond me.</p>
<p><strong>Or.</strong> Or you could have asked for daemons to send their data (to let know
they're ready) by simply writing to a given file descriptor. That means any
upstream project could do that without the need for any new dependency, because
writing to a file is something they should all be able to do already. And
creating a pipe and reading an fd is a pretty generic, portable thing that could
be implemented in about any other init system out there.</p>
<p>So you could have done it so it benefits the entire ecosystem, so all init
systems could benefit from it, and daemons could easily add support for it, and
it would work for any and all init systems supporting it.</p>
<p>But that's not the systemd way. Instead they do systemd-only APIs, they want to
have one big thing that does more and more, and I'm sure there'll be technical
reasons for udev to add support for kdbus, and then to require it (one way or
another), which will likely lead to udev requiring systemd as your PID1. Not a
bright future of openness & freedom if you ask me...</p>
<h3>So whose system is this again?</h3>
<blockquote>
<p>As Judd Vinet, the founder of the Arch Linux project said: "[Arch Linux] is
what you make it."</p>
</blockquote>
<p>That is a great thing, one that is still true today, but I believe that it
becomes harder and harder with the adoption of systemd as only official init
system. And seeing how things evolve with systemd, it will only get harder.</p>
<p>This may be great for people making distributions with another user type in
mind, people who want nice, easy things to use and aren't interested in knowing
how it works or how to configure things to one's specific needs/preferences.
It feels to me that wasn't Arch, or its goals.</p>
<p>systemd developers (which include Arch devs as well, as least via Tom Gundersen
in the linked post) have <a href="http://0pointer.net/blog/revisiting-how-we-put-together-linux-systems.html" title="Revisiting How We Put Together Linux Systems">ideas for the
future</a>
for sure, I'm just not sure I share the same visions they do, and I certainly
don't like the way they push for it at the expense of everything else.</p>
<p>It feels to me that isn't the Way of Arch, that Arch was targeting the
competent GNU/Linux users, focusing more on being user-centric than
user-friendly, giving you tools to build <u>your</u> system the way <u>you</u> want, not
forcing on you someone else's vision. And that's what I liked, and why I picked
it. But as it goes, I wonder: has Arch lost its Way?</p>
<p>I'm sure many, starting with Arch developers, will disagree. But in the mean
time, I'll look for a way to use a different init system myself, to begin with.</p>
kalu 3.0.0 released2014-12-20T00:00:00+00:00http://jjacky.com/2014-12-20-kalu-3.0.0-released<p>A new version of pacman (4.2) has been released, introducing some API changes to
ALPM. To go along with it, version 3.0.0 of kalu has been released, with the
usual few fixes as well as some new features.</p>
<p>If you've been using branch <code>pacman-next</code> you're already familiar with said
changes, mainly the fact, using kalu's updater, it can now keep track of any
<code>.pacnew</code> and <code>.pacorig</code> file created during a sysupgrade, and will made such
information available as variable <code>$PACFILES</code> in the post-sysupgrade</p>
<p>This can be used to e.g. perform 3-way merge of .pacnew files. See man page for
more, as well as <a href="/2014-07-23-better-pacnew-handling-with-the-next-kalu/" title="Better pacnew handling with the next kalu">this
post</a>
for an example of use.</p>
</p>
<p>Other changes include:</p>
<ul>
<li><p>simulation: Add button to download packages only</p></li>
<li><p>kalu-updater: Add ability to abort a transaction (e.g. downloading packages)</p></li>
<li><p>Keep temporary databases around to speed things up/save bandwidth</p>
<p>Instead of removing the tmp dbs after the checks/simulation, they're now kept
around. That way, for the next checks/simulation they can be re-used and might
already be up-to-date (even though the system's ones aren't).</p>
<p>If the DB path changed or the folder is gone they're just re-created, and of
course it is cleaned up when exiting kalu.</p></li>
<li><p>Add KDE's StatusNotifierItem support</p>
<p>With Plasma Next KDE doesn't support the good old xembed systray, and so
GtkStatusIcon are "useless."</p>
<p>Adding a new configure option <code>--enable-status-notifier</code> to enable support of
KDE's interface via our small library, <a href="/statusnotifier" title="statusnotifier: KDE's Status Notifier Item as GObject">statusnotifier</a>.</p></li>
<li><p>Use <code>$XDG_CONFIG_HOME</code> instead of <code>$HOME/.config</code></p>
<p>Likely to not change what's actually used, since it'll default to the same
value should <code>$XDG_CONFIG_HOME</code> not be set, but it's better/proper/allows user
customization.</p></li>
<li><p>Add config tweaks to define colors used in updater. Useful in case (default)
colors do not work well with the theme.</p></li>
<li><p>Add repo name in a column on kalu updater, as well as available via <code>$REPO</code> in
package template for updates & watched packages.</p></li>
<li><p>simulation: Show ALPM log messages (e.g. warnings, etc)</p></li>
<li><p>Preferences: Unchecking a template field wasn't always remembered</p>
<p>When unchecking a template field (to have it use its fallback value) it
wouldn't be remembered when said field has a hard-coded default value in kalu,
which would then be restored. (E.g. the Title field for packages not found in
the AUR)</p>
<p>Now such fields are saved to the .conf file without a value (e.g. "Title=") to
preserve their disabled/falling-back state.</p></li>
<li><p>Force icon size on notifications</p>
<p>Since GTK+3.14 the icon size might not be the requested one, so force it if
necessary.</p></li>
<li><p>Add a 16x16 logo for use in menus/buttons</p>
<p>Because GTK+3.14 won't resize the 48x48 one anymore, and gives us extra large
icons on menus/buttons instead.</p></li>
<li><p>Some other fixes (see git log for details)</p></li>
</ul>
<h3>Downloads and whatnot</h3>
<p>Thanks to all those who reported bugs or suggested features; With contributions
from EmanueL Czirai, and Kolibry for the updated French translation.</p>
<p>See <a href="/kalu" title="kalu: Keep Arch Linux Up-to-date">kalu</a> for longer descriptions & all the links you should need.</p>
<p>Note that on Arch Linux, pacman-4.2 is only in testing for now, as such the
PKGBUILD in the AUR hasn't yet been updated. (You can find an up-to-date one
<a href="https://github.com/jjk-jacky/abs/tree/master/kalu" title="kalu PKGBUILD @ github.com">here</a>.)</p>
<p>And of course, as always, new bug reports, suggestions or any other form of
constructive criticism is very much welcome.</p>
Use tool of your choice to perform IO operations in donnatella2014-12-13T00:00:00+00:00http://jjacky.com/2014-12-13-use-tool-of-your-choice-to-perform-io-operations-in-donnatella<p>A few changes have just been pushed to branch <code>next</code> of donnatella, introducing
some changes when it comes to IO operations (i.e. copy/move/delete files).</p>
<p>Starting at the top: donnatella doesn't perform any such IO operations itself.
This isn't a not-yet-implemented feature but a design choice: there are plenty
of tools which specialized in such things, no need to re-invent the wheel, let's
use the existing ones instead!</p>
</p>
<p>So when you copy/move/delete files in donna, it will actually run cp/mp/rm to
perform the operation (parsing the output to determine what was done/ask
confirmations/etc).</p>
<p>This is good, but quite limited. In fact, when it comes to GUI operations one
might expect to have, in case e.g. a file already exists, a detailled window
with information about both files, and possibilities to skip, overwrite, rename,
etc.</p>
<p>None of that is currently possible, though - truth be told - it's on a todo list
of mine (though not as part of donna, but an external tool).</p>
<h3>IO Engines</h3>
<p>To try to maybe help and offer more possibilities, donna now introduces the
notion of IO engines, giving you the ability to choose which one to use.</p>
<p>New options <code>providers/fs/engine_{copy,move,delete}</code> have been added, and must
be set to the name of the IO engine to use to perform copy, move or delete
operations respectively.</p>
<p>By default, donna uses the <code>basic</code> IO engine, the one "wrapping" cp/mv/rm as
needed. But another one is now avaialable as well, called <code>exec</code></p>
<h3>IO Engine "exec"</h3>
<p>This engine simply allows you to specify a command line to be executed to
perform the corresponding IO operation. Therefore, you can now use about any
tool you want to perform IO operation in donna, e.g. use rsync to copy files.</p>
<p>As you may know, in donna an IO operation comes from command <code>nodes_io()</code> where
the source(s), destination (if any) and type of operation (copy/move/delete) are
specified.</p>
<p>Optionally, for copy/move operation with a single source, a new name can be
specified, to rename the item as it is copied/moved.</p>
<p>The command-line to be used when IO engine exec is used are defined under
<code>providers/fs/ioengine-exec</code> and are named:</p>
<ul>
<li><code>copy_cmdline</code> : for copy operations</li>
<li><code>copy_cmdline_new_name</code> : for copy operations with a new name specified
(implies a single source)</li>
<li><code>move_cmdline</code> : for move operations</li>
<li><code>move_cmdline_new_name</code> : for move operations with a new name specified
(implies a single source)</li>
<li><code>delete_cmdline</code> : for delete operations</li>
</ul>
<p>Those command-lines support the following variables :</p>
<ul>
<li><code>%s</code> : the source node(s)</li>
<li><code>%d</code> : the destination node</li>
<li><code>%n</code> : the new name</li>
</ul>
<p>It should be noted that because behind <code>%s</code> and <code>%d</code> are nodes, they should
most likely be used with FS dereferencing, e.g. <code>cp -irvat %:d %:s</code></p>
<p>Similarly, you'll want to use <code>%'n</code> to have the new name escaped in a
shell-compatible way.</p>
<p>The options allow you to define a command line, but the way it will be processed
is actually as a location in provider "exec" which means that, for instance, you
can use supported prefixes to e.g. execute it inside a(n embedded) terminal.</p>
<h4>Limitations</h4>
<p>It is important to note that <code>nodes_io()</code> usually returns an array of nodes, of
the copied/moved files. This is obviously not possible when using IO engine
"exec" since it has no awareness of what actually gets done.</p>
<p>As a result, using it will have the command return nothing, which could lead to
errors if you tried to get/used the command's return value furthermore. For such
cases, you might need to use another engine (e.g basic).</p>
<h3>Command fs_nodes_io()</h3>
<p>A new command has also been added, which works just like <code>nodes_io()</code> except
that :</p>
<ul>
<li>it takes an extra optional argument, the name of the IO engine to use;</li>
<li>if said argument isn't specified, different default options
(<code>fs_engine_{copy,move,delete}</code>) are used before falling back to the main ones
(<code>engine_{copy,move,delete}</code>).</li>
</ul>
<h3>Example</h3>
<p>As an example, one could decide to have e.g. copy and move operations be done
via a small script wrapping cp/mv and to be run inside an embedded terminal.</p>
<p>To do so, one could set it up like so (note that we set the default for
<code>fs_nodes_io()</code> back to "basic" so we can use that function to use the basic IO
engine easilly) :</p>
<pre><code>[providers/fs]
engine_copy=exec
engine_move=exec
fs_engine_copy=basic
fs_engine_move=basic
[providers/fs/ioengine-exec]
copy_cmdline=!!donna-io cp %:d %:s
copy_cmdline_new_name=!!donna-io cp-nn %:d %'n %:s
move_cmdline=!!donna-io mv %:d %:s
move_cmdline_new_name=!!donna-io mv-nn %:d %'n %:s
</code></pre>
<p>And the script in question could look something like this:</p>
<p><ol class="bash"><li class="li1"><div class="de1"><span class="co0">#!/bin/bash</span></div></li>
<li class="li1"><div class="de1"> </div></li>
<li class="li1"><div class="de1"><span class="re2">ALL_OFF</span>=<span class="st0">"\e[0m"</span></div></li>
<li class="li1"><div class="de1"><span class="re2">BOLD</span>=<span class="st0">"\e[1m"</span></div></li>
<li class="li1"><div class="de1"><span class="re2">BLUE</span>=<span class="st0">"<span class="es3">${BOLD}</span>\e[34m"</span></div></li>
<li class="li1"><div class="de1"><span class="re2">GREEN</span>=<span class="st0">"<span class="es3">${BOLD}</span>\e[32m"</span></div></li>
<li class="li1"><div class="de1"><span class="re2">RED</span>=<span class="st0">"<span class="es3">${BOLD}</span>\e[31m"</span></div></li>
<li class="li1"><div class="de1"><span class="re2">YELLOW</span>=<span class="st0">"<span class="es3">${BOLD}</span>\e[33m"</span></div></li>
<li class="li1"><div class="de1"> </div></li>
<li class="li1"><div class="de1">msg<span class="br0">(</span><span class="br0">)</span> <span class="br0">{</span></div></li>
<li class="li1"><div class="de1"> <span class="kw3">local</span> <span class="re2">mesg</span>=<span class="re4">$1</span>; <span class="kw3">shift</span></div></li>
<li class="li1"><div class="de1"> <span class="kw3">printf</span> <span class="st0">"<span class="es3">${GREEN}</span>==><span class="es3">${ALL_OFF}</span><span class="es3">${BOLD}</span> <span class="es3">${mesg}</span><span class="es3">${ALL_OFF}</span><span class="es1">\n</span>"</span> <span class="st0">"$@"</span> <span class="sy0">>&</span><span class="nu0">2</span></div></li>
<li class="li1"><div class="de1"><span class="br0">}</span></div></li>
<li class="li1"><div class="de1"> </div></li>
<li class="li1"><div class="de1">error<span class="br0">(</span><span class="br0">)</span> <span class="br0">{</span></div></li>
<li class="li1"><div class="de1"> <span class="kw3">local</span> <span class="re2">mesg</span>=<span class="re4">$1</span>; <span class="kw3">shift</span></div></li>
<li class="li1"><div class="de1"> <span class="kw3">printf</span> <span class="st0">"<span class="es3">${RED}</span>==> ERROR:<span class="es3">${ALL_OFF}</span><span class="es3">${BOLD}</span> <span class="es3">${mesg}</span><span class="es3">${ALL_OFF}</span><span class="es1">\n</span>"</span> <span class="st0">"$@"</span> <span class="sy0">>&</span><span class="nu0">2</span></div></li>
<li class="li1"><div class="de1"><span class="br0">}</span></div></li>
<li class="li1"><div class="de1"> </div></li>
<li class="li1"><div class="de1">err<span class="br0">(</span><span class="br0">)</span> <span class="br0">{</span></div></li>
<li class="li1"><div class="de1"> error <span class="st0">"$@"</span></div></li>
<li class="li1"><div class="de1"> <span class="kw3">exit</span> <span class="nu0">1</span></div></li>
<li class="li1"><div class="de1"><span class="br0">}</span></div></li>
<li class="li1"><div class="de1"> </div></li>
<li class="li1"><div class="de1"> </div></li>
<li class="li1"><div class="de1"><span class="re2">op</span>=<span class="re4">$1</span></div></li>
<li class="li1"><div class="de1"><span class="kw3">shift</span></div></li>
<li class="li1"><div class="de1"> </div></li>
<li class="li1"><div class="de1"><span class="re2">nn</span>=<span class="nu0">0</span></div></li>
<li class="li1"><div class="de1"><span class="kw1">case</span> <span class="re1">$op</span> <span class="kw1">in</span></div></li>
<li class="li1"><div class="de1"> <span class="st0">"copy"</span><span class="sy0">|</span><span class="st0">"cp"</span><span class="br0">)</span></div></li>
<li class="li1"><div class="de1"> <span class="re2">op</span>=<span class="st0">"cp"</span></div></li>
<li class="li1"><div class="de1"> <span class="re2">action</span>=<span class="st0">"Copying"</span></div></li>
<li class="li1"><div class="de1"> <span class="sy0">;;</span></div></li>
<li class="li1"><div class="de1"> </div></li>
<li class="li1"><div class="de1"> <span class="st0">"copy-new-name"</span><span class="sy0">|</span><span class="st0">"cp-nn"</span><span class="br0">)</span></div></li>
<li class="li1"><div class="de1"> <span class="re2">op</span>=<span class="st0">"cp-nn"</span></div></li>
<li class="li1"><div class="de1"> <span class="re2">action</span>=<span class="st0">"Copying"</span></div></li>
<li class="li1"><div class="de1"> <span class="re2">nn</span>=<span class="nu0">1</span></div></li>
<li class="li1"><div class="de1"> <span class="sy0">;;</span></div></li>
<li class="li1"><div class="de1"> </div></li>
<li class="li1"><div class="de1"> <span class="st0">"move"</span><span class="sy0">|</span><span class="st0">"mv"</span><span class="br0">)</span></div></li>
<li class="li1"><div class="de1"> <span class="re2">op</span>=<span class="st0">"mv"</span></div></li>
<li class="li1"><div class="de1"> <span class="re2">action</span>=<span class="st0">"Moving"</span></div></li>
<li class="li1"><div class="de1"> <span class="sy0">;;</span></div></li>
<li class="li1"><div class="de1"> </div></li>
<li class="li1"><div class="de1"> <span class="st0">"move-new-name"</span><span class="sy0">|</span><span class="st0">"mv-nn"</span><span class="br0">)</span></div></li>
<li class="li1"><div class="de1"> <span class="re2">op</span>=<span class="st0">"mv-nn"</span></div></li>
<li class="li1"><div class="de1"> <span class="re2">action</span>=<span class="st0">"Moving"</span></div></li>
<li class="li1"><div class="de1"> <span class="re2">nn</span>=<span class="nu0">1</span></div></li>
<li class="li1"><div class="de1"> <span class="sy0">;;</span></div></li>
<li class="li1"><div class="de1"> </div></li>
<li class="li1"><div class="de1"> <span class="st0">"delete"</span><span class="sy0">|</span><span class="st0">"rm"</span><span class="br0">)</span></div></li>
<li class="li1"><div class="de1"> <span class="re2">op</span>=<span class="st0">"rm"</span></div></li>
<li class="li1"><div class="de1"> <span class="re2">action</span>=<span class="st0">"Deleting"</span></div></li>
<li class="li1"><div class="de1"> <span class="sy0">;;</span></div></li>
<li class="li1"><div class="de1"> </div></li>
<li class="li1"><div class="de1"> <span class="sy0">*</span><span class="br0">)</span></div></li>
<li class="li1"><div class="de1"> err <span class="st0">"invalid operation '<span class="es2">$op</span>': must be 'copy', 'move' or 'delete'"</span></div></li>
<li class="li1"><div class="de1"> <span class="sy0">;;</span></div></li>
<li class="li1"><div class="de1"><span class="kw1">esac</span></div></li>
<li class="li1"><div class="de1"> </div></li>
<li class="li1"><div class="de1"><span class="kw1">if</span> <span class="br0">[</span><span class="br0">[</span> <span class="re1">$op</span> = <span class="st0">"rm"</span> <span class="br0">]</span><span class="br0">]</span>; <span class="kw1">then</span></div></li>
<li class="li1"><div class="de1"> <span class="re2">nb</span>=<span class="re4">$#</span></div></li>
<li class="li1"><div class="de1"> <span class="kw1">if</span> <span class="br0">[</span><span class="br0">[</span> <span class="re1">$nb</span> <span class="re5">-gt</span> <span class="nu0">1</span> <span class="br0">]</span><span class="br0">]</span>; <span class="kw1">then</span></div></li>
<li class="li1"><div class="de1"> msg <span class="st0">"<span class="es2">$action</span> <span class="es2">$nb</span> files..."</span></div></li>
<li class="li1"><div class="de1"> <span class="kw1">elif</span> <span class="br0">[</span><span class="br0">[</span> <span class="re1">$nb</span> <span class="re5">-eq</span> <span class="nu0">1</span> <span class="br0">]</span><span class="br0">]</span>; <span class="kw1">then</span></div></li>
<li class="li1"><div class="de1"> msg <span class="st0">"<span class="es2">$action</span> $1..."</span></div></li>
<li class="li1"><div class="de1"> <span class="kw1">else</span></div></li>
<li class="li1"><div class="de1"> err <span class="st0">"missing source(s)"</span></div></li>
<li class="li1"><div class="de1"> <span class="kw1">fi</span></div></li>
<li class="li1"><div class="de1"><span class="kw1">else</span></div></li>
<li class="li1"><div class="de1"> <span class="re2">dest</span>=<span class="re4">$1</span></div></li>
<li class="li1"><div class="de1"> <span class="kw3">shift</span></div></li>
<li class="li1"><div class="de1"> <span class="kw1">if</span> <span class="br0">[</span><span class="br0">[</span> <span class="re1">$nn</span> <span class="re5">-eq</span> <span class="nu0">1</span> <span class="br0">]</span><span class="br0">]</span>; <span class="kw1">then</span></div></li>
<li class="li1"><div class="de1"> <span class="re2">new_name</span>=<span class="re4">$1</span></div></li>
<li class="li1"><div class="de1"> <span class="kw3">shift</span></div></li>
<li class="li1"><div class="de1"> <span class="kw1">fi</span></div></li>
<li class="li1"><div class="de1"> </div></li>
<li class="li1"><div class="de1"> <span class="re2">nb</span>=<span class="re4">$#</span></div></li>
<li class="li1"><div class="de1"> <span class="kw1">if</span> <span class="br0">[</span><span class="br0">[</span> <span class="re1">$nn</span> <span class="re5">-eq</span> <span class="nu0">1</span> <span class="br0">]</span><span class="br0">]</span>; <span class="kw1">then</span></div></li>
<li class="li1"><div class="de1"> msg <span class="st0">"<span class="es2">$action</span> $1 as <span class="es2">$dest</span>/<span class="es2">$new_name</span>..."</span></div></li>
<li class="li1"><div class="de1"> <span class="kw1">elif</span> <span class="br0">[</span><span class="br0">[</span> <span class="re1">$nb</span> <span class="re5">-gt</span> <span class="nu0">1</span> <span class="br0">]</span><span class="br0">]</span>; <span class="kw1">then</span></div></li>
<li class="li1"><div class="de1"> msg <span class="st0">"<span class="es2">$action</span> <span class="es2">$nb</span> files to <span class="es2">$dest</span>..."</span></div></li>
<li class="li1"><div class="de1"> <span class="kw1">elif</span> <span class="br0">[</span><span class="br0">[</span> <span class="re1">$nb</span> <span class="re5">-eq</span> <span class="nu0">1</span> <span class="br0">]</span><span class="br0">]</span>; <span class="kw1">then</span></div></li>
<li class="li1"><div class="de1"> msg <span class="st0">"<span class="es2">$action</span> $1 to <span class="es2">$dest</span>..."</span></div></li>
<li class="li1"><div class="de1"> <span class="kw1">else</span></div></li>
<li class="li1"><div class="de1"> err <span class="st0">"missing source(s)"</span></div></li>
<li class="li1"><div class="de1"> <span class="kw1">fi</span></div></li>
<li class="li1"><div class="de1"><span class="kw1">fi</span></div></li>
<li class="li1"><div class="de1"><span class="kw3">echo</span></div></li>
<li class="li1"><div class="de1"> </div></li>
<li class="li1"><div class="de1"><span class="kw1">case</span> <span class="re1">$op</span> <span class="kw1">in</span></div></li>
<li class="li1"><div class="de1"> <span class="st0">"cp"</span><span class="br0">)</span></div></li>
<li class="li1"><div class="de1"> <span class="kw2">cp</span> <span class="re5">-irvat</span> <span class="st0">"<span class="es2">$dest</span>"</span> <span class="st0">"$@"</span></div></li>
<li class="li1"><div class="de1"> <span class="sy0">;;</span></div></li>
<li class="li1"><div class="de1"> </div></li>
<li class="li1"><div class="de1"> <span class="st0">"cp-nn"</span><span class="br0">)</span></div></li>
<li class="li1"><div class="de1"> <span class="kw2">cp</span> <span class="re5">-irvaT</span> <span class="st0">"$@"</span> <span class="st0">"<span class="es2">$d</span>/<span class="es2">$new_name</span>"</span></div></li>
<li class="li1"><div class="de1"> <span class="sy0">;;</span></div></li>
<li class="li1"><div class="de1"> </div></li>
<li class="li1"><div class="de1"> <span class="st0">"mv"</span><span class="br0">)</span></div></li>
<li class="li1"><div class="de1"> <span class="kw2">mv</span> <span class="re5">-ivt</span> <span class="st0">"<span class="es2">$dest</span>"</span> <span class="st0">"$@"</span></div></li>
<li class="li1"><div class="de1"> <span class="sy0">;;</span></div></li>
<li class="li1"><div class="de1"> </div></li>
<li class="li1"><div class="de1"> <span class="st0">"mv-nn"</span><span class="br0">)</span></div></li>
<li class="li1"><div class="de1"> <span class="kw2">mv</span> <span class="re5">-ivT</span> <span class="st0">"$@"</span> <span class="st0">"<span class="es2">$dest</span>/<span class="es2">$new_name</span>"</span></div></li>
<li class="li1"><div class="de1"> <span class="sy0">;;</span></div></li>
<li class="li1"><div class="de1"> </div></li>
<li class="li1"><div class="de1"> <span class="st0">"rm"</span><span class="br0">)</span></div></li>
<li class="li1"><div class="de1"> <span class="kw2">rm</span> <span class="re5">-Irv</span> <span class="st0">"$@"</span></div></li>
<li class="li1"><div class="de1"> <span class="sy0">;;</span></div></li>
<li class="li1"><div class="de1"><span class="kw1">esac</span></div></li>
<li class="li1"><div class="de1"> </div></li>
<li class="li1"><div class="de1"><span class="kw3">echo</span></div></li>
<li class="li1"><div class="de1">msg <span class="st0">"done"</span></div></li>
</ol></p>
<h3>Where to get it?</h3>
<p>For Arch Linux users, you can use
<a href="https://aur.archlinux.org/packages/donnatella-git/">donnatella-git</a> in the AUR
to easilly get it. Or simply clone the git repo from
<a href="https://github.com/jjk-jacky/donnatella/tree/next">github</a> and compile things
yourself.</p>
<p>For a a complete list of all changes/bug fixes please refer to the git log.</p>
<p>And in case you read all that and are wondering what donnatella is, or are
looking for more information, download links, etc please refer to <a href="/donnatella" title="donnatella: your file manager">donnatella</a>.</p>
<p>As always, bug reports, suggestions or any other form of constructive criticism
is very much welcome. You can open <a href="https://github.com/jjk-jacky/donnatella/issues">issues on
github</a>, use the thread on Arch
Linux forums, or simply email me.</p>
donnatella 0.3.1 released2014-12-11T00:00:00+00:00http://jjacky.com/2014-12-11-donnatella-0.3.1-released<p>A new version of donnatella, your GTK3 file manager, is available. A few fixes
since <a href="/2014-11-05-donnatella-0.3.0-released/" title="donnatella 0.3.0 released">0.3.0</a>,
as well as the addition of option <code>cancel_childless</code> for terminals.</p>
<p>Enabled by default, it will cancel the running task on Enter/Esc if the running
process (i.e. terminal emulator) has no children.</p>
<p>For example after running <code>df -h</code> in an embedded terminal that doesn't autoclose
when the running process is done (e.g. urxvt has an option <code>-hold</code>), so that you
get a chance to see the ourput, a simple Enter will close the terminal.</p>
</p>
<h3>Changes since 0.3.0</h3>
<p>Quick recap over the different changes since last version :</p>
<ul>
<li>Fix scripts not installed in subfolder 'bin'</li>
<li>terminal: Add option <code>cancel_childless</code></li>
<li>A few other (documentation) fixes; see <code>git log</code> for details</li>
</ul>
<h3>Downloads and whatnot</h3>
<p>See <a href="/donnatella" title="donnatella: your file manager">donnatella</a> for longer descriptions & all the links you should need.</p>
<p>And of course, as always, new bug reports, suggestions or any other form of
constructive criticism is very much welcome.</p>
How to simply create a "media pool" on Linux?2014-11-09T00:00:00+00:00http://jjacky.com/2014-11-09-how-to-simply-create-a-media-pool-on-linux<p>Ever since I switched to (Arch) Linux, I've always loved the command line. It
can often be quite amazing, I find. Back in the Windows world, you're pretty
much expected to forget that such a thing even exists.</p>
<p>Things are different over here (particularly with Arch, I guess), and that's all
for the better. Many reasons for that, one being the fantastic simplicity and
power that it offers you.</p>
</p>
<p>Case in point, let's say you've got a bunch of external disks that you quite
unimaginatively call "disk1" to "disk4" on which you store things such as
movies, TV/web series and the likes.</p>
<p>All those data spread over many disks, and you don't necessarily know where to
find what you're looking for, or you don't want to have to plug all the drives
just to go through the list of what you do have (memory can be tricky).</p>
<p>A solution is to create what I'll call a "media pool," which is simply a folder
that will "list" all you have. Say on every disk there's a folder "Movies"
containing, well, movies. In our pool, we want a folder "Movies" that will
"contain" all movies from all the disks.</p>
<p>Of course, the actual data won't be there, just symlinks. Enough for us to know
what we have, and where it is. I'm not sure how you'd go and do that on Windows,
but things couldn't be easier on a GNU/Linux system: a simple <code>cp</code> will do,
since it has a flag (<code>-s, --symbolic-link</code>) to create symlinks instead of
copying.</p>
<p>To do so over all disks as we want, this is all we need:</p>
<p><ol class="bash"><li class="li1"><div class="de1"><span class="co0">#!/bin/bash</span></div></li>
<li class="li1"><div class="de1"><span class="kw1">for</span> d <span class="kw1">in</span> <span class="sy0">/</span>media<span class="sy0">/</span>disk?<span class="sy0">/*</span>; <span class="kw1">do</span></div></li>
<li class="li1"><div class="de1"> <span class="br0">[</span><span class="br0">[</span> <span class="re5">-d</span> <span class="st0">"<span class="es2">$d</span>"</span> <span class="br0">]</span><span class="br0">]</span> <span class="sy0">||</span> <span class="kw3">continue</span></div></li>
<li class="li1"><div class="de1"> <span class="br0">[</span><span class="br0">[</span> <span class="co1">${d:${!d}</span> - <span class="nu0">11</span><span class="br0">}</span> == <span class="st0">"/lost+found"</span> <span class="br0">]</span><span class="br0">]</span> <span class="sy0">&&</span> <span class="kw3">continue</span></div></li>
<li class="li1"><div class="de1"> <span class="kw2">cp</span> <span class="re5">-asR</span> <span class="st0">"<span class="es2">$d</span>"</span> <span class="sy0">/</span>media<span class="sy0">/</span>pool</div></li>
<li class="li1"><div class="de1"><span class="kw1">done</span></div></li>
</ol></p>
<p>Done indeed, as that is all we need.</p>
<h3>But where is the data?</h3>
<p>Now because <code>cp</code> is smart, the symlinks it'll create will be based on how you
called it. Since here we're using full/absolute path names, symlinks will use
the same.</p>
<p>Which means that we know every single symlink points to <code>/media/disk?/...</code> Why
is that great, you ask? Because with the wonders of the command line, it
couldn't be any easier to get the disk's name for a symlink/movie:</p>
<p><ol class="bash"><li class="li1"><div class="de1"><span class="kw2">readlink</span> <span class="re1">$SYMLINK</span> <span class="sy0">|</span> <span class="kw2">cut</span> -d<span class="sy0">/</span> <span class="re5">-f3</span></div></li>
</ol></p>
<p>Simple as that. Probably nothing special if you've been dealing with this
forever, but I always find it quite amazing how simple & easy this is. But let's
not stop there...</p>
<h3>Benefit from all this in you file manager!</h3>
<p>Because while I like the command line, I'm also using graphical applications,
and in fact I use a GUI file manager. Sometimes nothing beats opening a terminal
and typing a few commands, and sometimes I like the ease & interface comfort
only such a tool can provide.</p>
<p>And when I want to browse through my media pool, I'd like to use my file
manager. But I'd like to know where my data is quite easily as well.</p>
<p>With <a href="/donnatella" title="donnatella: your file manager">donnatella</a>, this is rather easy to do actually; Though not everything
might make sense if you're not familiar with it.</p>
<p>First, I'll create a new arrangement for folders in <code>/media/pool</code> An arrangement
defines things like column layout/options, and that can be made specific on a
per-folder basis :</p>
<pre><code>[arrangements/]
mask=fs:/media/pool/*
columns=ln,name,text,perms,own
[arrangements//columns_options/name]
width=270
[arrangements//columns_options/text]
title=Disk(s)
property=pool-disk
width=120
</code></pre>
<p>Here we define the columns to use, as well as changing a few options: column
name will be made a bit smaller, we don't have a column size but use a column
text instead, which will show the content of property "pool-disk"</p>
<p>What is that, you ask? It's a custom property we'll also have to define:</p>
<pre><code>[custom_properties/]
domain=fs
filter=location:/media/pool/*
[custom_properties//pool-disk]
cmdline=donna-pool-disk %:n
</code></pre>
<p>And then we have a little script, <code>donna-pool-disk</code>, that will return the name
of the disk(s); We're using a script because we want to support this for folders
as well, but obviously this will be based on files contained within, and we'd
like to support the case where those are spread across multiple disks (may not
be likely for movies, but more but TV/web series).</p>
<p><ol class="bash"><li class="li1"><div class="de1"><span class="co0">#!/bin/bash</span></div></li>
<li class="li1"><div class="de1"> </div></li>
<li class="li1"><div class="de1"><span class="kw1">while</span> <span class="br0">[</span><span class="br0">[</span> <span class="re5">-n</span> <span class="re4">$1</span> <span class="br0">]</span><span class="br0">]</span>; <span class="kw1">do</span></div></li>
<li class="li1"><div class="de1"> <span class="re2">file</span>=<span class="re4">$1</span></div></li>
<li class="li1"><div class="de1"> <span class="kw3">shift</span></div></li>
<li class="li1"><div class="de1"> <span class="kw1">if</span> <span class="br0">[</span><span class="br0">[</span> <span class="re5">-d</span> <span class="st0">"<span class="es2">$file</span>"</span> <span class="br0">]</span><span class="br0">]</span>; <span class="kw1">then</span></div></li>
<li class="li1"><div class="de1"> <span class="re2">disks</span>=$<span class="br0">(</span><span class="kw2">find</span> <span class="st0">"<span class="es2">$file</span>"</span> <span class="re5">-type</span> l <span class="re5">-print0</span> <span class="sy0">|</span> <span class="kw2">xargs</span> <span class="re5">-0</span> <span class="kw2">readlink</span> <span class="sy0">|</span> \</div></li>
<li class="li1"><div class="de1"> <span class="kw2">cut</span> -d<span class="sy0">/</span> <span class="re5">-f3</span> <span class="sy0">|</span> <span class="kw2">sort</span> <span class="re5">-u</span> <span class="sy0">|</span> <span class="kw2">tr</span> $<span class="st_h">'\n'</span> ,<span class="br0">)</span></div></li>
<li class="li1"><div class="de1"> <span class="kw3">echo</span> <span class="st0">"<span class="es2">$file</span>|pool-disk|<span class="es3">${disks:0:-1}</span>"</span></div></li>
<li class="li1"><div class="de1"> <span class="kw1">else</span></div></li>
<li class="li1"><div class="de1"> <span class="re2">disk</span>=$<span class="br0">(</span><span class="kw2">readlink</span> <span class="st0">"<span class="es2">$file</span>"</span> <span class="sy0">|</span> <span class="kw2">cut</span> -d<span class="sy0">/</span> -f3<span class="br0">)</span></div></li>
<li class="li1"><div class="de1"> <span class="kw3">echo</span> <span class="st0">"<span class="es2">$file</span>|pool-disk|<span class="es2">$disk</span>"</span></div></li>
<li class="li1"><div class="de1"> <span class="kw1">fi</span></div></li>
<li class="li1"><div class="de1"><span class="kw1">done</span></div></li>
</ol></p>
<h3>Et voilà!</h3>
<p><img src="/donnatella/donnatella-ss8.png" alt="donnatella: Browsing the media pool" title="donnatella: Browsing the media pool" /></p>
donnatella 0.3.0 released2014-11-05T00:00:00+00:00http://jjacky.com/2014-11-05-donnatella-0.3.0-released<p>A new version of donnatella, your GTK3 file manager, is available. A bunch of
fixes and improvments/optimizations since
<a href="/2014-04-03-donnatella-0.2.0-released/" title="donnatella 0.2.0 released">0.2.0</a>,
some new things as well, the most "important" ones being the addition of
<strong>custom properties</strong>, and facilities for <strong>scripting</strong></p>
<p>Sicne day one, things have been quite configurable in donna, but there was no
scripting support. Instead, donna uses commands and lets you combine them as you
want, assign them a click or key, etc And when that's not enough? Well, then you
script.</p>
</p>
<p>It is now possible to communicate with donna, i.e. trigger commands (nodes,
really, it's not actually limited to commands) and get their return values. All
this easilly in any language of your choice, either using the socket directly or
via helper <code>donna-trigger</code></p>
<p>And if you could always configure donna as you wanted, defining the layout and
configuring columns as you'd like, things can now go even further via the
addition of custom properties.</p>
<p>You'll now be able to have columns for video duration, uncompressed size of
archives, or whatever you can come up with!</p>
<h3>Changes since 0.2.0</h3>
<p>Quick recap over the different changes since last version :</p>
<ul>
<li>Add command <code>exec()</code> See <a href="/2014-04-20-columns-format-and-command-exec-in-donnatella/" title="Columns formats and command exec in donnatella">this
post</a>
for more</li>
<li>Add event "notify-dirname" when current directory changes</li>
<li>provider-exec: Parse environment variables See <a href="/2014-04-20-columns-format-and-command-exec-in-donnatella/" title="Columns formats and command exec in donnatella">this
post</a>
for more</li>
<li>Add <strong>custom properties</strong> See <a href="/2014-05-04-donnatella-adds-custom-properties/" title="Show & use any properties you want: donnatella adds custom properties!">this
post</a>
and <a href="/2014-05-24-donnatella-fluid-time-format-and-custom-properties/" title="Fluid time format and custom properties in donnatella">this
one</a>
for more</li>
<li>treeview: <code>save_to_config()</code>: Fix not saving right column layout</li>
<li>ColumnType text: Add tooltip, and option <code>property_tooltip</code></li>
<li>ColumnType time: Support ":property" & ":format" in tooltip options</li>
<li>treeview: Fix not refreshing column options saved to arrangement/defaults</li>
<li>tree: Trigger flat item when selected</li>
<li>config: Fix not exporting/saving empty categories</li>
<li>Command <code>config_save()</code>: Emit event info upon save</li>
<li>ColumnType time: Remove tooltip versions of some options (not needed/useful)</li>
<li>ColumnType time: Add new specifier <code>%f</code> for "fluid" format See <a href="/2014-05-24-donnatella-fluid-time-format-and-custom-properties/" title="Fluid time format and custom properties in donnatella">this
post</a>
for more</li>
<li>ColumnTypes time, perms & text: Add option <code>align</code></li>
<li>Add a <strong>socket to communicate with donna</strong> from e.g. scripts; as well as helper
<code>donna-trigger</code> See <a href="/2014-07-14-now-you-can-script-donnatella/" title="Now you can script donnatella!">this
post</a>
for more</li>
<li>Add command <code>intref_free()</code></li>
<li>tree: Add commands <code>root_{g,s}et_child_visual()</code> to get/set tree visuals even
for a row that isn't accessible or not yet loaded</li>
<li>Add provider filter to handle filters See <a href="/2014-10-29-donnatella-filters-mrus-scripts-and-gtk-3.14/" title="donnatella, filters, MRUs, scripts, and GTK+ 3.14!">this
post</a>
for more</li>
<li>Add command <code>get_node_from()</code></li>
<li>Add command <code>node_set_property()</code></li>
<li>Provider command: Add prefix '<' to make the node a container instead of an
item: See <a href="/2014-10-29-donnatella-filters-mrus-scripts-and-gtk-3.14/" title="donnatella, filters, MRUs, scripts, and GTK+ 3.14!">this
post</a>
for more</li>
<li>Content menus: Add new context-type "combined" for defining both the item and
the submenu (via container) part of a menu item. See <a href="/2014-10-29-donnatella-filters-mrus-scripts-and-gtk-3.14/" title="donnatella, filters, MRUs, scripts, and GTK+ 3.14!">this
post</a>
for more</li>
<li>Add command <code>node_get_children()</code></li>
<li>Add command <code>nodes_add()</code></li>
<li>Add provider mru to maintain Most Recently Used lists. See <a href="/2014-10-29-donnatella-filters-mrus-scripts-and-gtk-3.14/" title="donnatella, filters, MRUs, scripts, and GTK+ 3.14!">this
post</a>
for more</li>
<li>Menus: Fix keys (e.g. Enter) not triggering items</li>
<li>Add <code>$DONNATELLA_CONFIG_DIR</code> & extend <code>$PATH</code> (for scripts) See <a href="/2014-10-29-donnatella-filters-mrus-scripts-and-gtk-3.14/" title="donnatella, filters, MRUs, scripts, and GTK+ 3.14!">this
post</a>
for more</li>
<li>Add commands <code>{nodes,strings}_{len,get_item}</code></li>
<li>GTK+3.14 fixes/compatibility changes, update patchset <code>gtk3-donnatella</code></li>
<li>list: Fix refreshing relative line number column (when not first one)</li>
<li>Many other fixes & optimizations; see <code>git log</code> for details</li>
</ul>
<h3>Configuration updates</h3>
<p>As you might know if you've read the posts about changes pushed in <code>next</code>
alongside changes in the code, were changes in the (default) configuration as
well. And since almost everything in donna is configurable, you might wanna use
an updated config as well.</p>
<p>There are, however, no automatic process for this. You can use your favorite
tool to handle the merging, even do a 3-way merge using the original .conf file
if you want.</p>
<p>And in case it might help, here are the changes done between 0.2.0 and 0.3.0 :</p>
<p><ol class="diff"><li class="li1"><div class="de1">diff --git a/misc/donnatella.conf b/misc/donnatella.conf</div></li>
<li class="li1"><div class="de1">index b6b<span class="re0">2a03</span>..b9810df <span class="nu0">100644</span></div></li>
<li class="li1"><div class="de1"><span class="re3">--- a/misc/donnatella.conf</span></div></li>
<li class="li1"><div class="de1"><span class="re4">+++ b/misc/donnatella.conf</span></div></li>
<li class="li1"><div class="de1"><span class="re6">@@ -136,6 +136,7 @@ key_mode_select_foreground=white</span></div></li>
<li class="li1"><div class="de1"> last_location=command:tv_set_location <span class="br0">(</span>:active, @config_get_string <span class="br0">(</span>donna/last_location<span class="br0">)</span><span class="br0">)</span></div></li>
<li class="li1"><div class="de1"> marks=command:mark_load <span class="br0">(</span>,<span class="nu0">1</span><span class="br0">)</span></div></li>
<li class="li1"><div class="de1"> registers=command:register_load_all <span class="br0">(</span>,<span class="nu0">1</span><span class="br0">)</span></div></li>
<li class="li1"><div class="de1"><span class="re8">+filters=command:filter_load <span class="br0">(</span><span class="br0">)</span></span></div></li>
<li class="li1"><div class="de1"> # enable when using layout "tm"</div></li>
<li class="li1"><div class="de1"> #tm=@tv_set_location<span class="br0">(</span>tm,task:/<span class="br0">)</span></div></li>
<li class="li1"><div class="de1"> </div></li>
<li class="li1"><div class="de1"><span class="re6">@@ -205,7 +206,7 @@ context_menu_colheader=columns<!columns>,-,:sort_order<!sort_order>,:second_sort</span></div></li>
<li class="li1"><div class="de1"> # some color filters</div></li>
<li class="li1"><div class="de1"> </div></li>
<li class="li1"><div class="de1"> <span class="br0">[</span>defaults/lists/arrangement/color_filters/<span class="br0">]</span></div></li>
<li class="li1"><div class="de1"><span class="re7">-filter=|*.tar.*|*.tgz|*.zip|*.rar</span></div></li>
<li class="li1"><div class="de1"><span class="re8">+filter=|a</span></div></li>
<li class="li1"><div class="de1"> column=name</div></li>
<li class="li1"><div class="de1"> foreground=green</div></li>
<li class="li1"><div class="de1"> </div></li>
<li class="li1"><div class="de1"><span class="re6">@@ -231,25 +232,25 @@ foreground-rgba=rgb<span class="br0">(</span>108,0,0<span class="br0">)</span></span></div></li>
<li class="li1"><div class="de1"> </div></li>
<li class="li1"><div class="de1"> <span class="br0">[</span>defaults/lists/arrangement/color_filters/<span class="br0">]</span></div></li>
<li class="li1"><div class="de1"> # modified less than an hour ago</div></li>
<li class="li1"><div class="de1"><span class="re7">-filter=time:A<=1H</span></div></li>
<li class="li1"><div class="de1"><span class="re8">+filter=|h</span></div></li>
<li class="li1"><div class="de1"> column=time</div></li>
<li class="li1"><div class="de1"> foreground-rgba=rgb<span class="br0">(</span><span class="nu0">0</span>,<span class="nu0">80</span>,<span class="nu0">210</span><span class="br0">)</span></div></li>
<li class="li1"><div class="de1"> </div></li>
<li class="li1"><div class="de1"> <span class="br0">[</span>defaults/lists/arrangement/color_filters/<span class="br0">]</span></div></li>
<li class="li1"><div class="de1"> # modified today</div></li>
<li class="li1"><div class="de1"><span class="re7">-filter=time:A0d</span></div></li>
<li class="li1"><div class="de1"><span class="re8">+filter=|t</span></div></li>
<li class="li1"><div class="de1"> column=time</div></li>
<li class="li1"><div class="de1"> foreground-rgba=rgb<span class="br0">(</span><span class="nu0">0</span>,<span class="nu0">150</span>,<span class="nu0">200</span><span class="br0">)</span></div></li>
<li class="li1"><div class="de1"> </div></li>
<li class="li1"><div class="de1"> <span class="br0">[</span>defaults/lists/arrangement/color_filters/<span class="br0">]</span></div></li>
<li class="li1"><div class="de1"> # modified yesterday</div></li>
<li class="li1"><div class="de1"><span class="re7">-filter=time:A1d</span></div></li>
<li class="li1"><div class="de1"><span class="re8">+filter=|y</span></div></li>
<li class="li1"><div class="de1"> column=time</div></li>
<li class="li1"><div class="de1"> foreground-rgba=rgb<span class="br0">(</span><span class="nu0">0</span>,<span class="nu0">200</span>,<span class="nu0">160</span><span class="br0">)</span></div></li>
<li class="li1"><div class="de1"> </div></li>
<li class="li1"><div class="de1"> <span class="br0">[</span>defaults/lists/arrangement/color_filters/<span class="br0">]</span></div></li>
<li class="li1"><div class="de1"> # modified this week</div></li>
<li class="li1"><div class="de1"><span class="re7">-filter=time:A0V</span></div></li>
<li class="li1"><div class="de1"><span class="re8">+filter=|w</span></div></li>
<li class="li1"><div class="de1"> column=time</div></li>
<li class="li1"><div class="de1"> foreground-rgba=rgb<span class="br0">(</span><span class="nu0">0</span>,<span class="nu0">180</span>,<span class="nu0">0</span><span class="br0">)</span></div></li>
<li class="li1"><div class="de1"> </div></li>
<li class="li1"><div class="de1"><span class="re6">@@ -410,7 +411,7 @@ type:ct=name</span></div></li>
<li class="li1"><div class="de1"> # File System</div></li>
<li class="li1"><div class="de1"> </div></li>
<li class="li1"><div class="de1"> <span class="br0">[</span>arrangements/<span class="br0">]</span></div></li>
<li class="li1"><div class="de1"><span class="re7">-mask=fs:/*</span></div></li>
<li class="li1"><div class="de1"><span class="re8">+mask=^fs:/</span></div></li>
<li class="li1"><div class="de1"> columns=ln,name,size,time,perms,own</div></li>
<li class="li1"><div class="de1"> sort_column=name</div></li>
<li class="li1"><div class="de1"> sort_order:order=asc</div></li>
<li class="li1"><div class="de1"><span class="re6">@@ -423,7 +424,7 @@ second_sort_always=true</span></div></li>
<li class="li1"><div class="de1"> # Search Results</div></li>
<li class="li1"><div class="de1"> </div></li>
<li class="li1"><div class="de1"> <span class="br0">[</span>arrangements/<span class="br0">]</span></div></li>
<li class="li1"><div class="de1"><span class="re7">-mask=exec:*</span></div></li>
<li class="li1"><div class="de1"><span class="re8">+mask=^exec:</span></div></li>
<li class="li1"><div class="de1"> columns=ln,path,name,size,time,perms,own</div></li>
<li class="li1"><div class="de1"> sort_column=path</div></li>
<li class="li1"><div class="de1"> sort_order:order=asc</div></li>
<li class="li1"><div class="de1"><span class="re6">@@ -440,7 +441,7 @@ width=285</span></div></li>
<li class="li1"><div class="de1"> # Configuration</div></li>
<li class="li1"><div class="de1"> </div></li>
<li class="li1"><div class="de1"> <span class="br0">[</span>arrangements/<span class="br0">]</span></div></li>
<li class="li1"><div class="de1"><span class="re7">-mask=config:/*</span></div></li>
<li class="li1"><div class="de1"><span class="re8">+mask=^config:/</span></div></li>
<li class="li1"><div class="de1"> columns=ln,name,opt-type,value</div></li>
<li class="li1"><div class="de1"> </div></li>
<li class="li1"><div class="de1"> <span class="br0">[</span>arrangements//columns_options/name<span class="br0">]</span></div></li>
<li class="li1"><div class="de1"><span class="re6">@@ -453,7 +454,7 @@ width=420</span></div></li>
<li class="li1"><div class="de1"> # Task Manager</div></li>
<li class="li1"><div class="de1"> </div></li>
<li class="li1"><div class="de1"> <span class="br0">[</span>arrangements/<span class="br0">]</span></div></li>
<li class="li1"><div class="de1"><span class="re7">-mask=task:/*</span></div></li>
<li class="li1"><div class="de1"><span class="re8">+mask=^task:/</span></div></li>
<li class="li1"><div class="de1"> columns=ln,name,progress,text,label</div></li>
<li class="li1"><div class="de1"> </div></li>
<li class="li1"><div class="de1"> <span class="br0">[</span>arrangements//columns_options/name<span class="br0">]</span></div></li>
<li class="li1"><div class="de1"><span class="re6">@@ -479,7 +480,7 @@ width=80</span></div></li>
<li class="li1"><div class="de1"> # Marks</div></li>
<li class="li1"><div class="de1"> </div></li>
<li class="li1"><div class="de1"> <span class="br0">[</span>arrangements/<span class="br0">]</span></div></li>
<li class="li1"><div class="de1"><span class="re7">-mask=mark:/*</span></div></li>
<li class="li1"><div class="de1"><span class="re8">+mask=^mark:/</span></div></li>
<li class="li1"><div class="de1"> columns=ln,name,mark-type,mark-value</div></li>
<li class="li1"><div class="de1"> </div></li>
<li class="li1"><div class="de1"> <span class="br0">[</span>arrangements//columns_options/name<span class="br0">]</span></div></li>
<li class="li1"><div class="de1"><span class="re6">@@ -783,11 +784,9 @@ trigger=command:tv_start_interactive_search <span class="br0">(</span>%o<span class="br0">)</span></span></div></li>
<li class="li1"><div class="de1"> <span class="br0">[</span>key_modes/donna/key_f<span class="br0">]</span></div></li>
<li class="li1"><div class="de1"> type:key=spec</div></li>
<li class="li1"><div class="de1"> spec:spec=lower,upper</div></li>
<li class="li1"><div class="de1"><span class="re7">-trigger=command:tv_set_visual_filter <span class="br0">(</span>%o, @config_get_string <span class="br0">(</span>filters/%k<span class="br0">)</span>, 1<span class="br0">)</span></span></div></li>
<li class="li1"><div class="de1"><span class="re8">+trigger=command:tv_set_visual_filter <span class="br0">(</span>%o, filter:|%k, 1<span class="br0">)</span></span></div></li>
<li class="li1"><div class="de1"> <span class="br0">[</span>key_modes/donna/key_F<span class="br0">]</span></div></li>
<li class="li1"><div class="de1"><span class="re7">-type:key=spec</span></div></li>
<li class="li1"><div class="de1"><span class="re7">-spec:spec=lower,upper</span></div></li>
<li class="li1"><div class="de1"><span class="re7">-trigger=command:tv_set_visual_filter <span class="br0">(</span>%o, @config_set_string <span class="br0">(</span>filters/%k, @ask_text <span class="br0">(</span>Enter filter %k,,@config_try_get_string <span class="br0">(</span>filters/%k, @tv_get_visual_filter <span class="br0">(</span>%o<span class="br0">)</span><span class="br0">)</span><span class="br0">)</span><span class="br0">)</span>, 1<span class="br0">)</span></span></div></li>
<li class="li1"><div class="de1"><span class="re8">+trigger=command:tv_set_visual_filter <span class="br0">(</span>%o, @get_node_from <span class="br0">(</span>filter, @ask_text <span class="br0">(</span>Enter visual filter,, @node_get_property <span class="br0">(</span>@tv_get_visual_filter <span class="br0">(</span>%o<span class="br0">)</span>, location<span class="br0">)</span><span class="br0">)</span><span class="br0">)</span><span class="br0">)</span></span></div></li>
<li class="li1"><div class="de1"> </div></li>
<li class="li1"><div class="de1"> # VF: by age</div></li>
<li class="li1"><div class="de1"> <span class="br0">[</span>key_modes/donna/key_ampersand<span class="br0">]</span></div></li>
<li class="li1"><div class="de1"><span class="re6">@@ -797,16 +796,16 @@ custom_chars=HMSdmVY</span></div></li>
<li class="li1"><div class="de1"> combine=age_unit</div></li>
<li class="li1"><div class="de1"> <span class="br0">[</span>key_modes/donna/key_q<span class="br0">]</span></div></li>
<li class="li1"><div class="de1"> combine=age_unit</div></li>
<li class="li1"><div class="de1"><span class="re7">-trigger=command:tv_set_visual_filter <span class="br0">(</span>%o, time:A%m%c<span class="br0">)</span></span></div></li>
<li class="li1"><div class="de1"><span class="re8">+trigger=command:tv_set_visual_filter <span class="br0">(</span>%o, filter:time:A%m%c<span class="br0">)</span></span></div></li>
<li class="li1"><div class="de1"> <span class="br0">[</span>key_modes/donna/key_Q<span class="br0">]</span></div></li>
<li class="li1"><div class="de1"> combine=age_unit</div></li>
<li class="li1"><div class="de1"><span class="re7">-trigger=command:tv_set_visual_filter <span class="br0">(</span>%o, time:A<=%m%c<span class="br0">)</span></span></div></li>
<li class="li1"><div class="de1"><span class="re8">+trigger=command:tv_set_visual_filter <span class="br0">(</span>%o, filter:time:A<=%m%c<span class="br0">)</span></span></div></li>
<li class="li1"><div class="de1"> </div></li>
<li class="li1"><div class="de1"> # VF: by size</div></li>
<li class="li1"><div class="de1"> <span class="br0">[</span>key_modes/donna/key_less<span class="br0">]</span></div></li>
<li class="li1"><div class="de1"><span class="re7">-trigger=command:tv_set_visual_filter <span class="br0">(</span>%o, size:<=%mM<span class="br0">)</span></span></div></li>
<li class="li1"><div class="de1"><span class="re8">+trigger=command:tv_set_visual_filter <span class="br0">(</span>%o, filter:size:<=%mM<span class="br0">)</span></span></div></li>
<li class="li1"><div class="de1"> <span class="br0">[</span>key_modes/donna/key_greater<span class="br0">]</span></div></li>
<li class="li1"><div class="de1"><span class="re7">-trigger=command:tv_set_visual_filter <span class="br0">(</span>%o, size:>=%mM<span class="br0">)</span></span></div></li>
<li class="li1"><div class="de1"><span class="re8">+trigger=command:tv_set_visual_filter <span class="br0">(</span>%o, filter:size:>=%mM<span class="br0">)</span></span></div></li>
<li class="li1"><div class="de1"> </div></li>
<li class="li1"><div class="de1"> </div></li>
<li class="li1"><div class="de1"> # F2 to rename</div></li>
<li class="li1"><div class="de1"><span class="re6">@@ -814,16 +813,16 @@ trigger=command:tv_set_visual_filter <span class="br0">(</span>%o, size:>=%mM<span class="br0">)</span></span></div></li>
<li class="li1"><div class="de1"> trigger=command:tv_column_edit <span class="br0">(</span>%o, %n, name<span class="br0">)</span></div></li>
<li class="li1"><div class="de1"> # F6 to edit focused item <span class="br0">(</span>vim in a terminal<span class="br0">)</span></div></li>
<li class="li1"><div class="de1"> <span class="br0">[</span>key_modes/donna/key_F6<span class="br0">]</span></div></li>
<li class="li1"><div class="de1"><span class="re7">-trigger=exec:!vim %:n</span></div></li>
<li class="li1"><div class="de1"><span class="re8">+trigger=exec:!$EDITOR %:n</span></div></li>
<li class="li1"><div class="de1"> # F9 to view focused item <span class="br0">(</span>less in a terminal<span class="br0">)</span></div></li>
<li class="li1"><div class="de1"> <span class="br0">[</span>key_modes/donna/key_F9<span class="br0">]</span></div></li>
<li class="li1"><div class="de1"><span class="re7">-trigger=exec:!less %:n</span></div></li>
<li class="li1"><div class="de1"><span class="re8">+trigger=exec:!$LESS %:n</span></div></li>
<li class="li1"><div class="de1"> </div></li>
<li class="li1"><div class="de1"> # Terminals</div></li>
<li class="li1"><div class="de1"> <span class="br0">[</span>key_modes/donna/key_t<span class="br0">]</span></div></li>
<li class="li1"><div class="de1"><span class="re7">-trigger=exec:!bash</span></div></li>
<li class="li1"><div class="de1"><span class="re8">+trigger=exec:!$SHELL</span></div></li>
<li class="li1"><div class="de1"> <span class="br0">[</span>key_modes/donna/key_T<span class="br0">]</span></div></li>
<li class="li1"><div class="de1"><span class="re7">-trigger=exec:>bash</span></div></li>
<li class="li1"><div class="de1"><span class="re8">+trigger=exec:>$SHELL</span></div></li>
<li class="li1"><div class="de1"> </div></li>
<li class="li1"><div class="de1"> # selection stuff -- note that this required a patched GTK <span class="br0">(</span>to invert range<span class="br0">)</span></div></li>
<li class="li1"><div class="de1"> <span class="br0">[</span>key_modes/donna/key_v<span class="br0">]</span></div></li>
<li class="li1"><div class="de1"><span class="re6">@@ -957,12 +956,12 @@ trigger=command:tv_save_tree_file <span class="br0">(</span>%o, @ask_text <span class="br0">(</span>Save Tree As...,Enter the name</span></div></li>
<li class="li1"><div class="de1"> name=Open Terminal Here</div></li>
<li class="li1"><div class="de1"> icon=terminal</div></li>
<li class="li1"><div class="de1"> is_sensitive=has_ref</div></li>
<li class="li1"><div class="de1"><span class="re7">-trigger=exec:!WORKDIR=%:n bash</span></div></li>
<li class="li1"><div class="de1"><span class="re8">+trigger=exec:!WORKDIR=%:n $SHELL</span></div></li>
<li class="li1"><div class="de1"> </div></li>
<li class="li1"><div class="de1"> <span class="br0">[</span>context_menus/tree_views/terminal_nw<span class="br0">]</span></div></li>
<li class="li1"><div class="de1"> name=...In New Window</div></li>
<li class="li1"><div class="de1"> is_sensitive=has_ref</div></li>
<li class="li1"><div class="de1"><span class="re7">-trigger=>WD=%:n bash</span></div></li>
<li class="li1"><div class="de1"><span class="re8">+trigger=>WD=%:n $SHELL</span></div></li>
<li class="li1"><div class="de1"> </div></li>
<li class="li1"><div class="de1"> <span class="br0">[</span>context_menus/tree_views/tree_visuals<span class="br0">]</span></div></li>
<li class="li1"><div class="de1"> type:context-type=empty</div></li>
<li class="li1"><div class="de1"><span class="re6">@@ -1054,8 +1053,12 @@ name=Invert Selection</span></div></li>
<li class="li1"><div class="de1"> trigger=command:tv_selection <span class="br0">(</span>%o, i, :all<span class="br0">)</span></div></li>
<li class="li1"><div class="de1"> </div></li>
<li class="li1"><div class="de1"> <span class="br0">[</span>context_menus/tree_views/selection_filter<span class="br0">]</span></div></li>
<li class="li1"><div class="de1"><span class="re8">+type:context-type=combined</span></div></li>
<li class="li1"><div class="de1"> name=Selection Filter...</div></li>
<li class="li1"><div class="de1"><span class="re7">-trigger=command:tv_selection_nodes <span class="br0">(</span>%o, d, @nodes_filter <span class="br0">(</span>@tv_get_nodes <span class="br0">(</span>%o, :all<span class="br0">)</span>, @ask_text <span class="br0">(</span>Selection Filter,Enter the selection filter to apply<span class="br0">)</span>, %o<span class="br0">)</span><span class="br0">)</span></span></div></li>
<li class="li1"><div class="de1"><span class="re8">+trigger=&donna-sel_filter %o</span></div></li>
<li class="li1"><div class="de1"><span class="re8">+container=@<nodes_add <span class="br0">(</span>@nodes_add<span class="br0">(</span>@mru_get_nodes <span class="br0">(</span>mru:sel_filter<span class="br0">)</span><span class="br0">)</span>, filter:/<span class="br0">)</span></span></div></li>
<li class="li1"><div class="de1"><span class="re8">+submenus:enabled=combine</span></div></li>
<li class="li1"><div class="de1"><span class="re8">+menu=sel_filter</span></div></li>
<li class="li1"><div class="de1"> </div></li>
<li class="li1"><div class="de1"> # Timestamp stuff</div></li>
<li class="li1"><div class="de1"> </div></li>
<li class="li1"><div class="de1"><span class="re6">@@ -1091,6 +1094,12 @@ children:node-type=items</span></div></li>
<li class="li1"><div class="de1"> sort=true</div></li>
<li class="li1"><div class="de1"> left_click=command:tv_goto_line <span class="br0">(</span>:active, s+f, @nodes_io <span class="br0">(</span>%n, c, @tv_get_location <span class="br0">(</span>:active<span class="br0">)</span>, @ask_text <span class="br0">(</span>New Items,Enter the name of the item to create,@node_get_property<span class="br0">(</span>%n,name<span class="br0">)</span><span class="br0">)</span><span class="br0">)</span><span class="br0">)</span></div></li>
<li class="li1"><div class="de1"> </div></li>
<li class="li1"><div class="de1"><span class="re8">+# Selection Filters</span></div></li>
<li class="li1"><div class="de1"><span class="re8">+<span class="br0">[</span>menus/sel_filter<span class="br0">]</span></span></div></li>
<li class="li1"><div class="de1"><span class="re8">+sort=false</span></div></li>
<li class="li1"><div class="de1"><span class="re8">+submenus:enabled=enabled</span></div></li>
<li class="li1"><div class="de1"><span class="re8">+left_click=command:tv_selection_nodes <span class="br0">(</span>:active, d, @nodes_filter <span class="br0">(</span>@tv_get_nodes <span class="br0">(</span>:active, :all<span class="br0">)</span>, @mru_add_node <span class="br0">(</span>mru:sel_filter, %n<span class="br0">)</span>, :active<span class="br0">)</span><span class="br0">)</span></span></div></li>
<li class="li1"><div class="de1"><span class="re8">+</span></div></li>
<li class="li1"><div class="de1"> # to show children but not hidden/dotFiles</div></li>
<li class="li1"><div class="de1"> <span class="br0">[</span>menus/children_not_hidden<span class="br0">]</span></div></li>
<li class="li1"><div class="de1"> sort=true</div></li>
<li class="li1"><div class="de1"><span class="re6">@@ -1181,6 +1190,42 @@ terminal=term</span></div></li>
<li class="li1"><div class="de1"> prefix=!</div></li>
<li class="li1"><div class="de1"> terminal=term</div></li>
<li class="li1"><div class="de1"> terminal_cmdline=:hold</div></li>
<li class="li1"><div class="de1"><span class="re8">+<span class="br0">[</span>providers/filter/<span class="br0">]</span></span></div></li>
<li class="li1"><div class="de1"><span class="re8">+alias=f</span></div></li>
<li class="li1"><div class="de1"><span class="re8">+name=No filtering</span></div></li>
<li class="li1"><div class="de1"><span class="re8">+icon_name=edit-delete</span></div></li>
<li class="li1"><div class="de1"><span class="re8">+filter=</span></div></li>
<li class="li1"><div class="de1"><span class="re8">+<span class="br0">[</span>providers/filter/<span class="br0">]</span></span></div></li>
<li class="li1"><div class="de1"><span class="re8">+alias=h</span></div></li>
<li class="li1"><div class="de1"><span class="re8">+name=Within the hour</span></div></li>
<li class="li1"><div class="de1"><span class="re8">+filter=time:A<=1H</span></div></li>
<li class="li1"><div class="de1"><span class="re8">+<span class="br0">[</span>providers/filter/<span class="br0">]</span></span></div></li>
<li class="li1"><div class="de1"><span class="re8">+alias=t</span></div></li>
<li class="li1"><div class="de1"><span class="re8">+name=Today</span></div></li>
<li class="li1"><div class="de1"><span class="re8">+icon_name=vcalendar</span></div></li>
<li class="li1"><div class="de1"><span class="re8">+filter=time:A0</span></div></li>
<li class="li1"><div class="de1"><span class="re8">+<span class="br0">[</span>providers/filter/<span class="br0">]</span></span></div></li>
<li class="li1"><div class="de1"><span class="re8">+alias=y</span></div></li>
<li class="li1"><div class="de1"><span class="re8">+name=Yesterday</span></div></li>
<li class="li1"><div class="de1"><span class="re8">+filter=time:A1d</span></div></li>
<li class="li1"><div class="de1"><span class="re8">+<span class="br0">[</span>providers/filter/<span class="br0">]</span></span></div></li>
<li class="li1"><div class="de1"><span class="re8">+alias=w</span></div></li>
<li class="li1"><div class="de1"><span class="re8">+name=This week</span></div></li>
<li class="li1"><div class="de1"><span class="re8">+filter=time:A0V</span></div></li>
<li class="li1"><div class="de1"><span class="re8">+<span class="br0">[</span>providers/filter/<span class="br0">]</span></span></div></li>
<li class="li1"><div class="de1"><span class="re8">+alias=v</span></div></li>
<li class="li1"><div class="de1"><span class="re8">+name=Videos</span></div></li>
<li class="li1"><div class="de1"><span class="re8">+icon_name=video</span></div></li>
<li class="li1"><div class="de1"><span class="re8">+filter=desc:* video</span></div></li>
<li class="li1"><div class="de1"><span class="re8">+<span class="br0">[</span>providers/filter/<span class="br0">]</span></span></div></li>
<li class="li1"><div class="de1"><span class="re8">+alias=i</span></div></li>
<li class="li1"><div class="de1"><span class="re8">+name=Images</span></div></li>
<li class="li1"><div class="de1"><span class="re8">+icon_name=image</span></div></li>
<li class="li1"><div class="de1"><span class="re8">+filter=desc:* image</span></div></li>
<li class="li1"><div class="de1"><span class="re8">+<span class="br0">[</span>providers/filter/<span class="br0">]</span></span></div></li>
<li class="li1"><div class="de1"><span class="re8">+alias=a</span></div></li>
<li class="li1"><div class="de1"><span class="re8">+name=Archives</span></div></li>
<li class="li1"><div class="de1"><span class="re8">+filter=desc:* archive*</span></div></li>
<li class="li1"><div class="de1"> </div></li>
<li class="li1"><div class="de1"> </div></li>
<li class="li1"><div class="de1"> #</div></li>
<li class="li1"><div class="de1"><span class="re6">@@ -1201,25 +1246,4 @@ node=config:/</span></div></li>
<li class="li1"><div class="de1"> box=box-orange</div></li>
<li class="li1"><div class="de1"> </div></li>
<li class="li1"><div class="de1"> </div></li>
<li class="li1"><div class="de1"><span class="re7">-#</span></div></li>
<li class="li1"><div class="de1"><span class="re7">-# FILTERS</span></div></li>
<li class="li1"><div class="de1"><span class="re7">-#</span></div></li>
<li class="li1"><div class="de1"><span class="re7">-</span></div></li>
<li class="li1"><div class="de1"><span class="re7">-<span class="br0">[</span>filters<span class="br0">]</span></span></div></li>
<li class="li1"><div class="de1"><span class="re7">-# used to unset current VF <span class="br0">(</span>via ff<span class="br0">)</span></span></div></li>
<li class="li1"><div class="de1"><span class="re7">-f=</span></div></li>
<li class="li1"><div class="de1"><span class="re7">-# today</span></div></li>
<li class="li1"><div class="de1"><span class="re7">-t=time:A0</span></div></li>
<li class="li1"><div class="de1"><span class="re7">-# yesterday</span></div></li>
<li class="li1"><div class="de1"><span class="re7">-y=time:A1d</span></div></li>
<li class="li1"><div class="de1"><span class="re7">-# this week</span></div></li>
<li class="li1"><div class="de1"><span class="re7">-w=time:A0V</span></div></li>
<li class="li1"><div class="de1"><span class="re7">-# videos</span></div></li>
<li class="li1"><div class="de1"><span class="re7">-v=desc:* video</span></div></li>
<li class="li1"><div class="de1"><span class="re7">-# images</span></div></li>
<li class="li1"><div class="de1"><span class="re7">-i=desc:* image</span></div></li>
<li class="li1"><div class="de1"><span class="re7">-# archives</span></div></li>
<li class="li1"><div class="de1"><span class="re7">-a=desc:* archive*</span></div></li>
<li class="li1"><div class="de1"><span class="re7">-</span></div></li>
<li class="li1"><div class="de1"><span class="re7">-</span></div></li>
<li class="li1"><div class="de1"> # EOF</div></li>
</ol></p>
<h3>Downloads and whatnot</h3>
<p>See <a href="/donnatella" title="donnatella: your file manager">donnatella</a> for longer descriptions & all the links you should need.</p>
<p>And of course, as always, new bug reports, suggestions or any other form of
constructive criticism is very much welcome.</p>
donnatella, filters, MRUs, scripts, and GTK+ 3.14!2014-10-29T00:00:00+00:00http://jjacky.com/2014-10-29-donnatella-filters-mrus-scripts-and-gtk-3.14<p>Yes, GTK+ 3.14 has been out for some time now, and it's even been available in
Arch's official repos for a little while as well. Unfortunately I haven't been
able to find enough time to work on donna as of late, and I didn't follow GTK's
developement closely, so when 3.14 was released I had a few patches to rebase,
and some to rewrite completely (think rubber band handling, since the internals
are now full of gestures).</p>
<p>But I have some (good) news for you, finally.</p>
</p>
<h3>What's new to next?</h3>
<p>First of all, a few things have finally been pushed to branch <code>next</code> so let's
quickly go over the main ones :</p>
<h4>Filters are now a thing.</h4>
<p>That is, <strong>donna now has a provider "filter" that handles them</strong>, and obviously
that means a filter can be represented with a node, as is common in donnatella.</p>
<p>The main benefit from this is that now <strong>filters can be defined in config, and
assigned a name, alias and/or icon name</strong>. So when one wants to use a filter, a
simple reference to its alias will do the trick, and should that filter need to
be updated, it only happens in one simple place. Also, when used in menus they
can have a nice name ("e.g. "From yesterday") and/or icon to make things easier.</p>
<p>The location of a filter is that actual filter string itself, with two specials
cases: if it starts with a pipe sign, then what follows is an alias. Note that
when asking for e.g. <code>filter:|y</code> the node you'll get will be that of the actual
filter, i.e. with for full location e.g. <code>filter:A1d</code> And, the node <code>filter:</code>
(i.e. with an empty location) refers to a lack of filter, which is a way to set
no filter, or what commands (such as <code>tv_get_visual_filter()</code>) will return when
no filter is set.</p>
<h4>Commands as containers</h4>
<p>The node for a command is usually an item that can be triggered. Usually,
because it is now possible to prefix the command's name/location with the lesser
than sign, in order to get a container instead.</p>
<p>This is obviously only supported for commands that return either a node, or an
array of nodes. Then, getting the children of the node/container will trigger
the command, returning what the command returned.</p>
<p>This can be useful in e.g. (context) menus; Speaking of which...</p>
<h4>A new type of item in context menus</h4>
<p>A new context-type <code>combined</code> has been added when defining a user item in a
context menu. It works like the regular item, with option <code>trigger</code> for the
trigger/item part, but also reads option <code>container</code> for the full location of
a container, used for the submenu part of the item.</p>
<p>Obviously, this is intended for used with option "submenus" set to "combine" and
allows to define both the item & the submenu part of an item.</p>
<h4>Most-Recently Used lists</h4>
<p>A new provider "mru" has been added, allowing to manager MRU lists of nodes or
strings. In the later case, the node for the MRU will be an item and the only
way to get items is via command <code>mru_get_strings()</code></p>
<p>In the former case, the node will be a container, usable just as any other (e.g.
in treeviews, menus, etc).</p>
<p>Not unlike filters, asking for the node of an MRU will automatically create it
if it doesn't yet exist, though command <code>mru_new()</code> allows to perform a
creation, failing if the MRU already exists.</p>
<h4>Add $DONNATELLA_CONFIG_DIR and extend $PATH</h4>
<p>The environment used when executing things from donna (e.g. from provider exec)
will have an extra variable <code>DONNATELLA_CONFIG_DIR</code> set to the current
configuration directory, which might be useful for scripts.</p>
<p>Similarly, the $PATH will be extended (unless boolean option <code>donna/extand_path</code>
was set to false) to end with <code>$DONNATELLA_CONFIG_DIR/bin</code> as well as
subfolder "donnatella/bin" of all system config directories (<code>$XDG_CONFIG_DIRS</code>)
to e.g. easily run donna-specific scripts.</p>
<h4>As an example...</h4>
<p>By default the "Selection Filter" item in the list's context menu now makes use
of about all of this, being a item that can be triggered, then using a script
that deals with an MRU of filters, and a submenu made from using some of the new
commands like <code>nodes_add()</code> to get recently used filters from an MRU as well as
listing all available filters.</p>
<p>So if you're curious about all those changes and wantto known more, have a look
at the git log as well as configuration options (and related scripts) regarding
the "Selection Filter" menu item.</p>
<h3>GTK+ 3.14</h3>
<p>Of course a few bugs have been fixed and other minor/internal changes took
place. Amongst which is the compatibility with GTK+ 3.14 and the updated
patches, also known as
<a href="/donnatella/gtk3-donnatella-3.14.4-1.tar.gz">gtk3-donnatella</a>.</p>
<p>As hinted earlier, major changes took place in the rubber band handling, as it's
been rewritten in GTK+ which now uses GtkGesture to handle all of this. It
shouldn't however make any difference from a user point of view, and everything
should continue working as before in donna.</p>
<h3>Configuration changes</h3>
<p>As always, after updating you'll have to update your configuration as well to
benefit from all the changes. Here's the diff for this time around, since the
last time:</p>
<p><ol class="diff"><li class="li1"><div class="de1">diff --git a/misc/donnatella.conf b/misc/donnatella.conf</div></li>
<li class="li1"><div class="de1">index 1ab177f..b9810df <span class="nu0">100644</span></div></li>
<li class="li1"><div class="de1"><span class="re3">--- a/misc/donnatella.conf</span></div></li>
<li class="li1"><div class="de1"><span class="re4">+++ b/misc/donnatella.conf</span></div></li>
<li class="li1"><div class="de1"><span class="re6">@@ -136,6 +136,7 @@ key_mode_select_foreground=white</span></div></li>
<li class="li1"><div class="de1"> last_location=command:tv_set_location <span class="br0">(</span>:active, @config_get_string <span class="br0">(</span>donna/last_location<span class="br0">)</span><span class="br0">)</span></div></li>
<li class="li1"><div class="de1"> marks=command:mark_load <span class="br0">(</span>,<span class="nu0">1</span><span class="br0">)</span></div></li>
<li class="li1"><div class="de1"> registers=command:register_load_all <span class="br0">(</span>,<span class="nu0">1</span><span class="br0">)</span></div></li>
<li class="li1"><div class="de1"><span class="re8">+filters=command:filter_load <span class="br0">(</span><span class="br0">)</span></span></div></li>
<li class="li1"><div class="de1"> # enable when using layout "tm"</div></li>
<li class="li1"><div class="de1"> #tm=@tv_set_location<span class="br0">(</span>tm,task:/<span class="br0">)</span></div></li>
<li class="li1"><div class="de1"> </div></li>
<li class="li1"><div class="de1"><span class="re6">@@ -205,7 +206,7 @@ context_menu_colheader=columns<!columns>,-,:sort_order<!sort_order>,:second_sort</span></div></li>
<li class="li1"><div class="de1"> # some color filters</div></li>
<li class="li1"><div class="de1"> </div></li>
<li class="li1"><div class="de1"> <span class="br0">[</span>defaults/lists/arrangement/color_filters/<span class="br0">]</span></div></li>
<li class="li1"><div class="de1"><span class="re7">-filter=|*.tar.*|*.tgz|*.zip|*.rar</span></div></li>
<li class="li1"><div class="de1"><span class="re8">+filter=|a</span></div></li>
<li class="li1"><div class="de1"> column=name</div></li>
<li class="li1"><div class="de1"> foreground=green</div></li>
<li class="li1"><div class="de1"> </div></li>
<li class="li1"><div class="de1"><span class="re6">@@ -231,25 +232,25 @@ foreground-rgba=rgb<span class="br0">(</span>108,0,0<span class="br0">)</span></span></div></li>
<li class="li1"><div class="de1"> </div></li>
<li class="li1"><div class="de1"> <span class="br0">[</span>defaults/lists/arrangement/color_filters/<span class="br0">]</span></div></li>
<li class="li1"><div class="de1"> # modified less than an hour ago</div></li>
<li class="li1"><div class="de1"><span class="re7">-filter=time:A<=1H</span></div></li>
<li class="li1"><div class="de1"><span class="re8">+filter=|h</span></div></li>
<li class="li1"><div class="de1"> column=time</div></li>
<li class="li1"><div class="de1"> foreground-rgba=rgb<span class="br0">(</span><span class="nu0">0</span>,<span class="nu0">80</span>,<span class="nu0">210</span><span class="br0">)</span></div></li>
<li class="li1"><div class="de1"> </div></li>
<li class="li1"><div class="de1"> <span class="br0">[</span>defaults/lists/arrangement/color_filters/<span class="br0">]</span></div></li>
<li class="li1"><div class="de1"> # modified today</div></li>
<li class="li1"><div class="de1"><span class="re7">-filter=time:A0d</span></div></li>
<li class="li1"><div class="de1"><span class="re8">+filter=|t</span></div></li>
<li class="li1"><div class="de1"> column=time</div></li>
<li class="li1"><div class="de1"> foreground-rgba=rgb<span class="br0">(</span><span class="nu0">0</span>,<span class="nu0">150</span>,<span class="nu0">200</span><span class="br0">)</span></div></li>
<li class="li1"><div class="de1"> </div></li>
<li class="li1"><div class="de1"> <span class="br0">[</span>defaults/lists/arrangement/color_filters/<span class="br0">]</span></div></li>
<li class="li1"><div class="de1"> # modified yesterday</div></li>
<li class="li1"><div class="de1"><span class="re7">-filter=time:A1d</span></div></li>
<li class="li1"><div class="de1"><span class="re8">+filter=|y</span></div></li>
<li class="li1"><div class="de1"> column=time</div></li>
<li class="li1"><div class="de1"> foreground-rgba=rgb<span class="br0">(</span><span class="nu0">0</span>,<span class="nu0">200</span>,<span class="nu0">160</span><span class="br0">)</span></div></li>
<li class="li1"><div class="de1"> </div></li>
<li class="li1"><div class="de1"> <span class="br0">[</span>defaults/lists/arrangement/color_filters/<span class="br0">]</span></div></li>
<li class="li1"><div class="de1"> # modified this week</div></li>
<li class="li1"><div class="de1"><span class="re7">-filter=time:A0V</span></div></li>
<li class="li1"><div class="de1"><span class="re8">+filter=|w</span></div></li>
<li class="li1"><div class="de1"> column=time</div></li>
<li class="li1"><div class="de1"> foreground-rgba=rgb<span class="br0">(</span><span class="nu0">0</span>,<span class="nu0">180</span>,<span class="nu0">0</span><span class="br0">)</span></div></li>
<li class="li1"><div class="de1"> </div></li>
<li class="li1"><div class="de1"><span class="re6">@@ -783,11 +784,9 @@ trigger=command:tv_start_interactive_search <span class="br0">(</span>%o<span class="br0">)</span></span></div></li>
<li class="li1"><div class="de1"> <span class="br0">[</span>key_modes/donna/key_f<span class="br0">]</span></div></li>
<li class="li1"><div class="de1"> type:key=spec</div></li>
<li class="li1"><div class="de1"> spec:spec=lower,upper</div></li>
<li class="li1"><div class="de1"><span class="re7">-trigger=command:tv_set_visual_filter <span class="br0">(</span>%o, @config_get_string <span class="br0">(</span>filters/%k<span class="br0">)</span>, 1<span class="br0">)</span></span></div></li>
<li class="li1"><div class="de1"><span class="re8">+trigger=command:tv_set_visual_filter <span class="br0">(</span>%o, filter:|%k, 1<span class="br0">)</span></span></div></li>
<li class="li1"><div class="de1"> <span class="br0">[</span>key_modes/donna/key_F<span class="br0">]</span></div></li>
<li class="li1"><div class="de1"><span class="re7">-type:key=spec</span></div></li>
<li class="li1"><div class="de1"><span class="re7">-spec:spec=lower,upper</span></div></li>
<li class="li1"><div class="de1"><span class="re7">-trigger=command:tv_set_visual_filter <span class="br0">(</span>%o, @config_set_string <span class="br0">(</span>filters/%k, @ask_text <span class="br0">(</span>Enter filter %k,,@config_try_get_string <span class="br0">(</span>filters/%k, @tv_get_visual_filter <span class="br0">(</span>%o<span class="br0">)</span><span class="br0">)</span><span class="br0">)</span><span class="br0">)</span>, 1<span class="br0">)</span></span></div></li>
<li class="li1"><div class="de1"><span class="re8">+trigger=command:tv_set_visual_filter <span class="br0">(</span>%o, @get_node_from <span class="br0">(</span>filter, @ask_text <span class="br0">(</span>Enter visual filter,, @node_get_property <span class="br0">(</span>@tv_get_visual_filter <span class="br0">(</span>%o<span class="br0">)</span>, location<span class="br0">)</span><span class="br0">)</span><span class="br0">)</span><span class="br0">)</span></span></div></li>
<li class="li1"><div class="de1"> </div></li>
<li class="li1"><div class="de1"> # VF: by age</div></li>
<li class="li1"><div class="de1"> <span class="br0">[</span>key_modes/donna/key_ampersand<span class="br0">]</span></div></li>
<li class="li1"><div class="de1"><span class="re6">@@ -797,16 +796,16 @@ custom_chars=HMSdmVY</span></div></li>
<li class="li1"><div class="de1"> combine=age_unit</div></li>
<li class="li1"><div class="de1"> <span class="br0">[</span>key_modes/donna/key_q<span class="br0">]</span></div></li>
<li class="li1"><div class="de1"> combine=age_unit</div></li>
<li class="li1"><div class="de1"><span class="re7">-trigger=command:tv_set_visual_filter <span class="br0">(</span>%o, time:A%m%c<span class="br0">)</span></span></div></li>
<li class="li1"><div class="de1"><span class="re8">+trigger=command:tv_set_visual_filter <span class="br0">(</span>%o, filter:time:A%m%c<span class="br0">)</span></span></div></li>
<li class="li1"><div class="de1"> <span class="br0">[</span>key_modes/donna/key_Q<span class="br0">]</span></div></li>
<li class="li1"><div class="de1"> combine=age_unit</div></li>
<li class="li1"><div class="de1"><span class="re7">-trigger=command:tv_set_visual_filter <span class="br0">(</span>%o, time:A<=%m%c<span class="br0">)</span></span></div></li>
<li class="li1"><div class="de1"><span class="re8">+trigger=command:tv_set_visual_filter <span class="br0">(</span>%o, filter:time:A<=%m%c<span class="br0">)</span></span></div></li>
<li class="li1"><div class="de1"> </div></li>
<li class="li1"><div class="de1"> # VF: by size</div></li>
<li class="li1"><div class="de1"> <span class="br0">[</span>key_modes/donna/key_less<span class="br0">]</span></div></li>
<li class="li1"><div class="de1"><span class="re7">-trigger=command:tv_set_visual_filter <span class="br0">(</span>%o, size:<=%mM<span class="br0">)</span></span></div></li>
<li class="li1"><div class="de1"><span class="re8">+trigger=command:tv_set_visual_filter <span class="br0">(</span>%o, filter:size:<=%mM<span class="br0">)</span></span></div></li>
<li class="li1"><div class="de1"> <span class="br0">[</span>key_modes/donna/key_greater<span class="br0">]</span></div></li>
<li class="li1"><div class="de1"><span class="re7">-trigger=command:tv_set_visual_filter <span class="br0">(</span>%o, size:>=%mM<span class="br0">)</span></span></div></li>
<li class="li1"><div class="de1"><span class="re8">+trigger=command:tv_set_visual_filter <span class="br0">(</span>%o, filter:size:>=%mM<span class="br0">)</span></span></div></li>
<li class="li1"><div class="de1"> </div></li>
<li class="li1"><div class="de1"> </div></li>
<li class="li1"><div class="de1"> # F2 to rename</div></li>
<li class="li1"><div class="de1"><span class="re6">@@ -1054,8 +1053,12 @@ name=Invert Selection</span></div></li>
<li class="li1"><div class="de1"> trigger=command:tv_selection <span class="br0">(</span>%o, i, :all<span class="br0">)</span></div></li>
<li class="li1"><div class="de1"> </div></li>
<li class="li1"><div class="de1"> <span class="br0">[</span>context_menus/tree_views/selection_filter<span class="br0">]</span></div></li>
<li class="li1"><div class="de1"><span class="re8">+type:context-type=combined</span></div></li>
<li class="li1"><div class="de1"> name=Selection Filter...</div></li>
<li class="li1"><div class="de1"><span class="re7">-trigger=command:tv_selection_nodes <span class="br0">(</span>%o, d, @nodes_filter <span class="br0">(</span>@tv_get_nodes <span class="br0">(</span>%o, :all<span class="br0">)</span>, @ask_text <span class="br0">(</span>Selection Filter,Enter the selection filter to apply<span class="br0">)</span>, %o<span class="br0">)</span><span class="br0">)</span></span></div></li>
<li class="li1"><div class="de1"><span class="re8">+trigger=&donna-sel_filter %o</span></div></li>
<li class="li1"><div class="de1"><span class="re8">+container=@<nodes_add <span class="br0">(</span>@nodes_add<span class="br0">(</span>@mru_get_nodes <span class="br0">(</span>mru:sel_filter<span class="br0">)</span><span class="br0">)</span>, filter:/<span class="br0">)</span></span></div></li>
<li class="li1"><div class="de1"><span class="re8">+submenus:enabled=combine</span></div></li>
<li class="li1"><div class="de1"><span class="re8">+menu=sel_filter</span></div></li>
<li class="li1"><div class="de1"> </div></li>
<li class="li1"><div class="de1"> # Timestamp stuff</div></li>
<li class="li1"><div class="de1"> </div></li>
<li class="li1"><div class="de1"><span class="re6">@@ -1091,6 +1094,12 @@ children:node-type=items</span></div></li>
<li class="li1"><div class="de1"> sort=true</div></li>
<li class="li1"><div class="de1"> left_click=command:tv_goto_line <span class="br0">(</span>:active, s+f, @nodes_io <span class="br0">(</span>%n, c, @tv_get_location <span class="br0">(</span>:active<span class="br0">)</span>, @ask_text <span class="br0">(</span>New Items,Enter the name of the item to create,@node_get_property<span class="br0">(</span>%n,name<span class="br0">)</span><span class="br0">)</span><span class="br0">)</span><span class="br0">)</span></div></li>
<li class="li1"><div class="de1"> </div></li>
<li class="li1"><div class="de1"><span class="re8">+# Selection Filters</span></div></li>
<li class="li1"><div class="de1"><span class="re8">+<span class="br0">[</span>menus/sel_filter<span class="br0">]</span></span></div></li>
<li class="li1"><div class="de1"><span class="re8">+sort=false</span></div></li>
<li class="li1"><div class="de1"><span class="re8">+submenus:enabled=enabled</span></div></li>
<li class="li1"><div class="de1"><span class="re8">+left_click=command:tv_selection_nodes <span class="br0">(</span>:active, d, @nodes_filter <span class="br0">(</span>@tv_get_nodes <span class="br0">(</span>:active, :all<span class="br0">)</span>, @mru_add_node <span class="br0">(</span>mru:sel_filter, %n<span class="br0">)</span>, :active<span class="br0">)</span><span class="br0">)</span></span></div></li>
<li class="li1"><div class="de1"><span class="re8">+</span></div></li>
<li class="li1"><div class="de1"> # to show children but not hidden/dotFiles</div></li>
<li class="li1"><div class="de1"> <span class="br0">[</span>menus/children_not_hidden<span class="br0">]</span></div></li>
<li class="li1"><div class="de1"> sort=true</div></li>
<li class="li1"><div class="de1"><span class="re6">@@ -1181,6 +1190,42 @@ terminal=term</span></div></li>
<li class="li1"><div class="de1"> prefix=!</div></li>
<li class="li1"><div class="de1"> terminal=term</div></li>
<li class="li1"><div class="de1"> terminal_cmdline=:hold</div></li>
<li class="li1"><div class="de1"><span class="re8">+<span class="br0">[</span>providers/filter/<span class="br0">]</span></span></div></li>
<li class="li1"><div class="de1"><span class="re8">+alias=f</span></div></li>
<li class="li1"><div class="de1"><span class="re8">+name=No filtering</span></div></li>
<li class="li1"><div class="de1"><span class="re8">+icon_name=edit-delete</span></div></li>
<li class="li1"><div class="de1"><span class="re8">+filter=</span></div></li>
<li class="li1"><div class="de1"><span class="re8">+<span class="br0">[</span>providers/filter/<span class="br0">]</span></span></div></li>
<li class="li1"><div class="de1"><span class="re8">+alias=h</span></div></li>
<li class="li1"><div class="de1"><span class="re8">+name=Within the hour</span></div></li>
<li class="li1"><div class="de1"><span class="re8">+filter=time:A<=1H</span></div></li>
<li class="li1"><div class="de1"><span class="re8">+<span class="br0">[</span>providers/filter/<span class="br0">]</span></span></div></li>
<li class="li1"><div class="de1"><span class="re8">+alias=t</span></div></li>
<li class="li1"><div class="de1"><span class="re8">+name=Today</span></div></li>
<li class="li1"><div class="de1"><span class="re8">+icon_name=vcalendar</span></div></li>
<li class="li1"><div class="de1"><span class="re8">+filter=time:A0</span></div></li>
<li class="li1"><div class="de1"><span class="re8">+<span class="br0">[</span>providers/filter/<span class="br0">]</span></span></div></li>
<li class="li1"><div class="de1"><span class="re8">+alias=y</span></div></li>
<li class="li1"><div class="de1"><span class="re8">+name=Yesterday</span></div></li>
<li class="li1"><div class="de1"><span class="re8">+filter=time:A1d</span></div></li>
<li class="li1"><div class="de1"><span class="re8">+<span class="br0">[</span>providers/filter/<span class="br0">]</span></span></div></li>
<li class="li1"><div class="de1"><span class="re8">+alias=w</span></div></li>
<li class="li1"><div class="de1"><span class="re8">+name=This week</span></div></li>
<li class="li1"><div class="de1"><span class="re8">+filter=time:A0V</span></div></li>
<li class="li1"><div class="de1"><span class="re8">+<span class="br0">[</span>providers/filter/<span class="br0">]</span></span></div></li>
<li class="li1"><div class="de1"><span class="re8">+alias=v</span></div></li>
<li class="li1"><div class="de1"><span class="re8">+name=Videos</span></div></li>
<li class="li1"><div class="de1"><span class="re8">+icon_name=video</span></div></li>
<li class="li1"><div class="de1"><span class="re8">+filter=desc:* video</span></div></li>
<li class="li1"><div class="de1"><span class="re8">+<span class="br0">[</span>providers/filter/<span class="br0">]</span></span></div></li>
<li class="li1"><div class="de1"><span class="re8">+alias=i</span></div></li>
<li class="li1"><div class="de1"><span class="re8">+name=Images</span></div></li>
<li class="li1"><div class="de1"><span class="re8">+icon_name=image</span></div></li>
<li class="li1"><div class="de1"><span class="re8">+filter=desc:* image</span></div></li>
<li class="li1"><div class="de1"><span class="re8">+<span class="br0">[</span>providers/filter/<span class="br0">]</span></span></div></li>
<li class="li1"><div class="de1"><span class="re8">+alias=a</span></div></li>
<li class="li1"><div class="de1"><span class="re8">+name=Archives</span></div></li>
<li class="li1"><div class="de1"><span class="re8">+filter=desc:* archive*</span></div></li>
<li class="li1"><div class="de1"> </div></li>
<li class="li1"><div class="de1"> </div></li>
<li class="li1"><div class="de1"> #</div></li>
<li class="li1"><div class="de1"><span class="re6">@@ -1201,25 +1246,4 @@ node=config:/</span></div></li>
<li class="li1"><div class="de1"> box=box-orange</div></li>
<li class="li1"><div class="de1"> </div></li>
<li class="li1"><div class="de1"> </div></li>
<li class="li1"><div class="de1"><span class="re7">-#</span></div></li>
<li class="li1"><div class="de1"><span class="re7">-# FILTERS</span></div></li>
<li class="li1"><div class="de1"><span class="re7">-#</span></div></li>
<li class="li1"><div class="de1"><span class="re7">-</span></div></li>
<li class="li1"><div class="de1"><span class="re7">-<span class="br0">[</span>filters<span class="br0">]</span></span></div></li>
<li class="li1"><div class="de1"><span class="re7">-# used to unset current VF <span class="br0">(</span>via ff<span class="br0">)</span></span></div></li>
<li class="li1"><div class="de1"><span class="re7">-f=</span></div></li>
<li class="li1"><div class="de1"><span class="re7">-# today</span></div></li>
<li class="li1"><div class="de1"><span class="re7">-t=time:A0</span></div></li>
<li class="li1"><div class="de1"><span class="re7">-# yesterday</span></div></li>
<li class="li1"><div class="de1"><span class="re7">-y=time:A1d</span></div></li>
<li class="li1"><div class="de1"><span class="re7">-# this week</span></div></li>
<li class="li1"><div class="de1"><span class="re7">-w=time:A0V</span></div></li>
<li class="li1"><div class="de1"><span class="re7">-# videos</span></div></li>
<li class="li1"><div class="de1"><span class="re7">-v=desc:* video</span></div></li>
<li class="li1"><div class="de1"><span class="re7">-# images</span></div></li>
<li class="li1"><div class="de1"><span class="re7">-i=desc:* image</span></div></li>
<li class="li1"><div class="de1"><span class="re7">-# archives</span></div></li>
<li class="li1"><div class="de1"><span class="re7">-a=desc:* archive*</span></div></li>
<li class="li1"><div class="de1"><span class="re7">-</span></div></li>
<li class="li1"><div class="de1"><span class="re7">-</span></div></li>
<li class="li1"><div class="de1"> # EOF</div></li>
</ol></p>
<h3>Where to get it?</h3>
<p>For Arch Linux users, you can use
<a href="https://aur.archlinux.org/packages/donnatella-git/">donnatella-git</a> in the AUR
to easilly get it. Or simply clone the git repo from
<a href="https://github.com/jjk-jacky/donnatella/tree/next">github</a> and compile things
yourself.</p>
<p>For a a complete list of all changes/bug fixes please refer to the git log.</p>
<p>And in case you read all that and are wondering what donnatella is, or are
looking for more information, download links, etc please refer to <a href="/donnatella" title="donnatella: your file manager">donnatella</a>.</p>
<p>As always, bug reports, suggestions or any other form of constructive criticism
is very much welcome. You can open <a href="https://github.com/jjk-jacky/donnatella/issues">issues on
github</a>, use the thread on Arch
Linux forums, or simply email me.</p>
kalu, GTK+ 3.14, KDE and pacman 4.22014-10-28T00:00:00+00:00http://jjacky.com/2014-10-28-kalu-gtk-3.14-kde-and-pacman-4.2<p>A quick update regarding all things kalu; As you might have noticed since GTK+
3.14 hit the official repos, there might be "glitches" due to the latest
<strike>breakage</strike> changes in GTK, notably some icons in menus/buttons
being quite oversized.</p>
<p>This, and a few other bugs, has been fixed, however no new version is available
yet. This is mainly because the next version is planned to come alongside the
next version of pacman (as it introduces API changes, thus requires an upgrade
of kalu at the same time).</p>
<p>Worry not, you can simply switch to kalu-git (<a href="https://aur.archlinux.org/packages/kalu-git/" title="AUR: kalu-git">in the
AUR</a>) to benefit
from all the fixes, already pushed to branch <code>next</code> since a few days now.</p>
</p>
<h3>pacman 4.2, only now</h3>
<p>Additionally, branch <code>pacman-next</code> was updated as well, not only to include the
previously mentionned changes but also take into account the latest API changes
pushed to pacman-git, so if you're using the latest pacman-git you can now use
kalu alongside as well!</p>
<p>In addition to <a href="/2014-07-23-better-pacnew-handling-with-the-next-kalu/" title="Better pacnew handling with the next kalu">previously discussed
changes</a>
you'll also see a new button in kalu's updater window, Abort. As you've guessed
already, this wil allow to abort the current operation taking place.</p>
<p>This is basically similar to hitting Ctrl+C in your pacman-running terminal,
which is to say it will handle aborting downloading packages just fine (that's
in fact the reason this was added, specifically for use from the simulation's
new "download packages only" feature) but could also be used to abort the actual
system upgrade operation.</p>
<p>In that case however, just as in your terminal, you'll likely end with with an
unstable/broken system, but if that's what you want, who am I to stop ya?</p>
<p>(Note that pressing "Abort" won't do anything until you've confirmed it, so
clicking the button is actually safe.)</p>
<h3>KDE and the systray</h3>
<p>While kalu requires GTK+, some of you might be using it from KDE. And starting
with Plasma Next, <a href="http://blog.martin-graesslin.com/blog/2014/03/system-tray-in-plasma-next/">KDE doesn't support the XEmbed systray
anymore</a>
in favor of their own <a href="http://www.notmart.org/misc/statusnotifieritem/">Status Notifier
Specification</a>.</p>
<p>So for those who don't have a systray anymore, or simply prefer to use KDE's own
notifier interface instead, I should probably mention that it is possible!</p>
<p>The code is now part of both branches <code>next</code> and <code>pacman-next</code> and is ready to
be used, though not activated by default.</p>
<p>In order to use it, you'll need to edit the PKGBUILD file a little bit before,
adding a new dependency to <a href="/statusnotifier" title="statusnotifier: KDE's Status Notifier Item as GObject">statusnotifier</a>, a small library to use KDE's Status
Notifier Interface, available <a href="https://aur.archlinux.org/packages/statusnotifier" title="AUR: statusnotifier">in the
AUR</a>,
and add option <code>--enable-status-notifier</code> to the ./configure line.</p>
<p>Then build & install the package as usual, and kalu shall try & register a
StatusNotifierItem automatically, only using the systray as a fallback in case
that failed (e.g. you don't have a Watcher running, etc).</p>
<p>As always, see <a href="/kalu" title="kalu: Keep Arch Linux Up-to-date">kalu</a> for more about kalu, download links, etc And don't
hesitate to report bugs or suggestions via email, github, or through the Arch
Linux forums.</p>
Better pacnew handling with the next kalu2014-07-23T00:00:00+00:00http://jjacky.com/2014-07-23-better-pacnew-handling-with-the-next-kalu<p>If you've been following development of the next version of pacman, and are
using <code>pacman-git</code>, then you weren't able to use kalu; Let's fix that today.</p>
<p>Also, you might already know that some new events have been added into ALPM,
<a href="https://projects.archlinux.org/pacman.git/commit/?id=cfaff6e0c14d29f07246386695bce0188ce6f44b">notably events when <code>.pac*</code> files are
created</a>.
This will make it possible/much easier for frontends (such as pacman, or kalu)
to know when such files are created.</p>
<p>From a user perspective, it might not change anything as it's all internal
changes. However, the next version of kalu will actually take advantage of this,
and can thus make your handling of those <code>.pacnew</code> files quite easier.</p>
</p>
<h3>kalu's updater and post-sysupgrade processes</h3>
<p>As you may already know, when using kalu's updater to perform your system
upgrade, you can already define one or more processes to be ran after said
sysupgrade was completed.</p>
<p>You can simply enter the command line to be started as is, but you can also use
special variables. Specifically, <code>$PACKAGES</code> will be replaced with the list of
all packages involved in the sysupgrade (i.e. packages upgraded, as well as
those added or removed, for instance with a package is replaced by another one).</p>
<p>The next version of kalu will introduce another variable - <code>$PACFILES</code> - which
will be replaced with the list of all <code>.pacnew</code> and <code>.pacorig</code> files created
during the sysupgrade.</p>
<p>For <code>.pacorig</code> files the full /path/to/filename will be specified; For <code>.pacnew</code>
files it will also be followed by an extra parameter, consisting of the package
name & old version.</p>
<p>For example, if <code>/etc/pacman.conf.pacnew</code> was installed during the upgrade,
while upgrading from 4.1.2-3 to 4.2.0-1 then the two parameters would be:</p>
<pre><code>/etc/pacman.conf.pacnew pacman-4.1.2-3
</code></pre>
<p>Therefore, you can know use this information to improve your handling of those
files. Obviously kalu won't do anything else, but you can have e.g. a little
bash script to <strong>perform a 3-way merge, having pulled the old file from the old
package file</strong> (assuming it was still in your pacman cache).</p>
<h3>Example of automatic 3-way merge handling of .pacnew files</h3>
<p>Here's an example of a little script you could call, using <code>$PACFILES</code> as
argument. And whenever <code>.pacorig</code> files were installed, a diff of said file and
its existing counterpart will show up in GVim. And for every <code>.pacnew</code> files
that were installed during the system upgrade, automatically afterwards you'll
have a nice 3-way diff opened (for each file, one after the other) in GVim.</p>
<p><ol class="bash"><li class="li1"><div class="de1"><span class="co0">#!/bin/bash</span></div></li>
<li class="li1"><div class="de1"><span class="re2">tmpdir</span>=</div></li>
<li class="li1"><div class="de1"><span class="kw1">while</span> <span class="kw2">true</span>; <span class="kw1">do</span></div></li>
<li class="li1"><div class="de1"> <span class="re2">pacnew</span>=<span class="re4">$1</span></div></li>
<li class="li1"><div class="de1"> <span class="kw3">shift</span></div></li>
<li class="li1"><div class="de1"> <span class="br0">[</span><span class="br0">[</span> <span class="re5">-z</span> <span class="re1">$pacnew</span> <span class="br0">]</span><span class="br0">]</span> <span class="sy0">&&</span> <span class="kw3">break</span></div></li>
<li class="li1"><div class="de1"> <span class="kw1">if</span> <span class="br0">[</span><span class="br0">[</span> <span class="co1">${pacnew:${#pacnew}</span>-<span class="nu0">8</span><span class="br0">}</span> == <span class="st0">".pacorig"</span> <span class="br0">]</span><span class="br0">]</span>; <span class="kw1">then</span></div></li>
<li class="li1"><div class="de1"> gvim <span class="re5">-f</span> <span class="re5">-geometry</span> 199x60 <span class="re5">-d</span> <span class="st0">"<span class="es2">$pacnew</span>"</span> <span class="st0">"<span class="es3">${pacnew:0:-8}</span>"</span></div></li>
<li class="li1"><div class="de1"> ic-question <span class="st0">"Remove <span class="es2">$pacnew</span> ?"</span></div></li>
<li class="li1"><div class="de1"> <span class="br0">[</span><span class="br0">[</span> <span class="re4">$?</span> <span class="re5">-eq</span> <span class="nu0">0</span> <span class="br0">]</span><span class="br0">]</span> <span class="sy0">&&</span> <span class="re2">SUDO_ASKPASS</span>=~<span class="sy0">/</span>bin<span class="sy0">/</span>sap <span class="kw2">sudo</span> <span class="re5">-A</span> <span class="kw2">rm</span> <span class="st0">"<span class="es2">$pacnew</span>"</span></div></li>
<li class="li1"><div class="de1"> <span class="kw3">continue</span>;</div></li>
<li class="li1"><div class="de1"> <span class="kw1">fi</span></div></li>
<li class="li1"><div class="de1"> <span class="re2">pkg</span>=<span class="re4">$1</span></div></li>
<li class="li1"><div class="de1"> <span class="kw3">shift</span></div></li>
<li class="li1"><div class="de1"> </div></li>
<li class="li1"><div class="de1"> <span class="br0">[</span><span class="br0">[</span> <span class="re5">-z</span> <span class="re1">$tmp</span> <span class="br0">]</span><span class="br0">]</span> <span class="sy0">&&</span> <span class="re2">tmpdir</span>=$<span class="br0">(</span><span class="kw2">mktemp</span> -d<span class="br0">)</span></div></li>
<li class="li1"><div class="de1"> </div></li>
<li class="li1"><div class="de1"> <span class="re2">pkg</span>=<span class="sy0">/</span>var<span class="sy0">/</span>cache<span class="sy0">/</span>pacman<span class="sy0">/</span>pkg<span class="sy0">/</span><span class="re1">$pkg</span></div></li>
<li class="li1"><div class="de1"> <span class="re2">file</span>=<span class="co1">${pacnew:1:-7}</span></div></li>
<li class="li1"><div class="de1"> <span class="re2">old</span>=<span class="st0">"<span class="es2">$tmpdir</span>"</span><span class="sy0">/</span><span class="co1">${file##*/}</span>.old</div></li>
<li class="li1"><div class="de1"> </div></li>
<li class="li1"><div class="de1"> <span class="kw2">tar</span> xJf <span class="st0">"<span class="es2">$pkg</span>"</span><span class="sy0">*</span> <span class="re5">--xform</span> <span class="st_h">'s#.*/##'</span> <span class="re5">--xform</span> <span class="st_h">'s/$/.old/'</span> <span class="re5">-C</span> <span class="st0">"<span class="es2">$tmpdir</span>"</span> <span class="st0">"<span class="es2">$file</span>"</span></div></li>
<li class="li1"><div class="de1"> gvim <span class="re5">-f</span> <span class="re5">-geometry</span> 199x60 <span class="re5">-d</span> <span class="st0">"<span class="es2">$old</span>"</span> <span class="st0">"/<span class="es2">$file</span>"</span> <span class="st0">"<span class="es2">$pacnew</span>"</span></div></li>
<li class="li1"><div class="de1"> <span class="kw2">rm</span> <span class="st0">"<span class="es2">$old</span>"</span></div></li>
<li class="li1"><div class="de1"> ic-question <span class="st0">"Remove <span class="es2">$pacnew</span> ?"</span></div></li>
<li class="li1"><div class="de1"> <span class="br0">[</span><span class="br0">[</span> <span class="re4">$?</span> <span class="re5">-eq</span> <span class="nu0">0</span> <span class="br0">]</span><span class="br0">]</span> <span class="sy0">&&</span> <span class="re2">SUDO_ASKPASS</span>=~<span class="sy0">/</span>bin<span class="sy0">/</span>sap <span class="kw2">sudo</span> <span class="re5">-A</span> <span class="kw2">rm</span> <span class="st0">"<span class="es2">$pacnew</span>"</span></div></li>
<li class="li1"><div class="de1"><span class="kw1">done</span></div></li>
<li class="li1"><div class="de1"><span class="br0">[</span><span class="br0">[</span> <span class="re5">-n</span> <span class="re1">$tmpdir</span> <span class="br0">]</span><span class="br0">]</span> <span class="sy0">&&</span> <span class="kw2">rmdir</span> <span class="re1">$tmpdir</span></div></li>
</ol></p>
<p>Now, this obviously would need tweaking (and could be improved), but it's an
example of what can be done.</p>
<p>In this script, it is assumed any old package can/will be found under
<code>/var/cache/pacman/pkg</code> and it uses <code>ic-question</code> as well a another little
script, <code>sap</code> which reads as follow:</p>
<p><ol class="bash"><li class="li1"><div class="de1"><span class="co0">#!/bin/bash</span></div></li>
<li class="li1"><div class="de1">ic-input <span class="re5">-H</span> <span class="st0">"$@"</span></div></li>
<li class="li1"><div class="de1"><span class="kw3">echo</span></div></li>
</ol></p>
<p>And uses <code>ic-input</code>, both of which are simple tool from <code>intercourse</code> (<a href="https://aur.archlinux.org/packages/intercourse/">available
in the AUR</a>) to provide GUI
interfaces to scripts, e.g. could be replaced with things like zenity or the
likes; You're in control.</p>
<h3>Download packages only</h3>
<p>In other news, the next version of kalu will also offer <strong>the ability to simply
download packages</strong> (but not perform the sysupgrade). This is about the same as
doing a <code>pacman -Syuw</code> but, again, <strong>using a temporary copy of your databases</strong>
so your databases aren't synced, for the same reason as always.</p>
<p>This works simply by starting a simulation, where you'll find a new button
"Download packages" waiting to be clicked. Then, after the usual polkit password
prompt (and a final confirmation), downloading of packages will occur.</p>
<p>This can allow you to "pre-download" packages ahead of time, but leaving the
actual sysupgrade to later, maybe when you have more time but less bandwidth
(nothing that some remains required, to sync your databases).</p>
<h3>Downloads and whatnot</h3>
<p>All this will be in the next kalu, alongside a few bugfixes and other minor
changes, for a full detailled list please refer to the git log. This next
version of kalu, which will be called kalu 3.0, is planned for soon after the
release of pacman 4.2 (<a href="https://mailman.archlinux.org/pipermail/pacman-dev/2014-June/019157.html">planned for August
31st</a>).</p>
<p>But if you can't wait & are willing to, or are already running <code>pacman-git</code>,
then you'll be happy to find a branch <code>pacman-next</code> <a href="https://github.com/jjk-jacky/kalu/tree/pacman-next">on
github</a>, which you can use
to build a compatible kalu, and benefit from all the aforementioned additions.
(You can use <a href="https://github.com/jjk-jacky/abs/tree/master/kalu-git">this PKGBUILD</a>
as source, making sure to change the branch name.)</p>
<p>See <a href="/kalu" title="kalu: Keep Arch Linux Up-to-date">kalu</a> for more about it in general, and of course, as always, new bug
reports, suggestions or any other form of constructive criticism is very much
welcome.</p>
Now you can script donnatella!2014-07-14T00:00:00+00:00http://jjacky.com/2014-07-14-now-you-can-script-donnatella<p>Finally pushed to the branch <code>next</code> on <a href="/donnatella" title="donnatella: your file manager">donnatella</a>'s
<a href="https://github.com/jjk-jacky/donnatella/tree/next">github</a> are a few commits,
focusing on one thing: allow you to script donnatella!</p>
<p>Since day one, customization has been a big thing in donna, with columns you can
create and customize fully, or click modes & key modes that let you decide
exactly which commands to trigger and when.</p>
<p>And while you could combine commands, either using the return value of a command
as argument for another one, or via special command <code>void()</code>, there was no
scripting: no conditions, loops, or the likes.</p>
<p>This was on purpose, because this is Linux, <strong>there are already plenty of
scripting languages out there</strong>, fast, powerful, and known; No need to add one
more.</p>
<p>Instead, the plan was always to allow you to "script" donnatella using the
language of your choice, and <strong>this would be done via a socket</strong> to communicate
with donnatella.</p>
</p>
<h3>donnatella adds a socket to open communication</h3>
<p>On start, a socket is created as <code>$XDG_RUNTIME_DIR/donnatella_socket_PID</code> (where
PID is donnatella's process ID).</p>
<p>This socket will be used to send messages to, and receives messages from, donna.</p>
<h4>A bit of "technical" talk</h4>
<p>Messages sent via this socket must be the length of the message as string,
followed by a colon and the message. For example, to send <code>FOOBAR</code> the message
sent shall be <code>6:FOOBAR</code></p>
<p>Messages can either start with a command (nothing to do with donna's command),
then a space and some arguments, or simply be a command.</p>
<p>donna will respond with a message starting with either "OK" or "ERR", the
command, and optionally extra information, separated by spaces. For example,
a full message could be <code>26:ERR FOOBAR Unknown command</code></p>
<p>If multiple commands were sent, the first response message will refer to the
first one received/sent, since they're processed in the order they're received.</p>
<h4>What can you do with this?</h4>
<p>Pretty much, anything that can be done in donna. Let's take it slow: the first
command is "VERSION" and doesn't take any arguments. The response will be the
version number of donnatella.</p>
<p>The other command is "TRIGGER" and allows to trigger any node, i.e. it does
indeed give full power to everything in donna. The given full location is parsed
as expected, so prefixes/aliases are supported.</p>
<p>On success, an ID is given (e.g. "OK TRIGGER 1") which can then be used
to cancel the task, should one want to.</p>
<p>It will also be used when the task reaches POST_RUN state, as either:</p>
<ul>
<li>"DONE <ID>[ <RETURN VALUE>]"</li>
<li>"CANCELLED <ID>"</li>
<li>"FAILED <ID>[ <ERROR MESSAGE>]</li>
</ul>
<p>The return value will be as intref when it was a treeview, node, terminal, or an
array (or nodes or strings).</p>
<p>Ideally scripts should free the intrefs they get once done, using new command
<code>intref_free()</code> If they fail to do so, intref-s will still be free after some
time as part of an internal's garbage collecting process.</p>
<h3>A socket is nice, but maybe not easy to use...</h3>
<p>You can of course use the socket directly from your script, but that might not
be the easiest to do, so <strong>a little helper tool is introduced: donna-trigger</strong></p>
<p>donna-trigger makes it easy to trigger nodes via donna's socket, e.g. from
script. It takes a full location as argument, connects to donnatella's socket
and sends a message to trigger it.</p>
<p>It then waits until the task is done, cancelled or failed. When done, the return
value (if any) - or if it failed (or the TRIGGER failed, e.g. invalid location)
the error message (if any) - will be printed on stdout.</p>
<p>Since it uses environment variable <code>DONNATELLA_SOCKET</code> (set whenever executing
something from donna) one can simply do in bash e.g:</p>
<pre><code>ret=$(donna-trigger foobar)
</code></pre>
<p>to trigger "foobar" and get the return value/error message in <code>$ret</code> The return
code will indicate if it worked or not.</p>
<h3>Where to get it?</h3>
<p>For Arch Linux users, you can use
<a href="https://aur.archlinux.org/packages/donnatella-git/">donnatella-git</a> in the AUR
to easilly get it. Or simply clone the git repo from
<a href="https://github.com/jjk-jacky/donnatella/tree/next">github</a> and compile things
yourself.</p>
<p>For a a complete list of all changes/bug fixes please refer to the git log.</p>
<p>And in case you read all that and are wondering what donnatella is, or are
looking for more information, download links, etc please refer to <a href="/donnatella" title="donnatella: your file manager">donnatella</a>.</p>
<p>As always, bug reports, suggestions or any other form of constructive criticism
is very much welcome. You can open issues on
<a href="https://github.com/jjk-jacky/donnatella/issues">github</a>, use the thread on Arch
Linux forums, or simply email me.</p>
Fluid time format and custom properties in donnatella2014-05-24T00:00:00+00:00http://jjacky.com/2014-05-24-donnatella-fluid-time-format-and-custom-properties<p>Freshly pushed to the branch <code>next</code> on <a href="/donnatella" title="donnatella: your file manager">donnatella</a>'s
<a href="https://github.com/jjk-jacky/donnatella/tree/next">github</a> are a few commits,
some fixes and other improvements here and there of course, as well as the
introduction of a new time format called "fluid" and some changes regarding
custom properties.</p>
<p>First off, the obligatory screenshot that might make everything obvious in
seconds:</p>
</p>
<p><img src="/donnatella/donnatella-ss7.png" alt="donnatella: New "fluid" time format" title="donnatella: New fluid time format" /></p>
<h3>The "fluid" format</h3>
<p>As <a href="/2014-04-20-columns-format-and-command-exec-in-donnatella/" title="Columns format and command exec in donnatella @ jjacky.com">seen previously</a>,
donnatella allows you to use a format string to chose how dates/times should be
represented, and besides the many usual specifiers, even adds one to show the
age (e.g. 42 min ago).</p>
<p>Now I'm adding another one, which you might actually already be familiar with
since, giving proper credits, it's very much inspired from what the GTK2 file
chooser uses.</p>
<p>The idea is that when the file (let's make this easy and pretend we're talking
about the modified timestamp of a file) was modified today, only the time will
be shown. If it was modified yesterday, the time will be prefixed with
"Yesterday". If modified within the last 7 days, the weekday will then be
prefixed instead; And when modified before that, the date is then shown.</p>
<p>This actually makes for a very simple way to get a sense of when a file was
modified, while still getting the actual information (e.g. as opposed to using
the age). Of course, the actual time & date formats used can be configured via
new options (<code>fluid_time_format</code> and <code>fluid_date_format</code>), and you can also
decide whether to use the full or abbreviated weekday via boolean option
<code>fluid_short_weekday</code>.</p>
<p>When showing the date, only the date format is used, allowing you to choose
whether to only shown the date and also include the time, as you wish. In the
screenshot above, for example, the time was included in the time format as well.</p>
<p>You might also suspect that a new column option was introduced for a few
columntypes, such as time: <code>align</code> So you can align the column's content on
left, center or right as you please.</p>
<p>It might be worth noting that this is (obviously) implemented in donnatella,
which means you get pretty much the same behavior as with GTK2 filechooser (only
customizable). Because things changed with GTK3, and though the filechooser
still uses similar formatting rules, it's a bit different: e.g. it will show
only the time not when the file was modified today, but when it was done within
<u>the last 24 hours</u>. How is that an improvement and not just annoyingly
confusing I don't know, but then again recent changes in GTK3 have left me
perplexed before... Luckily donna isn't affected here.</p>
<h4>Why the name, "fluid" ?</h4>
<p>Short version: the specifier <code>f</code> was available, and it seemed to match somehow.</p>
<p>Long version: See short version.</p>
<h3>Incompatible changes regarding custom properties</h3>
<p>From now on, the output parsed by donnatella to refresh custom properties has
changed a bit: instead of using colon (<code>:</code>) as separator, the pipe sign (<code>|</code>)
should now be used.
So any definition or scripts you might have been using will need to be updated.</p>
<p>Why? Simply because it works just as well, but given its special meaning on a
shell, I'll guess files are less likely to contain a pipe sign than they are a
colon.</p>
<h3>Custom properties: new option "use_nuls"</h3>
<p>Why if you have files with pipe signs in them? Well, set new option <code>use_nuls</code>
to <code>true</code> when defining your custom properties, and a different parser will be
used, one that still use pipe sign as separator (though no more LF), but also
expects both filename and property value to be NUL-terminated strings.</p>
<p>For example an output could look like the following:</p>
<pre><code><FILENAME><NUL>|<PROPERTY>|<VALUE><NUL><FILENAME><NUL>|<PROPERTY>|<VALUE><NUL>
</code></pre>
<h3>What's the "Uncomp." column in the screenshot?</h3>
<p>Just another example of what can be done with custom properties in donna.
Specifically, this column shows the uncompressed size of each file.</p>
<p>How does it do that? Well, <code>xz</code> can give the information so all you need is to
create a custom property to get it, e.g:</p>
<pre><code>[custom_properties/]
domain=fs
filter=name:"+f" AND name:"$.xz"
[custom_properties//uncompressed_size]
type:cp-type=uint
cmdline=sh -c 'xz -l --robot %:n | awk '"'"'/^name/{print $2"|"} /^file/{print "|uncompressed_size|"$5}'"'"
</code></pre>
<p>Now imagine you have a column defined as such:</p>
<pre><code>[defaults/lists/columns/uncompressed_size]
type:ct=size
property=uncompressed_size
title=Uncomp.
width=80
</code></pre>
<p>And you could get something like what you saw in the screenshot earlier. Simple
as that.</p>
<h3>Where to get it?</h3>
<p>For Arch Linux users, you can use
<a href="https://aur.archlinux.org/packages/donnatella-git/">donnatella-git</a> in the AUR
to easilly get it. Or simply clone the git repo from
<a href="https://github.com/jjk-jacky/donnatella/tree/next">github</a> and compile things
yourself.</p>
<p>For a a complete list of all changes/bug fixes please refer to the git log.</p>
<p>And in case you read all that and are wondering what donnatella is, or are
looking for more information, download links, etc please refer to <a href="/donnatella" title="donnatella: your file manager">donnatella</a>.</p>
<p>As always, bug reports, suggestions or any other form of constructive criticism
is very much welcome. You can open issues on
<a href="https://github.com/jjk-jacky/donnatella/issues">github</a>, use the thread on Arch
Linux forums, or simply email me.</p>
Show & use any properties you want: donnatella adds custom properties!2014-05-04T00:00:00+00:00http://jjacky.com/2014-05-04-donnatella-adds-custom-properties<p>Freshly pushed to the branch <code>next</code> on <a href="/donnatella" title="donnatella: your file manager">donnatella</a>'s
<a href="https://github.com/jjk-jacky/donnatella/tree/next">github</a> are a few commits,
as usual some fixes and other improvements of course, but mainly this is about
the addition of "custom properties."</p>
<p>As you may know, in donna everything is a node, and a node has properties. They
are the name, size, dates and permissions of your files for example. But
sometimes you need more than just those basic properties, and donna will let you
use whatever you want...</p>
</p>
<h3>Introducing custom properties</h3>
<p><img src="/donnatella/donnatella-ss6.png" alt="donnatella: Custom properties in action" title="donnatella: Custom properties in action" /></p>
<p>It is now possible to easilly add properties to any nodes you want. The way this
works is:</p>
<ol>
<li>you specify on which nodes to add the property. This will be done using
donna's powerful filtering system.</li>
<li>you specify the name (and type) of the property to add, as well as the
command line that will be executed in order to get the property's value.</li>
<li>voilà!</li>
</ol>
<p>Well, almost. Obviously you then need to use this property; This will simply be
done like with any other: create a new column for said property, and you'll be
able to add this column whenever you need. You can even sort/filter via this
column if you want.</p>
<h3>How is a property's value obtained?</h3>
<p>When donna needs to obtain/refresh a property, it will execute the specified
command line for the custom property (CP), usually specifying the node (file)
for which it is needed.</p>
<p>The process output will then be parsed, expecting to get a line with the node's
location (e.g. /full/path/filename), a pipe sign as separator, the property's
name, another pipe sign, and the value until the end of line (LF).</p>
<p>As you may have guessed, donna will try and "regroup" refresh requests, so that
one process can be started to refresh a property on multiple nodes/files at
once.</p>
<p>There's also the possibility of having multiple properties handled as a group
(by one command line), for cases where the program reads the file and obtains
all properties at once, hence the need for the property name as well.</p>
<h3>Your first custom property</h3>
<p>Custom properties can be of 2 types as of now: string, and uint (for sizes or
timestamps). For a simple example, let's say we want to show the last commit
message (from a git repo) associated with files/folders in a given repo.
Somewhat like what you see on many git interfaces, starting with github.</p>
<p>The script for such a CP (named <code>git-commit</code>) could be something like the
following:</p>
<p><ol class="bash"><li class="li1"><div class="de1"><span class="co0">#!/bin/bash</span></div></li>
<li class="li1"><div class="de1"><span class="kw1">while</span> <span class="br0">[</span><span class="br0">[</span> <span class="re5">-n</span> <span class="re4">$1</span> <span class="br0">]</span><span class="br0">]</span>; <span class="kw1">do</span></div></li>
<li class="li1"><div class="de1"> <span class="re2">file</span>=<span class="re4">$1</span></div></li>
<li class="li1"><div class="de1"> <span class="kw3">shift</span></div></li>
<li class="li1"><div class="de1"> <span class="re2">path</span>=<span class="co1">${file%/*}</span></div></li>
<li class="li1"><div class="de1"> <span class="re2">msg</span>=$<span class="br0">(</span><span class="kw2">git</span> <span class="re5">-C</span> <span class="st0">"<span class="es2">$path</span>"</span> log <span class="re5">-1</span> HEAD <span class="re5">--format</span>=<span class="st0">"format:%s"</span> <span class="re5">--</span> <span class="st0">"<span class="es2">$file</span>"</span><span class="br0">)</span></div></li>
<li class="li1"><div class="de1"> <span class="kw3">echo</span> <span class="st0">"<span class="es2">$file</span>|git-commit|<span class="es2">$msg</span>"</span></div></li>
<li class="li1"><div class="de1"><span class="kw1">done</span></div></li>
</ol></p>
<p>As for definning the property in donna, a simple config will do:</p>
<pre><code>[custom_properties/]
domain=fs
filter=location:"^/path/to/project folder/"
[custom_properties//git-commit]
cmdline=git-commit %:n
</code></pre>
<p>The filter makes sure we only add this property to files in our project, and it
assumes our script above - named after the CP - is in the path. <code>%:n</code> will put
every file path/name in between quotes, as expected.</p>
<p>Obviously it requires a column "location" defined as such:</p>
<pre><code>[defaults/lists/columns/location]
type:ct=text
property=location
</code></pre>
<p>The last thing left to do is show this property in a (new) column. The default
configuration actually includes a column "text" which can be used here. A simple
arrangement such as the following will do the trick :</p>
<pre><code>[arrangements/]
mask=^/path/to/project folder
columns=ln,name,text,size,time,own,perms
[arrangements//columns_options/name]
width=200
[arrangements//columns_options/text]
title=Last Commit
width=230
property=git-commit
refresh_properties:col-rp=preload
</code></pre>
<p>This arrangement redefines the columns layout, adding our column text. Since a
new column is added, we reduce the size of column name to make room for the new
one, specifying the needed options to show our custom property.</p>
<h3>When are CPs refreshed?</h3>
<p>You'll probably have noticed option <code>refresh_properties</code> in our arrangement
above: Indeed, by default donna only creates the CP on the node, but no value is
set.</p>
<p>The idea is that if said property is never used, the value will never be needed,
or refreshed. And only when it is needed will donna trigger the command line to
refresh the value. As said before, it waits a little (about 800ms) before
actually triggering the refresh, so one call can be done for multiple
nodes/files at once.</p>
<p>However, sometimes this might not give the best results. There are a couple of
possibilities:</p>
<ul>
<li>you can set option <code>preload</code> to <code>true</code> when defining the CP, in which case a
refresh request will be emitted right after the property has been added to a
node. That way the property has a value set as soon as possible, but it also
means it's always loaded, even when the node is simply used e.g. in a menu,
and the CP never actually used.</li>
<li>you can use a column's option <code>refresh_properties</code> to define when the treeview
will trigger a refresh of the property: <code>visible</code> (default) to do so only when
the row is visible; <code>preload</code> to also request refresh for non-yet-visible
rows (as in, scrolling is needed, this does not apply to hidden rows, e.g. via
a visual filter); or <code>on_demand</code> to have a refresh icon shown in the column,
requiring a user action (click on said icon) to trigger the refresh. The last
option is especially useful when refreshing the property can be a slow
operation, e.g. reading the entire file to calculate its hash (MD5, SHA1,
etc).</li>
</ul>
<h3>Video properties: A group of CPs</h3>
<p>Sometimes the program you'll use to refresh a property can get more than one
property at once; for example imagine using mediainfo to get the duration, video
& audio codecs from video files. One call to mediainfo can be used to get all 3
properties at once, and to allow to only run it once instead of three times, you
can use groups.</p>
<p>Creating a group of properties is very muck like a "regular" CP; Here's an
example:</p>
<pre><code>[custom_properties/]
domain=fs
filter=name:"+f" AND name:"|$.avi|$.mp4|$.mkv"
[custom_properties//video]
is_group=true
cmdline=mediainfo --output=file:///path/to/template %:n
[custom_properties//video/duration]
[custom_properties//video/vcodec]
[custom_properties//video/acodec]
</code></pre>
<p>This creates a group "video" with 3 properties - "duration", "vcodec" and
"acodec" - which will be expected to all be refreshed when the command line is
executed. Obviously, if refresh requests of all 3 properties are performed on
the same file, only one will be processed.</p>
<p>And to go along those CPs, here are corresponding columns :</p>
<pre><code>[defaults/lists/columns/duration]
type:ct=text
title=Duration
width=80
property=duration
refresh_properties:col-rp=on_demand
[defaults/lists/columns/vcodec]
type:ct=text
title=Video
width=55
property=vcodec
refresh_properties:col-rp=on_demand
[defaults/lists/columns/acodec]
type:ct=text
title=Audio
width=55
property=acodec
refresh_properties:col-rp=on_demand
</code></pre>
<p>Add those columns in the appropriate arrangement, or toggle them manually, and
you'll be able to get those video properties for any video file in one simple
click on a refresh icon.</p>
<p>Note that one can also use command <code>tv_column_refresh_nodes()</code> to refresh such
properties on one or more rows at once. For example, you could select all the
files for which you want the properties refreshed, and use
<code>tv_column_refresh_nodes (:active,:selected,,duration)</code> to refresh them all at
once (i.e. in one single command line execution. Note that there might be more
than one, as if requests for at least 20 nodes/files have been emitted, donna
might not wait the full 800ms and trigger a command line execution before that).
Only asking for one of the properties is enough to refresh them all, since
they're in the same group.</p>
<h3>Examples</h3>
<p>A few more notes about the examples that can be seen in the screenshot on top.</p>
<h4>Package version</h4>
<p>The example shows the folder with the different PKGBUILDs I maintain. In
addition to the last commit message for each folder, is a pkgver. This is simply
done via a small script like the following:</p>
<p><ol class="bash"><li class="li1"><div class="de1"><span class="co0">#!/bin/bash</span></div></li>
<li class="li1"><div class="de1"><span class="kw1">while</span> <span class="br0">[</span><span class="br0">[</span> <span class="re5">-n</span> <span class="re4">$1</span> <span class="br0">]</span><span class="br0">]</span>; <span class="kw1">do</span></div></li>
<li class="li1"><div class="de1"> <span class="re2">file</span>=<span class="re4">$1</span></div></li>
<li class="li1"><div class="de1"> <span class="kw3">shift</span></div></li>
<li class="li1"><div class="de1"> <span class="kw1">if</span> <span class="br0">[</span><span class="br0">[</span> <span class="re5">-f</span> <span class="st0">"<span class="es2">$file</span>/PKGBUILD"</span> <span class="br0">]</span><span class="br0">]</span>; <span class="kw1">then</span></div></li>
<li class="li1"><div class="de1"> <span class="re2">ver</span>=$<span class="br0">(</span><span class="kw2">grep</span> ^<span class="re2">pkgver</span>= <span class="st0">"<span class="es2">$file</span>/PKGBUILD"</span><span class="br0">)</span></div></li>
<li class="li1"><div class="de1"> <span class="kw3">echo</span> <span class="st0">"<span class="es2">$file</span>|pkgver|<span class="es3">${ver:7}</span>"</span></div></li>
<li class="li1"><div class="de1"> <span class="kw1">else</span></div></li>
<li class="li1"><div class="de1"> <span class="co0"># set the property to empty string (avoid try to refreshing it</span></div></li>
<li class="li1"><div class="de1"> <span class="co0"># again if it had failed/not be set)</span></div></li>
<li class="li1"><div class="de1"> <span class="kw3">echo</span> <span class="st0">"<span class="es2">$file</span>|pkgver|"</span></div></li>
<li class="li1"><div class="de1"> <span class="kw1">fi</span></div></li>
<li class="li1"><div class="de1"><span class="kw1">done</span></div></li>
</ol></p>
<h4>Mediainfo</h4>
<p>Here's the template file used with mediainfo to refresh the properties :</p>
<pre><code>General;%CompleteName%|duration|%Duration/String3%\n
Video;|vcodec|%Codec/String%\n
Audio;|acodec|%Codec%\n
</code></pre>
<p>As you can see, it is possible not to repeat the full filename for each
properties, omitting it and simply starting the line with a pipe sign will have
donna use the last file.</p>
<p>It it also possible to first output a line with the full filename and a pipe
sign at the end, nothing else (no property name/value), and then lines with
properties names & value, starting with a pipe sign but omitting the full
filename.</p>
<p>This obviously is only useful for groups (though supported all the time), when
multiple properties are refreshed for each file.</p>
<h4>File Hashes</h4>
<p>Last example featured on the screenshot: here's how you could create a property
"md5" that, when refreshed, would contain the MD5 of the file:</p>
<pre><code>[custom_properties/]
domain=fs
filter=+f
[custom_properties//md5]
cmdline=sh -c 'md5sum %:n | awk '"'"'{ v=$1;$1="";print substr($0,2)"|md5|"v }'"'"
</code></pre>
<p>Remember that command lines in donnatella aren't shells, so to use any shell
feature (e.g. pipe redirection) you need to start a shell.</p>
<p>(Also make sure to set the column's option <code>refresh_properties</code> to <code>on_demand</code>
as to not have MD5 of every listed/visible files be calculated automatically
- unless that's what you want, of course.)</p>
<h3>Sorting & filtering via CPs</h3>
<p>Quick note regarding performing operations such as sorting or filtering using
custom properties: Obviously, it can be done exactly as with "regular"
properties, and it'll work just the same.</p>
<p>However, note that if the properties' values aren't yet known, refresh requests
will be triggered, but it will be done via single execution and in blocking
manner.</p>
<p>So if not all rows have had their properties refreshed, it might be a good idea
to refresh them all (e.g. using <code>tv_column_refresh_nodes()</code>) before.</p>
<p>One exception is when the column option <code>refresh_properties</code> is set to
<code>on_demand</code>, in which case only known values will be used. When sorting, all
unset values will be listed last, when filtering they will simply not match.</p>
<h3>Where to get it?</h3>
<p>For Arch Linux users, you can use
<a href="https://aur.archlinux.org/packages/donnatella-git/">donnatella-git</a> in the AUR
to easilly get it. Or simply clone the git repo from
<a href="https://github.com/jjk-jacky/donnatella/tree/next">github</a> and compile things
yourself.</p>
<p>For a a complete list of all changes/bug fixes please refer to the git log.</p>
<p>And in case you read all that and are wondering what donnatella is, or are
looking for more information, download links, etc please refer to <a href="/donnatella" title="donnatella: your file manager">donnatella</a>.</p>
<p>As always, bug reports, suggestions or any other form of constructive criticism
is very much welcome. You can open issues on
<a href="https://github.com/jjk-jacky/donnatella/issues">github</a>, use the thread on Arch
Linux forums, or simply email me.</p>
<p><u><strong>Edited on 2014-05-24:</strong> A recent change switched the separator used in the
output parsed for custom properties from colon to pipe sign. This post has been
edited to reflect the change.</u></p>
Columns formats and command exec in donnatella2014-04-20T00:00:00+00:00http://jjacky.com/2014-04-20-columns-format-and-command-exec-in-donnatella<p>Freshly pushed to the branch <code>next</code> on <a href="/donnatella" title="donnatella: your file manager">donnatella</a>'s
<a href="https://github.com/jjk-jacky/donnatella/tree/next">github</a> are a few commits,
some fixes and other improvements here and there of course, as well as the
addition of command exec, allowing to execute a command line as a command, and
have its output be the command's return value.</p>
<p>We'll see how this can be used, but first as some improvements and fixes were
done on column types, let's have a quick look at how columns work in donna.</p>
</p>
<p>As you may already know, most things in donna aren't hard-coded, but can be
configured. Columns are no exceptions, in fact donna doesn't provide columns,
but <u>columntypes</u>.</p>
<p>That is, you have the "engine" of a column, that you can configure the way you
want, and this combination of an engine, or columntype, a set of (generic &
columntype-specific) options, and a name of course, are what's known as a
column.</p>
<p>Options can be things such as e.g. the format to use for dates, but also which
property to use. For instance, a file has 3 properties containing a date
(a timestamp, really) : mtime, ctime, and atime.</p>
<p>And in donna, there's a columntype "time" which can be used with timestamps.
Which information will be shown is simply a matter of configuration: option
<code>property</code> defines which property it will use.</p>
<p>You can show the mtime, or the atime, or create two columns, one for each. And
if in the future some nodes were to have yet another timestamp in a new
property, you could very easily add a column for it.</p>
<h3>Formats</h3>
<p>Some columntypes do not really offer to format the information they show. The
columntype name will show the node's name, and there's not much to configure
there. (Though it does offer a few options when it comes to sorting.)</p>
<p>But for others, not everyone likes the same: when it comes to dates, permissions
or even sizes, you might have your habbits, your preferred formats.</p>
<p>As hinted before, donna will let you configure things to your liking. But
instead of simply listing a few of the most common formats, allowing you to pick
whichever fits you best, columntypes use a format string, often set via option
<code>format</code></p>
<h4>Sizes</h4>
<p>It might not seem like there's a lot of choice when it comes to sizes, but some
might want a rounded size to the best fitting unit, others rather have the raw
size (in bytes), while some might like a size always given in KiB or MiB for
instance.</p>
<p>All of those are available, and once again thanks to the use of format string,
you can combine them, e.g. you could use <code>%R (%b)</code> to have the size rounded (to
best-fitting unit), then the raw size in bytes in between parenthesis.</p>
<p>Of course, if you like to save your pixels, you might like to stick with one,
and put the other one in the tooltip. Indeed, most columntypes will also have an
option to set the format string to be used for tooltips, as each column can
provide its own tooltip.</p>
<h4>Dates/Times</h4>
<p>Format strings for dates are pretty common, and supported specifiers should
allow you to show your dates exactly how you want them. As always, via a
right-click on the column header, submenu "Options/Column Options/Column" will
list a few common formats you might like. Of course, the "Custom" option will
let you enter the format of your choice.</p>
<p>Supported specifers are the ones provided by GLib's <code>g_date_time_format()</code> and
should cover all possible needs. One thing that can come in handy and is
missing, though, is the age.</p>
<p>While having the actual date/time is obviously good, sometimes all you want to
know is how long ago was that file modified. So, donna adds specifier <code>%o</code> to
show just that, how much time as passed since the timestamp (or is left, should
it be in the future). E.g: "1h 23m ago"</p>
<p>Simple, and potentially of great help at times.</p>
<p>There's also <code>%O</code> which does the same, but works with a few other options, so
you can define a limit, and another format string to fallback to once the limit
is reached. E.g. show the age as long as the timestamp is from the last 7 days,
then back to a "regular" date/time format.</p>
<h4>User/Group/Permissions</h4>
<p>The same columntype, perms, handles the permissions, as well as the user (owner)
and group. Of course, as seen before, you can have all information in the same
column, or create as many columns as you see fit.</p>
<p>For permissions, the classic "rwxrwxrwx" format is available obviously. There is
also a specifier to try and limit the space required, showing only one group of
permissions, i.e. only one "rwx" group, the one that applies to you (e.g. group
if you're not the owner of the file, but are in the group).</p>
<p>There's also one to always show three letters, in lowercase when you do <strong>not</strong>
have the permission, in <u>uppercase</u> when you do. Additionally, the letter will
be in a color to give out extra info: in color "none" when the permission isn't
available to anyone, in regular color if other has permission, in color "group"
if group has it, and in color "user" if user has it.</p>
<p>Permissions are checked in that order, meaning that while with color "user" only
the user (owner) has the permission, while with regular color the permission if
available to other, but might also be available to user and/or group.</p>
<p>Of course, all mentioned colors are configurable; Defaults have green as color
"user", blue as color "group" and gray as color "none".</p>
<p>Quick example: if you see "RWx" with the "R" in black, the "W" in green and the
"x" in gray, it means you can read & write, no one can execute, and only user
can write. Had the "W" be in blue, it meant the group could write, whereas other
could not (not saying anything about owner).</p>
<p>The same color can also be used for user (owner) & group names: the user name
can be in color "user" when you are the owner, and the group name can be in
color "group" when you're not the owner, but are in the group. IOW your name
will be in green indicating you have user permissions, if not the group name
will be in blue when you have group permissions. If neither are in color, you
have other permissions.</p>
<h3>Provider exec: environment variables</h3>
<p>Provider exec allows to execute command line. It is now possible to use
enviroment variables in said command line, which will be resolved to their
values upon node creation.</p>
<p>Now when creating a node, location is processed and environment variables are
resolved. <code>$FOOBAR</code> will be replaced with its value (if any), quoted (to make
things easier). <code>$"FOOBAR</code> can be used for as-is value. Use <code>$$</code> to include a
literal dollar sign.</p>
<p>This is all done on node creation, so the node's location will then be the
resolved string (i.e. this isn't a shell-like parsing or anything.)</p>
<p>This allows to use <code>$SHELL</code> to open a new terminal, or <code>$EDITOR</code> to edit a file
using the correct eidtor, instead of needing to "hardcode" which editor to use
in the config.</p>
<h3>Execute something, as a command!</h3>
<p>As seen above, executing something has been possible with donna since day one,
via provider exec. In fact, donna has a few modes where it will either simply
start it, or wait for it to be done, it might also parse the output expecting a
full filename per line and process them as search results, or start things
inside an (embedded) terminal emulator.</p>
<p>But now, you can also use command <code>exec()</code> to execute something. How is that
different, you ask?</p>
<p>Well, it means donna will wait until the process is over, and then have its
output by used as return value of the command. Of course, that return value
could then be used as argument to yet another command...</p>
<p>Quick example: Are you familiar with
<a href="https://github.com/joelthelion/autojump/wiki" title="Autojump: a cd command that learns">autojump</a>?
It's a tool that given some "keywords" (partial path component) will find the
most commonly used match, and show its full name on stdout.</p>
<p>So, if you wanted to go to <code>/var/cache/pacman/pkg</code> you could use something like
<code>autojump cac pk</code> and it would respond with the desired path.</p>
<p>Usually you'd use <code>j</code> which would then automatically change to the resulting
directory. How about doing the same in donna?</p>
<p>Simply create a new alias, as such:</p>
<pre><code>[donna/aliases/j]
replacement=command:tv_set_location (:active, @exec (autojump
suffix=))
</code></pre>
<p>And now, pressing <code>:</code> in donna then enterring <code>j cac pk</code> will do extactly the
same, and jump to <code>/var/cache/pacman/pkg</code> directly.</p>
<p>This is, of course, only one example.</p>
<h4>Updating autojump's database</h4>
<p>Of course, to have "complete" support of autojump in donnatella, there's one
more thing required. Everytime you actually change location, you should let
autojump know about it, so it can update its database.</p>
<p>This can be achieved via new event "notify-dirname" which is trigerred whenever
the current dirname (i.e. current location in fs) is changed. So, simply adding
the following:</p>
<pre><code>[events/notify-dirname]
autojump=&autojump -a %d
</code></pre>
<p>Will do the trick.</p>
<h3>Updating your config to benefit from all of this</h3>
<p>Now, there's still work to do when it comes to upgrades in donna. Specifically,
there isn't currently a way to update/import new defaults, so that is a manual
operation. Archers, think of this as some king of <code>.pacnew</code> handling! ;)</p>
<p>Here's the patch to update your donnatella.conf from
<a href="/2014-04-03-donnatella-0.2.0-released/">v0.2.0</a>:</p>
<p><ol class="diff"><li class="li1"><div class="de1">diff --git a/misc/donnatella.conf b/misc/donnatella.conf</div></li>
<li class="li1"><div class="de1">index b6b<span class="re0">2a03</span>..bb1ec4f <span class="nu0">100644</span></div></li>
<li class="li1"><div class="de1"><span class="re3">--- a/misc/donnatella.conf</span></div></li>
<li class="li1"><div class="de1"><span class="re4">+++ b/misc/donnatella.conf</span></div></li>
<li class="li1"><div class="de1"><span class="re6">@@ -814,16 +814,16 @@ trigger=command:tv_set_visual_filter <span class="br0">(</span>%o, size:>=%mM<span class="br0">)</span></span></div></li>
<li class="li1"><div class="de1"> trigger=command:tv_column_edit <span class="br0">(</span>%o, %n, name<span class="br0">)</span></div></li>
<li class="li1"><div class="de1"> # F6 to edit focused item <span class="br0">(</span>vim in a terminal<span class="br0">)</span></div></li>
<li class="li1"><div class="de1"> <span class="br0">[</span>key_modes/donna/key_F6<span class="br0">]</span></div></li>
<li class="li1"><div class="de1"><span class="re7">-trigger=exec:!vim %:n</span></div></li>
<li class="li1"><div class="de1"><span class="re8">+trigger=exec:!$EDITOR %:n</span></div></li>
<li class="li1"><div class="de1"> # F9 to view focused item <span class="br0">(</span>less in a terminal<span class="br0">)</span></div></li>
<li class="li1"><div class="de1"> <span class="br0">[</span>key_modes/donna/key_F9<span class="br0">]</span></div></li>
<li class="li1"><div class="de1"><span class="re7">-trigger=exec:!less %:n</span></div></li>
<li class="li1"><div class="de1"><span class="re8">+trigger=exec:!$LESS %:n</span></div></li>
<li class="li1"><div class="de1"> </div></li>
<li class="li1"><div class="de1"> # Terminals</div></li>
<li class="li1"><div class="de1"> <span class="br0">[</span>key_modes/donna/key_t<span class="br0">]</span></div></li>
<li class="li1"><div class="de1"><span class="re7">-trigger=exec:!bash</span></div></li>
<li class="li1"><div class="de1"><span class="re8">+trigger=exec:!$SHELL</span></div></li>
<li class="li1"><div class="de1"> <span class="br0">[</span>key_modes/donna/key_T<span class="br0">]</span></div></li>
<li class="li1"><div class="de1"><span class="re7">-trigger=exec:>bash</span></div></li>
<li class="li1"><div class="de1"><span class="re8">+trigger=exec:>$SHELL</span></div></li>
<li class="li1"><div class="de1"> </div></li>
<li class="li1"><div class="de1"> # selection stuff -- note that this required a patched GTK <span class="br0">(</span>to invert range<span class="br0">)</span></div></li>
<li class="li1"><div class="de1"> <span class="br0">[</span>key_modes/donna/key_v<span class="br0">]</span></div></li>
<li class="li1"><div class="de1"><span class="re6">@@ -957,12 +957,12 @@ trigger=command:tv_save_tree_file <span class="br0">(</span>%o, @ask_text <span class="br0">(</span>Save Tree As...,Enter the name</span></div></li>
<li class="li1"><div class="de1"> name=Open Terminal Here</div></li>
<li class="li1"><div class="de1"> icon=terminal</div></li>
<li class="li1"><div class="de1"> is_sensitive=has_ref</div></li>
<li class="li1"><div class="de1"><span class="re7">-trigger=exec:!WORKDIR=%:n bash</span></div></li>
<li class="li1"><div class="de1"><span class="re8">+trigger=exec:!WORKDIR=%:n $SHELL</span></div></li>
<li class="li1"><div class="de1"> </div></li>
<li class="li1"><div class="de1"> <span class="br0">[</span>context_menus/tree_views/terminal_nw<span class="br0">]</span></div></li>
<li class="li1"><div class="de1"> name=...In New Window</div></li>
<li class="li1"><div class="de1"> is_sensitive=has_ref</div></li>
<li class="li1"><div class="de1"><span class="re7">-trigger=>WD=%:n bash</span></div></li>
<li class="li1"><div class="de1"><span class="re8">+trigger=>WD=%:n $SHELL</span></div></li>
<li class="li1"><div class="de1"> </div></li>
<li class="li1"><div class="de1"> <span class="br0">[</span>context_menus/tree_views/tree_visuals<span class="br0">]</span></div></li>
<li class="li1"><div class="de1"> type:context-type=empty</div></li>
</ol></p>
<p>Note that this obviously doesn't include the autojump support used as example,
though all you need is what was said: the alias to trigger autojump, and the
event to update its database.</p>
<h3>Where to get it?</h3>
<p>For Arch Linux users, you can use
<a href="https://aur.archlinux.org/packages/donnatella-git/">donnatella-git</a> in the AUR
to easilly get it. Or simply clone the git repo from
<a href="https://github.com/jjk-jacky/donnatella/tree/next">github</a> and compile things
yourself.</p>
<p>For a a complete list of all changes/bug fixes please refer to the git log.</p>
<p>And in case you read all that and are wondering what donnatella is, or are
looking for more information, download links, etc please refer to <a href="/donnatella" title="donnatella: your file manager">donnatella</a>.</p>
<p>As always, bug reports, suggestions or any other form of constructive criticism
is very much welcome. You can open issues on
<a href="https://github.com/jjk-jacky/donnatella/issues">github</a>, use the thread on Arch
Linux forums, or simply email me.</p>
Hey Archer, when did you install glibc?2014-04-15T00:00:00+00:00http://jjacky.com/2014-04-15-hey-archer-when-did-you-install-pam<p>Quick question for anyone who's been running Arch Linux for some time now:
<strong>do you know when you installed <code>glibc</code> ?</strong></p>
<p>This isn't a trick question or anything of the sort. Yes, glibc is a pretty
essential package, required by lots of things (directly or not), and you most
likely did install it when you installed your system. Remember, back in the
days...</p>
<p>But when was it, actually?</p>
</p>
<p>Any good Archer will not even need to think about it, a quick <code>grep glibc
/var/log/pacman.log</code> will provider the exact date <u>and time</u> of said
installation. Beautiful, simple, very Arch. So what's that date for you?</p>
<p>If you're anything like me, you won't have it. You'll have plenty of dates,
every time said package was updated, but oddly enough it seems it never was
installed.</p>
<h3>I don't install my system, only upgrade it...</h3>
<p>Let's rewind a bit: As I do every once in a while, earlier today I ran <code>pacman
-Qdtq</code> to see if there wasn't any packages installed on my system that shouldn't
be. I have a few packages that show up, it's normal I know why.</p>
<p>But today I noticed one I wasn't familiar with: <code>libgssglue</code></p>
<p>What's that? Probably an old dependency that isn't required anymore, and I
should get rid of it. But from where did it come, and how long has it been
uselessly eating my precious disk space?</p>
<p>A few grep & less later, I was confused. Seems I have never installed this one;
Upgraded it, yes, a couple of times even. But no installation...
I have installed the kernel, even pacman itself, but not libgssglue. What's so
special about it?</p>
<p>I looked things up on another machine, same deal. Quickly start a VM I use for
tests and stuff, again, same thing. Took me a little while to figure it out...</p>
<p>Back when, I used the old CLI installer that came with Arch, and it took care of
creating the partitions, file systems, and installing the first batch of
packages (amongst other things).</p>
<p>And I had never really looked into it more, plus I knew much less then than I do
today about this whole Linux thing, and even the times I looked into my
pacman.log I never noticed/paid attention to the fact that it didn't actually
start properly.</p>
<p>If you've also used that old installer to set up your system, the first line of
your pacman.log probably says something about when package <code>filesystem</code> was
installed.</p>
<p>Because until then, most likely <strong>there was simply no folder <code>/var/log</code> for
pacman to write its log in</strong>! So anything that was installed before, there's no
log of it.
And that would include <code>libgssglue</code>, which - until the end of last year - used
to be a dependency of <code>libtirpc</code>, itself a dependency of <code>pam</code>.</p>
<p>Of course, any "recent" installation, i.e. done using <code>pacstrap</code>, won't have
this issue, as it creates a few folders - including <code>/var/log</code> - before running
pacman.</p>
<h3>About those old dependencies that aren't needed anymore</h3>
<p>This fun little mystery solved, it also reminded me of something else. I thought
I did a <code>Qdtq</code> somewhat regularly, but either I don't, or I had completely
missed things for the four months of 2014 so far.</p>
<p>And that reminded me of an idea I had, about adding an option to pacman, so that
it would handle those for me. Basically, it would notice, during a sysupgrade,
that a package has been "dropped" as dependency, and if it's now useless,
instead of keeping it around, even possibly upgrading it, it would remove it.</p>
<p>So naturally I spent a few hours looking into pacman's (ALPM's really) source
code, to see about adding such a thing. It's far from complete and pretty darn
ugly so far, but a quick pactest says it seems to work.</p>
<p>I'm not sure if pacman devs would like it or not, but hopefully I'll have a
patch to send their way at some point in the (not too distant) future...</p>
donnatella 0.2.0 released2014-04-03T00:00:00+00:00http://jjacky.com/2014-04-03-donnatella-0.2.0-released<p>A new version of donnatella, your GTK3 file manager, is available. A few things
have happened since the last push to branch <code>next</code> (and obviously even more
since v0.1.1).</p>
<p>Let's have a go over the main changes; First of all, since the last push to
<code>next</code> there were a few fixes & optimizations, as well as some
fixes/adjustements done regarding the latest GTK+ release (3.12.0), although
some dialogs (e.g. error messages, etc) might still not look too good, I'll have
to work on that.</p>
</p>
<p>Then, command <code>terminal_add_tab()</code> got a new argument to specify the working
directory of the new (embedded) terminal. And in the same spirit, one can now
define the working directory when using provider exec.</p>
<p>This is done simply by prefixing the command line (works in all modes but
desktop file) with either <code>WORKDIR=</code> or simply <code>WD=</code> followed by the directory
to use, quoted if needed.</p>
<p>As a simple example of this, a couple new items in the tree's default context
menu allow to "Open Terminal Here" (one as embedded terminal, the other as
external one).</p>
<h3>Changes since 0.1.1</h3>
<p>Quick recap over the different changes since last version :</p>
<ul>
<li>New event "log" to process some log events in donna; Messages are sent on
different occasions, e.g. loading/saving a treeview from/to a file, adding
nodes to a register, dropping a register, etc See <a href="/2014-02-22-coming-next-to-donnatella/">this
post</a> for more</li>
<li>New source ":app" for statusbar, supporting messages from event "log"</li>
<li>Command <code>tv_column_set_option()</code>: Fix setting "width" not working</li>
<li>treeview: Add option <code>default_save_location</code></li>
<li>Add command <code>tv_set_columns()</code> to change which columns are visible</li>
<li>Command <code>tv_set_option()</code> & <code>tv_column_set_option()</code>: Allow no value to set
in-memory values to configuration</li>
<li>Command <code>tv_set_option()</code>: Fix setting "title" not always working</li>
<li>Add command <code>tv_save_to_config()</code> to save group of options (treeview options,
columns (layout), column options, main/second sort order) to configuration
at once. See <a href="/2014-02-22-coming-next-to-donnatella/">this post</a> for more</li>
<li>ColumnType time: Fix getting "42m ago" on inline editing</li>
<li>Fix Enter/Esc not working to set/cancel on a few windows</li>
<li>Provider exec: Add options for prefixes: you can define which prefixes to
use for each supported modes, as well as the default mode. See <a href="/2014-03-09-donnatella-adds-embedded-terminals/">this
post</a> for more</li>
<li>treeview: Fix handling key before last key has been fully processed</li>
<li>ColumnTypes: Place floating windows on center of parent</li>
<li>Command <code>focus_set()</code>: Allow ":active" as treeview name</li>
<li>Add embedded terminal support (via XEMBED); See <a href="/2014-03-09-donnatella-adds-embedded-terminals/">this
post</a> for more</li>
<li>Provider exec: Add mode for embedded terminal</li>
<li>Patterns: Add support of different modes: pattern, search, begin, end, case
sensitive & case insensitive matches, and Perl-compatible regex. See <a href="/2014-03-23-visual-filters-extended-patterns-and-more-in-donnatella/">this
post</a>
for more</li>
<li>list: Fix reload possibly not doing anything</li>
<li>list: Add visual filters (commands <code>tv_{g,s}et_visual_filter</code>); See <a href="/2014-03-23-visual-filters-extended-patterns-and-more-in-donnatella/">this
post</a>
for more</li>
<li>treeview: status: Add <code>%f</code> for name of focused row</li>
<li>treeview: status: Add <code>%F</code> (current VF) and colors</li>
<li>treeview: status: Add <code>%h</code>/<code>%H</code> for nb/size of hidden rows</li>
<li>treeview: status: "avhsF" now support an extra w/ recursion; See <a href="/2014-03-23-visual-filters-extended-patterns-and-more-in-donnatella/">this
post</a>
for more</li>
<li>Command <code>tv_set_visual_filter()</code>: Add parameter toggle; and treat empty filter
as if unspecified</li>
<li>Commands <code>config_set_{boolean,int,string}</code>: Return set value</li>
<li>Add commands <code>config_try_get_{boolean,int,string}</code>: Doesn't fail if option
doesn't exist, but returns specified default</li>
<li>list: Fix status not refreshed after change of location</li>
<li>treeview: status: Add tooltip support (<code>format_tooltip</code>)</li>
<li>ColumnType name: Add filtering by node type (See <a href="/2014-03-23-visual-filters-extended-patterns-and-more-in-donnatella/">this
post</a>
for more)</li>
<li>list: Add option <code>vf_items_only</code></li>
<li>Alias: Fix option <code>replacement_no_args</code> not working</li>
<li>Alias: Add options <code>include_space</code> & <code>suffix</code></li>
<li>Provider exec: Fix output possibly truncated</li>
<li>Command <code>terminal_add_tab()</code>: Add param workdir</li>
<li>Provider exec: Add setting working directory on command line</li>
<li>Add "Open Terminal Here/...in new window" in tree context menu</li>
<li>Many other fixes & optimizations; see git log for details</li>
</ul>
<h3>Configuration updates</h3>
<p>As you might know if you've read the posts about changes pushed in <code>next</code>
alongside changes in the code, were changes in the (default) configuration as
well. And since almost everything in donna is configurable, you might wanna use
an updated config as well.</p>
<p>There are, however, no automatic process for this. You can use your favorite
tool to handle the merging, even do a 3-way merge using the original .conf file
if you want.</p>
<p>And in case it might help, here are the changes done between 0.1.1 and 0.2.0 :</p>
<p><ol class="diff"><li class="li1"><div class="de1">diff --git a/misc/donnatella.conf b/misc/donnatella.conf</div></li>
<li class="li1"><div class="de1">index 57f69b1..b6b<span class="re0">2a03</span> <span class="nu0">100644</span></div></li>
<li class="li1"><div class="de1"><span class="re3">--- a/misc/donnatella.conf</span></div></li>
<li class="li1"><div class="de1"><span class="re4">+++ b/misc/donnatella.conf</span></div></li>
<li class="li1"><div class="de1"><span class="re6">@@ -5,7 +5,7 @@</span></div></li>
<li class="li1"><div class="de1"> #</div></li>
<li class="li1"><div class="de1"> </div></li>
<li class="li1"><div class="de1"> <span class="br0">[</span>layouts<span class="br0">]</span></div></li>
<li class="li1"><div class="de1"><span class="re7">-std=paneH<span class="br0">(</span>!treeview:tree@230,treeview:list<span class="br0">)</span></span></div></li>
<li class="li1"><div class="de1"><span class="re8">+std=paneH<span class="br0">(</span>!treeview:tree@230,paneV<span class="br0">(</span>treeview:list@230,terminal:term<span class="br0">)</span><span class="br0">)</span></span></div></li>
<li class="li1"><div class="de1"> dp=paneH<span class="br0">(</span>!treeview:tree@230,paneV<span class="br0">(</span>treeview:foo,treeview:list<span class="br0">)</span><span class="br0">)</span></div></li>
<li class="li1"><div class="de1"> tm=paneV<span class="br0">(</span>paneH<span class="br0">(</span>!treeview:tree@230,paneV<span class="br0">(</span>treeview:list,treeview:list2<span class="br0">)</span><span class="br0">)</span>@300,!treeview:tm<span class="br0">)</span></div></li>
<li class="li1"><div class="de1"> </div></li>
<li class="li1"><div class="de1"><span class="re6">@@ -38,6 +38,10 @@ prefix=~</span></div></li>
<li class="li1"><div class="de1"> is_home_dir=true</div></li>
<li class="li1"><div class="de1"> </div></li>
<li class="li1"><div class="de1"> <span class="br0">[</span>donna/prefixes/<span class="br0">]</span></div></li>
<li class="li1"><div class="de1"><span class="re8">+prefix=:</span></div></li>
<li class="li1"><div class="de1"><span class="re8">+replacement=exec::</span></div></li>
<li class="li1"><div class="de1"><span class="re8">+</span></div></li>
<li class="li1"><div class="de1"><span class="re8">+<span class="br0">[</span>donna/prefixes/<span class="br0">]</span></span></div></li>
<li class="li1"><div class="de1"> prefix=></div></li>
<li class="li1"><div class="de1"> replacement=exec:></div></li>
<li class="li1"><div class="de1"> </div></li>
<li class="li1"><div class="de1"><span class="re6">@@ -61,10 +65,10 @@ replacement=command:</span></div></li>
<li class="li1"><div class="de1"> # ALIASES</div></li>
<li class="li1"><div class="de1"> </div></li>
<li class="li1"><div class="de1"> <span class="br0">[</span>donna/aliases/g<span class="br0">]</span></div></li>
<li class="li1"><div class="de1"><span class="re7">-replacement=exec:>git</span></div></li>
<li class="li1"><div class="de1"><span class="re8">+replacement=exec:!git</span></div></li>
<li class="li1"><div class="de1"> </div></li>
<li class="li1"><div class="de1"> <span class="br0">[</span>donna/aliases/m<span class="br0">]</span></div></li>
<li class="li1"><div class="de1"><span class="re7">-replacement=exec:>man</span></div></li>
<li class="li1"><div class="de1"><span class="re8">+replacement=exec:!man</span></div></li>
<li class="li1"><div class="de1"> </div></li>
<li class="li1"><div class="de1"> <span class="br0">[</span>donna/aliases/f<span class="br0">]</span></div></li>
<li class="li1"><div class="de1"> replacement=exec:<find</div></li>
<li class="li1"><div class="de1"><span class="re6">@@ -78,7 +82,7 @@ replacement=exec:<pacman -Qlq</span></div></li>
<li class="li1"><div class="de1"> #</div></li>
<li class="li1"><div class="de1"> </div></li>
<li class="li1"><div class="de1"> <span class="br0">[</span>statusbar<span class="br0">]</span></div></li>
<li class="li1"><div class="de1"><span class="re7">-areas=tasks,active,keys,focus</span></div></li>
<li class="li1"><div class="de1"><span class="re8">+areas=tasks,active,log,keys,focus</span></div></li>
<li class="li1"><div class="de1"> </div></li>
<li class="li1"><div class="de1"> <span class="br0">[</span>statusbar/tasks<span class="br0">]</span></div></li>
<li class="li1"><div class="de1"> source=:task</div></li>
<li class="li1"><div class="de1"><span class="re6">@@ -87,8 +91,18 @@ expand=false</span></div></li>
<li class="li1"><div class="de1"> </div></li>
<li class="li1"><div class="de1"> <span class="br0">[</span>statusbar/active<span class="br0">]</span></div></li>
<li class="li1"><div class="de1"> source=:active</div></li>
<li class="li1"><div class="de1"><span class="re7">-format=%v/%a files <span class="br0">(</span>%V<span class="br0">)</span> %N</span></div></li>
<li class="li1"><div class="de1"><span class="re8">+expand=false</span></div></li>
<li class="li1"><div class="de1"><span class="re8">+<span class="br0">{</span>% raw %<span class="br0">}</span>format=%<span class="br0">{</span>%s/<span class="br0">}</span>s%<span class="br0">{</span>no rows,1 row,%v rows<span class="br0">}</span>v <span class="br0">(</span>%<span class="br0">{</span>%S / <span class="br0">}</span>s%V<span class="br0">)</span>%<span class="br0">{</span> %h hidden <span class="br0">(</span>%H<span class="br0">)</span><span class="br0">}</span>h</span></div></li>
<li class="li1"><div class="de1"><span class="re8">+<span class="br0">{</span>% endraw %<span class="br0">}</span>format_tooltip=%<span class="br0">{</span>Current VF: %F<span class="br0">}</span>F</span></div></li>
<li class="li1"><div class="de1"> size_format=%R</div></li>
<li class="li1"><div class="de1"><span class="re8">+colors:tree-st-colors=vf</span></div></li>
<li class="li1"><div class="de1"><span class="re8">+foreground=blue</span></div></li>
<li class="li1"><div class="de1"><span class="re8">+</span></div></li>
<li class="li1"><div class="de1"><span class="re8">+<span class="br0">[</span>statusbar/log<span class="br0">]</span></span></div></li>
<li class="li1"><div class="de1"><span class="re8">+source=:app</span></div></li>
<li class="li1"><div class="de1"><span class="re8">+format=%d</span></div></li>
<li class="li1"><div class="de1"><span class="re8">+format_tooltip=donnatella v%v</span></div></li>
<li class="li1"><div class="de1"><span class="re8">+timeout=5</span></div></li>
<li class="li1"><div class="de1"> </div></li>
<li class="li1"><div class="de1"> <span class="br0">[</span>statusbar/keys<span class="br0">]</span></div></li>
<li class="li1"><div class="de1"> source=:focused</div></li>
<li class="li1"><div class="de1"><span class="re6">@@ -101,7 +115,7 @@ source=:focused</span></div></li>
<li class="li1"><div class="de1"> format=%o %K</div></li>
<li class="li1"><div class="de1"> width=<span class="nu0">100</span></div></li>
<li class="li1"><div class="de1"> expand=false</div></li>
<li class="li1"><div class="de1"><span class="re7">-key_modes_colors=true</span></div></li>
<li class="li1"><div class="de1"><span class="re8">+colors:tree-st-colors=keys</span></div></li>
<li class="li1"><div class="de1"> key_mode_select_background-rgba=rgba<span class="br0">(</span><span class="nu0">0</span>,<span class="nu0">42</span>,<span class="nu0">200</span>,<span class="nu0">0.8</span><span class="br0">)</span></div></li>
<li class="li1"><div class="de1"> key_mode_select_foreground=white</div></li>
<li class="li1"><div class="de1"> </div></li>
<li class="li1"><div class="de1"><span class="re6">@@ -155,12 +169,13 @@ notify=exec:&notify-send "Donnatella: A task just failed" %N</span></div></li>
<li class="li1"><div class="de1"> <span class="br0">[</span>defaults/trees<span class="br0">]</span></div></li>
<li class="li1"><div class="de1"> click_mode=tree</div></li>
<li class="li1"><div class="de1"> key_mode=donna</div></li>
<li class="li1"><div class="de1"><span class="re8">+default_save_location:save-location=ask</span></div></li>
<li class="li1"><div class="de1"> node_types:node-type=containers</div></li>
<li class="li1"><div class="de1"> show_hidden=false</div></li>
<li class="li1"><div class="de1"> sort_groups:sg=first</div></li>
<li class="li1"><div class="de1"> select_highlight:highlight=column</div></li>
<li class="li1"><div class="de1"> context_menu_menus=context</div></li>
<li class="li1"><div class="de1"><span class="re7">-context_menu=add_root,:move_root:up<:move_root:first>,:move_root:down<:move_root:last>,:remove_row,-,goto<goto_fs,marks>,-,save_tree<save_tree_as>,load_tree<load_tree_from>,-,tree_visuals<@tree_visuals>,-,tv_options<!tv_options>,-,@register,-,:register:+<@register:+>,-,:refresh<@refresh></span></div></li>
<li class="li1"><div class="de1"><span class="re8">+context_menu=add_root,:move_root:up<:move_root:first>,:move_root:down<:move_root:last>,:remove_row,-,goto<goto_fs,marks>,terminal<terminal_nw>,-,save_tree<save_tree_as>,load_tree<load_tree_from>,-,tree_visuals<@tree_visuals>,-,tv_options<!tv_options,-,save_tree_to_config>,-,@register,-,:register:+<@register:+>,-,:refresh<@refresh></span></div></li>
<li class="li1"><div class="de1"> </div></li>
<li class="li1"><div class="de1"> <span class="br0">[</span>defaults/trees/arrangement<span class="br0">]</span></div></li>
<li class="li1"><div class="de1"> columns=name</div></li>
<li class="li1"><div class="de1"><span class="re6">@@ -172,23 +187,25 @@ sort_column=name</span></div></li>
<li class="li1"><div class="de1"> <span class="br0">[</span>defaults/lists<span class="br0">]</span></div></li>
<li class="li1"><div class="de1"> click_mode=list</div></li>
<li class="li1"><div class="de1"> key_mode=donna</div></li>
<li class="li1"><div class="de1"><span class="re8">+default_save_location:save-location=ask</span></div></li>
<li class="li1"><div class="de1"> show_hidden=true</div></li>
<li class="li1"><div class="de1"> node_types:node-type=all</div></li>
<li class="li1"><div class="de1"> sort_groups:sg=first</div></li>
<li class="li1"><div class="de1"> select_highlight:highlight=column-underline</div></li>
<li class="li1"><div class="de1"> focusing_click=true</div></li>
<li class="li1"><div class="de1"> goto_item_set:tree-set=scroll,focus</div></li>
<li class="li1"><div class="de1"><span class="re8">+vf_items_only=false</span></div></li>
<li class="li1"><div class="de1"> history_max=<span class="nu0">100</span></div></li>
<li class="li1"><div class="de1"> context_menu_menus=context</div></li>
<li class="li1"><div class="de1"> context_menu=@go:tree,marks,-,add_to_tree<add_as_root>,-,!new_nodes,-,@register,-,@selection,-,column_edit<!column_edit>,-,:refresh<@refresh></div></li>
<li class="li1"><div class="de1"> context_menu_fs=@go:tree,marks,-,add_to_tree<add_as_root>,-,!new_nodes,new_items,-,@register,-,:register:+<@register:+>,-,@selection,-,column_edit<!column_edit,-,@touch>,-,:refresh<@refresh></div></li>
<li class="li1"><div class="de1"> context_menu_task=@selection,-,:refresh<@refresh>,-,@tasks</div></li>
<li class="li1"><div class="de1"><span class="re7">-context_menu_colheader=columns<!columns>,-,:sort_order<!sort_order>,:second_sort_order<!second_sort_order>,-,options<column_options<!column_options>,list_options<!tv_options>></span></div></li>
<li class="li1"><div class="de1"><span class="re8">+context_menu_colheader=columns<!columns>,-,:sort_order<!sort_order>,:second_sort_order<!second_sort_order>,-,options<column_options<!column_options>,list_options<!tv_options>>,-,save_list_to_config</span></div></li>
<li class="li1"><div class="de1"> </div></li>
<li class="li1"><div class="de1"> # some color filters</div></li>
<li class="li1"><div class="de1"> </div></li>
<li class="li1"><div class="de1"> <span class="br0">[</span>defaults/lists/arrangement/color_filters/<span class="br0">]</span></div></li>
<li class="li1"><div class="de1"><span class="re7">-filter=*.tar.*|*.tgz|*.zip|*.rar</span></div></li>
<li class="li1"><div class="de1"><span class="re8">+filter=|*.tar.*|*.tgz|*.zip|*.rar</span></div></li>
<li class="li1"><div class="de1"> column=name</div></li>
<li class="li1"><div class="de1"> foreground=green</div></li>
<li class="li1"><div class="de1"> </div></li>
<li class="li1"><div class="de1"><span class="re6">@@ -299,7 +316,7 @@ format_tooltip=%p <span class="br0">(</span>%o<span class="br0">)</span></span></div></li>
<li class="li1"><div class="de1"> color_user=green</div></li>
<li class="li1"><div class="de1"> color_group=blue</div></li>
<li class="li1"><div class="de1"> color_mixed=#00aaaa</div></li>
<li class="li1"><div class="de1"><span class="re7">-sort=1</span></div></li>
<li class="li1"><div class="de1"><span class="re8">+sort:sort-perms=myperms</span></div></li>
<li class="li1"><div class="de1"> </div></li>
<li class="li1"><div class="de1"> </div></li>
<li class="li1"><div class="de1"> # COLUMNS</div></li>
<li class="li1"><div class="de1"><span class="re6">@@ -335,7 +352,7 @@ title=Own</span></div></li>
<li class="li1"><div class="de1"> width=<span class="nu0">70</span></div></li>
<li class="li1"><div class="de1"> format=%V:%H</div></li>
<li class="li1"><div class="de1"> format_tooltip=</div></li>
<li class="li1"><div class="de1"><span class="re7">-sort=3</span></div></li>
<li class="li1"><div class="de1"><span class="re8">+sort:sort-perms=user</span></div></li>
<li class="li1"><div class="de1"> </div></li>
<li class="li1"><div class="de1"> <span class="br0">[</span>defaults/lists/columns/desc<span class="br0">]</span></div></li>
<li class="li1"><div class="de1"> type:ct=text</div></li>
<li class="li1"><div class="de1"><span class="re6">@@ -762,12 +779,51 @@ trigger=command:node_trigger<span class="br0">(</span>@ask_text<span class="br0">(</span>Enter FL to trigger<span class="br0">)</span><span class="br0">)</span></span></div></li>
<li class="li1"><div class="de1"> <span class="br0">[</span>key_modes/donna/key_slash<span class="br0">]</span></div></li>
<li class="li1"><div class="de1"> trigger=command:tv_start_interactive_search <span class="br0">(</span>%o<span class="br0">)</span></div></li>
<li class="li1"><div class="de1"> </div></li>
<li class="li1"><div class="de1"><span class="re8">+# Visual Filters</span></div></li>
<li class="li1"><div class="de1"><span class="re8">+<span class="br0">[</span>key_modes/donna/key_f<span class="br0">]</span></span></div></li>
<li class="li1"><div class="de1"><span class="re8">+type:key=spec</span></div></li>
<li class="li1"><div class="de1"><span class="re8">+spec:spec=lower,upper</span></div></li>
<li class="li1"><div class="de1"><span class="re8">+trigger=command:tv_set_visual_filter <span class="br0">(</span>%o, @config_get_string <span class="br0">(</span>filters/%k<span class="br0">)</span>, 1<span class="br0">)</span></span></div></li>
<li class="li1"><div class="de1"><span class="re8">+<span class="br0">[</span>key_modes/donna/key_F<span class="br0">]</span></span></div></li>
<li class="li1"><div class="de1"><span class="re8">+type:key=spec</span></div></li>
<li class="li1"><div class="de1"><span class="re8">+spec:spec=lower,upper</span></div></li>
<li class="li1"><div class="de1"><span class="re8">+trigger=command:tv_set_visual_filter <span class="br0">(</span>%o, @config_set_string <span class="br0">(</span>filters/%k, @ask_text <span class="br0">(</span>Enter filter %k,,@config_try_get_string <span class="br0">(</span>filters/%k, @tv_get_visual_filter <span class="br0">(</span>%o<span class="br0">)</span><span class="br0">)</span><span class="br0">)</span><span class="br0">)</span>, 1<span class="br0">)</span></span></div></li>
<li class="li1"><div class="de1"><span class="re8">+</span></div></li>
<li class="li1"><div class="de1"><span class="re8">+# VF: by age</span></div></li>
<li class="li1"><div class="de1"><span class="re8">+<span class="br0">[</span>key_modes/donna/key_ampersand<span class="br0">]</span></span></div></li>
<li class="li1"><div class="de1"><span class="re8">+type:key=combine</span></div></li>
<li class="li1"><div class="de1"><span class="re8">+spec:spec=custom</span></div></li>
<li class="li1"><div class="de1"><span class="re8">+custom_chars=HMSdmVY</span></div></li>
<li class="li1"><div class="de1"><span class="re8">+combine=age_unit</span></div></li>
<li class="li1"><div class="de1"><span class="re8">+<span class="br0">[</span>key_modes/donna/key_q<span class="br0">]</span></span></div></li>
<li class="li1"><div class="de1"><span class="re8">+combine=age_unit</span></div></li>
<li class="li1"><div class="de1"><span class="re8">+trigger=command:tv_set_visual_filter <span class="br0">(</span>%o, time:A%m%c<span class="br0">)</span></span></div></li>
<li class="li1"><div class="de1"><span class="re8">+<span class="br0">[</span>key_modes/donna/key_Q<span class="br0">]</span></span></div></li>
<li class="li1"><div class="de1"><span class="re8">+combine=age_unit</span></div></li>
<li class="li1"><div class="de1"><span class="re8">+trigger=command:tv_set_visual_filter <span class="br0">(</span>%o, time:A<=%m%c<span class="br0">)</span></span></div></li>
<li class="li1"><div class="de1"><span class="re8">+</span></div></li>
<li class="li1"><div class="de1"><span class="re8">+# VF: by size</span></div></li>
<li class="li1"><div class="de1"><span class="re8">+<span class="br0">[</span>key_modes/donna/key_less<span class="br0">]</span></span></div></li>
<li class="li1"><div class="de1"><span class="re8">+trigger=command:tv_set_visual_filter <span class="br0">(</span>%o, size:<=%mM<span class="br0">)</span></span></div></li>
<li class="li1"><div class="de1"><span class="re8">+<span class="br0">[</span>key_modes/donna/key_greater<span class="br0">]</span></span></div></li>
<li class="li1"><div class="de1"><span class="re8">+trigger=command:tv_set_visual_filter <span class="br0">(</span>%o, size:>=%mM<span class="br0">)</span></span></div></li>
<li class="li1"><div class="de1"><span class="re8">+</span></div></li>
<li class="li1"><div class="de1"><span class="re8">+</span></div></li>
<li class="li1"><div class="de1"><span class="re8">+# F2 to rename</span></div></li>
<li class="li1"><div class="de1"><span class="re8">+<span class="br0">[</span>key_modes/donna/key_F2<span class="br0">]</span></span></div></li>
<li class="li1"><div class="de1"><span class="re8">+trigger=command:tv_column_edit <span class="br0">(</span>%o, %n, name<span class="br0">)</span></span></div></li>
<li class="li1"><div class="de1"> # F6 to edit focused item <span class="br0">(</span>vim in a terminal<span class="br0">)</span></div></li>
<li class="li1"><div class="de1"> <span class="br0">[</span>key_modes/donna/key_F6<span class="br0">]</span></div></li>
<li class="li1"><div class="de1"><span class="re7">-trigger=exec:>vim %:n</span></div></li>
<li class="li1"><div class="de1"><span class="re8">+trigger=exec:!vim %:n</span></div></li>
<li class="li1"><div class="de1"> # F9 to view focused item <span class="br0">(</span>less in a terminal<span class="br0">)</span></div></li>
<li class="li1"><div class="de1"> <span class="br0">[</span>key_modes/donna/key_F9<span class="br0">]</span></div></li>
<li class="li1"><div class="de1"><span class="re7">-trigger=exec:>less %:n</span></div></li>
<li class="li1"><div class="de1"><span class="re8">+trigger=exec:!less %:n</span></div></li>
<li class="li1"><div class="de1"><span class="re8">+</span></div></li>
<li class="li1"><div class="de1"><span class="re8">+# Terminals</span></div></li>
<li class="li1"><div class="de1"><span class="re8">+<span class="br0">[</span>key_modes/donna/key_t<span class="br0">]</span></span></div></li>
<li class="li1"><div class="de1"><span class="re8">+trigger=exec:!bash</span></div></li>
<li class="li1"><div class="de1"><span class="re8">+<span class="br0">[</span>key_modes/donna/key_T<span class="br0">]</span></span></div></li>
<li class="li1"><div class="de1"><span class="re8">+trigger=exec:>bash</span></div></li>
<li class="li1"><div class="de1"> </div></li>
<li class="li1"><div class="de1"> # selection stuff -- note that this required a patched GTK <span class="br0">(</span>to invert range<span class="br0">)</span></div></li>
<li class="li1"><div class="de1"> <span class="br0">[</span>key_modes/donna/key_v<span class="br0">]</span></div></li>
<li class="li1"><div class="de1"><span class="re6">@@ -897,6 +953,17 @@ trigger=command:tv_save_tree_file <span class="br0">(</span>%o, %o, all<span class="br0">)</span></span></div></li>
<li class="li1"><div class="de1"> name=Save Tree As...</div></li>
<li class="li1"><div class="de1"> trigger=command:tv_save_tree_file <span class="br0">(</span>%o, @ask_text <span class="br0">(</span>Save Tree As...,Enter the name of the file<span class="br0">)</span>, all<span class="br0">)</span></div></li>
<li class="li1"><div class="de1"> </div></li>
<li class="li1"><div class="de1"><span class="re8">+<span class="br0">[</span>context_menus/tree_views/terminal<span class="br0">]</span></span></div></li>
<li class="li1"><div class="de1"><span class="re8">+name=Open Terminal Here</span></div></li>
<li class="li1"><div class="de1"><span class="re8">+icon=terminal</span></div></li>
<li class="li1"><div class="de1"><span class="re8">+is_sensitive=has_ref</span></div></li>
<li class="li1"><div class="de1"><span class="re8">+trigger=exec:!WORKDIR=%:n bash</span></div></li>
<li class="li1"><div class="de1"><span class="re8">+</span></div></li>
<li class="li1"><div class="de1"><span class="re8">+<span class="br0">[</span>context_menus/tree_views/terminal_nw<span class="br0">]</span></span></div></li>
<li class="li1"><div class="de1"><span class="re8">+name=...In New Window</span></div></li>
<li class="li1"><div class="de1"><span class="re8">+is_sensitive=has_ref</span></div></li>
<li class="li1"><div class="de1"><span class="re8">+trigger=>WD=%:n bash</span></div></li>
<li class="li1"><div class="de1"><span class="re8">+</span></div></li>
<li class="li1"><div class="de1"> <span class="br0">[</span>context_menus/tree_views/tree_visuals<span class="br0">]</span></div></li>
<li class="li1"><div class="de1"> type:context-type=empty</div></li>
<li class="li1"><div class="de1"> is_sensitive=has_ref</div></li>
<li class="li1"><div class="de1"><span class="re6">@@ -909,6 +976,10 @@ name=Tree Options</span></div></li>
<li class="li1"><div class="de1"> icon=preferences-desktop</div></li>
<li class="li1"><div class="de1"> submenu:enabled=enabled</div></li>
<li class="li1"><div class="de1"> </div></li>
<li class="li1"><div class="de1"><span class="re8">+<span class="br0">[</span>context_menus/tree_views/save_tree_to_config<span class="br0">]</span></span></div></li>
<li class="li1"><div class="de1"><span class="re8">+name=Save all options to configuration</span></div></li>
<li class="li1"><div class="de1"><span class="re8">+trigger=command:tv_save_to_config <span class="br0">(</span>%o,:options<span class="br0">)</span></span></div></li>
<li class="li1"><div class="de1"><span class="re8">+</span></div></li>
<li class="li1"><div class="de1"> </div></li>
<li class="li1"><div class="de1"> # LIST-SPECIFIC</div></li>
<li class="li1"><div class="de1"> </div></li>
<li class="li1"><div class="de1"><span class="re6">@@ -963,6 +1034,10 @@ type:context-type=empty</span></div></li>
<li class="li1"><div class="de1"> name=List Options</div></li>
<li class="li1"><div class="de1"> submenus:enabled=enabled</div></li>
<li class="li1"><div class="de1"> </div></li>
<li class="li1"><div class="de1"><span class="re8">+<span class="br0">[</span>context_menus/tree_views/save_list_to_config<span class="br0">]</span></span></div></li>
<li class="li1"><div class="de1"><span class="re8">+name=Save to configuration...</span></div></li>
<li class="li1"><div class="de1"><span class="re8">+trigger=command:tv_save_to_config <span class="br0">(</span>%o<span class="br0">)</span></span></div></li>
<li class="li1"><div class="de1"><span class="re8">+</span></div></li>
<li class="li1"><div class="de1"> # Selection</div></li>
<li class="li1"><div class="de1"> </div></li>
<li class="li1"><div class="de1"> <span class="br0">[</span>context_menus/tree_views/selection_select<span class="br0">]</span></div></li>
<li class="li1"><div class="de1"><span class="re6">@@ -1088,7 +1163,33 @@ not_active_list=true</span></div></li>
<li class="li1"><div class="de1"> #</div></li>
<li class="li1"><div class="de1"> </div></li>
<li class="li1"><div class="de1"> <span class="br0">[</span>providers/exec<span class="br0">]</span></div></li>
<li class="li1"><div class="de1"><span class="re7">-terminal=urxvt -hold -e</span></div></li>
<li class="li1"><div class="de1"><span class="re8">+default_mode:exec-mode=exec</span></div></li>
<li class="li1"><div class="de1"><span class="re8">+prefix_exec=&</span></div></li>
<li class="li1"><div class="de1"><span class="re8">+prefix_exec_and_wait=:</span></div></li>
<li class="li1"><div class="de1"><span class="re8">+prefix_terminal=></span></div></li>
<li class="li1"><div class="de1"><span class="re8">+prefix_embedded_terminal=!</span></div></li>
<li class="li1"><div class="de1"><span class="re8">+prefix_parse_output=<</span></div></li>
<li class="li1"><div class="de1"><span class="re8">+prefix_desktop_file==</span></div></li>
<li class="li1"><div class="de1"><span class="re8">+<span class="br0">[</span>providers/exec/terminal<span class="br0">]</span></span></div></li>
<li class="li1"><div class="de1"><span class="re8">+cmdline=urxvt -e</span></div></li>
<li class="li1"><div class="de1"><span class="re8">+<span class="br0">[</span>providers/exec/terminal/<span class="br0">]</span></span></div></li>
<li class="li1"><div class="de1"><span class="re8">+prefix=></span></div></li>
<li class="li1"><div class="de1"><span class="re8">+cmdline=urxvt -hold -e</span></div></li>
<li class="li1"><div class="de1"><span class="re8">+<span class="br0">[</span>providers/exec/embedded_terminal<span class="br0">]</span></span></div></li>
<li class="li1"><div class="de1"><span class="re8">+terminal=term</span></div></li>
<li class="li1"><div class="de1"><span class="re8">+<span class="br0">[</span>providers/exec/embedded_terminal/<span class="br0">]</span></span></div></li>
<li class="li1"><div class="de1"><span class="re8">+prefix=!</span></div></li>
<li class="li1"><div class="de1"><span class="re8">+terminal=term</span></div></li>
<li class="li1"><div class="de1"><span class="re8">+terminal_cmdline=:hold</span></div></li>
<li class="li1"><div class="de1"><span class="re8">+</span></div></li>
<li class="li1"><div class="de1"><span class="re8">+</span></div></li>
<li class="li1"><div class="de1"><span class="re8">+#</span></div></li>
<li class="li1"><div class="de1"><span class="re8">+# TERMINALS</span></div></li>
<li class="li1"><div class="de1"><span class="re8">+#</span></div></li>
<li class="li1"><div class="de1"><span class="re8">+</span></div></li>
<li class="li1"><div class="de1"><span class="re8">+<span class="br0">[</span>terminals/term<span class="br0">]</span></span></div></li>
<li class="li1"><div class="de1"><span class="re8">+cmdline=urxvt -embed %w -e</span></div></li>
<li class="li1"><div class="de1"><span class="re8">+cmdline_hold=urxvt -embed %w -hold -e</span></div></li>
<li class="li1"><div class="de1"> </div></li>
<li class="li1"><div class="de1"> </div></li>
<li class="li1"><div class="de1"> #</div></li>
<li class="li1"><div class="de1"><span class="re6">@@ -1100,4 +1201,25 @@ node=config:/</span></div></li>
<li class="li1"><div class="de1"> box=box-orange</div></li>
<li class="li1"><div class="de1"> </div></li>
<li class="li1"><div class="de1"> </div></li>
<li class="li1"><div class="de1"><span class="re8">+#</span></div></li>
<li class="li1"><div class="de1"><span class="re8">+# FILTERS</span></div></li>
<li class="li1"><div class="de1"><span class="re8">+#</span></div></li>
<li class="li1"><div class="de1"><span class="re8">+</span></div></li>
<li class="li1"><div class="de1"><span class="re8">+<span class="br0">[</span>filters<span class="br0">]</span></span></div></li>
<li class="li1"><div class="de1"><span class="re8">+# used to unset current VF <span class="br0">(</span>via ff<span class="br0">)</span></span></div></li>
<li class="li1"><div class="de1"><span class="re8">+f=</span></div></li>
<li class="li1"><div class="de1"><span class="re8">+# today</span></div></li>
<li class="li1"><div class="de1"><span class="re8">+t=time:A0</span></div></li>
<li class="li1"><div class="de1"><span class="re8">+# yesterday</span></div></li>
<li class="li1"><div class="de1"><span class="re8">+y=time:A1d</span></div></li>
<li class="li1"><div class="de1"><span class="re8">+# this week</span></div></li>
<li class="li1"><div class="de1"><span class="re8">+w=time:A0V</span></div></li>
<li class="li1"><div class="de1"><span class="re8">+# videos</span></div></li>
<li class="li1"><div class="de1"><span class="re8">+v=desc:* video</span></div></li>
<li class="li1"><div class="de1"><span class="re8">+# images</span></div></li>
<li class="li1"><div class="de1"><span class="re8">+i=desc:* image</span></div></li>
<li class="li1"><div class="de1"><span class="re8">+# archives</span></div></li>
<li class="li1"><div class="de1"><span class="re8">+a=desc:* archive*</span></div></li>
<li class="li1"><div class="de1"><span class="re8">+</span></div></li>
<li class="li1"><div class="de1"><span class="re8">+</span></div></li>
<li class="li1"><div class="de1"> # EOF</div></li>
</ol></p>
<h3>Downloads and whatnot</h3>
<p>See <a href="/donnatella" title="donnatella: your file manager">donnatella</a> for longer descriptions & all the links you should need.</p>
<p>And of course, as always, new bug reports, suggestions or any other form of
constructive criticism is very much welcome.</p>
Visual Filters, extended patterns and more in donnatella2014-03-23T00:00:00+00:00http://jjacky.com/2014-03-23-visual-filters-extended-patterns-and-more-in-donnatella<p>Freshly pushed to the branch <code>next</code> on <a href="/donnatella" title="donnatella: your file manager">donnatella</a>'s
<a href="https://github.com/jjk-jacky/donnatella/tree/next">github</a> are a few commits,
some fixes and other improvements here and there of course, and a few things
worth spending a few more words about.</p>
<p>First of all, you could use patterns in a few places in donna, such as when
filtering via names (or any text property) or to define arrangements. A pattern
was a string that could contain wildchars in a glob-like manner. They've now
become a bit more powerful...</p>
</p>
<h3>Patterns are more than just patterns</h3>
<p>A pattern is now a string that can start with one of the following, to specify
which mode to use :</p>
<ul>
<li>a double quote (<code>"</code>) for <strong>glob-like pattern mode</strong>, the only thing originally
supported: the given string can use <code>*</code> and <code>?</code> as wildchars with similar
semantics as the standard glob() function</li>
<li>a single-quote (<code>'</code>) for <strong>search mode</strong>: the given string will be searched
(case sensitive) in the matched against string</li>
<li>a caret (<code>^</code>) for <strong>begin mode</strong>: the matched against string must begin with
the given string to match</li>
<li>a dollar sign (<code>$</code>) for <strong>end mode</strong>: the matched against string must end with
the given string to match</li>
<li>a tilde sign (<code>~</code>) for <strong>case-insensitive matching mode</strong>: the matched against
string and the given string must be the same (case insensitively)</li>
<li>an equal sign (<code>=</code>) for <strong>case-sensitive matching mode</strong>: the matched against
string and the given string must be the exact same</li>
<li>a greater than sign (<code>></code>) for <strong>regex mode</strong>: the given string must be
Perl-compatible regular expression to be matched against</li>
</ul>
<p>If the string doesn't start with any of those, search mode will be used unless
there is at least one wildchar, then pattern mode is used.</p>
<p>Additionally, if the string first starts with a pipe character (<code>|</code>) then any
other pipe character will be used as a separator (i.e. it cannot be used in any
pattern definition), allowing you to specify more than one possible patterns to
match.</p>
<p>Note that each time the prefix rule apply, e.g. to match strings that end either
with "foo" or "bar" use <code>|$foo|$bar</code> Of course you can use different types, e.g:
<code>|this file|*.pdf|>report [0-9]{4}\.xml</code></p>
<p>This makes every feature using patterns much more powerfull than before. One
thing worth mentionning though, is that the columntype name used to support
using the pipe character to specify more than one pattern. It was a oddity (in
that it was alone to support it), but <strong>now that this is part of the general
pattern syntax, a change of syntax is in order</strong>: the pattern string must start
with a pipe character, to enable it.</p>
<h3>Filter by node type</h3>
<p>Columntype name only allowed to filter using patterns, matched against the
node's name. You can now also filter by node type, using <code>+</code> or <code>-</code> followed by
either <code>c</code> (or <code>d</code>) to match only containers (directories), or <code>i</code> (or <code>f</code>) to
match only items (files).</p>
<p>So using <code>+f</code> will match only files, just like <code>-d</code> would. So if you're looking
to filter only directories modified yesterday, you could use:</p>
<pre><code>name:"+d" and time:A1d
</code></pre>
<h3>Visual Filters</h3>
<p>Another addition is that of visual filters (VF). Filtering capabilities have
been part of donna from day one, but until now you couldn't use them to filter
what is visible on list: now you can!</p>
<p>Two new commands have been added to do so: <code>tv_set_visual_filter()</code> to set a
visual filter, and <code>tv_get_visual_filter()</code> to get the current one. Unsetting a
VF is simply done by not specifying a new one (or using an empty string as VF).</p>
<p>An option <code>toggle</code> also allows to unset the VF if trying to set a VF that is
already set.</p>
<h4>How to use some VF</h4>
<p>Some default keys allow you to use VF easily: pressing <code>f</code> followed by a letter
will apply said filter, which is simply defined as a configuration option under
category "filters" For example, "fv" to only show videos, "fi" for images, "ft"
for rows modified today, "fw" for ones modified this week...</p>
<p>And using <code>F</code> instead will work the same, but allowing you to edit the filter
before applying it. As a nice trick, keeping <code>filters/f</code> an option set to an
empty string will allow to press "ff" to unset any current VF.</p>
<h4>Dynamic VFs</h4>
<p>Some other nice things can be done, for example typing a size followed by either
lesser than (<code><</code>) or greater than (<code>></code>) will filter by the specified size (in
MiB).</p>
<p>Pressing <code>q</code> will only show rows modified today. Of course, you can prefix it
with a number of days, e.g. <code>1q</code> to show rows from yesterday, <code>2q</code> from two
days ago, etc.
You can even prefix this with <code>&</code> followed by a time unit, e.g. <code>&Vq</code> for
modified this week, <code>&V2q</code> for two weeks ago, etc</p>
<p>Lastly, using <code>Q</code> works similarly, but where <code>q</code> resolves to <code>time:A<NB><UNIT></code>
using <code>Q</code> will resolves to <code>time:A<=<NB><UNIT></code> so e.g. <code>&V2Q</code> means modified
anytime from two weeks ago (i.e. includes last week and this week as well).</p>
<p>Those are only examples of course, since as always, you can define things how
you like/want/need them to be. (And don't hesitate to share your cool tricks!)</p>
<h4>Filter files only</h4>
<p>One last note: if you only ever want your VF to apply to files, but mean for all
directories to always all remain visible, no need to specify it on each & every
filter you use: simply set treeview option <code>vf_items_only</code> to true.</p>
<h3>Better status info</h3>
<p>Some changes in the possibilities of the status area from a treeview. A few
variables were added: <code>%f</code> for the focused row, <code>%F</code> for the current VF, <code>%h</code>
and <code>%H</code> for the number/size of hidden rows respectively.</p>
<p>All of "avhsF" also supports an extra (in between brackets), which is itself a
string parsed the same way and supporting the same variables (If you need
recursion, any backslash or closing braquet must be escaped via backslash).</p>
<p>The parsed string will then be shown instead of what the variable usually
resolves to. However, there's a twist:</p>
<ul>
<li>for <code>%F</code> it will only be shown when a VF is set (else resolves to
nothing/empty string)</li>
<li>for the others, the string will also be splitted using comma as separator (if
you need to use commas, you then need to use %,), so you can specify up to 3
strings.</li>
</ul>
<p>With only 1 string, it will be shown unless the reference (i.e. the number of
items the variable refers to) is zero. With 2 strings, nothing is shown if the
reference is zero, the first one is shown if it is one, else the second one is
shown. Lastly, with 3 strings, the first one is shown is reference is zero, the
second one if it's one, else the last one is shown.</p>
<p><code>%a</code> behaves a little differently, in that instead of not showing anything (or
the first of the 3 specified strings) when the reference (i.e. number of all
rows) is zero, it does so when it is the same as the number of visible rows.
This is to make it easy to show e.g. "23 rows" when all are visible, and "23/42
rows" when some are hidden, using: <code>%{%v/}a%a rows</code>
</p>
<p>And option <code>key_modes_colors</code> was renamed to simply <code>colors</code> and isn't a boolean
anymore, but can take values "off", "keys" or "vf" The later case being used
when a VF is set.</p>
<p>Finally, the same variables are supported in option <code>format_tooltip</code>, used for
the tooltip of the statusbar area (no color support there).</p>
<h3>Updating your config to benefit from all of this</h3>
<p>Now, there's still work to do when it comes to upgrades in donna. Specifically,
there isn't currently a way to update/import new defaults, so that is a manual
operation. Archers, think of this as some king of <code>.pacnew</code> handling! ;)</p>
<p>Here's the patch to update your donnatella.conf (from <a href="/2014-03-09-donnatella-adds-embedded-terminals/">last
time</a>) :</p>
<p><ol class="diff"><li class="li1"><div class="de1">diff --git a/misc/donnatella.conf b/misc/donnatella.conf</div></li>
<li class="li1"><div class="de1">index d45fd98..e58b10b <span class="nu0">100644</span></div></li>
<li class="li1"><div class="de1"><span class="re3">--- a/misc/donnatella.conf</span></div></li>
<li class="li1"><div class="de1"><span class="re4">+++ b/misc/donnatella.conf</span></div></li>
<li class="li1"><div class="de1"><span class="re6">@@ -92,8 +92,11 @@ expand=false</span></div></li>
<li class="li1"><div class="de1"> <span class="br0">[</span>statusbar/active<span class="br0">]</span></div></li>
<li class="li1"><div class="de1"> source=:active</div></li>
<li class="li1"><div class="de1"> expand=false</div></li>
<li class="li1"><div class="de1"><span class="re7">-format=%v/%a files <span class="br0">(</span>%V<span class="br0">)</span> %N</span></div></li>
<li class="li1"><div class="de1"><span class="re8">+<span class="br0">{</span>% raw %<span class="br0">}</span>format=%<span class="br0">{</span>%s/<span class="br0">}</span>s%<span class="br0">{</span>no rows,1 row,%v rows<span class="br0">}</span>v<span class="br0">(</span>%<span class="br0">{</span>%S / <span class="br0">}</span>s%V<span class="br0">)</span>%<span class="br0">{</span> %h hidden <span class="br0">(</span>%H<span class="br0">)</span><span class="br0">}</span>h</span></div></li>
<li class="li1"><div class="de1"><span class="re8">+<span class="br0">{</span>% endraw %<span class="br0">}</span>format_tooltip=%<span class="br0">{</span>Current VF: %F<span class="br0">}</span>F</span></div></li>
<li class="li1"><div class="de1"> size_format=%R</div></li>
<li class="li1"><div class="de1"><span class="re8">+colors:tree-st-colors=vf</span></div></li>
<li class="li1"><div class="de1"><span class="re8">+foreground=blue</span></div></li>
<li class="li1"><div class="de1"> </div></li>
<li class="li1"><div class="de1"> <span class="br0">[</span>statusbar/log<span class="br0">]</span></div></li>
<li class="li1"><div class="de1"> source=:app</div></li>
<li class="li1"><div class="de1"><span class="re6">@@ -112,7 +115,7 @@ source=:focused</span></div></li>
<li class="li1"><div class="de1"> format=%o %K</div></li>
<li class="li1"><div class="de1"> width=<span class="nu0">100</span></div></li>
<li class="li1"><div class="de1"> expand=false</div></li>
<li class="li1"><div class="de1"><span class="re7">-key_modes_colors=true</span></div></li>
<li class="li1"><div class="de1"><span class="re8">+colors:tree-st-colors=keys</span></div></li>
<li class="li1"><div class="de1"> key_mode_select_background-rgba=rgba<span class="br0">(</span><span class="nu0">0</span>,<span class="nu0">42</span>,<span class="nu0">200</span>,<span class="nu0">0.8</span><span class="br0">)</span></div></li>
<li class="li1"><div class="de1"> key_mode_select_foreground=white</div></li>
<li class="li1"><div class="de1"> </div></li>
<li class="li1"><div class="de1"><span class="re6">@@ -191,6 +194,7 @@ sort_groups:sg=first</span></div></li>
<li class="li1"><div class="de1"> select_highlight:highlight=column-underline</div></li>
<li class="li1"><div class="de1"> focusing_click=true</div></li>
<li class="li1"><div class="de1"> goto_item_set:tree-set=scroll,focus</div></li>
<li class="li1"><div class="de1"><span class="re8">+vf_items_only=false</span></div></li>
<li class="li1"><div class="de1"> history_max=<span class="nu0">100</span></div></li>
<li class="li1"><div class="de1"> context_menu_menus=context</div></li>
<li class="li1"><div class="de1"> context_menu=@go:tree,marks,-,add_to_tree<add_as_root>,-,!new_nodes,-,@register,-,@selection,-,column_edit<!column_edit>,-,:refresh<@refresh></div></li>
<li class="li1"><div class="de1"><span class="re6">@@ -201,7 +205,7 @@ context_menu_colheader=columns<!columns>,-,:sort_order<!sort_order>,:second_sort</span></div></li>
<li class="li1"><div class="de1"> # some color filters</div></li>
<li class="li1"><div class="de1"> </div></li>
<li class="li1"><div class="de1"> <span class="br0">[</span>defaults/lists/arrangement/color_filters/<span class="br0">]</span></div></li>
<li class="li1"><div class="de1"><span class="re7">-filter=*.tar.*|*.tgz|*.zip|*.rar</span></div></li>
<li class="li1"><div class="de1"><span class="re8">+filter=|*.tar.*|*.tgz|*.zip|*.rar</span></div></li>
<li class="li1"><div class="de1"> column=name</div></li>
<li class="li1"><div class="de1"> foreground=green</div></li>
<li class="li1"><div class="de1"> </div></li>
<li class="li1"><div class="de1"><span class="re6">@@ -775,6 +779,36 @@ trigger=command:node_trigger<span class="br0">(</span>@ask_text<span class="br0">(</span>Enter FL to trigger<span class="br0">)</span><span class="br0">)</span></span></div></li>
<li class="li1"><div class="de1"> <span class="br0">[</span>key_modes/donna/key_slash<span class="br0">]</span></div></li>
<li class="li1"><div class="de1"> trigger=command:tv_start_interactive_search <span class="br0">(</span>%o<span class="br0">)</span></div></li>
<li class="li1"><div class="de1"> </div></li>
<li class="li1"><div class="de1"><span class="re8">+# Visual Filters</span></div></li>
<li class="li1"><div class="de1"><span class="re8">+<span class="br0">[</span>key_modes/donna/key_f<span class="br0">]</span></span></div></li>
<li class="li1"><div class="de1"><span class="re8">+type:key=spec</span></div></li>
<li class="li1"><div class="de1"><span class="re8">+spec:spec=lower,upper</span></div></li>
<li class="li1"><div class="de1"><span class="re8">+trigger=command:tv_set_visual_filter <span class="br0">(</span>%o, @config_get_string <span class="br0">(</span>filters/%k<span class="br0">)</span>, 1<span class="br0">)</span></span></div></li>
<li class="li1"><div class="de1"><span class="re8">+<span class="br0">[</span>key_modes/donna/key_F<span class="br0">]</span></span></div></li>
<li class="li1"><div class="de1"><span class="re8">+type:key=spec</span></div></li>
<li class="li1"><div class="de1"><span class="re8">+spec:spec=lower,upper</span></div></li>
<li class="li1"><div class="de1"><span class="re8">+trigger=command:tv_set_visual_filter <span class="br0">(</span>%o, @config_set_string <span class="br0">(</span>filters/%k, @ask_text <span class="br0">(</span>Enter filter %k,,@config_try_get_string <span class="br0">(</span>filters/%k, @tv_get_visual_filter <span class="br0">(</span>%o<span class="br0">)</span><span class="br0">)</span><span class="br0">)</span><span class="br0">)</span>, 1<span class="br0">)</span></span></div></li>
<li class="li1"><div class="de1"><span class="re8">+</span></div></li>
<li class="li1"><div class="de1"><span class="re8">+# VF: by age</span></div></li>
<li class="li1"><div class="de1"><span class="re8">+<span class="br0">[</span>key_modes/donna/key_ampersand<span class="br0">]</span></span></div></li>
<li class="li1"><div class="de1"><span class="re8">+type:key=combine</span></div></li>
<li class="li1"><div class="de1"><span class="re8">+spec:spec=custom</span></div></li>
<li class="li1"><div class="de1"><span class="re8">+custom_chars=HMSdmVY</span></div></li>
<li class="li1"><div class="de1"><span class="re8">+combine=age_unit</span></div></li>
<li class="li1"><div class="de1"><span class="re8">+<span class="br0">[</span>key_modes/donna/key_q<span class="br0">]</span></span></div></li>
<li class="li1"><div class="de1"><span class="re8">+combine=age_unit</span></div></li>
<li class="li1"><div class="de1"><span class="re8">+trigger=command:tv_set_visual_filter <span class="br0">(</span>%o, time:A%m%c<span class="br0">)</span></span></div></li>
<li class="li1"><div class="de1"><span class="re8">+<span class="br0">[</span>key_modes/donna/key_Q<span class="br0">]</span></span></div></li>
<li class="li1"><div class="de1"><span class="re8">+combine=age_unit</span></div></li>
<li class="li1"><div class="de1"><span class="re8">+trigger=command:tv_set_visual_filter <span class="br0">(</span>%o, time:A<=%m%c<span class="br0">)</span></span></div></li>
<li class="li1"><div class="de1"><span class="re8">+</span></div></li>
<li class="li1"><div class="de1"><span class="re8">+# VF: by size</span></div></li>
<li class="li1"><div class="de1"><span class="re8">+<span class="br0">[</span>key_modes/donna/key_less<span class="br0">]</span></span></div></li>
<li class="li1"><div class="de1"><span class="re8">+trigger=command:tv_set_visual_filter <span class="br0">(</span>%o, size:<=%mM<span class="br0">)</span></span></div></li>
<li class="li1"><div class="de1"><span class="re8">+<span class="br0">[</span>key_modes/donna/key_greater<span class="br0">]</span></span></div></li>
<li class="li1"><div class="de1"><span class="re8">+trigger=command:tv_set_visual_filter <span class="br0">(</span>%o, size:>=%mM<span class="br0">)</span></span></div></li>
<li class="li1"><div class="de1"><span class="re8">+</span></div></li>
<li class="li1"><div class="de1"><span class="re8">+</span></div></li>
<li class="li1"><div class="de1"> # F2 to rename</div></li>
<li class="li1"><div class="de1"> <span class="br0">[</span>key_modes/donna/key_F2<span class="br0">]</span></div></li>
<li class="li1"><div class="de1"> trigger=command:tv_column_edit <span class="br0">(</span>%o, %n, name<span class="br0">)</span></div></li>
<li class="li1"><div class="de1"><span class="re6">@@ -1155,4 +1189,25 @@ node=config:/</span></div></li>
<li class="li1"><div class="de1"> box=box-orange</div></li>
<li class="li1"><div class="de1"> </div></li>
<li class="li1"><div class="de1"> </div></li>
<li class="li1"><div class="de1"><span class="re8">+#</span></div></li>
<li class="li1"><div class="de1"><span class="re8">+# FILTERS</span></div></li>
<li class="li1"><div class="de1"><span class="re8">+#</span></div></li>
<li class="li1"><div class="de1"><span class="re8">+</span></div></li>
<li class="li1"><div class="de1"><span class="re8">+<span class="br0">[</span>filters<span class="br0">]</span></span></div></li>
<li class="li1"><div class="de1"><span class="re8">+# used to unset current VF <span class="br0">(</span>via ff<span class="br0">)</span></span></div></li>
<li class="li1"><div class="de1"><span class="re8">+f=</span></div></li>
<li class="li1"><div class="de1"><span class="re8">+# today</span></div></li>
<li class="li1"><div class="de1"><span class="re8">+t=time:A0</span></div></li>
<li class="li1"><div class="de1"><span class="re8">+# yesterday</span></div></li>
<li class="li1"><div class="de1"><span class="re8">+y=time:A1d</span></div></li>
<li class="li1"><div class="de1"><span class="re8">+# this week</span></div></li>
<li class="li1"><div class="de1"><span class="re8">+w=time:A0V</span></div></li>
<li class="li1"><div class="de1"><span class="re8">+# videos</span></div></li>
<li class="li1"><div class="de1"><span class="re8">+v=desc:* video</span></div></li>
<li class="li1"><div class="de1"><span class="re8">+# images</span></div></li>
<li class="li1"><div class="de1"><span class="re8">+i=desc:* image</span></div></li>
<li class="li1"><div class="de1"><span class="re8">+# archives</span></div></li>
<li class="li1"><div class="de1"><span class="re8">+a=desc:* archive*</span></div></li>
<li class="li1"><div class="de1"><span class="re8">+</span></div></li>
<li class="li1"><div class="de1"><span class="re8">+</span></div></li>
<li class="li1"><div class="de1"> # EOF</div></li>
</ol></p>
<h3>Where to get it?</h3>
<p>For Arch Linux users, you can use
<a href="https://aur.archlinux.org/packages/donnatella-git/">donnatella-git</a> in the AUR
to easilly get it. Or simply clone the git repo from
<a href="https://github.com/jjk-jacky/donnatella/tree/next">github</a> and compile things
yourself.</p>
<p>For a a complete list of all changes/bug fixes please refer to the git log.</p>
<p>And in case you read all that and are wondering what donnatella is, or are
looking for more information, download links, etc please refer to <a href="/donnatella" title="donnatella: your file manager">donnatella</a>.</p>
<p>As always, bug reports, suggestions or any other form of constructive criticism
is very much welcome. You can open issues on
<a href="https://github.com/jjk-jacky/donnatella/issues">github</a>, use the thread on Arch
Linux forums, or simply email me.</p>
donnatella adds embedded terminals2014-03-09T00:00:00+00:00http://jjacky.com/2014-03-09-donnatella-adds-embedded-terminals<p>Freshly pushed to the branch <code>next</code> on <a href="/donnatella" title="donnatella: your file manager">donnatella</a>'s
<a href="https://github.com/jjk-jacky/donnatella/tree/next">github</a> are a few commits,
some fixes and other improvements here and there of course, but mostly the
addition of <strong>embedded terminals</strong>.</p>
<p>Let's rewind a bit: you could already run external process in donna by using the
domain <code>exec</code> which supports a few modes: simply run the specified command
line, run & wait for it to be over, run it in a(n external) terminal, or capture
its output and process it as search results.</p>
</p>
<p>This was done using prefixes, e.g. <code>exec:>foobar</code> would run <code>foobar</code> inside a
terminal, as indicated by the greater than sign.</p>
<p>First of all: you can now define which prefixes to use for each modes: a few
options have been added in <code>providers/exec</code> so you can define the prefix for
each mode, as well as the default mode to use (i.e. when no prefix was used).</p>
<h3>Support multiple terminals</h3>
<p>In addition, for the mode "terminal" you can also use a "secondary prefix" to
specify which terminal to use. This might be of interest if you'd like to <strong>use
different terminal emulators from time to time, or to use different options</strong>
(e.g. whether or not the terminal should automatically close its window after
the process ended or not, often an option <code>-hold</code> or similar).</p>
<p>The command line prefix to start the terminal is defined under option
<code>providers/exec/terminal/cmdline</code> Let's say you set it to use urxvt as your
default terminal.</p>
<p>Now you want to be able to start some process in another terminal, e.g. xterm.
Then you would simply add a secondary prefix - e.g. <code>xt:</code> - for this case. An
example configuration could be:</p>
<pre><code>[providers/exec]
prefix_terminal=>
[providers/exec/terminal]
cmdline=urxvt -e
[providers/exec/terminal/]
prefix=xt:
cmdline=xterm -e
</code></pre>
<p>With such a config, you can start something in urxvt or xterm simply by using
either <code>exec:>foobar</code> (urxvt) or <code>exec:>xt:foobar</code> (xterm).</p>
<h3>Embedded terminals</h3>
<p>The other addition in the support of embedded terminals. Once again, donna will
let you use the terminal of your choice, so <strong>embedding terminals is done via the
XEMBED protocol</strong> (supported, for example, by urxvt or xterm).</p>
<p>To use an embedded terminal, you first need to add it to your layout. This is
done simply by adding a new componement "terminal" Much like for treeviews, it
should be followed by a colon and a name, identifying it & defining where its
configuration will be found (namely, under <code>terminals/<NAME></code>.</p>
<p>After that, you can start a process in the embedded terminal using command
<code>terminal_add_tab()</code> Embedded terminals are indeed automatically tabbed, so when
starting a new process within a new embedded terminal, a new tab is added to
donna's terminal component (which is only visible if there's at least one tab).</p>
<p>The command takes a few arguments, besides the actual terminal (name) to use:
The command line of the process to start of course, but also optionally the
command line for starting the terminal emulator.</p>
<p>If not specified, option <code>terminals/<NAME>/cmdline</code> will be used. And as a
facility, it can also be a string starting with a colon, to load an alternative
option. For example with ":foobar" option <code>terminals/<NAME>/cmdline_foobar</code>
would be used.</p>
<p>This command line must contain <code>%w</code> which will be parsed to the window id to be
used by the terminal emulator, as per XEMBED protocol.</p>
<h4>Options</h4>
<p>Terminals support a few options:</p>
<ul>
<li>option <code>always_show_tabs</code> will determine whether the tab bar is visible even
if there's only one tab (true), or only when there are at least 2 tabs (false,
the default).</li>
</ul>
<p>Double clicking a tab will send the focus to the embedded terminal. By default,
clicking in a terminal should also give it focus. Note that for this to work,
donna needs to do some work & handle mouse events on its own, as (most) terminal
emulators do not implement a click-to-focus model. If this is causing issue with
your terminal, you can disable it by setting boolean option <code>catch_events</code> to
false.</p>
<ul>
<li>option <code>focusing_click</code> makes it that a left click on the terminal will only
focus it, but the click (button press) won't be sent to the terminal. This can
be disabled by setting it to false. Also note that this obviously only works
when option <code>catch_events</code> is true.</li>
</ul>
<p>As usual, options can be set under <code>terminals/<TERMINAL>/</code> for terminal-specific
options, or under <code>defaults/terminals</code> for options common to all terminals.</p>
<p>By default, tabs will use the command line as title. donna will then update
the title as a window manager would, relying on the properties <code>_NET_WM_NAME</code>
(or <code>WM_NAME</code>) set on the window by the emulator.</p>
<h4>Via the exec domain</h4>
<p>Of course you can also use embedded terminals via the exec domain, since a new
prefix/option cas been added: "embedded_terminal"</p>
<p>Option <code>providers/exec/embedded_terminal/terminal</code> must be set to the name of
the terminal component to use; And you can also use option <code>terminal_cmdline</code> to
specify the command line to use to start the terminal emulator.</p>
<p>Again, via the use of secondary prefixes this will allow to specify which
emulator to use, of use different options.</p>
<h3>Updating your config to benefit from all of this</h3>
<p>Now, there's still work to do when it comes to upgrades in donna. Specifically,
there isn't currently a way to update/import new defaults, so that is a manual
operation. Archers, think of this as some king of <code>.pacnew</code> handling! ;)</p>
<p>Here's the patch to update your donnatella.conf (from <a href="/2014-02-22-coming-next-to-donnatella/">last
time</a>) :</p>
<p><ol class="diff"><li class="li1"><div class="de1">diff --git a/misc/donnatella.conf b/misc/donnatella.conf</div></li>
<li class="li1"><div class="de1">index 39ac154..d45fd98 <span class="nu0">100644</span></div></li>
<li class="li1"><div class="de1"><span class="re3">--- a/misc/donnatella.conf</span></div></li>
<li class="li1"><div class="de1"><span class="re4">+++ b/misc/donnatella.conf</span></div></li>
<li class="li1"><div class="de1"><span class="re6">@@ -5,7 +5,7 @@</span></div></li>
<li class="li1"><div class="de1"> #</div></li>
<li class="li1"><div class="de1"> </div></li>
<li class="li1"><div class="de1"> <span class="br0">[</span>layouts<span class="br0">]</span></div></li>
<li class="li1"><div class="de1"><span class="re7">-std=paneH<span class="br0">(</span>!treeview:tree@230,treeview:list<span class="br0">)</span></span></div></li>
<li class="li1"><div class="de1"><span class="re8">+std=paneH<span class="br0">(</span>!treeview:tree@230,paneV<span class="br0">(</span>treeview:list@230,terminal:term<span class="br0">)</span><span class="br0">)</span></span></div></li>
<li class="li1"><div class="de1"> dp=paneH<span class="br0">(</span>!treeview:tree@230,paneV<span class="br0">(</span>treeview:foo,treeview:list<span class="br0">)</span><span class="br0">)</span></div></li>
<li class="li1"><div class="de1"> tm=paneV<span class="br0">(</span>paneH<span class="br0">(</span>!treeview:tree@230,paneV<span class="br0">(</span>treeview:list,treeview:list2<span class="br0">)</span><span class="br0">)</span>@300,!treeview:tm<span class="br0">)</span></div></li>
<li class="li1"><div class="de1"> </div></li>
<li class="li1"><div class="de1"><span class="re6">@@ -38,6 +38,10 @@ prefix=~</span></div></li>
<li class="li1"><div class="de1"> is_home_dir=true</div></li>
<li class="li1"><div class="de1"> </div></li>
<li class="li1"><div class="de1"> <span class="br0">[</span>donna/prefixes/<span class="br0">]</span></div></li>
<li class="li1"><div class="de1"><span class="re8">+prefix=:</span></div></li>
<li class="li1"><div class="de1"><span class="re8">+replacement=exec::</span></div></li>
<li class="li1"><div class="de1"><span class="re8">+</span></div></li>
<li class="li1"><div class="de1"><span class="re8">+<span class="br0">[</span>donna/prefixes/<span class="br0">]</span></span></div></li>
<li class="li1"><div class="de1"> prefix=></div></li>
<li class="li1"><div class="de1"> replacement=exec:></div></li>
<li class="li1"><div class="de1"> </div></li>
<li class="li1"><div class="de1"><span class="re6">@@ -61,10 +65,10 @@ replacement=command:</span></div></li>
<li class="li1"><div class="de1"> # ALIASES</div></li>
<li class="li1"><div class="de1"> </div></li>
<li class="li1"><div class="de1"> <span class="br0">[</span>donna/aliases/g<span class="br0">]</span></div></li>
<li class="li1"><div class="de1"><span class="re7">-replacement=exec:>git</span></div></li>
<li class="li1"><div class="de1"><span class="re8">+replacement=exec:!git</span></div></li>
<li class="li1"><div class="de1"> </div></li>
<li class="li1"><div class="de1"> <span class="br0">[</span>donna/aliases/m<span class="br0">]</span></div></li>
<li class="li1"><div class="de1"><span class="re7">-replacement=exec:>man</span></div></li>
<li class="li1"><div class="de1"><span class="re8">+replacement=exec:!man</span></div></li>
<li class="li1"><div class="de1"> </div></li>
<li class="li1"><div class="de1"> <span class="br0">[</span>donna/aliases/f<span class="br0">]</span></div></li>
<li class="li1"><div class="de1"> replacement=exec:<find</div></li>
<li class="li1"><div class="de1"><span class="re6">@@ -771,12 +775,21 @@ trigger=command:node_trigger<span class="br0">(</span>@ask_text<span class="br0">(</span>Enter FL to trigger<span class="br0">)</span><span class="br0">)</span></span></div></li>
<li class="li1"><div class="de1"> <span class="br0">[</span>key_modes/donna/key_slash<span class="br0">]</span></div></li>
<li class="li1"><div class="de1"> trigger=command:tv_start_interactive_search <span class="br0">(</span>%o<span class="br0">)</span></div></li>
<li class="li1"><div class="de1"> </div></li>
<li class="li1"><div class="de1"><span class="re8">+# F2 to rename</span></div></li>
<li class="li1"><div class="de1"><span class="re8">+<span class="br0">[</span>key_modes/donna/key_F2<span class="br0">]</span></span></div></li>
<li class="li1"><div class="de1"><span class="re8">+trigger=command:tv_column_edit <span class="br0">(</span>%o, %n, name<span class="br0">)</span></span></div></li>
<li class="li1"><div class="de1"> # F6 to edit focused item <span class="br0">(</span>vim in a terminal<span class="br0">)</span></div></li>
<li class="li1"><div class="de1"> <span class="br0">[</span>key_modes/donna/key_F6<span class="br0">]</span></div></li>
<li class="li1"><div class="de1"><span class="re7">-trigger=exec:>vim %:n</span></div></li>
<li class="li1"><div class="de1"><span class="re8">+trigger=exec:!vim %:n</span></div></li>
<li class="li1"><div class="de1"> # F9 to view focused item <span class="br0">(</span>less in a terminal<span class="br0">)</span></div></li>
<li class="li1"><div class="de1"> <span class="br0">[</span>key_modes/donna/key_F9<span class="br0">]</span></div></li>
<li class="li1"><div class="de1"><span class="re7">-trigger=exec:>less %:n</span></div></li>
<li class="li1"><div class="de1"><span class="re8">+trigger=exec:!less %:n</span></div></li>
<li class="li1"><div class="de1"><span class="re8">+</span></div></li>
<li class="li1"><div class="de1"><span class="re8">+# Terminals</span></div></li>
<li class="li1"><div class="de1"><span class="re8">+<span class="br0">[</span>key_modes/donna/key_t<span class="br0">]</span></span></div></li>
<li class="li1"><div class="de1"><span class="re8">+trigger=exec:!bash</span></div></li>
<li class="li1"><div class="de1"><span class="re8">+<span class="br0">[</span>key_modes/donna/key_T<span class="br0">]</span></span></div></li>
<li class="li1"><div class="de1"><span class="re8">+trigger=exec:>bash</span></div></li>
<li class="li1"><div class="de1"> </div></li>
<li class="li1"><div class="de1"> # selection stuff -- note that this required a patched GTK <span class="br0">(</span>to invert range<span class="br0">)</span></div></li>
<li class="li1"><div class="de1"> <span class="br0">[</span>key_modes/donna/key_v<span class="br0">]</span></div></li>
<li class="li1"><div class="de1"><span class="re6">@@ -1105,7 +1118,32 @@ not_active_list=true</span></div></li>
<li class="li1"><div class="de1"> #</div></li>
<li class="li1"><div class="de1"> </div></li>
<li class="li1"><div class="de1"> <span class="br0">[</span>providers/exec<span class="br0">]</span></div></li>
<li class="li1"><div class="de1"><span class="re7">-terminal=urxvt -hold -e</span></div></li>
<li class="li1"><div class="de1"><span class="re8">+default_mode:exec-mode=exec</span></div></li>
<li class="li1"><div class="de1"><span class="re8">+prefix_exec=&</span></div></li>
<li class="li1"><div class="de1"><span class="re8">+prefix_exec_and_wait=:</span></div></li>
<li class="li1"><div class="de1"><span class="re8">+prefix_terminal=></span></div></li>
<li class="li1"><div class="de1"><span class="re8">+prefix_embedded_terminal=!</span></div></li>
<li class="li1"><div class="de1"><span class="re8">+prefix_parse_output=<</span></div></li>
<li class="li1"><div class="de1"><span class="re8">+<span class="br0">[</span>providers/exec/terminal<span class="br0">]</span></span></div></li>
<li class="li1"><div class="de1"><span class="re8">+cmdline=urxvt -e</span></div></li>
<li class="li1"><div class="de1"><span class="re8">+<span class="br0">[</span>providers/exec/terminal/<span class="br0">]</span></span></div></li>
<li class="li1"><div class="de1"><span class="re8">+prefix=></span></div></li>
<li class="li1"><div class="de1"><span class="re8">+cmdline=urxvt -hold -e</span></div></li>
<li class="li1"><div class="de1"><span class="re8">+<span class="br0">[</span>providers/exec/embedded_terminal<span class="br0">]</span></span></div></li>
<li class="li1"><div class="de1"><span class="re8">+terminal=term</span></div></li>
<li class="li1"><div class="de1"><span class="re8">+<span class="br0">[</span>providers/exec/embedded_terminal/<span class="br0">]</span></span></div></li>
<li class="li1"><div class="de1"><span class="re8">+prefix=!</span></div></li>
<li class="li1"><div class="de1"><span class="re8">+terminal=term</span></div></li>
<li class="li1"><div class="de1"><span class="re8">+terminal_cmdline=:hold</span></div></li>
<li class="li1"><div class="de1"><span class="re8">+</span></div></li>
<li class="li1"><div class="de1"><span class="re8">+</span></div></li>
<li class="li1"><div class="de1"><span class="re8">+#</span></div></li>
<li class="li1"><div class="de1"><span class="re8">+# TERMINALS</span></div></li>
<li class="li1"><div class="de1"><span class="re8">+#</span></div></li>
<li class="li1"><div class="de1"><span class="re8">+</span></div></li>
<li class="li1"><div class="de1"><span class="re8">+<span class="br0">[</span>terminals/term<span class="br0">]</span></span></div></li>
<li class="li1"><div class="de1"><span class="re8">+cmdline=urxvt -embed %w -e</span></div></li>
<li class="li1"><div class="de1"><span class="re8">+cmdline_hold=urxvt -embed %w -hold -e</span></div></li>
<li class="li1"><div class="de1"> </div></li>
<li class="li1"><div class="de1"> </div></li>
<li class="li1"><div class="de1"> #</div></li>
</ol></p>
<p>And with that config (and assuming you have urxvt installed, if not you might
want to update things to use whatever emulator you prefer), you can now view a
file within donna by pressing F9, and edit it by pressing F6. This will be done
usnig less/vim inside an embedded terminal.</p>
<p>You can also start a new shell in the current location, in an embedded terminal
by pressing <code>t</code> or in an external terminal via <code>T</code></p>
<h3>Where to get it?</h3>
<p>For Arch Linux users, you can use
<a href="https://aur.archlinux.org/packages/donnatella-git/">donnatella-git</a> in the AUR
to easilly get it. Or simply clone the git repo from
<a href="https://github.com/jjk-jacky/donnatella/tree/next">github</a> and compile things
yourself.</p>
<p>For a a complete list of all changes/bug fixes please refer to the git log.</p>
<p>And in case you read all that and are wondering what donnatella is, or are
looking for more information, download links, etc please refer to <a href="/donnatella" title="donnatella: your file manager">donnatella</a>.</p>
<p>As always, bug reports, suggestions or any other form of constructive criticism
is very much welcome. You can open issues on
<a href="https://github.com/jjk-jacky/donnatella/issues">github</a>, use the thread on Arch
Linux forums, or simply email me.</p>
kalu 2.4.0 released2014-03-02T00:00:00+00:00http://jjacky.com/2014-03-02-kalu-2.4.0-released<p>A new version of kalu is available, with a few fixes, more visibility for the
<a href="/2013-08-21-preview-conflicts-in-arch-linux-system-upgrade/" title="Preview conflicts in Arch Linux system upgrade">system upgrade simulation
feature</a>
introduced in 2.3.0, and the addition of FIFO commands.</p>
<p><a href="/2013-10-20-next-kalu-is-in-aur-with-fifo-commands/" title="Next kalu is in AUR, with FIFO commands">FIFO commands</a>
will allow you to send commands to a running kalu simply by writing text to its
FIFO. One use for this might be to assign keyboard shortcuts to some common
commands, so you can e.g. (un)pause kalu, run the checks or start a sysupgrade
from your keyboard, instead of having to go click on the systray icon.</p>
</p>
<p>More detailled changelog:</p>
<ul>
<li><p>Add FIFO to send commands to kalu</p>
<p>On start a FIFO named kalu_fifo_XXXX (where XXXX is kalu's process id) will
be created under <code>$XDG_RUNTIME_DIR</code>. One can write to this FIFO to send
commands to kalu, to e.g. run checks, start a sysupgrade, etc</p>
<p>This allows to use kalu without the need to click its systray icon/menu,
even from keyboard shortcuts.</p></li>
<li><p>Watched (AUR) packages: Include packages not found in results</p>
<p>They have "package not found" as description, and "-" as new version.</p></li>
<li><p>Add a new notification for packages not found in AUR</p>
<p>When checking the AUR, any and all packages not found will now be listed in
an additionnal notification. This allows to catch e.g. when a package might
have been renamed/removed.</p>
<p>Note that such packages should be put on the ignore list, to avoid useless
querying of the AUR.</p></li>
<li><p>Promote "sysupgrade simulation" a bit</p>
<p>Make it possible to start a sysupgrade simulation from menu, clicks on the
systray icon and via FIFO command</p></li>
<li><p>kalu updater: Add download/install/net sizes to kalu's log</p></li>
<li><p>Fix possibly trying to start a sysupgrade while busy</p></li>
<li><p>Update French translation</p></li>
<li><p>Remove config tweak ForceImages (Images are now always shown)</p></li>
<li><p>Add option (NotificationIconSize) to define the size of icons used on notifications</p></li>
<li><p>Some other fixes (see git log for details)</p></li>
</ul>
<h3>Downloads and whatnot</h3>
<p>Thanks to all those who reported bugs or suggested features, and to Kolibry for
the updated French translation.</p>
<p>See <a href="/kalu" title="kalu: Keep Arch Linux Up-to-date">kalu</a> for longer descriptions & all the links you should need.</p>
<p>And of course, as always, new bug reports, suggestions or any other form of
constructive criticism is very much welcome.</p>
Coming next to donnatella...2014-02-22T00:00:00+00:00http://jjacky.com/2014-02-22-coming-next-to-donnatella<p>A couple of weeks ago was the first public release of <a href="/donnatella" title="donnatella: your file manager">donnatella</a>, and for
those of you trying it out, you don't have to wait for the next release. The
branch <code>next</code> on <a href="https://github.com/jjk-jacky/donnatella/tree/next">github</a>
already contains a few things.</p>
<p>For Arch Linux users, you can use
<a href="https://aur.archlinux.org/packages/donnatella-git/">donnatella-git</a> in the AUR
to easilly get it.</p>
</p>
<h3>An event for log messages</h3>
<p>Firstly, donna now has an event <code>log</code> for some of its log messages, specifically
those at levels MESSAGE, INFO, WARNING and CRITICAL. (The others ones are for
debugging purposes, and you should run donna from a terminal then, really.)</p>
<p>Alongside a new source (<code>:app</code>) for the statusbar, this will allow to have some
feedback for such messages, even when running donna without a terminal, as most
people would.</p>
<p>This new source will show the last log message, for as long as specified via
option <code>timeout</code> (in seconds). Of course it can be set to 0 for unlimited, but
you can also have it time out after a bit, and then use option <code>format</code> to
specify what (if anything) should be shown.
The same variables are available as for the window title, so that includes
active list, current location, etc</p>
<p>Having those messages shown in the UI will become more and more useful in time,
because in addition to warnings whenever something not quite right happens,
donna will use INFO messages to provide non essential feedback; For example,
right now it happens when you set/add nodes to a register, or when
loading/saving a treeview from/to a file. Of course over time, more will be
added.</p>
<h3>Dealing with options & config</h3>
<p>Some changes were also done regarding options & configuration. By default in
donna so far, changing treeview/column options would only have the new value set
in memory, nothing was saved to the configuration.</p>
<p>A new treeview option (which applies to all its options, i.e. including column
options) allows to set the default save location: in memory, in current
location, or ask.</p>
<p>So now you can be asked, when changing an option, where and if it should be
saved to configuration.</p>
<p>Now, there are still a few things that can only be changed in memory, e.g. the
sort order or the column layout - that is, which columns are visible & in what
order. Also about that, new commands are available to toggle columns or set a new
column layout.</p>
<p>Which is why a new command was introduced, to save a few things to
configuration: treeview options, column options, column layout and (second) sort
order. You can of course chose which of those to save (including which column to
save options of), and where.</p>
<h3>Updating your config to benefit from all of this</h3>
<p>Now, there's still work to do when it comes to upgrades in donna. Specifically,
there isn't currently a way to update/import new defaults, so that is a manual
operation. Archers, think of this as some king of <code>.pacnew</code> handling! ;)</p>
<p>Here's the patch to update your donnatella.conf :</p>
<p><ol class="diff"><li class="li1"><div class="de1">diff --git a/misc/donnatella.conf b/misc/donnatella.conf</div></li>
<li class="li1"><div class="de1">index 57f69b1..39ac154 <span class="nu0">100644</span></div></li>
<li class="li1"><div class="de1"><span class="re3">--- a/misc/donnatella.conf</span></div></li>
<li class="li1"><div class="de1"><span class="re4">+++ b/misc/donnatella.conf</span></div></li>
<li class="li1"><div class="de1"><span class="re6">@@ -78,7 +78,7 @@ replacement=exec:<pacman -Qlq</span></div></li>
<li class="li1"><div class="de1"> #</div></li>
<li class="li1"><div class="de1"> </div></li>
<li class="li1"><div class="de1"> <span class="br0">[</span>statusbar<span class="br0">]</span></div></li>
<li class="li1"><div class="de1"><span class="re7">-areas=tasks,active,keys,focus</span></div></li>
<li class="li1"><div class="de1"><span class="re8">+areas=tasks,active,log,keys,focus</span></div></li>
<li class="li1"><div class="de1"> </div></li>
<li class="li1"><div class="de1"> <span class="br0">[</span>statusbar/tasks<span class="br0">]</span></div></li>
<li class="li1"><div class="de1"> source=:task</div></li>
<li class="li1"><div class="de1"><span class="re6">@@ -87,9 +87,16 @@ expand=false</span></div></li>
<li class="li1"><div class="de1"> </div></li>
<li class="li1"><div class="de1"> <span class="br0">[</span>statusbar/active<span class="br0">]</span></div></li>
<li class="li1"><div class="de1"> source=:active</div></li>
<li class="li1"><div class="de1"><span class="re8">+expand=false</span></div></li>
<li class="li1"><div class="de1"> format=%v/%a files <span class="br0">(</span>%V<span class="br0">)</span> %N</div></li>
<li class="li1"><div class="de1"> size_format=%R</div></li>
<li class="li1"><div class="de1"> </div></li>
<li class="li1"><div class="de1"><span class="re8">+<span class="br0">[</span>statusbar/log<span class="br0">]</span></span></div></li>
<li class="li1"><div class="de1"><span class="re8">+source=:app</span></div></li>
<li class="li1"><div class="de1"><span class="re8">+format=%d</span></div></li>
<li class="li1"><div class="de1"><span class="re8">+format_tooltip=donnatella v%v</span></div></li>
<li class="li1"><div class="de1"><span class="re8">+timeout=5</span></div></li>
<li class="li1"><div class="de1"><span class="re8">+</span></div></li>
<li class="li1"><div class="de1"> <span class="br0">[</span>statusbar/keys<span class="br0">]</span></div></li>
<li class="li1"><div class="de1"> source=:focused</div></li>
<li class="li1"><div class="de1"> format=%k</div></li>
<li class="li1"><div class="de1"><span class="re6">@@ -155,12 +162,13 @@ notify=exec:&notify-send "Donnatella: A task just failed" %N</span></div></li>
<li class="li1"><div class="de1"> <span class="br0">[</span>defaults/trees<span class="br0">]</span></div></li>
<li class="li1"><div class="de1"> click_mode=tree</div></li>
<li class="li1"><div class="de1"> key_mode=donna</div></li>
<li class="li1"><div class="de1"><span class="re8">+default_save_location:save-location=ask</span></div></li>
<li class="li1"><div class="de1"> node_types:node-type=containers</div></li>
<li class="li1"><div class="de1"> show_hidden=false</div></li>
<li class="li1"><div class="de1"> sort_groups:sg=first</div></li>
<li class="li1"><div class="de1"> select_highlight:highlight=column</div></li>
<li class="li1"><div class="de1"> context_menu_menus=context</div></li>
<li class="li1"><div class="de1"><span class="re7">-context_menu=add_root,:move_root:up<:move_root:first>,:move_root:down<:move_root:last>,:remove_row,-,goto<goto_fs,marks>,-,save_tree<save_tree_as>,load_tree<load_tree_from>,-,tree_visuals<@tree_visuals>,-,tv_options<!tv_options>,-,@register,-,:register:+<@register:+>,-,:refresh<@refresh></span></div></li>
<li class="li1"><div class="de1"><span class="re8">+context_menu=add_root,:move_root:up<:move_root:first>,:move_root:down<:move_root:last>,:remove_row,-,goto<goto_fs,marks>,-,save_tree<save_tree_as>,load_tree<load_tree_from>,-,tree_visuals<@tree_visuals>,-,tv_options<!tv_options,-,save_tree_to_config>,-,@register,-,:register:+<@register:+>,-,:refresh<@refresh></span></div></li>
<li class="li1"><div class="de1"> </div></li>
<li class="li1"><div class="de1"> <span class="br0">[</span>defaults/trees/arrangement<span class="br0">]</span></div></li>
<li class="li1"><div class="de1"> columns=name</div></li>
<li class="li1"><div class="de1"><span class="re6">@@ -172,6 +180,7 @@ sort_column=name</span></div></li>
<li class="li1"><div class="de1"> <span class="br0">[</span>defaults/lists<span class="br0">]</span></div></li>
<li class="li1"><div class="de1"> click_mode=list</div></li>
<li class="li1"><div class="de1"> key_mode=donna</div></li>
<li class="li1"><div class="de1"><span class="re8">+default_save_location:save-location=ask</span></div></li>
<li class="li1"><div class="de1"> show_hidden=true</div></li>
<li class="li1"><div class="de1"> node_types:node-type=all</div></li>
<li class="li1"><div class="de1"> sort_groups:sg=first</div></li>
<li class="li1"><div class="de1"><span class="re6">@@ -183,7 +192,7 @@ context_menu_menus=context</span></div></li>
<li class="li1"><div class="de1"> context_menu=@go:tree,marks,-,add_to_tree<add_as_root>,-,!new_nodes,-,@register,-,@selection,-,column_edit<!column_edit>,-,:refresh<@refresh></div></li>
<li class="li1"><div class="de1"> context_menu_fs=@go:tree,marks,-,add_to_tree<add_as_root>,-,!new_nodes,new_items,-,@register,-,:register:+<@register:+>,-,@selection,-,column_edit<!column_edit,-,@touch>,-,:refresh<@refresh></div></li>
<li class="li1"><div class="de1"> context_menu_task=@selection,-,:refresh<@refresh>,-,@tasks</div></li>
<li class="li1"><div class="de1"><span class="re7">-context_menu_colheader=columns<!columns>,-,:sort_order<!sort_order>,:second_sort_order<!second_sort_order>,-,options<column_options<!column_options>,list_options<!tv_options>></span></div></li>
<li class="li1"><div class="de1"><span class="re8">+context_menu_colheader=columns<!columns>,-,:sort_order<!sort_order>,:second_sort_order<!second_sort_order>,-,options<column_options<!column_options>,list_options<!tv_options>>,-,save_list_to_config</span></div></li>
<li class="li1"><div class="de1"> </div></li>
<li class="li1"><div class="de1"> # some color filters</div></li>
<li class="li1"><div class="de1"> </div></li>
<li class="li1"><div class="de1"><span class="re6">@@ -299,7 +308,7 @@ format_tooltip=%p <span class="br0">(</span>%o<span class="br0">)</span></span></div></li>
<li class="li1"><div class="de1"> color_user=green</div></li>
<li class="li1"><div class="de1"> color_group=blue</div></li>
<li class="li1"><div class="de1"> color_mixed=#00aaaa</div></li>
<li class="li1"><div class="de1"><span class="re7">-sort=1</span></div></li>
<li class="li1"><div class="de1"><span class="re8">+sort:sort-perms=myperms</span></div></li>
<li class="li1"><div class="de1"> </div></li>
<li class="li1"><div class="de1"> </div></li>
<li class="li1"><div class="de1"> # COLUMNS</div></li>
<li class="li1"><div class="de1"><span class="re6">@@ -335,7 +344,7 @@ title=Own</span></div></li>
<li class="li1"><div class="de1"> width=<span class="nu0">70</span></div></li>
<li class="li1"><div class="de1"> format=%V:%H</div></li>
<li class="li1"><div class="de1"> format_tooltip=</div></li>
<li class="li1"><div class="de1"><span class="re7">-sort=3</span></div></li>
<li class="li1"><div class="de1"><span class="re8">+sort:sort-perms=user</span></div></li>
<li class="li1"><div class="de1"> </div></li>
<li class="li1"><div class="de1"> <span class="br0">[</span>defaults/lists/columns/desc<span class="br0">]</span></div></li>
<li class="li1"><div class="de1"> type:ct=text</div></li>
<li class="li1"><div class="de1"><span class="re6">@@ -909,6 +918,10 @@ name=Tree Options</span></div></li>
<li class="li1"><div class="de1"> icon=preferences-desktop</div></li>
<li class="li1"><div class="de1"> submenu:enabled=enabled</div></li>
<li class="li1"><div class="de1"> </div></li>
<li class="li1"><div class="de1"><span class="re8">+<span class="br0">[</span>context_menus/tree_views/save_tree_to_config<span class="br0">]</span></span></div></li>
<li class="li1"><div class="de1"><span class="re8">+name=Save all options to configuration</span></div></li>
<li class="li1"><div class="de1"><span class="re8">+trigger=command:tv_save_to_config <span class="br0">(</span>%o,:options<span class="br0">)</span></span></div></li>
<li class="li1"><div class="de1"><span class="re8">+</span></div></li>
<li class="li1"><div class="de1"> </div></li>
<li class="li1"><div class="de1"> # LIST-SPECIFIC</div></li>
<li class="li1"><div class="de1"> </div></li>
<li class="li1"><div class="de1"><span class="re6">@@ -963,6 +976,10 @@ type:context-type=empty</span></div></li>
<li class="li1"><div class="de1"> name=List Options</div></li>
<li class="li1"><div class="de1"> submenus:enabled=enabled</div></li>
<li class="li1"><div class="de1"> </div></li>
<li class="li1"><div class="de1"><span class="re8">+<span class="br0">[</span>context_menus/tree_views/save_list_to_config<span class="br0">]</span></span></div></li>
<li class="li1"><div class="de1"><span class="re8">+name=Save to configuration...</span></div></li>
<li class="li1"><div class="de1"><span class="re8">+trigger=command:tv_save_to_config <span class="br0">(</span>%o<span class="br0">)</span></span></div></li>
<li class="li1"><div class="de1"><span class="re8">+</span></div></li>
<li class="li1"><div class="de1"> # Selection</div></li>
<li class="li1"><div class="de1"> </div></li>
<li class="li1"><div class="de1"> <span class="br0">[</span>context_menus/tree_views/selection_select<span class="br0">]</span></div></li>
</ol></p>
<p>And of course there were a few bugfixes here and there, for a complete list
please refer to the git log. With that, I go back to coding, with idea being
that next time, hopefully we'll talk inline terminal...</p>
<p>In case you read all that and are wondering what donnatella is, or are looking
for more information, download links, etc please refer to <a href="/donnatella" title="donnatella: your file manager">donnatella</a>.</p>
<p>As always, bug reports, suggestions or any other form of constructive criticism
is very much welcome. You can open issues on
<a href="https://github.com/jjk-jacky/donnatella/issues">github</a>, use the thread on Arch
Linux forums, or simply email me.</p>
donnatella 0.1.1 is out2014-02-09T00:00:00+00:00http://jjacky.com/2014-02-09-donnatella-0.1.1<p>A new release of donnatella is out, fixing a few bugs. Most notably might be
that if you tried donna without the GTK patchset, no click would work on the
list!</p>
<p>This is a silly mistake on my part, setting the default click mode to a
non-existing one. New installations won't have the problem anymore, but for
others this can easilly be fixed (even without the update, though you should
upgrade as well) by editing your <code>~/.config/donnatella/donnatella.conf</code> file,
and looking for option <code>click_mode</code> under section <code>[defaults/lists]</code></p>
<p>It will be set to "donna_unpatched" while it should be simply set to "donna"</p>
</p>
<p>Apart from that and a few other bugfixes, when you have files in the clipboard
(register '+') it will now be possible to paste them as text (e.g. in your
terminal or text editor), as a list of full filenames.</p>
<p>As usual, see <a href="/donnatella" title="donnatella: your file manager">donnatella</a> for all the links and a more complete description.
And of course, as always, new bug reports, suggestions or any other form of
constructive criticism is very much welcome.</p>
donnatella: A brand new Linux file manager2014-02-08T00:00:00+00:00http://jjacky.com/2014-02-08-donnatella-a-brand-new-linux-file-manager<p>So I have been working on this little project for some time now, and I am happy
to finally have a first (pre-alpha) release to share with the world. That makes
a first (and important) milestone I can check.</p>
<p>donnatella - donna for short - is a free software, file manager for GNU/Linux
systems.</p>
<p>Did the world really need (yet) another file manager, you ask? Well, obviously I
felt it did. I have my reasons, so let me explain why I decided to work on this,
and see if donna might (or not) be of interest to you.</p>
</p>
<h3>Why another file manager ?</h3>
<p>True, there is already a selection of file managers one can choose from, so why
make another one? Mostly because I couldn't find what I was looking for.</p>
<p>While there are file managers, it felt to me that there was really mainly 2
kinds of FM: CLI ones, which were of no interest to me simply because, while -
as any good Arch Linux users - not afraid of the command line, I was looking for
a GUI one; and ones made for, it seems, always the same target users, which I
don't recognize myself as. (And let's not event mention the recent trend to
"simplify" everything to the extreme, because the desktop is dead and everything
is made for phones and other tablets nowadays, of course.)</p>
<p>Most file managers seem to approach things in a similar fashion and target the
same kind of users. Nothing wrong with that, but I was looking for something
different. Targeting what can sometimes be referred to as "power users," for
those who - even on GNU/Linux - would like to use a GUI file manager instead of
a CLI one (or none at all).</p>
<p>And as a free software enthusiast, I like the idea of putting the user in the
center, giving him/her the control. A good tool isn't one you have to change
your habits & workflow to adapt to, but one that adapts to you. Because the
user has to be in charge, that's (part of) the whole idea.</p>
<p>Adding to that is the fact that I had been using Windows for (too) many (many)
years, and there as well it took me some time to find a file manager I liked.
But I eventually did, I loved it and even became addicted to quite a few of its
unique features.</p>
<p>So I knew I was looking certain things I would most likely not find in any
existing file managers for Linux.</p>
<h3>Inspiration</h3>
<p>If you're working on Windows, consider switching to the wonderful world of free
software. If you can't, and are in need of a good file manager, I couldn't
recommend anything other than <a href="http://www.xyplorer.com">XYplorer</a>.</p>
<p>It is a brilliant tool, backed by its amazing author who's listening to its
customers and improving it daily. donnatella is in no way trying to be a
"clone" of XY in any way, but having used it for as many years as I have, being
addicted to some of its unique features as I am, users of XY will certainly
recognize in donna some features from XY, such as the Mini Tree, Boxed Branches,
and other wonders.</p>
<h3>Unix: Where you have one tool for one job</h3>
<p>Another source of inspiration for donna was this famous idea that says that you
should have one tool for one job, and combine them to perform whatever task you
need done.</p>
<p>It's an idea I certainly like, but that seem to vanish as soon as we enter the
world of GUI. I'll use an analogy that is certainly imperfect and has its
limitations, but bear with me (and forget that there are CLI file managers for a
minute) :</p>
<p>On the command line, the equivalent of the GUI file manager would be your shell.
You can use whichever you want, you can even switch at will, this will not
impact what tools you use daily.</p>
<p>You shell will not copy, delete or search for files. It's not its role. It is
there to <strong>provide you an interface to your file system, to help you easily use
the tools you need on your files</strong>, but it doesn't actually do those jobs, it
lets you use that one tool for the job.</p>
<p>And yet, as soon as we use a GUI file manager, it becomes a completely different
story: your FM will be the one tool to do everything: copy, delete, search,
show/preview any media files, (un)mount devices, it does it all.</p>
<p>donna doesn't follow this idea, and tries to do nothing; Nothing else than being
an interface to your file system, and provide ways to easily use whatever tools
you might need to work with your files.</p>
<p>Why redo <code>cp</code>, <code>mv</code>, and other <code>find</code> when they are all very good, tested &
optimized tools for their specific jobs. For example, donna will simply allow
you to start <code>find</code>, then parse its output and present the results in its own
GUI: you get the speed & power of find with the efficiency of donna's interface.</p>
<p>And if you want to search for files owned by a given package, you can simply use
your package manager the same way. Pick the right tool for the job, and use
donna (and its GUI interface) to help you work better/faster.</p>
<h3>Also: unique features!</h3>
<p>This explains why I decided to work on this little project. But that's not all.
As hinted earlier, during my years using XYplorer, I've become addicted to quite
a few fantastic features that were either really nice to have, or became a
requirement in my daily workflow.</p>
<p>donna aims to provide such really cool features, brand new ones or ones clearly
inspired from other tools. Please see <a href="/donnatella" title="donnatella: your file manager">donnatella</a> for a (non exhaustive) list
of such (implemented) features, as well as download links and the likes.</p>
<p>And of course, as always, bug reports, suggestions or any other form of
constructive criticism is very much welcome.</p>
Make jekyll fast again: Compile rb-gsl with Ruby 2.12014-02-03T00:00:00+00:00http://jjacky.com/2014-02-03-make-jekyll-fast-again-compile-rb-gsl-with-ruby-2.1<p>In order to make this blog, I use <a href="http://jekyllrb.com/">jekyll</a>. It does the
job quite well, but it's not the first time I find it's becoming a PITA to keep
it updated and running.</p>
<p>Today it wasn't so much one of the many dependencies that caused issues though,
but the very much required rb-gsl, if you don't want jekyll to take about 2 to 6
months to generate a small site like this one.</p>
<p>Arch Linux is now offering ruby 2.1, and rb-gsl doesn't compile anymore. Looking
into it, I found a few reports of the errors I got, such as <a href="https://github.com/romanbsd/rb-gsl/issues/10">this
one</a>. Unfortunately, there was no
solution.</p>
</p>
<p>So I kept looking, and found that recent changes in ruby caused this, and
apparently one cannot set <code>RBASIC(obj)->klass</code> anymore, as it has been marked
const.</p>
<p>From <a href="https://bugs.ruby-lang.org/projects/ruby-trunk/repository/revisions/40691">this</a>
I gather that a new macro - <code>RBASIC_SET_CLASS</code> - is apparently going to be added
to fix such code, but even though the breaking was part of 2.1, the way to fix
it wasn't. I'm sure there's a reason/excuse for that somewhere, but I didn't
have time to look for it.</p>
<p>So instead, I just came up with some ugly hack to "fix" things so that it
compiles again, adding the macro whenever it's needed, and using it. It could be
done more properly, but I had spent enough time on this as this was. If you
need it, <a href="https://github.com/jjk-jacky/abs/blob/master/rb-gsl-jjk/fix-ruby-2.1.patch">here's the
patch</a>.</p>
<p>It should also be noted that while Arch Linux now has gsl 1.16, rb-gsl won't
compile with it. I'm sure there's a way to fix it, but I just downgraded.</p>
Restore "Click to Activate" per-element in Firefox2013-10-24T00:00:00+00:00http://jjacky.com/2013-10-24-restore-click-to-activate-per-element-in-firefox<p>This certainly comes a little late, but it took me this long to finally look
into it, and I'm glad I did, so let's share.</p>
<p>As you may know, with Firefox 24 the behavior of the "Click to Activate" feature
for plugins, most notably Flash, was changed. I don't remember when it was first
introduced, and am too lazy to go look for it, but for a little while know there
has been an option <code>plugins.click_to_play</code> that one could/should set to <code>true</code>
in order to have plugins not enabled by default.</p>
<p>And if/when you wanted to activate something, all you had to do was click on it.
This would not enable the plugin for the whole page, but just that one element
you clicked on.</p>
<p>As <a href="https://blog.mozilla.org/futurereleases/2013/09/24/plugin-activation-in-firefox/">they explained</a>,
Mozilla did change this behavior - apparently too confusing for some users - and
now there's a supposedly much better UI, I suppose.</p>
</p>
<h3>Allow Now or Allow and Remember?</h3>
<p>That is, when you click on a disactivated plugin, you get a little prompt asking
you to "Allow Now" or "Allow and Remember" ? Which makes it pretty obvious what
they'll do, right?</p>
<p>For one, they activate the plugin <strong>on the entire page</strong>, it's all or nothing,
no more fine selection.</p>
<p>Also, "Allow Now" doesn't mean, as you could have thought, that once you leave
the page/close the tab, the plugin is disabled again. Nope, <strong>it'll remain
enabled now, for the entire domain you activated it for, and for quite some
time</strong>. Which I suppose was made clear by the "Allow Now" label, or something.</p>
<p>Seriously though, turns out "Allow Now" means allow for the entire domain, and
remain enabled for 60 minutes. As for "Allow and Remember" it's the same, only
for 90 days. So "Now" does remember for a while, while "Remember" does forget
after some time. That's what makes obvious sense for Mozilla I guess.</p>
<p>"Good news everyone!" <strong>Those can be changed</strong>: using options
<code>plugin.sessionPermissionNow.intervalInMinutes</code> and
<code>plugin.persistentPermissionAlways.intervalInDays</code> you can customize how long
the plugin will remain enabled/activated for in each case.</p>
<h4>A nice trick</h4>
<p>The cool thing being that is you set e.g.
<code>plugin.sessionPermissionNow.intervalInMinutes</code> to 0 (zero), then it won't
remain enabled at all. In other words, you really enable it <u>for now</u> and that's
it. Close the tab, leave/reload the page, it's not enabled anymore.</p>
<h3>How about the per-element feature?</h3>
<p>If you happen to have read the Mozilla blog post linked earlier, you'll already
be aware of that nice little addon: <a href="https://addons.mozilla.org/en-US/firefox/addon/click-to-play-per-element/">Click to Play
per-element</a>
which, as you guessed, restores the ability to only enable the clicked element,
and nothing else.</p>
<p>So now, combining the two - which is what I do/recommend - you can have the
choice:</p>
<ul>
<li><p>Click on an element to only enable said element and nothing else (and only for
now of course, close/reload and it's disabled again);</p></li>
<li><p>Click the icon on the left of the address bar, and click "Allow Now" to enable
it on the whole page, but again only for now;</p></li>
<li><p>If you're mad, use "Allow and Remember" and be scared for the next 90 days (or
however long you wish).</p></li>
</ul>
<p>This pretty much restores the original behavior we had in earlier versions,
which was - IMO - much better. Either way, you should now know all you need to
set things up the way you want, hopefully.</p>
Next kalu is in AUR, with FIFO commands2013-10-20T00:00:00+00:00http://jjacky.com/2013-10-20-next-kalu-is-in-aur-with-fifo-commands<p>First of all, I've shared before a PKGBUILD to build kalu from its branch next
on github, but I had yet to <a href="https://aur.archlinux.org/packages/kalu-git" title="kalu-git @ AUR">upload it the the
AUR</a>. I'm not sure
why I hadn't, but this has now been done.</p>
<p>So if you want to test the next version of kalu, you just need to switch from
kalu to kalu-git in the AUR. And speaking of the next version of kalu, you can
now send it "commands" simply by writing to a FIFO.</p>
</p>
<p>On start, kalu will create a FIFO named <code>kalu_fifo_XXXX</code> (where <u>XXXX</u> is kalu's
process ID) under your runtime directory (i.e. <code>$XDG_RUNTIME_DIR</code>), and it is
possible to send kalu "commands" simply by writing to this FIFO. Commands are
simple text strings, followed by a new-line character (\n).</p>
<p>This can be used e.g. to pause kalu, or have it run its checks either from a
terminal, a script, or even via keyboard shortcuts, instead of having to go
click on its systray icon/menu.</p>
<p>Note that it is possible for some commands to, at times, be no-op. For example,
sending a command to start a sysupgrade while kalu is running its check will do
nothing.</p>
<p>Supported commands are:</p>
<ul>
<li><p><strong>run-checks</strong> (or <strong>manual-checks</strong>)
Run the manual checks, same as using menu "Check for Upgrades..."</p></li>
<li><p><strong>auto-checks</strong>
Run the automatic checks. This is usually only triggered by kalu and cannot
otherwise be triggered manually (except using the <code>--auto-checks</code> command line
argument).</p></li>
<li><p><strong>show-last-notifs</strong>
Re-show last notifications.</p></li>
<li><p><strong>toggle-pause</strong>
Pause/resume automatic checks.</p></li>
<li><p><strong>sysupgrade</strong>
Start a system upgrade. Like using menu "System upgrade..." the actual action
(e.g. run kalu's updater, or start a command line) depends on your preferences.</p></li>
<li><p><strong>show-unread-news</strong>
Show unread Arch Linux news</p></li>
<li><p><strong>show-recent-news</strong>
Show recent Arch Linux news</p></li>
<li><p><strong>popup-menu</strong>
Pops up the systray menu at current mouse pointer position.</p></li>
</ul>
<p>If you're interested, don't hesitate to give it a try, and please report
anything broken or that could be better.</p>
<p>And thanks to Danil Semelenov for the original idea.</p>
kalu 2.3.0 released2013-10-18T00:00:00+00:00http://jjacky.com/2013-10-18-kalu-2.3.0-released<p>A new version of kalu is available, with a few fixes and the <a href="/2013-08-21-preview-conflicts-in-arch-linux-system-upgrade" title="Preview Conflicts in Arch Linux system upgrade @ jjacky.com">simulation in case
of conflicts</a>
as previously discussed, as well as support for <code>\e</code> in template variables,
which can be useful if you're running kalu as CLI application, to use
bold/colors.</p>
<p>Also, following the <a href="2013-10-08-fixing-the-gnome-3.10-upgrade" title="Fixing the GNOME 3.10 upgrade @ jjacky.com">GTK 3.10
upgrade</a>
and for those who didn't downgrade or patch their GTK, i.e. are missing their
icons in menus & buttons, I've also added a config tweak to forces them back.</p>
</p>
<h3>Downloads and whatnot</h3>
<p>Thanks to all those who reported bugs or suggested features, to Kolibry for the
updated French translation and Mickael FALCK for his contributions.</p>
<p>See <a href="/kalu" title="kalu: Keep Arch Linux Up-to-date">kalu</a> for longer descriptions & all the links you should need.</p>
<p>And of course, as always, new bug reports, suggestions or any other form of
constructive criticism is very much welcome.</p>
journal-triggerd v0.2.0 is out2013-10-12T00:00:00+00:00http://jjacky.com/2013-10-12-journal-triggerd-v0.2.0-is-out<p>A new version of <a href="/journal-triggerd" title="journal-triggerd: Run triggers on systemd's journal message">journal-triggerd</a> is available, fixing a possible segfault
when certain loading rules, and some other little changes :</p>
<ul>
<li><p>Failing to load a rule will now simply be announced & the file skipped. Only
if no rule could be loaded will journal-triggerd not start.</p></li>
<li><p>Added options <code>--verbose</code> & <code>--quiet</code></p></li>
<li><p>Added support for <code>$'FIELD</code> on trigger, that allows to not include the field's
value as-in, but put it between single quote (shell-compatible style).</p></li>
</ul>
</p>
<h3>Downloads and whatnot</h3>
<p>Thanks to barjac for his bug report & suggestions, as well as create a package
for journal-triggerd on <a href="https://www.mageia.org/">Mageia</a>.</p>
<p>See <a href="/journal-triggerd" title="journal-triggerd: Run triggers on systemd's journal message">journal-triggerd</a> for longer descriptions & all the links you should need.</p>
<p>And of course, as always, new bug reports, suggestions or any other form of
constructive criticism is very much welcome.</p>
"Fixing" the GNOME 3.10 upgrade2013-10-08T00:00:00+00:00http://jjacky.com/2013-10-08-fixing-the-gnome-3.10-upgrade<p>Recently GNOME 3.10 was pushed to the <a href="https://www.archlinux.org" title="Arch Linux">Arch Linux</a> repos. I don't really
care about GNOME as I don't use it, but with a GNOME release usually also come
new versions of a few independent components such as GLib or GTK+.</p>
<p>Unfortunately, it seems GNOME developers have no problem trying to force their
decisions not only to their users, but also users of any application using GTK+
regardless of their DE.</p>
<p>Specifically, this upgrade wasn't easy (to me) when it comes to icons. After the
upgrade, I had quite a few icons broken, and lots of buttons & menus where icons
were simply missing altogether.</p>
</p>
<h3>Broken icons: what's with symbolic icons anyways?</h3>
<p>The first issue was linked to symbolic icons. In addition to the "regular"
icons, provided by whatever theme you have installed, GNOME (and GTK) also uses
those so-called symbolic icons, for some reason.</p>
<p>This isn't another icon theme that one can chose to use or not. Those icons are
"part" of the main theme, complementing it somehow. And in quite a few places,
instead of asking for an icon, e.g. "dialog-error" when showing an error
message, GTK will ask for the symbolic version ("dialog-error-symbolic").</p>
<p>Until now, when such icon couldn't be found, it would fall back to the
non-symbolic version. However, the algorithm was buggy, as it could send
"foo-bar" when "foo-bar-symbolic" wasn't found, even though "foo-symbolic"
existed (and therefore should have been returned); See <a href="https://bugzilla.gnome.org/show_bug.cgi?id=680926">this bug
report</a> for more.</p>
<p>And when that got fixed, they decided to never fall back to non-symbolic icons.
If no symbolic icon is found, then it's the missing icon that will be used.
Which is a problem for me, because, of course, I don't have any of those.</p>
<p>I'm not sure what's the point of such icons is, but as far as I'm concerned they
just replaced my perfectly fine looking icons from the icon theme I selected,
with ugly flat icons I didn't like at all. So I removed them, plain & simple.</p>
<h4>Adding a fallback to non-symbolic icons</h4>
<p>Once this was established, I decided to simply add a fallback to the "regular"
icons in the algorithm, as originally suggested in the bug report. For this to
work, it had to be done twice: once in GLib (re: GThemedIcon), and once in GTK
(re: GtkIconTheme).</p>
<p>Here are the patches I used:</p>
<h4>Patching GLib</h4>
<p><ol class="diff"><li class="li1"><div class="de1">diff --git a/gio/gthemedicon.c b/gio/gthemedicon.c</div></li>
<li class="li1"><div class="de1">index <span class="nu0">9016860</span>..e<span class="re0">7a59</span>f8 <span class="nu0">100644</span></div></li>
<li class="li1"><div class="de1"><span class="re3">--- a/gio/gthemedicon.c</span></div></li>
<li class="li1"><div class="de1"><span class="re4">+++ b/gio/gthemedicon.c</span></div></li>
<li class="li1"><div class="de1"><span class="re6">@@ -187,12 +187,12 @@ g_themed_icon_constructed <span class="br0">(</span>GObject *object<span class="br0">)</span></span></div></li>
<li class="li1"><div class="de1"> </div></li>
<li class="li1"><div class="de1"> if <span class="br0">(</span>is_symbolic<span class="br0">)</span></div></li>
<li class="li1"><div class="de1"> <span class="br0">{</span></div></li>
<li class="li1"><div class="de1"><span class="re7">- themed->names = g_new <span class="br0">(</span>char *, dashes + <span class="nu0">1</span> + <span class="nu0">1</span><span class="br0">)</span>;</span></div></li>
<li class="li1"><div class="de1"><span class="re8">+ themed->names = g_new <span class="br0">(</span>char *, <span class="nu0">2</span> * <span class="br0">(</span>dashes + <span class="nu0">1</span><span class="br0">)</span> + <span class="nu0">1</span><span class="br0">)</span>;</span></div></li>
<li class="li1"><div class="de1"> for <span class="br0">(</span>i = <span class="nu0">0</span>; names<span class="br0">[</span>i<span class="br0">]</span> != NULL; i++<span class="br0">)</span></div></li>
<li class="li1"><div class="de1"> themed->names<span class="br0">[</span>i<span class="br0">]</span> = g_strconcat <span class="br0">(</span>names<span class="br0">[</span>i<span class="br0">]</span>, "-symbolic", NULL<span class="br0">)</span>;</div></li>
<li class="li1"><div class="de1"> </div></li>
<li class="li1"><div class="de1"><span class="re7">- themed->names<span class="br0">[</span>i<span class="br0">]</span> = NULL;</span></div></li>
<li class="li1"><div class="de1"><span class="re7">- g_strfreev <span class="br0">(</span>names<span class="br0">)</span>;</span></div></li>
<li class="li1"><div class="de1"><span class="re8">+ memcpy <span class="br0">(</span>themed->names + i, names, sizeof <span class="br0">(</span>char *<span class="br0">)</span> * <span class="br0">(</span>dashes + <span class="nu0">1</span> + <span class="nu0">1</span><span class="br0">)</span><span class="br0">)</span>;</span></div></li>
<li class="li1"><div class="de1"><span class="re8">+ g_free <span class="br0">(</span>names<span class="br0">)</span>;</span></div></li>
<li class="li1"><div class="de1"> <span class="br0">}</span></div></li>
<li class="li1"><div class="de1"> else</div></li>
<li class="li1"><div class="de1"> <span class="br0">{</span></div></li>
</ol></p>
<h4>Patching GTK</h4>
<p><ol class="diff"><li class="li1"><div class="de1">diff --git a/gtk/gtkicontheme.c b/gtk/gtkicontheme.c</div></li>
<li class="li1"><div class="de1">index d912687..<span class="re0">1a225</span>a2 <span class="nu0">100644</span></div></li>
<li class="li1"><div class="de1"><span class="re3">--- a/gtk/gtkicontheme.c</span></div></li>
<li class="li1"><div class="de1"><span class="re4">+++ b/gtk/gtkicontheme.c</span></div></li>
<li class="li1"><div class="de1"><span class="re6">@@ -1897,12 +1897,12 @@ gtk_icon_theme_lookup_icon_for_scale <span class="br0">(</span>GtkIconTheme *icon_theme,</span></div></li>
<li class="li1"><div class="de1"> </div></li>
<li class="li1"><div class="de1"> if <span class="br0">(</span>is_symbolic<span class="br0">)</span></div></li>
<li class="li1"><div class="de1"> <span class="br0">{</span></div></li>
<li class="li1"><div class="de1"><span class="re7">- names = g_new <span class="br0">(</span>gchar *, dashes + <span class="nu0">2</span><span class="br0">)</span>;</span></div></li>
<li class="li1"><div class="de1"><span class="re8">+ names = g_new <span class="br0">(</span>gchar *, <span class="nu0">2</span> * <span class="br0">(</span>dashes + <span class="nu0">1</span><span class="br0">)</span> + <span class="nu0">1</span><span class="br0">)</span>;</span></div></li>
<li class="li1"><div class="de1"> for <span class="br0">(</span>i = <span class="nu0">0</span>; nonsymbolic_names<span class="br0">[</span>i<span class="br0">]</span> != NULL; i++<span class="br0">)</span></div></li>
<li class="li1"><div class="de1"> names<span class="br0">[</span>i<span class="br0">]</span> = g_strconcat <span class="br0">(</span>nonsymbolic_names<span class="br0">[</span>i<span class="br0">]</span>, "-symbolic", NULL<span class="br0">)</span>;</div></li>
<li class="li1"><div class="de1"> </div></li>
<li class="li1"><div class="de1"><span class="re7">- names<span class="br0">[</span>i<span class="br0">]</span> = NULL;</span></div></li>
<li class="li1"><div class="de1"><span class="re7">- g_strfreev <span class="br0">(</span>nonsymbolic_names<span class="br0">)</span>;</span></div></li>
<li class="li1"><div class="de1"><span class="re8">+ memcpy <span class="br0">(</span>names + i, nonsymbolic_names, sizeof <span class="br0">(</span>gchar *<span class="br0">)</span> * <span class="br0">(</span>dashes + <span class="nu0">2</span><span class="br0">)</span><span class="br0">)</span>;</span></div></li>
<li class="li1"><div class="de1"><span class="re8">+ g_free <span class="br0">(</span>nonsymbolic_names<span class="br0">)</span>;</span></div></li>
<li class="li1"><div class="de1"> <span class="br0">}</span></div></li>
<li class="li1"><div class="de1"> else</div></li>
<li class="li1"><div class="de1"> <span class="br0">{</span></div></li>
</ol></p>
<h3>No more icons on buttons & in menus</h3>
<p>This one was also a deliberate change, though while I'll give you that maybe not
having symbolic icons isn't the "proper"/usual way of doing things, this time I
don't have a special setup at all.</p>
<p>What happened is that apparently the GNOME folks decided they don't want to have
any icons in their buttons or menus anymore. I'm not sure why, since it's a
great help as everyone can see how using icons helps you recognize what you're
looking for much easier/faster.</p>
<p>I'm also not sure if forcing their choices onto their users is a good move, I
thought the whole idea of a GNU/Linux system was to put the <u>user</u> in control.
But where things go seriously wrong is when they force their changes to every
GTK users, or users/developers of GTK applications.</p>
<p>Which is what happened, what they deprecated options <code>gtk-button-images</code> and
<code>gtk-menu-images</code> in 3.10, meaning that those settings are now ignored, and
users have no choice in the matter anymore.</p>
<p>They'll tell you developers can still put icons in their menus/buttons if they
want to, but (a) that means patching every single GTK application to fix what
GTK 3.10 broke, and (b) that's doing nothing for <u>users</u>. What badly broke here
is the user experience of anyone using a GTK application that had icons in menus
and/or buttons (and that's <u>a lot</u> of them).</p>
<p>This is an issue they were fully aware of -- see <a href="https://bugzilla.gnome.org/show_bug.cgi?id=708674">this bug
report</a> -- but apparently
that didn't bother them much.</p>
<p>So I'm not sure how best to handle this eventually, but for now what I did was
simply revert the two commits that removed support of said options.
Specifically, I reverted commits <a href="https://git.gnome.org/browse/gtk+/commit/?h=gtk-3-10&id=65c31629c38b3b1f49fb6f3327dc28819ffe0657">65c31629</a>
and <a href="https://git.gnome.org/browse/gtk+/commit/?h=gtk-3-10&id=e8147d15f74e62047c84eb95e393449722198d89">e8147d15</a>.</p>
<p>And with all that, I finally have my system working as it should, with all icons
showing properly (including in buttons & menus, because I want/need that), with
GTK 3.10 installed.</p>
Run triggers on systemd's journal messages2013-10-06T00:00:00+00:00http://jjacky.com/2013-10-06-run-triggers-on-systemd-journal-messages<p>Running <a href="https://www.archlinux.org" title="Arch Linux">Arch Linux</a>, I've now been using systemd's journal as logging
engine for a little while. This isn't about how good/bad it is, or how it
compares to other solutions (e.g. syslog).</p>
<p>I'm using the journal, and for a little while now I've been wondering about
having a few things automatically triggered when certain messages are logged. I
looked for a tool to do that, but couldn't find one.</p>
<p>There are a few tools that will do that sort of things, but they're made for
very specific things, for instance listen for failed SSH login attempts, and
will (temporary) ban an IP after a while or something.</p>
</p>
<p>This is pretty much exactly the sort of things I was looking to do, but I wanted
to be able to define which messages to listen for, and what actions shall be
triggered.</p>
<p>Which is why I wrote a little tool to do just that: listen to any new messages
added to the journal, and whenever there's a match for a given "rule," trigger
the associated action.</p>
<h3>Filtering rules</h3>
<p>Identifying messages is done via so-called rules, which can be made of different
group of conditions, used via boolean logic. Each group of conditions can be
made of as many conditions as needed, all of which must match for the group to
be a match.</p>
<p>A condition is simply a test on a given field of the message. Supported tests
are exact match, pattern (glob-like) match, lesser/greater than tests which can
be used when the value of the message is an integer. It is also possible to
"negate" the test, so the condition match when the field is <strong>not</strong> a match.</p>
<p>Installed as a service, it runs in the background and whenever a matching
messages is added to the journal, the corresponding action is triggered. Exactly
what I was looking for.</p>
<p>For example, an error can sometimes occur leading to the network being down,
as the interface goes down with a speed/duplex mismatch error. This doesn't
happen very often and is easy enough to fix once the problem has been
identified, but now I don't have to, thanks to a simple rule like the following:</p>
<pre><code>[Rule]
trigger=systemctl restart network.service
[Filter]
_KERNEL_DEVICE=+pci:0000:02:00.0
MESSAGE=sky2 0000:02:00.0 net0: speed/duplex mismatch
</code></pre>
<h3>Download</h3>
<p>If you're interested, you can find out more about it from <a href="/journal-triggerd" title="journal-triggerd: Run triggers on systemd's journal message">journal-triggerd</a>. It
is released under GNU GPL v3+ The source code is available on <a href="https://github.com/jjk-jacky/journal-triggerd" title="journal-triggerd @ Github.com">this Github
repository</a>.</p>
<p>And of course any bug report, suggestion or other constructive criticism is very
much welcome.</p>
Automatically switch DPMS off in VLC 2.12013-09-30T00:00:00+00:00http://jjacky.com/2013-09-30-automatically-switch-dpms-off-in-vlc-2.1<p>For a little while now I've been using a little module of my own to handle
switching DPMS off automatically when playing, but as I recently upgraded to VLC
2.1 it broke.</p>
<p>I had to have a look at this again, and after fixing it I figured I might as
well share this, since I hadn't really done so yet, in case it might turn useful
to someone else, maybe you.</p>
</p>
<h3>Why is anything needed at all? VLC does it on its own...</h3>
<p>It is absolutely true that VLC comes with an option to "inhibit power management
daemon during playback" and a few modules to take care of that. There are,
however, a couple reasons why that didn't work for me.</p>
<p>First of all is the fact that I'm not using a session manager, which means I
might have a few things that would otherwise work fine, not actually work for
me. This is my choice and I'm fine with it, I still don't see the need for me to
have a session manager.</p>
<p>However, it is possible that the module "Inhibits power suspend and session idle
timeout" would work if I had one, or that <code>xdg-screensaver</code> (which is used by
the module "XDG screen saver inhibition") might work (better) as well (little
more on that in a bit).</p>
<p>Thing is, though, that it would still not meet my needs; And that's because of
how the whole inhibition system works in VLC, which - if I'm not mistaken - is
meant to start inhibition when playing a media, and until it stops.</p>
<p>Sounds about right, but the key word here is <u>stop</u>, it means that quite
literally, as in you need to hit "Stop" for it to be triggered, "Pause" won't do
it.</p>
<p>Now this might be what most people want, but not me. I happen to sometimes have
say a video running, I hit pause and go AFK for a few minutes, or hours. And
when that happens, I want my screens to go off, even though I did not hit "Stop"
(as I intend to come back and resume playing just where I was, thank you very
much).</p>
<p>For that reason, the "inhibit" capability of VLC's modules isn't really working
for me, and that would be the case even if I had a session manager running.</p>
<h3>How to handle the switching off & on</h3>
<p>I'm not exactly sure how the DBus module works, since I didn't really look into
it, but as explained above, the whole "inhibit" system in VLC makes it work on
Play & Stop only, not Pause.</p>
<p>The way the XDG module works, is that it will call <code>xdg-screensaver reset</code> every
30s or so from the moment you play a video, and until you stop it. As hinted,
this doesn't really do anything for me, but I believe the intent is to prevent
the screensaver to kick in while playing the media.</p>
<p>As I said, not at all what I was looking for. But besides adding the event for
"Pause" I decided to approach things a bit differently (if only, because that
method wouldn't work for me, of course).</p>
<p>I decided to trigger an action on "Play", and another one on "Pause" or "Stop."
This could (should?) have been <code>xdg-screensaver suspend/resume <window-id></code> but,
as you guessed, isn't what I went with.</p>
<p>The reason isn't due to my lack of session manager this time, but that I also do
not have <code>xprop</code> installed either, which is required by <code>xdg-screensaver</code> to
handle the whole "tracking of the window" bit that happens behind those
suspend/resume commands.</p>
<p>Not having it installed, those calls are simply turning DPMS off and on. So I
might as well just do that (e.g. call <code>xset +dpms</code> directly), and that's what I
did.</p>
<p>It's proper, but another reason to do that, was that I have no idea how to get
the window ID for VLC's window, and was too lazy to go find out.</p>
<h3>A new module, switching DPMS off on play, and back on on pause/stop</h3>
<p>And that's how this module was born. It registers its capability under
"interface" and not "inhibit" because, as explained, the latter didn't allow to
handle the switch on pause, as I wanted.</p>
<p>Once the module written & compiled, all I had to do was turn off the option for
inhibiting the screen saver (since it's useless for me, no need to have
some module uselessly calling <code>xdg-screensaver</code> every so often) and also add
"dpms" (the name of the module) under "Extra interfaces modules."</p>
<p>This is option "extraintf" in <code>vlcrc</code> (or on command-line), and for some reason
while it is in my <code>vlcrc</code> file, it doesn't show up when I open the Preferences
window in VLC. I'm not sure why, I don't doubt that next time I save my
preferences it will remove it, which will lead to me getting annoyed when my
monitor will go black in the middle of a video, so if anyone knows why/how to
fix it, please let me know -- thanks.</p>
<p>Anyhow, that was it. Now it works as I like/expect, I'm happy again. If you're
interested you can find <a href="https://github.com/jjk-jacky/abs/blob/8dfd37a74a9f2619ca4a7686d8c017cae660452c/vlc-jjk/0001-Add-dpms-module-to-switch-it-off-while-playing.patch">the patch to add this module on
Github</a>.</p>
<h3>Off topic: window won't get small no more</h3>
<p>Just as an extra note: In my constant aim to save pixels, I had tweaked VLC's
interface, notably to put the time slider in the main toolbar in order to get
rid of the time toolbar.</p>
<p>This worked well in previous versions, but since 2.1 it's broken, and the window
would refuse to have its width under 800 pixels or so. Incredibly annoying, so I
had to use the useless time toolbar again and waste so many space (but at least
I can resize the window however I want again).</p>
<p>In case that happened to you as well, and you're wondering why/how to "fix" it.</p>
Preview conflicts in Arch Linux system upgrade2013-08-21T00:00:00+00:00http://jjacky.com/2013-08-21-preview-conflicts-in-arch-linux-system-upgrade<p>Every once in a while, <a href="/kalu" title="kalu: Keep Arch Linux Up-to-date">kalu</a> will not be able to tell you what upgrades are
available. This isn't due to a bug, or because there's something wrong anywhere,
it's simply because there is (at least) one conflict.</p>
<p>A conflict often isn't a big deal, and handling it is quite simple, but it
requires <strong>your</strong> intervention, and that's why kalu can't list the upgrades:
because <strong>you</strong> need to decide whether or not to replace one package with
another, for example.</p>
<p>This was always a little annoying to me, because then kalu failed to do its
first objective: inform about what upgrades are available, what will happen
should a system upgrade be performed.</p>
<p>Sure, one can go on <a href="https://www.archlinux.org" title="Arch Linux">Arch's website</a>,
check the recent package updates and manually figure things out, but that
defeats the purpose of having a tool to do the job for you.</p>
<p>One could also just start a sysupgrade, but it forces you to sync your databases,
which basically means you then <u>have</u> to perform the whole operation right now.
What if you just wanted to know what would need to be done (including every
upgrades unrelated to the conflict), and <u>then</u> make an informed decision, about
<u>when</u> you'll perform the sysupgrade?</p>
</p>
<h3>Introducing a system upgrade "simulation"</h3>
<p>This is why kalu now features what's called a "simulation." When there's a
conflict - preventing kalu to compile the list of packages for which upgrades
are available - a new button will be featured on the notification: "Run
simulation"</p>
<p>A simulation is simply running the first step (i.e. compiling the list of
packages in the sysupgrade) of kalu's updater on a temporary copy of your
(synchronized) databases, in order to see what the conflict(s) is (are).</p>
<p>You will be presented with the usual GUI of kalu's updater, and after answering
the questions to resolve (or not) the conflicts, you'll be able to see the full
list of available upgrades.</p>
<p>Of course it stops there, there's no upgrading. The point of this is simply to
see how to resolve the conflict, and see what the upgrades are, as there might
be new dependencies to install, old packages to remove/replace, and of course a
few other/unrelated packages with available upgrades.</p>
<h4>Try again, test different scenario</h4>
<p>Once you have the list of packages - or just an error message about unresolved
conflict, as might also happen - you can easily start over.</p>
<p>Pressing the button "Rerun simulation" will reset the things, and instantly have
questions asked again, so you can try different scenario and see their impact
and figure out which one works (best) for you.</p>
<p>Once you're done, press "Close" and all temporary files will be removed. That's
it, your system remains unchanged. If you now want to actually do the upgrade,
use "Upgrade system" as usual (or manually run <code>pacman -Syu</code> or whatever you
prefer).</p>
<h3>Requirements</h3>
<p>Of course, you don't actually need to use kalu's updater for this to work, the
simulation will be available regardless of what action you've set for the
"Upgrade system" button (and even if you don't use that feature at all).</p>
<p>The only requirement is that kalu's updater was compiled in, of course, i.e. it
won't work if you compiled kalu using <code>--disable-updater</code> (or <code>--disable-gui</code>)</p>
<h3>Wanna try it?</h3>
<p>If you wanna test it, it's been pushed to the <a href="https://github.com/jjk-jacky/kalu/tree/next" title="kalu, branch next @ Github">branch 'next' on
Github</a>,
and you can use <a href="https://github.com/jjk-jacky/abs/tree/master/kalu-git" title="kalu-git @ Github">this
PKGBUILD</a>
to install it.</p>
<p>After that, all you need is a conflict in your next sysupgrade! :) And don't
hesitate to report any problems/bugs/suggestions you have for kalu, about this
feature or something else.</p>
kalu 2.2.0 released2013-06-30T00:00:00+00:00http://jjacky.com/2013-06-30-kalu-2.2.0-released<p>A new version of kalu is available, which will now set a user-agent to be used
for all its connections, including those done via ALPM (i.e. synchronizing
databases, but also downloading packages when using kalu's sysupgrader).</p>
<p>It's not a bad thing to do, and will even fix issues some have been having with
e.g. infinality-bundle repos, where lack of user-agent resulted in a download
error (HTTP 406).</p>
</p>
<h3>Tweak kalu's icons to your liking</h3>
<p>Changes were also done in how icons are loaded. kalu uses 4 versions of its icon
in the systray, based on its current state. The regular (blue) icon indicates
that upgrades were found during the last checks, the gray version indicates that
nothing was found; Both versions exists with a pause symbol on top, when kalu is
paused.</p>
<p>kalu will now try and load all icons from the current theme, thus allowing you
to override any (and all) of them as you wish. The main icon is <code>kalu</code>, the
paused version <code>kalu-paused</code>, the gray versions are <code>kalu-gray</code> and
<code>kalu-gray-paused</code> respectively.</p>
<p>So to e.g. use a different gray icon, one could simply put a file
<code>kalu-gray.png</code> in folder <code>~/.local/share/icons</code></p>
<p>Of course, kalu will still create the gray and/or paused versions as needed,
based on loaded icons.</p>
<p>Note that the regular icon is also used elsewhere in kalu, e.g. in buttons or
menus.</p>
<h3>Perform sysupgrade without enterring a password?</h3>
<p>Thanks to tips from moonman, kalu now comes with a polkit rule that will allow
any user in the group <code>kalu</code> to perform a sysupgrade (through kalu, obviously)
without the need for authentication (e.g. being prompted for one's password).</p>
<p>So if you don't want to have to enter your password before doing a system
upgrade, simply add yourself to the group <code>kalu</code> and that's it.</p>
<p>Note that the group's name can actually be set on configure time, and it's also
possible to simply copy <code>/usr/share/polkit-1/rules.d/30-kalu.rules</code> to
<code>/etc/polkit-1/rules.d</code> and tweak it to your liking.</p>
<h3>Downloads and whatnot</h3>
<p>Thanks to all those who reported bugs or suggested features, and Kolibry for the
updated French translation.</p>
<p>See <a href="/kalu" title="kalu: Keep Arch Linux Up-to-date">kalu</a> for longer descriptions & all the links you should need.</p>
<p>And of course, as always, new bug reports, suggestions or any other form of
constructive criticism is very much welcome.</p>
pacdep 1.1.0: Dependency path2013-06-23T00:00:00+00:00http://jjacky.com/2013-06-23-pacdep-1.1.0-dependency-path<p>A new version of pacdep is out, fixing optional dependencies not working since
pacman 4.1.0, and introducing a new option to show the "dependency path" for
each package, inspired by <a href="https://bugs.archlinux.org/task/35661" title="FS#35661 - [pacman] Make pactree show the shortest dependency path between packages foo and bar">karol's request for
pactree</a>.</p>
<p>Using option <strong>--show-path</strong> will show the (shorter) "dependency path" for each
of the listed dependency, that is showing why a dependency is there, up to the
main package.</p>
<p>This can be useful to understand why a dependency is listed, if it appears as
dependency of a dependency of yet another dependency of the main package.</p>
</p>
<p>For example, if one wonders why ncurses appears as (shared) dependency as kalu,
a quick <code>pacdep -Ps kalu</code> would provider the answer:</p>
<pre><code>ncurses 9.75 MiB <- readline <- js <- polkit <- kalu
</code></pre>
<h3>Downloads and whatnot</h3>
<p>Thanks to all those who reported bugs or suggested features (for pacdep, or
other projects ;)).</p>
<p>For longer descriptions & all the links you should need, see <a href="/pacdep" title="pacdep: Easily list package dependencies">pacdep</a>.</p>
<p>And of course, as always, new bug reports, suggestions or any other form of
constructive criticism is very much welcome.</p>
kalu 2.1.0 and PkgClip 1.2.1 are out2013-05-12T00:00:00+00:00http://jjacky.com/2013-05-12-kalu-2.1.0-and-pkgclip-1.2.1-are-out<p>Couple of updates are available. Nothing new for <a href="/pkgclip" title="PkgClip: Cached Packages Trimmer Utility">pkgclip</a>, just minor tweaks in
the code and a little rewrite to move the process of loading packages into a
separate thread. This should ensure the GUI doesn't get somewhat unresponsive
during that time, and even make things be/feel a bit faster.</p>
<p>As far as <a href="/kalu" title="kalu: Keep Arch Linux Up-to-date">kalu</a> goes, a couple new options were added as well as a tweak that
might be helpful for those using notify-osd as notification daemons (which has
the unfortunate idea of turning notifications with action buttons into
non-expiring windows).</p>
<p>And it also includes changes to reflect the latest changes in the API introduced
with pacman 4.1.1.</p>
<p>Also, both of those see their option "SaneSortOrder" disappear, since there's
actually a GTK+ option (in GTK3) that allows to do the same (but for <u>all</u> GTK3
applications!), so better to use that: <code>gtk-alternative-sort-arrows</code></p>
</p>
<p>In case you're interrested, that means simply edit/create the file
<code>~/.config/gtk-3.0/settings.ini</code> and put this in:
[Settings]
gtk-alternative-sort-arrows=true
Unfortunately, I don't think there's such a thing for GTK2. (If I'm wrong about
this, please let me know!)</p>
<h3>kalu 2.1.0</h3>
<p>Changes since last version are :</p>
<ul>
<li><p>Add new option on single/double-click to exit kalu</p></li>
<li><p>Add support of middle-click on the systray icon</p></li>
<li><p>kalu-updater: Change the way expander (Log) behaves: It wasn't very nice
whenever the paned position was changed, with regards to resizing the toplevel
window. Now it won't resize it, and should remember the last used positions
(expanded & collapsed).
Still not perfect, but better.</p></li>
<li><p>Preferences: Reset timeout for next auto-checks after a save</p></li>
<li><p>Add config tweak <code>NotifButtons</code> to remove buttons from all notifications
(So notify-osd doesn't turn notifications into non-expiring windows.)</p></li>
<li><p>Remove option SaneSortOrder; It's useless, since GTK3 actually has an option
of its own for that.</p></li>
<li><p>kalu-dbus: <code>ALPM_QUESTION_LOCAL_NEWER</code> was removed from ALPM in libalpm 8.0.1
(pacman 4.1.1)</p></li>
<li><p>Update French translation to 2.0.1</p></li>
</ul>
<h3>pkgclip 1.2.1</h3>
<p>Changes since last vesion are :</p>
<ul>
<li><p>Loading packages is now done in a separate thread, so it should be/feel faster</p></li>
<li><p>Remove option "sane sort indicator"</p></li>
</ul>
<h3>Downloads and whatnot</h3>
<p>Thanks to all those who reported bugs or suggested features.</p>
<p>Longer descriptions & all the links you should need can be found for <a href="/kalu" title="kalu: Keep Arch Linux Up-to-date">kalu</a> and
<a href="/pkgclip" title="PkgClip: Cached Packages Trimmer Utility">pkgclip</a>.</p>
<p>And of course, as always, new bug reports, suggestions or any other form of
constructive criticism is very much welcome.</p>
Make jekyll fast again: Compile rb-gsl on Arch Linux2013-04-21T00:00:00+00:00http://jjacky.com/2013-04-21-make-jekyll-fast-again-compile-rb-gsl-on-arch-linux<p>In order to make this blog, I use <a href="http://jekyllrb.com/">jekyll</a>. It's a great
little thing that takes simple text files (using Markdown syntax in my case,
more is supported) and turns them into the HTML files your browser is showing
you now.</p>
<p>It's great, but awfully slow by default. This blog doesn't have a lot of
content, yet it takes, well, too long for me to have actually waited for it. As
a note nicely indicates though, using <code>rb-gsl</code> will speed things up immensely. It
mentions 10 times faster results, but I'm pretty sure it's (much) much more than
that for me.</p>
<p>Unfortunately, things didn't work so well recently, as I upgraded to ruby 2.0
The cost of living bleeding edge and all that, or something. Anyhow, rb-gsl wouldn't
compile no more, making me a sad panda.</p>
</p>
<p>Here's the error I would get :</p>
<pre><code>rb-gsl-1.14.7/ext/extconf.rb:245:in `<main>': undefined method `searcher' for Gem:Module (NoMethodError)
</code></pre>
<p>After some research, I figured this would be because the <code>searcher</code> method, or
the <code>GemPathSearcher</code> object behind it, have been removed from the latest ruby. I
don't know anything about ruby, but luckily was able to find <a href="https://github.com/whistlerbrk/rb-gsl">a
fork</a> where this issue has <a href="https://github.com/whistlerbrk/rb-gsl/commit/062436bb188046862dfa4d697d45ddc73ceaf54a">been
fixed</a>.</p>
<p>Another error then popped out of course, though it came from C compilation this
time (maybe linked to the new gcc version?) :</p>
<pre><code>ieee.c:64:31: error: lvalue required as unary ‘&’ operand
</code></pre>
<p>This was fixed with the following patch:</p>
<p><ol class="diff"><li class="li1"><div class="de1"><span class="re3">--- ext/ieee.c.org 2010-11-10 05:41:02.000000000 +0100</span></div></li>
<li class="li1"><div class="de1"><span class="re4">+++ ext/ieee.c 2013-04-20 14:36:09.983516799 +0200</span></div></li>
<li class="li1"><div class="de1"><span class="re6">@@ -61,7 +61,8 @@</span></div></li>
<li class="li1"><div class="de1"> rb_raise<span class="br0">(</span>rb_eTypeError, "wrong argument type %s <span class="br0">(</span>Float expected<span class="br0">)</span>",</div></li>
<li class="li1"><div class="de1"> rb_class2name<span class="br0">(</span>CLASS_OF<span class="br0">(</span>vtmp<span class="br0">)</span><span class="br0">)</span><span class="br0">)</span>;</div></li>
<li class="li1"><div class="de1"> #ifdef RUBY_1_9_LATER</div></li>
<li class="li1"><div class="de1"><span class="re7">- gsl_ieee_fprintf_double<span class="br0">(</span>fp, &<span class="br0">(</span>RFLOAT_VALUE<span class="br0">(</span>vtmp<span class="br0">)</span><span class="br0">)</span><span class="br0">)</span>;</span></div></li>
<li class="li1"><div class="de1"><span class="re8">+ double _dbl = RFLOAT_VALUE<span class="br0">(</span>vtmp<span class="br0">)</span>;</span></div></li>
<li class="li1"><div class="de1"><span class="re8">+ gsl_ieee_fprintf_double<span class="br0">(</span>fp, &_dbl<span class="br0">)</span>;</span></div></li>
<li class="li1"><div class="de1"> #else</div></li>
<li class="li1"><div class="de1"> gsl_ieee_fprintf_double<span class="br0">(</span>fp, &<span class="br0">(</span>RFLOAT<span class="br0">(</span>vtmp<span class="br0">)</span>->value<span class="br0">)</span><span class="br0">)</span>;</div></li>
<li class="li1"><div class="de1"> #endif</div></li>
</ol></p>
<p>And with that, rb-gsl is back, and jekyll is fast again with a fully up-to-date
system. (Well, almost, <a href="https://github.com/mojombo/jekyll/issues/988">kramdown 1.0 isn't
supported</a>.)</p>
kalu 2.0.1 to make sysupgrade work again2013-04-06T00:00:00+00:00http://jjacky.com/2013-04-06-kalu-2.0.1-to-make-sysupgrade-work-again<p>Ok, little screw up on my part in kalu 2.0.0, as I removed an init call
(<code>g_type_init()</code>) in <code>kalu-dbus</code> a little too soon. This call has actually only
be deprecated in GGlib 2.36 :)</p>
<p>My bad; Sorry about that.</p>
</p>
<p>Version 2.0.1 fixes this little issue (thanks to those who reported it), and
also includes a couple other (minor) fixes while at it.</p>
<h3>Downloads and whatnot</h3>
<p>Longer descriptions & all the links you should need can be <a href="/kalu" title="kalu: Keep Arch Linux Up-to-date">found here</a>.</p>
<p>And of course, as always, new bug reports, suggestions or any other form of
constructive criticism is very much welcome.</p>
kalu 2.0.0; pkgclip 1.2.0; pacdep 1.0.02013-04-05T00:00:00+00:00http://jjacky.com/2013-04-05-kalu-2.0.0-pkgclip-1.2.0-pacdep-1.0.0<p>pacman 4.1 has now hit core, so time for official updates of everything that
uses libalpm. For the most part this is only about being compatible with the new
API.</p>
</p>
<h3>kalu 2.0.0</h3>
<p>Changes since last version are :</p>
<ul>
<li><p>Major version bump for compatibility with API changes of pacman 4.1</p></li>
<li><p>Add menu "Show unread news" to help marking them read
Not so much to avoid running all checks (just re-show notifs) but for people who
do not have buttons shown on notifications.</p></li>
<li><p>Escape a few more characters for notifications (Fix #3)</p></li>
<li><p>Watched (AUR) window: add scrollbar to the list of watched packages</p></li>
<li><p>Parse UseDelta value in locale-independent way</p></li>
<li><p>Timeouts for checks are now calculated using real time (and not monotonic
time) to handled suspended system.</p></li>
</ul>
<h3>pkgclip 1.2.0</h3>
<p>Changes since last vesion are :</p>
<ul>
<li>Compatibility with API changes of pacman 4.1</li>
</ul>
<h3>pacdep 1.0.0</h3>
<p>Changes since last version are :</p>
<ul>
<li><p>Bumping to stable</p></li>
<li><p>Compatibility changes with pacman 4.1</p></li>
</ul>
<h3>Downloads and whatnot</h3>
<p>Thanks to all those who reported bugs or suggested features.</p>
<p>Longer descriptions & all the links you should need can be found here: <a href="/kalu" title="kalu: Keep Arch Linux Up-to-date">kalu</a>,
<a href="/pkgclip" title="PkgClip: Cached Packages Trimmer Utility">pkgclip</a> & <a href="/pacdep" title="pacdep: Easily list package dependencies">pacdep</a>.</p>
<p>And of course, as always, new bug reports, suggestions or any other form of
constructive criticism is very much welcome.</p>
Where does your window manager place new windows?2013-04-04T00:00:00+00:00http://jjacky.com/2013-04-04-where-does-your-window-manager-place-new-windows<p>I'm not even sure this falls under the "an itch to scratch" category, it wasn't
that much of an itch, but here we are.</p>
<p>Though I don't use the whole DE, I'm using lots of XFCE applications, such as
their window manager, <code>xfwm4</code> I really like it, but somewhat regularly I would
get a little annoyed by where it would place new windows.</p>
<p>Typical case would be this: I have an application (e.g. file manager) maximized,
then I have a gVim window on the left side (the window is about half my screen's
size, so I can have two side by side). Then I would open a new terminal; my
terminal window is 1/4th of the screen, so I could have 4 opened at the same
time.</p>
<p>Naturally, I would expect my terminal window to go on the top-right corner, but
it wouldn't go there. Instead, it was on the bottom-left one, i.e. on top of
gVim. Now this might not seem to make sense, but it does (of course) if you know
how xfwm4 actually works.</p>
</p>
<h3>How xfwm4 works</h3>
<p>It tries to find the best place, that is <strong>the one with less overlaps</strong>. It
calculates such overlap by taking into account all visible windows, with
importance that "visible" here doesn't mean that you can see it, but that it
isn't hidden (e.g. minimized).</p>
<p>That is to say, <strong>a window that you cannot see because another window is on top
of it will still count</strong>. In fact, in such a case and as far as xfwm4 goes, that
would make 2 overlaps. Back to my case, knowing that I happen to have 2
terminals opened already, on the top-right and bottom-right corners (both below
the maximized window), explains xfwm4's choice.</p>
<p>I know this, because <s>Tyler knows this</s> I looked into it, since for some
reason I decided to spend time on this, and see if I couldn't improve things a
bit (as far as my expectations for placement are, at least).</p>
<p>Since we're talking about how it works, for the curious let's go a bit more into
details: what it actually does is basically place the window on the top-left
corner, and calculate the overlaps. That is, how much of the window would
overlap with other windows, again taking into consideration all windows on that
area, even ones below other ones.</p>
<p>Once it's got the total overlapping area calculated, it moves the window by 8
pixels to the right, and calculates the overlaps. Repeat until you reached the
right side, then back on the left, but 8 pixels lower, and start again. Until
you've done the entire screen, and can figure out which position was the one
with the least overlaps.</p>
<p><u>Note: of course it doesn't place/move the window, this is just to explain which
calculations are done. Still, comments refer to this as "the good old CPU
consuming algorithm" ;-)</u></p>
<h3>Let's try to make xfwm4 smarter</h3>
<p>So since I like to procrastinate or something, I decided to change how xfwm4
would place new windows, and wrote a patch that will hopefully make it place the
window always where I'd expect it to.</p>
<p>So here's how things are now done :</p>
<ul>
<li><p>First, it considers the entire screen, i.e. the place where it can potientally
place the window (Note: this has already been limited to the current monitor,
and excluding any panels/docks, prior to our function being called).</p></li>
<li><p>Then, it will <strong>look at windows on the stack in reverse order</strong>. What this
means is: it will look at the last window to have been
drawn/focused/activated, i.e. the one on top of all the other ones. It gets
the area where that window is, and marks it as unusuable.</p></li>
<li><p>Moving on to the next window, i.e. the one right below it (Note that that
means on the stack, the window doesn't have to actually <u>be</u> below the other
one, it could simply be e.g. on the side); and do the same. Repeat this
operation until there's no more screen space available, then go back one
iteration.</p></li>
<li><p>It has now figured out the place where to put the window. Of course, it might
not be a rectangle space, it could be a bit more complicated than that. For
example, if that space comes from the maximized application you have below a
few other windows, there might be a few rectangles where to put the new
window.</p>
<p>Example: you have a maximized window in the back, and then two windows on top
of it. One in the top-middle of the screen, the other one on the
bottom-middle. Depending on a few factors, we could see this as 5 rectangles,
if we process things "horizontally" (on the left & right on the top window,
then the middle part, then on the left & right of the bottom window), or only
3 if we do things vertically (in "columns" and assuming our two windows are
the same size, and have the same X position). (In reality, it'll probably
depend on the order each window was processed.)</p>
<p>To handle this, each rectangle will be looked at, and every time xfwm4 will
try to expand it the most (trying horizontal expansion then vertical
expansion, then the other way around and keeping the largest one of the two).
Once such a rectangle has been determined, obviously ones where the window can
fit are favored.</p>
<p>In case we only have multiple rectangles where the window can't fit, the
largest one will be used. If we have more than one where it can fit, then the
<u>smallest</u> one will be used (to try to not waste space as much as possible).
And of course when the window didn't fit, it might move a little to make sure
it is fully within the screen.</p></li>
</ul>
<p>And... it works. :) At least for the few tries I've done with it, it works as
expected. And that makes much more sense to me: I'd rather see less of a window
I used some time ago than of the one I'm currently using, even if there are a
few other windows below that other window, and none below the one I'm using now.</p>
<p>To come back to my original example: Now when I open a new terminal, it doesn't
go over my gVim window but on the top-right corner, regardless of how many other
window might be stacked on that very spot. Exactly what I'd expect, so I like it.</p>
<p>To illustrate how it works, let's keep opening windows: if I open a new
terminal, it will naturally go in the bottom-left corner, the last I could see
of the maximized file manager.</p>
<p>Now I have gVim on the left side, and two terminals on the right side. And if I
open yet another terminal? It will go on top of gVim. It makes sense, since the
last two windows I used where the terminals (In other words: gVim is now the
oldest window I used (of the ones I can see)).</p>
<p>Now, what if before opening that new terminal, I had switched back to gVim? Well
then the new terminal would have gone over the terminal on the top-right corner.
Again, since gVim is the most recent used application, we shouln't put windows
on top of it (unless we can't avoid it), and that terminal had become the oldest
window used.</p>
<h3>2013-04-05 edit: snap to borders</h3>
<p>Little addendum: After using it a little more and trying out how it behaved in
different situations, I realized that there was a case where things could
possibly be improved a bit.</p>
<p>On occasions it might look like windows are snapped to the top and/or left
borders, but this is just a side-effect of placing the window on the top-left
corner of the selected rectangle.</p>
<p>It could also look like windows would be snapped on the bottom and/or right
borders, but only when the top-left corner would have had the window not fully
shown, and it was therefore moved just enough to be fully visible.</p>
<p>But why not actually try & snap to those borders? It usually feels like this
might be the natural/expected behavior. So I decided to add just that, but made
it dependant on an existing option : <code>snap_to_border</code> (You can find it under the
window manager's settings, tab Advanced: "Snap windows to screen border")</p>
<p>While it wasn't exactly intended for this, I feel it makes sense that
auto-placement of windows would follow this setting. (Also, I have one computer
where I don't want this behavior, so I needed a way to disable it; This was the
easiest.)</p>
<h3>The code</h3>
<p>This patch (alongside my old patch to have <a href="/2011-12-12-xfce-window-manager">hover effects for inactive windows
too</a>) can be found on
<a href="https://github.com/jjk-jacky/xfwm4-jjk" title="xfwm4-jjk @ GitHub">github</a> (in
separate branches). I've also <a href="https://bugzilla.xfce.org/show_bug.cgi?id=9976">submitted it
upstream</a> (even though there's
already been a few issue asking for change in the placement over the years),
feel free to comment there as well (or especially, if you do - or don't - want
it merged).</p>
Natural Sort Order in C2013-03-22T00:00:00+00:00http://jjacky.com/2013-03-22-natural-sort-order-in-c<p>As <a href="http://www.codinghorror.com/blog/2007/12/sorting-for-humans-natural-sort-order.html" title="Sorting for Humans : Natural Sort Order @ Coding Horror">Jeff Atwood said back in 2007</a>, "The default sort
functions in almost every programming language are poorly suited for human
consumption."</p>
<p>This was true then, and remains true today. Working on a project of mine, I
needed to sort strings, filenames to be precise, using the famous <strong>natural sort
order</strong>. Because that's how we expect things to work, "foo2" comes before
"foo15"</p>
<p>Unfortunately, it's not as simple as one might hope. Most sort functions are
indeed pretty bas at this, because while they might do a lot of great things,
when it comes to comparing strings containing numbers they still have no
understanding of natural order, and use what's referred to as "ASCII order".</p>
</p>
<p>After some research, knowing that I'm working in C and using GLib, here's what
I ended up with :</p>
<ul>
<li><p>Either you write your own comparison function,</p></li>
<li><p>Or you need to try and "workaround" the existing functions that are
locale-based (e.g. <strong>strcoll(3)</strong>).</p></li>
</ul>
<p>The former is the best option in terms of the control you'll have over things,
obviously, but it also needs the more work. And if implementing natural sort
order is easy enough, it gets a whole more complicated if you want to do
locale-based comparisons.</p>
<p>So the later option is usually taken, since most of the work (the locale-based
stuff) is done for you.</p>
<h3>GLib, collation keys, and natural order</h3>
<p>Using GLib, one can use <strong>g_utf8_collate_key()</strong> to get a collation key they
will take into account all that the current locale needs. So it works well when
it comes to handling characters with accents, or German's "ß" which should be
equivalent to a double "s" or something.</p>
<p>That's great, but unfortunately there are limitations :</p>
<ul>
<li><p><strong>you have no control over things</strong>. For instance, it will be case sensitive
or not, based on the locale. And there's no way to change it. (Well, one could
force a <strong>g_utf8_casefold()</strong> before, to force case insensitivity, but (1) as
the documentation says, "<strong>calling g_utf8_casefold() followed by
g_utf8_collate() is only an approximation to the correct linguistic case
insensitive ordering, though it is a fairly good one. Getting this exactly
right would require a more sophisticated collation function that takes case
sensitivity into account</strong>" and (2) this would only allow you to force case
insensitivity, but you'd still have no way to force case sensitivity.</p></li>
<li><p><strong>it doesn't do natural sort order</strong>, so "foo15" comes before "foo2" (even
though I'm guessing in all locales, people see 2 as being lower than 15).</p></li>
</ul>
<p>So you can try and work around it, as is done for instance in
<strong>g_utf8_collate_key_for_filename()</strong> which aims to do things such as add
natural sort order.</p>
<p>The way it does it that it will basically "split" the strings compared into
chunks, and use the usual <strong>g_utf8_collate_key()</strong> on each chunk individually.
This allows to split before a number, and make sure said numbers will be treated
so that 2 comes before 15.</p>
<p>It does get a natural order, but it has a cost: Anything that the locale-based
function would have done by treating the string as a whole is gone. As a simple
example, consider the following:</p>
<pre><code>Test1
tesT1
test1
tEst2
test2
test3
test15
test23
</code></pre>
<p>They are ordered as one would expect. But that's not what you would get with
<strong>g_utf8_collate_key_for_filename()</strong> (I'm assuming here that your locale makes
it be case insensitive) because due to its "splitting" of the string, the
comparison basically sees all those as the same string "test" and therefore
takes case sensitivity into account to perform the ordering, and that before
realizing that the string isn't over, and there are numbers that follow. So what
you get, is this odd order :</p>
<pre><code>Test1
tEst2
tesT1
test1
test2
test3
test15
test23
</code></pre>
<p>Yes, there's (some) natural order going on, but that's not exactly what would
be expected, is it?</p>
<p>Now as I said, we can also workaround this by calling <strong>g_utf8_casefold()</strong> ahead
of time, thus forcing case insensitivity. But then all the "test1" strings would
be considered absolutely the same, and their order would therefore be
unpredictable (i.e. based on the order strings are compared/were originally
ordered), which isn't necessarily ideal either.</p>
<h3>Natural order done manually</h3>
<p>Unless you're satisfied with the above, you'll now be looking back at option 1:
doing it yourself. Originally, I went with option 2 myself, simply writing my
own alternative to <strong>g_utf8_collate_key_for_filename()</strong> so that I could have
options to e.g. enable or not natural order.</p>
<p>But as described, this still isn't entirely satisfying, and eventually I looked
back at that former option.</p>
<p>Implementing a comparison function to handle (amongst other things) natural
order is relatively easy, since all you need to do is compare numbers as such,
instead of looking at their character value.</p>
<p>So I did create my own function, and it offers options for natural order, case
sensitivity, and a few things that might be useful when you deal with filenames
(e.g. putting dot files first, or mixed).</p>
<p>Because we don't actually "split" the strings in chunks, or because we do it
without losing focus the entire string as a whole, we can deal properly with
the case described above, where we don't see all those strings as "test" and a
number, but a few ones all being "test1" and only for those do we fall back on
case sensitivity, and so on.</p>
<p>And if you're dealing with basically English strings, as in mostly made of ASCII
characters, it looks perfect. Problems arise when you're in a different locale,
and you have things like accents to consider. I'd like to now talk about the
solution I found, only I did not found one.</p>
<p>This is quite a complicated thing: With the former option, we fall back on
<strong>g_utf8_collate_key()</strong> which itself just falls back on the good old
<strong>strxfrm()</strong> to handle this. It does the job well, but we can't sneak it to add
options, or natural order support.</p>
<p>And having to handle the whole locale-based thing on your own is just too much
for me I'm afraid. (Some kind of basic character replacement could be done, e.g.
replace all of "é", "ê", "ë", "è", and the others with "e" before comparing.
That might give better results for (most?) easy cases, but there will surely be
lots of cases where it just doesn't work, so it's really not a solution.)</p>
<h3>Conclusion?</h3>
<p>It's not as easy as it looks, and I don't have a solution, unfortunately. So
far here's what I'm gonna go with (for now?) : both options.</p>
<p>It helps that I did do both already, I guess, but I just don't see one as
clearly better than the other, it might just depend on what you need and which
files/strings you're dealing with.</p>
<p>Using the collate key functions from GLib will probably give results that are
pretty good most of the times, where using my own implementation of the natural
sort order might give better results unless you're using a locale that isn't
ASCII oriented, basically.</p>
<p>Anyways, that's what I gathered from my looking into this, hopefully this may
have been helpful to some of you.</p>
<h3>Natural Sorting utility</h3>
<p>In case you are yourself dealing with this, or looking for a solution, let me
share with you my implementation of the natural sort order. As I said, it's not
locale-based, but it does support natural order, if strings are otherwise equal,
it will use the number of leading zeros (strings with less come first, just like
shorter strings come first).</p>
<p>In the case of case-insensitive comparison, if strings are equals then the
result of case-sensitive comparison will be returned, to keep order predictable.</p>
<p>As I said, I'm mostly dealing with filenames myself, so there are also a couple
of options that probably don't make sense outside of this, e.g. having strings
starting with a dot listed first, or have them mixed together (instead of the
default, which would have them between strings starting with numbers and those
starting with (upper case) letters).</p>
<p>I'm not gonna bore you with the code here, it's on github as part of a little
utility: <strong><a href="/natsort" title="natsort: Natural Sorting utility">natsort</a></strong></p>
<p>It's a small CLI tool that will take strings from its standard input, sort them
based on specified options (if any), and print them on its standard output. (And
while I said I was working with GLib, this is actually not dependent on GLib.)</p>
<p>Have fun with all this, and if you do implement/have a better solution, as in
one that both does what natsort does, but also supports locale-based
comparisons, please let me know!</p>
strdup/free vs atomic reference counting2013-03-16T00:00:00+00:00http://jjacky.com/2013-03-16-strdup-free-vs-atomic-reference-counting<p>As I was working on a little C project of mine, I realized that often times I
would have functions returning strings, and couldn't simply return the pointer
directly (especially in mutli-threaded app) as the caller needs to be safe using
the string.</p>
<p>Typically, what is done is simply return a copy of the string, and the caller
must free it once it's done. But this would be happening a lot on my
application, and I wondered if it wouldn't be better to save those strdup/free
calls, using reference counting.</p>
<p>So I implemented that, and then recently found myself reading about this again,
where I'd find both that avoiding those malloc/memcpy calls by using reference
counting is good, or that atomic operations (which I used to implement reference
counting) could be slow and once shouldn't be afraid of using malloc/free.</p>
<p>And I started wondering...</p>
</p>
<p>Since I couldn't really find a definite answer, I went ahead and made a little
test app, to see the difference between those two methods. For those interested,
here are the results.</p>
<h3>Test application</h3>
<p>First, the code used for those little tests, compiled simply with:
gcc <code>pkg-config --cflags --libs glib-2.0</code> m.c</p>
<p><ol class="c"><li class="li1"><div class="de1"><span class="co2">#include <glib.h></span></div></li>
<li class="li1"><div class="de1"> </div></li>
<li class="li1"><div class="de1"><span class="co2">#define REFCOUNT 1</span></div></li>
<li class="li1"><div class="de1"><span class="co2">#define ATOMIC 1</span></div></li>
<li class="li1"><div class="de1"><span class="co2">#define NB_THREADS 5</span></div></li>
<li class="li1"><div class="de1"> </div></li>
<li class="li1"><div class="de1"><span class="co2">#if REFCOUNT</span></div></li>
<li class="li1"><div class="de1"><span class="kw4">typedef</span> <span class="kw4">struct</span></div></li>
<li class="li1"><div class="de1"><span class="br0">{</span></div></li>
<li class="li1"><div class="de1"> <span class="kw4">const</span> gchar <span class="sy0">*</span>str<span class="sy0">;</span></div></li>
<li class="li1"><div class="de1"> guint ref<span class="sy0">;</span></div></li>
<li class="li1"><div class="de1"><span class="co2">#if ATOMIC</span></div></li>
<li class="li1"><div class="de1"><span class="co2">#else</span></div></li>
<li class="li1"><div class="de1"> GMutex mutex<span class="sy0">;</span></div></li>
<li class="li1"><div class="de1"><span class="co2">#endif</span></div></li>
<li class="li1"><div class="de1"><span class="br0">}</span> ss_t<span class="sy0">;</span></div></li>
<li class="li1"><div class="de1"> </div></li>
<li class="li1"><div class="de1"><span class="kw4">static</span> ss_t <span class="sy0">*</span></div></li>
<li class="li1"><div class="de1">ref <span class="br0">(</span>ss_t <span class="sy0">*</span>ss<span class="br0">)</span></div></li>
<li class="li1"><div class="de1"><span class="br0">{</span></div></li>
<li class="li1"><div class="de1"><span class="co2">#if ATOMIC</span></div></li>
<li class="li1"><div class="de1"> g_atomic_int_inc <span class="br0">(</span><span class="sy0">&</span>ss<span class="sy0">-></span>ref<span class="br0">)</span><span class="sy0">;</span></div></li>
<li class="li1"><div class="de1"><span class="co2">#else</span></div></li>
<li class="li1"><div class="de1"> g_mutex_lock <span class="br0">(</span><span class="sy0">&</span>ss<span class="sy0">-></span>mutex<span class="br0">)</span><span class="sy0">;</span></div></li>
<li class="li1"><div class="de1"> <span class="sy0">++</span>ss<span class="sy0">-></span>ref<span class="sy0">;</span></div></li>
<li class="li1"><div class="de1"> g_mutex_unlock <span class="br0">(</span><span class="sy0">&</span>ss<span class="sy0">-></span>mutex<span class="br0">)</span><span class="sy0">;</span></div></li>
<li class="li1"><div class="de1"><span class="co2">#endif</span></div></li>
<li class="li1"><div class="de1"> <span class="kw1">return</span> ss<span class="sy0">;</span></div></li>
<li class="li1"><div class="de1"><span class="br0">}</span></div></li>
<li class="li1"><div class="de1"> </div></li>
<li class="li1"><div class="de1"><span class="kw4">static</span> <span class="kw4">void</span></div></li>
<li class="li1"><div class="de1">unref <span class="br0">(</span>ss_t <span class="sy0">*</span>ss<span class="br0">)</span></div></li>
<li class="li1"><div class="de1"><span class="br0">{</span></div></li>
<li class="li1"><div class="de1"><span class="co2">#if ATOMIC</span></div></li>
<li class="li1"><div class="de1"> <span class="kw1">if</span> <span class="br0">(</span>g_atomic_int_dec_and_test <span class="br0">(</span><span class="sy0">&</span>ss<span class="sy0">-></span>ref<span class="br0">)</span><span class="br0">)</span></div></li>
<li class="li1"><div class="de1"> g_free <span class="br0">(</span>ss<span class="br0">)</span><span class="sy0">;</span></div></li>
<li class="li1"><div class="de1"><span class="co2">#else</span></div></li>
<li class="li1"><div class="de1"> g_mutex_lock <span class="br0">(</span><span class="sy0">&</span>ss<span class="sy0">-></span>mutex<span class="br0">)</span><span class="sy0">;</span></div></li>
<li class="li1"><div class="de1"> <span class="kw1">if</span> <span class="br0">(</span><span class="sy0">--</span>ss<span class="sy0">-></span>ref <span class="sy0">==</span> <span class="nu0">0</span><span class="br0">)</span></div></li>
<li class="li1"><div class="de1"> <span class="br0">{</span></div></li>
<li class="li1"><div class="de1"> g_mutex_clear <span class="br0">(</span><span class="sy0">&</span>ss<span class="sy0">-></span>mutex<span class="br0">)</span><span class="sy0">;</span></div></li>
<li class="li1"><div class="de1"> g_free <span class="br0">(</span>ss<span class="br0">)</span><span class="sy0">;</span></div></li>
<li class="li1"><div class="de1"> <span class="br0">}</span></div></li>
<li class="li1"><div class="de1"> <span class="kw1">else</span></div></li>
<li class="li1"><div class="de1"> g_mutex_unlock <span class="br0">(</span><span class="sy0">&</span>ss<span class="sy0">-></span>mutex<span class="br0">)</span><span class="sy0">;</span></div></li>
<li class="li1"><div class="de1"><span class="co2">#endif</span></div></li>
<li class="li1"><div class="de1"><span class="br0">}</span></div></li>
<li class="li1"><div class="de1"> </div></li>
<li class="li1"><div class="de1"><span class="kw4">static</span> ss_t <span class="sy0">*</span>str<span class="sy0">;</span></div></li>
<li class="li1"><div class="de1"><span class="kw4">static</span> ss_t <span class="sy0">*</span></div></li>
<li class="li1"><div class="de1">get_string <span class="br0">(</span><span class="kw4">void</span><span class="br0">)</span></div></li>
<li class="li1"><div class="de1"><span class="br0">{</span></div></li>
<li class="li1"><div class="de1"> <span class="kw1">return</span> ref <span class="br0">(</span>str<span class="br0">)</span><span class="sy0">;</span></div></li>
<li class="li1"><div class="de1"><span class="br0">}</span></div></li>
<li class="li1"><div class="de1"><span class="co2">#else</span></div></li>
<li class="li1"><div class="de1"><span class="kw4">static</span> <span class="kw4">const</span> gchar <span class="sy0">*</span>str <span class="sy0">=</span> <span class="st0">"foobar"</span><span class="sy0">;</span></div></li>
<li class="li1"><div class="de1"><span class="kw4">static</span> gchar <span class="sy0">*</span></div></li>
<li class="li1"><div class="de1">get_string <span class="br0">(</span><span class="kw4">void</span><span class="br0">)</span></div></li>
<li class="li1"><div class="de1"><span class="br0">{</span></div></li>
<li class="li1"><div class="de1"> <span class="kw1">return</span> g_strdup <span class="br0">(</span>str<span class="br0">)</span><span class="sy0">;</span></div></li>
<li class="li1"><div class="de1"><span class="br0">}</span></div></li>
<li class="li1"><div class="de1"><span class="co2">#endif</span></div></li>
<li class="li1"><div class="de1"> </div></li>
<li class="li1"><div class="de1"><span class="kw4">static</span> <span class="kw4">void</span></div></li>
<li class="li1"><div class="de1">worker <span class="br0">(</span><span class="kw4">void</span><span class="br0">)</span></div></li>
<li class="li1"><div class="de1"><span class="br0">{</span></div></li>
<li class="li1"><div class="de1"> <span class="kw4">int</span> i<span class="sy0">;</span></div></li>
<li class="li1"><div class="de1"><span class="co2">#if REFCOUNT</span></div></li>
<li class="li1"><div class="de1"> ss_t <span class="sy0">*</span>s<span class="sy0">;</span></div></li>
<li class="li1"><div class="de1"><span class="co2">#else</span></div></li>
<li class="li1"><div class="de1"> gchar <span class="sy0">*</span>s<span class="sy0">;</span></div></li>
<li class="li1"><div class="de1"><span class="co2">#endif</span></div></li>
<li class="li1"><div class="de1"> </div></li>
<li class="li1"><div class="de1"> <span class="kw1">for</span> <span class="br0">(</span>i <span class="sy0">=</span> <span class="nu0">0</span><span class="sy0">;</span> i <span class="sy0"><</span> <span class="nu0">100000</span><span class="sy0">;</span> <span class="sy0">++</span>i<span class="br0">)</span></div></li>
<li class="li1"><div class="de1"> <span class="br0">{</span></div></li>
<li class="li1"><div class="de1"> s <span class="sy0">=</span> get_string <span class="br0">(</span><span class="br0">)</span><span class="sy0">;</span></div></li>
<li class="li1"><div class="de1"><span class="co2">#if REFCOUNT</span></div></li>
<li class="li1"><div class="de1"> unref <span class="br0">(</span>s<span class="br0">)</span><span class="sy0">;</span></div></li>
<li class="li1"><div class="de1"><span class="co2">#else</span></div></li>
<li class="li1"><div class="de1"> g_free <span class="br0">(</span>s<span class="br0">)</span><span class="sy0">;</span></div></li>
<li class="li1"><div class="de1"><span class="co2">#endif</span></div></li>
<li class="li1"><div class="de1"> <span class="br0">}</span></div></li>
<li class="li1"><div class="de1"><span class="br0">}</span></div></li>
<li class="li1"><div class="de1"> </div></li>
<li class="li1"><div class="de1"><span class="kw4">int</span></div></li>
<li class="li1"><div class="de1">main <span class="br0">(</span><span class="kw4">void</span><span class="br0">)</span></div></li>
<li class="li1"><div class="de1"><span class="br0">{</span></div></li>
<li class="li1"><div class="de1"> <span class="kw4">int</span> i<span class="sy0">;</span></div></li>
<li class="li1"><div class="de1"> GThread <span class="sy0">*</span>thread<span class="br0">[</span>NB_THREADS<span class="br0">]</span><span class="sy0">;</span></div></li>
<li class="li1"><div class="de1"> </div></li>
<li class="li1"><div class="de1"><span class="co2">#if REFCOUNT</span></div></li>
<li class="li1"><div class="de1"> str <span class="sy0">=</span> g_new <span class="br0">(</span>ss_t<span class="sy0">,</span> <span class="nu0">1</span><span class="br0">)</span><span class="sy0">;</span></div></li>
<li class="li1"><div class="de1"> str<span class="sy0">-></span>str <span class="sy0">=</span> <span class="st0">"foobar"</span><span class="sy0">;</span></div></li>
<li class="li1"><div class="de1"> str<span class="sy0">-></span>ref <span class="sy0">=</span> <span class="nu0">1</span><span class="sy0">;</span></div></li>
<li class="li1"><div class="de1"><span class="co2">#if ATOMIC</span></div></li>
<li class="li1"><div class="de1"><span class="co2">#else</span></div></li>
<li class="li1"><div class="de1"> g_mutex_init <span class="br0">(</span><span class="sy0">&</span>str<span class="sy0">-></span>mutex<span class="br0">)</span><span class="sy0">;</span></div></li>
<li class="li1"><div class="de1"><span class="co2">#endif</span></div></li>
<li class="li1"><div class="de1"><span class="co2">#endif</span></div></li>
<li class="li1"><div class="de1"> </div></li>
<li class="li1"><div class="de1"> <span class="kw1">for</span> <span class="br0">(</span>i <span class="sy0">=</span> <span class="nu0">0</span><span class="sy0">;</span> i <span class="sy0"><</span> NB_THREADS<span class="sy0">;</span> <span class="sy0">++</span>i<span class="br0">)</span></div></li>
<li class="li1"><div class="de1"> thread<span class="br0">[</span>i<span class="br0">]</span> <span class="sy0">=</span> g_thread_new <span class="br0">(</span><span class="st0">"worker"</span><span class="sy0">,</span> <span class="br0">(</span>GThreadFunc<span class="br0">)</span> worker<span class="sy0">,</span> NULL<span class="br0">)</span><span class="sy0">;</span></div></li>
<li class="li1"><div class="de1"> </div></li>
<li class="li1"><div class="de1"> <span class="kw1">for</span> <span class="br0">(</span>i <span class="sy0">=</span> <span class="nu0">0</span><span class="sy0">;</span> i <span class="sy0"><</span> NB_THREADS<span class="sy0">;</span> <span class="sy0">++</span>i<span class="br0">)</span></div></li>
<li class="li1"><div class="de1"> g_thread_join <span class="br0">(</span>thread<span class="br0">[</span>i<span class="br0">]</span><span class="br0">)</span><span class="sy0">;</span></div></li>
<li class="li1"><div class="de1"> </div></li>
<li class="li1"><div class="de1"><span class="co2">#if REFCOUNT</span></div></li>
<li class="li1"><div class="de1"> unref <span class="br0">(</span>str<span class="br0">)</span><span class="sy0">;</span></div></li>
<li class="li1"><div class="de1"><span class="co2">#endif</span></div></li>
<li class="li1"><div class="de1"> </div></li>
<li class="li1"><div class="de1"> <span class="kw1">return</span> <span class="nu0">0</span><span class="sy0">;</span></div></li>
<li class="li1"><div class="de1"><span class="br0">}</span></div></li>
</ol></p>
<h3>Results</h3>
<p>First I ran those with 8 threads :</p>
<h4>Reference counting, using mutex</h4>
<p>Binary was 8,652 bytes; Average time: <strong>0.442</strong></p>
<pre><code>==17320== HEAP SUMMARY:
==17320== in use at exit: 5,476 bytes in 12 blocks
==17320== total heap usage: 38 allocs, 26 frees, 8,092 bytes allocated
==17320==
==17320== LEAK SUMMARY:
==17320== definitely lost: 0 bytes in 0 blocks
==17320== indirectly lost: 0 bytes in 0 blocks
==17320== possibly lost: 2,016 bytes in 2 blocks
==17320== still reachable: 3,460 bytes in 10 blocks
==17320== suppressed: 0 bytes in 0 blocks
./a.out 1.32s user 0.47s system 345% cpu 0.520 total
./a.out 1.29s user 0.37s system 335% cpu 0.495 total
./a.out 1.35s user 0.40s system 334% cpu 0.524 total
./a.out 1.11s user 0.38s system 334% cpu 0.444 total
./a.out 1.37s user 0.53s system 357% cpu 0.531 total
</code></pre>
<h4>Reference counting, atomic operations</h4>
<p>Binary was 8,053 bytes; Average time: <strong>0.199</strong></p>
<pre><code>==17441== HEAP SUMMARY:
==17441== in use at exit: 5,476 bytes in 12 blocks
==17441== total heap usage: 37 allocs, 25 frees, 8,044 bytes allocated
==17441==
==17441== LEAK SUMMARY:
==17441== definitely lost: 0 bytes in 0 blocks
==17441== indirectly lost: 0 bytes in 0 blocks
==17441== possibly lost: 2,016 bytes in 2 blocks
==17441== still reachable: 3,460 bytes in 10 blocks
==17441== suppressed: 0 bytes in 0 blocks
./a.out 0.76s user 0.00s system 357% cpu 0.214 total
./a.out 0.65s user 0.00s system 356% cpu 0.183 total
./a.out 0.83s user 0.00s system 372% cpu 0.225 total
./a.out 0.72s user 0.00s system 365% cpu 0.197 total
./a.out 0.61s user 0.00s system 349% cpu 0.175 total
</code></pre>
<h4>Duplicate strings</h4>
<p>Binary was 7,761 bytes; Average time: <strong>0.039</strong></p>
<pre><code>==17601== HEAP SUMMARY:
==17601== in use at exit: 5,476 bytes in 12 blocks
==17601== total heap usage: 800,036 allocs, 800,024 frees, 5,608,028 bytes allocated
==17601==
==17601== LEAK SUMMARY:
==17601== definitely lost: 0 bytes in 0 blocks
==17601== indirectly lost: 0 bytes in 0 blocks
==17601== possibly lost: 2,016 bytes in 2 blocks
==17601== still reachable: 3,460 bytes in 10 blocks
==17601== suppressed: 0 bytes in 0 blocks
./a.out 0.10s user 0.00s system 292% cpu 0.035 total
./a.out 0.11s user 0.00s system 252% cpu 0.042 total
./a.out 0.10s user 0.01s system 269% cpu 0.040 total
./a.out 0.10s user 0.01s system 273% cpu 0.039 total
./a.out 0.10s user 0.00s system 273% cpu 0.038 total
</code></pre>
<p>After looking at these results, I worried that implementing reference counting
might have done more bad than good in the end, slowing things here by a factor
of 5. Of course, this is a pretty extreme case (8 threads all doing 100,000
operations). And let's not forget the difference in memory usage, either.</p>
<h3>Down to 5 threads</h3>
<h4>Atomic reference counting</h4>
<p>Average time: <strong>0.117</strong></p>
<pre><code>==19689== HEAP SUMMARY:
==19689== in use at exit: 5,476 bytes in 12 blocks
==19689== total heap usage: 28 allocs, 16 frees, 7,087 bytes allocated
==19689==
==19689== LEAK SUMMARY:
==19689== definitely lost: 0 bytes in 0 blocks
==19689== indirectly lost: 0 bytes in 0 blocks
==19689== possibly lost: 2,016 bytes in 2 blocks
==19689== still reachable: 3,460 bytes in 10 blocks
==19689== suppressed: 0 bytes in 0 blocks
./a.out 0.43s user 0.00s system 355% cpu 0.122 total
./a.out 0.40s user 0.00s system 346% cpu 0.117 total
./a.out 0.38s user 0.00s system 350% cpu 0.110 total
./a.out 0.37s user 0.00s system 338% cpu 0.108 total
./a.out 0.45s user 0.00s system 350% cpu 0.127 total
</code></pre>
<h4>Duplicating strings</h4>
<p>Average time: <strong>0.028</strong></p>
<pre><code>==19584== HEAP SUMMARY:
==19584== in use at exit: 5,476 bytes in 12 blocks
==19584== total heap usage: 500,027 allocs, 500,015 frees, 3,507,071 bytes allocated
==19584==
==19584== LEAK SUMMARY:
==19584== definitely lost: 0 bytes in 0 blocks
==19584== indirectly lost: 0 bytes in 0 blocks
==19584== possibly lost: 2,016 bytes in 2 blocks
==19584== still reachable: 3,460 bytes in 10 blocks
==19584== suppressed: 0 bytes in 0 blocks
./a.out 0.07s user 0.00s system 253% cpu 0.026 total
./a.out 0.06s user 0.01s system 239% cpu 0.028 total
./a.out 0.06s user 0.00s system 250% cpu 0.027 total
./a.out 0.07s user 0.00s system 222% cpu 0.030 total
./a.out 0.07s user 0.00s system 214% cpu 0.031 total
</code></pre>
<p>Atomic operations are still slower, but only by a factor or 4.</p>
<h3>Down to 2 threads</h3>
<p>Things change quite a bit with only two threads, where - apart for memory usage
obviously - results were pretty much the same :</p>
<h4>Reference counting (atomic)</h4>
<p>Average time: <strong>0.018</strong></p>
<pre><code>==19473== HEAP SUMMARY:
==19473== in use at exit: 5,476 bytes in 12 blocks
==19473== total heap usage: 19 allocs, 7 frees, 6,130 bytes allocated
==19473==
==19473== LEAK SUMMARY:
==19473== definitely lost: 0 bytes in 0 blocks
==19473== indirectly lost: 0 bytes in 0 blocks
==19473== possibly lost: 2,016 bytes in 2 blocks
==19473== still reachable: 3,460 bytes in 10 blocks
==19473== suppressed: 0 bytes in 0 blocks
./a.out 0.02s user 0.00s system 149% cpu 0.016 total
./a.out 0.02s user 0.00s system 137% cpu 0.017 total
./a.out 0.03s user 0.00s system 170% cpu 0.018 total
./a.out 0.03s user 0.00s system 168% cpu 0.018 total
./a.out 0.04s user 0.00s system 162% cpu 0.022 total
</code></pre>
<h4>Duplicating strings</h4>
<p>Average time: <strong>0.017</strong></p>
<pre><code>==19381== HEAP SUMMARY:
==19381== in use at exit: 5,476 bytes in 12 blocks
==19381== total heap usage: 200,018 allocs, 200,006 frees, 1,406,114 bytes allocated
==19381==
==19381== LEAK SUMMARY:
==19381== definitely lost: 0 bytes in 0 blocks
==19381== indirectly lost: 0 bytes in 0 blocks
==19381== possibly lost: 2,016 bytes in 2 blocks
==19381== still reachable: 3,460 bytes in 10 blocks
==19381== suppressed: 0 bytes in 0 blocks
./a.out 0.03s user 0.00s system 171% cpu 0.016 total
./a.out 0.03s user 0.00s system 160% cpu 0.017 total
./a.out 0.03s user 0.00s system 164% cpu 0.016 total
./a.out 0.03s user 0.00s system 156% cpu 0.019 total
./a.out 0.03s user 0.00s system 145% cpu 0.018 total
</code></pre>
<p>Reference counting might not be a bad thing after all. Yes, atomic operations
might be "slow"/slower, but it remains pretty fast, is definitely better as far
as memory usage goes, and will probably only slow things down in extreme cases,
if at all.</p>
<p>As a last try, I ran those tests again but having each of the 8 threads only do
1,000 operations, instead of the 100,000 they did so far. In this case, again
except for memory usage of course, the results are pretty much exactly the same,
averaging at 0.003 both when duplicating strings, or using atomic reference
counting.</p>
<h4>Atomic reference counting</h4>
<pre><code>==20666== HEAP SUMMARY:
==20666== in use at exit: 5,476 bytes in 12 blocks
==20666== total heap usage: 37 allocs, 25 frees, 8,044 bytes allocated
==20666==
==20666== LEAK SUMMARY:
==20666== definitely lost: 0 bytes in 0 blocks
==20666== indirectly lost: 0 bytes in 0 blocks
==20666== possibly lost: 2,016 bytes in 2 blocks
==20666== still reachable: 3,460 bytes in 10 blocks
==20666== suppressed: 0 bytes in 0 blocks
./a.out 0.00s user 0.00s system 79% cpu 0.004 total
./a.out 0.00s user 0.00s system 0% cpu 0.002 total
./a.out 0.00s user 0.00s system 0% cpu 0.002 total
./a.out 0.00s user 0.00s system 0% cpu 0.002 total
./a.out 0.00s user 0.00s system 69% cpu 0.005 total
</code></pre>
<h4>Duplicating strings</h4>
<pre><code>==20634== HEAP SUMMARY:
==20634== in use at exit: 5,476 bytes in 12 blocks
==20634== total heap usage: 8,036 allocs, 8,024 frees, 64,028 bytes allocated
==20634==
==20634== LEAK SUMMARY:
==20634== definitely lost: 0 bytes in 0 blocks
==20634== indirectly lost: 0 bytes in 0 blocks
==20634== possibly lost: 2,016 bytes in 2 blocks
==20634== still reachable: 3,460 bytes in 10 blocks
==20634== suppressed: 0 bytes in 0 blocks
./a.out 0.00s user 0.00s system 0% cpu 0.003 total
./a.out 0.00s user 0.00s system 0% cpu 0.003 total
./a.out 0.00s user 0.00s system 0% cpu 0.002 total
./a.out 0.00s user 0.00s system 0% cpu 0.003 total
./a.out 0.00s user 0.00s system 0% cpu 0.003 total
</code></pre>
<p>So in the end, I'm gonna stick with atomic reference counting in my app, it
should not, or barely, have any impact on speed, but will definitely help as far
as memory usage goes.</p>
Wanna try pacman 4.1 (and still use kalu) ?2013-03-11T00:00:00+00:00http://jjacky.com/2013-03-11-wanna-try-pacman-4.1-and-still-use-kalu<p>As you've probably heard, the next version of pacman is coming, and <a href="http://allanmcrae.com/2013/03/pacman-4-1-0rc1/" title="Pacman 4.1.0rc1 @ Allan McRae">you can try
the first RC</a>.</p>
<p>Because API changes are introduced, whatever uses libalpm will require not only
to be rebuild against the new library, but is likely to need code adjustements
as well.</p>
<p>This was obviously the case for kalu, and everything should be done & ready.
I've been using it for a little while now, and now that rc1 is out I've pushed
it (in the <code>next</code> branch) on
<a href="https://github.com/jjk-jacky/kalu/tree/next" title="kalu [next] @ Github">github</a>, so
you can test the next pacman while still enjoying kalu.</p>
</p>
<p>All you need is to build kalu using the <code>next</code> branch from github, which as
always you can do using <a href="https://github.com/jjk-jacky/abs/blob/master/kalu-git/PKGBUILD">PKGBUILD like this
one</a>, which has
been modified to include a dependency on pacman 4.1.</p>
<p>There shouldn't really be anything noticable from using kalu, as changes were
mostly behind-the-scenes stuff. The only real change you might see in kalu is a
new step during an upgrade: "Checking keyring"</p>
<p>If you notice any problems/bugs (related or not to API changes), let me know.</p>
kalu goes 1.4.0, speaks French2013-01-22T00:00:00+00:00http://jjacky.com/2013-01-22-kalu-goes-1.4.0-speaks-french<p>It's been a little while since a new version of kalu - <a href="/kalu" title="kalu: Keep Arch Linux Up-to-date">upgrade notifier for
Arch Linux</a> - has been released. But version 1.4.0 is here, and with it
comes a bunch a bugfixes, as well as a couple of new features.</p>
</p>
<h3>Put kalu on pause</h3>
<p>Pretty much since forever, you could set in kalu a "skip period," i.e. a period
of time during which kalu would not run its automatic tests. Especially useful
for people keeping their computer on 24/7 yet having to sleep regularly.</p>
<p>From now on kalu introduces a pause feature, allowing you to basically do the
same, but whenever you want: you can pause kalu.</p>
<p>The "skip period" (or "paused period") defined in Preferences now simply
switches kalu's paused state. Upon start, kalu checks whether we're during the
skip period or not, and simply either auto-pauses or auto-resumes (i.e. triggers
auto-checks).</p>
<p>When kalu is paused, its icon will give a visual feedback, automatic checks will
not be ran anymore until it is resumed, either manually or through this "skip
period" (or "paused period").</p>
<p>Additionally, you can now define a different set of actions to be done
(including toggling its paused stated) on single/double-click on kalu's icon,
depending on whether it is paused or not.</p>
<h3>kalu can speak your language; knows French</h3>
<p>As announced <a href="/2012-12-08-kalu-could-speak-your-language" title="kalu could speak your language! @ jjacky.com">a little while ago</a>, kalu can now talk different
languages, all it needs is a translation.</p>
<p>And version 1.4.0 of kalu is already available in French, thanks to kolibry.
And if you want to translate it to your own language, just refer to the post
above for the how-to and send me the .po file!</p>
<h3>What's else is new?</h3>
<ul>
<li><p>Preferences: Fix double click action empty on re-show last notifications</p>
<p>When action show last notifs was used on dbl-click, showing preferences
would not select it in the list, and could therefore have it lost upon
saving.</p></li>
<li><p>Add config tweak to not show notifications on auto-checks</p>
<p>Adding <code>AutoNotifs = 0</code> to <code>kalu.conf</code> will disable showing notifications
during automatic checks. They can be shown using "re-show last
notifications" as usual. (Notifications will still be shown for manual
checks.)</p></li>
<li><p>AUR: Fix package names not being urlencoded</p>
<p>Package names were used as-is in the URLs for the AUR, which could lead to
unexpected results (likely segfault) when said names contained "special"
characters, e.g. the plus sign.</p></li>
<li><p>AUR: Avoid segfault in case of unexpected results</p>
<p>If a package returned by the AUR wasn't on the list asked for (which could
happen when names weren't urlencoded, and both foo and foo+ were packages
existing in the AUR) kalu would segfault.</p>
<p>We now ensure the package was found, and if not trigger an error.</p></li>
<li><p>AUR: Fix possible memory leak on invalid JSON</p></li>
<li><p>kalu-updater: Fix question to skip package not being asked</p>
<p>Question to skip upgrading a package when dependencies cannot be resolved
was not asked, leading to kalu (and kalu-dbus) hanging, needing to be
killed.</p></li>
<li><p>Fix empty notifications when '&' was used in text</p>
<p>Seems that because it uses a subset of HTML, the text in notifications
should not use '&' directly, but encode it as &amp; (else, the text of
notification is just empty, at least with notification-daemon and
xfce4-notifyd)</p>
<p>So, when creating new notifications, we make sure to "convert" those '&'
since there can be some in e.g. a package description, which could be used
as part of the template (text is untouched on CLI output).</p></li>
<li><p>Fix hanging on error parsing config</p>
<p>When error occured parsing configuration, since 13c4ffb4 GTK init wasn't yet
done, error messages couldn't be shown and kalu would just hang.</p></li>
<li><p>Fix <code>Makefile.am</code> to handle spaces (in {dist,install-data}-hook)</p></li>
<li><p>Help: Add info about conf files structure, and a section about config tweaks</p>
<p>Describe the format of the different conf files used by kalu, as well as the
name and supported values of each settings.</p></li>
<li><p>kalu will now use the installed kalu.png file as its logo. It'll be used
about everywhere (systray, windows, menus...)</p></li>
</ul>
<h3>Download and whatnot</h3>
<p>You'll find all download links and information <a href="/kalu" title="kalu: Keep Arch Linux Up-to-date">right there</a>.</p>
<p>Many thanks to all those who contributed/reported bugs or suggested features.
And as always, new bug reports, suggestions or any other form of constructive
criticism is very much welcome.</p>
dapper 1.0.0 released2013-01-19T00:00:00+00:00http://jjacky.com/2013-01-19-dapper-1.0.0-released<p>Version 1.0.0 of dapper - a simple <a href="/dapper" title="dapper, a desktop applications autostarter">desktop applications autostarter</a> -
has been released. In addition to the bump to 1.0.0 as per semantic version
rules, this release is mostly about bugfixes.</p>
</p>
<p>Changes since last version are :</p>
<ul>
<li><p>Add support of ~ (replaced by <code>$HOME</code>) in <code>Exec</code> and <code>TryExec</code></p></li>
<li><p>Quoting arguments can now be done using single quote as well</p></li>
<li><p>Fix segfault in failed parsing when <code>.desktop</code> file did not have the "Desktop
Entry" section</p></li>
</ul>
<h3>Downloads and whatnot</h3>
<p>You'll find all download links and information <a href="/dapper" title="dapper, a desktop applications autostarter">right here</a>.</p>
kalu could speak your language!2012-12-08T00:00:00+00:00http://jjacky.com/2012-12-08-kalu-could-speak-your-language<p>The next version of kalu - <a href="/kalu" title="kalu: Keep Arch Linux Up-to-date">upgrade notifier for Arch Linux</a> - is almost
ready, and one of the changes it will introduce, is support for
internationalization.</p>
</p>
<h3>In other words, kalu is ready to speak your language!</h3>
<p>Source code has been (reorganized and) modified to use
<a href="http://www.gnu.org/software/gettext/manual/gettext.html" title="GNU gettext Manual">gettext</a>, it's ready, all it needs now to speak other languages,
are translations.</p>
<p>So, if you like kalu but would like it better if it spoke your language, please
consider translating it.</p>
<h3>Create a translation</h3>
<p>If you want to translate kalu and are alredy familiar with the whole gettext
process, you probably know better than I do what to do.</p>
<p>If not, here's a little guide that should allow anyone to make a translation :</p>
<p>First, clone the git repo (brach next) and prepare things :</p>
<pre><code>git clone https://github.com/jjk-jacky/kalu.git -b next
cd kalu
./autogen.sh
./configure
cd po
make kalu.pot
</code></pre>
<p>Then create a new PO file for your locale using msginit : <code>msginit</code></p>
<p>If you want to create a translation for another locale than your current one,
you'll simply have to use option <code>-l</code>, e.g. for French (fr) : <code>msginit -l fr</code></p>
<p>Edit the generated .po file (using your editor of choice), translating each
msgid in the corresponding msgstr. (Also make sure to check the comments on top,
including your name, email, etc. It's also recommended to use UTF-8 as charset.)</p>
<p>Edit <code>LINGUAS</code> and add the language code (name of the .po file, without .po) on
a new line.</p>
<p>To test your translation, first make the .gmo file for your translation, e.g:
<code>make fr.gmo</code></p>
<p>Then you'll have to build & install kalu, as usual. You can create yourself a
PKGBUILD to do so, see <a href="https://github.com/jjk-jacky/abs/blob/master/kalu-git/PKGBUILD" title="PKGBUILD for kalu-git">this
one</a> as example, and simply update the <code>_gitroot</code> variable
to point to your local clone. (Make sure to have committed your changes to
<code>LINGUAS</code> and your new .po file.)</p>
<p>Just start kalu, and it should speak your language. Note that if writing a
translation for a locale other than your current one, you'll have to specify it
on launch, e.g: <code>LANG=fr_FR.utf8 kalu</code> (Also note that you might have to
re-generate your locales to include it.)</p>
<p>When you're satisfied with the translation, simply send it over to have it
included in the next release. You can :</p>
<ul>
<li>Fork kalu of github and send a pull request; Or</li>
<li>Host the .po file somewhere and open an issue with a link; Or</li>
<li>Send me the file via email</li>
</ul>
Easily list package dependencies2012-11-04T00:00:00+00:00http://jjacky.com/2012-11-04-easily-list-package-dependencies<p>Sometimes I wonder about a package and its dependencies, and more specifically
the (installed) size of it all. For a simple list of a package's dependencies,
<code>pactree</code> is a great tool that does the job fine.</p>
<p>But when I'm wondering about the size, something else is needed. In fact, quite
a few times I've found myself doing a <code>pacman -S/-Rs package</code> in order to know
either how much size a package (and its "exclusive" (as in not needd by any
other packages) dependencies) are eating up, or how much would be needed to
install them.</p>
<p>This isn't, however, an ideal solution, obviously. It does require root
privileges, even though I don' go through with the transaction, and adds useless
entry in pacman.log</p>
<p>So I started thinking about it a bit, fast-forward a little and here comes
<strong>pacdep</strong></p>
</p>
<h3>pacdep: Package Dependencies listing</h3>
<p>pacdep is a little tool that will show the installed size of the package, its
exclusive dependencies, and its shared dependencies; Optional dependencies can
be shown as well.</p>
<p>By default pacdep searches the local database first, and if not found searches
all sync databases, making it easy to use with packages installed or not all the
same. Of course, there's an option to use sync databases only, should you need
that.</p>
<p>Package names are prefixed by the repository name they were found in when
they're not from the local database.</p>
<p>As hinted, pacdep creates groups of dependencies: exclusive ones, shared ones,
and (optionally) optional ones. By default, only the total size of each group
will be shown, but of course you can have packages of any of those groups be
listed.</p>
<h4>Package size</h4>
<p>After the package's installed size, in parenthesis will be the installed size of
the package and its exclusive (and optional, if <code>--show-optional</code> was used)
dependencies.</p>
<p>If the package is from local database (i.e. is installed), only dependencies
from local database are taken into account. If it is from a sync database (i.e.
is not installed), only dependencies from sync databases are taken into account.</p>
<p>In other words, this size represents either the size the package and its
dependencies are using on the system (size that could potentially be freed if
removing the package and its dependencies), or the size needed to install them.</p>
<h3>Reverse Mode</h3>
<p>When option <code>--reverse</code> is used, instead of listing the dependencies of the
specified packages, pacdep will list packages that require them (i.e. the
dependency tree is browsed <u>in reverse</u>).</p>
<p>By default only immediate "requirers" are listed, i.e. packages that have one of
the specified packages as dependency.</p>
<p>Specifying the option a second time will go through the entire dependency tree,
until a package that isn't required is found. All packages met will be listed.</p>
<p>Specifying the option a third time will go through the dependency tree all the
same, but only the end packages (that aren't required) will be listed.</p>
<h4>Optional Requirements</h4>
<p>Just like in "regular" mode, you can have optional dependencies taken into
account as well.</p>
<p>Instead of listing optional dependencies, you can list packages that have one of
the specified packages as optional dependency.</p>
<h3>Examples</h3>
<p>To give you a quick idea of what you can get, here are a few examples.</p>
<p>Listing exclusive & optional dependencies of git :</p>
<pre><code>% pacdep -eo git
git 17.24 MiB ( 20.71 MiB)
Exclusive dependencies: 2.76 MiB
perl-convert-binhex 56.00 KiB
perl-error 76.00 KiB
perl-io-socket-ssl 140.00 KiB
perl-io-stringy 148.00 KiB
perl-mailtools 204.00 KiB
perl-net-ssleay 1.93 MiB
perl-timedate 228.00 KiB
Optional dependencies: 732.00 KiB
perl-authen-sasl 188.00 KiB
perl-mime-tools 500.00 KiB
perl-net-smtp-ssl 44.00 KiB
Shared dependencies: 20.09 MiB
Total dependencies: 23.57 MiB ( 40.81 MiB)
</code></pre>
<p>Listing optional dependencies of git, in quiet mode, using raw sizes :</p>
<pre><code>% pacdep -oqw git
git 18079744
perl-authen-sasl 192512
perl-mime-tools 512000
perl-net-smtp-ssl 45056
</code></pre>
<p>Listing packages (sorted by size) that (optionally) require git, from sync
databases :</p>
<pre><code>% pacdep -Roz --from-sync git
extra/git 17.24 MiB
Required by: 7.47 MiB
community/giggle 2.41 MiB
community/gitg 1.70 MiB
extra/archboot 1.20 MiB
community/qgit 948.00 KiB
community/sparkleshare 880.00 KiB
community/tig 232.00 KiB
community/hub 160.00 KiB
Optionally required by: 71.18 MiB
community/qtcreator 50.10 MiB
extra/kdevelop 13.02 MiB
community/zim 7.01 MiB
extra/kdesdk-dolphin-plugins 540.00 KiB
community/luarocks 536.00 KiB
Total dependencies: 78.65 MiB ( 95.89 MiB)
</code></pre>
<p>Listing optional dependencies of gparted (not installed), including all optional
dependencies ;</p>
<pre><code>% pacdep -oppp gparted
extra/gparted 5.58 MiB ( 34.05 MiB)
Exclusive dependencies: 29.37 MiB
local: 8.12 MiB
sync: 21.25 MiB
Optional dependencies: 9.00 MiB
local: 1.77 MiB
polkit 1.77 MiB
sync: 7.23 MiB
extra/dosfstools 240.00 KiB
extra/gpart 52.00 KiB
core/jfsutils 1.03 MiB
extra/mtools 412.00 KiB
core/nilfs-utils 512.00 KiB
extra/ntfsprogs 576.00 KiB
core/reiserfsprogs 1.01 MiB
core/xfsprogs 3.44 MiB
Shared dependencies: 244.99 MiB
Total dependencies: 283.35 MiB (288.93 MiB)
</code></pre>
<h3>Download</h3>
<p>If you want to give it a try, go ahead. pacdep is released under GNU GPL v3+ The
source code is available on <a href="https://github.com/jjk-jacky/pacdep" title="pacdep @ GitHub.com">this GitHub
repository</a>.</p>
<p>You can also find <a href="https://aur.archlinux.org/packages/pacdep/" title="AUR: pacdep">a PKGBUILD in the
AUR</a>.</p>
<p>And of course bug reports, suggestions or any other form of constructive
criticism is very much welcome.</p>
PkgClip 1.1.0 & kalu 1.3.0 released2012-10-27T00:00:00+00:00http://jjacky.com/2012-10-27-pkgclip-1.1.0-and-kalu-1.3.0-released<p>New versions of PkgClip - <a href="/pkgclip" title="PkgClip: Cached Packages Trimmer Utility">Cached Packages Trimmer Utility</a> - and kalu
- <a href="/kalu" title="kalu: Keep Arch Linux Up-to-date">upgrade notifier for Arch Linux</a>
- have just been released.</p>
</p>
<h3>PkgClip 1.1.0</h3>
<p>Changes since last version are :</p>
<ul>
<li><p>Use package description as tooltip for the Package column</p></li>
<li><p>Add a panel to show info about the focused item</p>
<p>Info on panel can be defined through config option <code>PkgInfo</code>. Markup syntax
is supported for formatting, as well as the following variables: <code>$NAME</code>,
<code>$DESC</code>, <code>$VERSION</code>, <code>$FILE</code>, <code>$SIZE</code>, <code>$RECOMM</code> and <code>$REASON</code></p></li>
<li><p>Update polkit policy: use auth_admin for all, add message & icon</p></li>
<li><p>pkgclip's source code moved from a mercurial repo
(https://bitbucket.org/jjacky/pkgclip) to a git one
(https://github.com/jjk-jacky/pkgclip)</p></li>
<li><p>Add option <code>--enable-git-version</code> to configure. When enabled, the version used
in pkgclip (and man page) will come from <code>git describe</code> ran at compile/make
time.</p></li>
</ul>
<h3>kalu 1.3.0</h3>
<p>Changes since last version are :</p>
<ul>
<li><p>Add <code>$DESC</code> to all templates (but news) for package description</p></li>
<li><p>Update polkit policy: use auth_admin for all, add message & icon</p></li>
<li><p>kalu's updater: Add tooltip to columns name & all sizes</p></li>
<li><p>Fix segfault on invalid JSON from the AUR</p></li>
<li><p>Fix invalid state when marking read while checking is still running</p>
<p>Notifications appear as soon as possible, and allow user to mark things
read/start upgrades. When this was done while the checking was still
running, it wouldn't be taken into account for kalu's icon/tooltip.</p></li>
<li><p>Fix re-show notifications which would ignore conflicting files error.</p>
<p>When the list of packages to upgrade couldn't be compiled due to file
conflict, a "special" notif is shown, with an error message but also the
"Upgrade system" button.
This notification wasn't registered in the last_notifs list, and re-show
would ignore it (e.g. say "no notifications to show")</p></li>
<li><p>Fix download sizes possibly incorrect (when file already in cache)</p>
<p>Cachedirs weren't set with ALPM during the checks, but they are actually
used when determining the download sizes, in case files are already
downloaded/available in the cache.</p></li>
<li><p>Fix marking watched (AUR) packages could get garbage in memory</p>
<p>Marking watched (AUR) packages as seen could sometimes lead to garbage
used as new version number in memory (data on disk was valid).</p></li>
<li><p>Set icon & tooltip properly when conflict makes upgrades number unknown</p></li>
<li><p>If downloads (news, AUR...) are slow/timeout it might be linked to IPv6, in
which case adding <code>UseIP=4</code> in <code>~/.config/kalu/kalu.conf</code> (under [options])
might help.</p></li>
</ul>
<p>And for the record, I didn't mention it here but on October 21st version 1.2.1
was released with a hotfix for an error checking news (due to the switch to
https-only of Arch Linux website).</p>
<h3>Downloads and whatnot</h3>
<p>Thanks to all those who reported bugs or suggested features.</p>
<p><strong>PkgClip</strong> is released under GNU GPL v3+ The source code is available on <a href="https://github.com/jjk-jacky/pkgclip" title="PkgClip @ GitHub.com">this
GitHub repository</a>,
where bugs/suggestions can be added to the issue tracker.</p>
<p>The release tarball can be downloaded
<a href="https://github.com/jjk-jacky/downloads/pkgclip/pkgclip-1.1.0.tar.gz">here</a>; You
can also find <a href="https://aur.archlinux.org/packages.php?ID=55870" title="AUR: pkgclip">a PKGBUILD in the
AUR</a>.</p>
<p><strong>kalu</strong> is released under GNU GPL v3+ The source code is available on <a href="https://github.com/jjk-jacky/kalu" title="kalu @ GitHub.com">this
GitHub repository</a>, where
bugs/suggestions can be added to the issue tracker.</p>
<p>The release tarball can be downloaded
<a href="https://github.com/downloads/jjk-jacky/kalu/kalu-1.3.0.tar.gz">here</a>; You can
also find <a href="https://aur.archlinux.org/packages.php?ID=56673" title="AUR: kalu">a PKGBUILD in the
AUR</a>.</p>
<p>And of course, as always, new bug reports, suggestions or any other form of
constructive criticism is very much welcome.</p>
kalu 1.2.0 released2012-09-15T00:00:00+00:00http://jjacky.com/2012-09-15-kalu-1.2.0-released<p>A new version of kalu - <a href="/kalu" title="kalu: Keep Arch Linux Up-to-date">upgrade notifier for Arch Linux</a> - has been
released.</p>
</p>
<p>Changes since last version are :</p>
<ul>
<li><p>Instead of hard-coded use of xdg-open, one can now define the command line to
be used when a link is clicked (in news). Variable <code>$URL</code> will be replaced by
the URL to be opened.</p>
<p>Additionally an error message will now be shown in case of failure.</p></li>
<li><p>On the command line to be executed on AUR upgrades, a variable <code>$PACKAGES</code> can
now be used. It will be replaced by the list (space separated) of all AUR
packages for which an upgrade is available.</p></li>
<li><p>It is now possible to have kalu re-show all notifications from the last ran
checks. New option is available in the menu, and as action on single/double
click.</p>
<p>All notifications from the last ran checks will be shown as they were
originally (including action buttons), including any error notifications.</p>
<p>Notifications are removed/altered as needed. For instance, when marking
watched (AUR) packages/news, the corresponding last notification will be
removed (if nothing remains unread/unmarked), or altered to inform that
running checks again is required (also, the button is gone).</p>
<p>It should be noted that the tooltip doesn't display status from the last ran
check, but last known info. Meaning if the last checks failed (e.g. Internet
connection was down), the tooltip will still show data from the (successful)
check before, while re-show will only show the error notification(s).</p></li>
<li><p>Fixed a bug in marking watched (AUR) packages, where garbage could end up as
new version number.</p></li>
<li><p>News parser now handles "all" kinds of new lines (<br >, <br / >,
etc)</p></li>
<li><p>kalu's updater: error messages of 1024+ characters are no longer being
truncated</p></li>
<li><p>kalu's source code moved from a mercurial repo
(https://bitbucket.org/jjacky/kalu) to a git one
(https://github.com/jjk-jacky/kalu)</p></li>
<li><p>Added option <code>--enable-git-version</code> to <u>configure</u>. When enabled, the version
used in kalu (and man page) will come from <code>git describe</code> ran at compile/make
time.</p></li>
</ul>
<h3>Downloads and whatnot</h3>
<p>Thanks to all those who reported bugs or suggested features.</p>
<p><strong>kalu</strong> is released under GNU GPL v3+ The source code is available on <a href="https://github.com/jjk-jacky/kalu" title="kalu @ GitHub.com">this
GitHub repository</a>, where
bugs/suggestions can be added to the issue tracker.</p>
<p>The release tarball can be downloaded
<a href="https://github.com/downloads/jjk-jacky/kalu/kalu-1.2.0.tar.gz">here</a>; You can
also find <a href="https://aur.archlinux.org/packages.php?ID=56673" title="AUR: kalu">a PKGBUILD in the
AUR</a>.</p>
<p>And of course, as always, new bug reports, suggestions or any other form of
constructive criticism is very much welcome.</p>
How to convert a mercurial repo to git2012-09-10T00:00:00+00:00http://jjacky.com/2012-09-10-how-to-convert-a-mercurial-repo-to-git<p>When I started working on a few things, and needed to use some version control,
I used mercurial. This wasn't really something I thought about all that much: I
had used subversion & mercurial before (back on Windows) without problems,
whereas with git the few times I had to use it (e.g. to try things quickly, or
clone a repo) things weren't as smooth (to me, that is).</p>
<p>Admittedly I never bothered looking into git then, and so mercurial was an
obvious "choice" when I needed to use a VCS. Just like
<a href="https://bitbucket.org/jjacky" title="jjacky @ BitBucket">bitbucket</a> was obvious for
the same reason (it's probably the best hosting solution with mercurial
support).</p>
<p>But the Linux ecosystem loves git, they're both quite close historically, and
lately I decided to actually looked into git. I'm still not done with all the
reading, but already I like it a lot.</p>
<p>It can do a lot, so far I understand & like how things work, and I therefore
decided to move. Which means, I'll have to convert my mercurial repos into git
ones; starting with <a href="/kalu" title="kalu: Keep Arch Linux Up-to-date">kalu</a>.</p>
</p>
<h3>The right tool for the job</h3>
<p>There are many possible solutions to do the conversion. I tried a few :</p>
<ul>
<li><p>First I used the <a href="http://hg-git.github.com/" title="Hg-Git Mercurial Plugin">hg-git</a>
plugin. It gives hg the ability to pull to and push from a Git server. Simple
enough, however I wasn't entirely satisfied with the results. (I don't
remember exactly why, but it had to do with tags being lightweight, maybe also
missing branches...)</p></li>
<li><p>I then tried <a href="https://github.com/antono/hg2git" title="Mercurial to Git converter">hg2git</a>, but the results weren't satisfying. Tags were
still lightweight, which I was hoping to find a way around, and my branches
had all (but master) been renamed "branch-xx"</p></li>
<li><p>Finally, I looked at <a href="http://repo.or.cz/w/fast-export.git" title="mercurial to git converter using git-fast-import">fast-export</a>, which gave me the most
satisfying results.</p></li>
</ul>
<p>The convertion itself is easy enough to do:</p>
<pre><code>git clone git://repo.or.cz/fast-export.git .
rm -rf .git .gitignore
git init
./hg-fast-export.sh -r /path/to/hg/repo
git clean -f # remove fast-export files
</code></pre>
<p><u>Note: On Arch Linux, python 3 is the default, so you need to edit
<code>hg-fast-export.sh</code> to add a 2: <code>PYTHON=${PYTHON:-python2}</code></u></p>
<p>However, things still weren't perfect. Tags were still lightweight, and my
history was a bit of a mess. Though I believe this is my fault, due to the way
things were done in hg.</p>
<p>I'm not sure if I just created this mess, or if it is due to the fact that
branches work quite differently in git that they do in mercurial, but the end
result is the same.</p>
<p><strong>I ended up with two parallel branches in the history</strong> : <u>master</u>, where daily
commits were done, and <u>stable</u>, where things were merged and tags done. This
seemed alright at the time, but not anymore.</p>
<p>Because <strong>I wanted to have a "cleaner" (more linear) history in git</strong>, and one
where all tags could be seen from the branch <u>master</u>. The branch <u>stable</u>
should in fact just be in the same history line, only lower up until things are
deemed stable and it gets fast-forwarded (and a tag is added).</p>
<p>So, even though I don't know any python, I started looking at the source code,
to see if I could help "improve" things a bit.</p>
<h3>Let's hack fast-export a bit</h3>
<p>Lucky enough, things looked pretty simple & straight forward, and I was able to
make a few adjustements.</p>
<p>As I said, I don't know python so expect things to be ugly. And those are
probably quite specific to my needs, and might not be applicable as-is to any
other repo.</p>
<h4>Create annotated tags</h4>
<p>Tags were not annotated, even though <strong>in mercurial every time a tag is created,
we have a commit</strong> (that updates the <code>.hgtags</code> file). fast-export was smart
enough to ignore this file, since it's completely useless in git, but still kept
those (empty) commits.</p>
<p>I decided to change things, to ignore those commits (again, they were
empty/useless in git, even more so without the <code>.hgtags</code> file around) and
instead use their info (date, author...) to create the annotated tags.</p>
<p>Should be noted that I didn't make sure this would always work, and it's
probably not ideal for a very large repo. But for the small one that I was
working on, it worked fine.</p>
<p>Every time a commit is added, we check to see if it's tagged. If so, <strong>the next
commit will be "ignored", and instead the annotated tag will be created</strong>. As
mentionned, the commit author becomes the tagger, we re-use the date as well,
and I forced the commit message to <u>Add tag for version <tag></u> since all
my tags are version number, and the original commit message was about the same,
only referencing a mercurial changeset which, here, meant nothing.</p>
<p>It was also needed to adjust the marks used, to not reference the commit we
didn't import but the one before (i.e. the one tagged) instead.</p>
<h4>Avoid the unnecessary history branch</h4>
<p>One problem remained: at one point I had created a new branch (stable), where
tags for stable versions would be done. As described earlier, this resulted in a
"messy" history, with <strong>two parallel branches of commits in the history</strong> : one
with the actual work/commits being done, and one where things were merged, and
tagged.</p>
<p>This looked bad, but because I had consistently done it the same way, it was
easy enough to fix it. It always went like so :</p>
<ul>
<li>commit 1 : [master] some work</li>
<li>commit 2 : [stable, tagged] merge latest</li>
<li>commit 3 : [stable] add tag (to commit 2)</li>
<li>commit 4 : [master] more work</li>
</ul>
<p>So all I had to do was, when dealing with a commit being the result of a merge,
check if it was tagged. If so, in addition to "ignoring" commit 3 (and using its
info for the annotated tag), simply have the tag applied to commit 1 instead of
commit 2.</p>
<p>This worked well, and while all the "commit 2-s" were still being added to git,
they would all go away since their branch wasn't used in any way. I only had to
manually delete the branch stable to make it all proper, and then re-create it
pointing to the right commit (last tagged one).</p>
<p>And with that, <strong>I ended up with a "clean", linear history in git</strong>. Success!</p>
<h3>kalu is now using GIT</h3>
<p>Now kalu is now using <a href="https://github.com/jjk-jacky/kalu" title="kalu @ GitHub">a git
repo</a>
(with a nice linear history), hosted on github. And for those interested/curious,
<a href="https://github.com/jjk-jacky/fast-export" title="jjk-jacky/fast-export on GitHub">my fork of fast-export</a> is also available on github, in branch
<a href="https://github.com/jjk-jacky/fast-export/compare/master...annotated-tags" title="Compare branches master and annotated-tags">annotated-tags</a>.</p>
A couple of plugins for WeeChat2012-09-01T00:00:00+00:00http://jjacky.com/2012-09-01-a-couple-of-plugins-for-weechat<p>When I moved to Linux, I looked for an IRC client. Originally, I wanted/looked
for a GUI one, probably because coming from Windows I'm used to GUI
applications.</p>
<p>Soon enough it looked like I wouldn't be able to find a client that would fit my
needs, so I tried CLI clients, and eventually found
<a href="http://www.weechat.org/" title="WeeChat, the extensible chat client.">WeeChat</a>. It's
a great client, does lots of things by itself, but also has scripting support to
extend things even further.</p>
</p>
<p>Still, as I started to use it more and more, there were a few things I needed
that I couldn't find scripts for. Probably, the easiest way to add them would
have been to write such a script, either in perl, python, or any of the other
languages supported by WeeChat.</p>
<p>Instead, I went with C plugins. The only reason, to be fair, is that I don't
know anything about any of the (many) script languages supported by WeeChat,
while I had been doing some C for a little while. So it was easier/faster <u>for
me</u> to do so, is all.</p>
<h3>weenick: Provides support for common NickServ operations</h3>
<p>First of all, since I use registered nicks of a few networks, I wanted to be
identified automatically. This could be done by a simple command triggered upon
connection, but I also wanted that on reconnection the command to kill the
ghost, the change of nick & do the identification all be done without me having
to do anything. Laziness is strong with me. :)</p>
<p>weenick should handle all of that, and you can also define command(s) to be
executed once identified.</p>
<p>It is configured through options under
<code>var.plugins.weenick.server_default.SETTING</code> for "global" values, which will be
used (as fallback) on all servers. You can also define options under
<code>var.plugins.server.SERVER.SETTING</code> for settings to be used on server SERVER
only.</p>
<p>The options are :</p>
<ul>
<li><p><code>nick</code> : your (registered) nickname. When defined, weenick will try to use
that nick upon connection (in case WeeChat used another one). If the nick is
already in use, killing the ghost will be triggered.</p></li>
<li><p><code>password</code> : your password, to identify/kill ghost with services</p></li>
<li><p><code>command</code> : command(s) to get processed upon identification</p></li>
<li><p><code>nickserv_nick</code> : nickname to send messages to. Default: <u>NickServ</u></p></li>
<li><p><code>nickserv_registered</code> : string to identify notice that nick is registered
Default: <u>nickname is registered</u></p></li>
<li><p><code>nickserv_ghost_killed</code> : string to identify notice that ghost was killed
Default: <u>ghost with your nick has been killed</u></p></li>
<li><p><code>nickserv_identified</code> : string to identify notice that nick was identified
Default: <u>password accepted</u></p></li>
<li><p><code>nickserv_failed</code> : string to identify notice that password is wrong Default:
<u>access denied</u></p></li>
</ul>
<p>The <code>nickserv_*</code> options are there because not all servers uses the same strings
for each case (starting with servers in another language than English, I guess).</p>
<p>(Of course, a match must happen in a NOTICE from NickServ (or whatever is
specified as <code>nickserv_nick</code>) for it to be effective.)</p>
<p>Going over this, I realized the actual commands to kill ghost or identify are
hard-coded, which probably isn't the best. Hopefully all services use the same,
specifically: <code>/msg <nickserv> GHOST <nick> <password></code> and <code>/msg <nickserv>
IDENTIFY <password></code></p>
<p>(Registering your nick with services is all up to you, btw.)</p>
<h3>weereact: Triggers commands in reaction to messages</h3>
<p>Another thing I was after, was a way to have commands be triggered automatically
in reaction to something that was said in a channel. Sort of a bot-like
behavior, if you will.</p>
<p>weereact will allow to do just that: you can define "triggers" that will filter
messages, and trigger the specified command(s) for each match.</p>
<p>Messages can be filtered by server, channel, user and content (through
perl-compatible regular expression).</p>
<p>All configuration must be done in file <code>weereact.conf</code> in WeeChat's working
directory (e.g. <code>~/.weechat</code>). There's no interface, you need to manually edit
the file in your favorite editor, and can use the <code>/reload</code> command to have
weereact reload its config from the file.</p>
<p>Syntax in that file is pretty basic: Empty lines and lines starting with # are
ignored; otherwise the format is simply: <code>key=value</code></p>
<p>To start a new trigger definition, use the following on a new line: <code>[]</code></p>
<p>Options (keys) can be used to filter on which messages should the actions be
triggered, as well as define said actions.</p>
<ul>
<li><p><code>on</code> : name of the server the message must be sent on</p></li>
<li><p><code>to</code> : name of the channel (with #) or nick for PMs. For PMs send to
yourself/you're receiving, use: <code>to=-</code></p></li>
<li><p><code>by</code> : name of the sender of the message. For messages you're sending, use:
<code>by=-</code></p></li>
<li><p><code>is</code> : <a href="http://developer.gnome.org/glib/2.30/glib-regex-syntax.html" title="Regular expression syntax">perl-compatible
regex</a> to filter the message.</p></li>
<li><p><code>do</code> : command to be executed when a message matches. You can specify this
option as many as times as you need. In addition to the back-references from
the regex in <code>is</code>, you can also use the following variables:</p></li>
<li><code>$on</code> : name of the server</li>
<li><code>$to</code> : name of the #channel/nick the message is sent to</li>
<li><code>$by</code> : name of the sender (only available if you're not sending the message)</li>
</ul>
<h4>New command: /tobuffer</h4>
<p>One last thing this plugin does, is introduce a new command - <code>/tobuffer</code> -
which can be used to send text (or commands) to a specific buffer.</p>
<p>It's very possible you don't need it for most things, since you can e.g. specify
a server & channel with <code>/msg</code> for instance, but I needed to send text/command
to plugin buffers (i.e. not IRC channel/privates).</p>
<p>Also, I'm not sure there's a way, from such a command, to do a <code>/me does
nothing</code> Although you wouldn't need to use <code>/tobuffer</code> for that, if that needed
to happen in the channel/private where the original message occured, as by
default all text/commands sent by weereact are done to the buffer of the
original message, IOW in the same channel/private as the original message.</p>
<h3>Downloads and whatnot</h3>
<p><strong>weeplugins</strong> is released under GNU GPL v3+ The source code is available on
<a href="https://bitbucket.org/jjacky/weeplugins" title="weeplugins @ BitBucket.org">this BitBucket repository</a>, where bugs/suggestions can be added to the issue
tracker.</p>
<p>Arch Linux users can also use the <a href="https://aur.archlinux.org/packages.php?ID=62366" title="AUR: weeplugins">PKGBUILD in the
AUR</a>, which
grabs the latest code from the GIT repo.</p>
<p>And of course, as always, new bug reports, suggestions or any other form of
constructive criticism is very much welcome.</p>
kalu now usable from CLI (1.1.0 released)2012-08-11T00:00:00+00:00http://jjacky.com/2012-08-11-kalu-now-usable-from-CLI-1.1.0-released<p>A new version of kalu - <a href="/kalu" title="kalu: Keep Arch Linux Up-to-date">upgrade notifier for Arch Linux</a> - has been
released.</p>
<p>Two main changes with this version. Firstly, the addition of two command-line
options - <code>--manual-checks</code> (<code>-m</code>) and <code>--auto-checks</code> (<code>-a</code>) - to <strong>run
manual/auto checks from command line</strong>. No GUI will be used at all, everything
gets printed on stderr/stdout (using the same templates as for notifications).</p>
<p>This can be done without the need for a DISPLAY/running X server (i.e. no GTK
init performed), thus <strong>works from a tty or through SSH</strong>. This can also be
useful to use kalu from scripts.</p>
</p>
<p>Alongside those options is a <u>configure</u> option (<code>--disable-gui</code>) to make kalu a
small CLI-only binary (i.e. no dependency to GTK nor libnotify), which could be
useful on GUIless box (e.g. servers), where kalu can then still be used to check
for upgrades, watched packages, etc</p>
<p>(Running this CLI kalu without arguments will do the same as using
<code>--manual-checks</code>)</p>
<p>And then, there were improvments & fixes on the news parser, mainly with
<strong>support for links</strong>. As expected, links will now be in blue & underlined, the
URL available as tooltip, and clicking it will open it in your default browser.</p>
<p>Opening the URL is actually done via <code>xdg-open</code> Although I just realized, right
after uploading the new version to the AUR in fact, that this wasn't really the
best way to go.</p>
<p>A better solution than hardcoding the use of xdg-open would be to introduce a
new option, and that's what I did. The code is already done, though it's not in
this version. But next version will also use xdg-open by default, but let you
change it to whatever replacement you use, or even your web browser directly. Up
to you.</p>
<p><u>(So if you don't have <code>xdg-utils</code> on your system and don't want to install it
just for kalu, but want to be able to click on links, you can download the code
from the repo (branch default) and you'll then have the option available (under
Misc).)</u></p>
<h3>Downloads and whatnot</h3>
<p>Thanks to all those who reported bugs or suggested features.</p>
<p><strong>kalu</strong> is released under GNU GPL v3+ The source code is available on <a href="https://bitbucket.org/jjacky/kalu" title="kalu @ BitBucket.org">this
BitBucket repository</a>,
where bugs/suggestions can be added to the issue tracker.</p>
<p>The release tarball can be downloaded
<a href="https://bitbucket.org/jjacky/kalu/downloads/kalu-1.1.0.tar.gz">here</a>; You can
also find <a href="https://aur.archlinux.org/packages.php?ID=56673" title="AUR: kalu">a PKGBUILD in the
AUR</a>.</p>
<p>And of course, as always, new bug reports, suggestions or any other form of
constructive criticism is very much welcome.</p>
dapper 0.1.2 released2012-06-21T00:00:00+00:00http://jjacky.com/2012-06-21-dapper-0.1.2-released<p>As I explained before, I don't use a session manager, and when I needed
something to take care of handling the autostart of Desktop applications for me,
and couldn't find anything what I wanted, <a href="/2012-06-01-dapper-a-desktop-applications-autostarter" title="dapper, a desktop applications autostarter">I made
dapper</a>.</p>
<p>Until now it only followed the FreeDesktop specifications, that is started
things according to <code>.desktop</code> files found in user & system autostart folders.
In that order, in fact.</p>
<p>Version 0.1.2 now works differently, introducing options allowing you to decide
which folders should be processed :
</p>
<p><code>--system-dirs</code> to process system (<strong>XDG_CONFIG_DIRS</strong>) autostart folders</p>
<p><code>--user-dir</code> to process user (<strong>XDG_CONFIG_HOME</strong>) autostart folder</p>
<p><code>--extra-dir PATH</code> to process the specified <u>PATH</u> (not an autostart subfolder)</p>
<p>Bonus: process will happen in the same order the options were specified.</p>
<p>This turns out to be pretty useful to me, because I really don't like to have
thing autostarted when I open a new session, I like things to stay fast & clean.</p>
<p>(So I'm all for pulse or the PolicyKit agent to be started, but not much else,
for instance. That's done with a clean <code>~/.config/autostart</code> and <code>dapper -su</code> on
session openning)</p>
<p>However, I do start a few of the same applications every single time : web
browser, file manager, e-mail reader, kalu, etc</p>
<p>So now, I just made myself a new folder (<code>~/.local/autostart</code>) where I put
symlinks to <code>.desktop</code> files of those very applications. And when I want to
start it all, instead of doing it manually for each of them, I just start
<code>dapper -e ~/.local/autostart</code> and voilà!</p>
<p><u>Note: dapper doesn't actually resolve the tilde (~) to your home folder. That
is if you were, as I did, to create a <code>.desktop</code> file to start this in a single
click on a menu item, make sure to specify the full actual path, e.g: <code>dapper -e
/home/jjacky/.local/autostart</code></u></p>
<p>Also worth mentionning a few bugs have been fixed, notably dapper would crash if
the config file couldn't be opened, or a folder to be processed did not exist
(fixed in 0.1.1); and parsing fields was actually quite buggy/not working (fixed
in 0.1.2).</p>
<h3>Download</h3>
<p>dapper is released under GNU GPL v3+ The source code is available on <a href="https://bitbucket.org/jjacky/dapper" title="dapper @ BitBucket.org">this
BitBucket repository</a>,
where the issue tracker welcomes bugs/suggestions.</p>
<p>The release tarball can be downloaded here; and Arch Linux users can use <a href="https://aur.archlinux.org/packages.php?ID=59681" title="AUR: dapper">the
PKGBUILD in the AUR</a>.</p>
dapper: a desktop applications autostarter2012-06-01T00:00:00+00:00http://jjacky.com/2012-06-01-dapper-a-desktop-applications-autostarter<p>A little while ago, XFCE released a new version, 4.10, and with it a few changes
were introduced. Amongst which is the moving of the starting script
(<code>startxfce4</code>), which used to belong to <code>xfce4-util</code>, a package that no longer
exists.</p>
<p>So the script got moved to <code>xfce4-session</code>, which is a little problem for me
because I don't have that one installed, and I don't want to install it. It's
possible I don't know exactly all that a session manager has to offer, but as
far as I know what it would provide me is the ability to shutdown/restart the
computer from XFCE, which I don't care for since I can/would rather do it from
my login shell, or restart whatever applications were running last time I logged
out, something I absolutely don't want at all.</p>
<p>So, I don't use a session manager. But because <code>startxfce4</code> moved to that
package, I needed to do something. The easiest thing would have obviously been
to just copy that file and keep using it, outside of any packages.</p>
<p>But I wasn't too inclined to do so, because this script does quite a few things,
or tries to do them at least, and I figured if I make it my own and need to
maintain it, I might as well keep things as simple as possible.</p>
</p>
<p>One thing this script did, although not very well, was take care of the
autostarting of desktop applications. I say not very well, because it would only
look in one folder for <code>.desktop</code> files, thus ignoring quite a few things.</p>
<p>This resulted in things not being autostarted for me (e.g. the PolicyKit
authentication agent) unless I manually added it.</p>
<h3>A Desktop Applications Autostarter</h3>
<p>So I started looking for a simple application autostarter, one that would do
just that: as per the <a href="http://standards.freedesktop.org/autostart-spec/autostart-spec-latest.html" title="Desktop Application Autostart Specification">FreeDesktop
specifications</a>, look up for <code>.desktop</code> files in
the different folders, and start whatever needs to be started.</p>
<p>Unfortunately I couldn't find what I was looking for, and that's how dapper was
born. dapper does just that, nothing else, and tries to follow the FreeDesktop
specifictions.</p>
<p>I say "tries to," only because there are a couple things not implemented
(because I don't have a need for them, and am lazy) :</p>
<ul>
<li><p>Keys <code>StartupNotify</code> and <code>StartupWMClass</code> are not supported.</p></li>
<li><p>When parsing command line in <code>Exec</code>, field code <code>%c</code> is not supported, and
simply removed.</p></li>
</ul>
<p>Other than that it will start all that should be started pretty fast, and you
can define which desktop to start applications for (e.g. GNOME, XFCE, etc) in
configuration file (<code>~/.config/dapper.conf</code>) or from command line.</p>
<h3>Download</h3>
<p>Maybe this might be useful to some of you, though note that autostarting desktop
applications is probably already taken care of if you do use a desktop
environment/session manager.</p>
<p>dapper is released under GNU GPL v3+ The source code is available on <a href="https://bitbucket.org/jjacky/dapper" title="dapper @ BitBucket.org">this
BitBucket repository</a>.</p>
<p>You can also find <a href="https://aur.archlinux.org/packages.php?ID=59681" title="AUR: dapper">a PKGBUILD in the
AUR</a>.</p>
<p>And of course bug reports, suggestions or any other form of constructive
criticism is very much welcome.</p>
Automatic restart of services on upgrade2012-05-10T00:00:00+00:00http://jjacky.com/2012-05-10-automatic-restart-of-services-on-upgrade<p>Sometimes after an upgrade of the system, there might be a few tasks that needs
to be done. For example, aplications or services migh need to be restarted for
the new version to be used/in use.</p>
<p>While libalpm/pacman does not have hooks, and neither does kalu, I thought I'd
just take a little time to highlight the fact that <strong>kalu does support the start
of post-sysupgrade processes</strong>.</p>
<p>For example, I use this to start
<a href="https://aur.archlinux.org/packages.php?ID=11975" title="AUR: localepurge">localepurge</a>
after every sysupgrade (or package installation, though then through my use of
alias (<a href="https://bitbucket.org/jjacky/dotfiles/src/7402a2335add/bashrc#cl-187" title=".bashrc @ BitBucket.org">function</a>, actually) for pacman) to save some space.</p>
<p>I also have
<a href="/2012-01-17-pkgclip-does-your-pacman-cache-need-a-trim" title="PkgClip: Cached Packages Trimmer Utility">PkgClip</a>, to keep pacman's cache trimmed,
and not long ago I added a <a href="/2012-04-09-what-to-restart-after-a-system-upgrade" title="What to restart after a system upgrade ?">little script to list deleted librairies in
use</a>.</p>
<p>And now, with <a href="/kalu" title="kalu: Keep Arch Linux Up-to-date">kalu</a> 1.0.0, I was even able to add a few more things. Besides
having the option to remove the confirmation before starting anything, you can
now use <strong>variable <code>$PACKAGES</code> which will be replaced by the list of packages
involved</strong>.</p>
</p>
<p>While this isn't meant to replace hooks, it can be used to trigger some actions
(or alerts, or anything you want really) based on whether a package has been
upgraded or not.</p>
<p>In my case, I simply look for packages for which I know some service will need
to be restarted, and after a confirmation a new terminal will be opened for said
restart to take place.</p>
<p>It certainly doesn't mean you shouldn't check what gets upgraded or read the
log, it just helps making things a little easier/faster, which is always nice.</p>
<p>If you're curious, <a href="https://bitbucket.org/jjacky/scripts/src/default/postsysupgrade" title="scripts: postsysupgrade @ BitBucket.org">here's the
script</a> I have automatically started by kalu
after a sysupgrade, as <code>postsysupgrade kalu $PACKAGES</code></p>
PkgClip 1.0.0 & kalu 1.0.0 released2012-05-10T00:00:00+00:00http://jjacky.com/2012-05-10-pkgclip-1.0.0-and-kalu-1.0.0-released<p>New versions of PkgClip - <a href="/pkgclip" title="PkgClip: Cached Packages Trimmer Utility">Cached Packages Trimmer Utility</a> - and kalu
- <a href="/kalu" title="kalu: Keep Arch Linux Up-to-date">upgrade notifier for Arch Linux</a> - have just been released.</p>
<p>Both have been bumped to 1.0.0, not because they've undergone major changes but
simply because my versioning so far had been possibly a little, hmm... "random",
so I decided to try and use something better, specifically <a href="http://semver.org/" title="Semantic Versioning">semantic
versioning</a>.</p>
<p>And while both PkgClip & kalu have been stable for a little while now, they were
still in the 0.y.z branch, which in semantic versioning should be for
development phase, while the first stable version should be 1.0.0, hence the
bump.</p>
<p>Of course that's not all, both have actually been updated as well :</p>
</p>
<h3>PkgClip 1.0.0</h3>
<p>Changes since last version are :</p>
<ul>
<li><p>Added buttons to "Select previous/next marked package" to allow quick & easy
review of marked packages</p></li>
<li><p>Added menus for "Select previous/next marked package" and "Remove marked
packages", all with accelerators</p></li>
<li><p>Added minimum command line options (<code>--help</code>, <code>--version</code>)</p></li>
<li><p>Under certain conditions, all sizes on the list could show as "128 TiB" (in
list only, tooltips & total were correct), fixed</p></li>
<li><p>Other minor fixes</p></li>
<li><p>Bumped to 1.0.0 to follow semantic versioning</p></li>
</ul>
<h3>kalu 1.0.0</h3>
<p>Changes since last version are :</p>
<ul>
<li><p>Preferences: kalu's updater: added option to disable confirmation before
starting PostSysUpgrade processes.</p></li>
<li><p>PostSysUpgrade: now you can use variable <code>$PACKAGES</code> in the command line, to
be replaced by the list of upgraded packages.</p>
<p>Note that the list actually is of all packages involved in the sysupgrade,
i.e. also those removed or added (e.g. when a package is replaced by another
one).</p></li>
<li><p>When buttons for Upgrades & AUR were both used/clicked at the same time, kalu
would run a check after each, fixed</p></li>
<li><p>Parsing config file was broken for lines with more than 255 characters, fixed</p></li>
<li><p>News parser: added support for lists and &quot;</p></li>
<li><p>Other minor fixes.</p></li>
<li><p>Bumped to 1.0.0 to follow semantic versioning</p></li>
</ul>
<h3>Downloads and whatnot</h3>
<p>Thanks to all those who reported bugs or suggested features.</p>
<p><strong>PkgClip</strong> is released under GNU GPL v3+ The source code is available on <a href="https://bitbucket.org/jjacky/pkgclip" title="PkgClip @ BitBucket.org">this
BitBucket repository</a>, where bugs/suggestions can be added to the issue
tracker.</p>
<p>The release tarball can be downloaded
<a href="https://bitbucket.org/jjacky/kalu/downloads/pkgclip-1.0.0.tar.gz">here</a>; You
can also find <a href="https://aur.archlinux.org/packages.php?ID=55870" title="AUR: pkgclip">a PKGBUILD in the
AUR</a>.</p>
<p><strong>kalu</strong> is released under GNU GPL v3+ The source code is available on <a href="https://bitbucket.org/jjacky/kalu" title="kalu @ BitBucket.org">this
BitBucket repository</a>,
where bugs/suggestions can be added to the issue tracker.</p>
<p>The release tarball can be downloaded
<a href="https://bitbucket.org/jjacky/kalu/downloads/kalu-1.0.0.tar.gz">here</a>; You can
also find <a href="https://aur.archlinux.org/packages.php?ID=56673" title="AUR: kalu">a PKGBUILD in the
AUR</a>.</p>
<p>And of course, as always, new bug reports, suggestions or any other form of
constructive criticism is very much welcome.</p>
Version 0.1.5 of kalu released2012-04-14T00:00:00+00:00http://jjacky.com/2012-04-14-version-0.1.5-of-kalu-released<p>A new version of kalu - <a href="/kalu" title="kalu: Keep Arch Linux Up-to-date">upgrade notifier for Arch Linux</a> - has just been
released. Changes since last version are :</p>
<ul>
<li><p>Now using automake & autoconf. (Hopefully) this shouldn't really change much
for most people, but if you don't care for kalu's updater and only want to use
kalu as update notifier, you can use option <code>--disable-updater</code> to configure.
You'll get a smaller binary, no second binary (<code>kalu-dbus</code>) nor dependency to
DBus/PolicyKit.</p></li>
<li><p>When starting an external process to perform sysupgrade (or AUR upgrade), kalu
now waits for the process to end (being "busy" meanwhile), and runs another
check right after, to refresh its state.</p></li>
</ul>
</p>
<ul>
<li><p>kalu always shipped with a man page, and recently a changelog. Both can both
easily be read using menus Help & Change log.</p></li>
<li><p>Added new option to customize icon used on notification: none, kalu's default,
or specifying a file to load the icon from. The icon will be shown full size,
so e.g. using <code>/usr/share/pixmaps/kalu.png</code> will uses kalu's icon at 48x48 (if
loading icon fails, silently falls back to kalu's default icon).</p></li>
<li><p>kalu's updater always used <code>/etc/pacman.conf</code> (instead of whatever is set in
Preferences), fixed</p></li>
<li><p>Parsing kalu.conf would report & stop on first error, now it ignores the line,
continues parsing, and report all errors (at once)</p></li>
<li><p>kalu's updater: log messages longer than 1023 characters would be truncated,
fixed</p></li>
<li><p>Other minor fixes</p></li>
</ul>
<p>Thanks to all those who reported bugs or suggested features.</p>
<p>kalu is released under GNU GPL v3+ The source code is available on <a href="https://bitbucket.org/jjacky/kalu" title="kalu @ BitBucket.org">this
BitBucket repository</a>,
where bugs/suggestions can be added to the issue tracker.</p>
<p>The release tarball can be downloaded
<a href="https://bitbucket.org/jjacky/kalu/downloads/kalu-0.1.5.tar.gz">here</a>; You can
also find <a href="https://aur.archlinux.org/packages.php?ID=56673" title="AUR: kalu">a PKGBUILD in the
AUR</a>.</p>
<p>And of course new bug reports, suggestions or any other form of constructive
criticism is very much welcome.</p>
What to restart after a system upgrade ?2012-04-09T00:00:00+00:00http://jjacky.com/2012-04-09-what-to-restart-after-a-system-upgrade<p>If you're familiar with Windows, you know rebooting is something pretty common.
You're usually asked to reboot after a system upgrade, after (or in order to)
installing a new application, after removing one...</p>
<p>And one of the thing you hear about Linux, is that you almost never need to
reboot. Unless you install a new kernel, rebooting is not necessary, but that
doesn't mean you don't have to restart a few things.</p>
<p>It was actually one question I had early on after moving to Linux : <strong>how to
know what to restart after a system upgrade ?</strong></p>
</p>
<p>Some things are pretty obvious: if you upgraded Firefox to a new version, you'll
have to restart it.</p>
<p>Similarly, having upgraded the X server, it needs to be restarted. I'm not
exactly sure how that works when one uses a Display Manager, but as it turns out
I don't (I use the great <a href="https://bitbucket.org/jjacky/xlsh-jjk/overview" title="eXtended Login Shell fork">xlsh</a> to log in, and auto-start my X session through
<a href="https://bitbucket.org/jjacky/dotfiles/src/tip/bash_profile" title="my .bash_profile"><code>.bash_profile</code></a>), so when I need to restart X, I just log out and back in.</p>
<p>But <strong>things gets a bit more complicated when it comes to libraries</strong>. Because
it's not always obvious which application uses a given library, even when you
know what said library does.</p>
<p>A <a href="http://forums.gentoo.org/viewtopic-t-842297.html" title="When are .so's reloaded? @ Gentoo Forums">little trick</a> I found recently that can help with
that, is using <a href="http://people.freebsd.org/~abe/" title="lsof - LiSt Open Files"><strong>lsof</strong></a>. It's a great tool that can list all opened files, and
of course that also includes deleted files.</p>
<p>So, one can easily use it and grep the list of all opened files whose name
contains "lib" - as is often if not always the case for libraries - and then we
get the list of applications that are still using old/deleted versions of one or
more libraries. Or, of applications that should be restarted.</p>
<p>Now because I'm curious I guess, I like to know why a given app needs to be
restarted, so I tweaked it a bit, so that it not only gives the application to
restart; but also the name of the deleted library it uses :</p>
<pre><code>lsof +c 0 | grep 'DEL.*lib' | awk '1 { print $1 ": " $NF }' | sort -u
</code></pre>
<h3>Automaticly check for deleted libraries in use after a sysupgrade</h3>
<p>As you might know, I do my system upgrades through <a href="/kalu" title="kalu: Keep Arch Linux Up-to-date">kalu</a> & its system updater.
And one thing it allows you to do, is define some process to be ran after each
sysupgrade.</p>
<p>Now because this is all done from a GUI, I wanted this to also be done through a
GUI and not by opening a terminal. So here's the little script I made :</p>
<p><ol class="bash"><li class="li1"><div class="de1"><span class="co0">#!/bin/bash</span></div></li>
<li class="li1"><div class="de1"><span class="re2">ret</span>=<span class="nu0">2</span></div></li>
<li class="li1"><div class="de1"><span class="kw1">while</span> <span class="br0">[</span> <span class="re1">$ret</span> <span class="re5">-eq</span> <span class="nu0">2</span> <span class="br0">]</span>; <span class="kw1">do</span></div></li>
<li class="li1"><div class="de1"> <span class="re2">LIST</span>=$<span class="br0">(</span>lsof +c <span class="nu0">0</span> <span class="sy0">|</span> <span class="kw2">grep</span> <span class="st_h">'DEL.*lib'</span> <span class="sy0">|</span> <span class="kw2">awk</span> <span class="st_h">'1 { print $1 ": " $NF }'</span> <span class="sy0">|</span> <span class="kw2">sort</span> -u<span class="br0">)</span></div></li>
<li class="li1"><div class="de1"> <span class="kw1">if</span> <span class="br0">[</span><span class="br0">[</span> <span class="re1">$LIST</span> = <span class="st0">""</span> <span class="br0">]</span><span class="br0">]</span>; <span class="kw1">then</span></div></li>
<li class="li1"><div class="de1"> ic-info <span class="st_h">'No deleted libraries in use found'</span></div></li>
<li class="li1"><div class="de1"> <span class="kw3">exit</span> <span class="nu0">0</span></div></li>
<li class="li1"><div class="de1"> <span class="kw1">fi</span></div></li>
<li class="li1"><div class="de1"> <span class="kw3">echo</span> <span class="st0">"<span class="es2">$LIST</span>"</span> <span class="sy0">|</span> ic-text <span class="re5">-e</span> Refresh <span class="re5">-E</span> gtk-refresh <span class="re5">-T</span> <span class="st_h">'Deleted Libraries In Use'</span></div></li>
<li class="li1"><div class="de1"> <span class="re2">ret</span>=<span class="re4">$?</span></div></li>
<li class="li1"><div class="de1"><span class="kw1">done</span></div></li>
</ol></p>
<p>This makes use of <a href="https://bitbucket.org/jjacky/intercourse" title="intercourse - GTK+ GUI elements for scripts">intercourse</a> to provide GUI elements, but of
course you could use anything else, e.g.
<a href="http://library.gnome.org/users/zenity/stable/" title="Zenity Manual @ Gnome">zenity</a>.</p>
<h3>Restarting XFCE panel ?</h3>
<p>As I mentionned earlier, I don't use a Display Manager, and upon login a new X
session is automatically started via my <code>.bash_profile</code></p>
<p>One more thing I don't use, is a session manager, not XFCE's own or any other.
As far as I can tell, what this would do besides eat ressources is make note of
running applications when I log out, to start them back when I log in.
Definately <u>not</u> something I have any interest in.</p>
<p>Something else it would do, is get me buttons to restart or shutdown the
computer. But I don't care for that, since I can do it from my xlsh shell.</p>
<p>But as a result, when I want to close th XFCE panel, I get a little warning :
<u>You have started X without session manager. Clicking Quit will close the X
server.</u></p>
<p>This is a bit unfortunate, because it means that <strong>I can't restart the panel
without closing X</strong>, any running X apps while at it, and logging me out. Of
course, <strong>there's a way around this</strong>.</p>
<p><code>xfce-utils</code> comes with a xinitrc that already takes care of panel crash. In
such an event, you get a little message (using <code>xmessage</code>) about it, and the
panel is restarted. So I just edited my <code>~/.config/xfce4/xinitrc</code> to have the
ability to either log out, or simply restart the panel, e.g. so it can use a
newly-upgraded library.</p>
<p><ol class="bash"><li class="li1"><div class="de1"><span class="kw1">while</span> <span class="kw2">true</span>; <span class="kw1">do</span></div></li>
<li class="li1"><div class="de1"> <span class="kw1">if</span> <span class="kw3">test</span> <span class="re1">$ret</span> <span class="re5">-ne</span> <span class="nu0">0</span>; <span class="kw1">then</span></div></li>
<li class="li1"><div class="de1"> ic-error <span class="re5">-T</span> Error <span class="st_h">'A crash occured in the panel'</span> <span class="re5">-D</span> <span class="co2"><<EOF</span></div></li>
<li class="li1"><div class="de1"><span class="co2">Please report this to the xfce4-dev@xfce.org list</span></div></li>
<li class="li1"><div class="de1"><span class="co2">or on http://bugs.xfce.org</span></div></li>
<li class="li1"><div class="de1"><span class="co2">Meanwhile the panel will be restarted</span></div></li>
<li class="li1"><div class="de1"><span class="co2">EOF</span></div></li>
<li class="li1"><div class="de1"> <span class="kw2">cat</span> <span class="sy0">>&</span><span class="nu0">2</span> <span class="co2"><<EOF</span></div></li>
<li class="li1"><div class="de1"><span class="co2">A crash occured in the panel</span></div></li>
<li class="li1"><div class="de1"><span class="co2">Please report this to the xfce4-dev@xfce.org list</span></div></li>
<li class="li1"><div class="de1"><span class="co2">or on http://bugs.xfce.org</span></div></li>
<li class="li1"><div class="de1"><span class="co2">Meanwhile the panel will be restarted</span></div></li>
<li class="li1"><div class="de1"><span class="co2">EOF</span></div></li>
<li class="li1"><div class="de1"> <span class="kw1">else</span></div></li>
<li class="li1"><div class="de1"> <span class="co0"># 3 = closed w/out button; 1 = Restart; 0 = Close & log out</span></div></li>
<li class="li1"><div class="de1"> ic-question <span class="re5">-T</span> <span class="st_h">'Logging out?'</span> \</div></li>
<li class="li1"><div class="de1"> <span class="re5">-b</span> <span class="st_h">'Close X and log out'</span> <span class="re5">-i</span> gtk-quit \</div></li>
<li class="li1"><div class="de1"> <span class="re5">-B</span> <span class="st_h">'Restart panel'</span> <span class="re5">-I</span> gtk-refresh \</div></li>
<li class="li1"><div class="de1"> <span class="st_h">'Do you want to close X & log out ?'</span> \</div></li>
<li class="li1"><div class="de1"> <span class="re5">-d</span> <span class="st_h">'Closing X will terminate all running programs. Better to close them properly first.'</span></div></li>
<li class="li1"><div class="de1"> <span class="kw1">if</span> <span class="kw3">test</span> <span class="re4">$?</span> <span class="re5">-eq</span> <span class="nu0">0</span>; <span class="kw1">then</span></div></li>
<li class="li1"><div class="de1"> <span class="kw3">break</span></div></li>
<li class="li1"><div class="de1"> <span class="kw1">fi</span></div></li>
<li class="li1"><div class="de1"> <span class="kw1">fi</span></div></li>
<li class="li1"><div class="de1"> <span class="re1">$panel</span></div></li>
<li class="li1"><div class="de1"> <span class="re2">ret</span>=<span class="re4">$?</span></div></li>
<li class="li1"><div class="de1"><span class="kw1">done</span></div></li>
</ol></p>
Rename a group of files at once2012-03-21T00:00:00+00:00http://jjacky.com/2012-03-21-rename-a-group-of-files-at-once<p>One thing I need to do pretty much every day, is rename a batch of files, using
a set of predetermined rules. A few months back, when I was still on Windows, I
used to have a tool to do just that, so logically I started looking for a
"replacement" now that I'm on Linux.</p>
<p>However, while I did find a few batch renaming utilities, none of them would
really fill all the checkboxes of my requirements list. Either because they
didn't provide the "rules" I was looking for, or because they would rename files
after each rule has been applied, or because they couldn't be used from scripts
(that way I wanted), or whatever the reason.</p>
</p>
<p>So, I just went ahead and made (yet another) one:</p>
<h3>molt: batch renaming utility</h3>
<p>As said, the aim of this little tool is to rename a group of files, using a set
of rules.</p>
<p>molt will, for each file, apply all the rules to determine the new name. It will
make sure those new names are "free," as in not already in use; and handles
"avoidable conflicts" - when a file's new name is taken by another file to be
renamed (performing two-steps renaming with a temporary name if needed).</p>
<p>By default, molt will only attempt to rename anything if no errors or conflicts
were found (though this could be changed via option <code>--continue-on-error</code>)</p>
<h4>Rules</h4>
<p>Rules are the heart of molt, since they're what determines the new names will
be. molt comes in with a few rules, currently they are:</p>
<p><code>--upper</code> : convert to upper case</p>
<p><code>--lower</code> : convert to lower case</p>
<p><code>--camel</code> : convert to Camel Case</p>
<p><code>--list</code> : use list of new news read from stdin</p>
<p><code>--sr search[/replacement[/options]]</code> : perform (optionally case insensitive)
search and replace operation. Removes search if no replacement is specified</p>
<p><code>--regex pattern[/replacement[/options]]</code> : same as above, but using regular
expressions</p>
<p><code>--vars</code> : resolves variables</p>
<p><code>--tpl template</code> : set all filenames to <code>template</code> and, so it's actually useful,
resolves variables</p>
<p>That's it, but I might add a few more, such as ways to insert a string at a
given place, and maybe remove a string by location as well. (And if you have
needs/ideas for rules, let me know.)</p>
<p>Another thing to note: molt comes with plugin support, which can provide new
rules.</p>
<h4>Variables</h4>
<p>You can use "variables" in the new flenames, which will be resolved
independently for each file. The syntax is to put the variable's name in between
dollar signs, e.g: <code>$FOOBAR$</code></p>
<p>Some variables can also support optional parameters. Those can be specified
using colon as separator, e.g: <code>$FOOBAR:PARAM1:PARAM2$</code></p>
<p>Variables are not automatically resolved, you need to use the rule <code>--vars</code> in
order to have them resolved, which gives you the ability to determine when
resolving happens, as well as continue processing with more rules afterwards.</p>
<p>Currently molt only supports one variable :</p>
<p><code>NB[:digits[:start[:increment]]]</code> : resolves to a number, starting at <code>start</code>
(default: 1) and incremented by <code>increment</code> (default: 1; can be negative) for
each file using it. The number will have at least <code>digits</code> digits, padded with
zeros.</p>
<p>This means that is you use the variable on only some of the files (e.g. through
a rule like <code>--sr</code>) then counter will only be incremented for each of those
files, "skipping" the files whose name doesn't include the variable.</p>
<p>However, if used multiple times within the same name, it'll only be incremented
once.</p>
<p>As with rules, plugins can provide new variables as well. Speaking of which,</p>
<h3>plugin: magicvar</h3>
<p>molt comes with plugin support, so new rules and/or variables can be added
easily. And since I wanted to make one, both as an example and a way to make
sure the whole thing worked as expected, molt comes with a plugin called
magicvar.</p>
<p>What it does is provide a new variable, whose name is a underscore. The idea is
that this variable requires one parameter, which is the "actual name" of the
variable you want to include. And resolving it will be done through an external
process.</p>
<p>For example, let's say you want to be able to use a variable "type" to get the
type of file, as returned by command <code>file</code></p>
<p>First you need to create a configuration file, in <code>~/.config/molt/magicvar.conf</code>
and within section <code>variables</code> you define which command line shall be run to
resolve the variable. You can use <code>%F</code> as placeholder for the path/filename of
the file, as well as <code>%P</code> for any additional parameters given to the magic
variable (in molt's new name).</p>
<p>For example, with:</p>
<pre><code>[variables]
type=file -b %F
</code></pre>
<p>Then, using <code>$_:type$</code> in molt will have magicvar run <code>file -b</code> for each file,
and use its output as value for the variable (auto-stripping the trailing \n).</p>
<p>This could e.g. be used to get EXIF data from pictures, ID3 tags from MP3 files,
that sort of things. (Although a dedicated plugin might be better/faster,
especially since it could cache data, to e.g. read the file once for all
possible variables.)</p>
<h3>Output & return value</h3>
<p>molt provides two outputs that can be of use from scripts: only the new names of
files (or, if they haven't - or couldn't - be renamed, their current names), or
both their old and new names.</p>
<p>It returns 0 in case of success, else uses bit fields with the following :</p>
<p>1 Syntax error (e.g. invalid option, etc)</p>
<p>2 File not found</p>
<p>4 Rule failed</p>
<p>8 Invalid new name</p>
<p>16 New name already in use</p>
<p>32 Internal conflict (multiple files with the same new name)</p>
<p>64 Rename operation failed</p>
<h3>Important</h3>
<p>molt is not an advanced <code>mv</code>, it is a (batch) renaming utility, and as such only
ever tries to <u>rename</u> files (whereas mv can also effectively <u>move</u> files).</p>
<p>While with certain options it can also seems like it moves file, this will only
work if said files remain on the same file system. Trying to have a file moved
to another file system is likely to fail with an error such as "Invalid
cross-device link"</p>
<h3>Download</h3>
<p>There you go. Hopefully this might be useful to some. molt is released under GNU
GPL v3+ The source code is available on <a href="https://bitbucket.org/jjacky/molt" title="molt @ BitBucket.org">this BitBucket
repository</a>.</p>
<p>You can also find <a href="https://aur.archlinux.org/packages.php?ID=57775" title="AUR: molt">a PKGBUILD in the
AUR</a>.</p>
<p>And of course bug reports, suggestions or any other form of constructive
criticism is very much welcome.</p>
Keep Arch Linux Up-to-date with kalu2012-03-15T00:00:00+00:00http://jjacky.com/2012-03-15-keep-arch-linux-up-to-date-with-kalu<p>Keeping one's system up-to-date is something that should be done regardless of
one's system. It's not that it's more true with <a href="https://www.archlinux.org" title="Arch Linux">Arch Linux</a>, just that
updates are (likely to be) more frequent, due to its rolling-release nature.</p>
<p>One way to do so is to remember to manually do a <code>syu</code> (or whatever alias you
have set for <code>sudo pacman -Syu</code>), but that might not be ideal. If you work
within a X session, using an upgrade notifier might feel like a very logical
solution.</p>
<p>There are already a few "update notifier" out there, which will run in the
background and let you know as soon as a package has been updated, but I
couldn't find one that would fit my needs (granted I didn't search too hard, I
was also interested in making my own as a fun exercice...) so I decided to make
a new one.</p>
</p>
<h3>Introducing kalu</h3>
<p>I already <a href="/2012-02-14-kalu-keeping-arch-linux-up-to-date" title="kalu: Keeping Arch Linux Up-to-date">posted about
kalu</a> a little while ago, but at the time it
was still in development stage. It has now hit stable status, so I figured I
might make a little post about it.</p>
<p>kalu (which could stand for "Keeping Arch Linux Up-to-date") is a small
application that will add an icon to your systray and sit there, regularly
checking if there's anything new for you to upgrade. As soon as it finds
something, it'll show a notification to let you know about it. Very classic
stuff.</p>
<p><img src="/kalu/kalu-notif.png" alt="kalu: example of notification" title="kalu: example of notification" /></p>
<p>You can know whether kalu found something or not during its last check simply by
looking at its icon: if all gray, nothing was found. If blue, move your pointer
over it to see (in the tooltip) what was found. If the icon happens to "blink"
from gray to blue, it simply means kalu is currently busy.</p>
<h3>What makes kalu any different?</h3>
<p>For starter, <strong>it doesn't need root privileges</strong> to do its checking. Not because
it doesn't synchronize databases, since that would make it mostly useless, but
because it will create a temporary copy of your sync databases, sync those, and
then remove them of course.</p>
<p>The idea is not only not to require root privileges, but more importantly to
<strong>avoid putting you in a situation where you'd risk messing up your system</strong>, as
you might unknowingly end up basically doing a <code>pacman -Sy foobar</code> (which is
pretty generally understood to be a bad idea).</p>
<p>Because if kalu did sync your databases, and there were upgrades available, but
you did not apply them right away (for one reason or another, e.g. you're busy,
or were AFK when the notification poped up and didn't see it...) then your next
-S operation would really by a -Sy, event though you might not even realize it.</p>
<h3>What does it check for?</h3>
<p>kalu can check for a few things :</p>
<ul>
<li><p><strong>Arch Linux News</strong>. To be sure not to miss an important announcement from
Arch Linux's official website.</p></li>
<li><p><strong>Available upgrades for installed packages</strong>. That is, anything from one of
the repos, or what would be upgraded with a <code>pacman -Syu</code></p></li>
<li><p><strong>Available upgrades for non-installed packages</strong>. You can define a list of
"watched packages", that is packages for which you'd like to be notified when
an upgrade is out, even though they're not installed. (E.g. packages you
repack for yourself to apply a patch or something)</p></li>
<li><p><strong>Available upgrades for AUR packages</strong>. All foreign packages (i.e. not found
in any repo, aka <code>-Qm</code>) can be checked for upgrades available in the AUR.</p></li>
<li><p><strong>Available upgrades for watched AUR packages</strong>. Just like with "regular"
packages, you can have a list of packages in the AUR for which you'd like to
be notified when an upgrade is available, even though they're not installed.</p></li>
</ul>
<p>Of course you don't have to use all of this, and you can define which of those
checks kalu should do. Besides maintaining lists of watched (AUR) packages, you
can also define a list of foreign packages that kalu should not check the AUR
for. Since there's no reason to check for packages you know aren't from the AUR
(e.g. packages of your own making).</p>
<h3>When does it check?</h3>
<p>You can define how often kalu should run its automatic checks, from few minutes
to days (or more). You can also, of course, have them run at any time though
menu <u>Check for Upgrades</u>.</p>
<p>Automatic checks are good if you're in front of the screen, so you can see the
notifications and act of them (or not). But even if you have your computer on
24/7, chances are you still go to bed at some point. Since there's no reason to
have kalu keep checking for upgrades then, you can define a period of time
during which no automatic checks will be performed (e.g. nothing from 11 p.m.
till 8 a.m.).</p>
<h3>Notifications</h3>
<p>Whenever something is found, kalu will show a notification. Each check has its
own notification, defined using a template.</p>
<p>All templates are made of 3 fields: Title, Package (or News item), and
Separator. Title will be the title of the notification. Package (News item) is
the text corresponding to one package/news item. It will be repeated for each
package/news item, separated using Separator, to make the body of the
notification.</p>
<p>Each field can have none, one or more variables. They are not the same for all
templates, but basically you have the package name, its old/current version
number, the new version number, and (if applicable, i.e. not for AUR packages)
the download, installed and net (post-installation difference) sizes. <u>(For a
bit more information, check out kalu's man page.)</u></p>
<p>Notifications for upgrades & AUR upgrades can also feature a button to start the
corresponding upgrade. This button can be used to simply trigger a process of
your choosing, e.g. you could have it start pacman with something like <code>urxvt -e
sudo pacman -Syu</code></p>
<p>While for AUR upgrades there is no more option, for upgrades you can decide to
use <strong>kalu's own system updater</strong>, which does exactly the same, only in a GTK
GUI.</p>
<h3>Checking is good. Upgrading too.</h3>
<p>kalu's updater aims to provide a way to upgrade your system (like a <code>pacman
-Syu</code> would) from a GUI. It doesn't do anything else (i.e. it's not a package
manager, and can't be used to install or remove packages).</p>
<p>Before being able to synchronize your databases (and possibly upgrade the
system) the updater will obviously require root privileges. The way it works is:
<strong>kalu itself only contains the GUI</strong>, and the part that does interact with
libalpm (to actually upgrade your system) is in a secondary binary
(<code>kalu-dbus</code>). Only this binary requires root privileges, will be started
through <strong>DBus</strong> and rely on <strong>PolicyKit</strong> to ensure you are authorized before
doing anything.</p>
<p>Obviously this requires you to have PolicyKit installed, but also (assuming
default configuration) a PolicyKit agent, which is the one in charge of asking
for your/root password and making sure you don't just press random keys and
whatnot.</p>
<p>You can also define one or more processes to be run after completing a system
upgrade (to start e.g.
<a href="https://aur.archlinux.org/packages.php?ID=11975" title="AUR: localepurge: Script to remove disk space wasted for unneeded localizations">localepurge</a>
and/or
<a href="/2012-01-17-pkgclip-does-your-pacman-cache-need-a-trim" title="PkgClip: Does your pacman cache need a trim?">PkgClip</a>), and kalu will ask whether to
start them or not. In case you specify more than one, the full list will be
featured and you will be able to determine which (if any) to start each time.</p>
<h3>Screenshots</h3>
<p>Because people love screenshots, right? :-)</p>
<p><img src="/kalu/kalu-ss5.png" alt="kalu: Manage Watched Packages" title="kalu: Manage Watched Packages" /></p>
<p><img src="/kalu/kalu-ss6.png" alt="kalu Preferences: General" title="kalu's Preferences: General" /></p>
<p><img src="/kalu/kalu-ss7.png" alt="kalu Preferences: Upgrades" title="kalu's Preferences: Upgrades" /></p>
<p><img src="/kalu/kalu-ss8.png" alt="kalu Preferences: AUR" title="kalu's Preferences: AUR" /></p>
<p><u>(And there are a few more in <a href="/2012-02-14-kalu-keeping-arch-linux-up-to-date" title="kalu: Keeping Arch Linux Up-to-date">the original post
here</a>).</u></p>
<h3>Download</h3>
<p>There you go. Hopefully this might be useful to some. As hinted above, DBus and
PolicyKit (including a running PK agent) are required for kalu to work. It also
requires libalpm 7 (pacman 4), cURL, libnotify (and a notify daemon if you wanna
see something, obviously) as well as GTK3.</p>
<p>Thanks to the Pacman development team for their great work and nice code; Thanks
to Dave Gamble for his JSON parser; And thanks to Painless Rob for <a href="https://bbs.archlinux.org/viewtopic.php?id=130839" title="Arch icons (slightly cartoony) @ Arch Linux Forums">his great
icon</a>.</p>
<p>kalu is released under GNU GPL v3+ The source code is available on <a href="https://bitbucket.org/jjacky/kalu" title="kalu @ BitBucket.org">this
BitBucket repository</a>.</p>
<p>You can also find <a href="https://aur.archlinux.org/packages.php?ID=56673" title="AUR: kalu">a PKGBUILD in the
AUR</a>.</p>
<p>And of course bug reports, suggestions or any other form of constructive
criticism is very much welcome.</p>
kalu: Keeping Arch Linux Up-to-date2012-02-14T00:00:00+00:00http://jjacky.com/2012-02-14-kalu-keeping-arch-linux-up-to-date<p>One thing you (should) do quite often, as a good <a href="https://www.archlinux.org" title="Arch Linux">Arch Linux</a> user, is
upgrade your system. Arch is, after all, a rolling-release distribution. As a
result something one ends up doing often is <code>sudo pacman -Syu</code> (in fact, if
you're like me, lazy, you probably have an alias set, e.g. <code>syu</code>)</p>
<p>There are already a few "update notifier" out there, which will run in the
background and let you know as soon as a package has been updated, but I
couldn't find one that would fit my needs (granted I didn't search too hard, I
was also interested in making my own as a fun exercice...) so I decided to make
a new one.</p>
</p>
<h3>Introducing kalu</h3>
<p><u><strong>IMPORTANT</strong>: this is version 0.0.1 because it is still in beta stage. It
works, but there's probably bugs crawling in there, and it's not quite finished
yet. But I figured I might as well share it now, and see what happens. Whatever
happens though, I'm not responsible. :-)</u></p>
<p>kalu (which could stand for "Keeping Arch Linux Up-to-date") is a small
application that will add an icon to your systray and sit there, regularly
checking if there's anything new for you to upgrade. As soon as it finds
something, it'll show a notification to let you know about it. Very classic
stuff.</p>
<p><img src="/kalu/kalu-notif.png" alt="kalu: example of notification" title="kalu: example of notification" /></p>
<p>You can know whether kalu found something or not during its last check simply by
looking at its icon: if all gray, nothing was found. If blue, move your pointer
over it to see (in the tooltip) what was found. If the icon happens to "blink"
from gray to blue, it simply means kalu is currently busy.</p>
<h4>So what makes kalu any different?</h4>
<p>For starter, <strong>it doesn't need root privileges</strong> to do its checking. Not because
it doesn't synchronize databases, since that would make it mostly useless, but
because it will create a temporary copy of your sync databases, sync those, and
then remove them of course.</p>
<p>The idea is not only not to require root privileges, but more importantly to
<strong>avoid putting you in a situation where you'd risk messing up your system</strong>, as
you might unknowingly end up basically doing a <code>pacman -Sy foobar</code> (which is
pretty generally understood to be a bad idea).</p>
<p>Because if kalu did sync your dbs, and there were upgrades available, but you
did not apply them right away (for one reason or another, e.g. you're busy, or
were AFK when the notification poped up and didn't see it...) then your next -S
operation would really by a -Sy, event though you might not even realize it.</p>
<h4>Checking more packages than are installed</h4>
<p>kalu also includes a feature where it can check for other packages than the ones
installed, called "<u>watched packages</u>." The idea is that you might wanna keep an
eye on some packages, and know whenever they're updated, even though they are
not installed. (E.g. because you recompile said packages or something, but
didn't subscribe to upstream's mailing list.)</p>
<p>kalu can maintain a list of packages (name & version) and check whether or not
an upgrade is available. If so, a notification will let you know about it, and
you can very easilly decide to mark it seen (i.e. update the version number
tracked) or not.</p>
<h4>Checking for AUR upgrades as well</h4>
<p>kalu can also compile the list of foreign packages (i.e. not found in any repo,
aka <code>-Qm</code>) and check to see if they are available on the AUR. If so, versions
are compared and if any upgrades if available in the AUR, as you probably
guessed, a notification will let you know about it.</p>
<p>And just like for "regular" packages, you can also have a list of "<u>watched AUR
packages</u>" which works exactly the same as watched packages, only with packages
in the AUR.</p>
<h4>Finally, the news!</h4>
<p>kalu can also check the news from the website, and - surprise - show a
notification when a new item has been posted. The notification will only include
the title, but you can click the action button to show the full news.</p>
<p><img src="/kalu/kalu-news.png" alt="kalu: Showing Unread News" title="kalu: Showing Unread News" /></p>
<p>Note that links are not (yet?) supported.</p>
<h3>Checking is good. Upgrading too.</h3>
<p>When a notification is shown, it will feature an action button. This button can
be used to simply trigger a process of your choosing, e.g. you could have it
start pacman with something like <code>urxvt -e sudo pacman -Syu</code></p>
<p>However, <strong>kalu comes with an integrated system upgrader</strong>, which does exactly
the same, only in a GTK GUI. Before being able to synchronize your databases
(and possibly upgrade the system) the updater needs root privileges, obviously.</p>
<p>The way it works is: <strong>kalu itself only contains the GUI</strong>, and the part that
does interact with libalpm (to actually upgrade your system) is in a secondary
binary (<code>kalu-dbus</code>). This binary only will require root privileges, and will
rely on <strong>PolicyKit</strong> to ensure you are authorized before doing anything.</p>
<p>Obviously this requires you to have PolicyKit installed, but also (assuming
default configuration) a PolicyKit agent, which is the one in charge of asking
for your/root password and making sure you don't just press random keys and
whatnot.</p>
<p><img src="/kalu/kalu-ss1.png" alt="kalu's updater: listing packages to upgrade" title="kalu's updater: listing packages to upgrade" /></p>
<p>The updater does what a <code>pacman -Syu</code> would, and nothing more (well, there's
<code>PostSysUpgrade</code> in the options below). It shouldn't be any faster or slower
than pacman (especially since most of the work comes from libalpm either way),
and it will also update your log (<code>pacman.log</code> that is, as defined in
<code>pacman.conf</code>).</p>
<p>Log entries coming from libalpm itself (e.g. any warning during a package
upgrade, etc) will obviously be as with pacman, anything from kalu (e.g.
indication after a database has been synchronized, or package has been
upgraded...) will have a <code>kalu:</code> prefix. When you start an upgrade, kalu first
adds an entry ("upgrading system..."), and adds one ("sysupgrade completed")
once the operation is complete.</p>
<p>During the process, another log (as in: it's not exactly what's going in
<code>pacman.log</code> but something slightly more verbose) is avalaible, any warning,
error or scriptlet output will obviously be featured there as well. (The log
will be made visible automatically if any such thing occur.)</p>
<h4>Updater Screenshots</h4>
<p>Because people love screenshots, right? :-)</p>
<p><img src="/kalu/kalu-ss2.png" alt="kalu's updater: downloading packages" title="kalu's updater: downloading packages" /></p>
<p><img src="/kalu/kalu-ss3.png" alt="kalu's updater: asking to import a key" title="kalu's updater: asking to import a key" /></p>
<p><img src="/kalu/kalu-ss4.png" alt="kalu's updater: upgrading system" title="kalu's updater: upgrading system" /></p>
<h3>Preferences</h3>
<p>Right now kalu does not include a Preferences window, but you can of course set
things manually. To do so, simply edit <code>~/.config/kalu/kalu.conf</code> where all
settings are stored. For the record, the lists of watched (AUR) packages are
stored in that same folder, as <code>watched{,-aur}.conf</code></p>
<p>String values can be quoted, which might be useful - and required - if you want
to include a space at the beginning or end of something. (Mostly useful for
templates, e.g. to do <code>Sep = ", "</code> -- see below). You can use # to comment
lines, and yes, it is all very case-sensitive</p>
<p>The main options must be set in section <code>[options]</code> :</p>
<ul>
<li><p><strong>PacmanConf</strong> : path/name to your pacman.conf -- defaults to
<code>/etc/pacman.conf</code></p></li>
<li><p><strong>Interval</strong> : the number of minutes between each auto-check -- defaults to 60</p></li>
<li><p><strong>SkipPeriod</strong> : this is e.g. in case you keep your computer on 24/7, yet go
to sleep at some point. It would then make sense that you don't want kalu to do
its checks while you're sleeping. Specify here this "skip period" during which
no (automatic) checks will be performed (Of course, you can always ask for one
manually)
The value must be formatted as "HH:MM-HH:MM" using 24h format, e.g.
"23:00-08:00" to disable auto-checks from 11 p.m. to 8 a.m.</p></li>
<li><p><strong>UpgradeAction</strong> : By default, the action button on the notification of
upgraded packages will trigger kalu's updater (1). However, you can decide
that you'd rather start something else (2) or that you simply don't want such
a button (0).</p></li>
<li><p><strong>CmdLine</strong> : With <code>UpgradeAction=2</code> the action button will start whatever you
specify here. (Note: kalu never checks the validy of what you specify here or
anything, instead it assumes you have a functionning brain.)</p></li>
<li><p><strong>CmdLineAur</strong> : Same as above, only for the notification of upgraded AUR
packages. However, here there's no Action setting: either you define
CmdLineAur and there's a button, or you don't and there isn't.</p></li>
<li><p><strong>PostSysUpgrade</strong> : When using kalu's updater, once the system upgrade has
completed you can have kalu start some extra process. This could be useful if
you have some cleaning process you wanna start (e.g.
<a href="https://aur.archlinux.org/packages.php?ID=11975" title="AUR: localepurge">localepurge</a> or something). Simply specify it here, and after an upgrade
kalu will ask you whether it should start it or not. Note: You can specify this
setting more than once. Then, the question will include the list and you'll be
able to decide which one(s) to start, if any.</p></li>
<li><p><strong>AurIgnore</strong> : You might have some foreign packages that do not come from the
AUR, and therefore checking the AUR for such upgrades is useless. Specify here
such packages and kalu will ignore them/not check the AUR for them. Use space
as separator between packages. (You can also specify this option multiple
times.)</p></li>
<li><p><strong>ManualChecks</strong> : Define what checks will be done when right-clicking on
kalu's systray icon and using "Check for Updates" This should be a list
containing one or more of the following values (using space as separator) :
UPGRADES, WATCHED, AUR, WATCHED_AUR, NEWS</p></li>
<li><p><strong>AutoChecks</strong> : Same as above, but for automatic checks.</p></li>
<li><p><strong>Verbose</strong> : The notifications can either be verbose or not. By default
("auto"), kalu checks if option <code>VerbosePkgLists</code> was enabled or not in your
<code>pacman.conf</code> to determine what to do. You can also force it off ("off") or on
("on") using this option. It will apply for notifications of upgrades.</p></li>
<li><p><strong>VerboseWatched</strong> : Same as above, but for notifications of watched packages.</p></li>
<li><p><strong>VerboseAur</strong> : Same as above, but for notifications of upgraded AUR
packages.</p></li>
<li><p><strong>VerboseWatchedAur</strong> : Same as above, but for notifications of watched AUR
packages.</p></li>
</ul>
<p>As hinted before, the notifications can either be verbose or not. You can also
tweak the templates that will be used. This is done by defining options in the
following sections :</p>
<ul>
<li><code>[template]</code></li>
<li><code>[template-verbose]</code></li>
<li><code>[template-watched]</code></li>
<li><code>[template-watched-verbose]</code></li>
<li><code>[template-aur]</code></li>
<li><code>[template-aur-verbose]</code></li>
<li><code>[template-watched-aur]</code></li>
<li><code>[template-watched-aur-verbose]</code></li>
<li><code>[template-news]</code></li>
</ul>
<p>I'll let you figure out which refers to what. In those, the following options
are supported:</p>
<ul>
<li><p><strong>Title</strong> : The title of the notification. Variables available are <code>$NB</code> for
the number of packages (or news items), <code>$DL</code> the total download size, and
<code>$NET</code> the total net (difference after installation) size. I just now realized
the total installation size isn't there, that's odd. Where's my to do list?</p></li>
<li><p><strong>Package</strong> : The package (or, for news, the news item). Repeated as needed,
and separated using the separator as defined with <code>Sep</code> (below). Variables
available are <code>$PKG</code> for the package name, <code>$OLD</code> for the old version number,
<code>$NEW</code> the new version number, <code>$DL</code> the download size, <code>$INS</code> the install
size, and <code>$NET</code> the net size.
For news items, only one variable is available: <code>$NEWS</code> for the item's title.</p></li>
<li><p><strong>Sep</strong> : The separator used between packages (news items)</p></li>
</ul>
<h3>Download</h3>
<p>Also, this is (obviously) still in beta, so beware. It should all work just
fine, in fact I've been using it for some weeks now, even doing all my system
upgrades using kalu's updater, and I'm still alive.</p>
<p>Anyhow, that's about it. Hopefully this might be useful to some. As hinted
above, DBus and PolicyKit are required for kalu to work. It also requires
libalpm 7 (pacman 4), cURL, libnotify (and a notify daemon if you wanna see
something, obviously) as well as GTK3.</p>
<p>Thanks to the Pacman development team for their great work and nice code; Thanks
to Dave Gamble for his JSON parser; And thanks to Painless Rob for <a href="https://bbs.archlinux.org/viewtopic.php?id=130839" title="Arch icons (slightly cartoony) @ Arch Linux Forums">his great
icon</a>.</p>
<p>kalu is released under GNU GPL v3+ The source code is available on <a href="https://bitbucket.org/jjacky/kalu" title="kalu @ BitBucket.org">this
BitBucket repository</a>.</p>
<p>You can also find <a href="https://aur.archlinux.org/packages.php?ID=56673" title="AUR: kalu">a PKGBUILD in the
AUR</a>.</p>
<p>And of course bug reports, suggestions or any other form of constructive
criticism is very much welcome.</p>
PkgClip: Does your pacman cache need a trim?2012-01-17T00:00:00+00:00http://jjacky.com/2012-01-17-pkgclip-does-your-pacman-cache-need-a-trim<p><a href="https://wiki.archlinux.org/index.php/Pacman" title="Pacman @ ArchWiki">pacman</a> - Arch Linux's package manager - is a great application, and one I
probably use every single day, which - given Arch's rolling release principle -
I'm sure is the case of many others as well.</p>
<p>Whenever pacman downloads a package, whether because you install something new,
or when you do an update, said packages will be stored in its cache (usually in
<code>/var/cache/pacman/pkg</code>). And then, nothing.</p>
<p>pacman will never remove anything from its cache <u>(*)</u>, and it's a good thing
because should you e.g. ever want to downgrade some package to a previous
version for one reason or another, your cache is probably the best place to find
what you're looking for.</p>
<p><u>(*) Actually, it can, but only if you ask him to. See below.</u></p>
<p>But if your cache keeps growing and only ever growing, over time it'll get
pretty fat. And while keeping old versions is good, there's no point to keep
every single version of everything you ever installed.</p>
</p>
<p>Now, you can actually do some cleaning through pacman and its <code>--clean</code> option,
but this will be pretty basic: either remove every packages but the ones
currently installed, or just remove everything. (Note: this is assuming you use
default options (<code>CleanMethod = KeepInstalled</code>), you could also used
<code>KeepCurrent</code> to keep any packages present in a sync database.)</p>
<p>When I noticed my pacman's cache kept growing, I wondered if I couldn't trim it
a little bit. Not get rid of everything, and keep more than what a <code>pacman -Sc</code>
would do, but still remove unneeded packages. And so I made <strong>PkgClip</strong>.</p>
<h3>Find a reason for your action</h3>
<p><strong>PkgClip</strong> is a little helper utility that will scan pacman's cache, and
classify every package into different groups, also called "reasons." Reasons,
because they'll be used to determine whether a package should be kept, or
removed. (Well, to determine the recommended action, up to you to go with it or
not, of course.)</p>
<p><u>Note: All packages usually have a version number, that of the installed
software, alongside a package release number. That is, package <code>foobar-1.2.3-4</code>
would be for foobar v1.2.3; and it is the fourth package release for that
version.</u></p>
<p>For each package, PkgClip will check whether or not it is installed on the
system. The test will determine whether this version of the package is
installed, or another one. Based on this, each package will fall under one of
the following :</p>
<ul>
<li>Package of a version more recent than the one currently installed; Marked to
<strong>Keep</strong>.</li>
<li>Package of the currently installed version; Marked to <strong>Keep</strong></li>
<li>Package of the same version but a previous package release (pkgrel); Marked to
<strong>Remove</strong></li>
<li>Package of an older version. You can define how many of those you'd like to
keep. As many will be marked to <strong>Keep</strong>, any other (i.e. the oldest ones, of
course) will be marked to <strong>Remove</strong></li>
<li>Package for which no version is currently installed; Marked to <strong>Remove</strong></li>
</ul>
<p><img src="/pkgclip/pkgclip.png" alt="PkgClip Screenshot" title="PkgClip Screenshot" /></p>
<p>As a result, you might have quite a few packages marked to be removed, but still
keep a few more than what <code>pacman -Sc</code> would do. Of course you can tweak this
selection:
- You can define how many older versions to keeping
- You can set not to remove old package releases, that is a package of the same
version but a previous package release will simply be treated as an old
version
- Finally, all of this only defines the recommended/default values for each
packages. You can obviously then review the list and manually add/remove
packages to be removed as you wish.</p>
<h3>Actual removal of the files: PolicyKit required</h3>
<p>As you probably know, you cannot actually just run <code>pacman -Sc</code> from your
terminal, if you're logged in as a regular user. Because those files belong to
root and therefore root privileges are required to do anything.</p>
<p>PkgClip is not intended to be run as root of course, and will rely on
<strong>PolicyKit</strong> to ensure correct authorization has been granted. Obviously it
requires you to have PolicyKit installed, but also (assuming default
configuration) a PolicyKit agent, which is the one in charge of asking for
your/root password and making sure you don't just press random keys and whatnot.</p>
<h3>Download</h3>
<p>That's about it. Everything should be pretty straight-forward; hopefully this
might be useful to some. As hinted above, DBus and PolicyKit are required for
PkgClip to work. It also requires libalpm 7 (pacman 4) and GTK3.</p>
<p>PkgClip is released under GNU GPL v3+ The source code is available on <a href="https://bitbucket.org/jjacky/pkgclip" title="PkgClip @ BitBucket.org">this
BitBucket repository</a>.</p>
<p>For Arch Linux users, you can also find <a href="https://aur.archlinux.org/packages.php?ID=55870" title="AUR: pkgclip">a PKGBUILD in the
AUR</a>.</p>
<p>And of course bug reports, suggestions or any other form of constructive
criticism is very much welcome.</p>
Scrolling/mouse wheel improvments (VTE-like) in urxvt2011-12-19T00:00:00+00:00http://jjacky.com/2011-12-19-scrolling-mouse-wheel-improvments-vte-like-in-urxvt<p>When I started, and having decided to use <a href="http://xfce.org/" title="XFCE Desktop Environment">XFCE</a>, I did originally
install it with a lot of what it comes with. That is, I used the panel of
course, which I still use & like very much, but also XFCE's own window manager
(<code>xfwm4</code>), terminal emulator (<code>terminal</code>), and more.</p>
<p>Over time though, I did not keep using all that. I kept some things because I
liked them, such as <code>xfce4-panel</code> or <code>xfwm4</code> (<a href="/2011-12-12-xfce-window-manager" title="XFCE Window Manager">which is full of nice
tricks</a>), others I
removed because I didn't see a need for (<code>xfce4-session</code>), and others I
replaced, like <code>terminal</code>. If I decided to look for a replacement, it was
because of a little bug that would regularly occur, and annoy me.</p>
<p>But once I found <code>rxvt-unicode</code>, aka <code>urxvt</code>, I realized that even if that bug
got fixed, I would not go back. urxvt is really a nice terminal emulator, comes
with a lot of options and I am really enjoying using it every day. It would
pretty much be perfect, if it wasn't for one thing, one pretty annoying little
thing...</p>
</p>
<h3>Mouse wheel: it scrolls, and only that</h3>
<p>As much as I use a terminal, which is obviously keyboard-driven, I still like my
mouse. And I use it frequently, including when I'm using a terminal. Like pretty
much all other emulators, <strong>urxvt supports using the mouse wheel to scroll in
the terminal's buffer; But, unlike some others, that is all it does.</strong> Some
other terminals, specifically all VTE-based terminals (such as XFCE's
<code>terminal</code>), allow for more.</p>
<p>When running an application that uses the "secondary screen"<u>(*)</u> those
terminals will disable their scrollbar, and instead you can use the wheel to
interact with said application. For example, when in <code>less</code> or <code>man</code> you can
scroll around using the mouse wheel. And it's a really nice thing, because it
feels very natural (to me, at least).</p>
<p><u>(*) not sure whether this is the "official" term or not, but at least that's
how it's called in urxvt.</u></p>
<p>And it is the one thing that always annoyed me about urxvt: even in such
applications, the mouse wheel will simply scroll through urxvt's own buffer. So
I finally decided to grab the source code and have a look, and lucky enough it
turned out to be pretty easy to change things.</p>
<h3>Introducing a new option: secondaryWheel (ssw)</h3>
<p>Yeah, that name might not be the best, but it goes along side <code>secondaryScreen</code>
(<code>ssc</code>) - which is obviously required for this to work at all - as well as
<code>secondaryScroll</code> (<code>ssr</code>) - with which, IMHO, it is somewhat related. So, there
you go.</p>
<p>What this new option does, is pretty simple: when using the mouse wheel, <strong>if
you're on secondary screen then no scrolling will occur, and instead some (3, to
be exact) "fake" keystrokes will be sent to the running application</strong>. So, a
wheel up will have the same result as pressing the Up key three times, and wheel
down will do the same as pressing 3 times the Down key.</p>
<p>Easy enough, but that does the trick: now when running <code>man</code>, <code>less</code> or any
other application that uses the secondary screen, you can use the mouse wheel to
move around (or whatever said application would do, if you pressed the Up/Down
keys). It should be noted that I'm not sure this is actually how things are done
in VTE-based terminals - I never checked - but this does the job, so it works
for me.</p>
<p>This is just another option (disabled by default), so you can either use it from
command-line (<code>ssw</code>), or specify it in your <code>.Xdefaults</code> using it's long-name:
<code>secondaryWheel</code></p>
<p>Like I mentioned earlier, I believe this option is related to <code>secondaryScroll</code>,
as in it works best if you disable it, while enabling <code>secondaryWheel</code> That way,
not only can you use your mouse wheel to scroll around in those applications,
but whatever you do here will not "mess up" your scrolling buffer (on primary
screen). That's how I use it, and I really like it that way.</p>
<h4>Clear patch, by rlblaster</h4>
<p>And to be really perfect, there's another little change that can be done. When
resetting the terminal (Ctrl+L), by default urxvt simply moves the cursor on top
of the window, and clears everything that was there. Meaning that as a result,
<strong>it can cut off some of your buffer</strong>, as those lines are just cleared.</p>
<p>To fix this, rlblaster on the Arch Linux forums <a href="https://bbs.archlinux.org/viewtopic.php?id=129302" title="urxvt patch: VTE like clear screen behavior @ Arch Linux Forums">shared a nice
patch</a> that will,
before hand, add lines, <strong>thus allowing to keep your full scrolling buffer
intact</strong>.</p>
<p>It looks the same, except that when scrolling up everything is there, nothing
was cut.</p>
<h3>Download</h3>
<p>The modified source code is available on <a href="https://bitbucket.org/jjacky/rxvt-unicode-jjk" title="rxvt-unicode with scrolling/mouse wheel improvments @ BitBucket.org">this BitBucket
repository</a>. This is
what I use, so it includes both my changes (<code>secondaryWheel</code>) as well as the
modifications by rlblaster (from his <code>clear.patch</code>)</p>
<p>For Arch Linux users, you can also find <a href="https://aur.archlinux.org/packages.php?ID=55097" title="AUR: rxvt-unicode-better-wheel-scrolling">a PKGBUILD in the
AUR</a>, which uses the official source code
and both patches to get there, simply because I figured it would allow people to
check the changes more easily.</p>
<p>Note: The PKGBUILD includes both patches, and also uses different compilation
options (than the official package) to disable utmp/wtmp support and tabbed
support. This is mainly because I don't use those, plus I beleive that utmp/wtmp
doesn't actually work anyway (it would require setuid to be set, which isn't the
case in the official package. Though, I did include the required lines
(commented out) in the PKGBUILD; should you want to use it, you can simply
uncomment them, and don't forget to change the options as well).</p>
<p>And of course bug reports, suggestions or any other form of constructive
criticism is very much welcome.</p>
XFCE Window Manager2011-12-12T00:00:00+00:00http://jjacky.com/2011-12-12-xfce-window-manager<p>I am using <a href="http://xfce.org/" title="XFCE Desktop Environment">XFCE</a> as my Desktop Environment, and that includes XFWM -
XFCE's own window manager. I could have used another one, but I find XFWM to be
quite good.</p>
<p>I did look briefly at what other WMs are out there, and what I pretty much ended
with was that a <a href="http://en.wikipedia.org/wiki/Compositing_window_manager" title="Compositing window manager @ Wikipedia">Compositing window
manager</a> would be best (XFWM is one), and not
just for fun visual effects. Actually, if that's what you're looking for
<a href="http://www.compiz.org/" title="Compiz">Compiz</a> might be what you want to give a try.
But I'm not really looking for all those visual effects, and XFWM offered what I
needed, so I didn't see the need to look for anything else.</p>
<p>Having been using it for a little while now, I did however figure out a few nice
tips & tricks that I thought I might share. Some might be quite known, and/or
even common with other WMs, but either way they're pretty nice and might come in
handy every once in a while.</p>
</p>
<h3>Moving a window without decorations (or whose decorations aren't available)</h3>
<p>This is how I started looking for such tricks: in one application, a window
would open and be misplaced, probably because of my dual monitor setup and a bug
in the window placement of said application. It was a problem because I could
only see the lower half or so of the window.</p>
<p>Moving a window isn't usually a problem, but in this case I obviously couldn't
use the title bar, since it was not visible, the whole upper-half of the window
being "outside" of my monitor. And because this wasn't a top-level window, it
didn't appear in the XFCE-Panel, so I couldn't use that to trigger a move
operation either.</p>
<p>I know that <a href="http://openbox.org/" title="Openbox">Openbox</a> also supports right-click
on window's border, to popup its menu, but XFWM only does it from the title bar.
But fear not, as it does, however, offer quite a few ways to get things done,
even without any decorations.</p>
<p>For starter, you can <strong>middle-click-and-drag from the window's border to move
it</strong>. Just like you would usually click-and-drag from the border to resize a
window, but using the middle button instead of the left one. And of course, the
right button also does something of its own: you can <strong>right-click-and-drag to
resize a window without activating it</strong>.</p>
<p>But it doesn't stop there, as you can also <strong>move a window by simply holding Alt
and click-and-drag from anywhere the window</strong>. This is especially usefull for
windows without decorations (and thus, not even borders). Hold Alt, and you
shoud be able to click-and-drag from anywhere in the window to move it around.
You can also <strong>Hold Alt and double-click anywhere in the window to (un)maximize
it</strong>.</p>
<p>This can be quite nice, for instance if you have a decoration-less terminal
window, you can (un)maximize it & move it around very easily.</p>
<p>But it gets better!</p>
<p>As you might have guessed now, using other buttons will get you different
results: <strong>hold Alt and rght-click-and-drag will resize the window</strong> but wuth a
trick: the result will depend on where you clicked in the window. That is, if
you clicked in the upper side of the window, you'll resize it as if you
left-clicked on the top border. <strong>If you clicked on the right side of the
window, it'll be as if you used the right border, and so on.</strong></p>
<p>Again, this allows you to resize at will any window, even when it doesn't have
any border/decorations. And yes, holding Alt and using the middle-click will do
something else: it sends the window behind all other windows.</p>
<h3>Different kinds of maximize</h3>
<p>Another nice little thing, that does requires decorations this time. About every
WM out there offers a Maximize button as part of the window decorations. But
XFWM allows you to have some other kind of maximize. That is, you can
<strong>middle-click the maximize button to only maximize the height of the window</strong>,
while leaving the width unchanged. Which might come in handy when you have e.g.
a terminal with a file or a man page opened. Similarly, you can also
<strong>right-click the maximize button to only maximize the width of the window</strong>,
leaving its height unchanged.</p>
<p>I'm not exactly sure whether all this is (well-)known or not, since when I
looked on XFCE's website I couldn't really find much about such XFWM
features/tricks, so hopefully this might be useful to some of you. And if you
happen to know other tricks I missed/am not aware of yet, please let me know.</p>
<h4>And also...</h4>
<p>Couple other things, that for some reason I feel are more known, but might not
be:</p>
<ul>
<li>Wheel up/down over the titlebar to roll the window up/down</li>
<li>Hold Alt and use the wheel over the title bar to change the window's opacity</li>
</ul>
<h3>Hover effect for inactive windows, too</h3>
<p>The only little thing that XFWM does not do, and that I really would have liked,
was a visual effect: When hovering titlebar's buttons, there is usually a little
effect. It's just a visual thing, but it also "confirms" which button you're
about to click, and - maybe as a Windows user - I'm used to it, and to rely on
it to check responsiveness and whatnot.</p>
<p>Anyways, <strong>while XFWM does support such a thing</strong> (depends on your theme,
actually), <strong>it does so only for the active window</strong>. Inactive windows, or their
decorations/button, will not react to mouse hovering. So I looked into it, and
<strong>while this isn't supported by XFWM, it's quite easy to change it</strong>.</p>
<p>So I did, and as usual the modified source code is available on <a href="https://bitbucket.org/jjacky/xfwm4-jjk" title="XFWM with hover effect for inactive windows @ BitBucket.org">this BitBucket
repository</a>.</p>
<p>For Arch Linux users, you can also find <a href="https://aur.archlinux.org/packages.php?ID=54787" title="AUR: xfwm4-hover-inactive">a PKGBUILD in the
AUR</a>, which uses the official source code and a patch to
get there, simply because I figured it would allow people to check the changes
more easily.</p>
pmount & safe removal of USB device2011-11-21T00:00:00+00:00http://jjacky.com/2011-11-21-pmount-and-safe-removal-of-usb-device<p>When you plug an USB device on your computer, under Windows it automatically
becomes available. Under Arch, not so much. It makes sense, I didn't
install/configure anything to do so, so why would it?</p>
<p>So I started wondering about auto-mounting of USB devices, although I must admit
that I'm not a fan of such automated tasks, just like I hate (and always
disabled) any & all form of autorun that Windows provides. (And on a side note,
it's also a potentially major security risk. I think I read recently that
Microsoft concluded that by simply turning that damn autorun off, people would
see a huge drop (around 50% or something) of virus/malware infections.)</p>
<p>Anyways, I don't really mind having to mount things. Right now I need to call
<code>mount</code> whenever I put a CD/DVD in the drive, why should it be any different for
an USB device? But the thing is, with a CD I only need to call <code>mount</code> and
<code>umount</code> to do the work, no need for <code>sudo</code> Which begs the question, why should
it be any different for an USB device?</p>
</p>
<h3>Enters pmount</h3>
<p><a href="http://pmount.alioth.debian.org/" title="pmount: mount removable devices as normal user project">pmount</a> is a great little that
will allow users to p(u)mount removable devices, USB and the likes, without the
need to call <code>sudo</code> -- Exactly what I was looking for. While giving it a try, I
did however noticed a couple of things.</p>
<p>First of all, it's a simple thing but where a CD or DVD only ever offers one
filesystem to be mounted, an USB device can have just as many partitions as an
internal drive, which can be a lot. And <strong>I wasn't too happy about having to
mount each & every one of those whenever I would need to</strong>.</p>
<p>One solution to this problem could be to have <code>pmount</code> automatically called
through an udev rule or something, so all partitions would be automounted when
the device is plugged in. Of course, we'd be back to the security risk mentioned
earlier...</p>
<p>It's a little thing, but it's there. The other thing I noticed was, on the other
hand, more of a problem to me. It seems that the only thing pumount does is
unmount without the need for sudo. It's exactly what it says it does, so no
surprises there.</p>
<p>But if for a CD it makes sense, we're talking about something else here. Because
here, <strong>it is the actual device I want to remove/unplug from the computer</strong>, and
simply unmounting any mounted filesystem seemed a little... <u>not enough</u>.</p>
<h3>How does one safely remove an USB device, in Linux?</h3>
<p>Question I asked myself, and then turned to the Internet. Apparently, a lot of
people are fine with, and only do unmount the filesystem before unplugging their
device.</p>
<blockquote>
<p>Simply call umount and you can turn it off/unplug it.</p>
</blockquote>
<p>A common answer I found here & there, when looking for a way to safely remove an
USB device on Linux. People would sometimes add a note about how they've been
doing it for years without problems.</p>
<p>Great, but somewhat unsatisfying. I mean, after all on Windows - to come back to
what I'm used to - I do need to click on the "Remove device" option before I
unplug anything, and that <strong>even when the drive has no partition on it</strong>. And
therefore, nothing is/can be mounted, so clearly Windows does <u>more</u> than just
mounting whatever needs to be unmounted.</p>
<p>In fact, sometimes the device actually let you know it is ready to be unplugged:
a LED goes off, or you hear it spinning down, something. Things that obviously
do not happen after a simple call to <code>umount</code></p>
<h3>Unmounting is good, but not enough</h3>
<p>Unmounting any mounted filesystem is good, required even, but it's only the
first step. I found <a href="http://elliotli.blogspot.com/2009/01/safely-remove-usb-hard-drive-in-linux.html" title="Safely remove an USB hard drive in Linux">a great post by Yan
Li</a> where he described all <strong>the <u>four</u>
steps that needs to be done before a device can be safely removed</strong> (okay,
three, as the last one is optional) :</p>
<blockquote>
<p>From the hardware aspect, the drive should only be removed when the following
requirements are met:</p>
<ol>
<li>there's no pending I/O request and software cache flushed</li>
<li>it's hardware cache flushed</li>
<li>it's driver spins down (means "not spinning")</li>
<li>(optional) the USB port is put into "suspend" mode</li>
</ol>
</blockquote>
<p>Unmounting the filesystem will obviously take care of the first step, but that's
all it does. To go further, one then needs to unbind the device from the driver
- which, <a href="https://lkml.org/lkml/2009/1/2/173" title="Re: Enable CONFIG_USB_SUSPEND by default or some mobile HD can't be unplugged safely">according to Alan Stern</a>,
will have the Linux kernel automatically "send a SYNCHRONIZE CACHE command
followed by START-STOP (if the device supports it)" - after which one can then
tell the USB core driver to put that device into suspend mode.</p>
<p>Li also provides <a href="https://github.com/liyan/suspend-usb-device/blob/master/suspend-usb-device" title="Yan Li's suspend-usb-device script @ GitHub">a little
script</a> that accomplishes all those
steps. I tried it a little, and it seems to work as advertised. When used with a
device that beeps when it can be unplugged, I got the magic beep. I also noticed
that the device was gone from <code>/dev/</code> afterwards (and before unplugging it), a
natural result of unbinding the driver.</p>
<p>So this seems to be not just a better solution than a simple call to (p)umount,
but the right way to (fully) do things. To quote Li again,</p>
<blockquote>
<p>I know electronic devices are <strong>fragile</strong>, <strong>rigid</strong> and <strong>obtuse</strong> if you
don't use them as the way they are designed. For a well-designed and robust
piece of hardware, theoretically you can disconnect the device safely when the
first two steps are done. The firmware on the device would notice the USB cable
was unplugged and shut down the disk drive properly. If not, the drive would be
stopped sharply as if you pulled it's power when it's running and this damages
the hardware gradually. As an outsider of the manufacturer, we hardly know
whether it's well-designed or not so the only safe principle is to follow it's
manual, means we should not disconnect the device until at least all three
steps are done.</p>
</blockquote>
<p>And since most of my USB devices happen to be drives where I hold precious data,
I'd rather do things right, just in case.</p>
<h3>pmount, the return</h3>
<p>I then knew what I has been looking for, had the steps to safely remove an USB
device, so I decided to try and modify pmount a little bit. The reason behind
this was not only to have only one tool to do the job, but also that Li's
script, while it works fine, requires root privileges, therefore <code>sudo</code>. Since
pmount already allows to deal with things without such a requirement, I figured
it might be a good idea.</p>
<p>So I added a new option <code>-D</code> that will do the following:</p>
<ul>
<li>in pmount : it will mount all the partitions of the specified device.</li>
<li>in pumount : it will unmount all the partitions of the specified device, and
then make it safe to be removed.</li>
</ul>
<p>In pmount, what it means is that when you call e.g. <code>pmount /dev/sdd1</code> and here
happen to be two more partitions on that device, they will both also be mounted.
You could as well have used either one of those, or even <code>/dev/sdd</code> and would
have gotten the exact same result. This is just to allow mounting of all
partitions of a drive without the need to do each one manually (or use some sort
of automounting).</p>
<p>In pumount, it's the same but in reverse. Similarly you can use either
<code>/dev/sdd</code> or any of the partitions (e.g. <code>/dev/sdd2</code>) or, in typical pumount
fashion, use a mount point, e.g. <code>/media/sdd2</code> It will always (try to) unmount
all the mounted partitions of the device.</p>
<p>Then, unless there was an error, it will also do those four steps to prepare the
device for safe removal. That is:</p>
<ul>
<li>Calls <code>sync()</code> to flush buffers</li>
<li>Unbinds the driver (which, as discussed earlier, takes care of sending the
SYNCHRONIZE CACHE and START-STOP messages to the device)</li>
<li>Suspend the device</li>
</ul>
<p>This is all done according to the discussion and script by Yan Li. And in pure
pmount fashion, you don't need to use <code>sudo</code> to get this done, unlike with the
previously mentioned script.</p>
<h3>/etc/pmount.conf for some configuration</h3>
<p>I also did something else, and introduced the use of a configuration file, in
<code>/etc/pmount.conf</code></p>
<p>Because while I could p(u)mount my USB drives easily now, and safely unplug them
as well, there was one more thing I would have liked: I wanted to mount them
outside of <code>/media/</code> Also, I intend to use LUKS-encrypted partitions, and I
figured it would be nice if those drives were mounted automatically without the
need for me to enter a passphrase <u>(*)</u>.</p>
<p><u>(*) After all, It's already how it works for internal drives. Once I enterred
the passphrase for the root file system, other partitions are LUKS decrypted
using key-files (found in <code>/root/</code>).</u></p>
<p>pmount offers a command-line option to specify a file to use for passphrase,
instead of prompting the user. So I decided to introduce a configuration file
where a few options could be defined, options that would take precedence over
default & command-line arguments.</p>
<p>This file (<code>/etc/pmount.conf</code>) has a structure somewhat similar to an INI file:
sections defined using a name in between square brackets (<code>[ ]</code>), then one or
more options defined simply in format <code>name=value</code></p>
<p>The name of the sections must be a way to identify the partition. It could be
<code>/dev/sdd1</code> although it would make more sense, I imagine, to use an entry either
in <code>/dev/disk/by-label/</code> or in <code>/dev/disk/by-uuid/</code> When mounting said
partition, pmount will take care of resolving the device name, meaning that it
doesn't have to be mounted using the same name/symlink (E.g. you could use the
UUID in the configuration file, and the label when calling pmount to mount
it...).</p>
<p>Supported options in the file are:</p>
<ul>
<li><code>fs</code> to define the file system (overwrites option <code>-t</code>)</li>
<li><code>charset</code> to define the I/O character set (overwrites option <code>-c</code>)</li>
<li><code>passphrase</code> to define the file to read passphrase from (overwrites options
<code>-p</code>/<code>--passphrase</code>)</li>
<li><code>mntpt</code> to define the mount point. Overwrites the usual way (e.g. specified
label), can be anywhere (not restricted to <code>/media/</code>)</li>
<li><code>options</code> to defines the mounting options. That is, this allows you to
overwrite the defaut options, as defined in <code>fs.c</code> <strong>No checks are done
here</strong>, so make sure not to include non-existing options, as well as not to
include any options auto-added by pmount (that is, things based on
command-line options, such as atime/noatime, exec/noexec, etc)</li>
</ul>
<p>Values should not be quoted, and comments are supported using either <code>;</code> or <code>#</code></p>
<p>In the end, with a simple call to pmount I can now have my LUKS encrypted
partitions mounted automatically; and when I'm done one call to pumount will
have them all unmounted, and the device be prepared for safe removal. I think I
now have everything I was looking for. If you're interested, it's all below.</p>
<h3>Download</h3>
<p>The modified source code is available on <a href="https://bitbucket.org/jjacky/pmount-jjk" title="pmount with safe removal option @ BitBucket.org">this BitBucket
repository</a>.</p>
<p>For Arch Linux users, you can also find <a href="https://aur.archlinux.org/packages.php?ID=54191" title="AUR: pmount-safe-removal">a PKGBUILD in the
AUR</a>, which uses the official source code and a patch to
get there, simply because I figured it would allow people to check the changes
more easily.</p>
<p>It's all released under GPL, and of course bug reports, suggestions or any other
form of constructive criticism is very much welcome.</p>
Middle-click in Firefox2011-11-21T00:00:00+00:00http://jjacky.com/2011-11-21-middle-click-in-firefox<p>It's a very common thing in Linux, but coming from Windows this was new to me:
select something, and the mere fact that it was selected/highlighted is enough
to make it available for "paste" using the middle-click. It's a common thing
that should work pretty much everywhere in Linux it seems, and once you're used
to it, it can be quite useful.</p>
<p>Firefox, my browser of choice for a few years now, naturally supports this.
However, its behavior in that matter is regulated through a couple of options,
and their default values aren't the same on Windows and Linux. On linux, both
<code>middlemouse.paste</code> and <code>middlemouse.contentLoadURL</code> default to <code>true</code> (while on
Windows both default to <code>false</code>).</p>
</p>
<p>The second one is especially nice, because it means that if you do have an URL
ready to be middle-pasted, a middle click anywhere on the current page will
automatically open said URL. Pretty nice, however there were a couple of things
I wanted:</p>
<ol>
<li>I wanted said URL to be opened in a new tab</li>
<li>I thought it would be nice if, when I have something other than a URL,
instead of doing nothing it would start a search</li>
</ol>
<h3>Middle Search</h3>
<p>The second issue was solved thanks to a nice FF extension, <a href="https://addons.mozilla.org/en-US/firefox/addon/middle-search/" title="Middle Search">Middle
Search</a> by Ivo Danihelka. This extension does exactly that: if the text
is not an URL (does not start with <code>http(s)://</code> or <code>ftp://</code>) then it will be
used as keyword in a new search, done using your default search engine.</p>
<p>The only little problem I had with it, is that - much like the native handling
of the URL - it happens in the current tab, when I'd like it to open a new tab
instead.</p>
<p>Fortunately this FF extension is made of a little JavaScript, and could be
easily modified. Even better, I could also make it take care of the case when an
URL is present, instead of letting Firefox deal with it, and therefore open it
in a new tab as well.</p>
<p>If you also want a version that opens everything (URL and searches) in a new
tab, the modified source code is available on <a href="https://bitbucket.org/jjacky/middle-search-jjk" title="Middle Search in new tab @ BitBucket.org">this BitBucket
repository</a>. You can also find <a href="https://bitbucket.org/jjacky/middle-search-jjk/downloads/middle-search-jjk-0.8.1.1.xpi" title="Middle Search in new tab">an XPI
file</a> of said version.</p>
<p><u><strong>Edit 2011-12-21</strong>: updated download link to v0.8.1.1; just a bump in version
numbers to support Firefox 9.</u></p>
<h3>Selection in the address bar</h3>
<p>One last thing about this whole issue, and again a difference in how Firefox
behaves (by default) depending on your OS. On Windows, a click in the address
bar will automatically select it all. Not so in Linux, which isn't a bad idea
considering how the whole middle-paste thing works.</p>
<p>However, on Windows when you double-click somewhere on the URL (in the address
bar), only part of it gets selected. It works on a "word" basis, which makes it
pretty easy to quickly select only a part of the URL, for example only the
domain name, or the file name. But in Linux, the double-click will select the
whole thing!</p>
<p>It annoyed me, but it doesn't anymore since, once again, this is only one
setting that can be easily changed. Open <code>about:config</code> and search for
<code>browser.urlbar.doubleClickSelectsAll</code> What it does is pretty obvious, and it
does default to <code>false</code> on Windows, but <code>true</code> on Linux. Once adjusted, the
double-click will work again on a "per-word" basis, and you will still be able
to select the whole URL with a triple-click.</p>
Choosing a display manager, or not2011-11-18T00:00:00+00:00http://jjacky.com/2011-11-18-choosing-a-display-manager-or-not<p>One thing that happens when you come to Linux from Windows, is you start seeing
the different parts that make up your system. For instance, on Windows when you
power up your computer, you have a boot logo, then you enter your password and
there's your desktop. All of that, like the rest, it's all "Windows".</p>
<p>You don't have to known about the different parts of that whole process, and
Microsoft usually likes to hide it from you anyways. In Linux, it's not that you
<strong>need</strong> to known about them, but you can. And with Arch, chances are you will.</p>
<p>It's not a bad thing though, far from it, because as with pretty much everything
else on Linux, if there's something you don't like, you can change it. Chances
are there are a few alternatives our there, and if not and assuming you have the
knowledge and time for it, you can also just make your own replacement.</p>
</p>
<p>(Also, you can sometimes get rid of things you don't need. I never had any use
for a desktop, it's always been useless to me, only used by software installers
that either didn't respect or didn't bother asking about putting shortcuts
there. And now, I just don't have one. No change for me, except a few MBs of
disk space & memory saved!)</p>
<h3>Display Managers</h3>
<p>And so I discovered the notion of Display Managers (DM), those little login
screens where you enter your login/password and that then start your XFCE
session, or whatever DE/WM you're using. Having a DM is not a requirement, you
can simply log in as always and manually type <code>startx</code> to get things started.
(You could also use an alias, like <code>x</code> or something, if you're lazy. I know I
am.)</p>
<p>Originally I started installing GDM only because I knew it a little (as in, I've
tried Fedora a little before), and it does look nice. But as I did that I also
realized that it came with a few dependencies, and thinking about it, I
wondered: why? <strong>Why would I need all that, for just a pretty window asking for
my login & password?</strong></p>
<p>So I removed it, and switched to XDM instead, which after a few tweaks did not
look too bad, and worked just as well. Also, it required much less disk space
(well, it's relative of course) than GDM. But the truth is, the question pretty
much remained.</p>
<h3>Who needs a DM anyways?</h3>
<p>It's not that XDM needs a lot of disk space, or RAM, but it obviously needs
some. And it is always running, even though I only need it for a few seconds
every once in a while (I don't turn my computer off very often...), so <strong>all in
all, it all seems like a waste</strong>. Maybe not a big one, but one nonetheless.</p>
<p>It is entirely possible that there's more to a DM than what I think of right
now, and/or that there are things it does/allows that I haven't (yet)
discovered/thought of, but as far as I can see, all I need from the DM is to log
me in and start X(FCE); that is, call <code>startx</code> (and while I don't actually use a
session manager, I don't think it would change anything if I did.)</p>
<p>Looking around about all that, two things made me get rid of XDM, and not use a
DM in the end. First of all, I started to wonder about what I would have to do
whenever there would be an update of X. I was already aware that I needed to
quit XFCE and all I had running there, which I'm not too happy about_(*)_ but
hopefully it's not updated every week, but would I also have to end/restart XDM?
Then it's starting to become a little annoyance.</p>
<p><u>(*) By which I mean, while it surely doesn't require as much time, it pretty
much feels the same as needing to reboot the whole computer as far as I'm
concerned. I still need to close every application I have running and start
over...</u></p>
<p>And of course, I figured out that using a little bash script, I could make it so
that upon login, XFCE would be started automatically without me having to even
press a single key! So really, who needs a DM?</p>
<h4>.bash_profile</h4>
<p>So how does this work? I simply added a little something in my <code>.bash_profile</code>
so that X would be started automatically when I log in, but adding a couple more
requirements:</p>
<ul>
<li>only if I'm logging in on tty2 (where I usually log in). This is so I can
still log in and stay in console, or open one alongside my XFCE session,
should I need to.</li>
<li>only when the runlevel is 5. This isn't really needed obviously, but I figured
I'd still use level 5 with the auto-launching of XFCE.</li>
</ul>
<p>Here's the result:</p>
<p><ol class="bash"><li class="li1"><div class="de1"><span class="re2">level</span>=$<span class="br0">(</span>runlevel<span class="br0">)</span></div></li>
<li class="li1"><div class="de1"><span class="kw1">if</span> <span class="br0">[</span> <span class="re5">-z</span> <span class="st0">"<span class="es2">$DISPLAY</span>"</span> <span class="br0">]</span> <span class="sy0">&&</span> <span class="br0">[</span> $<span class="br0">(</span>tty<span class="br0">)</span> = <span class="st0">"/dev/tty2"</span> <span class="br0">]</span> <span class="sy0">&&</span> <span class="br0">[</span> <span class="st0">"<span class="es3">${level:2:1}</span>"</span> = <span class="st0">"5"</span> <span class="br0">]</span>; <span class="kw1">then</span></div></li>
<li class="li1"><div class="de1"> <span class="kw3">exec</span> startx <span class="re5">--</span> vt7</div></li>
<li class="li1"><div class="de1"><span class="kw1">fi</span></div></li>
</ol></p>
<p>Now, I believe there might be an "issue" in that, while XFCE is running and
everything, <strong>one could switch to tty2 and hit Ctrl+C to "mess things up"</strong>.
Because <code>exec</code> is used you would go back to the login screen - you don't get a
shell, which could then also be a security risk - but it would "crash" X and
everything that was running in there.</p>
<p>It might not be a good thing, however it doesn't bother me in this case, and on
the other hand I do like the fact that I can switch to tty2 to:</p>
<ul>
<li>go see any potential (warning/error) messages. I known anything <u>important</u>
should find its way to <code>/var/log/Xorg.0.log</code> anyways, but not everything does,
and I guess I like the idea of being able to see such things, just in case.
(It's also why I do my logging in on tty2, and force X to start on vt7 : I
like the idea of keeping my boot messages on tty1. Just in case, and because
sometimes some things don't get to go to <code>/var/log/boot</code>.)</li>
<li>hit Ctrl+C and "kill everything" in there. It's probably not gonna be
something I'm gonna need to do a lot, hopefully pretty much never, but if
somehow I manage to get a system unresponsive or something, I can switch to
tty2, hit Ctrl+C, and that should reset things without the need to actually
reboot.</li>
</ul>
<h3>xlsh - eXtended Login Shell</h3>
<p>This was all fine and working, and then I found out about
<a href="https://github.com/Nadrin/xlsh" title="xlsh - eXtended Login Shell @ GitHub">xlsh</a>,
the "eXtended Login Shell" that fellow Arch user Michał Siejak shared in the
forums. It isn't a DM, but <strong>a login replacement</strong>. It's a small and simple tool
that can actually also be used to replace your DM, since it has support to work
in X, however I'm really not interested in that part.</p>
<p>No, what I like is that it will present a "pre-login shell" with basically three
commands: <code>login</code> to log in, of course, but also <code>reboot</code> and <code>shutdown</code> to do
just that.</p>
<p>So this would give me the only thing I actually missed from a DM, which was
<strong>the ability to reboot or shutdown the computer from there and without the need
to log in first (and sudo)</strong>. In other words, it was the perfect addition to my
setup. All it takes to make it work is edit <code>/etc/inittab</code> and replace the line
of the tty where you want it active with something like this:</p>
<pre><code>c1:2345:respawn:/sbin/agetty -8 -s 38400 -n -l /usr/sbin/xlsh tty1 linux
</code></pre>
<p>When using it, I did however found what I believe to be a little bug, in that
<strong>signals that are blocked by xlsh are not restored upon login</strong>, and so for
instance all SIGINTs were blocked when logging in through xlsh; Which I believe
is a problem, certainely was the case for me. So I did fix this, and while at it
I removed two things (or, added compilation options to do so) because I liked it
better that way :</p>
<ol>
<li>no more login completion. Just because. 2. no more X support. This is
because I have no use/interest for such a thing (All it does basically is start
X, and start a terminal to have xlsh running in there. I'd rather have xlsh
directly on tty and not waste any time or ressource.), but also because the
PKGBUILD had a few extra dependencies due to this that I didn't want to bother
with (xterm, xdotool, xorg-xsetroot, xorg-xwininfo, xorg-xmessage and
xorg-xrdb).</li>
</ol>
<p>So, if you're interested in xlsh you can find the <a href="https://aur.archlinux.org/packages.php?ID=53520" title="AUR: eXtended Login Shell - fast, minimalistic login/xdm replacement">official package
here</a> (from
xlsh's author masterm); or you can find my version <a href="https://aur.archlinux.org/packages.php?ID=54113" title="AUR: eXtended Login Shell - fast, minimalistic login replacement (without X support)">without X support
here</a>.</p>
<p>And if you do use the official version, note that signals are blocked so you
might want to use this patch to fix it:</p>
<p><ol class="diff"><li class="li1"><div class="de1">diff -r c<span class="re0">2c082</span>c4832e -r 0906dbb5f675 include/libxlsh.h</div></li>
<li class="li1"><div class="de1"><span class="re3">--- a/include/libxlsh.h Tue Nov 15 13:02:40 2011 +0100</span></div></li>
<li class="li1"><div class="de1"><span class="re4">+++ b/include/libxlsh.h Tue Nov 15 13:23:37 2011 +0100</span></div></li>
<li class="li1"><div class="de1"><span class="re6">@@ -24,6 +24,7 @@</span></div></li>
<li class="li1"><div class="de1"> </div></li>
<li class="li1"><div class="de1"> size_t libxlsh_strnlen<span class="br0">(</span>const char* s, size_t maxlen<span class="br0">)</span>;</div></li>
<li class="li1"><div class="de1"> void libxlsh_proc_sigmask<span class="br0">(</span>void<span class="br0">)</span>;</div></li>
<li class="li1"><div class="de1"><span class="re8">+void libxlsh_restore_sigmask<span class="br0">(</span>void<span class="br0">)</span>;</span></div></li>
<li class="li1"><div class="de1"> pid_t libxlsh_proc_exec<span class="br0">(</span>const char* cmdline, int flags<span class="br0">)</span>;</div></li>
<li class="li1"><div class="de1"> pid_t libxlsh_pid_read<span class="br0">(</span>const char* filename<span class="br0">)</span>;</div></li>
<li class="li1"><div class="de1"> int libxlsh_pid_lock<span class="br0">(</span>const char* filename, pid_t pid, int flags<span class="br0">)</span>;</div></li>
<li class="li1"><div class="de1">diff -r c<span class="re0">2c082</span>c4832e -r 0906dbb5f675 src/libxlsh.c</div></li>
<li class="li1"><div class="de1"><span class="re3">--- a/src/libxlsh.c Tue Nov 15 13:02:40 2011 +0100</span></div></li>
<li class="li1"><div class="de1"><span class="re4">+++ b/src/libxlsh.c Tue Nov 15 13:23:37 2011 +0100</span></div></li>
<li class="li1"><div class="de1"><span class="re6">@@ -32,6 +32,11 @@</span></div></li>
<li class="li1"><div class="de1"> sigprocmask<span class="br0">(</span><span class="nu0">0</span>, NULL, &xlsh_default_sigmask<span class="br0">)</span>;</div></li>
<li class="li1"><div class="de1"> <span class="br0">}</span></div></li>
<li class="li1"><div class="de1"> </div></li>
<li class="li1"><div class="de1"><span class="re8">+void libxlsh_restore_sigmask<span class="br0">(</span>void<span class="br0">)</span></span></div></li>
<li class="li1"><div class="de1"><span class="re8">+<span class="br0">{</span></span></div></li>
<li class="li1"><div class="de1"><span class="re8">+ sigprocmask<span class="br0">(</span>SIG_SETMASK, &xlsh_default_sigmask, NULL<span class="br0">)</span>;</span></div></li>
<li class="li1"><div class="de1"><span class="re8">+<span class="br0">}</span></span></div></li>
<li class="li1"><div class="de1"><span class="re8">+</span></div></li>
<li class="li1"><div class="de1"> pid_t libxlsh_proc_exec<span class="br0">(</span>const char* cmdline, int flags<span class="br0">)</span></div></li>
<li class="li1"><div class="de1"> <span class="br0">{</span></div></li>
<li class="li1"><div class="de1"> pid_t pid;</div></li>
<li class="li1"><div class="de1">diff -r c<span class="re0">2c082</span>c4832e -r 0906dbb5f675 src/xlsh.c</div></li>
<li class="li1"><div class="de1"><span class="re3">--- a/src/xlsh.c Tue Nov 15 13:02:40 2011 +0100</span></div></li>
<li class="li1"><div class="de1"><span class="re4">+++ b/src/xlsh.c Tue Nov 15 13:23:37 2011 +0100</span></div></li>
<li class="li1"><div class="de1"><span class="re6">@@ -330,6 +330,7 @@</span></div></li>
<li class="li1"><div class="de1"> if<span class="br0">(</span>*terminal<span class="br0">)</span></div></li>
<li class="li1"><div class="de1"> setenv<span class="br0">(</span>"TERM", terminal, <span class="nu0">1</span><span class="br0">)</span>;</div></li>
<li class="li1"><div class="de1"> </div></li>
<li class="li1"><div class="de1"><span class="re8">+ libxlsh_restore_sigmask<span class="br0">(</span><span class="br0">)</span>;</span></div></li>
<li class="li1"><div class="de1"> execlp<span class="br0">(</span>session, _arg0, <span class="br0">(</span>char*<span class="br0">)</span><span class="nu0">0</span><span class="br0">)</span>;</div></li>
<li class="li1"><div class="de1"> exit<span class="br0">(</span>EXIT_FAILURE<span class="br0">)</span>;</div></li>
<li class="li1"><div class="de1"> <span class="br0">}</span></div></li>
</ol></p>
Automatic backups with rsync2011-11-12T00:00:00+00:00http://jjacky.com/2011-11-12-automatic-backups-with-rsync<p>As <a href="/2011/11/09/precious-data-not-to-be-lost" title="Precious data, not to be lost">I've explained
before</a>,
one of the first things I did upon installation of <a href="https://www.archlinux.org" title="Arch Linux">Arch</a> was to set up a
backup solution. This was done simply using a little bash script, which itself
would launch <a href="http://rsync.samba.org" title="rsync: fast incremental file transfer (and more)"><code>rsync</code></a> to do the actual backup.</p>
<p>But after using this system for a little while, I decided that it needed a
rewrite. This was mainly due to two reasons:</p>
<ul>
<li>A "bug" in rsync</li>
<li>A flaw in the script/system</li>
</ul>
</p>
<h3>A "bug" in rsync</h3>
<p>I put <u>bug</u> in between quotes, because while some could classify this as a bug,
it isn't really one, since the current behavior of rsync actually matches what
the manual says. It's just that one could easily see how a change in the current
behavior would make a lot of sense.</p>
<p>It all comes down to the famous <code>--link-dest</code> option that I'm using, as a way to
get multiple backups of my system, where all identicital files only need to be
copied/stored once on the backup disk, and then hard-linked as many times as
needed.</p>
<p>This works great, however here's what the manual says:</p>
<blockquote>
<p>This option works best when copying into an empty destination hierarchy, as
rsync treats existing files as definitive (so it never looks in the link-dest
dirs when a destination file already exists)</p>
</blockquote>
<p>So if a file already exists in the destination, rsync will not look into the
link-dest dirs. Which means that, in my case, when updating the backup <code>week</code> it
would happen that a file did exists (from the previous week), had changed since
then, and as a result rsync would copy the new file.</p>
<p>Ideally, it would have looked into the link-dest dir before, thus realizing that
there's already an up-to-date version of the file, and therefore simply creating
a hard-link is enough. It would make the whole process go faster, and save space
of course. Alas, that's not how rsync works, and this would be repeated for the
<code>month</code> backup as well.</p>
<p>This issue has been reported a few times, including
<a href="https://bugzilla.samba.org/show_bug.cgi?id=5644" title="Option to recheck basis dirs for existing dest files @ rsync bugzilla">here</a> where
someone even proposed a patch. Unfortunately, while the patch seemed to work as
expected on a small test, when I tried to run it for a "real" run rsync just
crashed.</p>
<p>Two solutions at that point:</p>
<ol>
<li>I try to fix it myself; but I don't think I would be able to do that.</li>
<li>Change the way I use rsync to bypass this "bug"</li>
</ol>
<h3>A flaw in the script/system</h3>
<p>And I went with the later, because of something else that, while I knew it from
the start and originally was okay with, I changed my mind. My script would run
each day (cron) to make a new backup <code>day</code></p>
<p>In addition, every week it would make a backup <code>week</code> and every month a backup
<code>month</code>, the idea being that at any given moment I have three backups: beginning
of the day, the week, and the month.</p>
<p>But the way it was done would result in two backups being pretty much the same,
and every once in a while all three of them would actually be identical. So, I
figured I might as well improve this, and also work it so that I use rsync in a
way that will bypass the "bug" described earlier.</p>
<h3>The new & improved backup script</h3>
<p>So I made a new version of the script, which now works like the following:</p>
<ul>
<li>launch rsync to make a backup (in a new folder named after the current date,
e.g. <code>2011-09-23</code>). It still uses the <code>--link-dest</code> option (pointing to the
latest backup), but since the destination always is a new folder, no more
problem.</li>
<li>then it creates/updates a symlink <code>latest</code> so that it points to the newly
created backup. This symlink is what's used in the <code>--link-dest</code> option.</li>
<li>the backup from the day before is removed, unless:
<ul>
<li>we are the 2nd day of the month, then last month's backup is removed
instead</li>
<li>we are Tuesday, then:
<ul>
<li>if we are also the 2nd day of the month, nothing else is removed</li>
<li>if we are also the 9th day of the month, the backup from 2 weeks ago
is also removed</li>
<li>else, last week's backup is also removed</li>
</ul></li>
</ul></li>
</ul>
<p>The result is pretty much the same as before, except that now I never have 2 (or
more) backups identical. There's even handling of the case where a new day, week
and month all begins at the same time. In which case on the 2nd I'll have my
daily backup, the backup from the day before (as new backup of the month), and
kept the backup from the previous week - which will be removed on the 9th.</p>
<p>I also used this occasion to put some things out in a configuration file (and/or
as command-line options), because I realized the first version has a few too
many things hard-coded (for instance, I hadn't even realized it couldn't be used
to backup anything else than <code>/</code> !).</p>
<p>Now the script relies on configuration file, so you can define as many backup
schemes as you want, then simply specify which config file to use form the
command line (using <code>-c</code> or <code>--config</code>). Of course you can also simply define
all options from command-line, should you want to.</p>
<p>In case you define the same option both in a config file and on the
command-line, the later takes precedence.</p>
<h3>Configuration</h3>
<p>The configuration file is a simple text file, where you can use comments (start
the line with <code>#</code>). Values should not be put between quotes but directly
specified after the equal sign.</p>
<p>Backup folders are created in a destination root, set by option <code>dest-root</code>
Alongside the actual backups, a symlink will be automatically created/updated
after each backup, pointing to the latest backup. Its name can be set using
<code>link-dest</code></p>
<p>For the whole process to work, backups should be named after the date they were
ran at. You can customize their names using option <code>date-format</code>, defaulting to
<code>%Y-%m-%d</code> (see <code>man date</code> for more about the format supported). You can also
run the script while specifying the name to use this time (instead of using the
date format), using option <code>name</code></p>
<p>The backup source is simply set using option <code>source</code> and as before you can
define exclusions through option <code>exclude-from</code> (will be sent to rsync's option
of the same name).</p>
<p>Speaking of, you can also define the arguments for rsync through option <code>args</code>
Make sure not to use <code>--verbose</code>, <code>--exclude-from</code> or <code>--link-dest</code> as they are
auto-added if needed. If not set, it defaults to <code>--archive --acls --xattrs
--human-readable -h --stats</code></p>
<p>A sample configuration file is included, and you can use <code>-h</code> or <code>--help</code> to get
command-line help.</p>
<h3>Download</h3>
<p>All files are available on <a href="https://bitbucket.org/jjacky/backups" title="simple backup/restore scripts using rsync @ BitBucket.org">this BitBucket
repository</a>. For fellow Arch
users, there's <a href="https://aur.archlinux.org/packages.php?ID=54077" title="AUR: auto-rsync-backups 0.2-1">a
package</a> in the AUR.</p>
<p>Additionally, you can also download the latest version from <a href="https://bitbucket.org/jjacky/backups/get/stable.tar.gz" title="Download the latest version">this
link</a>.</p>
<p>It's all released under GPLv3, and of course bug reports, suggestions or any
other form of constructive criticism is very much welcome.</p>
Precious data, not to be lost2011-11-09T00:00:00+00:00http://jjacky.com/2011-11-09-precious-data-not-to-be-lost<p>One of the first things I did, after having installed
<a href="http://www.archlinux.org/" title="Arch Linux">Arch</a>, was to think about a backup
solution. Well, in fact I had been thinking about that before I even knew which
distro I would use, and I had decided to set up a mirroring of my "main" drive,
containing both the system (<code>/</code> and its friends) and my data (<code>/home</code>), which
actually are on the same partition (for now?).</p>
<p>Logically, what I did was play with <a href="http://neil.brown.name/blog/mdadm" title="mdadm: managing Linux Software RAID arrays"><code>mdadm</code></a>, and started setting up a RAID1
array. This went well, <code>mdadm</code> allowing to do things very easily, and since this
was all done in a VM I could without a problem make a disk disappear, bring a
new one and see how rebuilding the array would work (in brief: couldn't be
easier, and it was pretty fast, too).</p>
</p>
<p><u>Side note: It's one thing I'm liking more and more each day with Linux,
<strong>everything seems pretty easy to do (it's all relative, of course), and doable
simply from the command line</strong>. Now I'll admit that I'm more of a GUI guy
myself, but I can still appreciate how a couple of commands allow one to
create/format a partition, resize it, move it, create an image of it, or set up
an encryption or pretty much any kind of RAID array of one's choice. And all
that (once you start to understand how it works) with an obvious simplicity. And
while this is a Linux thing in general, it feels even more true in Arch.
Anyways...</u></p>
<p>But then I realized I made a mistake, and <strong>a mirror wasn't what I'm looking
for</strong>. Because while this was easy enough to set up, and had the other great
advantage of being a "set & forget" solution, it didn't actually provide what I
needed. A mirror means if one drive dies, you can still go on as if nothing
happened, get a new drive, do the replacement and keep going without any trouble
or data loss.</p>
<p>It's not nothing, but I wanted something else. I wanted to be able to stare at
my screen and go, "<strong>Alright, I screwed things up nicely. Now let's restore
things to a working situation again.</strong>" I wanted to be able to realize that,
while I meant <code>mv</code>, what I actually typed was <code>rm</code>, for some odd reason, without
having to panic or cry.</p>
<p>In other words, <strong>I wanted to have actual backups of my data</strong>, and not just a(n
always up-to-date) mirror. Backups that could be old, not too old, but
definitely no instant mirror. So I said goodbye to <code>mdadm</code>, and simply settled
for a little bash script using <a href="http://rsync.samba.org/" title="rsync: fast incremental file transfer (and more)"><code>rsync</code></a>, that would run
automatically at night as a cron.</p>
<h3>Multiple backups, with just one copy of the data</h3>
<p><code>rsync</code> is a great a powerful too, and one that allows to create a whole lot of
backup solutions, including over ssh and many more things I don't need. One of
the things it does, though, that will be of use for me, is that <strong>it can
basically create different backups of your data, with only one full copy of the
data</strong>, and then simply what changed (i.e. new/modified files).</p>
<p>I'm not talking about its algorithm that only transfers part of a file that
changed, to minimize the amount of data to transfer and speed things up, but how
the data are stored. The idea is that you provide <code>rsync</code> with one (or more)
additional location(s), besides the usual source & destination. When a file is
missing in the destination, before copying it from the source <code>rsync</code> will check
those additional locations. Then, it can do different things:</p>
<ul>
<li>using <code>--compare-dest</code> it will simply skip those files; Thus only new/modified
files are backed up.</li>
<li>using <code>--copy-dest</code> it will do a local copy of the files; This doesn't
actually save any space.</li>
<li>using <code>--link-dest</code> it will create hard links of the files; This is the magic
we want.</li>
</ul>
<p>It's that third option that interests me, because it means <strong>you will end up
with e.g. three backups</strong>, each folder containing a fill backup of your
drive/data at a given time, but <strong>you don't actually need three times the space
for it</strong>. Only one, plus what's changed.</p>
<h3>The magic of hard links</h3>
<p>Quickly, for those not familiar with hard links: basically when you have a file
stored on your drive, there are two things: the actual data, the content of the
file, and its name. Usually there's only one name per content, but you can
actually have more. For example, <code>/home/user/foo.log</code> and <code>/var/log/foo</code> could
be <strong>the <strong>same</strong> file</strong>.</p>
<p>There's no links, shortcuts or anything like it: both names represent the same
data. Editing one file is the same as editing the other, since they "share"
their content. When you remove one, you just remove its name, thus leaving the
other unaffected. When you remove the last one, and there are no more names for
the data, it is "dropped" and the space on the drive is made available again.</p>
<p>Using the <code>-i</code> option of <code>ls</code> one can have the inode number shown. This number
is a unique index that represents the data linked to. Two files with the same
inode are actually pointing to the same data, i.e. are two hard-links for the
same data. You can also use the <code>-l</code> option of <code>cp</code> to create a new hard-link of
a file, instead of copying its data.</p>
<p>And that's what <code>rsync</code> will do with the <code>--link-dest</code> option, create
hard-links. If the same file in source is found on that additional location
(we're not talking same inodes here, of course. <code>rsync</code> uses size, dates and
such attributes to determine equality of file be default, though you can have it
use checksums (e.g. MD5) as well) then a new hard-link will be created and no
data needs to be copied. <strong>This not only speed things up quite a lot, but
reduces the amount of space needed to keep multiple backups at once.</strong></p>
<p>And since usually what regularly changes are small files, with the big ones tend
to stay the same, this can allow to keep a few backups for far much less space
that complete separated copies would require. <strong>Yet, each backup folder contains
the full backup</strong>, and not just a partial/incremental copy. That's the beauty of
it.</p>
<p>With that in mind, I decided to make me a little bash script that would run each
night, and update a backup in "day" which would represent the backup at the
beginning of the day. It would also, every Sunday night/Monday morning, update
the backup "week" representing the backup at the beginning of the week, using
the "day" backup of reference (additional location in <code>--link-dest</code> that is),
and then lastly the first of each month the backup "month" will be updated the
same way.</p>
<p>So now I have three backups: "day", "week", and "month". Each one is a full
backup of my system at a different time. There is about 5 GB of data in the
source, and the three backups are using about 7.4 GB altogether, so less than
what would be needed for two "full" backups. Pretty cool, isn't it?</p>
<h3>Scripting time</h3>
<p>In case you're interested, here are the two scripts I made. The first one is of
course the one to create backups, the second one will be of use when needing to
restore things.</p>
<p>I should mention that I wrote those for me, and poorly hard-coded some
things(*), like the destinations of the backups : <strong>they all go in <code>/backups/</code>
and are called, as we've see, <code>day</code>, <code>week</code> and <code>month</code></strong></p>
<p><u>(*) I should note that I am actually planning on doing a full rewrite of those
scripts, for a couple of reasons, and I'll then try to make things a bit better.
Meanwhile, those are easy enough to adapt, should you want to.</u></p>
<h4>backups.sh</h4>
<p>The first script is used to create a backup of the data. It supports two modes:
<code>auto</code>, and <code>manual</code></p>
<p>The mode <code>auto</code> is likely to be used in a cron job, to run automatically every
night or something like that. It will always create/update <code>/backups/day</code>, then
if the day is the first of the month it will also create/update <code>/backups/month</code>
(using <code>day</code> as reference, i.e. in <code>--link-dest</code>) and if the day is a Monday it
will do the same in <code>/backups/week</code> (still using <code>day</code> as reference)</p>
<p>The mode <code>manual</code> allows one to create a backup whenever one wants. You can give
it a name (i.e. the name of the folder where the backup will be, though it will
be a subfolder of <code>/backups/</code>) or, if you don't, it defaults to the current date
(e.g: 2011-09-23_15-42). The way it's done, it always uses <code>day</code> as "reference"
and therefore cannot be run if it doesn't exists.</p>
<p>It also uses a file with a list of locations to exclude from the backup,
<code>/backups/backups.excludes</code> It is simply sent to <code>rsync</code> using its
<code>--exclude-from</code> option. Note that this file is also used in the restore script.</p>
<h4>restore.sh</h4>
<p>This script is just there to easily restore a full backup. Usually, one would
imagine you will only need to go get a file or two, but should there be a major
problem or something, and you want to restore everything, this is for you.</p>
<p>It will simply do two things:</p>
<ul>
<li>start <code>rsync</code> with all the required options</li>
<li>read the <code>/backups/backups.excludes</code> file and, for each line in that file that
starts with "- " (dash & space) - i.e. each folder that was excluded from the
backup - it will make sure said folder does exists in the restored location,
creating it if not.</li>
</ul>
<p>The point of this is that you'll probably want to exclude things like <code>/dev/</code>,
<code>/media/</code>, <code>/mnt/</code>, <code>/proc/</code> or, of course, <code>/backups/</code> itself. But it might be
required to have those folders if you want your system to boot (correctly),
therefore.</p>
<h4>Download</h4>
<p>Both scripts (and a <code>backups.exclude</code>) are available on <a href="https://bitbucket.org/jjacky/backups" title="simple backup/restore scripts using rsync @ BitBucket.org">this BitBucket
repository</a>.</p>
<p>Or, you can simply download the latest version from <a href="https://bitbucket.org/jjacky/backups/get/stable.tar.gz" title="Download the latest version">this
link</a>.</p>
<p>It's all released under GPLv3, and of course bug reports, suggestions or any
other form of constructive criticism is very much welcome.</p>
On my way to Arch...2011-11-08T00:00:00+00:00http://jjacky.com/2011-11-08-on-my-way-to-arch<h3>Windows or Linux?</h3>
<p>If you were to ask me, the answer would have to be Windows, I am running
Windows. Not really per choice, mind you. Of course no one is forcing me, it's
more simply that, back in the days, I started using a Microsoft operating
system, and since then I have kept doing so, only updating it from time to time
but never leaving it.</p>
<p>Of course I have been tempted to switch and enter the joyful world of open
source, but <strong>it's just not something you can do like that</strong>. Not when you're
used to a system, know your way around it, and have a set of tools that fits
your work flow and is the result of years and years of testing & careful
selection.</p>
<p>But <strong>I have finally decided to switch to Linux</strong>, and for that I gave myself
one year. One year to find/pick the software I'll need/use, get familiarized
with this new environment and its eco-system, one year to get ready, and
probably adapt my work flow here and there. One year until I take Linux out of
the VM and get rid of Windows.</p>
</p>
<p>I say a year, but the truth is I started working on this about a couple of
months ago already. And early on I thought about making a little blog like what
this one will hopefully be, as a way both to provide me with a log of what I
went through, and what I did/learned along the way (including things I'll
probably be looking for in about 10 months or so, when I'll have forgotten
already and time will come to re-install Linux, but "for real" this time).</p>
<p>Of course, laziness being such a good friend of mine, it didn't happen - until
now. But I'll try to keep doing this all along the way, and who knows, maybe
some of you out there might find a thing or two worthy of interest out of it as
well, hopefully.</p>
<h3>First things first: Linux, yes, but which one?</h3>
<p>Deciding to move to Linux is nice and all, but the nature of it is such that
<strong>there isn't such a thing as one Linux</strong>, but a variety of distributions. So I
had to make a choice. Originally, <strong>I went with
<a href="http://fedoraproject.org/" title="Fedora Project Homepage">Fedora</a></strong>.</p>
<p>It seemed a good choice, a solid distro, one I had heard of before, and so I
grabbed a few ISOs (to give a try to different Desktop Environments) and started
some testing. I also tried a couple other distros, but I was focusing on Fedora
really. Then one day, I asked myself <strong>why</strong>. And I couldn't really answer.</p>
<p>So I turned to the interwebz, trying to see what other distros but the few I
knew/had heard of were out there, trying to find out the pros & cons of each one
and see if Fedora was really a good choice, those sort of things.</p>
<p>Honestly, I wasn't even so much looking into which distro to use, as to what
differences there are between distros, or how my choice would impact my future
life with Linux.</p>
<p>And somehow, I stumbled upon something, a distribution that I actually seemed to
like. Or, since I hadn't tried it yet, I liked what I read about it, what people
said about it, what it said on its official website, and then I felt like I had
found what I was looking for: <u>my <strong>choice</strong></u>.</p>
<h3>Arch Linux.</h3>
<p>Often times, you'll hear that <a href="http://www.archlinux.org/" title="Arch Linux">Arch</a> is
targeted at advanced GNU/Linux users, that it is good for people who are already
familiar with Linux and know their way around a Linux system. So, in other
words, <strong>not me</strong>. I could have stopped there, but I kept reading about it, and
the Arch Way...</p>
<blockquote>
<p>Arch Linux defines simplicity as without unnecessary additions, modifications,
or complications, and provides a lightweight UNIX-like base structure that
allows an individual user to shape the system according to their own needs. In
short: an elegant, minimalist approach.</p>
</blockquote>
<p>Really, <strong>Arch seemed perfect for me</strong>, both in that it would provide me a base
to build my system, something with all the things I need/want, but none of the
crap I don't - or you know, just none of the stuff useless to me (but that might
come pre-installed with a lot of distro out there). It would also provide a
great way to learn, learn about Arch of course, but also Linux in general.</p>
<p>Arch isn't Ubuntu, or Windows, and doesn't try - or want - to be. It's not meant
for one to launch the install and look at pretty pictures before entering a
brand new desktop, ready for use. No, <strong>you'll need to work to get to your
desktop</strong> (assuming you want one, of course). You'll need to find out how things
work, before you can install & configure them.</p>
<p>So no, it's not for everybody, and you need not to be afraid of the console, of
having to search and work to get things done, but I was attracted to this, it
seemed to be exactly what I needed. And so - at 19:01 on September 14, 2011
according to my pacman.log - I installed Arch Linux inside a VM, and the
adventure began...</p>
<h3>Don't run away just yet</h3>
<p>If you're new to Linux, or looking to get into it, don't let that(/me) scare you
away though. When I say it needs work, <strong>it doesn't mean you need to become a
Linux expert</strong>, simply that you will have to have *some* understanding of how
things work. Knowledge that is always good to have, that will surely come in
handy should something break, or when you'll want to do something "special" that
best fits you, and knowledge that is easily reachable through all the wonders
offered by the Arch community.</p>
<p>Of course there is a whole lot more than what I quickly mentioned to Arch, but
they have, among other things, <a href="https://wiki.archlinux.org/index.php/Main_Page" title="ArchWiki">this fantastic
wiki</a>. If you want to
know more about it, the Arch way, the rolling release principle, pacman, or
pretty much anything Linux related, this is the place to go.</p>