Packaging

From iPhone Development Wiki
Jump to: navigation, search

Packaging is the step prior to sharing or releasing a tweak/application/tool/library/theme. Here you put all your project files into a single nicely wrapped file that others can install on their devices.

Cydia is based on Debian APT (Advanced Packaging Tool), so a lot of general documentation about packaging for APT also applies to packaging for Cydia.

To do: bring over http://iphonedevwiki.net/index.php/Best_Practices#Packaging. Maybe http://iphonedevwiki.net/index.php/MobileSubstrate_Pitfalls#Packaging too.

Tools

To do: add existing tools, on which platforms they are available, how to use them.

DEBIAN folder

Control file

To do: add layout of fields, what do they mean, how they are used. Refer to saurik's post and links at the bottom.

If you need to list dependencies or conflicting packages, Debian's packaging manual may be useful (because Cydia packaging is based on Debian packaging): Syntax of relationship fields, Dependencies, Conflicts -- or if you're submitting this package to a default repository, you can just ask your repository maintainer for help with this.

Other files

You can add preinst, postinst, extrainst_, prerm, and postrm files to run scripts at various points of the package installation and uninstallation lifecycle. It's important to be conservative with this code - as Best Practices explains, "Do not use postinst/preinst/extrainst_ for file management purposes! Do not store in the package files or directories that your software could create. Do not enforce permissions that your package should contain. dpkg uses an expressive packaging format that has support for permissions, ownership, and links. Use that support!"

If your package scripts have problems, especially upon uninstallation, this can be very frustrating for your user because that can be very hard to fix for them. You don't want to cause the dreaded "subprocess pre-removal script returned error" and "Sub-process /usr/bin/dpkg returned an error code" error messages. A related unfortunate reality is that if your package has complex scripts, that can increase the chances that if a pirate repository poorly repackages your tweak, somebody doing "try before they buy" can run into those error messages and get frustrated.

Documentation about these scripts in the Debian packaging manual: basics and more info.

extrainst_

I get a lot of requests for things like "I want to run stuff after the install, but only on install, not on upgrade". APT/dpkg is miserable at this. Its sad, but true. It has a file called postinst, but postinst is really designed for reconfiguring a package, not for installing it: its called /long after/ the package is installed (like, APT will go on and install more things and then queue up the postinst files to the very end) and it doesn't /really/ know anything about the package.

Example: in a postinst you know that the previous configuration on disk was from version 1.0, but not that 1.0 itself was actually on disk. And if you are a new install it still tells you that /you're/ already the configuration there (which is really just a stupid semantic).

/So/, after dealing with an issue in a package with _BigBoss_, I have decided to do something about this: I have added to dpkg a new script called extrainst_. This script takes one of two arguments: install or upgrade (in which case you also get the version you are upgrading from), and is designed to completely ignore configuration files (so if you were previously in a configuration file only state that isn't considered "installed"). I believe that this new script now provides a very simple conceptualization for how you do "extra stuff" during an install.

In fact, if you are previously coming from Installer, this script will likely feel like "ahhhh".

To use this new script (which yes, really ends in an underscore) your package should Pre-Depends: dpkg (>= 1.13.25-5). This will make it so that that version of dpkg is actually available during the install and is used to run the scripts. (Yes, this will work even during the install using the old version of dpkg to upgrade dpkg and then switching to the new version of dpkg to install your script ;P).

If this script fails then the install is considered to not have worked and the installation procedure will get rolled back (files will get removed, replaced back to the backup copies if it was an upgrade, and a million random scripts will get called with irritatingly complicated to remember arguments).

(Note that this version of dpkg isn't up right now, but will be up within an hour or two: i.e., long before any of you is likely to bother to try to use it ;P).

An example extrainst_:

#!/bin/bash

if [[ $1 == install || $1 == upgrade ]]; then
    do_something awesome
fi

if [[ $1 == upgrade && $2 == 1.0-4 ]]; then
   fix_bug_in old version
fi

-J

To see the whole discussion about this, see this thread.

Telling Cydia to respring/reboot etc. after install

From this paste

#!/bin/bash
# extrainst_
# postrm

## Acceptable parameters for finish
# return - normal behaviour (return to cydia)
# reopen - exit cydia
# restart - reload springboard
# reload - reload springboard
# reboot - reboot device
##
# Historically, 'restart' restarted springboard but did not reload the launchdaemon.
# (reload was used for this purpose.) Now, restart and reload are equivalent.
function finish() {
	f="${1}"

	# No control fd: bail out
	[[ -z "${f}" || -z "${CYDIA}" ]] && return
	cydia=(${CYDIA})

	# Cydia control fd version != 1: bail out
	[[ ${cydia[1]} -eq 1 ]] || return

	echo "finish:${f}" >&${cydia[0]}
}

if [[ `basename $0` == "extrainst_" ]]; then
	case "$1" in
	install )
		echo Removing
		finish restart
		;;
	upgrade )
		echo Removing
		finish return
		;;
	esac
elif [[ `basename $0` == "postrm" ]]; then
	# If this script is postrm, you need to do something a bit more complex:
	# postrm is called with remove, purge, upgrade, failed-upgrade, abort-install and abort-upgrade
	# You probably only want to act on remove and (as this is the actual removal phase.)
	case "$1" in
	remove )
		echo Removing
		finish restart
		;;
	purge )
		echo Purging
		finish return
		;;
	abort-install )
		echo Aborting install
		finish return
		;;
	upgrade )
		echo Upgrading
		finish restart
		;;
	abort-upgrade )
		echo Aborting upgrade
		finish return
		;;
	failed-upgrade )
		echo Failed upgrading
		finish return
		;;
	esac
fi

exit 0

To do: Explain how it fits into Debian packaging (how it interacts with apt/aptitude/dpkg/Cydia).

This should be looked at deeper. This is an implementation of communicating via file descriptors to Cydia from a C program int cydiaFd = (int)strtoul(getenv("CYDIA"), NULL, 10); write(cydiaFd, "finish:reboot", 13);

Troubleshooting

dpkg-deb

Infinite upgrade

Does Cydia seem to think a package on your repository has an available upgrade no matter what you do? Check the control file for that package - you might have an error in it, such as a duplicated line.