= 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, Upload a downstream release to an 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. 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.
2. Create a file _~/.devscripts_ with contents like:

       DEBSIGN_KEYID=E2EA41DCE2F8A99AD17A1E463A67D5D966D15C5C
       DEBEMAIL="leamas.alec@gmail.com"
       DEBFULLNAME="Alec Leamas"
+
Of course, all values here are personal.
DEBSIGN_KEYID is the secret key verified above.
This key is only required when uploading source packages to an ubuntu
PPA.
[#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 three branches:


    $ mkdir OpenCPN
    $ cd OpenCPN
    $ git clone --origin upstream  https://github.com/OpenCPN/OpenCPN.git
    $ cd OpenCPN
    $ git fetch upstream upstream/latest:upstream/latest
    $ git fetch upstream pristine-tar:pristine-tar
    $ git fetch upstream ubuntu/numbat:ubuntu/numbat
    $ git checkout ubuntu/numbat

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

To update an existing clone:

    $ git fetch upstream upstream/latest:upstream/latest
    $ git fetch upstream pristine-tar:pristine-tar
    $ git checkout ubuntu/numbat
    $ git pull upstream ubuntu/numbat


[#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`

`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".

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

   $ gbp import-orig ../opencpn_5.9.3~beta3+dfsg.orig.tar.xz

=== Push upstream changes

Final step is to push these changes:

   $ 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. 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>>
6. Commit all changes.
7. Finalize the changelog entry using `dch -r`.
8. Commit the change in _debian/changelog_
9. 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. Clone and checkout all branches, or update existing clone.
   See <<create-clone, above>>.
3. Make sure the repo is synchronized: `git clean -fxd; git checkout .`
4. Create the upstream source tarball: `gbp export-orig`
5. Create the source package: `debuild --no-lintian -S`
6.  List all available source packages using `ls -lt ../*source.changes`.
7. 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)
```

[#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
    
[#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`
