/git-annex-configure

Declarative git-annex configuration with Guile Scheme

Primary LanguageSchemeGNU General Public License v3.0GPL-3.0

git-annex-configure

Table of Contents

  1. Introduction
  2. Installation
  3. Using git-annex-configure
    1. Limitations
    2. Examples
    3. Specification
  4. Hacking git-annex-configure
    1. Testing your changes
    2. Running the test suites

Introduction

git-annex-configure is a git-annex addon command that enables declarative configuration of git-annex repositories using Guile Scheme. With a few limitations, you can apply settings for all of your repositories with a config file and a single execution of git-annex-configure.

Installation

git-annex-configure is likely not available in your package manager’s repositories at the moment, but feel free to open an issue if this statement becomes inaccurate.

If you have GNU Guix, this repository comes with a package definition in guix.scm that you can use for installation. After cloning this repository, the following can be run in the directory where guix.scm is located to install it to your default profile:

guix package --install-from-file=guix.scm

Using git-annex-configure

To apply a configuration, simply run something like this:

git-annex configure /path/to/config/file

The configuration file should be located inside a git-annex repository, otherwise git-annex-configure will not know what repository it should operate on.

Limitations

Most settings can be set from a single repository and then propagated via syncing to other repositories, which is what git-annex-configure takes advantage of. However, some settings are not propagated (i.e. can only be done when on the same machine), and thus have to be applied on a repository-by-repository basis:

  • Remotes (including git-annex special remotes).
  • Git config (not including git-annex config).
  • Hooks.

git-annex-configure will only apply configurations of this nature for the repository that it is executed on, if any such configurations exist.

Examples

Here is a fairly basic setup with two client repositories:

(use-modules
 (git-annex-configure git remote))

