.. _spec_templates_from_scratch:

Spec templates from scratch

To setup the test environment, run the following commands:


    mkdir test-project
    cd test-project
    cat > simple-template.spec.rpkg <<EOF
    Name:       {{{ git_dir_name }}}
    Version:    {{{ git_dir_version }}}
    Release:    1%{?dist}
    Summary:    This is a test package.

    License:    GPLv2+
    URL:        https://someurl.org
    VCS:        {{{ git_dir_vcs }}}

    Source: {{{ git_dir_pack }}}

    This is a test package.

    {{{ git_dir_setup_macro }}}

    {{{ git_dir_changelog }}}
    git init

Those commands will create a local git repository called `test-project`
containing our first spec template called ``simple-template.spec.rpkg``.

We can now try to invoke ``rpkg`` to generate a real spec file from the template:


    $ rpkg spec
    git_dir_name: Could not get remote URL.
    git_dir_name failed with value 2

...well, not so fast :).

Remote URL for the current branch should be set first and that's
because the ``git_dir_name`` macro determines the value of package name
from that URL.

For testing purposes, we can set it up by running:


    git remote add origin ssh://git@pagure.io/test-project.git
    git config --add branch.master.remote origin

Note that we don't really need `pagure.io/test-project.git` project
to exist publicly for the following parts to work. We only need the
local Git repository variables to be set appropriately to our needs.

Let's try again:


    $ rpkg spec
    Wrote: /tmp/rpkg/simple-template-2-ck20yI/simple-template.spec

VoilĂ ! You can see that the real spec was generated into a directory under
``/tmp/rpkg``, which is a default output path. Name of the directory is
derived from the name of the spec file and count (plus one) of already
existing directories under ``/tmp/rpkg`` for that particular spec file name.
There is also a dynamic suffix appended to ensure  directory name uniqueness.
A new directory is created for each new .spec generating operation.


    $ cat /tmp/rpkg/simple-template-2-ck20yI/simple-template.spec
    Name:       test-project
    Version:    0.0.wtree.zf4r62
    Release:    1%{?dist}
    Summary:    This is a test package.

    License:    GPLv2+
    URL:        https://someurl.org
    VCS:        git+ssh://git@pagure.io/test-project.git#HEAD:

    Source: test-project-0.0.wtree.zf4r62.tar.gz

    This is a test package.

    %setup -q -n test-project-0.0.wtree.zf4r62


In the resulting spec file, you can also see that the ``Version:`` field value is ``0.0``
followed by a curious ``.wtree.zf4r62`` suffix. The fact that the suffix is present
means that our working tree is dirty. The ``zf4r62`` substring encodes the time of
the latest uncommitted file status change.

You can also notice that the same suffix is present in the ``Source`` filename
as well as in the parameter given to ``%setup -n`` macro. That's because the output
of ``git_dir_version`` is remembered and the subsequent rpkg macro invocations
may use it as part of their own output value.

The ``.wtree.*`` suffix will disappear once we make our first commit (see below).
The version will stay at ``0.0``, however, and it will be incremented later to
``0.1`` when we make our first tag.

Now let's make the first commit in our test project and see what happens:


    git add simple-template.spec.rpkg
    git commit -m 'first commit'

Viewing the commit:


    $ git log --oneline
    dadef2a (HEAD -> master) first commit

Regenerating the spec file:


    rpkg spec

Finally getting:

.. code-block:: spec

    Name:       test-project
    Version:    0.0.git.1.dadef2a
    Release:    1%{?dist}
    Summary:    This is a test package.

    License:    GPLv2+
    URL:        https://someurl.org
    VCS:        git+ssh://git@pagure.io/test-project.git#dadef2a8b9554e94797a7336261192e02d5d9351:

    Source: test-project-0.0.git.1.dadef2a.tar.gz

    This is a test package.

    %setup -q -n test-project-0.0.git.1.dadef2a


