= Creating a Debian/Ubuntu package

NOTE: This is provisionary docs, these things are far from stable.
You have been warned!

== General

This page describes how to create .deb packages usable on Debian
based distros like vanilla Debian, Ubuntu, Raspbian, Mint, etc.

Work is done on a Debian or Ubuntu host.
Uploading an ubuntu  package must be done from an Ubuntu host.

Here are five main tasks:

  - <<import-version,Importing new opencpn releases into the packaging
    branches>>.
  - <<src-release, Creating a new downstream release>>.
  - <<publish, Publish an existing  downstream release to a Ubuntu PPA>>
  - <<test-build, Local test build of the package from existing release>>
  - <<master-build, Local test build of the package from master>>

Here, the term "downstream release" refers to a release based on the
same opencpn release but where the packaging has been modified.

There is also some support tasks, see the right panel.

[#setup]
== Setting up the environment


1. Create a file _~/.devscripts_ with contents like:
+
       DEBEMAIL="leamas.alec@gmail.com"
       DEBFULLNAME="Alec Leamas"
+
Values here are of course personal.

[#install-tools]
3. Install development tools

    $ sudo apt install devscripts git-buildpackage equivs


[#create-clone]
== Make a fresh OpenCPN clone.

The Debian tools creates things in the parent directory. To handle this,
create  new, empty directory and put the OpenCPN tree there. Then,
get all necessary branches:


    $ mkdir OpenCPN
    $ cd OpenCPN
    $ git clone --origin upstream  https://github.com/OpenCPN/OpenCPN.git
    $ cd OpenCPN
    $ git fetch upstream ubuntu/numbat:ubuntu/numbat
    $ git checkout ubuntu/numbat
    $ git checkout .; git clean -fxd
    $ gbp pull upstream

`ubuntu/numbat` is the branch to use when building Ubuntu Numbat (24.04)
packages.
Alternatives includes  `ubuntu/jammy` and `debian/sid`.
The latter builds packages for the rolling Sid distribution.

To update an existing clone:

    $ git checkout ubuntu/numbat
    $ gbp pull upstream

[#import-version]
== Import a new opencpn version into packaging branches.

=== Initiate the changelog with a new version

_debian/changelog_ is picky about the format. Editing by hand is hard. Instead,
use the `dch` tool. It has a multitude of options.In preparation of importing a
new version, first update *debian/changelog* with a new version, something like
`dch -v 1:5.9.3-beta3+dfsg-1~bpo24.04+1`

`dch` throws you in an editor loaded with _debian/changelog_.
Complete the entry as you consider best.
The standard message for a new version is "New upstream Release". 
Commit the update using a like 
`git commit -am "d/chnangelog: provisionary 1:5.9.3-beta3+dfsg-1~bpo24.04+1"`
The entry is, as stated in the commit message, provisionary at this point.

=== Import a release tag into upstream/latest

Create an archive based on a tag.
Using the tag v5.9.3-beta3 as example:

    $ git archive --prefix opencpn-5.9.3-beta3/ --output ../opencpn.tar.gz v5.9.3-beta3

The `--prefix` part should be modified to reflect current version, but is not
critical. Note the trailing slash!

Next step is to convert the tarball to a formal debian source tarball. This
is about renaming and stripping files not used  in the Debian build. Do:

    $ git checkout ubuntu/numbat.
    $ mk-origtargz ../opencpn.tar.gz

Where _../opencpn.tar.gz_  is the file created by `git archive` above. This
creates something like  _../opencpn_.5.10.920.orig.tar.gz_. The version in
the filename is taken from debian/changelog.

`ubuntu/numbat` is just an example,
see Make a fresh clone <<create-clone, above>>.

Nest step is to import this tarball into upstream/latest. Using the
tarball created by git-archive above do:

    $ git clean -fxd; git checkout .
    $ gbp import-orig ../opencpn_5.9.3~beta3+dfsg.orig.tar.xz


=== Push upstream changes

Final step is to push these changes. 
Updates the `pristine-tar` and `upstream/latest` branches and a new tag like 
`upstream/5.12.2+dfsg`

   $ gbp push


[#src-release]
== Create a downstream release

Assuming the new upstream (opencpn) release is available as of <<import-version,
above>> creating a downstream release goes like:

1. Initiate the environment as described <<setup, above>>.
2. Clone and checkout all branches, see <<create-clone, above>>.

For each release do:

1. Checkout the actual branch like ubuntu/jammy.
   Work on ubuntu branches must be done on an ubuntu host
2. Create a provisional version entry in _debian/changelog_ using 
   something like `dch -v 1:5.10.2+dfsg-1ubuntu1~bpo20.04+2`.
3. Create a orig.tar.xz tarball in .. using `gbp export-orig`.
4. Merge upstream changes using `gbp import-ref -u5.9.3-beta3`. 
   The -u argument is the last part of an upstream tag like 
   `upstream/5.9.3-beta3`.
5. Rebase possible patches to new version, see
   <<rebase-patches, Rebase patches>> below
6. Do possible changes in the new release.
   Note that only files in the _debian/_ directory can be modified;
   changes in other files are handled using patches in _debian/patches_.
   See Modifying Sources <<edit-src,below>>
7. Commit all changes.
8. Finalize the changelog entry using `dch -r`.
9. Commit the change in _debian/changelog_
10. Push the actual branch, for example `git push upstream ubuntu/jammy`

[#publish]
== Publish existing downstream release to PPA

1. Initiate the environment as described <<setup, above>>.
2. Creating releases requires a working gpg secret key including the
   password is available.
   Verify using something like
   `gpg --export-secret-keys E2EA41DCE2F8A99AD17A1E463A67D5D966D15C5C`.
   This key must be registered on the PPA about the be used. Make key
   being used by default by adding
+
```
  DEBSIGN_KEYID=E2EA41DCE2F8A99AD17A1E463A67D5D966D15C5C
```
+
to *~/.devscripts*

3. Clone and checkout all branches, or update existing clone.
   See <<create-clone, above>>.
4. Optionally, mark the package as released by you:
+
```
  $ dch -r    # complete changelog entry in editor
  $ git add debian/changelog
  $ git commit -m "<changelog version>"
```
5. Make sure the repo is clean: `git clean -fxd; git checkout .`
6. Create the upstream source tarball: `gbp export-orig`
7. Create the source package: `debuild --no-lintian -d -S -sa`. 
This uses the default key defined in *~/.devscripts*. 
+
Or use an explicit key; `debuild --no-lintian -d -S -sa -kE2EA41DCE2F8A99AD17A1E463A67D5D966D15C5` 
8. List all available source packages using `ls -lt ../*source.changes`. Push the 
   most recent package to a PPA using something like:
+
```
  $ dput ppa:leamas-alec/opencpn \
       ../opencpn_5.9.4~beta4+dfsg-1ubuntu1~bpo24.04+1_source.changes
```
Or, a more generic oneliner pushing the most recent _source.changes_ file:
+
```
  $ dput ppa:leamas-alec/opencpn $(ls -t ../*source.changes | head -1)
```
9. Tag the published  release using a tag name like 
   *ppa/5.12.2+dfsg-1-bpo20.04+2*

[#test-build]
== Local test build from existing upstream tag.

First step is to setup the environment, see <<setup, above>>.
However, no gpg key is required.

Then, create a fresh clone as described <<create-clone, above>>.

Install build dependencies:

    $ mk-build-deps
    $ sudo dpkg -i *deb     # Expect error messages, ignore them
    $ sudo apt install -f
    $ git clean -fxd

List available upstream tags using `git tag -l | grep upstream/`.
Normally use the most recent one like:

    $ git clean -fxd; git checkout .
    $ gbp buildpackage --git-upstream-tag=upstream/whatever -us -uc

This builds testable .deb packages in _.._.

[#master-build]
== Local test build from master
First step is to setup the environment, see <<setup, above>>.
However, no gpg key is required.

Make sure the build dependencies are in place, see <<test-build, above>>

Work is done in a clean clone of the master branch.
Make sure the remote "upstream" exists and update it:

    $ git config remote.upstream.url > /dev/null || \
         git remote add upstream https://github.com/OpenCPN/OpenCPN.git
    $ git remote update upstream

Checkout  the debian/ directory from the packaging branch. At the time of
writing, this is only possible for Bookworm:

    $ git fetch upstream ci/bookworm-backports:ci/bookworm-backports
    $ git checkout ci/bookworm-backports debian
    $ git commit -m "Add debian/ packaging directory from ci/bookworm-backports"

Create a debian changelog entry. This is an example of building a post 5.10 package
for the bookworm release, YMMV:

    $ version="1:5.11.0~$(date "+%Y%m%d%H%m").$(git rev-parse --short HEAD)-1"
    $ dch --distribution bookworm -v "$version" "Test build from master"
    $ git add debian/changelog
    $ git commit -m "d/changelog: $version"

Create orig tarball.
The name of the orig tarball created by `mk-origtargz` reflects the changelog 
version.

    $ git archive --prefix opencpn-5.11.0/ --output ../opencpn.tar.gz HEAD
    $ mk-origtargz ../opencpn.tar.gz

Extract the orig tarball and work in the sources it provides:

    $ cd ..
    $ tar xf opencpn-5.11.0*orig*xz
    $ cd opencpn-5.11.0*

And build package. -j4 builds in  four parallel pipes, depending on processor
you might want to use another value (I typically use -j12).

    $  debuild -us -uc -j4

[#rebase-patches]
== Rebase patches to current release.

Rebasing patches could be more or less complicated. The canned workflow which
works in most cases:

    $ gbp pq import --force --time-machine=7
    $ git rebase ubuntu/numbat   #  Packaging  branch we work in
    $ gbp pg export 
    $ git add debian/patches
    $ git commit -m "d/patches: rebased"

Check that all is ok -- if this works the patches are rebased:

    $ gbp pq import --force; gbp pq drop

If this still does not work the patches need to be applied "by hand" using
`patch -p1` and eventually updated. Seldom required.


[#edit-src]
== Modifying sources in a downstream release.

One cannot change the opencpn sources when creating a release.
However, it is possible to add or modify a patch in _debian/patches_.
These patches are applied when building the opencpn package.

The basic workflow starts in a fresh, clean clone and goes like

    $ gbp pq import --force
    #     All the patches in debian/patches are applied.
    #     Edit sources as desired and do:
    $ git commit -am "Reason for this change"
    $ gbp pq export
    $ git add debian/patches/*
    $ git commit -m "d/patches: new patch: patch description"

After `gbp pq import` actually all sorts of changes can be done.
As usual, several small changes can and should be committed one
by one rather than as a big patch.

It is also possible to edit existing patches using the standard
git tools, in particular `git rebase -i`












