Friday, June 20, 2014

Installing Logstash v 1.4 (and Greater) on FreeBSD

In a previous post 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.

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 service. Further information about the new    distribution layout can be found in the Logstash release notes.

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.

Edit: 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 an updated FreeBSD port I've created to install Logstash on FreeBSD 10.

Edit: The Logstash port has been updated and I'm the new maintainer. Also, the pull request solving a JRuby bug on FreeBSD has been merged to upstream and will hopefully hit a Logstash release soon.

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.

Prerequisites

The essential prerequisites required to execute Logstash are:
The former is required because LogStash is a JRuby application while the latter, although not technically a requirement, is the recommended output for Logstash.

Installing Java

To install OpenJDK on FreeBSD you can use pkg to install a ready-to-use binary package:

# pkg install openjdk

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):

# pkg search openjdk
openjdk-7.60.19,1
openjdk6-b31_3,1
openjdk8-8.5.13_7
# pkg install openjdk8-8.5.13_7

Installing ElasticSearch

Logstash includes an embedded ElasticSearch instance you can use for standalone installations (see my previous post 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.

Although simpler from the standpoint of the configuration, Logstash installations using separate ElasticSearch instances are out of the scope of this post.

Installing Logstash

Logstash installation procedure is fairly simple since it is distributed as a tarball:
  • Download Logstash from the official website.
  • Extract the tarball in the designated installation directory (my personal suggestion is to avoid /usr/local because it is used by ports and to use /opt instead).

Creating an rc.d Script

An rc.d script is required in a BSD system to register a service, define its configuration and have the rc framework manage its lifetime. The following script 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:
  • Installation directory: ${logstash14_home="/opt/logstash-1.4.1"}
  • Configuration file path: ${logstash14_config="/usr/local/etc/${name}/${name}.conf"}
  • ElasticSearch data directory: ${logstash14_elastic_datadir="/var/db/logstash14"}
  • Java home: ${logstash14_java_home="/usr/local/openjdk6"}
You can override any of the supported configuration values in the /etc/rc.conf file. If, for example, you want to use an alternate Java home path, just add the following line to /etc/rc.conf setting the desired value:

logstash14_java_home="/usr/local/openjdk7"

Testing the Service

To test the Logstash service, the following command can be used:

# service logstash14 onestart

To stop it, use:

# service logstash14 onestop

To help troubleshooting any problem you might find you can enable the Logstash log, setting the logstash14_log variable to YES in the /etc/rc.conf file:

logstash14_log="YES"

The log file location is specified by the logstash14_log_file variable, whose default value is set by the service rc file (only the relevant lines are shown):

name=logstash14
logdir="/var/log"
: ${logstash14_log_file="${logdir}/${name}.log"}

The log file location can be overridden setting the logstash14_log_file variable in the /etc/rc.conf file.

Enabling the Service

Note that the rc script described above does not enable the Logstash service:

: ${logstash14_enable="NO"}

If everything works, you can enable the Logstash service just adding the following line to /etc/rc.conf:

logstash14_enable="YES"

Wednesday, June 18, 2014

Pkg Update Fails in FreeBSD 9.2 Because of a Python Setuptools Conflict

Today I launched pkg to upgrade some binary packages installed in a FreeBSD 9.2 instance but suddenly pkg failed complaining about a locally installed python package (py27-setuptools-2.0.1) 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:

WARNING: locally installed py27-setuptools-2.0.1 conflicts on /usr/local/bin/easy_install with:
- py27-setuptools27-2.0.1

All the software in this box was installed using pkg binary packages, so that at first this error sounded really strange to me.

Even though you use pkg 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:

/usr/ports/UPDATING

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 pkg.

A quick search starting from approximately the date of the last update of the affected machine pointed me in the right direction:

20140307:
  AFFECTS: users of devel/py-setuptools dependent ports
  AUTHOR: sunpoet@FreeBSD.org

  devel/py-setuptools is being used for every python ports (if USE_PYDISTUTILS
  defined) since r336553. Due to PKGORIGIN limitation, we cannot build one
  python port with python27 and the other with python33 since they require
  different setuptools versions which have same PKGORIGIN. With the addition
  of py-setuptools{27,32,33}, we could now have py27-foo and py33-bar coexist
  in one system.
  [...]

The suggested solution for pkg users is:

# pkg set -o devel/py-setuptools:devel/py-setuptoolsXX

where XX is the affected Python version. After running

# pkg set -o devel/py-setuptools:devel/py-setuptools27

pkg upgrade went fine and the problem was solved.

Monday, June 16, 2014

NSControlTextEditingDelegate Methods Are Not Called on a the Delegate of a View-Based NSTableView

I was developing a OS X Cocoa application and the time came to validate the text input by the user while editing cells of an NSTableView. My Cocoa-fu immediately suggested me to take advantage of the NSControlTextEditingDelegate protocol that specifies the following two methods to hook exactly where I need to:
  • control:textShouldBeginEditing:
  • control:textShouldEndEditing:

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:


Then I selected the Connection Inspector and connected the delegate outlet to the target object:


Finally, I implemented the two aforementioned methods on the delegate object, ran the application and... nothing happened!

The Official Documentation

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.

I revised the documentation, outlets and the code over and over again, but I could not detect the problem. Then I noticed that I was not the only one struggling with this issue, although no solution was provided.

To make a long story short, the documentation I checked seemed confirmed the it should have worked, until I found especially after reading an official Apple Technical Q&A, number QA1551, titled Detecting the start and end edit sessions of a cell in NSTableView, stating the following:

A: How do I detect start and end edit sessions of a cell in NSTableView
In order to detect when a user is about to start and end an edit session of a cell in NSTableView, you need to be set as the delegate of that table and implement the following NSControl delegate methods:
- (BOOL)control:(NSControl *)control textShouldBeginEditing:(NSText *)fieldEditor;
- (BOOL)control:(NSControl *)control textShouldEndEditing:(NSText *)fieldEditor;
The table forwards the delegate message it is getting from the text view on to your delegate object using the control:textShouldEndEditing: method. This way your delegate can be informed of which control the text view field editor is acting on its behalf.

So, you should not set the editable field delegate but the table one! Fortunately, that was easy to change. I removed the connection to the delegate outlet in the text field and set the table one instead. I started the application and... nothing happened again!

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.

The Solution

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 (NSControlTextEditingDelegate), the delegate was not. Better yet: they were not.

In fact, after some of tests I reached the following conclusions:
  • A cell-based NSTableView instance works as expected: setting the table delegate causes the NSControlTextEditingDelegate protocol methods to be invoked on it.
  • A view-based NSTableView instance (such as mine and almost surely most of the new NSTableView instances out there) required both the table and the field delegates to be set for the NSControlTextEditingDelegate protocol methods to be invoked.

I suspected that the aforementioned Apple Technical Q&A QA1551 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.

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 Table View Programming Guide for Mac makes no mention of this "peculiarity" despite being a fairly common use case.

I hope this post helps anybody falling into the same trap to quickly solve his issues with getting NSControlTextEditingDelegate notifications to his table delegate.

Thursday, June 5, 2014

EMCCountryPickerController v. 1.3.0 Has Been Released

EMCCountryPickerController v. 1.3.0 has been released bringing the possibility of resizing the flags shown in the table cells automatically resizing the cell height.

Here is a screenshot showing flags resized to fit in a square of size 20:

Custom Flag Size - Sized to Fit into 20x20

and here is a screenshot showing flags resized to fit in a square of size 80:

Custom Flag Size - Sized to Fit into 80x80


To set the desired flag size, just use the controller's flagSize property:

countryPicker.flagSize = 80;

You can get the latest version using CocoaPods, by adding a dependency to your Podfile:

pod 'EMCCountryPickerController' ~> '1.0'

If you are already using EMCCountryPickerController, then you just need to update your pod repository index:

$ pod repo update

and then and update your outdated project dependencies running this command in the project root directory:

$ pod update

Enjoy.

Monday, June 2, 2014

OS X: Creating Packages from the Command Line - Tutorial and a Makefile - Part II

In the previous part of this tutorial we examined how pkgbuild and productbuild are used to build component packages and product archives. We also saw how hdiutil can be used to create a DMG image file to nicely package and distribute your product archive.

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.

Exactly what a Makefile is for!

A Makefile to build a Product Archive

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

$ xcodebuild install

If this is not the case, just update the relevant action to run the build from the correct directory.

Let's start writing the Makefile in a top-down fashion. Let's add a default all target depending on anything else:
  • $(DISTDIR) is the source folder for the DMG file, where the product archive will be stored.
  • $(DEPSDIR) 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.
  • $(PRODUCT) is the product archive.
  • $(DMGFILE) is the DMG image file creating from the source folder $(DISTDIR).
The resulting target is:

.PHONY : all
all : $(DISTDIR) $(DEPSDIR) $(PRODUCT) $(DMGFILE)

$(DISTDIR) and $(DEPSDIR) are created by the Makefile since we assume it is the Makefile that populates them:

$(DISTDIR) :
  mkdir $(DISTDIR)

$(DEPSDIR) :
  mkdir $(DEPSDIR)

$(PRODUCT), the product archive, depends on:
  • $(BINARIES), the main component binaries.
  • $(DEPENDENCY), a placeholder for the dependencies, 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 productbuild would fail if a required component package is missing, but I think it is preferable to have make fail because of a missing target dependency.
  • $(COMPONENT_PFILE), the component package property list file.
  • $(COMPONENT), the component package.
  • $(DISTRIBUTION_FILE), the distribution file.
  • $(REQUIREMENTS), the requirements file.

$(PRODUCT) : $(BINARIES) $(REQUIREMENTS) \
             $(DEPENDENCY) $(COMPONENT_PFILE) \
             $(COMPONENT) $(DISTRIBUTION_FILE)
  productbuild --distribution $(DISTRIBUTION_FILE) \
    --resources . \
    --package-path $(DEPSDIR) \
    --package-path $(DEPENDENCYDIR) \
    $(PRODUCT)

The $(BINARIES) are usually compiled and installed with xcodebuild:

$(BINARIES) :
  xcodebuild install

The component package property list file, $(COMPONENT_PFILE), 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.

$(COMPONENT_PFILE) :
  @echo "Error: Missing component pfile."
  @echo "Create a component pfile with make compfiles."
  @exit 1

The main component package $(COMPONENT) depends on the binaries $(BINARIES) and the component property list file $(COMPONENT_PFILE) and it must be created with pkgbuild, as seen in the previous part of this tutorial:

$(COMPONENT) : $(BINARIES) $(COMPONENT_PFILE)
  pkgbuild --root $(BINARIES) \
  --component-plist $(COMPONENT_PFILE) \
  $(COMPONENT)

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:

$(DISTRIBUTION_FILE) :
  @echo "Error: Missing distribution file."
  @echo "Create a distribution file with make distfiles."
  @exit 1

Now the Makefile is functional except for one detail: who is going to create the two required property list files $(COMPONENT_PFILE) and $(DISTRIBUTION_FILE)? We have seen in the previous part of this tutorial that both pkgbuild and productbuild 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:

.PHONY : distfiles
distfiles : $(COMPONENT)
  productbuild --synthesize \
  --product $(REQUIREMENTS) \
  --package $(DEPENDENCY) \
  --package $(COMPONENT) \
  $(DISTRIBUTION_FILE).new
  @echo "Edit the $(DISTRIBUTION_FILE).new template to create a suitable $(DISTRIBUTION_FILE) file."

.PHONY : compfiles
compfiles : $(BINARIES)
  pkgbuild --analyze \
  --root $(BINARIES) \
  $(COMPONENT_PFILE).new
  @echo "Edit the $(COMPONENT_PFILE).new template to create a suitable $(COMPONENT_PFILE) file."

Note that in the distfiles target the $(DEPENDENCY) variable is used as argument of the --package 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, $(COMPONENT).

The files created by both the distfiles and the compfiles targets must be manually edited by the user and moved to their expected name by removing the .new extension.

Finally, let's add some targets to perform some housekeeping:
  • clean, to remove the DMG file and all the packages.
  • distclean, to remove the distribution files.
  • compclean, to remove the component file.

.PHONY : clean
clean :
  -rm -f $(DMGFILE) $(PRODUCT) $(COMPONENT)
  -rm -rf $(BINARIES)

.PHONY : distclean
distclean :
  -rm -f $(DISTRIBUTION_FILE) $(DISTRIBUTION_FILE).new

.PHONY : compclean
compclean :
  -rm -f $(COMPONENT_PFILE) $(COMPONENT_PFILE).new

Populate the Variables

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.

This is the typical variable definition block I use at the top of this kind of Makefiles:

PROGRAM = Name
DISTDIR = ./dist
DEPSDIR = ./deps
BINARIES = /tmp/Name.dst
DMGFILE = $(PROGRAM).dmg
PRODUCT = $(DISTDIR)/$(PROGRAM).pkg
COMPONENT = $(DEPSDIR)/$(PROGRAM)Component.pkg
COMPONENT_PFILE = $(PROGRAM).plist
DISTRIBUTION_FILE = distribution.dist
REQUIREMENTS = requirements.plist

PROGRAM is a shared fragment which is typically set to the XCode project name. The DMG file name DMGFILE, the product archive name PRODUCT and the binary installation directory BINARIES 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.

Use It

The default Makefile target, all, can be executed by simply invoking

$ make

If everything works correctly, you will find a DMG file image in your execution directory containing your product archive.

Conclusion

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.

OS X: Creating Packages from the Command Line - Tutorial and a Makefile - Part I

Over the years Apple has been removing useful tools from its flagship IDE, XCode, and PackageMaker 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 Mac Dev Center (search for a package called XCode Auxiliary Tools), PackageMaker is clearly an unsupported tool of the past, and you'd better rely on the current ones: pkgbuild and productbuild.

Both pkgbuild and productbuild are command-line tools and they provide developers all the functionality they need to (man page citation):
  • Build OS X installer component packages.
  • Build a product archive for the OS X installer.
  • Build a product archive for the Mac App Store.
The only issue with them is they do not have a GUI and XCode does not publish their functionality through its UI.

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:
  • Create your own product archives containing multiple component packages.
  • Create a DMG disk image for your product archive.

In the next part 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.

Using pkgbuild

pkgbuild is the tool used to create component packages, the building blocks of product archives, 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 cannot be submitted to the Mac App Store.

pkgbuild 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: pkgbuild provides an analyse 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.

Assuming we want to build a component package for an OS X application, we first invoke pkgbuild in analyse mode on a release installation directory to create an initial component property list file:

$ pkgbuild --analyze \
  --root /tmp/Name.dst \
  NameComponent.plist

The root path for an application project is an XCode project property (Project/Build Settings/Deployment/Installation Build Products Location) defaulting to /tmp/$(PROJECT_NAME) that can be specified when performing the xcodebuild install target by setting the DSTROOT variable.

When run, pkgbuild will create a file called NameComponent.plist containing default configuration values such as the following (output may vary):

<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
<plist version="1.0">
<array>
  <dict>
    <key>BundleHasStrictIdentifier</key>
    <true/>
    <key>BundleIsRelocatable</key>
    <true/>
    <key>BundleIsVersionChecked</key>
    <true/>
    <key>BundleOverwriteAction</key>
    <string>upgrade</string>
    <key>RootRelativeBundlePath</key>
    <string>Applications/Name.app</string>
  </dict>
</array>
</plist>

Tweak your component property file according to your needs (man pkgbuild for detailed information about the available configuration property) and when the configuration is ready pkgbuild can be run in its main mode to create the component package (split lines for better readability):

$ pkgbuild --root /tmp/Name.dst \
  --component-plist NameComponent.plist \
  NameComponent.pkg

Here, we use NameComponent.pkg as the name of the component package to distinguish from the name of the product archive package.

Sign Packages with pkgbuild

pkgbuild 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 pkgbuild with the --sign identityName option where identityName is the common name (CN) of the desired certificate.

If you are creating a signed product, 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 productbuild.

Using productbuild

Let's now suppose you have created two component packages for your product:
  • NameComponent.pkg, created in the previous section.
  • MyFramework.pkg, a dependency of NameComponent.pkg (created as seen in the previous section).

productbuild is the tool used to create product archives, 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.

Similarly to pkgbuild, productbuild runs in multiple modes (currently the available modes are 5, see the man page for detailed information), two of them being:
  • Analysis mode, to create an initial distribution file.
  • Create a product archive from a distribution file.
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):
  • A product license.
  • A product README file.
  • The list of component packages.
  • Constraints (such as minimum OS version).

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 --synthesize option to run productbuild in analysis mode, two component packages with multiple --package options, a requirement file (described in the next section) and the name of the resulting distribution file distribution.plist (split lines for better readability):