You can see that the ``.wtree.*`` suffix was replaced by ``.git.1.dadef2a``.
This suffix is based on the latest commit in the currently checked out branch.
The number ``1`` is given by number of commits from the latest git tag created
for our ``test-project`` package or from the repository initialization if no
such tag exists yet (our case).

The ``dadef2a`` part is the first seven characters of the full commit hash and you can
use this short hash to checkout the commit:


    git checkout dadef2a

This is not useful at the moment because we have just made the commit and we have it checked
out already in our repository but it becomes useful when you build a source rpm from the
generated spec file.

That's because the value in the spec file's version field gets propagated into the built srpm name,
which means that if you store that srpm somewhere and you will later come back to it, you will
know from which commit it was built and what it contains consequently.

Now let's examine how tagging works with ``rpkg`` because tagging becomes actually very handy
when your application reaches a certain stable (feature-complete) state that you would like
to share with people. We will need to assume that we have already reached that state after
just the first commit in our test-project :) (which is very rare).


    rpkg tag

First thing that happens is that an editor window pops up where you can edit a tag message:


    - first commit
    # Write a changelog for tag:
    #   test-project-0.1-1
    # Lines starting with '#' will be ignored.

The intial content of the tag message gets populated from the first lines
of all commit messages since the last tag. Because we don't have any existing
tag before this one, commit messages since the repository initialization are
collected and used to populate the initial message content.

You can keep this pre-generated tag message as it is, edit it in any way,
or just delete it and write your own stuff but note that this message
constitutes the basic information about our application release (and what
have changed since the previous realease), so it is quite important.

After you are finally satisfied with your message, you can save
the content and close the editor. The new tag will be generated:


    $ rpkg tag
    Wrote: /tmp/rpkg/simple-template-4-7Rh6hh/simple-template.spec
    Created tag: test-project-0.1-1
    Wrote: /tmp/rpkg/simple-template-4-7Rh6hh/simple-template.spec

You might wonder about the same two lines ``Wrote: /tmp/rpkg/simple-template-4-7Rh6hh/simple-template.spec``.
The first line is there because the tag name is derived from the `Name:`, `Version:`,
and `Release:` field values in the generated spec file. The second line is there
because the spec needs to be regenerated after the tag creation so that it contains
the latest changelog record.

.. note::

    `EXPERT INFO:` When tagging takes place, ``rpkg`` sets a special variable ``VERSION_BUMP``
    into the spec preprocessing environment. ``git_dir_version`` macro is aware of this variable
    and if it is set, an incremented version value is generated. This incremented value
    then gets carried over into the tag name together with the package name and release.

Let's view the final spec file now:


    $ cat /tmp/rpkg/simple-template-4-7Rh6hh/simple-template.spec
    Name:       test-project
    Version:    0.1
    Release:    1%{?dist}
    Summary:    This is a test package.

    License:    GPLv2+
    URL:        https://someurl.org
    VCS:        git+ssh://git@pagure.io/test-project.git#dadef2a8b9554e94797a7336261192e02d5d9351:

    Source: test-project-0.1.tar.gz

    This is a test package.

    %setup -q -n test-project-0.1

    * Wed Mar 07 2018 clime <clime@fedoraproject.org> 0.1-1
    - first commit

You can see that no dynamic version suffix has been generated into the
``Version:`` field this time.  This happens every time the currently
checked out commit is a tagged one.

The reason is that if you know a tag name, you can just
directly pass it to ``git checkout``:


    $ git checkout test-project-0.1

and you will get back to the respective commit for which
the tag was created.

You can also see that the changelog has been automatically generated
for us based on the currently existing tags and their content.

If you don't like this and you prefer editing your changelog messages
directly in the source spec file instead of having them generated from tags,
no problem. Just don't use the ``git_dir_changelog`` macro and instead do your
edits directly in the spec file template. Any normal text (not enclosed in
``{{{``, ``}}}`` brace triplets) will be copied verbatim into the resulting
spec file.

