.. _macro_reference:

Macro reference
===============

Base git macros
---------------

Without any parameters, these macros work on repository level and use globally available repository information.

.. note::

    If your local repository is not properly initialized or if, for example, the ``.git`` metadata directory in your local tree
    has been renamed or removed, operation of the base macros can get out of the intended scope. It is therefore recommended to
    use more specific ``git_dir_*`` macros where possible, which are always bound to the directory where the input spec file is
    located. This is mainly relevant for ``git_pack`` and ``git_archive`` macros (see below).

Output of every git macro call is cached and other macros are made to take those cached values into account by default.
You can see that a macro uses a cached value as a default input parameter value by looking at its function header definition
and searching for the ``cached`` keyword.


    ``git_version [name="$(cached git_name)"] [lead=0] [follow=]``

Default value for name in this definition is derived from the cached output of the
previously invoked ``git_name`` macro. If ``git_name`` macro has not been invoked
or if its output was an empty string, the default value for the ``name=`` parameter
above will be also an empty string.

Note that ``$(cached_git_name_version)`` in the function header definitions below
is an alias for ``"$(cached git_name)-$(cached git_version)"``.

----

.. code-block:: sh

    git_name [name=] [prepend=] [append=]

Without any parameters, lookup remote URL for the currently active
branch and output its basename with ``.git`` suffix stripped. If the
remote URL could not be determined, use "origin" remote URL
instead.

    Optional arguments:
        :``name``:     the base name to be output
        :``prepend``:  string to be prepended to the base name
        :``append``:   string to be appended to the base name

----

.. _git_version:


.. code-block:: sh

    git_version [name="$(cached git_name)"] [lead=0] [follow=]

Output version of a subpackage given by ``${name}``. The version
is a string constructed of the following parts:

    ``${lead}.${follow}${commit_count_appendix}${wtree_appendix}``

    ``${lead}`` is a mandatory argument of the macro. By default it is set
    to zero.

    ``${follow}`` (if not specified) is obtained from the follow part of
    the latest tag made for the subpackage given by ``${name}``.

    ``${commit_count_appendix}`` is generated only if the current commit
    is not tagged for the given subpackage and it is composed of the
    following parts


        ``.git.<commit_count>.<latest_commit_short_hash>``

Commit count is a number of commits from the latest tag on the
given subpackage.

``${wtree_appendix}`` is generated only if the currently checked
out working tree is dirty. It is composed of the following parts:

    ``.wtree.<encoded_latest_file_status_change>``

    Optional arguments:
        :``name``:     name of a subpackage
        :``lead``:     major version substring
        :``follow``:   minor version substring, dynamically generated if not specified

    Environment variables:
        **VERSION_BUMP**: if set to a non-empty value, the following procedure is applied
        to get the version string:

        If ``${follow}`` is specified by user explicitly, return ``${lead}.${follow}``.

        Otherwise, extract ``${follow}`` from the latest tag as the last version component (after the last dot)
        and return ``${lead}.${follow}+1``. If ``${follow}`` is not a number, throw an error (manual setting of
        follow is needed).

        rpkg sets the ``VERSION_BUMP`` variable into the preprocessing environment during
        execution of ``rpkg tag`` subcommand. Otherwise, it is unset.

----

.. code-block:: sh

    git_vcs [subtree=]

Output pseudo repository URL pointing the currently checked out tree.

    Optional arguments:
        :``subtree``:     path to a subtree to generate the URL for

Example output:

    ``git+ssh://git@pagure.io/test-project.git#dadef2a8b9554e94797a7336261192e02d5d9351:``

----

.. code-block:: sh

    git_pack [path="$(git rev-parse --show-toplevel)"] [dir_name="$(cached_git_name_version)"]
             [source_name="$(cached_git_name_version).tar.gz"]

Pack the whole working tree content (including untracked files) into a gzipped source tarball and output ``${source_name}``, which is a filename of the created tarball.
Uses ``GNU tar`` to do the job. Files ignored by git as well as ``.git`` metadata directory will be excluded from the resulting tarball.

    Optional arguments:
        :``path``:         path to a specific subdirectory to be packed
        :``dir_name``:     top-level directory name in the created tarball
        :``source_name``:  filename of the created source tarball

    Enviroment variables:
        **OUTDIR**: if empty, ``git_pack`` will not generate any sources, only the source filename will be output

        rpkg sets ``OUTDIR``, only if the tarball is actually needed to be generated. It does not set it
        when ``rpkg spec`` is called (without any additional arguments).

----

.. code-block:: sh

    git_archive [path="$(git rev-parse --show-toplevel)"] [dir_name="$(cached_git_name_version)"]
                [source_name="$(cached_git_name_version).tar.gz"]

Pack the latest commit tree content into a gzipped source tarball and output ``${source_name}``, which is a filename of the created tarball.
Uses ``git archive`` to do the job. Note that this macro will refuse to generate a tarball if your working tree is dirty.

    Optional arguments:
        :``path``:   path to a specific subdirectory to be packed
        :``dir_name``:     top-level directory name in the created tarball
        :``source_name``:  filename of the created source tarball

    Enviroment variables:
        **OUTDIR**: if empty, ``git_archive`` will not generate any sources, only the source filename will be output

        rpkg sets ``OUTDIR``, only if the tarball is actually needed to be generated. It does not set it
        when ``rpkg spec`` is called (without any additional arguments).

----

.. code-block:: sh

    git_setup_macro [dir_name="$(cached_git_name_version)"]

Output ``%setup`` rpm macro for the given top-level source-tarball directory.

    Optional arguments:
        :``dir_name``:     name of the top-level directory in the source-tarball

