tag:blogger.com,1999:blog-79528103304368231102024-03-18T07:41:37.751+01:00The Grey BlogA Solaris Addict and an Amateur Photographer Living in SpainEnrico M. Crisostomohttp://www.blogger.com/profile/02688166348157974808noreply@blogger.comBlogger361125tag:blogger.com,1999:blog-7952810330436823110.post-91220582757870911862018-04-14T17:59:00.003+02:002018-04-14T17:59:34.055+02:00jwt-cli: A Shell Library to Decode JSON Web Tokens (JWT Tokens)When I started having the need of decoding JSON Web Tokens quite often, I felt the urge of writing a program that allowed me to do it <i>quickly</i>. There are excellent options, such as <a href="http://jwt.io/">jwt.io</a>, but as soon as you need to do this operation often it becomes clumsy. And if you need to process multiple tokens, or further process the output, it becomes a necessity.<br />
<br />
That's why I wrote <a href="https://github.com/emcrisostomo/jwt-cli">a little shell scrip</a>t that allows you to do just that. <span style="font-family: Courier New, Courier, monospace;">jwt-decode</span> will accept a list of tokens as arguments and will decode them on standard output. The syntax is the following:<br />
<br />
<span style="font-family: Courier New, Courier, monospace;">$ jwt-decode token ...</span><br />
<span style="font-family: Courier New, Courier, monospace;">{</span><br />
<span style="font-family: Courier New, Courier, monospace;"> "alg": "RS256",</span><br />
<span style="font-family: Courier New, Courier, monospace;"> "typ": "JWT",</span><br />
<span style="font-family: Courier New, Courier, monospace;"> "kid": "sbS_BWBm0GzfIQRnYWolcWDRnjqwDTY_Aq6Fn_boqKM"</span><br />
<span style="font-family: Courier New, Courier, monospace;">}</span><br />
<span style="font-family: Courier New, Courier, monospace;">{</span><br />
<span style="font-family: Courier New, Courier, monospace;"> "jti": "271151a3-db11-4f37-a724-4cf9957774f4",</span><br />
<span style="font-family: Courier New, Courier, monospace;"> "exp": 1530979706,</span><br />
<span style="font-family: Courier New, Courier, monospace;"> "nbf": 0,</span><br />
<span style="font-family: Courier New, Courier, monospace;"> "iat": 1523117306,</span><br />
<span style="font-family: Courier New, Courier, monospace;"> "iss": "https://domain.com/auth/realms/realm",</span><br />
<span style="font-family: Courier New, Courier, monospace;"> "aud": "app-name",</span><br />
<span style="font-family: Courier New, Courier, monospace;"> "sub": "5132c417-d772-420e-b5db-401ea633dca1",</span><br />
<span style="font-family: Courier New, Courier, monospace;"> "typ": "Bearer",</span><br />
<span style="font-family: Courier New, Courier, monospace;"> "azp": "app",</span><br />
<span style="font-family: Courier New, Courier, monospace;"> "auth_time": 0,</span><br />
<span style="font-family: Courier New, Courier, monospace;"> "session_state": "84e6a759-e54d-4fd7-9fcf-bb51131aab89",</span><br />
<span style="font-family: Courier New, Courier, monospace;"> "acr": "1",</span><br />
<span style="font-family: Courier New, Courier, monospace;"> "allowed-origins": [</span><br />
<span style="font-family: Courier New, Courier, monospace;"> ""</span><br />
<span style="font-family: Courier New, Courier, monospace;"> ],</span><br />
<span style="font-family: Courier New, Courier, monospace;"> "realm_access": {</span><br />
<span style="font-family: Courier New, Courier, monospace;"> "roles": [</span><br />
<span style="font-family: Courier New, Courier, monospace;"> "role0",</span><br />
<span style="font-family: Courier New, Courier, monospace;"> "role1",</span><br />
<span style="font-family: Courier New, Courier, monospace;"> "role2"</span><br />
<span style="font-family: Courier New, Courier, monospace;"> ]</span><br />
<span style="font-family: Courier New, Courier, monospace;"> },</span><br />
<span style="font-family: Courier New, Courier, monospace;"> "resource_access": {</span><br />
<span style="font-family: Courier New, Courier, monospace;"> "account": {</span><br />
<span style="font-family: Courier New, Courier, monospace;"> "roles": [</span><br />
<span style="font-family: Courier New, Courier, monospace;"> "manage-account",</span><br />
<span style="font-family: Courier New, Courier, monospace;"> "manage-account-links",</span><br />
<span style="font-family: Courier New, Courier, monospace;"> "view-profile"</span><br />
<span style="font-family: Courier New, Courier, monospace;"> ]</span><br />
<span style="font-family: Courier New, Courier, monospace;"> }</span><br />
<span style="font-family: Courier New, Courier, monospace;"> },</span><br />
<span style="font-family: Courier New, Courier, monospace;"> "custom-property": "1797"</span><br />
<span style="font-family: Courier New, Courier, monospace;">}</span><br />
<span style="font-family: Courier New, Courier, monospace;">...</span><br />
<br />
You can find <a href="https://github.com/emcrisostomo/jwt-cli">jwt-cli</a> on GitHub.Enrico M. Crisostomohttp://www.blogger.com/profile/02688166348157974808noreply@blogger.com1tag:blogger.com,1999:blog-7952810330436823110.post-50645316278035064482018-01-01T12:50:00.000+01:002018-01-01T12:51:15.110+01:00tm-cleanup.sh: A Shell Script to Delete Old Time Machine Backups Now Features an Interactive InterfaceMore than two years ago I wrote <a href="https://github.com/emcrisostomo/Time-Machine-Cleanup">tm-cleanup.sh</a>, a shell script to delete Time Machine backups. During this time it has proven very useful to me, and it's been serving its purpose as it is, with barely any modification at all.<br />
<br />
However, I've been asked for help and clarifications quite a number of times by non-tech-savvy users who had some issues using the CLI. For this reason I thought that adding an <i>interactive</i>, <i>dialog-based interface</i> to this script may help people "visualise" what's going on when running <span style="font-family: "courier new" , "courier" , monospace;">tm-cleanup.sh</span>.<br />
<br />
The new interface has been added in v. 2.0.0, and can be opened by simply issuing the following command with no options:<br />
<br />
<span style="font-family: "courier new" , "courier" , monospace;">$ sudo tm-cleanup.sh</span><br />
<br />
The interactive interface opens a menu where the backup deletion operation can be triggered. The user is then presented the list of existing Time Machine backups and they can be individually selected and then deleted. Here's a screenshot of the interface showing the existing backups:<br />
<br />
<div class="separator" style="clear: both; text-align: center;">
<a href="https://raw.githubusercontent.com/emcrisostomo/Time-Machine-Cleanup/assets/images/tm-delete.png" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"><img border="0" data-original-height="489" data-original-width="682" height="457" src="https://raw.githubusercontent.com/emcrisostomo/Time-Machine-Cleanup/assets/images/tm-delete.png" width="640" /></a></div>
<br />
The documentation of the <a href="https://github.com/emcrisostomo/Time-Machine-Cleanup">repository</a> describes in detail both interfaces. I hope people will find it useful.Enrico M. Crisostomohttp://www.blogger.com/profile/02688166348157974808noreply@blogger.com0tag:blogger.com,1999:blog-7952810330436823110.post-70829892641916661732017-12-21T23:03:00.004+01:002017-12-21T23:10:38.786+01:00Starting an Emacs Daemon Automatically and Transparently using ZSHIf <a href="https://www.gnu.org/software/emacs/" target="_blank">GNU Emacs</a> is one of your editors of choice, then you may want to consider running Emacs as a <i>server</i>. Using an Emacs server is very convenient, especially if you open many Emacs processes (as it happens when the <span style="font-family: "courier new" , "courier" , monospace;">EDITOR</span> variable is set to <span style="font-family: "courier new" , "courier" , monospace;">emacs</span> in your shell). The reasons why you would use an Emacs server are manifold, and the most important are:<br />
<div>
<ul>
<li>Using an Emacs server results in a great increase in speed and responsiveness of Emacs.</li>
<li>The fact that sharing the same Emacs process implies sharing buffers, command history, and many other information.</li>
</ul>
<div>
<br /></div>
</div>
<div>
<h3>
Starting an Emacs Server</h3>
An Emacs server can be started in two ways:</div>
<div>
<ul>
<li>Running Emacs as a daemon, using the <span style="font-family: "courier new" , "courier" , monospace;">--daemon</span> option:</li>
</ul>
</div>
<div>
<span style="font-family: "courier new" , "courier" , monospace;">$ emacs --daemon</span></div>
<div>
<ul>
<li>By launching it from inside an Emacs process using the <span style="font-family: "courier new" , "courier" , monospace;">server-start</span> function:</li>
</ul>
</div>
<div>
<span style="font-family: "courier new" , "courier" , monospace;">M-x server-start</span></div>
<div>
<br /></div>
<div>
Once an Emacs server is running, you can use the <span style="font-family: "courier new" , "courier" , monospace;">emacsclient</span> program to tell a running Emacs server to visit a file. The server and the client are quite sophisticated, and you can use them for example to connect a client to a server running on a remote machine. Most of the time, however, you'll be running the daemon and the client on the same host.<br />
<br />
A question I get often is: how to start the server if it's not running and <i>then</i> connect to it? I've seen a lot of solutions to this problem, and probably one of the commonest is starting an Emacs server at login, and then using <span style="font-family: "courier new" , "courier" , monospace;">emacsclient</span> to connect to it.<br />
<br />
There's a fundamental thing I don't like about it: <i>it's not transparent</i>. However, since it's a very common approach, I'll quickly document how it's accomplished on macOS.</div>
<div>
<br /></div>
<div>
<h3>
Starting an Emacs Daemon on macOS at Login</h3>
<div>
The canonical way to start a process when a user logs in on macOS is using <span style="font-family: "courier new" , "courier" , monospace;">launchd</span>. <span style="font-family: "courier new" , "courier" , monospace;">launchd</span> is the "system wide and per-user daemon/agent manager" and it "manages processes, both for the system as a whole and for individual users" (<span style="font-family: "courier new" , "courier" , monospace;">launchd(8)</span> man page). The processes to be started at user login are called <i>launch agents</i> and are defined in plist files in the <span style="font-family: "courier new" , "courier" , monospace;">~/Library/LaunchAgents</span> directory.</div>
<div>
<br /></div>
<div>
The easiest way to start an Emacs server, then, is to launch <span style="font-family: "courier new" , "courier" , monospace;">emacs</span> with the <span style="font-family: "courier new" , "courier" , monospace;">--daemon</span> option. The corresponding launch agent file is the following:</div>
<div>
<br /></div>
<script src="https://gist.github.com/emcrisostomo/db8ab36d3fe4fcc1c83fdf95c4dee9bd.js"></script><br />
<div>
<b>Note:</b> the <span style="font-family: "courier new" , "courier" , monospace;">emacs</span> path and the <span style="font-family: "courier new" , "courier" , monospace;">UserName</span> element must contain correct values for your system.<br />
<br />
Once the launch agent descriptor has been created, it can be loaded using the following command:<br />
<br />
<span style="font-family: "courier new" , "courier" , monospace;"># launchctl load -w /Library/LaunchAgents/gnu.emacs.daemon.plist</span><br />
<br />
This solution is fine, but it has two major disadvantages: it requires a configuration, and the configuration is non-portable.<br />
<br />
<h3>
Starting an Emacs Daemon On-Demand and Transparently</h3>
A simpler and portable solution (provided you're using ZSH) is leveraging <span style="font-family: "courier new" , "courier" , monospace;">emacsclient</span>'s ability to start a daemon if none is found in a ZSH function. Instead of having to explicitly use <span style="font-family: "courier new" , "courier" , monospace;">emacsclient</span> <i>after</i> a server has been started, wouldn't it be nice to always use the same command, start a server if none is running, and connect to it transparently? Assuming we can do that, why not just calling this command <span style="font-family: "courier new" , "courier" , monospace;">emacs</span>?<br />
<br />
Fortunately, this is very easy to accomplish with <span style="font-family: "courier new" , "courier" , monospace;">emacsclient</span> and ZSH:<br />
<ul>
<li><span style="font-family: "courier new" , "courier" , monospace;">emacsclient</span> is able to start an Emacs daemon if none is running using the <span style="font-family: "courier new" , "courier" , monospace;">-a</span> option with an empty argument.</li>
<li><span style="font-family: "courier new" , "courier" , monospace;">emacsclient</span> can be invoked without a file name when the <span style="font-family: "courier new" , "courier" , monospace;">-c</span> option is used, in which case a new frame showing the <span style="font-family: "courier new" , "courier" , monospace;">*scratch*</span> buffer is created, mimicking <span style="font-family: "courier new" , "courier" , monospace;">emacs</span> behaviour.</li>
<li>ZSH lets us easily create "aliases on steroids" using a function such as the following:</li>
</ul>
<script src="https://gist.github.com/emcrisostomo/66b750c4565d28a92abe1387ca4117b0.js"></script><br />
<div>
<br /></div>
<div>
Now, every time you invoke <span style="font-family: "courier new" , "courier" , monospace;">emacs</span> in ZSH, the shell will run the <span style="font-family: "courier new" , "courier" , monospace;">emacs()</span> function instead, which will run <span style="font-family: "courier new" , "courier" , monospace;">emacsclient -c -a=</span> and will forward all its arguments to it.<br />
<br />
When using an Emacs daemon there are some things to take into account. And that's what the official documentation is for. I will only say that since you are now sharing a single Emacs process, its frames and its buffers, you may now want to use <span style="font-family: "courier new" , "courier" , monospace;">C-x #</span> when done with a buffer (or <span style="font-family: "courier new" , "courier" , monospace;">C-x C-k</span>). This way you will kill the buffer and it won't be left hanging around.</div>
<div>
<br /></div>
</div>
</div>
Enrico M. Crisostomohttp://www.blogger.com/profile/02688166348157974808noreply@blogger.com0tag:blogger.com,1999:blog-7952810330436823110.post-59986294050275933232017-11-27T08:52:00.000+01:002017-11-27T09:50:39.720+01:00Installing macOS High Sierra from Scratch: Not So Good a User ExperienceOne week ago a MacBook Pro of a relative of mine stopped booting. The symptoms indicated a hard disk failure, and the diagnosis confirmed it. I ordered a replacement drive on Amazon and I decided to allocate 30 minutes of a bright Saturday morning to fix it. The procedure should have been very simple:<br />
<div>
<ul>
<li>Create a bootable image of the latest macOS (<i>High Sierra</i>).</li>
<li>In the meantime, swap the hard disk in the MacBook Pro (a procedure that hardly takes more than 10 minutes on a MacBook with a serviceable hard disk drive such as this one).</li>
<li>Boot from an external device.</li>
<li>Launch the installation.</li>
<li>Go out and run.</li>
</ul>
<div>
Unfortunately, it took at least twice the estimated time and three macOS installation attempts.<br />
<br /></div>
</div>
<h3>
Attempt 1: Launching the macOS Installer</h3>
<div>
The MacBook Pro booted the base system correctly from the external device, but when I launched the installer, it failed with the following message: </div>
<div>
<br /></div>
<div>
<i>This copy of the Install macOS High Sierra.app application is damaged and can't be used to install macOS.</i></div>
<div>
<br /></div>
<div>
A quick search confirmed that this error frequently appears since macOS <i>Sierra</i> and the workarounds I found are quite imaginative. Apparently, many people thinks the installer is <i>actually</i> broken and are trying to download it again. Fortunately, it didn't take that much time to fix the problem. A post on the Apple website described the same problem (although on Sierra) and its solution (after several calls to Apple customer support, according to the author): deleting the <span style="font-family: "courier new" , "courier" , monospace;">./Contents/SharedSupport/InstallInfo.plist</span> from the bootable image should do the trick. And it did.<br />
<br /></div>
<h3>
Attempt 2: Launching the macOS Installer</h3>
<div>
The second attempt looked promising: the installer now launched correctly. Unfortunately, it failed on the second screen with the following message:</div>
<div>
<br /></div>
<div>
<i>The recovery server could not be contacted.</i></div>
<div>
<br /></div>
<div>
The first thing I do in these cases is open a terminal and perform basic checks. The second check I made caught the problem: the system was reporting January, 1st 2001 as the current date. Therefore, most probably, the HTTPS connection to the recovery server was failing because the certificate check was failing (chances are the validity period of that certificate appeared to be in the future). </div>
<div>
<br /></div>
<div>
I fixed the date using the <span style="font-family: "courier new" , "courier" , monospace;">date</span> command and restarted the macOS installer.<br />
<br /></div>
<h3>
Attempt 3: Finding the Hard Disk Drive</h3>
<div>
The installer was now working, but it couldn't find any disk to install the system. I quitted the installer (for the third time) and opened <i>Disk Utility</i>. To my surprise, Disk Utility couldn't find any internal disk either. Again, a quick search confirmed the obvious: High Sierra's Disk Utility doesn't recognise unformatted internal drives. I opened the terminal again in order to quickly format the drive:</div>
<div>
<ul>
<li>First of all, confirm the disk is available and its device name:</li>
</ul>
</div>
<div>
<div>
<span style="font-family: "courier new" , "courier" , monospace; font-size: x-small;">$ diskutil list</span></div>
<div>
<span style="font-family: "courier new" , "courier" , monospace; font-size: x-small;">/dev/disk0 (internal, physical):</span></div>
</div>
<div>
<span style="font-family: "courier new" , "courier" , monospace; font-size: x-small;">[...snip...]</span></div>
<div>
<ul>
<li>Then, format it to make it available to Disk Utility:</li>
</ul>
</div>
<div>
<span style="font-family: "courier new" , "courier" , monospace; font-size: x-small;">$ diskutil eraseDisk JHFS+ NewDisk GPT disk0</span></div>
<div>
<br /></div>
<div>
Disk Utility could now see the device. I reformatted it using APFS, restarted the installer again and this time the I successfully made it to the end of the installation.<br />
<br /></div>
<h3>
Final Thoughts</h3>
<div>
I never needed to reinstall OS X or macOS on any of the three computers I owned in the last 10 years: this was the first macOS installation from scratch I performed in a very long time. However, the three errors I experienced have three characteristics in common which make this experience unsettling:</div>
<div>
<ul>
<li>They are <i>obscure</i> and difficult to troubleshoot. I bet most non-tech-savvy user would have to ask for help.</li>
<li>They have been known for <i>years</i>.</li>
<li>They are, or seem to be, easily solvable. The date problem, for instance: why wouldn't an installer which requires a working Internet connection <i>not</i> synchronise the current time using NTP?</li>
</ul>
</div>
<div>
Come on Apple, you can do better than this.</div>
Enrico M. Crisostomohttp://www.blogger.com/profile/02688166348157974808noreply@blogger.com0tag:blogger.com,1999:blog-7952810330436823110.post-56246467879144852172017-11-18T00:25:00.000+01:002017-11-18T16:26:46.943+01:00Making Native Language Support (NLS) and gettext OptionalI've decided to write this blog post after noticing <i>how many </i>people were asking me to make <span style="font-family: "courier new" , "courier" , monospace;">gettext</span> optional when building <span style="font-family: "courier new" , "courier" , monospace;">fswatch</span>. At the beginning I actually thought it <i>was</i> optional. And I never dug any deeper into the matter because, apparently, everybody experiencing this problem was building <span style="font-family: "courier new" , "courier" , monospace;">fswatch</span> from the repository sources instead of building it from a release tar-ball. I would typically answer to build the release tar-ball instead and I would hear no more complaints.<br />
<br />
Making <span style="font-family: "courier new" , "courier" , monospace;">gettext</span> optional is easy, and should be a best practice when writing a piece of software. However, I've seen so many questions in the Internet about this topic that I've decided to write a blog post where I would outline the reasons why you should do it and <i>how</i> you should do it using the GNU Autotools.<br />
<br />
<h3>
So, What's the Issue With Building From Repository Sources?</h3>
Actually there's no issue. But probably many people asking that question don't know how the Autotools work. Autoconf is a tool whose goal is producing scripts (the ubiquitous <span style="font-family: "courier new" , "courier" , monospace;">configure</span> script) that configure the source code before building it to adapt it to the characteristics of the current system. In a typical flow the user does nothing but running <span style="font-family: "courier new" , "courier" , monospace;">configure</span>. The script will run and will test for the presence of all the features requested by the author. The presence of a feature, or its lack thereof, can then be used to parametrise <span style="font-family: "courier new" , "courier" , monospace;">Makefile</span><span style="font-family: inherit;">s</span>, or more generally, be used to conditionally drive the execution of other tests or scripts.<br />
<br />
The Autotools are <i>not</i> required by end users. The scripts generated by the Autotools are <i>fully</i> independent from them. These script are then bundled with the sources (in a <i>distribution</i>) which is often called a <i>release tar-ball</i>.<br />
<br />
As you can see, the goal of the Autotools is making <i>users'</i> life simple, not <i>maintainers'</i>. In fact, maintainers <i>need</i> to have the Autotools components they use in order to generate a distribution. These are the sources you typically find in a package repository such as <span style="font-family: "courier new" , "courier" , monospace;">fswatch</span>. <i>That's</i> why you don't find any <span style="font-family: "courier new" , "courier" , monospace;">configure</span> script in the source repository: it's created when a release is created and a distribution is packaged.<br />
<br />
Perhaps not surprisingly, <i>GNU gettext</i> is one of the components software authors may use conditionally. <span style="font-family: "courier new" , "courier" , monospace;">configure</span> would then check the build environment to detect the availability of all the required <span style="font-family: "courier new" , "courier" , monospace;">gettext</span> components and enable <i>Native Language Support</i> (NLS) if all checks succeed.<br />
<br />
<h3>
What's Special About Gettext?</h3>
This Autotools overview doesn't explain, though, what's the issue about <span style="font-family: "courier new" , "courier" , monospace;">gettext</span>. If it's just one of the many configuration checks performed by <span style="font-family: "courier new" , "courier" , monospace;">configure</span>, what's the relationship with the Autotools and the repository sources? The answer is that <span style="font-family: "courier new" , "courier" , monospace;">gettext</span> provides a tight integration with the Autotools, in the form of ready to use Autoconf and Automake macros to support the gettext operations during a normal workflow, such as:<br />
<ul>
<li>Extracting strings from sources.</li>
<li>Creating template files (POT files).</li>
<li>Creating translation files (PO files).</li>
<li>Updating template files.</li>
<li>Merging changes into translation files.</li>
<li>Compiling translation files into message catalogs.</li>
<li>Shipping required files in a distribution.</li>
<li>Installing message catalogs.</li>
</ul>
<br />
It goes without saying that the maintainers <i>do</i> need <span style="font-family: "courier new" , "courier" , monospace;">gettext</span> installed in their machines in order to be able to use these macros, to create the configuration scripts and to create a package distribution.<br />
<br />
<h3>
Making gettext Optional</h3>
To make <span style="font-family: "courier new" , "courier" , monospace;">gettext</span> optional, we have to perform at least these operations in the Autoconf configuration file (<span style="font-family: "courier new" , "courier" , monospace;">configure.ac</span>):<br />
<ul>
<li>Use the <span style="font-family: "courier new" , "courier" , monospace;">AM_GNU_GETTEXT</span> macro to check whether NLS should be used. If it should be used, the <span style="font-family: "courier new" , "courier" , monospace;">USE_NLS</span> variable would be set to <span style="font-family: "courier new" , "courier" , monospace;">yes</span>.</li>
<li>Create an Automake conditional to propagate this information to the <span style="font-family: "courier new" , "courier" , monospace;">Makefile</span><span style="font-family: inherit;">s, perhaps using something in the lines of:</span></li>
</ul>
<div>
<span style="font-family: "courier new" , "courier" , monospace; font-size: x-small;">AM_GNU_GETTEXT([external])</span><br />
<span style="font-family: "courier new" , "courier" , monospace; font-size: x-small;">AM_GNU_GETTEXT_VERSION([0.19.4])</span><br />
<span style="font-family: "courier new" , "courier" , monospace; font-size: x-small;">AM_CONDITIONAL([USE_NLS], [test "x${USE_NLS}" = "xyes"])</span></div>
<div>
<br /></div>
<div>
In the <span style="font-family: "courier new" , "courier" , monospace;">Makefile</span><span style="font-family: inherit;">s</span>, we have to leverage these information to:</div>
<div>
<ul>
<li>Conditionally distribute NLS-related files such as <span style="font-family: "courier new" , "courier" , monospace;">ABOUT-NLS:</span></li>
</ul>
<div>
<div>
<span style="font-family: "courier new" , "courier" , monospace; font-size: x-small;">if USE_NLS</span><br />
<span style="font-family: "courier new" , "courier" , monospace; font-size: x-small;"> dist_doc_DATA += ABOUT-NLS</span><br />
<span style="font-family: "courier new" , "courier" , monospace; font-size: x-small;">endif</span></div>
<span style="font-family: "courier new" , "courier" , monospace; font-size: x-small;">
</span></div>
<ul>
<li>Conditionally execute NLS-related targets. What I typically do is segregating all NLS-related stuff in a directory (<span style="font-family: "courier new" , "courier" , monospace;">po</span>) which is conditionally processed by the <span style="font-family: "courier new" , "courier" , monospace;">Makefile</span>:</li>
</ul>
<div>
<div>
<span style="font-family: "courier new" , "courier" , monospace; font-size: x-small;">if USE_NLS</span></div>
<div>
<span style="font-family: "courier new" , "courier" , monospace; font-size: x-small;"> PO_SUBDIR = po</span></div>
<div>
<span style="font-family: "courier new" , "courier" , monospace; font-size: x-small;">endif</span></div>
<div>
<span style="font-family: "courier new" , "courier" , monospace; font-size: x-small;"><br /></span></div>
<div>
<span style="font-family: "courier new" , "courier" , monospace; font-size: x-small;">SUBDIRS = other_paths $(PO_SUBDIR)</span></div>
</div>
</div>
<div>
<span style="font-family: "courier new" , "courier" , monospace; font-size: x-small;"><br /></span></div>
All the other <span style="font-family: "courier new" , "courier" , monospace;">Makefile</span> fragments required to use <span style="font-family: "courier new" , "courier" , monospace;">gettext</span>, such as defining the <span style="font-family: "courier new" , "courier" , monospace;">LOCALEDIR</span> to load catalog files and linking against <span style="font-family: "courier new" , "courier" , monospace;">libintl</span>, do not need to be modified. Even if always adding <span style="font-family: "courier new" , "courier" , monospace;">@LTLIBINTL@</span> to <span style="font-family: "courier new" , "courier" , monospace;">LDADD</span> may seem odd at first, the Autoconf output variable <span style="font-family: "courier new" , "courier" , monospace;">LTLIBINTL</span> is documented to expand to an <i>empty string</i> when NLS is not being used.<br />
<br />
<span style="font-family: "courier new" , "courier" , monospace; font-size: x-small;"># Prepare gettext-related symbols used by programs</span><br />
<span style="font-family: "courier new" , "courier" , monospace; font-size: x-small;">AM_CPPFLAGS += -DLOCALEDIR=\"$(localedir)\"</span><br />
<span style="font-family: "courier new" , "courier" , monospace; font-size: x-small;"><br /></span>
<span style="font-family: "courier new" , "courier" , monospace; font-size: x-small;"># Link program against libintl if gettext is being used</span><br />
<span style="font-family: "courier new" , "courier" , monospace; font-size: x-small;">prog_LDADD += @LTLIBINTL@</span><br />
<br />
<h3>
Conclusion</h3>
<div>
This is all that's required to make <span style="font-family: "courier new" , "courier" , monospace;">gettext</span> optional in your Autotools package. With these few changes, users will now be able to let <span style="font-family: "courier new" , "courier" , monospace;">configure</span> automatically determine whether to enable or disable NLS, and even disabling it using the <span style="font-family: "courier new" , "courier" , monospace;">--disable-nls</span> option:</div>
<div>
<br /></div>
<div>
<span style="font-family: "courier new" , "courier" , monospace; font-size: x-small;">$ ./configure --disable-nls</span></div>
<div>
<br /></div>
<div>
<br /></div>
<br />
<br />Enrico M. Crisostomohttp://www.blogger.com/profile/02688166348157974808noreply@blogger.com0tag:blogger.com,1999:blog-7952810330436823110.post-7348436977805172242015-05-02T14:21:00.000+02:002015-05-02T14:21:28.890+02:00A Shell Script to Delete Old Time Machine Backups and Free Disk SpaceIn <a href="http://thegreyblog.blogspot.com/2014/03/shrink-your-time-machine-backups-and.html" target="_blank">another post</a> I described the procedure to manually delete Time Machine snapshots and optionally shrink the disk image (in case a sparse bundle is being used) in order to free up disk space.<br />
<br />
I have written a shell script, <span style="font-family: Courier New, Courier, monospace;">tm-cleanup.sh</span>, to automate the backup deletion. The script accepts an optional argument to specify the maximum backup age in days: older backups are deleted (by default, backups older than 30 days are deleted).<br />
<br />
The latest version of the script can be obtained by cloning its <a href="https://github.com/emcrisostomo/Time-Machine-Cleanup" target="_blank">GitHub repository</a> and, optionally, run its installation script to create symbolic links to it into <span style="font-family: Courier New, Courier, monospace;">/usr/local/bin</span>:<br />
<br />
<span style="font-family: Courier New, Courier, monospace;">$ sudo make install</span><br />
<br />
<br />Enrico M. Crisostomohttp://www.blogger.com/profile/02688166348157974808noreply@blogger.com3tag:blogger.com,1999:blog-7952810330436823110.post-23049452965429178432014-10-17T20:20:00.000+02:002014-10-17T20:20:39.624+02:00Installing Drupal on FreeBSDDrupal ports have been available on FreeBSD since quite a long time, and binary packages can be installed very quickly. However, manual setup is required to connect Drupal to the database and have Apache serve the Drupal website. In this post I'll describe the setup procedure of Drupal 7 on FreeBSD 10.0. The process will not be very different if different versions of Drupal or FreeBSD are used.<br />
<br />
<h2>
Installing Drupal</h2>
Drupal ports are available on FreeBSD and, in fact, multiple versions are available:<br />
<br />
<span style="font-family: Courier New, Courier, monospace;"># pkg search drupal</span><br />
<span style="font-family: Courier New, Courier, monospace;">drupal6-6.31</span><br />
<span style="font-family: Courier New, Courier, monospace;">[...snip...]</span><br />
<span style="font-family: Courier New, Courier, monospace;">drupal7-7.31</span><br />
<span style="font-family: Courier New, Courier, monospace;">[...snip...]</span><br />
<br />
Unless there is a compelling reason not to do so, install the latest one:<br />
<br />
<span style="font-family: Courier New, Courier, monospace;"># pkg install drupal7</span><br />
<br />
To successfully run Drupal, you need:<br />
<ul>
<li>The Apache HTTP Server.</li>
<li>PHP.</li>
<li>A supported database server (PostgreSQL or MySQL).</li>
</ul>
<br />
The Drupal port, however, does not enforce these dependencies, so that you have to satisfy them manually.<br />
<br />
<h3>
Installing the Apache HTTP Server</h3>
Unless there is a compelling reason not to do so, install the latest available Apache port (<span style="font-family: Courier New, Courier, monospace;">apache24</span> at the time of writing):<br />
<br />
<span style="font-family: Courier New, Courier, monospace;"># pkg install apache24</span><br />
<br />
Once the port is installed, enable the corresponding service adding the following line to <span style="font-family: Courier New, Courier, monospace;">/etc/rc.conf</span>:<br />
<br />
<span style="font-family: Courier New, Courier, monospace;">apache24_enable="YES"</span><br />
<span style="font-family: Courier New, Courier, monospace;"><br /></span>
<br />
<h3>
Installing the Database</h3>
Drupal supports both PostgreSQL and MySQL but the Drupal port does not install any, by default, although it installs the MySQL client utilities. In this post MySQL will be used but if you prefer using PostgreSQL instead, just skip this section and read <a href="http://pgedit.com/install_drupal" target="_blank">this article</a> instead.<br />
<br />
Since the Drupal port by default defines the <span style="font-family: Courier New, Courier, monospace;">MYSQL</span> option, when you install the binary package using <span style="font-family: Courier New, Courier, monospace;">pkg</span> you'll also get a MySQL client port, such as what I got at the time of writing:<br />
<br />
<span style="font-family: Courier New, Courier, monospace;">mysql55-client-5.5.40</span><br />
<br />
As a consequence, you have to install the matching <span style="font-family: Courier New, Courier, monospace;">mysqlXX-server</span> port:<br />
<br />
<span style="font-family: Courier New, Courier, monospace;"># pkg install mysql55-server-5.5.40</span><br />
<br />
If you try to install a different version (at the time of writing <span style="font-family: Courier New, Courier, monospace;">mysql56</span> is available), you may be requested to remove Drupal itself because of the inter-dependencies between the client and server MySQL packages.<br />
<br />
Once MySQL is installed, enable the corresponding service adding the following line to <span style="font-family: Courier New, Courier, monospace;">/etc/rc.conf</span>:<br />
<br />
<span style="font-family: Courier New, Courier, monospace;">mysql_enable="YES"</span><br />
<span style="font-family: Courier New, Courier, monospace;"><br /></span>
<br />
<h3>
Installing PHP</h3>
The installation of PHP is taken care of by the Drupal port. However, the PHP module for the Apache HTTP Server is not installed and must be installed manually. Make sure you install the PHP module that corresponds with the PHP version installed by the Drupal port. At the time of writing, the following modules are available:<br />
<br />
<span style="font-family: Courier New, Courier, monospace;"># pkg search mod_php</span><br />
<span style="font-family: Courier New, Courier, monospace;">mod_php5-5.4.33_1,1</span><br />
<span style="font-family: Courier New, Courier, monospace;">mod_php55-5.5.17_1</span><br />
<span style="font-family: Courier New, Courier, monospace;">mod_php56-5.6.1</span><br />
<br />
Since the port depends on <span style="font-family: Courier New, Courier, monospace;">php5</span>, then <span style="font-family: Courier New, Courier, monospace;">mod_php5-5.4.33_1,1</span> should be installed:<br />
<br />
<span style="font-family: Courier New, Courier, monospace;"># pkg install mod_php5-5.4.33_1,1</span><br />
<br />
The port takes care of modifying the Apache HTTP Server configuration file so that the PHP module is loaded. If you did not install the packages in order suggested by this post, then you may have lost that piece of configuration. In any case, make sure a line similar to the following is present in <span style="font-family: Courier New, Courier, monospace;">/usr/local/etc/apache24/httpd.conf</span>:<br />
<br />
<span style="font-family: Courier New, Courier, monospace;">LoadModule php5_module libexec/apache24/libphp5.so</span><br />
<span style="font-family: Courier New, Courier, monospace;"><br /></span>
<br />
<h3>
Installing drush</h3>
<span style="font-family: Courier New, Courier, monospace;">drush</span> is an optional package offering an amazingly good command line interface to perform many Drupal-related management tasks: <span style="font-family: Courier New, Courier, monospace;">drush</span> could even be used to install Drupal, but this topic is not covered by this post, since I prefer relying on a port tested specifically on FreeBSD. However, once you have tested that a specific release works correctly, you may find <span style="font-family: Courier New, Courier, monospace;">drush</span> very useful to streamline your installations. If you are interested in using <span style="font-family: Courier New, Courier, monospace;">drush</span>, you will find plenty of good information on the Internet. To install <span style="font-family: Courier New, Courier, monospace;">drush</span>, the following command may be used:<br />
<br />
<span style="font-family: Courier New, Courier, monospace;"># pkg install drush</span><br />
<span style="font-family: Courier New, Courier, monospace;"><br /></span>
<br />
<h3>
Creating a Database for Drupal</h3>
A database for Drupal must be created in the DB server installed in the previous section. The MySQL port sets no password for the root user connecting from localhost; for this reason, setting its password is recommended (in <b>bold</b> the text input by the user):<br />
<br />
<span style="font-family: Courier New, Courier, monospace;"># <b>mysql -u root</b></span><br />
<span style="font-family: Courier New, Courier, monospace;">Welcome to the MySQL monitor. Commands end with ; or \g.</span><br />
<span style="font-family: Courier New, Courier, monospace;">[...snip...]</span><br />
<span style="font-family: Courier New, Courier, monospace;">mysql> <b>set password for root@localhost=PASSWORD('your-password')</b></span><br />
<span style="font-family: Courier New, Courier, monospace;">mysql> <b>exit</b></span><br />
<span style="font-family: Courier New, Courier, monospace;">Bye</span><br />
<br />
Once the password is set, you can try to reconnect (in <b><i>italic bold</i></b> the variables whose name should be changed with your values of choice):<br />
<br />
<span style="font-family: Courier New, Courier, monospace;"># <b>mysql -u root -p</b></span><br />
<span style="font-family: Courier New, Courier, monospace;">Enter password:</span><br />
<span style="font-family: Courier New, Courier, monospace;">Welcome to the MySQL monitor. Commands end with ; or \g.</span><br />
<span style="font-family: Courier New, Courier, monospace;">[...snip...]</span><br />
<span style="font-family: Courier New, Courier, monospace;">mysql> <b>create database <i>drupal_database_name</i>;</b></span><br />
<span style="font-family: Courier New, Courier, monospace;">mysql> <b>create user '<i>drupal_user</i>'@'<i>localhost</i>' identified by '<i>password</i>';</b></span><br />
<span style="font-family: Courier New, Courier, monospace;">mysql> <b>grant all privileges on <i>drupal_database_name</i>.* to '<i>drupal_user</i>'@'<i>localhost</i>' with grant option;</b></span><br />
<span style="font-family: Courier New, Courier, monospace;">mysql> <b>flush privileges;</b></span><br />
<span style="font-family: Courier New, Courier, monospace;"><b><br /></b></span>
<br />
<h3>
Configuring the Apache HTTP Server</h3>
Now that everything is in place, we can configure the web server so that it starts serving the Drupal web application. The tasks to perform are the following<br />
<ul>
<li>Configuring the required modules.</li>
<li>Configuring a virtual host to serve Drupal.</li>
<li>Configuring a MIME/type for PHP.</li>
</ul>
<br />
The modules required to run Drupal are <span style="font-family: Courier New, Courier, monospace;">mod_rewrite</span> and the PHP module. The latter was configured automatically by the PHP module port, and the latter can be configured uncommenting the following line from <span style="font-family: Courier New, Courier, monospace;">/usr/local/etc/apache24/httpd.conf</span>:<br />
<br />
<span style="font-family: Courier New, Courier, monospace;">LoadModule rewrite_module libexec/apache24/mod_rewrite.so</span><br />
<br />
The cleanest way to segregate the Drupal configuration is creating a <i>virtual host</i> for it. An additional advantage of this approach is that Drupal will be served from the root path (<span style="font-family: Courier New, Courier, monospace;">/</span>) and you won't need to use any rewrite rule to achieve the same result. Assuming the host name and the port where Drupal will be published is <span style="font-family: Courier New, Courier, monospace;">drupal.host.name:80</span>, then create a file in <span style="font-family: Courier New, Courier, monospace;">/usr/local/etc/apache24/Includes</span> named <span style="font-family: Courier New, Courier, monospace;">drupal.conf</span> and define the skeleton of the virtual host:<br />
<br />
<span style="font-family: Courier New, Courier, monospace;"><VirtualHost *:80></span><br />
<span style="font-family: Courier New, Courier, monospace;"> ServerName drupal.host.name</span><br />
<span style="font-family: Courier New, Courier, monospace;"><br /></span>
<span style="font-family: Courier New, Courier, monospace;"> # Drupal directory configuration placeholder</span><br />
<span style="font-family: Courier New, Courier, monospace;"> </span><br />
<span style="font-family: Courier New, Courier, monospace;"> ErrorLog ${APACHE_LOG_DIR}/drupal-error.log</span><br />
<span style="font-family: Courier New, Courier, monospace;"> LogLevel warn</span><br />
<span style="font-family: Courier New, Courier, monospace;"> CustomLog ${APACHE_LOG_DIR}/drupal-access.log combined</span><br />
<span style="font-family: Courier New, Courier, monospace;"></VirtualHost></span><br />
<br />
In the default configuration of Apache in FreeBSD, any <span style="font-family: Courier New, Courier, monospace;">.conf</span> file in this directory is included automatically, so that no additional code is required to add the virtual host to the web server configuration. In this fragment I've used an environment variable (${APACHE_LOG_DIR}) to separate some server configuration variables that could be reused in external scripts. To define environment variables, a <span style="font-family: Courier New, Courier, monospace;">.env</span> file must be created in <span style="font-family: Courier New, Courier, monospace;">/usr/local/etc/apache24/envvars.d</span> such as:<br />
<br />
The Drupal directory fragment defines the DocumentRoot of the virtual host and some of the required options:<br />
<br />
<span style="font-family: Courier New, Courier, monospace;">DocumentRoot /usr/local/www/drupal7</span><br />
<span style="font-family: Courier New, Courier, monospace;"><Directory "/usr/local/www/drupal7"></span><br />
<span style="font-family: Courier New, Courier, monospace;"> Options Indexes FollowSymLinks</span><br />
<span style="font-family: Courier New, Courier, monospace;"> AllowOverride All</span><br />
<span style="font-family: Courier New, Courier, monospace;"> Require all granted</span><br />
<span style="font-family: Courier New, Courier, monospace;"></Directory></span><br />
<br />
The option <span style="font-family: Courier New, Courier, monospace;">AllowOverride</span> set to <span style="font-family: Courier New, Courier, monospace;">All</span> is required so that <span style="font-family: Courier New, Courier, monospace;">.htaccess</span> files shipped with Drupal are taken into account by the Apache HTTP Server. In this fragment, the path of the Drupal installation directory of the FreeBSD port is used. If you installed Drupal using alternative methods (such as <span style="font-family: Courier New, Courier, monospace;">drush</span>), update the path accordingly.<br />
<br />
The complete virtual host configuration file is:<br />
<br />
<script src="https://gist.github.com/emcrisostomo/77f97fd0a07bf5ab87f8.js"></script>
Finally, the Apache HTTP Server must be instructed to execute the PHP code contained in PHP pages and to do so we need to add a MIME/type for them adding the following line in httpd.conf:<br />
<br />
<span style="font-family: Courier New, Courier, monospace;"><IfModule mime_module></span><br />
<span style="font-family: Courier New, Courier, monospace;"><br /></span>
<span style="font-family: Courier New, Courier, monospace;"> # Content has been trimmed</span><br />
<span style="font-family: Courier New, Courier, monospace;"><br /></span>
<span style="font-family: Courier New, Courier, monospace;"> # Add MIME type for PHP</span><br />
<span style="font-family: Courier New, Courier, monospace;"> AddType application/x-httpd-php .php</span><br />
<span style="font-family: Courier New, Courier, monospace;"><br /></span>
<span style="font-family: Courier New, Courier, monospace;"></IfModule></span><br />
<br />
Once all the settings are in place, Apache can be restarted and you can point your browser to http://drupal.host.name/ where the Drupal installation wizard will welcome you and will require you to input the database configuration and other Drupal website settings.<br />
<br />
To restart the Apache HTTP Server, the following command can be used:<br />
<br />
<span style="font-family: Courier New, Courier, monospace;"># service apache24 restart</span><br />
<br />
<h3>
Configuring Drupal behind a Proxy Server</h3>
Machines connecting to enterprise network often are not connected directly to the Internet but require the use of a web proxy server instead. Drupal can be configured to use a web proxy server by setting the following variables in <span style="font-family: Courier New, Courier, monospace;">${DRUPAL_HOME}/sites/default/settings.php</span>. If this file does not exist, copy the file <span style="font-family: Courier New, Courier, monospace;">default.settings.php</span> (shipped with Drupal) into <span style="font-family: Courier New, Courier, monospace;">settings.php</span>. The configuration variable that enable proxy support are the following:<br />
<br />
<script src="https://gist.github.com/emcrisostomo/be60d41ed6354e0bede1.js"></script>
Depending on your proxy settings, different values may be used.<br />
<br />
Beware that although Drupal itself (Core) supports a proxy, many third-party modules still do not. One notable exception at the time of writing is the <i><a href="https://www.drupal.org/project/recaptcha" target="_blank">reCaptcha</a></i> module which will not work without a direct Internet connection.<br />
<br />
<h3>
Setting Up Clean URLs</h3>
Last but not least, clean URLs support may be enabled. Drupal performs a sanity check and will not allow you to enable the Clean URLs feature if the test does not pass. However, I have found plenty of <i>false negatives</i> when running Drupal 7 on FreeBSD: if the Clean URL test fails in your installation, try checking if clean URLs are working and use the workaround described in the <a href="https://www.drupal.org/getting-started/clean-urls" target="_blank">official Drupal documentation</a> and forcibly enable Clean URLs.Enrico M. Crisostomohttp://www.blogger.com/profile/02688166348157974808noreply@blogger.com5tag:blogger.com,1999:blog-7952810330436823110.post-91825948161951468322014-09-27T13:25:00.000+02:002014-09-27T13:26:07.708+02:00fswatch 1.4.5 - Release Notes<a href="https://github.com/emcrisostomo/fswatch" target="_blank">fswatch</a> 1.4.5 has been <a href="https://github.com/emcrisostomo/fswatch/releases/tag/1.4.5" target="_blank">released</a>.<br />
<br />
New features and bug fixes added since v. 1.4.0 are:<br />
<br />
<ul>
<li>Add custom record formats.</li>
<li>Localize <span style="font-family: Courier New, Courier, monospace;">fswatch</span> and <span style="font-family: Courier New, Courier, monospace;">libfswatch</span> using GNU <span style="font-family: Courier New, Courier, monospace;">gettext</span>.</li>
<li>Add Italian (it) localization.</li>
<li>Add Spanish (es) localization.</li>
<li>Fix <span style="font-family: Courier New, Courier, monospace;">Makefile.am</span> because of broken link when <span style="font-family: Courier New, Courier, monospace;">DESTDIR</span> installs are performed.</li>
<li>Fix bug in <span style="font-family: Courier New, Courier, monospace;">fswatch-run</span> wrapper script for ZSH which caused last argument not to be split when passed to <span style="font-family: Courier New, Courier, monospace;">xargs</span>.</li>
<li>Add batch marker feature to delimit the boundaries of a batch of events.</li>
<li>Add Texinfo documentation.</li>
<li><span style="font-family: Courier New, Courier, monospace;">libfswatch</span> API is now versioned.</li>
<li>Improved Autoconf checks.</li>
<li>The inotify monitor now waits for events and honours the latency settings.</li>
<li>Automaticaly generate the <span style="font-family: Courier New, Courier, monospace;">ChangeLog</span> using Git.</li>
<li>Update <span style="font-family: Courier New, Courier, monospace;">autogen.sh</span> to honour some commonly used environment variables.</li>
<li>The inotify monitor now provides the same functionality provided by all the other monitors.</li>
<li>Recursive directory monitoring is now implemented.</li>
<li>Version and revision is now determined dynamically from Git by ancillary scripts invoked by the GNU Build System.</li>
<li><span style="font-family: Courier New, Courier, monospace;">fswatch</span> does not compile on OS X < 10.9 because some required C++11 classes are not supported by the C++ runtime.</li>
<li><span style="font-family: Courier New, Courier, monospace;">fswatch</span> does not compile on OS X < 10.9 because some required C++11 classes are not supported by the C++ runtime.</li>
<li>The <span style="font-family: Courier New, Courier, monospace;">libfswatch</span> library has been added with bindings for C and C++.</li>
<li><span style="font-family: Courier New, Courier, monospace;">fswatch</span> let users specify the monitor to use by name.</li>
</ul>
Enrico M. Crisostomohttp://www.blogger.com/profile/02688166348157974808noreply@blogger.com0tag:blogger.com,1999:blog-7952810330436823110.post-89543673758646148662014-08-21T11:25:00.000+02:002014-09-27T13:25:28.283+02:00fswatch 1.4.0 - Release Notes<a href="https://github.com/emcrisostomo/fswatch/releases/tag/1.4.0" target="_blank">fswatch 1.4.0 has been released</a> bringing few but important updates:<br />
<ul>
<li>Monitor implementations are found at runtime so no more hardcoded options to choose a specific monitor (the plugging mechanism still needs improvements).</li>
<li>The <span style="font-family: Courier New, Courier, monospace;">fswatch</span> engine has been moved to a separate library called <span style="font-family: Courier New, Courier, monospace;">libfswatch</span> with bindings for C and C++. If you need to use the functionality of <span style="font-family: Courier New, Courier, monospace;">fswatch</span> from your program, now it's very easy to do. The library and its headers are distributed in the same <span style="font-family: Courier New, Courier, monospace;">fswatch</span> bundle.</li>
<li>On OS X <span style="font-family: Courier New, Courier, monospace;">fswatch</span> can now be installed from either <a href="https://www.macports.org/" target="_blank">MacPorts</a> and <a href="http://brew.sh/" target="_blank">Homebrew</a> (see <span style="font-family: Courier New, Courier, monospace;">README</span> for more information).</li>
</ul>
<br />
I hope you enjoy using <span style="font-family: Courier New, Courier, monospace;">fswatch</span> as much as I enjoy writing it.Enrico M. Crisostomohttp://www.blogger.com/profile/02688166348157974808noreply@blogger.com0tag:blogger.com,1999:blog-7952810330436823110.post-72773859653955919422014-08-19T22:41:00.002+02:002014-08-19T22:41:21.195+02:00Writing a MacPorts Portfile (and Testing It on a Local Repository)As a MacPorts user, it is maybe funny that <a href="http://emcrisostomo.github.io/fswatch/" target="_blank">fswatch</a> is available on <a href="http://brew.sh/" target="_blank">Homebrew</a> and not on <a href="https://www.macports.org/" target="_blank">MacPorts</a>. Today I put an end to this idiosyncrasy of mine and submitted my first MacPorts port file.<br />
<br />
I was pleasantly surprised to discover that, although a deceiving initial impression, setting up my first port file was <i>way</i> easier than I first believed. Furthermore, the MacPorts guys have been very supportive and provided many insights that helped me improve the port file and my understanding of the MacPorts port system (beyond what is described in the nice <a href="https://guide.macports.org/" target="_blank">MacPorts Guide</a>).<br />
<br />
<h2>
The Basic Portfile</h2>
The basic Portfile for a source tarball generated by the GNU Build System, that is a package which is built and installed with the now classic:<br />
<br />
<span style="font-family: Courier New, Courier, monospace;">$ ./configure</span><br />
<span style="font-family: Courier New, Courier, monospace;">$ make</span><br />
<span style="font-family: Courier New, Courier, monospace;">$ make install</span><br />
<br />
is typically very simple, since these two operations are performed out of the box by the Configure, Build and Destroot phases of a port installation life cycle.<br />
<br />
In this case, the basic Portfile includes:<br />
<ul>
<li>The <i>modeline</i> (optional).</li>
<li>The Subversion ID tag: placeholder string automatically expanded by the MacPorts infrastructure.</li>
<li>The <i>PortSystem</i> line: required by all ports.</li>
<li>The port <i>name</i> and <i>version</i>: many other port variables (including the source tarball name) depend on these values.</li>
<li>The <i>category</i> line: one or more port categories.</li>
<li>The <i>platform</i>: darwin most of the times.</li>
<li>The <i>maintainers</i>.</li>
<li>The short and long <i>description</i>.</li>
<li>The <i>homepage</i>.</li>
<li>The <i>download</i> URLs.</li>
<li>The <i>checksums</i> (used to verify the integrity of the downloaded files).</li>
<li>The <i>dependencies</i> (optional).</li>
<li>The <i>configure</i> arguments (optional).</li>
</ul>
<div>
A fully working, basic port is the following:</div>
<br />
<script src="https://gist.github.com/emcrisostomo/8b2c600accedb20a933b.js"></script>
In this example you can see how the download URL is split in two pieces: the <span style="font-family: Courier New, Courier, monospace;">master_sites</span> and the <span style="font-family: Courier New, Courier, monospace;">distfiles</span> (or <span style="font-family: Courier New, Courier, monospace;">distnames</span>). The rationale behind this choice is the fact that a package may typically be hosted by multiple master sites (such as mirrors).<br />
<br />
In this example, <span style="font-family: Courier New, Courier, monospace;">distfiles</span> is specified. This variable contains the full distribution file name, including the suffix (the file extension). By default this value is set to <span style="font-family: Courier New, Courier, monospace;">${distname}${extract.suffix}</span>. You may as well define the <span style="font-family: Courier New, Courier, monospace;">distname</span> (which defaults to <span style="font-family: Courier New, Courier, monospace;">${name}-${version}</span>) and the <span style="font-family: Courier New, Courier, monospace;">extract.suffix</span> separately. These parameters, in the example above, are redundant, since they simply set the corresponding default value (and <span style="font-family: Courier New, Courier, monospace;">use_zip</span> is used as a shortcut to set <span style="font-family: Courier New, Courier, monospace;">extract.suffix</span> and other variables related to processing zip files).<br />
<br />
<h2>
A Portfile for a GitHub-Hosted Project</h2>
<span style="font-family: Courier New, Courier, monospace;">fswatch</span>, such as many other projects nowadays, is hosted at GitHub. Although not yet documented on the MacPorts Guide, a recently added <span style="font-family: Courier New, Courier, monospace;">PortGroup</span> called <span style="font-family: Courier New, Courier, monospace;">github</span> greatly simplifies the Portfile for such projects. The only existing documentation, at the moment, is <a href="https://trac.macports.org/browser/trunk/dports/_resources/port1.0/group/github-1.0.tcl" target="_blank">this port group source code</a>.<br />
<br />
Many of the aforementioned configuration variables are inferred by a much simpler GitHub configuration such as:<br />
<br />
<span style="font-family: Courier New, Courier, monospace;">github.setup emcrisostomo fswatch 1.3.9</span><br />
<span style="font-family: Courier New, Courier, monospace;">github.tarball_from releases</span><br />
<br />
This expands to:<br />
<ul>
<li><span style="font-family: Courier New, Courier, monospace;">name</span> is set as the GitHub project name (<span style="font-family: Courier New, Courier, monospace;">fswatch</span> in this case).</li>
<li><span style="font-family: Courier New, Courier, monospace;">version</span> is set as the GitHub version tag (<span style="font-family: Courier New, Courier, monospace;">1.3.9</span> in this case).</li>
<li>The download URL and the distribution file name is inferred from the repository configuration and the corresponding release URL. If the distribution file name is different than the default (<span style="font-family: Courier New, Courier, monospace;">${name}-${version}</span>) then you still have to configure it as described in the previous section.</li>
</ul>
The resulting Portfile is the following:<br />
<br />
<script src="https://gist.github.com/emcrisostomo/854dd2c3fed0d34fa582.js"></script>
<br />
<h2>
Checking Your Portfile</h2>
The <span style="font-family: Courier New, Courier, monospace;">port</span> utility can check whether a Portfile conforms to the MacPorts guidelines using the <span style="font-family: Courier New, Courier, monospace;">lint</span> command:<br />
<br />
<span style="font-family: Courier New, Courier, monospace;">$ port lint --nitpick fswatch</span><br />
<span style="font-family: Courier New, Courier, monospace;">---> Verifying Portfile for fswatch</span><br />
<span style="font-family: Courier New, Courier, monospace;">---> 0 errors and 0 warnings found.</span><br />
<br />
In the example above the fswatch Portfile passes verification with no errors nor warnings. Be sure to check your Portfile before submitting it to the MacPorts repository.<br />
<br />
<h2>
Testing Your Portfile With a Local Repository</h2>
You can test and store your Portfiles in a local repository before submitting them to a public repository in a private repository. Furthermore, you can take advantage of the MacPorts package management features to maintain your own local packages.<br />
<br />
Adding a Portfile to a local repository is very simple:<br />
<ul>
<li>Create the local repository directory somewhere (if it does not exist).</li>
<li>Create a subdirectory (if it does not exist) named after the primary category of the port you are adding.</li>
<li>Create a subdirectory named after the port.</li>
<li>Move the Portfile into this directory.</li>
<li>Make sure the user <span style="font-family: Courier New, Courier, monospace;">macports</span> has sufficient privileges to read the repository (I usually give him ownership of the port directory).</li>
<li>Update the port repository indexes running portindex from the repository root.</li>
</ul>
<br />
<script src="https://gist.github.com/emcrisostomo/dcc90cf148757051f22e.js"></script>
If you have not done it yet, you have to configure MacPorts to use your local repository, adding a line in <span style="font-family: Courier New, Courier, monospace;">$MACPORTS_HOME/etc/macports/sources.conf</span>:<br />
<br />
<span style="font-family: Courier New, Courier, monospace;">file:///ports</span><br />
<br />
right above any other repository so that ports in the local one take precedence over ports in the public repository.<br />
<br />
If everything is setup correctly, you will be able to query and install ports from your local repository.<br />
<br />
<h2>
Further Readings</h2>
A basic Portfile such as what I described in this blog post is just the beginning: we only scratched the surface of what MacPorts can offer you. If you want to get further information about MacPorts and the facilities it provides (either from an user or a developer standpoint), start from the <a href="https://guide.macports.org/" target="_blank">MacPorts Guide</a>.Enrico M. Crisostomohttp://www.blogger.com/profile/02688166348157974808noreply@blogger.com1tag:blogger.com,1999:blog-7952810330436823110.post-90148130508991340482014-08-19T17:11:00.005+02:002014-08-19T17:11:55.679+02:00Public Domain Flags Archive (in Vector Image Format)Some time ago, when I was implementing the <a href="https://github.com/emcrisostomo/EMCCountryPickerController" target="_blank">EMCCountryPickerController</a> component I described in some earlier posts (such as <a href="http://thegreyblog.blogspot.com/2014/06/emccountrypickercontroller-v-130-has.html" target="_blank">this one</a>), I soon realised I needed high quality images of the flags of all the countries listed in the <a href="http://en.wikipedia.org/wiki/ISO_3166" target="_blank">ISO 3166-1 standard</a>. And since the EMCCountryPickerController library is GPL-licensed, I needed images whose license was compatible with it in order to distribute them together with the component.<br />
<br />
I found decent collections of flags in the internet but at the end I decided to build my own, especially in order to overcome problems that arose from the limited resolution of many image collections.<br />
<br />
I picked the flags from <a href="http://commons.wikimedia.org/wiki/Main_Page" target="_blank">Wikimedia Commons</a> since they're available in SVG format (a widely used vector image format). This way, if I need to, I can render a flag at any resolution.<br />
<br />
I then assembled a <a href="https://github.com/emcrisostomo/flags" target="_blank">GitHub repository</a> where you can find:<br />
<ul>
<li>All the flags in SVG format.</li>
<li>All the flags in PNG format scaled to a width of 256 pixels.</li>
<li>All the flags in PNG format, scaled to a width of 512 pixels.</li>
</ul>
<br />
The following is a shell script that can be used to render the flags archive at the desired widths.<br />
<br />
<script src="https://gist.github.com/emcrisostomo/607ee2832353d1991c6d.js"></script>
The script requires <span style="font-family: Courier New, Courier, monospace;">librsvg</span> to be installed.Enrico M. Crisostomohttp://www.blogger.com/profile/02688166348157974808noreply@blogger.com2tag:blogger.com,1999:blog-7952810330436823110.post-8759065379299073432014-06-20T01:03:00.001+02:002015-01-28T09:30:03.769+01:00Installing Logstash v 1.4 (and Greater) on FreeBSDIn a <a href="http://thegreyblog.blogspot.com/2014/01/installing-logstash-on-freebsd.html" target="_blank">previous post</a> I described how to install Logstash (v. 1.3 and previous) on FreeBSD and in this post I will describe how to install Logstash v. 1.4 and greater.<br />
<br />
Until version 1.3 included, Logstash was distributed as a single JAR file, and when version 1.4 was released a new packaging style was introduced. As a consequence, new instructions are required to properly setup Logstash in FreeBSD and registering it as a <i>service</i>. Further information about the new distribution layout can be found in the <a href="http://logstash.net/docs/1.4.1/release-notes" target="_blank">Logstash release notes</a>.<br />
<br />
As seen in the previous post, a Logstash FreeBSD port exists, but it is currently outdated since it bundles Logstash v. 1.2. But while this could be used as a starting point for JAR-based Logstash installations (as we have seen, the update process only required updating the Logstash JAR), this is not possible with the new Logstash distribution because the included rc script will fail to work.<br />
<br />
<b>Edit:</b> I've managed to patch the broken Logstash dependency and I'm waiting for the pull request to be merged upstream. In the meantime you can use <a href="https://github.com/emcrisostomo/FreeBSD-Ports/tree/master/ports/sysutils/logstash" target="_blank">an updated FreeBSD port</a> I've created to install Logstash on FreeBSD 10.<br />
<br />
Edit: The Logstash port has been updated and I'm the new maintainer. Also, the <a href="https://github.com/jnr/jnr-ffi/pull/26" target="_blank">pull request</a> solving a JRuby bug on FreeBSD has been merged to upstream and will hopefully hit a Logstash release soon.<br />
<br />
Skimming through the original post is recommended because it provides general information about Logstash and FreeBSD which is required to properly plan and execute a Logstash setup.<br />
<br />
<h2>
Prerequisites</h2>
The essential prerequisites required to execute Logstash are:<br />
<ul>
<li>A working Java runtime environment.</li>
<li>An <a href="http://www.elasticsearch.org/" target="_blank">ElasticSearch</a> instance.</li>
</ul>
The former is required because LogStash is a JRuby application while the latter, although not technically a requirement, is the recommended output for Logstash.<br />
<br />
<h3>
Installing Java</h3>
To install OpenJDK on FreeBSD you can use pkg to install a ready-to-use binary package:<br />
<br />
<span style="font-family: Courier New, Courier, monospace;"># pkg install openjdk</span><br />
<br />
Currently, this command will install an instance of OpenJDK v. 7 in both FreeBSD 9 and 10. If you'd rather install a different version, you can search the available packages and pick the one you prefer (command output has been filtered for brevity):<br />
<br />
<span style="font-family: Courier New, Courier, monospace;"># pkg search openjdk</span><br />
<span style="font-family: Courier New, Courier, monospace;">openjdk-7.60.19,1</span><br />
<span style="font-family: Courier New, Courier, monospace;">openjdk6-b31_3,1</span><br />
<span style="font-family: Courier New, Courier, monospace;">openjdk8-8.5.13_7</span><br />
<span style="font-family: Courier New, Courier, monospace;"># pkg install openjdk8-8.5.13_7</span><br />
<br />
<h3>
Installing ElasticSearch</h3>
Logstash includes an embedded ElasticSearch instance you can use for standalone installations (see <a href="http://thegreyblog.blogspot.com/2014/01/installing-logstash-on-freebsd.html" target="_blank">my previous post</a> for an introductory view on Logstash operation modes). The required configuration to bootstrap the embedded ElasticSearch instance and to have Logstash use it as its outputs is described in the following sections.<br />
<br />
Although simpler from the standpoint of the configuration, Logstash installations using separate ElasticSearch instances are out of the scope of this post.<br />
<br />
<h2>
Installing Logstash</h2>
Logstash installation procedure is fairly simple since it is distributed as a tarball:<br />
<ul>
<li>Download Logstash from the <a href="http://logstash.net/" target="_blank">official website</a>.</li>
<li>Extract the tarball in the designated installation directory (my personal suggestion is to avoid <span style="font-family: Courier New, Courier, monospace;">/usr/local</span> because it is used by ports and to use <span style="font-family: Courier New, Courier, monospace;">/opt</span> instead).</li>
</ul>
<div>
<br /></div>
<div>
<h2>
Creating an rc.d Script</h2>
An <span style="font-family: Courier New, Courier, monospace;">rc.d</span> script is required in a BSD system to register a <i>service</i>, define its configuration and have the rc framework manage its lifetime. The <a href="https://gist.github.com/emcrisostomo/f7a309de84a7c0da09cc" target="_blank">following script</a> can be used as is or as a starting point to customise your own. If used as is, be aware that the script uses the following default values:<br />
<ul>
<li>Installation directory: <span style="font-family: Courier New, Courier, monospace;">${logstash14_home="/opt/logstash-1.4.1"}</span></li>
<li>Configuration file path: <span style="font-family: Courier New, Courier, monospace;">${logstash14_config="/usr/local/etc/${name}/${name}.conf"}</span></li>
<li>ElasticSearch data directory: <span style="font-family: Courier New, Courier, monospace;">${logstash14_elastic_datadir="/var/db/logstash14"}</span></li>
<li>Java home: <span style="font-family: Courier New, Courier, monospace;">${logstash14_java_home="/usr/local/openjdk6"}</span></li>
</ul>
<div>
<script src="https://gist.github.com/emcrisostomo/f7a309de84a7c0da09cc.js"></script>
You can override any of the supported configuration values in the <span style="font-family: Courier New, Courier, monospace;">/etc/rc.conf</span> file. If, for example, you want to use an alternate Java home path, just add the following line to <span style="font-family: Courier New, Courier, monospace;">/etc/rc.conf</span> setting the desired value:<br />
<br />
<span style="font-family: Courier New, Courier, monospace;">logstash14_java_home="/usr/local/openjdk7"</span><br />
<br />
<h3>
Testing the Service</h3>
To test the Logstash service, the following command can be used:<br />
<br />
<span style="font-family: Courier New, Courier, monospace;"># service logstash14 onestart</span><br />
<br />
To stop it, use:<br />
<br />
<span style="font-family: Courier New, Courier, monospace;"># service logstash14 onestop</span><br />
<br />
To help troubleshooting any problem you might find you can enable the Logstash log, setting the <span style="font-family: Courier New, Courier, monospace;">logstash14_log</span> variable to <span style="font-family: Courier New, Courier, monospace;">YES</span> in the <span style="font-family: Courier New, Courier, monospace;">/etc/rc.conf</span> file:<br />
<br />
<span style="font-family: Courier New, Courier, monospace;">logstash14_log="YES"</span><br />
<br />
The log file location is specified by the <span style="font-family: Courier New, Courier, monospace;">logstash14_log_file</span> variable, whose default value is set by the service rc file (only the relevant lines are shown):<br />
<br />
<span style="font-family: Courier New, Courier, monospace;">name=logstash14</span><br />
<span style="font-family: Courier New, Courier, monospace;">logdir="/var/log"</span><br />
<span style="font-family: Courier New, Courier, monospace;">: ${logstash14_log_file="${logdir}/${name}.log"}</span><br />
<br />
The log file location can be overridden setting the <span style="font-family: Courier New, Courier, monospace;">logstash14_log_file</span> variable in the <span style="font-family: Courier New, Courier, monospace;">/etc/rc.conf</span> file.<br />
<br />
<h3>
Enabling the Service</h3>
</div>
Note that the rc script described above does <i>not</i> enable the Logstash service:<br />
<br />
<span style="font-family: Courier New, Courier, monospace;">: ${logstash14_enable="NO"}</span><br />
<br />
If everything works, you can enable the Logstash service just adding the following line to <span style="font-family: Courier New, Courier, monospace;">/etc/rc.conf</span>:<br />
<br />
<span style="font-family: Courier New, Courier, monospace;">logstash14_enable="YES"</span></div>
Enrico M. Crisostomohttp://www.blogger.com/profile/02688166348157974808noreply@blogger.com8tag:blogger.com,1999:blog-7952810330436823110.post-5174972101127273072014-06-18T23:57:00.001+02:002014-06-19T17:03:12.974+02:00Pkg Update Fails in FreeBSD 9.2 Because of a Python Setuptools ConflictToday I launched <span style="font-family: Courier New, Courier, monospace;">pkg</span> to upgrade some binary packages installed in a FreeBSD 9.2 instance but suddenly <span style="font-family: Courier New, Courier, monospace;">pkg</span> failed complaining about a locally installed python package (<span style="font-family: Courier New, Courier, monospace;">py27-setuptools-2.0.1</span>) conflicting with the version required by it. The error began with the following statement, followed by a long list of repetitions of the same warning message:<br />
<br />
<span style="font-family: Courier New, Courier, monospace;">WARNING: locally installed </span><span style="font-family: 'Courier New', Courier, monospace;">py27-setuptools-2.0.1 conflicts on /usr/local/bin/easy_install with:</span><br />
<span style="font-family: Courier New, Courier, monospace;">- py27-setuptools27-2.0.1</span><br />
<br />
All the software in this box was installed using <span style="font-family: Courier New, Courier, monospace;">pkg</span> binary packages, so that at first this error sounded really strange to me.<br />
<br />
Even though you use <span style="font-family: Courier New, Courier, monospace;">pkg</span> to simplify package installations instead of compiling software from the ports collection, there is a file you should be aware of, especially if you are experiencing installation problems:<br />
<br />
<span style="font-family: Courier New, Courier, monospace;">/usr/ports/UPDATING</span><br />
<br />
This file contains important information about the update procedure and since binary packages are built from the port tree, the information applies even when installing with <span style="font-family: Courier New, Courier, monospace;">pkg</span>.<br />
<br />
A quick search starting from approximately the date of the last update of the affected machine pointed me in the right direction:<br />
<br />
<span style="font-family: Courier New, Courier, monospace;">20140307:</span><br />
<span style="font-family: Courier New, Courier, monospace;"> AFFECTS: users of devel/py-setuptools dependent ports</span><br />
<span style="font-family: Courier New, Courier, monospace;"> AUTHOR: sunpoet@FreeBSD.org</span><br />
<span style="font-family: Courier New, Courier, monospace;"><br /></span>
<span style="font-family: Courier New, Courier, monospace;"> devel/py-setuptools is being used for every python ports (if USE_PYDISTUTILS</span><br />
<span style="font-family: Courier New, Courier, monospace;"> defined) since r336553. Due to PKGORIGIN limitation, we cannot build one</span><br />
<span style="font-family: Courier New, Courier, monospace;"> python port with python27 and the other with python33 since they require</span><br />
<span style="font-family: Courier New, Courier, monospace;"> different setuptools versions which have same PKGORIGIN. With the addition</span><br />
<span style="font-family: Courier New, Courier, monospace;"> of py-setuptools{27,32,33}, we could now have py27-foo and py33-bar coexist</span><br />
<span style="font-family: Courier New, Courier, monospace;"> in one system.</span><br />
<span style="font-family: Courier New, Courier, monospace;"> [...]</span><br />
<br />
The suggested solution for <span style="font-family: Courier New, Courier, monospace;">pkg</span> users is:<br />
<br />
<span style="font-family: Courier New, Courier, monospace;"># pkg set -o devel/py-setuptools:devel/py-setuptoolsXX</span><br />
<br />
where <span style="font-family: Courier New, Courier, monospace;">XX</span> is the affected Python version. After running<br />
<br />
<span style="font-family: Courier New, Courier, monospace;"># pkg set -o devel/py-setuptools:devel/py-setuptools27</span><br />
<br />
<span style="font-family: Courier New, Courier, monospace;">pkg upgrade</span> went fine and the problem was solved.Enrico M. Crisostomohttp://www.blogger.com/profile/02688166348157974808noreply@blogger.com0tag:blogger.com,1999:blog-7952810330436823110.post-61563230638552377222014-06-16T20:18:00.000+02:002014-06-16T20:24:18.613+02:00NSControlTextEditingDelegate Methods Are Not Called on a the Delegate of a View-Based NSTableViewI was developing a OS X Cocoa application and the time came to validate the text input by the user while editing cells of an <span style="font-family: Courier New, Courier, monospace;">NSTableView</span>. My Cocoa-fu immediately suggested me to take advantage of the <span style="font-family: Courier New, Courier, monospace;">NSControlTextEditingDelegate</span> protocol that specifies the following two methods to hook exactly where I need to:<br />
<ul>
<li><span style="font-family: Courier New, Courier, monospace;">control:textShouldBeginEditing:</span></li>
<li><span style="font-family: Courier New, Courier, monospace;">control:textShouldEndEditing:</span></li>
</ul>
<br />
These two protocol methods are invoked on the delegate object. Everyday's Interface Builder outlet connection stuff, I thought, unaware I'd lose the rest of the day trying to have those method called. I then selected the text field in the editable column whose editing I wanted to be notified of:<br />
<br />
<div class="separator" style="clear: both; text-align: center;">
<a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEgz9OqjscUZXgDDh_BO-3ms23J14MOlGrhC9MkAKxQzBsB4O1I2acHlI9UcYfO8lWfgPqGuyiAxbfKZtBDasPIa5Kp_gZ5_wDcZkICBmPZ-qVqFa2tCVSMaTHHa60nogyTo5trzwj4rERAH/s1600/textfield.png" imageanchor="1" style="margin-left: 1em; margin-right: 1em;" target="_blank"><img border="0" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEgz9OqjscUZXgDDh_BO-3ms23J14MOlGrhC9MkAKxQzBsB4O1I2acHlI9UcYfO8lWfgPqGuyiAxbfKZtBDasPIa5Kp_gZ5_wDcZkICBmPZ-qVqFa2tCVSMaTHHa60nogyTo5trzwj4rERAH/s1600/textfield.png" /></a></div>
<br />
Then I selected the <i>Connection Inspector</i> and connected the <span style="font-family: Courier New, Courier, monospace;">delegate</span> outlet to the target object:<br />
<br />
<div class="separator" style="clear: both; text-align: center;">
<a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEjg_RQrabmlY3R_Y0qOFU3K1yOAGZgyT9F2cE2YDVaReFA8_CeJV-tdUZCU3UXaC5_3BGCvepGccRlZD6tRBpzlH8cQVzJB9VYv2HfKeuh2qojXCcRQT5_EOGbs9hBsHYoI7FS4LKHyJLMo/s1600/outlet.png" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"><img border="0" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEjg_RQrabmlY3R_Y0qOFU3K1yOAGZgyT9F2cE2YDVaReFA8_CeJV-tdUZCU3UXaC5_3BGCvepGccRlZD6tRBpzlH8cQVzJB9VYv2HfKeuh2qojXCcRQT5_EOGbs9hBsHYoI7FS4LKHyJLMo/s1600/outlet.png" /></a></div>
<br />
Finally, I implemented the two aforementioned methods on the delegate object, ran the application and... nothing happened!<br />
<br />
<h2>
The Official Documentation</h2>
I'll won't tell about the frustration I felt trying to do one of the simplest and most paradigmatic tasks in Cocoa programming: setting a delegate and implementing the corresponding protocol. Suffice it to say, I felt like I had some evident bug in front my eyes but could not notice it. Not immediately, not after a cup of tea or two, not after a hour diving into the documentation I could find.<br />
<br />
I revised <a href="https://developer.apple.com/library/mac/documentation/cocoa/reference/NSControlTextEditingDelegate_Protocol/Reference/Reference.html" target="_blank">the documentation</a>, outlets and the code over and over again, but I could not detect the problem. Then I noticed that <a href="http://stackoverflow.com/questions/9989498/textshouldendediting-does-not-get-called-in-nstableview" target="_blank">I was not the only one</a> struggling with this issue, although no solution was provided.<br />
<br />
To make a long story short, the documentation I checked seemed confirmed the it <i>should</i> have worked, until I found especially after reading an official <i>Apple Technical Q&A</i>, number <i>QA1551</i>, titled <i><a href="https://developer.apple.com/library/mac/qa/qa1551/_index.html" target="_blank">Detecting the start and end edit sessions of a cell in NSTableView</a></i>, stating the following:<br />
<br />
<blockquote class="tr_bq">
<blockquote class="tr_bq">
<b>A:</b> How do I detect start and end edit sessions of a cell in <span style="font-family: Courier New, Courier, monospace;">NSTableView</span>? </blockquote>
</blockquote>
<blockquote class="tr_bq">
<blockquote class="tr_bq">
In order to detect when a user is about to start and end an edit session of a cell in <span style="font-family: Courier New, Courier, monospace;">NSTableView</span>, you need to be set as the delegate of that table and implement the following <span style="font-family: Courier New, Courier, monospace;">NSControl</span> delegate methods:</blockquote>
<blockquote class="tr_bq">
<span style="font-family: Courier New, Courier, monospace;">- (BOOL)control:(NSControl *)control textShouldBeginEditing:(NSText *)fieldEditor;</span></blockquote>
</blockquote>
<blockquote class="tr_bq">
<blockquote class="tr_bq">
<span style="font-family: Courier New, Courier, monospace;">- (BOOL)control:(NSControl *)control textShouldEndEditing:(NSText *)fieldEditor;</span></blockquote>
<blockquote class="tr_bq">
The table forwards the delegate message it is getting from the text view on to your delegate object using the <span style="font-family: Courier New, Courier, monospace;">control:textShouldEndEditing:</span> method. This way your delegate can be informed of which control the text view field editor is acting on its behalf.</blockquote>
</blockquote>
<br />
So, you should <i>not</i> set the editable field delegate but the table one! Fortunately, that was easy to change. I removed the connection to the <span style="font-family: Courier New, Courier, monospace;">delegate</span> outlet in the text field and set the table one instead. I started the application and... nothing happened again!<br />
<br />
At this point I felt at a loss and started to wonder whether some code in my application was interfering with the editing notification path. I created a new Cocoa application and quickly replicated the solution suggested in the Apple documentation but the result was the same: the delegate methods were not being called.<br />
<br />
<h2>
The Solution</h2>
The solution was simple, and fortunately not very different from what a Cocoa programmer expects: setting a delegate and implementing a protocol. But while the protocol was the correct one (<span style="font-family: Courier New, Courier, monospace;">NSControlTextEditingDelegate</span>), the delegate was not. Better yet: they were not.<br />
<br />
In fact, after some of tests I reached the following conclusions:<br />
<ul>
<li>A <i>cell-based</i> <span style="font-family: Courier New, Courier, monospace;">NSTableView</span> instance works as expected: setting the table delegate causes the <span style="font-family: Courier New, Courier, monospace;">NSControlTextEditingDelegate</span> protocol methods to be invoked on it.</li>
<li>A <i>view-based</i> <span style="font-family: Courier New, Courier, monospace;">NSTableView</span> instance (such as mine and almost surely most of the new <span style="font-family: Courier New, Courier, monospace;">NSTableView</span> instances out there) required both the table and the field delegates to be set for the <span style="font-family: Courier New, Courier, monospace;">NSControlTextEditingDelegate</span> protocol methods to be invoked.</li>
</ul>
<br />
I suspected that the aforementioned <i>Apple Technical Q&A QA1551</i> document only considers the case of cell-based tables despite its date of publication: view-based tables were introduced in OS X 10.6, shipped two months before this document was issued. To dispel my doubts I decided to experiment with both kinds of table and found the behaviour described above, one for each different kind of table.<br />
<br />
Nevertheless, and even though I dedicated a lot of time to skimming through the documentation, I was unable to find a mention of this issue in any other guide, API documentation or technical article from Apple. Even the very good <a href="https://developer.apple.com/library/mac/documentation/Cocoa/Conceptual/TableView/Introduction/Introduction.html#//apple_ref/doc/uid/10000026i-CH1-SW1" target="_blank"><i>Table View Programming Guide for Mac</i></a> makes no mention of this "peculiarity" despite being a fairly common use case.<br />
<br />
I hope this post helps anybody falling into the same trap to quickly solve his issues with getting <span style="font-family: Courier New, Courier, monospace;">NSControlTextEditingDelegate</span> notifications to his table delegate.Enrico M. Crisostomohttp://www.blogger.com/profile/02688166348157974808noreply@blogger.com6tag:blogger.com,1999:blog-7952810330436823110.post-6967052984503328732014-06-05T14:26:00.001+02:002014-06-05T14:26:34.717+02:00EMCCountryPickerController v. 1.3.0 Has Been Released<a href="https://github.com/emcrisostomo/EMCCountryPickerController" target="_blank">EMCCountryPickerController</a> v. 1.3.0 has been released bringing the possibility of resizing the flags shown in the table cells automatically resizing the cell height.<div>
<br /></div>
<div>
Here is a screenshot showing flags resized to fit in a square of size 20:<br /><div>
<br /></div>
<table align="center" cellpadding="0" cellspacing="0" class="tr-caption-container" style="margin-left: auto; margin-right: auto; text-align: center;"><tbody>
<tr><td style="text-align: center;"><a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEiVzY2OAh-hx7f00hGVtdfxZdOoQU0qfA7ojGFzXRVCSuPgWe1hZphPmwzKALCq7equRKqswsjFCLYorLA-4fnW9bRXJqMnHM2J5qtHcyWTk3uYjN2t2SR0VuBmgzgpwFeVwvvLtrrSigWO/s1600/main-view-small-flags.png" imageanchor="1" style="margin-left: auto; margin-right: auto;"><img border="0" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEiVzY2OAh-hx7f00hGVtdfxZdOoQU0qfA7ojGFzXRVCSuPgWe1hZphPmwzKALCq7equRKqswsjFCLYorLA-4fnW9bRXJqMnHM2J5qtHcyWTk3uYjN2t2SR0VuBmgzgpwFeVwvvLtrrSigWO/s1600/main-view-small-flags.png" height="320" width="222" /></a></td></tr>
<tr><td class="tr-caption" style="text-align: center;">Custom Flag Size - Sized to Fit into 20x20</td></tr>
</tbody></table>
<div>
<br /></div>
<div>
and here is a screenshot showing flags resized to fit in a square of size 80:</div>
<div>
<br /></div>
<table align="center" cellpadding="0" cellspacing="0" class="tr-caption-container" style="margin-left: auto; margin-right: auto; text-align: center;"><tbody>
<tr><td style="text-align: center;"><a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEieaezB0KD7PnpWvRvUmgrcKKJ4lSYIaC4BXK6AdJQcQiAU6ozdxEnWHeA6Ah477LM1vI2e89p8vKpk9zyQT8EHUpreI6jA6rdouLFVsxWr6RzYyUAYAP-mm9g0Rw8XJej5wmZjOdZ6eWXU/s1600/Screen+Shot+2014-06-05+at+14.23.19.png" imageanchor="1" style="margin-left: auto; margin-right: auto;" target="_blank"><img alt="" border="0" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEieaezB0KD7PnpWvRvUmgrcKKJ4lSYIaC4BXK6AdJQcQiAU6ozdxEnWHeA6Ah477LM1vI2e89p8vKpk9zyQT8EHUpreI6jA6rdouLFVsxWr6RzYyUAYAP-mm9g0Rw8XJej5wmZjOdZ6eWXU/s1600/Screen+Shot+2014-06-05+at+14.23.19.png" height="320" width="222" /></a></td></tr>
<tr><td class="tr-caption" style="text-align: center;">Custom Flag Size - Sized to Fit into 80x80</td></tr>
</tbody></table>
<div>
<br /></div>
<div>
<br /></div>
<div>
To set the desired flag size, just use the controller's flagSize property:</div>
<div>
<br /></div>
<div>
<span style="font-family: Courier New, Courier, monospace;">countryPicker.flagSize = 80;</span></div>
<div>
<br /></div>
<div>
You can get the latest version using <a href="http://cocoapods.org/">CocoaPods</a>, by adding a dependency to your <span style="font-family: Courier New, Courier, monospace;">Podfile</span>:<br />
<br />
<span style="font-family: Courier New, Courier, monospace;">pod 'EMCCountryPickerController' ~> '1.0'</span><br />
<br />
If you are already using EMCCountryPickerController, then you just need to update your pod repository index:<br />
<br />
<span style="font-family: Courier New, Courier, monospace;">$ pod repo update</span><br />
<br />
and then and update your outdated project dependencies running this command in the project root directory:<br />
<br />
<span style="font-family: 'Courier New', Courier, monospace;">$ pod update</span><br />
<span style="font-family: 'Courier New', Courier, monospace;"><br /></span>Enjoy.<br />
<br /></div>
</div>
Enrico M. Crisostomohttp://www.blogger.com/profile/02688166348157974808noreply@blogger.com0tag:blogger.com,1999:blog-7952810330436823110.post-12295024203092253782014-06-02T21:49:00.003+02:002014-06-02T21:49:33.142+02:00OS X: Creating Packages from the Command Line - Tutorial and a Makefile - Part II<a href="http://thegreyblog.blogspot.com/2014/06/os-x-creating-packages-from-command_2.html" target="_blank">In the previous part</a> of this tutorial we examined how <span style="font-family: Courier New, Courier, monospace;">pkgbuild</span> and <span style="font-family: Courier New, Courier, monospace;">productbuild</span> are used to build component packages and product archives. We also saw how <span style="font-family: Courier New, Courier, monospace;">hdiutil</span> can be used to create a DMG image file to nicely package and distribute your product archive.<br />
<br />
Although simple, the procedure is somewhat tedious: lot of typing, three different commands (four or more if we include building), lots of different paths and a many options. All of which, in a precise order, in order to satisfy the dependencies of each commands and to make sure the archives are updated whenever some component file changes.<br />
<br />
Exactly what a Makefile is for!<br />
<br />
<h2>
A Makefile to build a Product Archive</h2>
All the steps described in the previous part of this tutorial can be automated with a proper Makefile. The Makefile we are going to create is basic, but can be used as a starting point to provide your project a set of ready to go and easy to use make targets to package it into a product archive and distribute it into a DMG file. This Makefile assumes that it is located into your XCode project root directory so that project binaries can be built and installed using<br />
<br />
<span style="font-family: Courier New, Courier, monospace;">$ xcodebuild install</span><br />
<br />
If this is not the case, just update the relevant action to run the build from the correct directory.<br />
<br />
Let's start writing the Makefile in a top-down fashion. Let's add a default <span style="font-family: Courier New, Courier, monospace;">all</span> target depending on anything else:<br />
<ul>
<li><span style="font-family: Courier New, Courier, monospace;">$(DISTDIR)</span> is the source folder for the DMG file, where the product archive will be stored.</li>
<li><span style="font-family: Courier New, Courier, monospace;">$(DEPSDIR)</span> is an ancillary folder used to store directory. You can add more than one if component packages are stored in multiple folders, or remove it altogether if your product archive will be made up of a single component package.</li>
<li><span style="font-family: Courier New, Courier, monospace;">$(PRODUCT)</span> is the product archive.</li>
<li><span style="font-family: Courier New, Courier, monospace;">$(DMGFILE)</span> is the DMG image file creating from the source folder <span style="font-family: Courier New, Courier, monospace;">$(DISTDIR)</span>.</li>
</ul>
The resulting target is:<br />
<br />
<span style="font-family: Courier New, Courier, monospace;">.PHONY : all</span><br />
<span style="font-family: Courier New, Courier, monospace;">all : $(DISTDIR) $(DEPSDIR) $(PRODUCT) $(DMGFILE)</span><br />
<br />
<span style="font-family: Courier New, Courier, monospace;">$(DISTDIR)</span> and <span style="font-family: Courier New, Courier, monospace;">$(DEPSDIR)</span> are created by the Makefile since we assume it is the Makefile that populates them:<br />
<br />
<span style="font-family: Courier New, Courier, monospace;">$(DISTDIR) :</span><br />
<span style="font-family: Courier New, Courier, monospace;"> mkdir $(DISTDIR)</span><br />
<span style="font-family: Courier New, Courier, monospace;"><br /></span>
<span style="font-family: Courier New, Courier, monospace;">$(DEPSDIR) :</span><br />
<span style="font-family: Courier New, Courier, monospace;"> mkdir $(DEPSDIR)</span><br />
<br />
<span style="font-family: Courier New, Courier, monospace;">$(PRODUCT)</span>, the product archive, depends on:<br />
<ul>
<li><span style="font-family: Courier New, Courier, monospace;">$(BINARIES)</span>, the main component binaries.</li>
<li><span style="font-family: Courier New, Courier, monospace;">$(DEPENDENCY)</span>, a placeholder for the <i>dependencies</i>, a set of component packages to add to the product archive. If you have multiple dependencies, you will create multiple entries of this kind. You could omit this entry altogether, since <span style="font-family: Courier New, Courier, monospace;">productbuild</span> would fail if a required component package is missing, but I think it is preferable to have <span style="font-family: Courier New, Courier, monospace;">make</span> fail because of a missing target dependency.</li>
<li><span style="font-family: Courier New, Courier, monospace;">$(COMPONENT_PFILE)</span>, the component package property list file.</li>
<li><span style="font-family: Courier New, Courier, monospace;">$(COMPONENT)</span>, the component package.</li>
<li><span style="font-family: Courier New, Courier, monospace;">$(DISTRIBUTION_FILE)</span>, the distribution file.</li>
<li><span style="font-family: Courier New, Courier, monospace;">$(REQUIREMENTS)</span>, the requirements file.</li>
</ul>
<br />
<span style="font-family: Courier New, Courier, monospace;">$(PRODUCT) : $(BINARIES) $(REQUIREMENTS) \</span><br />
<span style="font-family: Courier New, Courier, monospace;"> $(DEPENDENCY) $(COMPONENT_PFILE) \</span><br />
<span style="font-family: Courier New, Courier, monospace;"> $(COMPONENT) $(DISTRIBUTION_FILE)</span><br />
<span style="font-family: Courier New, Courier, monospace;"> productbuild --distribution $(DISTRIBUTION_FILE) \</span><br />
<span style="font-family: Courier New, Courier, monospace;"> --resources . \</span><br />
<span style="font-family: Courier New, Courier, monospace;"> --package-path $(DEPSDIR) \</span><br />
<span style="font-family: Courier New, Courier, monospace;"> --package-path $(DEPENDENCYDIR) \</span><br />
<span style="font-family: Courier New, Courier, monospace;"> $(PRODUCT)</span><br />
<br />
The <span style="font-family: Courier New, Courier, monospace;">$(BINARIES)</span> are usually compiled and installed with <span style="font-family: Courier New, Courier, monospace;">xcodebuild</span>:<br />
<br />
<span style="font-family: Courier New, Courier, monospace;">$(BINARIES) :</span><br />
<span style="font-family: Courier New, Courier, monospace;"> xcodebuild install</span><br />
<br />
The component package property list file, <span style="font-family: Courier New, Courier, monospace;">$(COMPONENT_PFILE)</span>, must be created beforehand as seen in the previous post. Let's emit a meaningful error if it is missing referring to a target we will examine later on.<br />
<br />
<span style="font-family: Courier New, Courier, monospace;">$(COMPONENT_PFILE) :</span><br />
<span style="font-family: Courier New, Courier, monospace;"> @echo "Error: Missing component pfile."</span><br />
<span style="font-family: Courier New, Courier, monospace;"> @echo "Create a component pfile with make compfiles."</span><br />
<span style="font-family: Courier New, Courier, monospace;"> @exit 1</span><br />
<br />
The main component package <span style="font-family: Courier New, Courier, monospace;">$(COMPONENT)</span> depends on the binaries <span style="font-family: Courier New, Courier, monospace;">$(BINARIES)</span> and the component property list file <span style="font-family: Courier New, Courier, monospace;">$(COMPONENT_PFILE)</span> and it must be created with <span style="font-family: Courier New, Courier, monospace;">pkgbuild</span>, as seen in the previous part of this tutorial:<br />
<br />
<span style="font-family: Courier New, Courier, monospace;">$(COMPONENT) : $(BINARIES) $(COMPONENT_PFILE)</span><br />
<span style="font-family: Courier New, Courier, monospace;"> pkgbuild --root $(BINARIES) \</span><br />
<span style="font-family: Courier New, Courier, monospace;"> --component-plist $(COMPONENT_PFILE) \</span><br />
<span style="font-family: Courier New, Courier, monospace;"> $(COMPONENT)</span><br />
<br />
The distribution file $(DISTRIBUTION_FILE), as in the case of $(COMPONENT_PFILE), must be created beforehand. We will emit a meaningful error if it missing referring to a target we will examine later on:<br />
<br />
<span style="font-family: Courier New, Courier, monospace;">$(DISTRIBUTION_FILE) :</span><br />
<span style="font-family: Courier New, Courier, monospace;"> @echo "Error: Missing distribution file."</span><br />
<span style="font-family: Courier New, Courier, monospace;"> @echo "Create a distribution file with make distfiles."</span><br />
<span style="font-family: Courier New, Courier, monospace;"> @exit 1</span><br />
<br />
Now the Makefile is functional except for one detail: who is going to create the two required property list files <span style="font-family: Courier New, Courier, monospace;">$(COMPONENT_PFILE)</span> and <span style="font-family: Courier New, Courier, monospace;">$(DISTRIBUTION_FILE)</span>? We have seen in the previous part of this tutorial that both <span style="font-family: Courier New, Courier, monospace;">pkgbuild</span> and <span style="font-family: Courier New, Courier, monospace;">productbuild</span> can be run in an analysis mode which analyses their input and creates an initial descriptor. We will add two targets to the Makefile that will provide the user a quick way to get initial versions of the required descriptors:<br />
<br />
<span style="font-family: Courier New, Courier, monospace;">.PHONY : distfiles</span><br />
<span style="font-family: Courier New, Courier, monospace;">distfiles : $(COMPONENT)</span><br />
<span style="font-family: Courier New, Courier, monospace;"> productbuild --synthesize \</span><br />
<span style="font-family: Courier New, Courier, monospace;"> --product $(REQUIREMENTS) \</span><br />
<span style="font-family: Courier New, Courier, monospace;"> --package $(DEPENDENCY) \</span><br />
<span style="font-family: Courier New, Courier, monospace;"> --package $(COMPONENT) \</span><br />
<span style="font-family: 'Courier New', Courier, monospace;"> $(DISTRIBUTION_FILE).new</span><br />
<span style="font-family: Courier New, Courier, monospace;"> @echo "Edit the $(DISTRIBUTION_FILE).new template to create a suitable $(DISTRIBUTION_FILE) file."</span><br />
<span style="font-family: Courier New, Courier, monospace;"><br /></span>
<span style="font-family: Courier New, Courier, monospace;">.PHONY : compfiles</span><br />
<span style="font-family: Courier New, Courier, monospace;">compfiles : $(BINARIES)</span><br />
<span style="font-family: Courier New, Courier, monospace;"> pkgbuild --analyze \</span><br />
<span style="font-family: Courier New, Courier, monospace;"> --root $(BINARIES) \</span><br />
<span style="font-family: Courier New, Courier, monospace;"> $(COMPONENT_PFILE).new</span><br />
<span style="font-family: Courier New, Courier, monospace;"> @echo "Edit the $(COMPONENT_PFILE).new template to create a suitable $(COMPONENT_PFILE) file."</span><br />
<br />
Note that in the <span style="font-family: Courier New, Courier, monospace;">distfiles</span> target the <span style="font-family: Courier New, Courier, monospace;">$(DEPENDENCY)</span> variable is used as argument of the <span style="font-family: Courier New, Courier, monospace;">--package</span> option. As explained earlier, you have to either add as many "dependency variables" as required by your product archive, or remove it altogether if the product archive only contains one component package, <span style="font-family: Courier New, Courier, monospace;">$(COMPONENT)</span>.<br />
<br />
The files created by both the <span style="font-family: Courier New, Courier, monospace;">distfiles</span> and the <span style="font-family: Courier New, Courier, monospace;">compfiles</span> targets must be manually edited by the user and moved to their expected name by removing the <span style="font-family: Courier New, Courier, monospace;">.new</span> extension.<br />
<br />
Finally, let's add some targets to perform some housekeeping:<br />
<ul>
<li><span style="font-family: Courier New, Courier, monospace;">clean</span>, to remove the DMG file and all the packages.</li>
<li><span style="font-family: Courier New, Courier, monospace;">distclean</span>, to remove the distribution files.</li>
<li><span style="font-family: Courier New, Courier, monospace;">compclean</span>, to remove the component file.</li>
</ul>
<br />
<span style="font-family: Courier New, Courier, monospace;">.PHONY : clean</span><br />
<span style="font-family: Courier New, Courier, monospace;">clean :</span><br />
<span style="font-family: Courier New, Courier, monospace;"> -rm -f $(DMGFILE) $(PRODUCT) $(COMPONENT)</span><br />
<span style="font-family: Courier New, Courier, monospace;"> -rm -rf $(BINARIES)</span><br />
<span style="font-family: Courier New, Courier, monospace;"><br /></span>
<span style="font-family: Courier New, Courier, monospace;">.PHONY : distclean</span><br />
<span style="font-family: Courier New, Courier, monospace;">distclean :</span><br />
<span style="font-family: Courier New, Courier, monospace;"> -rm -f $(DISTRIBUTION_FILE) </span><span style="font-family: 'Courier New', Courier, monospace;">$(DISTRIBUTION_FILE).new</span><br />
<span style="font-family: Courier New, Courier, monospace;"><br /></span>
<span style="font-family: Courier New, Courier, monospace;">.PHONY : compclean</span><br />
<span style="font-family: Courier New, Courier, monospace;">compclean :</span><br />
<span style="font-family: Courier New, Courier, monospace;"> -rm -f $(COMPONENT_PFILE) </span><span style="font-family: 'Courier New', Courier, monospace;">$(COMPONENT_PFILE).new</span><br />
<br />
<h2>
Populate the Variables</h2>
So far, we have used Makefile variables in our targets and actions in order to decouple the basic Makefile structure from the details of a specific project. Now, variables must be populated for the Makefile to work in every specific project.<br />
<br />
This is the typical variable definition block I use at the top of this kind of Makefiles:<br />
<br />
<span style="font-family: Courier New, Courier, monospace;">PROGRAM = Name</span><br />
<span style="font-family: Courier New, Courier, monospace;">DISTDIR = ./dist</span><br />
<span style="font-family: Courier New, Courier, monospace;">DEPSDIR = ./deps</span><br />
<span style="font-family: Courier New, Courier, monospace;">BINARIES = /tmp/Name.dst</span><br />
<span style="font-family: Courier New, Courier, monospace;">DMGFILE = $(PROGRAM).dmg</span><br />
<span style="font-family: Courier New, Courier, monospace;">PRODUCT = $(DISTDIR)/$(PROGRAM).pkg</span><br />
<span style="font-family: Courier New, Courier, monospace;">COMPONENT = $(DEPSDIR)/$(PROGRAM)Component.pkg</span><br />
<span style="font-family: Courier New, Courier, monospace;">COMPONENT_PFILE = $(PROGRAM).plist</span><br />
<span style="font-family: Courier New, Courier, monospace;">DISTRIBUTION_FILE = distribution.dist</span><br />
<span style="font-family: Courier New, Courier, monospace;">REQUIREMENTS = requirements.plist</span><br />
<br />
<span style="font-family: Courier New, Courier, monospace;">PROGRAM</span> is a shared fragment which is typically set to the XCode project name. The DMG file name <span style="font-family: Courier New, Courier, monospace;">DMGFILE</span>, the product archive name <span style="font-family: Courier New, Courier, monospace;">PRODUCT</span> and the binary installation directory <span style="font-family: Courier New, Courier, monospace;">BINARIES</span> are all initialised using this prefix. If want to customise any of these names or adjust any path to your needs, just modify accordingly the corresponding variable.<br />
<br />
<h2>
Use It</h2>
The default Makefile target, <span style="font-family: Courier New, Courier, monospace;">all</span>, can be executed by simply invoking<br />
<br />
<span style="font-family: Courier New, Courier, monospace;">$ make</span><br />
<br />
If everything works correctly, you will find a DMG file image in your execution directory containing your product archive.<br />
<br />
<h2>
Conclusion</h2>
In this tutorial we have covered the basic tasks every OS X developer should master in order to build product packages for his own projects. Furthermore, the skeleton of a Makefile performing all the required operations has been provided. This is only the beginning of the work of creating an installer, since most of an installer properties and requirements must be manually set by the developer. However, the tedious part of building component packages and creating product packages can be automated in a relatively simple Makefile that I hope it will be useful to many of you.Enrico M. Crisostomohttp://www.blogger.com/profile/02688166348157974808noreply@blogger.com3tag:blogger.com,1999:blog-7952810330436823110.post-38921859457208403732014-06-02T21:46:00.000+02:002014-06-02T21:50:17.049+02:00OS X: Creating Packages from the Command Line - Tutorial and a Makefile - Part IOver the years Apple has been removing useful tools from its flagship IDE, <i>XCode</i>, and <i>PackageMaker</i> was one of them. It didn't take me by surprise, though. But while on the one hand I understand that Apple would like most users to download software from the Mac App Store (for which plenty of functionality has been baked into XCode), on the other hand removing PackageMaker means leaving developers without a useful and simple graphical tool to build their packages. And even though you can still download it separately at the <a href="https://developer.apple.com/devcenter/mac/index.action">Mac Dev Center</a> (search for a package called <i>XCode Auxiliary Tools</i>), PackageMaker is clearly an unsupported tool of the past, and you'd better rely on the current ones: <span style="font-family: Courier New, Courier, monospace;">pkgbuild</span> and <span style="font-family: Courier New, Courier, monospace;">productbuild</span>.<br />
<br />
Both <span style="font-family: Courier New, Courier, monospace;">pkgbuild</span> and <span style="font-family: Courier New, Courier, monospace;">productbuild</span> are command-line tools and they provide developers all the functionality they need to (man page citation):<br />
<ul>
<li>Build OS X installer component packages.</li>
<li>Build a product archive for the OS X installer.</li>
<li>Build a product archive for the Mac App Store.</li>
</ul>
<div>
The only issue with them is they do not have a GUI and XCode does not publish their functionality through its UI.<br />
<br />
In this blog post I will give a brief overview of how this tools can be invoked to build your own packages. You will be able to:<br />
<ul>
<li>Create your own product archives containing multiple component packages.</li>
<li>Create a DMG disk image for your product archive.</li>
</ul>
<div>
<br />
<a href="http://thegreyblog.blogspot.com/2014/06/os-x-creating-packages-from-command.html" target="_blank">In the next part</a> of this tutorial we will see how we can write a Makefile to perform all the commands required to package your product and streamline your workflow, maybe executing it in a custom XCode target of yours.<br />
<br /></div>
</div>
<div>
<h2>
Using pkgbuild</h2>
<span style="font-family: Courier New, Courier, monospace;">pkgbuild</span> is the tool used to create <i>component packages</i>, the building blocks of <i>product archives</i>, the final products users install. Although component packages are packages themselves and you could distribute them and install them, building a product archive is in my opinion always preferable. Besides, component packages <i>cannot</i> be submitted to the Mac App Store.<br />
<br />
<span style="font-family: Courier New, Courier, monospace;">pkgbuild</span> main mode of operation is driven by a property list file which specifies the configuration of the component package to create. Developers do not need to write this file from scratch though: <span style="font-family: Courier New, Courier, monospace;">pkgbuild</span> provides an <i>analyse</i> mode of operation that analyses the contents found in the specified root path and outputs a template component property list file that can be used as a starting point.<br />
<br />
Assuming we want to build a component package for an OS X application, we first invoke <span style="font-family: Courier New, Courier, monospace;">pkgbuild</span> in <i>analyse</i> mode on a release installation directory to create an initial component property list file:<br />
<br />
<span style="font-family: Courier New, Courier, monospace;">$ pkgbuild --analyze \</span><br />
<span style="font-family: Courier New, Courier, monospace;"> --root /tmp/Name.dst \</span><br />
<span style="font-family: Courier New, Courier, monospace;"> NameComponent.plist</span><br />
<br />
The root path for an application project is an XCode project property (<i>Project/Build Settings/Deployment/Installation Build Products Location</i>) defaulting to <span style="font-family: Courier New, Courier, monospace;">/tmp/$(PROJECT_NAME)</span> that can be specified when performing the <span style="font-family: Courier New, Courier, monospace;">xcodebuild install</span> target by setting the <span style="font-family: Courier New, Courier, monospace;">DSTROOT</span> variable.<br />
<br />
When run, <span style="font-family: Courier New, Courier, monospace;">pkgbuild</span> will create a file called <span style="font-family: Courier New, Courier, monospace;">NameComponent.plist</span> containing default configuration values such as the following (output may vary):<br />
<br />
<span style="font-family: Courier New, Courier, monospace;"><?xml version="1.0" encoding="UTF-8"?></span><br />
<span style="font-family: Courier New, Courier, monospace;"><!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd"></span><br />
<span style="font-family: Courier New, Courier, monospace;"><plist version="1.0"></span><br />
<span style="font-family: Courier New, Courier, monospace;"><array></span><br />
<span style="font-family: Courier New, Courier, monospace;"> <dict></span><br />
<span style="font-family: Courier New, Courier, monospace;"> <key>BundleHasStrictIdentifier</key></span><br />
<span style="font-family: Courier New, Courier, monospace;"> <true/></span><br />
<span style="font-family: Courier New, Courier, monospace;"> <key>BundleIsRelocatable</key></span><br />
<span style="font-family: 'Courier New', Courier, monospace;"> </span><span style="font-family: 'Courier New', Courier, monospace;"> </span><span style="font-family: Courier New, Courier, monospace;"><true/></span><br />
<span style="font-family: 'Courier New', Courier, monospace;"> </span><span style="font-family: 'Courier New', Courier, monospace;"> </span><span style="font-family: Courier New, Courier, monospace;"><key>BundleIsVersionChecked</key></span><br />
<span style="font-family: 'Courier New', Courier, monospace;"> </span><span style="font-family: 'Courier New', Courier, monospace;"> </span><span style="font-family: Courier New, Courier, monospace;"><true/></span><br />
<span style="font-family: 'Courier New', Courier, monospace;"> </span><span style="font-family: 'Courier New', Courier, monospace;"> </span><span style="font-family: Courier New, Courier, monospace;"><key>BundleOverwriteAction</key></span><br />
<span style="font-family: 'Courier New', Courier, monospace;"> </span><span style="font-family: 'Courier New', Courier, monospace;"> </span><span style="font-family: Courier New, Courier, monospace;"><string>upgrade</string></span><br />
<span style="font-family: 'Courier New', Courier, monospace;"> </span><span style="font-family: 'Courier New', Courier, monospace;"> </span><span style="font-family: Courier New, Courier, monospace;"><key>RootRelativeBundlePath</key></span><br />
<span style="font-family: 'Courier New', Courier, monospace;"> </span><span style="font-family: 'Courier New', Courier, monospace;"> </span><span style="font-family: Courier New, Courier, monospace;"><string>Applications/Name.app</string></span><br />
<span style="font-family: 'Courier New', Courier, monospace;"> </span><span style="font-family: Courier New, Courier, monospace;"></dict></span><br />
<span style="font-family: Courier New, Courier, monospace;"></array></span><br />
<span style="font-family: Courier New, Courier, monospace;"></plist></span><br />
<br />
Tweak your component property file according to your needs (man <span style="font-family: Courier New, Courier, monospace;">pkgbuild</span> for detailed information about the available configuration property) and when the configuration is ready <span style="font-family: Courier New, Courier, monospace;">pkgbuild</span> can be run in its main mode to create the component package (split lines for better readability):<br />
<br />
<span style="font-family: Courier New, Courier, monospace;">$ pkgbuild --root /tmp/Name.dst \</span><br />
<span style="font-family: Courier New, Courier, monospace;"> --component-plist NameComponent.plist \</span><br />
<span style="font-family: Courier New, Courier, monospace;"> NameComponent.pkg</span><br />
<br />
Here, we use <span style="font-family: Courier New, Courier, monospace;">NameComponent.pkg</span> as the name of the component package to distinguish from the name of the product archive package.<br />
<br />
<h2>
Sign Packages with pkgbuild</h2>
<span style="font-family: Courier New, Courier, monospace;">pkgbuild</span> lets you sign packages using an "identity" (a certificate and the corresponding private key) that must be installed into one of your keychains. To sign a component package, invoke <span style="font-family: Courier New, Courier, monospace;">pkgbuild</span> with the <span style="font-family: Courier New, Courier, monospace;">--sign identityName</span> option where <span style="font-family: Courier New, Courier, monospace;">identityName</span> is the <i>common name</i> (CN) of the desired certificate.<br />
<br />
If you are creating a <i>signed product</i>, for example if you want to submit it to the Mac App Store, signing all its component packages is not required: you should only sign the product archive using <span style="font-family: Courier New, Courier, monospace;">productbuild</span>.<br />
<br />
<h2>
Using productbuild</h2>
Let's now suppose you have created two component packages for your product:<br />
<ul>
<li><span style="font-family: Courier New, Courier, monospace;">NameComponent.pkg</span>, created in the previous section.</li>
<li><span style="font-family: Courier New, Courier, monospace;">MyFramework.pkg</span>, a dependency of <span style="font-family: Courier New, Courier, monospace;">NameComponent.pkg</span> (created as seen in the previous section).</li>
</ul>
<br />
<span style="font-family: Courier New, Courier, monospace;">productbuild</span> is the tool used to create <i>product archives</i>, that is: packages to be installed by users or to be submitted to the Mac App Store. A product archive is made up of one or more component packages and in this tutorial we will create one containing the two aforementioned components.<br />
<br />
Similarly to <span style="font-family: Courier New, Courier, monospace;">pkgbuild</span>, productbuild runs in multiple modes (currently the available modes are 5, see the man page for detailed information), two of them being:<br />
<ul>
<li>Analysis mode, to create an initial <i>distribution file</i>.</li>
<li>Create a product archive from a distribution file.</li>
</ul>
A distribution file is to the product archive what the component property list is for the component package: it includes all the configuration of the product archive, including (see the man page for detailed information):<br />
<ul>
<li>A product license.</li>
<li>A product README file.</li>
<li>The list of component packages.</li>
<li>Constraints (such as minimum OS version).</li>
</ul>
<br />
To create the initial distribution file for our product archive, we run productbuild in analysis mode specifying the list of component packages to include. In this case we specify the <span style="font-family: Courier New, Courier, monospace;">--synthesize</span> option to run <span style="font-family: Courier New, Courier, monospace;">productbuild</span> in analysis mode, two component packages with multiple <span style="font-family: Courier New, Courier, monospace;">--package</span> options, a requirement file (described in the next section) and the name of the resulting distribution file <span style="font-family: Courier New, Courier, monospace;">distribution.plist</span> (split lines for better readability):<br />
<br />
<span style="font-family: Courier New, Courier, monospace;">$ productbuild --synthesize \</span><br />
<span style="font-family: Courier New, Courier, monospace;"> --product requirements.plist \</span><br />
<span style="font-family: Courier New, Courier, monospace;"> --package MyFrameworkComponent.pkg \</span><br />
<span style="font-family: Courier New, Courier, monospace;"> --package NameComponent.pkg \</span><br />
<span style="font-family: Courier New, Courier, monospace;"> distribution.plist</span><br />
<br />
Once <span style="font-family: Courier New, Courier, monospace;">productbuild</span> creates the initial distribution file, you can manually modify it to satisfy your needs.<br />
<br />
<h2>
Adding a License</h2>
If you want to add a license to your product archive, prepare a license file in one of the supported formats (including rtf, html and plain txt) and add its reference to the distribution file using a <span style="font-family: Courier New, Courier, monospace;"><license/></span> element to the distribution file root element <span style="font-family: Courier New, Courier, monospace;"><installer-gui-script/></span>:<br />
<br />
<span style="font-family: Courier New, Courier, monospace;"><?xml version="1.0" encoding="utf-8" standalone="no"?></span><br />
<span style="font-family: Courier New, Courier, monospace;"><installer-gui-script minSpecVersion="2"></span><br />
<span style="font-family: Courier New, Courier, monospace;"> <title>Name</title></span><br />
<span style="font-family: Courier New, Courier, monospace;"> ...</span><br />
<span style="font-family: Courier New, Courier, monospace;"><b> <license file="LICENSE.html"/></b></span><br />
<span style="font-family: Courier New, Courier, monospace;"> ...</span><br />
<span style="font-family: Courier New, Courier, monospace;"></installer-gui-script></span><br />
<br />
<h2>
Adding a README</h2>
A README file can be added using a procedure similar to what we have used to add a license file, but in this case the name of the element is <span style="font-family: Courier New, Courier, monospace;"><readme/></span>:<br />
<br />
<span style="font-family: Courier New, Courier, monospace;"><?xml version="1.0" encoding="utf-8" standalone="no"?></span><br />
<span style="font-family: Courier New, Courier, monospace;"><installer-gui-script minSpecVersion="2"></span><br />
<span style="font-family: Courier New, Courier, monospace;"> <title>Name</title></span><br />
<span style="font-family: Courier New, Courier, monospace;"> ...</span><br />
<span style="font-family: 'Courier New', Courier, monospace;"> <license file="LICENSE.html"/></span><br />
<span style="font-family: Courier New, Courier, monospace;"><b> <readme file="README.html"/></b></span><br />
<span style="font-family: Courier New, Courier, monospace;"> ...</span><br />
<span style="font-family: Courier New, Courier, monospace;"></installer-gui-script></span><br />
<br />
<h2>
Creating a Requirements File</h2>
Requirements can be specified in a requirement property list file (see man page for detailed information). A requirement property list file is a property list whose element is a dictionary in which may constraints can be expressed using a series of keys, including (but not limited to):<br />
<ul>
<li><span style="font-family: Courier New, Courier, monospace;">os</span>: Minimum allowable OS version.</li>
<li><span style="font-family: Courier New, Courier, monospace;">arch</span>: Supported architectures.</li>
<li><span style="font-family: Courier New, Courier, monospace;">ram</span>: Minimum required RAM.</li>
</ul>
<br />
To specify a dependency on OS X 10.9, we can create an empty property list file whose first child is a dictionary in which we add an <span style="font-family: Courier New, Courier, monospace;">os</span> key with the constraint we need:<br />
<br />
<span style="font-family: Courier New, Courier, monospace;"><?xml version="1.0" encoding="UTF-8"?></span><br />
<span style="font-family: Courier New, Courier, monospace;"><!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd"></span><br />
<span style="font-family: Courier New, Courier, monospace;"><plist version="1.0"></span><br />
<span style="font-family: Courier New, Courier, monospace;"><dict></span><br />
<span style="font-family: Courier New, Courier, monospace;"><b> <key>os</key></b></span><br />
<span style="font-family: Courier New, Courier, monospace;"><b> <array></b></span><br />
<span style="font-family: Courier New, Courier, monospace;"><b> <string>10.9</string></b></span><br />
<span style="font-family: Courier New, Courier, monospace;"><b> </array></b></span><br />
<span style="font-family: Courier New, Courier, monospace;"></dict></span><br />
<span style="font-family: Courier New, Courier, monospace;"></plist></span><br />
<br />
<h2>
Creating the Product Archive</h2>
Once the distribution file is ready, <span style="font-family: Courier New, Courier, monospace;">productbuild</span> can be run to finally create the product archive. In this case we have to specify the distribution file with the <span style="font-family: Courier New, Courier, monospace;">--distribution</span> option, the resource path where resource files are found (such as license and README, <i>even</i> if they are in the current working directory) the package path where component packages can be found using the <span style="font-family: Courier New, Courier, monospace;">--package-path</span> options (in case they are not in the current working directory) and the name of the product package:<br />
<br />
<span style="font-family: Courier New, Courier, monospace;">$ productbuild \</span><br />
<span style="font-family: Courier New, Courier, monospace;"> --distribution distribution.plist</span><br />
<span style="font-family: Courier New, Courier, monospace;"> --resources .</span><br />
<span style="font-family: Courier New, Courier, monospace;"> --package-path path/to/MyFrameworkComponent.pkg</span><br />
<span style="font-family: Courier New, Courier, monospace;"> --package-path path/to/NameComponent.pkg</span><br />
<span style="font-family: Courier New, Courier, monospace;"> Name.pkg</span><br />
<br />
<h2>
Signing the Product Archive</h2>
As explained in the case of <span style="font-family: Courier New, Courier, monospace;">pkgbuild</span>, productbuild lets you sign the product archive using the identity (a certificate common name) specified with the <span style="font-family: Courier New, Courier, monospace;">--sign</span> option. The specified certificate must be available in an accessible keychain, otherwise the path of a specific keychain must be specified using the <span style="font-family: Courier New, Courier, monospace;">--keychain</span> option.<br />
<br />
A product archive can even be signed <i>after</i> it has been created using the <span style="font-family: Courier New, Courier, monospace;">productsign</span> command (see the man page for further information).<br />
<br />
<h2>
Creating a DMG Disk Image</h2>
OS X installers are often distributed in a DMG disk image file. If you want to create a DMG file containing your product archive (and optionally other files) you have to:<br />
<ul>
<li>Put all the files your want to include in a folder (the <i>source folder</i> in <span style="font-family: Courier New, Courier, monospace;">hdiutil</span> jargon).</li>
<li>Use the <span style="font-family: Courier New, Courier, monospace;">hdiutil</span> command-line utility to create a DMG disk image from the source folder.</li>
</ul>
<br />
Assuming we have created the <span style="font-family: Courier New, Courier, monospace;">./dist</span> source folder where we have copied the <span style="font-family: Courier New, Courier, monospace;">Name.pkg</span> product archive, we can use the following command to create a <span style="font-family: Courier New, Courier, monospace;">Name.dmg</span> DMG file (split lines for better readability) named <i>My Product</i>:<br />
<br />
<span style="font-family: Courier New, Courier, monospace;">$ hdiutil create \</span><br />
<span style="font-family: Courier New, Courier, monospace;"> -volname "My Product" \</span><br />
<span style="font-family: Courier New, Courier, monospace;"> -srcfolder ./dist \</span><br />
<span style="font-family: Courier New, Courier, monospace;"> -ov \</span><br />
<span style="font-family: Courier New, Courier, monospace;"> Name.dmg</span><br />
<br />
The optional <span style="font-family: Courier New, Courier, monospace;">-ov</span> option is used to overwrite an existing DMG file.<br />
<br />
<h2>
A Makefile to Put It All Together</h2>
<a href="http://thegreyblog.blogspot.com/2014/06/os-x-creating-packages-from-command.html" target="_blank">In the next part</a> of this tutorial we will examine an example Makefile that can be used as a starting point to perform all the operations described in this post.</div>
Enrico M. Crisostomohttp://www.blogger.com/profile/02688166348157974808noreply@blogger.com4tag:blogger.com,1999:blog-7952810330436823110.post-53218910304468786182014-06-02T21:16:00.000+02:002014-06-02T21:16:12.013+02:00EMCCountryPickerController v. 1.2.0 Has Been Released<a href="https://github.com/emcrisostomo/EMCCountryPickerController">EMCCountryPickerController</a> v. 1.2.0 has been released bringing a new localisation in the Spanish (es) language:<br />
<br />
<div class="separator" style="clear: both; text-align: center;">
<a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEgnO0KicfbwUBkhTh7ujF3WXRqMbrynO6Kc3HuX_438fsvfTO0w31gO53JB_yF7Nahypn97pDHj_jXpHKIHFNhEAkvovBthoIvaUTuiIuN2NuxOoce0sTPw4P7bm8MjPlFB4DIXAkoOn4ZZ/s1600/EMCCountryPickerController-es.png" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"><img border="0" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEgnO0KicfbwUBkhTh7ujF3WXRqMbrynO6Kc3HuX_438fsvfTO0w31gO53JB_yF7Nahypn97pDHj_jXpHKIHFNhEAkvovBthoIvaUTuiIuN2NuxOoce0sTPw4P7bm8MjPlFB4DIXAkoOn4ZZ/s1600/EMCCountryPickerController-es.png" height="320" width="222" /></a></div>
<br />
<span id="goog_1690905208"></span>
You can get the latest version using <a href="http://cocoapods.org/">CocoaPods</a>, by adding a dependency to your <span style="font-family: Courier New, Courier, monospace;">Podfile</span>:<br />
<br />
<span style="font-family: Courier New, Courier, monospace;">pod 'EMCCountryPickerController' ~> '1.0'</span><br />
<br />
If you are already using EMCCountryPickerController, then you just need to update your pod repository index:<br />
<br />
<span style="font-family: Courier New, Courier, monospace;">$ pod repo update</span><br />
<br />
and then and update your outdated project dependencies running this command in the project root directory:<br />
<br />
<span style="font-family: 'Courier New', Courier, monospace;">$ pod update</span><br />
<span style="font-family: 'Courier New', Courier, monospace;"><br /></span>
Enjoy.Enrico M. Crisostomohttp://www.blogger.com/profile/02688166348157974808noreply@blogger.com0tag:blogger.com,1999:blog-7952810330436823110.post-41261557647667159362014-05-27T22:04:00.003+02:002014-06-02T21:19:23.533+02:00EMCCountryPickerController: A Country Picker View Controller for iOS<a href="https://github.com/emcrisostomo/EMCCountryPickerController">EMCCountryPickerController</a> is a view controller I've built that lets you choose a country from a searchable list that includes all the countries assigned an <a href="http://en.wikipedia.org/wiki/ISO_3166-1_alpha-2">ISO 3166-1 alpha-2</a> two-letter country codes.<br />
<br />
<div class="separator" style="clear: both; text-align: center;">
<a href="https://raw.githubusercontent.com/emcrisostomo/EMCCountryPickerController/master/Screenshots/main-view-with-flags.png" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"><img border="0" height="320" src="https://raw.githubusercontent.com/emcrisostomo/EMCCountryPickerController/master/Screenshots/main-view-with-flags.png" width="222" /></a></div>
<br />
<div class="separator" style="clear: both; text-align: center;">
<a href="https://raw.githubusercontent.com/emcrisostomo/EMCCountryPickerController/master/Screenshots/main-view-search.png" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"><img border="0" height="320" src="https://raw.githubusercontent.com/emcrisostomo/EMCCountryPickerController/master/Screenshots/main-view-search.png" width="222" /></a></div>
<br />
<i>EMCCountryPickerController</i> is extremely simple to use:<br />
<ul>
<li>It just has to be presented.</li>
<li>The user interacts with the user interface and selects a country.</li>
<li>The selection is communicated to a <i>delegate</i>, which dismisses the view controller and uses the results.</li>
</ul>
<div>
Comprehensive usage details, as well as a complete demo project, can be found in its <a href="https://github.com/emcrisostomo/EMCCountryPickerController">GitHub repository</a>.<br />
<br />
This component features also has the following additional features:</div>
<div>
<ul>
<li>Country name can be localised (some localisations are already provided, such as English and Italian).</li>
<li>Flag borders can be drawn and customised.</li>
<li>Flags can be optionally turned off.</li>
</ul>
</div>
<br />
The controller includes the flag of all the available countries, <a href="https://github.com/emcrisostomo/flags">rasterised from a SVG file in the public domain</a>. The controller is distributed with the <a href="http://opensource.org/licenses/BSD-3-Clause">BSD 3-clause license</a>.<br />
<br />
<h2>
Installation</h2>
Besides grabbing the sources and the resource files from its <a href="https://github.com/emcrisostomo/EMCCountryPickerController">GitHub repository</a>, the quickest way to use the controller is using <a href="http://cocoapods.org/">CocoaPods</a> and adding a reference to the <span style="font-family: Courier New, Courier, monospace;">EMCCountryPickerController</span> pod to your project <span style="font-family: Courier New, Courier, monospace;">Podfile</span>:<br />
<br />
<span style="font-family: Courier New, Courier, monospace;">pod 'EMCCountryPickerController', '~> 1.1'</span><br />
<br />
Enjoy.Enrico M. Crisostomohttp://www.blogger.com/profile/02688166348157974808noreply@blogger.com0tag:blogger.com,1999:blog-7952810330436823110.post-18714103475530719732014-03-20T16:40:00.000+01:002014-03-20T16:40:06.043+01:00Autoconf Macros to Check for C++11 Features in the Header<a href="http://en.wikipedia.org/wiki/C++11">C++11</a> introduces a lot of improvements and new features to the C++ language and the C++ Standard Library. Compilers and libraries are still implementing such features and it is likely your toolchain is still missing some piece, even though the ones I am using (GCC and CLang) are catching up quickly.<br />
<br />
While on the one hand the GNU Build System is mostly used to build C projects and an historical lack of C++ macros is suffered, on the other hand there were <i>no</i> C++11 specific macro to check for library compliance.<br />
<br />
For this reason, I began writing my own set of macros some weeks ago starting from what I needed at the time: C++11 features in the <span style="font-family: Courier New, Courier, monospace;"><functional></span> header. So far, I have written the following macros which cover all the new C++11 features in that header:<br />
<ul>
<li><span style="font-family: Courier New, Courier, monospace;"><a href="http://www.gnu.org/software/autoconf-archive/ax_cxx_have_bad_function_call.html">AX_CXX_HAVE_BAD_FUNCTION_CALL()</a></span>: checks for <span style="font-family: Courier New, Courier, monospace;">std::bad_function_call</span>.</li>
<li><span style="font-family: Courier New, Courier, monospace;"><a href="http://www.gnu.org/software/autoconf-archive/ax_cxx_have_bind.html">AX_CXX_HAVE_BIND()</a></span>: checks for <span style="font-family: Courier New, Courier, monospace;">std::bind</span>.</li>
<li><span style="font-family: Courier New, Courier, monospace;"><a href="http://www.gnu.org/software/autoconf-archive/ax_cxx_have_bit_and.html">AX_CXX_HAVE_BIT_AND()</a></span>: checks for <span style="font-family: Courier New, Courier, monospace;">std::bit_and</span>.</li>
<li><span style="font-family: Courier New, Courier, monospace;"><a href="http://www.gnu.org/software/autoconf-archive/ax_cxx_have_bit_or.html">AX_CXX_HAVE_BIT_OR()</a></span>: checks for <span style="font-family: Courier New, Courier, monospace;">std::bit_or</span>.</li>
<li><span style="font-family: Courier New, Courier, monospace;"><a href="http://www.gnu.org/software/autoconf-archive/ax_cxx_have_bit_xor.html">AX_CXX_HAVE_BIT_XOR()</a></span>: checks for <span style="font-family: Courier New, Courier, monospace;">std::bit_xor</span>.</li>
<li><span style="font-family: Courier New, Courier, monospace;"><a href="http://www.gnu.org/software/autoconf-archive/ax_cxx_have_cref.html">AX_CXX_HAVE_CREF()</a></span>: checks for <span style="font-family: Courier New, Courier, monospace;">std::cref</span>.</li>
<li><span style="font-family: Courier New, Courier, monospace;"><a href="http://www.gnu.org/software/autoconf-archive/ax_cxx_have_function.html">AX_CXX_HAVE_FUNCTION()</a></span>: checks for <span style="font-family: Courier New, Courier, monospace;">std::function</span>.</li>
<li><span style="font-family: Courier New, Courier, monospace;"><a href="http://www.gnu.org/software/autoconf-archive/ax_cxx_have_hash.html">AX_CXX_HAVE_HASH()</a></span>: checks for <span style="font-family: Courier New, Courier, monospace;">std::hash</span>.</li>
<li><span style="font-family: Courier New, Courier, monospace;"><a href="http://www.gnu.org/software/autoconf-archive/ax_cxx_have_is_bind_expression.html">AX_CXX_HAVE_IS_BIND_EXPRESSION()</a></span>: checks for <span style="font-family: Courier New, Courier, monospace;">std::is_bind_expression</span>.</li>
<li><span style="font-family: Courier New, Courier, monospace;"><a href="http://www.gnu.org/software/autoconf-archive/ax_cxx_have_is_placeholder.html">AX_CXX_HAVE_IS_PLACEHOLDER()</a></span>: checks for <span style="font-family: Courier New, Courier, monospace;">std::is_placeholder</span>.</li>
<li><span style="font-family: Courier New, Courier, monospace;"><a href="http://www.gnu.org/software/autoconf-archive/ax_cxx_have_mem_fn.html">AX_CXX_HAVE_MEM_FN()</a></span>: checks for <span style="font-family: Courier New, Courier, monospace;">std::mem_fn</span>.</li>
<li><span style="font-family: Courier New, Courier, monospace;">AX_CXX_HAVE_PLACEHOLDERS()</span>: checks for <span style="font-family: Courier New, Courier, monospace;">std::placeholders</span>.</li>
<li><span style="font-family: Courier New, Courier, monospace;"><a href="http://www.gnu.org/software/autoconf-archive/ax_cxx_have_ref.html">AX_CXX_HAVE_REF()</a></span>: checks for <span style="font-family: Courier New, Courier, monospace;">std::ref</span>.</li>
<li><span style="font-family: Courier New, Courier, monospace;"><a href="http://www.gnu.org/software/autoconf-archive/ax_cxx_have_reference_wrapper.html">AX_CXX_HAVE_REFERENCE_WRAPPER()</a></span>: checks for <span style="font-family: Courier New, Courier, monospace;">std::reference_wrapper</span>.</li>
</ul>
<br />
All the macros except <span style="font-family: Courier New, Courier, monospace;">AX_CXX_HAVE_PLACEHOLDERS</span> were submitted to the <a href="http://www.gnu.org/software/autoconf-archive/">GNU Autoconf Archive</a> some weeks ago and are already available for use: just follow the link on the macro name, download the m4 file and use it. I submitted <span style="font-family: Courier New, Courier, monospace;">AX_CXX_HAVE_PLACEHOLDERS</span> this morning and I expect it to be available shortly: I will update this post as soon as this macro has been accepted.<br />
<br />
For those who want to contribute to this set of macros, you can check out <a href="https://github.com/emcrisostomo/CXX-Autoconf-Macros.git">their GitHub repository</a>.<br />
<br />Enrico M. Crisostomohttp://www.blogger.com/profile/02688166348157974808noreply@blogger.com0tag:blogger.com,1999:blog-7952810330436823110.post-44434817968347879812014-03-17T15:58:00.000+01:002015-05-02T14:23:18.006+02:00Shrink Your Time Machine Backups and Free Disk Space<i><b>Update:</b> In a <a href="http://thegreyblog.blogspot.com/2015/05/a-shell-script-to-delete-old-time.html" target="_blank">newer post</a>, I describe a shell script I published to automate Time Machine backup deletion.</i><br />
<br />
Time Machine is a backup and restore tool from Apple which is very well integrated into OS X. In my personal opinion Time Machine is not yet <i>awesome</i> and its shortcomings often force me to use alternative methods when I need to backup files and folders with certain characteristics.<br />
<br />
The most important use case in which I <i>strongly discourage</i> anybody to use Time Machine is the backup of <i>frequently updated big files</i>. Time Machine <i>always</i> copies the whole file because it is <i>not</i> able to transfer only the differences between the previous state of a file and the current one. This fact has many detrimental consequences:<br />
<ul>
<li>Backups are <i>slow</i>.</li>
<li>Backups may take a <i>huge</i> amount of disk space.</li>
</ul>
<div>
When I say <i>huge</i>, I mean <i>enormous</i>. Think about a virtual machine disk stored as a file in your disk: if just one bit of that file changes (and you can bet it changes every time you use your virtual machine), Time Machine will perform a copy of the <i>whole</i> file the next time a backup is run.</div>
<div>
<br /></div>
<div>
Fortunately, there exist tools which <i>are</i> able to examine a file and transfer only the difference with a previous stored state, such as <i>rsync</i>, on which you can rely to build your custom backup policies.</div>
<br />
Anyway, no matter how Time Machine has eaten up a lot of your disk space, it may come a moment when you <i>really</i> <i>need</i> to free some of it, possibly deleting old backups and shrinking a Time Machine sparse bundle disk image.<br />
<br />
<h2>
Deleting Old Backups</h2>
Old backups can be deleted in many ways, the simplest one being the following:<br />
<ul>
<li>Open the <i>Time Machine</i> application when the Finder application is in the foreground.</li>
<li>Navigate to the backup to be deleted double clicking on the corresponding position of the ruler on the right side of the screen.</li>
<li>Right click with the mouse on the empty space in the Finder.</li>
<li>Select <i>Delete Backup</i>.</li>
</ul>
<div>
Time Machine will ask you to introduce the super user password and then it will delete the selected backup.</div>
<div>
<br /></div>
<div>
Unfortunately this method is very clumsy if you need to delete many backups.<br />
<br />
Another way is using the <span style="font-family: Courier New, Courier, monospace;">tmutil</span> command to perform the deletion. Not only it is simpler, but it will allow you to do it programmatically if you need to. To delete a backup using <span style="font-family: Courier New, Courier, monospace;">tmutil</span> you must perform the following operations:</div>
<div>
<ul>
<li>Make sure your time machine backup disk is mounted (the simplest way to do it is opening the Time Machine application).</li>
<li>The format of the backup folders created by Time Machine is <span style="font-family: Courier New, Courier, monospace;">YYYY-MM-DD-HHmmss.</span> If you want to delete a specific backup, you can use the following command:</li>
</ul>
<span style="font-family: Courier New, Courier, monospace;">$ sudo tmutil delete /full/path/to/backup/Backups.backupdb/machine/backup-name</span></div>
<div>
<br /></div>
<div>
Time Machine currently stores its backups in a folder named after the backed up machine, into the <span style="font-family: Courier New, Courier, monospace;">Backups.backupdb</span> folder in the backup disk. This means that, if your machine is called iMac and your backup disk is mounted on <span style="font-family: Courier New, Courier, monospace;">/Volumes/Time Machine Backups</span>, then backups will be located in the following folder:<br />
<br />
<span style="font-family: Courier New, Courier, monospace;">/Volumes/Time Machine Backups/Backups.backupdb/iMac</span><br />
<br />
If you want to delete the <span style="font-family: Courier New, Courier, monospace;">2014-02-02-123411</span> backup, you must run the following command:</div>
<div>
<br /></div>
<div>
<span style="font-family: Courier New, Courier, monospace;">$ sudo tmutil delete </span><span style="font-family: 'Courier New', Courier, monospace;">/Volumes/Time Machine Backups/Backups.backupdb/iMac/2014-02-02-123411</span><br />
<br />
You can easily make a script, for example, to delete all the backups of a specific month. The following commands will delete all the backups created in January 2014 (lines were split with <span style="font-family: Courier New, Courier, monospace;">\</span>):<br />
<br />
<span style="font-family: Courier New, Courier, monospace;">$ sudo bash</span><br />
<span style="font-family: Courier New, Courier, monospace;">Password:</span><br />
<span style="font-family: 'Courier New', Courier, monospace;">$ for i in /Volumes/Time\ Machine\ Backups/Backups.backupdb/iMac/2014-01* ; \</span><br />
<span style="font-family: Courier New, Courier, monospace;"> do \</span><br />
<span style="font-family: Courier New, Courier, monospace;"> tmutil delete "$i" ; \</span><br />
<span style="font-family: Courier New, Courier, monospace;"> done</span><br />
<br />
<h3>
Deleting Backups of Any Machine</h3>
The same commands can be used to delete backups performed by any machine, not only the machine you are executing them from. This is particularly useful if your time machine backup disk is located on a NAS (such as Apple's <i>Time Capsule</i>).<br />
<br />
In this case, though, you will have to mount the disk image file created for every machine and named after it. Time machine creates <i>sparse bundle</i> disk images which can be mounted using the <i>Disk Utility</i> application:<br />
<ul>
<li>Open the <i>Disk Utility</i> application.</li>
<li>Choose the <i>File/Open Disk Image...</i> menu item (⌥⌘O).</li>
<li>Choose the disk image file corresponding to the backup disk of the machine whose backups you want to delete.</li>
</ul>
Disk Utility will mount the disk image and you can now use the commands shown above to delete the time machine backups stored in this disk image.<br />
<br />
<h2>
Freeing Space</h2>
Now that you are able to delete backups, you may notice that <i>no disk space is relinquished</i> if a sparse bundle disk image is being used as backup disk, which is the default behaviour when the backup disk is not a locally attached physical disk.<br />
<br />
In this case, when Time Machine frees disk space, the space is freed <i>inside</i> the disk image, but unless the disk image itself frees it as well, the result is that <i>no space</i> is relinquished outside of it.<br />
<br />
Fortunately, unallocated space can be freed from a sparse bundle using the following command (make sure the disk image is not mounted when executing this command):<br />
<br />
<span style="font-family: Courier New, Courier, monospace;">$ sudo hdiutil compact /path/to/disk-image</span><br />
<span style="font-family: Courier New, Courier, monospace;">Starting to compact…</span><br />
<span style="font-family: Courier New, Courier, monospace;">Reclaiming free space…</span><br />
<span style="font-family: Courier New, Courier, monospace;">.................................................................................................................................................................................................................</span><br />
<span style="font-family: Courier New, Courier, monospace;">Finishing compaction…</span><br />
<span style="font-family: Courier New, Courier, monospace;">Reclaimed 11.2 GB out of 118.7 GB possible.</span><br />
<br />
As you can see, <span style="font-family: Courier New, Courier, monospace;">hdiutil</span> reports the space which has been reclaimed and you should now see the specified amount of space as additional free space in the corresponding disk.</div>
Enrico M. Crisostomohttp://www.blogger.com/profile/02688166348157974808noreply@blogger.com12tag:blogger.com,1999:blog-7952810330436823110.post-64414635390968652382014-02-25T14:31:00.001+01:002014-02-25T14:31:16.731+01:00Creating an Apple XCode Project Using the GNU Build System (a.k.a. Autotools)<a href="http://thegreyblog.blogspot.com/2013/09/cc-project-built-with-gnu-build-system.html">Some posts ago</a> I wrote about two of the best portable C/C++ IDEs, <a href="http://www.netbeans.org/">NetBeans</a> and <a href="https://www.eclipse.org/cdt/">Eclipse CDT,</a> and their support for projects configured and built with the GNU Build System (a.k.a. Autotools). The only shortcoming of these IDEs is the lack of support for Apple <i>frameworks</i> and <a href="http://thegreyblog.blogspot.com/2014/02/how-to-include-apple-frameworks-headers.html">in another post</a> I showed one possible workaround and provided the ZSH script I use, hosted on <a href="https://github.com/emcrisostomo/link-osx-framework-headers">GitHub</a>, to automatically create the soft links to include in the C/C++ include paths of your project.<br />
<br />
Sometimes, however, it may be desirable to use Apple XCode instead of the aforementioned IDEs. Since there's no native support for the GNU Build System in XCode, some manual configuration must be performed to have XCode use the Makefile (and the other artefacts) generated by <i>autoconf</i> and <i>automake</i> for your project.<br />
<br />
In this use case I prefer to maintain the sources completely separated from the XCode project. XCode lets you add <i>references</i> to the source files in a project, so that the physical location of either thing is irrelevant. Moreover, you won't risk polluting the sources with XCode-specific files and adding them by mistake to your source code repository.<br />
<br />
<h2>
Creating the project</h2>
First of all, an <i>External Build System</i> project must be created:<br />
<br />
<table align="center" cellpadding="0" cellspacing="0" class="tr-caption-container" style="margin-left: auto; margin-right: auto; text-align: center;"><tbody>
<tr><td style="text-align: center;"><a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEgkqhaI__z6JEitS94X7_QnSpAsZTqdkcloeLUrSdHyLK1U-npfvx8xTjaw-LNHQGsvSSjAo3GEgWLgNH7w7LTye8ZlTaTDjVxowkttV_myuuVfStGntrYxH9tffUif_rL3I__oDIsiqH_1/s1600/create-external-build.project.png" imageanchor="1" style="margin-left: auto; margin-right: auto;"><img border="0" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEgkqhaI__z6JEitS94X7_QnSpAsZTqdkcloeLUrSdHyLK1U-npfvx8xTjaw-LNHQGsvSSjAo3GEgWLgNH7w7LTye8ZlTaTDjVxowkttV_myuuVfStGntrYxH9tffUif_rL3I__oDIsiqH_1/s1600/create-external-build.project.png" height="216" width="320" /></a></td></tr>
<tr><td class="tr-caption" style="text-align: center;">Create <i>External Build System</i> project</td></tr>
</tbody></table>
<br />
In the project options window, type the name of the project and your name: since the build is made using your autotools configuration files, these fields are irrelevant and are only used to label the XCode project:<br />
<br />
<table align="center" cellpadding="0" cellspacing="0" class="tr-caption-container" style="margin-left: auto; margin-right: auto; text-align: center;"><tbody>
<tr><td style="text-align: center;"><a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEgl3QVvwa5KT89po964uGN-uAtKn9QeSEyQ1fmTB0TFI08oK-UqKV7sr-Bp2l2rmr614idbBG5gSN2BRcaA0dR92275_00DJ3QNiVeR-G-G1s8uIUGveOxIAZI7CncSA5EoWX4HbqT0Cv6m/s1600/project-options.png" imageanchor="1" style="margin-left: auto; margin-right: auto;"><img border="0" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEgl3QVvwa5KT89po964uGN-uAtKn9QeSEyQ1fmTB0TFI08oK-UqKV7sr-Bp2l2rmr614idbBG5gSN2BRcaA0dR92275_00DJ3QNiVeR-G-G1s8uIUGveOxIAZI7CncSA5EoWX4HbqT0Cv6m/s1600/project-options.png" height="216" width="320" /></a></td></tr>
<tr><td class="tr-caption" style="text-align: center;">Choose options for the project</td></tr>
</tbody></table>
<br />
Unless you want to use another <span style="font-family: inherit;"><i>make</i></span> binary, you can leave the <i>Build Tool</i> path as is.<br />
<br />
After setting up your project options, XCode will ask you the location where your new project must be created.<br />
<br />
<h2>
Configuring the Build Directory</h2>
As you know, the sources must be <i>configured</i> with the <span style="font-family: Courier New, Courier, monospace;">configure</span> script (created by the GNU Build System) in order for them to be built on a specific platform. Since XCode has no knowledge of this mechanism, you must configure as a build directory a directory where the sources have been configured.<br />
<br />
Once again, I prefer configuring the build on a separate directory, instead of doing it directly in the sources folder. This way, I do not pollute the source trees with object files and any other artefact created during configuration and build.<br />
<br />
To configure your sources you must perform the following operations:<br />
<ul>
<li>Go to the designated build directory of your XCode project (I usually create the <i>build</i> directory in the project root).</li>
<li>Run the configure script from your source root directory:</li>
</ul>
<span style="font-family: Courier New, Courier, monospace;">$ [sources]/configure [opts]</span><br />
<br />
Now, the build directory path must be set into your project configuration:<br />
<ul>
<li>Select the project root node in the <i>Project Navigator</i> pane.</li>
<li>Set the build directory in the <i>Directory</i> field, as shown in the following screenshot.</li>
</ul>
<br />
<table align="center" cellpadding="0" cellspacing="0" class="tr-caption-container" style="margin-left: auto; margin-right: auto; text-align: center;"><tbody>
<tr><td style="text-align: center;"><a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEgKHr1Y4at2TnwpZ95LapifEMdg6TmMcom6I3pemGbyjWN7MJ4GlaBF7LHrqf6v0e2rgQoCd0IivDyUDTKoM33mJCF1ulaGJY-2gjF9niAdqyzhm4vFV4oi6GEkT5vCL7EQQ2vs-eYM4BLc/s1600/project-build-directory.png" imageanchor="1" style="margin-left: auto; margin-right: auto;"><img border="0" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEgKHr1Y4at2TnwpZ95LapifEMdg6TmMcom6I3pemGbyjWN7MJ4GlaBF7LHrqf6v0e2rgQoCd0IivDyUDTKoM33mJCF1ulaGJY-2gjF9niAdqyzhm4vFV4oi6GEkT5vCL7EQQ2vs-eYM4BLc/s1600/project-build-directory.png" height="66" width="320" /></a></td></tr>
<tr><td class="tr-caption" style="text-align: center;">Project build directory</td></tr>
</tbody></table>
<br />
The configuration of the build directory is a one-time task for each target, no matter how many times you reconfigure the build in that folder. If you plan to have more than one kind of build, such as <i>debug</i> build and <i>release</i> builds (each one with different configuration options), just create multiple <i>targets</i> in different build directories (such as <i>build/debug</i> and <i>build/release</i>), each one configured separately. To create a new target in an XCode project, use the <i>File/New/Target</i> menu item.<br />
<br />
<h2>
Adding Sources to the Project</h2>
Your new XCode project will be <i>empty</i> and source files must be added to it. To add existing sources to your project you can use the <i>Add files to [project-name]</i> menu item in the <i>File</i> menu or in the contextual menu that appears when you right click over your project root in the <i>Project Navigator</i> pane. Alternatively, you can use the ⌥⌘<span style="font-family: Helvetica Neue, Arial, Helvetica, sans-serif;">A</span> shortcut.<br />
<br />
In the add files window, choose the files and/or the directories to be added. If you want to, you now have the opportunity to create groups or folder references for any added folders.<br />
<br />
<h2>
Build</h2>
Now you are ready to build your sources from XCode using the GNU Build System. And if you wonder where your build output is, in XCode the <i>Log Navigator</i> pane must be used.Enrico M. Crisostomohttp://www.blogger.com/profile/02688166348157974808noreply@blogger.com1tag:blogger.com,1999:blog-7952810330436823110.post-7143830507126951742014-02-15T01:11:00.001+01:002014-02-28T00:12:34.455+01:00fsw: a File System Event Monitor for OS X and *BSD SystemsA very often demanded feature by many different types of users is the possibility of receiving an <i>event</i> when a change in a specific file or directory occurs. One of the most common way to consume such an event in a UNIX(-like) system would be:<br />
<div>
<ul>
<li>Having a command which lets you watch a set of files or directories outputting on standard output a detailed record for each event received.</li>
<li>Piping such a process to a shell script that reacts accordingly.</li>
</ul>
<div>
<br />
Many UNIX and UNIX-like systems provide kernel facilities, subsystems and programs providing the possibility of receiving file system change events:<br />
<ul>
<li>Silicon Graphic's portable <a href="http://en.wikipedia.org/wiki/File_Alteration_Monitor">FAM</a>.</li>
<li>FreeBSD's <a href="http://en.wikipedia.org/wiki/Kqueue">kqueue</a>, originated in FreeBSD and available on many *BSD systems.</li>
<li>Linux <a href="http://en.wikipedia.org/wiki/Inotify">inotify</a>.</li>
<li>Apple OS X <a href="https://developer.apple.com/library/mac/documentation/Darwin/Conceptual/FSEvents_ProgGuide/Introduction/Introduction.html">FSEvents API</a>.</li>
</ul>
<br />
However, unlike Linux (where <i>inotifywatch</i> is available), neither OS X nor kqueue-enabled *BSD systems provide a user-land program for users to take advantage of those APIs. That's why I decided to fill the gap and write a small C++ program: <i><a href="https://github.com/emcrisostomo/fsw">fsw</a></i>, a shell-friendly file system event notifier for OS X and kqueue-enabled *BSD systems, <a href="https://github.com/emcrisostomo/fsw">hosted on GitHub</a>.</div>
</div>
<div>
<br /></div>
<h2>
fsw</h2>
<div>
fsw will let you subscribe to file system change events on multiple files or directories:</div>
<div>
<br /></div>
<div>
<span style="font-family: Courier New, Courier, monospace;">$ fsw file-0 ... file-n</span></div>
<div>
<span style="font-family: Courier New, Courier, monospace;"><br /></span></div>
<div>
When a file system event is received, fsw prints a complete record of the event such as</div>
<div>
<br /></div>
<div>
<span style="font-family: Courier New, Courier, monospace;">Sat Feb 15 00:26:30 2014 - /full/path/to/file:created renamed modified changeOwner isFile </span></div>
<div>
<span style="font-family: Courier New, Courier, monospace;">Sat Feb 15 00:26:31 2014 - /full/path/to/file:created renamed modified changeOwner xattrMod isFile</span></div>
<div>
<br /></div>
<div>
that include the following information:</div>
<div>
<ul>
<li>The timestamp when the event was received.</li>
<li>The full path of the changed file or directory.</li>
<li>The list of event <i>flags</i>, describing the type of change that occurred.</li>
</ul>
<div>
<br />
<h3>
Watchers</h3>
fsw implements three kind of watchers:<br />
<ul>
<li>A watcher based on the File System Events API, available only on Apple OS X.</li>
<li>A watcher based on kqueue, an event notification interface introduced in FreeBSD 4.1 and supported on most *BSD systems (including OS X).</li>
<li>The poll watcher, a watcher which periodically stats the file system, saves file modification times in memory and manually calculates file system changes.</li>
</ul>
<br />
The limitations of fsw depend largely on the watcher being used:<br />
<ul>
<li>The FSEvents watcher, available only on Apple OS X, has no known limitations and scales very well with the number of files being observed.</li>
<li>The kqueue watcher, available on any *BSD system featuring kqueue, requires a file descriptor to be opened for every file being watched. As a result, this watcher scales badly with the number of files being observed and may begin to misbehave as soon as the fsw process runs out of file descriptors. In this case, fsw dumps one error on standard error for every file that cannot be opened.</li>
<li>The poll watcher, available on any platform, only relies on available CPU and memory to perform its task. The performance of this watcher degrades linearly with the number of files being watched.</li>
</ul>
<div>
<br /></div>
<div>
<h3>
Recommendations</h3>
<ul>
<li>On OS X, use only the FSEvents watcher.</li>
<li>If the number of files to observe is sufficiently small, use the kqueue watcher. Beware that on some systems the maximum number of file descriptors that can be opened by a process is set to a very low value (values as low as 256 are not uncommon), even if the operating system may allow a much larger value. In this case, check your OS documentation to raise this limit on either a per process or a system-wide basis.</li>
<li>If feasible, watch directories instead of watching files.</li>
<li></li>
<li>If none of the above applies, use the poll watcher. The authors' experience indicates that fsw requires approximately 150 MB or RAM memory to observe a hierarchy of 500.000 files with a minimum path length of 32 characters. A common bottleneck of the poll watcher is disk access, since stat()-ing a great number of files may take a huge amount of time. In this case, the latency should be set to a sufficiently large value in order to reduce the performance degradation that may result from frequent disk access.</li>
</ul>
<br /></div>
</div>
<h3>
Configuring the Latency</h3>
</div>
<div>
Events are passed to the watching process via a callback and every callback call pass an array of events. When creating the event stream, a <i>latency</i> is specified and it defines how many seconds <i>d</i> (a double value) elapse between a callback invocation and another. fsw lets users specify the desired latency using the <i>-l</i>/<i>--latency</i> options:<br />
<br />
<span style="font-family: Courier New, Courier, monospace;">$ fsw -l 5 .</span><br />
<br />
In this case, fsw receives change events every 5 seconds.<br />
<br />
<h3>
Other Options</h3>
fsw currently supports the following options:<br />
<ul>
<li><i>-f, --format-time</i>: Print the event time using the specified format.</li>
<li><i>-h, --help</i>: Show this message.</li>
<li><i>-k, --kqueue</i>: Use the kqueue watcher.</li>
<li><i>-l, --latency=DOUBLE</i>: Set the latency.</li>
<li><i>-n, --numeric</i>: Print numeric event mask.</li>
<li><i>-p, --poll</i>: Use the poll watcher.</li>
<li><i>-r, --recursive</i>: Recurse subdirectories.</li>
<li><i>-t, --time-format</i>: Print the event time using the specified format.</li>
<li><i>-u, --utc-time</i>: Print the event time as UTC time.</li>
<li><i>-v, --verbose</i>: Verbose output.</li>
</ul>
<div>
<br /></div>
<h3>
Installing fsw</h3>
fsw is a C++ project using the GNU Build System and can be installed on any supported system (OS X, v. >= 10.6 or any *BSD system supported kqueue).<br />
<br />
Regular users should download a release tarball, uncompress it, configure it and build it:<br />
<br />
<span style="font-family: Courier New, Courier, monospace;">$ ./configure</span><br />
<span style="font-family: Courier New, Courier, monospace;">$ make</span><br />
<br />
If you're a developer and have the GNU Build System installed on your machine, you can clone the git repository to get the sources:<br />
<br />
<span style="font-family: Courier New, Courier, monospace;">$ git clone https://github.com/emcrisostomo/fsw.git</span><br />
<br />
Then, cd into <i>fsw</i> directory, bootstrap the GNU Build System, configure it and build it:<br />
<br />
<span style="font-family: Courier New, Courier, monospace;">$ ./autogen.sh</span><br />
<span style="font-family: Courier New, Courier, monospace;">$ ./configure</span><br />
<span style="font-family: Courier New, Courier, monospace;">$ make</span><br />
<br />
Finally, no matter you used a release tarball or the repository sources, you can install it system-wide to <span style="font-family: Courier New, Courier, monospace;">/usr/local</span> by running the following command:<br />
<br />
<span style="font-family: Courier New, Courier, monospace;">$ sudo make install</span><br />
<br />
If you cannot install it on <span style="font-family: Courier New, Courier, monospace;">/usr/local</span> or you just prefer to install it on a private directory, you can use the following command instead:<br />
<br />
<span style="font-family: Courier New, Courier, monospace;">$ DESTDIR=/installation/path make install</span><br />
<br />
<h3>
Documentation</h3>
fsw ships with a detailed man page you can consulting using the following command:<br />
<br />
<span style="font-family: Courier New, Courier, monospace;">$ man fsw</span><br />
<br />
<h3>
Getting Help or Giving Feedback</h3>
If you experience some issues or simply want to give your feedback, please contact me.</div>
Enrico M. Crisostomohttp://www.blogger.com/profile/02688166348157974808noreply@blogger.com0tag:blogger.com,1999:blog-7952810330436823110.post-59169101808489323612014-02-11T16:57:00.000+01:002014-02-11T16:57:23.442+01:00How to Include Apple Frameworks' Headers in C/C++ Projects in IDEs Lacking Proper Support such as Eclipse CDT and NetBeansC and C++ programmers using OS X have a nice selection of IDEs at their disposal, including Apple's XCode, <a href="https://www.eclipse.org/cdt/">Eclipse CDT</a>, <a href="https://netbeans.org/">NetBeans</a> and the <a href="http://www.jetbrains.com/objc/features/cpp.html">forthcoming JetBrains C/C++ IDE</a>. Each one has its strengths and weaknesses, and the best choice is often dictated by personal tastes and requirements.<br />
<br />
However, if you have ever written OS X or iOS-specific code, you already discovered that Apple uses a non-standard header organisation. This organisation stems from the concept of "<i>framework</i>" that, according to <a href="https://developer.apple.com/library/mac/documentation/macosx/conceptual/BPFrameworks/Concepts/WhatAreFrameworks.html#//apple_ref/doc/uid/20002303-BBCEIJFI">Apple official documentation</a>, is:<br />
<br />
<blockquote class="tr_bq">
<i>[...] a hierarchical directory that encapsulates shared resources, such as a dynamic shared library, nib files, image files, localized strings, header files, and reference documentation in a single package.</i></blockquote>
<br />
Needless to say, C/C++ compilers and linkers for OS X have been updated to correctly use framework resources. From a C/C++ programmer perspective, nowadays the only practical difference with any other UNIX-flavour is the requirement of using specific linker flags (<span style="font-family: Courier New, Courier, monospace;">-framework</span>).<br />
<br />
<h2>
The Problem with Framework Headers</h2>
There's an important catch, though. A Framework is organised in a directory hierarchy containing the header files into the <i>Headers</i> subdirectory, and such hierarchy can be nested: that is, a framework directory may contain a set of sub-framework subdirectories, each one organised as a self-contained framework with the same directory structure. The <i>CoreServices</i> framework, one of the basic OS X frameworks, contains a set of sub-frameworks including <i>OSServices</i> and <i>LaunchServices</i>, just to name a few.<br />
<br />
Two of the most popular cross-platform C/C++ IDEs, Eclipse CDT and NetBeans, do not feature proper support for OS X frameworks yet. Eclipse CDT is making some progresses, but there still are open bugs which make Eclipse CDT practically unusable for serious OS X programming, at least as far as Eclipse CDT Kepler is concerned. You can see the status and the description of the most important Eclipse bugs in the following links:<br />
<ul>
<li><a href="https://bugs.eclipse.org/bugs/show_bug.cgi?id=69529">Eclipse Bug 69529</a></li>
<li><a href="https://bugs.eclipse.org/bugs/show_bug.cgi?id=378768">Eclipse Bug 378768</a></li>
<li><a href="https://bugs.eclipse.org/bugs/show_bug.cgi?id=378769">Eclipse Bug 378769</a></li>
</ul>
<div>
What these bugs say, to make the long story short, is that frameworks are still <i>unusable</i>, especially so when they are nested.</div>
<div>
<br /></div>
<h2>
Solutions</h2>
<div>
There is no easy solution yet, and I'm only aware of the following workarounds:</div>
<div>
<ul>
<li>Using XCode.</li>
<li>Provide a "flattened" include directory containing symlinks to the header directories of each framework (at least the ones you need).</li>
</ul>
<div>
<br /></div>
<h3>
Using XCode</h3>
</div>
<div>
Using Apple's official C/C++ IDE is a solution to overcome the framework headers problem but it's hardly a "workaround"; instead, it's a switch to another IDE. Apple XCode is a good IDE for C/C++ project and it's being constantly improved, but there are important reasons <i>not</i> to use XCode, at least in certain situations. The most important reasons why I do not use XCode are the following:</div>
<ul>
<li>I want to use the same IDE on different operating systems, and XCode is available only on OS X.</li>
<li>I want to use an extensible IDE with a good plugin ecosystem: XCode, in my opinion, is not a good choice here.</li>
<li>I want to use an IDE that supports the <a href="http://en.wikipedia.org/wiki/GNU_build_system">GNU Build System</a> (AKA GNU Autotools). I've tried many times to maintain such projects with XCode but I couldn't find an efficient workflow.</li>
</ul>
<br />
<h3>
Provide a Flattened Include Directory</h3>
<a href="http://stackoverflow.com/questions/8067329/how-to-include-apple-frameworks-on-eclipse-cdt">A real solution</a> to the headers problem is providing an <i>alternate</i> include directory that your IDE may correctly scan and parse. Let's clarify the reasons why the problem originates in order to understand the rationale behind this solution. The framework directory organisation is tricky because of the following reasons (none of which is taken into account by the above-mentioned IDEs):<br />
<br />
<ul>
<li>A framework root directory is named after the framework to whose name the suffix <i>.framework</i> is added.</li>
<li>Headers are found into the <i>Headers</i> subdirectory of the framework root.</li>
<li>As explained in the previous section, frameworks can be <i>nested</i>.</li>
</ul>
<div>
Nested frameworks are particularly tricky and I'll illustrate it with an example. This statement:</div>
<div>
<br /></div>
<div>
<span style="font-family: Courier New, Courier, monospace;">#include <CoreServices/CoreServices.h></span></div>
<div>
<br /></div>
<div>
is supposed to do include the <i>CoreServices.h</i> file, located into the <i>Headers</i> subdirectory of the <i>CoreServices</i> framework root directory (<i>CoreServices.framework</i>), which is located in one of the operating system framework search path:</div>
<div>
<ul>
<li><i>/System/Library/Frameworks</i></li>
<li><i>/Library/Frameworks</i></li>
</ul>
</div>
<div>
Recent Eclipse CDT releases, for example, are able to do this correctly. Nevertheless, they do <i>not</i> work correctly when a framework header uses a nested framework header. The problem with nested frameworks is that this statement (locate into the <i>CoreServices.h</i> file)</div>
<div>
<br /></div>
<div>
<span style="font-family: Courier New, Courier, monospace;">#include <OSServices/OSServices.h></span></div>
<div>
<br /></div>
<div>
is supposed to include the <i>OSService.h</i> file, located into the <i>Headers</i> subdirectory of the <i>OSServices</i> framework root directory. But this framework is <i>not</i> located into the framework search path, but it's nested (as a sub-framework) into the <i>CoreServices</i> framework.</div>
<div>
<br /></div>
<div>
Both Eclipse CDT and NetBeans fail to interpret this kind of statements correctly, and as a consequence header files are not properly found nor scanned.</div>
<div>
<br /></div>
<div>
The easiest way to trick the IDE into including the files "correctly" is the following:</div>
<div>
<ul>
<li>Providing a new include directory.</li>
<li>The include directory will contain symbolic links to the header directories of <i>each</i> required framework (and <i>all</i> its sub-frameworks).</li>
<li>The name of the symbolic links will be the framework name, stripping the <i>.framework</i> suffix.</li>
</ul>
</div>
<div>
This way, when the IDE sees the <i>#include</i> statement of a nested header such as</div>
<div>
<br /></div>
<div>
<span style="font-family: Courier New, Courier, monospace;">#include <OSServices/OSServices.h></span></div>
<div>
<br /></div>
<div>
it will be able to find the <i>OSServices.h</i> header file by following the <i>OSServices</i> symbolic link, which takes to the sub-framework include directory.</div>
<div>
<br /></div>
<h4>
Automating the Creation of the Symbolic Links to the Header Directories</h4>
<div>
To automate this task I've written a shell script you can find <a href="https://github.com/emcrisostomo/link-osx-framework-headers">in this GitHub repository</a>. What it does is creating all the relevant links in the current directory. For example, the following command:</div>
<div>
<br /></div>
<div>
<span style="font-family: Courier New, Courier, monospace;">$ link-osx-framework-headers.zsh CoreServices</span></div>
<div>
<br /></div>
<div>
creates the following symbolic links (<i>ls</i> output stripped):</div>
<div>
<br /></div>
<div>
<span style="font-family: Courier New, Courier, monospace;">$ ls</span></div>
<div>
<div>
<span style="font-family: Courier New, Courier, monospace;">AE</span></div>
<div>
<span style="font-family: Courier New, Courier, monospace;">CarbonCore</span></div>
<div>
<span style="font-family: Courier New, Courier, monospace;">CoreServices</span></div>
<div>
<span style="font-family: Courier New, Courier, monospace;">DictionaryServices</span></div>
<div>
<span style="font-family: Courier New, Courier, monospace;">LaunchServices</span></div>
<div>
<span style="font-family: Courier New, Courier, monospace;">Metadata</span></div>
<div>
<span style="font-family: Courier New, Courier, monospace;">OSServices</span></div>
<div>
<span style="font-family: Courier New, Courier, monospace;">SearchKit</span></div>
</div>
<div>
<br /></div>
<div>
each one linking to the corresponding include directory, including for nested sub-frameworks:</div>
<div>
<br /></div>
<div>
<div>
<span style="font-family: Courier New, Courier, monospace;">$ ls -l OSServices </span></div>
<div>
<span style="font-family: Courier New, Courier, monospace;">OSServices -> /System/Library/Frameworks/CoreServices.framework/Versions/A/Frameworks/OSServices.framework/Headers</span></div>
</div>
<div>
<br /></div>
<h4>
Listing the Available Frameworks</h4>
<div>
If you do not remember the name of a framework you need you can have the script list all the available frameworks by simply invoking it with no parameters:</div>
<div>
<br /></div>
<div>
<div>
<span style="font-family: Courier New, Courier, monospace;">% link-osx-framework-headers.zsh</span></div>
<div>
<span style="font-family: Courier New, Courier, monospace;">/System/Library/Frameworks/AGL.framework</span></div>
<div>
<span style="font-family: Courier New, Courier, monospace;">/System/Library/Frameworks/AVFoundation.framework</span></div>
<div>
<span style="font-family: Courier New, Courier, monospace;">[...snip...]</span></div>
</div>
<div>
<div>
<span style="font-family: Courier New, Courier, monospace;">/Library/Frameworks/iLifeSlideshow.framework</span></div>
<div>
<span style="font-family: Courier New, Courier, monospace;">/Library/Frameworks/iTunesLibrary.framework</span></div>
</div>
<div>
<br /></div>
<h4>
Configuring the IDE</h4>
<div>
To have your IDE scan the newly created include directory, you have to configure it appropriately. Typically every C/C++ IDE will let you add <i>include paths</i>, where header files are searched. In the case of Eclipse CDT, for example, you can:</div>
<div>
<ul>
<li>Right-click a project and choose <i>Properties</i> (⌘I on OS X).</li>
<li>Navigate to the <i>C/C++ General/Paths and Symbols</i> pane.</li>
<li>Choose the <i>Includes</i> tab (the first one).</li>
<li>Add the include directory for your language (C, C++ or both).</li>
</ul>
Eclipse let you add directories of different kinds:</div>
<div>
<ul>
<li>Workspace.</li>
<li>File system.</li>
</ul>
</div>
<div>
If the directory containing the symbolic links is into the project root, you can include it as a <i>Workspace</i> path, otherwise specify its path as a <i>File System</i> directory. In the following screenshot you can see a workspace include path:</div>
<div>
<br /></div>
<table align="center" cellpadding="0" cellspacing="0" class="tr-caption-container" style="margin-left: auto; margin-right: auto; text-align: center;"><tbody>
<tr><td style="text-align: center;"><a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEjEfydY8OmSDOkNPi47kBIIilUrKGXVN-r-GRf9lOK2sJEcgK84NVT7dGItHGLm7sJZOcgeLZUtZBulGumysa7k7F0WQ74H8HzMkp25qs4bzFCgWZAFnZFEMb-bZnmeH4kI1zSRKSv8FeQi/s1600/c-include-path.png" imageanchor="1" style="margin-left: auto; margin-right: auto;"><img border="0" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEjEfydY8OmSDOkNPi47kBIIilUrKGXVN-r-GRf9lOK2sJEcgK84NVT7dGItHGLm7sJZOcgeLZUtZBulGumysa7k7F0WQ74H8HzMkp25qs4bzFCgWZAFnZFEMb-bZnmeH4kI1zSRKSv8FeQi/s1600/c-include-path.png" height="250" width="320" /></a></td></tr>
<tr><td class="tr-caption" style="text-align: center;">Eclipse CDT - C/C++ Include Path</td></tr>
</tbody></table>
<div>
<br /></div>
<h4>
Making a System-Wide Include Directory</h4>
<div>
You could be tempted to make a single include directory with symbolic links for all the framework. That's easy to do:</div>
<div>
<ul>
<li>Have <i>link-osx-framework-headers.zsh</i> list all the frameworks.</li>
<li>Pipe it through a <i>while read</i> loop.</li>
<li>Have <i>link-osx-framework-headers.zsh</i> create each links for each framework.</li>
</ul>
</div>
<div>
In shell parlance (using Z Shell):</div>
<div>
<br /></div>
<div>
<span style="font-family: Courier New, Courier, monospace;">$ exec zsh</span></div>
<div>
<span style="font-family: Courier New, Courier, monospace;">$ link-osx-framework-headers.zsh | \</span></div>
<div>
<span style="font-family: Courier New, Courier, monospace;"> while read fmk ; do \</span></div>
<div>
<span style="font-family: Courier New, Courier, monospace;"> link-osx-framework-headers.zsh ${${fmk:t}:r} ; \</span></div>
<div>
<span style="font-family: Courier New, Courier, monospace;"> done</span></div>
<div>
<br /></div>
<div>
The workspace include directory still is my favourite option. On the one hand you have to make one include directory for each project and configure each project individually, but on the other hand you are just including the frameworks you really use, thus reducing the quantity of files scanned by the IDE. If you use an external build system, such as the GNU Build System, I find it easier to setup the include directory alongside the Autotools configuration files, so that I keep the files seen by the IDE "in sync" with the package configuration.</div>
Enrico M. Crisostomohttp://www.blogger.com/profile/02688166348157974808noreply@blogger.com2tag:blogger.com,1999:blog-7952810330436823110.post-8644455013058102732014-01-22T18:37:00.002+01:002014-01-22T18:39:14.670+01:00Clean and Optimise the ElasticSearch Indexes of LogstashElasticSearch index files grow large quickly and one of the most common questions about them is how to optimise them and clean them, getting rid of old records you're not interested in any longer. A very easy way to accomplish these tasks is using the following <a href="https://github.com/crashdump/logstash-elasticsearch-scripts" target="_blank">two scripts</a>:<br />
<div>
<ul>
<li><span style="font-family: Courier New, Courier, monospace;">logstash_index_optimize.py</span></li>
<li><span style="font-family: Courier New, Courier, monospace;">logstash_index_cleaner.py</span></li>
</ul>
</div>
<div>
The first optimises the indexes <i>newer</i> than the specified number of days, while the latter cleans the indexes <i>older</i> than the specified number of days. The complete synopsis of either command can be obtained using the <span style="font-family: Courier New, Courier, monospace;">-h</span> option.</div>
<div>
<br /></div>
<h3>
Installing the Dependencies</h3>
<div>
These scripts depend on the following components:</div>
<div>
<ul>
<li>The Python runtime (at least version 2).</li>
<li>The <i>pyes</i> package.</li>
</ul>
<div>
The <i>pyes</i> package, in turn, can be installed using <i>pip</i>:<br />
<br />
<span style="font-family: Courier New, Courier, monospace;"># pip install pyes</span><br />
<br />
Beware that the ElasticSearch instance bundled by Logstash is not supported by the latest <i>pyes</i> release (0.90.x) which requires ElasticSearch 0.90. If you're using the ElasticSearch instance bundled in Logstash, you must install version 0.20.1:<br />
<br />
<span style="font-family: Courier New, Courier, monospace;"># pip install pyes==0.20.1</span><br />
<br />
<h4>
Installation on FreeBSD</h4>
The FreeBSD ports collection ships all the required dependencies as binary packages. The Python runtime can be installed with the following command:<br />
<br />
<span style="font-family: Courier New, Courier, monospace;"># pkg install python</span><br />
<br />
pip can be installed using (assuming Python 2.7 has been installed, as in FreeBSD 9.2 and 10.0):<br />
<br />
<span style="font-family: Courier New, Courier, monospace;"># pkg install py27-pip</span><br />
<br />
Once pip is installed, it can be used to installed <i>pyes</i> in a platform-independent way as explained in the previous section.<br />
<br />
<h3>
Running the Scripts</h3>
The simplest way to run the scripts is:<br />
<br />
<ul>
<li>Passing the <span style="font-family: Courier New, Courier, monospace;">--host</span> option to specify the ElasticSearch server to connect to.</li>
<li>Passing the <span style="font-family: Courier New, Courier, monospace;">-d</span> option to specify the desired number of days.</li>
</ul>
<div>
<br /></div>
<div>
<span style="font-family: Courier New, Courier, monospace;">$ python /path/to/logstash_index_cleaner.py \</span></div>
<div>
<span style="font-family: Courier New, Courier, monospace;"> --host es-host \</span></div>
<div>
<span style="font-family: Courier New, Courier, monospace;"> -d 30</span></div>
<div>
<br /></div>
<div>
Given the periodic nature of these tasks, I usually schedule them as cron jobs in a crontab file.</div>
<br />
<br />
<br /></div>
</div>
Enrico M. Crisostomohttp://www.blogger.com/profile/02688166348157974808noreply@blogger.com0