(configuration
 (annex-config `(("annex.largefiles"
                  . ,(string-join
                      (list "exclude=.annex.scm"
                            "exclude=.gitignore"
                            "exclude=*/.gitignore")
                      " and "))
                 ("annex.dotfiles"
                  . "true")))
 (repositories
  (list
   (repository-configuration
    (uuid "repository-1-uuid")
    (description "repository 1!")
    (groups
     (list "client"))
    (wanted "standard")
    (remotes
     (list (remote "repository-2" "/path/to/repository-2"))))
   (repository-configuration
    (uuid "repository-2-uuid")
    (description "repository 2!")
    (groups
     (list "client"))
    (wanted "standard")
    (remotes
     (list (remote "repository-1" "/path/to/repository-1")))))))

For comparison, the above configuration would be equivalent to the following script:

git-annex config --set annex.largefiles \
          "exclude=.annex.scm and exclude=.gitignore and exclude=*/.gitignore"
git-annex config --set annex.dotfiles true
git-annex describe "repository-1-uuid" "repository 1!"
git-annex group "repository-1-uuid" client
git-annex wanted "repository-1-uuid" standard
git-annex describe "repository-2-uuid" "repository 2!"
git-annex group "repository-2-uuid" client
git-annex wanted "repository-2-uuid" standard

if [ $(git config annex.uuid) = repository-1-uuid ]; then
    git remote add repository-2 /path/to/repository-2
elif [ $(git config annex.uuid) = repository-2-uuid ]; then
    git remote add repository-1 /path/to/repository-1
fi

Specification

In addition to the above examples, this section gives one more example with comments describing the full configuration specification at a high level for easy reference of what settings exist and how to apply them. If you would like a lower-level reference, you might find it useful to start by examining spec.scm, which is where the configuration record definitions are located.

With the exception of repository UUIDs (if any repository-configuration is specified) - which are not modified, but used as identifiers - all settings are optional and may be omitted.

Omitted settings will not be touched, so existing settings may coexist with settings specified for git-annex-configure. Otherwise, expect that any specified setting will have its corresponding setting in the repository be modified or overwritten.

;; use-modules may be needed for certain procedures to be available.
(use-modules
 ;; included for use of `remote' constructor.
 (git-annex-configure git remote)

 ;; included for use of `borg-remote' constructor.
 (git-annex-configure git annex remotes))

;; This is the configuration record where all settings will be specified.
;; git-annex-configure expects the configuration file to evaluate to some
;; value constructed from `configuration'.
(configuration

 ;; git-annex config settings. Value should be an alist of setting names to
 ;; setting values.
 (annex-config '(("config-key" . "config-value")
                 ("other-config-key" . "other-config-value")))

 ;; git-annex groupwanted setting. Value should be an alist of group names to
 ;; matchexpressions.
 (groupwanted '(("group1" . "group1 wanted matchexpression")
                ("group2" . "group2 wanted matchexpression")))

 ;; repository configurations. Value should be a list of repository
 ;; configurations, each made via `repository-configuration'.
 (repositories
  (list
   (repository-configuration

    ;; git-annex repository UUID string. Obtained via `git config
    ;; annex.uuid'. Required to correctly identify repositories that will be
    ;; configured.
    (uuid "repository-uuid")

    ;; Boolean telling git-annex-configure whether this repository
    ;; configuration is to be ignored when applying configurations.
    (disabled? #t)

    ;; git-annex description string.
    (description "example description")

    ;; git-annex wanted matchexpression string.
    (wanted "wanted matchexpression")

    ;; git-annex required matchexpression string.
    (required "required matchexpression")

    ;; git-annex groups. Value should be a list of groups.
    (groups
     (list "group1"
           "group2"))

    ;; The rest of the configurations that can be specified with
    ;; repository-configuration (described below) can only apply if
    ;; git-annex-configure is executed on this repository with the same UUID
    ;; due to limitations mentioned in this README.

    ;; git remotes and git-annex special remotes. Value should be a list of
    ;; remotes. All possible remote types are listed below.
    (remotes
     (list
      ;; Normal git remote. Made using the `(remote name url)' procedure,
      ;; where name is a string specifying the remote name, and url is a
      ;; string specifying the remote url.
      (remote "remote2-name" "remote2-url")

      ;; Borg special remote. Made with the procedure
      ;; `(borg-remote name #:borgrepo borgrepo #:subdir subdir
      ;; #:appendonly? appendonly)', where name is the borg remote name and
      ;; the rest are key arguments corresponding to the options in the borg
      ;; special remote documentation:
      ;; https://git-annex.branchable.com/special_remotes/borg/
      (borg-remote "borg-remote-name"
                   #:borgrepo "borg repository url"
                   #:subdir "borg repo subdir"
                   #:appendonly? #t)))

    ;; git config. Value should be an alist of config keys to config values,
    ;; where keys and values must be strings.
    (config '(("config1-key" . "config1-value")
              ("config2-key" . "config2-value")))

    ;; git hooks. Value should be an alist of hook script name strings to
    ;; quoted Guile expressions. A hook file script will be created with the
    ;; corresponding Guile expression inserted, which will then be executed
    ;; whenever the hook is called. Note that git-annex-configure does not
    ;; prevent you from overwriting other hook files, so be aware of what
    ;; hooks might already be used by git-annex.
    (hooks '(("hook1-name"
              . (begin
                  (display "the (begin ...) is required if...\n")
                  (display "...you want more than one expression")))
             ("hook2-name"
              . (begin
                  (display "do stuff")))))))))

Hacking git-annex-configure

This project’s infrastructure and development is managed primarily using Guix.

In the project root directory, run the following to enter an environment with all the necessary dependencies:

guix shell

Testing your changes

When you want to test your changes, you can run the following to build git-annex-configure and enter an environment with it included:

guix shell -f guix.scm

If you already have git-annex-configure installed, you should run the following instead to avoid using modules from the currently installed version:

guix shell --container -f guix.scm

Running the test suites

Tests exist in ./tests, however they are fairly basic at the moment and lack instructions for ease of use due to a recent re-organization of the project structure.