$ productbuild --synthesize \
  --product requirements.plist \
  --package MyFrameworkComponent.pkg \
  --package NameComponent.pkg \
  distribution.plist

Once productbuild creates the initial distribution file, you can manually modify it to satisfy your needs.

Adding a License

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 <license/> element to the distribution file root element <installer-gui-script/>:

<?xml version="1.0" encoding="utf-8" standalone="no"?>
<installer-gui-script minSpecVersion="2">
  <title>Name</title>
  ...
  <license file="LICENSE.html"/>
  ...
</installer-gui-script>

Adding a README

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 <readme/>:

<?xml version="1.0" encoding="utf-8" standalone="no"?>
<installer-gui-script minSpecVersion="2">
  <title>Name</title>
  ...
  <license file="LICENSE.html"/>
  <readme file="README.html"/>
  ...
</installer-gui-script>

Creating a Requirements File

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):
  • os: Minimum allowable OS version.
  • arch: Supported architectures.
  • ram: Minimum required RAM.

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 os key with the constraint we need:

<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
<plist version="1.0">
<dict>
  <key>os</key>
  <array>
    <string>10.9</string>
  </array>
</dict>
</plist>

Creating the Product Archive

Once the distribution file is ready, productbuild can be run to finally create the product archive. In this case we have to specify the distribution file with the --distribution option, the resource path where resource files are found (such as license and README, even if they are in the current working directory) the package path where component packages can be found using the --package-path options (in case they are not in the current working directory) and the name of the product package:

