I am trying to create an installer for a Java app on Mac OS 10.8.4. The app runs fine, and I can install it without a hitch from a zip file. I can create a .pkg installer with either productbuild or pkgbuild. I can also install either of the installer .pkg file successfully, however the app does not run properly due to the fact that both packaging programs change the ownership of a data directory and its subordinate files and subdirectories from user to root. I install this data directory in the Resources directory of the .app bundle, and the first time the program executes, it moves the data directory to /Users/user/Library/Application Support. I tried using the --ownership preserve and --ownership preserve-other options with pkgbuild to no avail. The only way I have been able to install and execute properly is via the zip file, since it leaves file ownership alone. Here is the pkgbuild command I am using:
pkgbuild --ownership preserve --component ./myApp.app ./myApp-installer.pkg
My questions are:
How can I force pkgbuild to honor my --ownership preserve option?
Is it possible to build a separate data-only package with user ownership and destined for the user area and merge it with the executable package via the --synthesize option of pkgbuild? if yes, could someone show me how to build such a data-only package?
I know it is quite old, I'll just answer in case someone else needs the answer.
What I usually do, is that I have a shell script which creates the .pkg file for me. In that script I set all the file permissions and ownership before packaging. Here is an example:
NAME="PKGFILENAME"
IDENTIFIER="com.pkg.APPNAME"
VERSION="1.0.0"
INSTALL_LOCATION="PATH_TO_WHERE_THE_FILES_SHOULD_BE_COPIED_ON_USERS_MACHINE"
ROOT_LOCATION="PATH_TO_WHERE_FILES_ARE_ON_YOUR_MASCHINE"
# Remove any unwanted .DS_Store files.
find "$ROOT_LOCATION" -name '*.DS_Store' -type f -delete
# put any command for changing the ownership or permissions here
chmod -R +r "$ROOT_LOCATION"
# Build package.
/usr/bin/pkgbuild \
--root "$ROOT_LOCATION" \
--install-location "$INSTALL_LOCATION" \
--identifier "$IDENTIFIER" \
--version "$VERSION" \
"$NAME.pkg"
save this something in a file like create-my-package.sh and run this in command line.
Related
I have a binary file, foo. Built using vercel/pkg.
I would like to bundle this in an installer for mac; A .pkg installer file.
It should install the binary in /usr/local/bin/foo.
Attempt:
$ cd Desktop // <--- foo binary is here
$ pkgbuild --identifier com.foo.pkg --install-location ./usr/local/bin/ --root ./ foo.pkg
This creates a .pkg file: foo.pkg on my desktop. And when i run foo.pkg, it installs the foo binary in /usr/local/bin correctly, except that it also leaves foo.pkg in /usr/local/bin also.
How can make pkgbuild avoid leaving foo.pkg inside /usr/local/bin?
UPDATE:
Based on this thread, I think it will work if i set BundleIsRelocatable to false. But I am not able to figure out how that is done.
When you pass --root, it takes everything in that folder and bakes it into the package. You're running pkgbuild in the root that you're building - it seems very likely that you have a copy of foo.pkg on your desktop that was created by an earlier run of pkgbuild. When you run it again, the old foo.pkg is now built into the new package.
Instead, point --root at a directory only containing the files you wish to package.
Otherwise, use --analyze to generate a component list of your root directory. Customize the resulting .plist as necessary (specifying the files you want to include and associated options), then feed it back into pkgbuild with --component-plist.
You should read the man page if you haven't already.
I’m having an odd issue where my installer properly overwrites the previously installed app, but then overwrites the app in my build directory.
My installer build looks like this:
mkdir /tmp/foo
cp -R ~/Projects/MyApp/Builds/MacOSX/build/Release/MyApp.app /tmp/foo
pkgbuild --quiet --analyze --root /tmp/foo/ MyApp.plist
pkgbuild --quiet --root /tmp/foo/ \
--component-plist MyApp.plist \
--identifier com.mycompany.myapp \
--version $VERSION \
--install-location "/Applications" \
MyApp.pkg
productbuild --quiet --distribution "./Distribution.xml" \
--package-path "./" --resources "./Resources" \
--sign "Developer ID Installer: My LLC" "MyApp Installer.pkg"
Now, this works…it installs the app in the /Applications folder as I’d expect. But I was noticing some issues with my next Xcode build. After some investigating, I noticed that my build folder looked like this after the Xcode build and before running the installer:
drwxr-xr-x# 3 me staff 96 Jul 11 23:15 My.app
…and like this, AFTER running the installer:
drwxr-xr-x 3 root wheel 96 Jul 11 23:44 My.app
Somehow, the owner of my app had changed. I double checked everything and didn’t see anything that touched my build folder. But then I checked the installer log and found this mysterious line:
PackageKit: Applications/MyApp.app relocated to
Users/me/Projects/MyApp/Builds/MacOSX/build/Release/MyApp.app
After some googling, others have speculated that the installer overwrites ANY copy of the app it finds anywhere on the drive…not just the one in the folder you tell it. It makes some sense…if I delete that copy of my app in the build folder, the installer doesn’t create a new one. It only overwrites it if it’s there.
While this isn’t a huge problem, it’s somewhat problematic as it changes the owner of the file which prevents the next build from working.
Has anyone else run into this issue? Is there some option for the installer to NOT overwrite EVERY copy of the installed app?
The Installer has a few features that allow it to locate application bundles that have moved in the file system. Inside your compiled .pkg, have a look at the PackageInfo and Distribution files, and see if you see any <locator> tags. The <locator> tag is defined at the link below, and is one of the main ways to enable this sort of thing.
https://developer.apple.com/library/archive/documentation/DeveloperTools/Reference/DistributionDefinitionRef/Chapters/Distribution_XML_Ref.html#//apple_ref/doc/uid/TP40005370-CH100-SW15
Another possibility is that you may have a <bundle> element with the search property set, as documented here:
https://developer.apple.com/library/archive/documentation/DeveloperTools/Reference/DistributionDefinitionRef/Chapters/Distribution_XML_Ref.html#//apple_ref/doc/uid/TP40005370-CH100-SW36
If you want to easily inspect the internal structure of your compiled package, you can use Pacifist to do that fairly easily. (disclaimer: I'm the author of Pacifist)
It's just a hunch, but I wonder if this can be solved by forgetting the current installs of your app by dropping the installation receipts like this:
sudo pkgutil --forget com.mycompany.myapp.pkg
You can get a list of all package receipts on your machine like this:
sudo pkgutil --pkgs
The reason I have this hunch is because I think the install locations might be stored in the receipts. Therefore causing the machine to "forget" (delete) where the packages are might make it so the installer has to install at the specified location specified by the package. I fully admit this is a WAG (wild-ass guess).
I can use pkgbuild and productbuild to create decent installers for an app. However, I need to create one that installs a bare executable and launch daemon, and I've hit a wall.
The crux of the problem seems to be the RootRelativeBundlePath item in the component list for pkgbuild. Since there's no bundle being installed, no path will work there, but I can't omit RootRelativeBundlePath either. So I can't generate the component package.
What do I do?
Found an answer to my own question, using the following command to build the component package, skipping the component list plist entirely:
pkgbuild --root software_root --install-location "/" --scripts scripts/ --identifier 'com.blah.pkg.blah' --version '1.0.0' installer.pkg
I understand PackageMaker is now deprecated. We're now supposed to use pkgbuild/productbuild.
However, I can't seem to find an example for creating an installer for a kext. I was hoping to build the package as part of a build step from my kext Xcode project. So any bash/script files would be great.
This answer is a seriously good guide for the general case.
For a kext specifically, after the Product -> Archive step, to generate the component plist, I found that I needed to 'cd' into the built archive package directory:
cd ~/Library/Developer/Xcode/Archives/2013-12-22/my-kext\ 22-12-2013\ 22.57.xcarchive
Then, the pkgbuild --analyze step looks like this:
pkgbuild --analyze --root ./Products/ my-kext.plist
The produced plist should contain a sensible-looking install destination for your kext under the RootRelativeBundlePath key. (typically /System/Library/Extensions/my.kext, or if codesigned and for 10.9+ it should be /Library/Extensions/my.kext) If not, fix the install location for your kext target in Xcode.
The main thing to watch out for when installing kexts is to get permissions right and to refresh the kext cache. pkgbuild seems to install the kext as root by default, so that's good. To force refreshing the kext cache, you need to update the modified time on /System/Library/Extensions (or /Library/Extensions if that's where you're installing to). You want to do this after your kext has been fully installed, so you'll need a postinstall script. Create a directory for it, e.g. ./scripts and create a file called 'postinstall' with the contents:
#!/bin/sh
touch /System/Library/Extensions
Then make it executable:
chmod +x postinstall
You can now build a generic package for your kext using:
pkgbuild --root ./Products/ --scripts ./scripts/ --component-plist my-kext.plist my-kext.pkg
For customisation, codesigning, etc., follow the instructions in catlan's linked answer - you can't beat them!
Being new to packagemaker I assume I am just missing something. It does not seem all the options in the GUI are available from the command line. I have read the man page but maybe I just don't get it.
Of most interest to me is how do I specify the install locations of the files?
From the commandline to I need to also use installer in combination with packagemaker to get the same results of the GUI packagemaker? If so are there any examples you can recommend?
Thanks
Vincent
What I ended up doing to change the install directory from command line:
create the package
extract the new package with pkgutil
string search for install-location="/" in the pkg file's PackageInfo, replace with desired install location
repackage with pkgutil
That works.
If you are creating packages using commandline mode of packagemaker, you will have to create a dummy directory which contains all your files in proper location. For example, if you have to install files A and B at /Library/Applications/ and /Library/Application Support/ respectively, then you create the structure as below.
Create a temp directory, say SourceFiles.
Add your files to this directory as follows-
SourceFiles/Library/Applications/A
SourceFiles/Library/Application Support/B
Now use the flag --root in packagemaker commandline mode.
packagemaker --root SourceFiles/ OTHER_OPTIONS
The idea is that instead of passing location of individual files to the command, you create a similar structure in a temporary directory and just pass that directory as argument to --root flag.
More for commandline mode of packagemaker:
http://macinstallers.blogspot.in/