# 👥📤 Yseme

**A make·file for syncing.**

👥📤 Yseme is an implementation of the sync process described in my
  blogpost [<cite>C·I pipelines have you down? Why not ‹ touch
  .grass ›?!</cite>][touch_grass].
It is intended to be included in projects as a Git submodule, and
  recursively called from within another make·file.

**Note:**
👥📤 Yseme requires functionality present in G·N·U Make 3.81 (or
  later) and will not work in previous versions, or other
  implementations of Make.
Compatibility with later versions of G·N·U Make is assumed, but not
  tested.

## Nomenclature

<i>Yseme</i> combines two archaic English terms: <i>y‐</i> (indicating
  togetherness or wholeness) and <i>seme</i> (< Old Norse <i>sǿmr</i>,
  meaning “seemly”, “appropriate”, or “beautiful”).

## Basic Usage

`make dry-sync` will ensure that the current repository is clean,
  built, and up‐to‐date, and then perform a dry run (`--dry-run`) of
  R·Sync.
`make sync` will perform the same checks, then push any new commits and
  perform an actual run of R·Sync.

👥📤 Yseme is intended to be called recursively from with·in another
  make·file.
The following is a sample make·file which makes use of 👥📤 Yseme :⁠—

```make
SHELL = /bin/sh

# © 2024 Lady [@ Lady’s Computer].
#
# This Source Code Form is subject to the terms of the Mozilla Public License, v. 2.0.
# If a copy of the M·P·L was not distributed with this file, You can obtain one at <https://mozilla.org/MPL/2.0/>.

# Assume 👥📤 Yseme is a git submodule located at <.yseme> in the
# current directory.
YSEME := .yseme
YSEMEVARS := DESTDIR='public'

# Build script (substitute with your own).
build:
	if [ ! -d public ]; then mkdir public; fi
	echo 'Hello, world!' > public/index
	touch .grass

# Set up the 👥📤 Yseme submodule.
$(YSEME)/GNUmakefile:
	git submodule update --init $(YSEME)

# Reload this make·file if the 👥📤 Yseme make·file has changed.
# (Replace `GNUmakefile´ with whatever your make·file is called.)
#
# This is required to ensure the correct value of the `YSEME_TARGETS´ variable.
#
# See <https://www.gnu.org/software/make/manual/html_node/Remaking-Makefiles.html>.
GNUmakefile: $(YSEME)/GNUmakefile
	touch GNUmakefile

# Ensure the 👥📤 Yseme make·file exists before running the following commands.
ifneq ($(wildcard $(YSEME)/GNUmakefile),)
# Programmatically get the list of phony targets defined by 👥📤 Yseme.
# You can also list these manually (e·g `sync´, `dry-sync´).
YSEME_TARGETS := $(shell sed '/^\.PHONY[ :]/!d;/^\.PHONY[ :]/s/ *;.*//;/^\.PHONY[ :]/s/\.PHONY.*: *//' < $(YSEME)/GNUmakefile)

# For each target defined by 👥📤 Yseme, forward it appropriately.
$(YSEME_TARGETS):
	$(MAKE) -f $(YSEME)/GNUmakefile $@ $(YSEMEVARS)
endif
```

👥📤 Yseme was designed and tested with G·N·U Make 3.81.
It likely works with newer versions of Make, but may break in older
  versions.

## Setup and Configuration

👥📤 Yseme depends on the following programs to run.
In every case, you may supply your own implementation by overriding the
  corresponding (allcaps) variable (e·g, set `RSYNC` to supply your own
  `rsync` implementation).

- `awk`
- `echo`
- `git`
- `rsync` (version 3.0 or later)
- `sed`
- `test`

The following varibales provide general configuration :⁠—

- **`BUILDTARGET`:**
  A file whose timestamp is guaranteed to be updated on every build
    (default: `.grass`).
  👥📤 Yseme will compare the modified time of this file to the commit
    time of the latest commit to determine if the build is out·of·date.

- **`DESTDIR`:**
  The directory which contains the result of the build.
  `rsync` will be called from this directory.

The following variables configure Git :⁠—

- **`GITFORCE`:**
  If this variable has a value, the current branch does not need to be
    up·to·date with its remote counterpart and a force‐push will be
    used (default: empty).

- **`GITOPTS`:**
  Options to pass to Git (default: empty).

The following variables configuer R·Sync :⁠—

- **`CLIENTCHARSET`:**
  The character set of the local machine (default: `utf-8-mac`).
  If both this and `SERVERCHARSET` are set and not equal, an appropriate
    `--iconv` option will be added to the R·Sync call.

- **`RSYNCFILTER`:**
  The location (relative to the working directory) of an R·Sync filter
    file (default: `.rsync-filter` if such a file exists; otherwise,
    empty).

- **`RSYNCOPTS`:**
  Option to use when calling R·Sync.
  The following flags are set by default :⁠—
    `--checksum`, `--compress`, `--del`, `--links`, `--omit-dir-times`,
    `--prune-empty-dirs`, `--recursive`, `--times`, `--verbose`.
  Additional flags may be set depending on the values of variables and
    which target is being built (e·g `dry-sync` 🆚 `sync`).

- **`SERVER`:**
  The remote machine to sync to (default: `computer`).

- **`SERVERCHARSET`:**
  The character set of the remote machine (default: `utf-8`).
  If both this and `CLIENTCHARSET` are set and not equal, an appropriate
    `--iconv` option will be added to the R·Sync call.

- **`SERVERPATH`:**
  The path on the remote machine to sync to (default: the name of the
    current directory).

If you use a method of syncing your website other than `rsync`, you can
  still use 👥📤 Yseme:
Just define your own `sync` and `dry-sync` targets which depend on
 👥📤 Yseme’s `ensure-clean`, `ensure-branch-up-to-date`, and
 `ensure-build`.

[touch_grass]: <https://blog.ladys.computer/2023-05-06/touch_grass/> "C·I pipelines have you down? Why not ‹ touch .grass ›?!"