$ productbuild \
  --distribution distribution.plist
  --resources .
  --package-path path/to/MyFrameworkComponent.pkg
  --package-path path/to/NameComponent.pkg
  Name.pkg

Signing the Product Archive

As explained in the case of pkgbuild, productbuild lets you sign the product archive using the identity (a certificate common name) specified with the --sign option. The specified certificate must be available in an accessible keychain, otherwise the path of a specific keychain must be specified using the --keychain option.

A product archive can even be signed after it has been created using the productsign command (see the man page for further information).

Creating a DMG Disk Image

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:
  • Put all the files your want to include in a folder (the source folder in hdiutil jargon).
  • Use the hdiutil command-line utility to create a DMG disk image from the source folder.

Assuming we have created the ./dist source folder where we have copied the Name.pkg product archive, we can use the following command to create a Name.dmg DMG file (split lines for better readability) named My Product:

$ hdiutil create \
  -volname "My Product" \
  -srcfolder ./dist \
  -ov \
  Name.dmg

The optional -ov option is used to overwrite an existing DMG file.

A Makefile to Put It All Together

In the next part 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.

EMCCountryPickerController v. 1.2.0 Has Been Released

EMCCountryPickerController v. 1.2.0 has been released bringing a new localisation in the Spanish (es) language:


You can get the latest version using CocoaPods, by adding a dependency to your Podfile:

pod 'EMCCountryPickerController' ~> '1.0'

If you are already using EMCCountryPickerController, then you just need to update your pod repository index:

$ pod repo update

and then and update your outdated project dependencies running this command in the project root directory:

$ pod update

Enjoy.