----

.. code-block:: sh

    git_changelog [name="$(cached git_name)"] [since_tag=] [until_tag=]
                  [header_locale=POSIX] [header_date_format="%a %b %d %Y"] [body_wrap=80]

Output rpm spec changelog as generated from tag messages for the subpackage given by ``${name}``.

    Optional arguments:
        :``name``:                name of the subpackage to generate the changelog for
        :``since_tag``:           start the changelog records with this tag
        :``until_tag``:           end the changelog records with this tag
        :``header_locale``:       locale to be used when changelog record date is being generated
        :``header_date_format``:  date format to be used in the changelog record headers
        :``body_wrap``:           maximum allowed line length for changelog body

When ``rpkg tag`` is called, it allows you to specify a tag message. This is the message
that will be used as a changelog record body.


git_dir macros
--------------

These macros operate on a directory level. In particular, on a directory where the input spec file template is located. They are basically
aliases to the GIT BASE MACROS with some input values set specifically for the directory-level operation. The input spec template location is
given by ``INPUT_PATH`` environment variable set by rpkg. You can influence it from the command line by explicitly specifying ``--spec <template_path>``
argument for rpkg subcommands that support it.

Below you can see to what the GIT DIR macros expand. In some cases, the macro is a direct alias to the underlying git base macro.

----

.. code-block:: sh

    git_dir_name

        git_name append="-$(git -C "$(dirname "$INPUT_PATH")" rev-parse --show-prefix | path_to_name_suffix)"

Outputs repository origin URL basename appended with the path (after slash to dash substitution) from the repository
root to the spec file's directory.

----

.. code-block:: sh

    git_dir_version

        git_version


Direct alias.

----

.. code-block:: sh

    git_dir_vcs

        git_vcs subtree="$(git -C "$(dirname "$INPUT_PATH")" rev-parse --show-prefix)"

Outputs VCS pseudo URL pointing to the spec file's subdirectory.

----

.. code-block:: sh

    git_dir_pack

        git_pack path="$(dirname "$INPUT_PATH")"

Packs spec file's subdirectory by using ``GNU tar``.

----

.. code-block:: sh

    git_dir_archive

        git_archive path="$(dirname "$INPUT_PATH")"

Packs spec file's subdirectory by using ``git archive``.

----

.. code-block:: sh

    git_dir_setup_macro

        git_setup_macro

Direct alias.

----

.. code-block:: sh

    git_dir_changelog

        git_changelog

Direct alias.


git_cwd macros
--------------

These macros operate on a directory level. In particular, on a rpkg's working directory. Again, they are
aliases to the GIT BASE MACROS with some input values set specifically for the directory-level operation.

You can influence the rpkg's working dir from the command line by explicitly specifying its ``--path`` argument.

Below you can see to what the GIT_CWD macros expand. In some cases, the macro is a direct alias for the underlying git base macro.

----

.. code-block:: sh

    git_cwd_name

        git_name append="-$(git -C "$(pwd)" rev-parse --show-prefix | path_to_name_suffix)"

Outputs repository origin URL basename appended with the rpkg's working directory path (after slash to dash substitution).

----

.. code-block:: sh

    git_cwd_version

        git_version

Direct alias.

----

.. code-block:: sh

    git_cwd_vcs

        git_vcs subtree="$(git -C "$(pwd)" rev-parse --show-prefix)"


Outputs VCS pseudo URL pointing to the rpkg's working directory.

----

.. code-block:: sh

    git_cwd_pack

        git_pack path="$(pwd)"

Packs rpkg's working directory by using ``GNU tar``.

----

.. code-block:: sh

    git_cwd_archive

        git_archive path="$(pwd)"

Packs rpkg's working directory by using ``git archive``.

----

.. code-block:: sh

    git_cwd_setup_macro

        git_setup_macro

Direct alias.

----

.. code-block:: sh

    git_cwd_changelog

        git_changelog

Direct alias.

.. _user_defined_macros:

User-defined macros
-------------------

You can define your own rpkg macros that are basically just standard bash functions
read from ``rpkg.macros`` file placed in an rpkg's working directory. Standard output
of your custom macro will be captured and the ``{{{ <macro_name> }}}`` invocation
in an input spec file will be replaced with it.

Example of a custom macro placed in ``rpkg.macros`` file:

.. code-block:: sh

    function git_commits_no {
        total_commits="$(git rev-list --all --count)"
        echo -n "$total_commits"
    }

You can then use this macro in your spec file to e.g. specify ``Release`` tag value:

.. code-block:: spec

    Release: {{{ git_commits_no }}}

Calling ``rpkg spec`` will then produce a spec file with the following line in the content:

.. code-block:: spec

    Release: 267

supposing the total number of commits in your project is 267.

Instead of ``echo -n <output>``, you can also use ``output <output>`` command
which comes directly from rpkg's standard bash library. This command
will first cache the output value under ``<macro_name>`` key and only
afterwards, it will echo the value to stdout.

You can later access this value by ``cached <macro_name>``, which might
become handy, for example, if computing your output is computionally demanding
and you need to compute that same value more than once.

Example usage:

.. code-block:: sh

    function git_commits_no {
        total_commits="$(cached git_commits_no)"

        if [ -z "$total_commits" ]; then
            total_commits="$(git rev-list --all --count)"
        fi

        output "$total_commits"
    }

**Tips and tricks:**

To get proper bash highlighting in ``rpkg.macros`` in your favourite editor of choice,
you can put ``#!/bin/bash`` shebang at the beginning. Alternatively for vim, you can
use ``#<white>vim:syntax=sh`` directive where ``<white>`` can be a space or tab.