If you like the ``git_dir_changelog`` macro but you don't have every single
changelog message stored in a tag, you can configure it to generate
changelog entries only since a certain point in history by specifying its
``since_tag`` parameter (e.g. ``git_dir_changelog since_tag=test-project-0.1-1``).

There are plenty of parameters also for the other macros to give you that
same freedom you experience when you are dealing with just plain spec files.

For example, you can increment the major version number (the first number in
the version string) by setting ``lead`` parameter of ``git_dir_version``:

.. code-block:: spec

    Name:       {{{ git_dir_name }}}
    Version:    {{{ git_dir_version lead=1 }}}
    Release:    1%{?dist}

For our project this will now generate something like:

.. code-block:: spec

    Name:       test-project
    Version:    1.0.wtree.zf4657
    Release:    1%{?dist}

The ``.wtree.*`` suffix is telling us that our working tree
is dirty again after adding ``lead=1`` and not commiting yet.

Read more about the macros and their parameters in :ref:`macro_reference`.

And of course, you can fallback to using the plain spec
files (without any rpkg macros) at any time, although
you will lose the advantage of the certain spec parts
being generated automatically for you.

So far, we have only seen generating spec from a template
but what if we want to generate a whole source package.

We can do that with ``rpkg srpm``:


    $ rpkg srpm
    git_dir_pack: packing path /home/clime/test-project
    git_dir_pack: Wrote: /tmp/rpkg/simple-template-5-H5AuzX/test-project-1.0.wtree.zgwsnr.tar.gz
    Wrote: /tmp/rpkg/simple-template-5-H5AuzX/simple-template.spec
    Wrote: /tmp/rpkg/simple-template-5-H5AuzX/test-project-1.0.wtree.zgwsnr-1.fc27.src.rpm

Now, actually we don't usually want to build an srpm from a dirty
tree because srpm is something, which eventually gets built into
a final installable rpm package.

It should be always possible to track that rpm package back to a
particular commit in a git history, so that you can look at the
exact sources it was built from. This becomes impossible if we build
an srpm from a dirty tree. It might be still useful for local development,

So let's reset to the latest commit (which is also a tagged one) and
continue from there:


    $ git reset --hard test-project-0.1-1
    HEAD is now at dadef2a first commit
    $ rpkg srpm
    git_dir_pack: packing path /home/clime/test-project
    git_dir_pack: Wrote: /tmp/rpkg/simple-template-6-gtzDQX/test-project-0.1.tar.gz
    Wrote: /tmp/rpkg/simple-template-6-gtzDQX/simple-template.spec
    Wrote: /tmp/rpkg/simple-template-6-gtzDQX/test-project-0.1-1.fc27.src.rpm

Three files were created. The spec (you can see the relevant
log message on the second line). The tarball that packs all our application
sources for the current commit (on the first line). And the source rpm that
bundles the generated spec file and the tarball and can be used for building
an rpm installation package (the third line).

Note that the names of the tarball and of the source srpm match the tag name
of the currently checked out commit as they should.

You can generate just a spec and a tarball with ``rpkg spec --sources``


    $ rpkg spec --sources
    git_dir_pack: packing path /home/clime/test-project
    git_dir_pack: Wrote: /tmp/rpkg/simple-template-7-b9rah4/test-project-0.1.tar.gz
    Wrote: /tmp/rpkg/simple-template-7-b9rah4/simple-template.spec

In the previous examples, we could see that ``git_dir_pack`` macro
generates the source tarball only when needed (e.g. when calling
``rpkg srpm``) or when explicitly asked to do it (``rpkg spec --sources``).

This is a useful optimization.

By the way, there is also ``git_dir_archive`` rpkg macro (which uses
``git archive`` command instead of ``tar`` to do the packing), which behaves
the same way in this regard. With this macro, however, all your changes
need to be committed before you can generate a tarball or a source rpm.

In this tutorial, we have learned:

- how to create a simple spec file template
- how to generate a real rpm spec from the template
- how the spec is automatically following git history
- how to tag a commit and create release notes
- how to generate a source tarball and even source rpm