Skip to content

Commit

Permalink
Merge branch 'template'
Browse files Browse the repository at this point in the history
  • Loading branch information
liskin committed Jun 16, 2024
2 parents a4f4f2f + d0f13c6 commit a9e45f1
Show file tree
Hide file tree
Showing 8 changed files with 223 additions and 37 deletions.
2 changes: 1 addition & 1 deletion .github/workflows/check.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -133,7 +133,7 @@ jobs:
apt update
apt install -t unstable -y python3-flake8
fi
- name: Workaround for https://github.com/actions/checkout/pull/762 not persisting
- name: Workaround for https://github.com/actions/checkout/issues/1169
run: git config --global --add safe.directory "$PWD"
- name: Install remaining dependencies
run: make venv-system-site-packages
Expand Down
67 changes: 67 additions & 0 deletions CONTRIBUTING.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,67 @@
# Contributing to strava-offline

## Development

Obtain the source code:

$ git clone https://github.com/liskin/strava-offline

Setup Python virtual env and install missing dependencies:

$ make

Make changes using your preferred editor.

Then invoke lints, tests, …:

$ make check

These checks are also invoked in [CI (GitHub Actions)][ci] (against multiple
Python versions and also using different Linux distributions Python packages)
whenever a branch is pushed or a pull request is opened. You may need to
enable Actions in your fork's settings.

Other common tasks are available in the [Makefile](Makefile):

<!-- include tests/readme/make-help.md -->
<!--
$ cd "$TESTDIR"/../..
$ function make {
> command make --no-print-directory COLUMNS=120 "$@" 2>/dev/null
> }
-->

$ make help
venv-system-site-packages: Setup ./.venv/ (--system-site-packages)
venv: Setup ./.venv/
pipx: Install locally using pipx
pipx-site-packages: Install locally using pipx (--system-site-packages)
check: Invoke all checks (lints, tests, readme)
lint: Invoke lints
lint-flake8:
lint-mypy:
lint-isort:
test: Invoke tests
test-pytest:
test-prysk:
readme: Update usage/examples in *.md and fail if it differs from version control
dist: Build distribution artifacts (tar, wheel)
twine-upload: Release to PyPI
ipython: Invoke IPython in venv (not installed by default)
clean: Clean all gitignored files/directories
template-update: Re-render cookiecutter template into the template branch
template-merge: Re-render cookiecutter template and merge into the current branch
check-wheel: Check that the wheel we build works in a completely empty venv (i.e. check for unspecified dependencies)
help: Display this help
<!-- end include tests/readme/make-help.md -->

[ci]: https://github.com/liskin/strava-offline/actions

## Style Guidelines

* Try to follow the existing style (where it's not already enforced by a
linter). This applies to both code and git commits.

* Familiarise yourself with [the seven rules of a great Git commit
message](https://cbea.ms/git-commit/#seven-rules).
42 changes: 32 additions & 10 deletions Makefile
Original file line number Diff line number Diff line change
Expand Up @@ -13,55 +13,63 @@ VENV_WHEEL_PYTHON = $(VENV_WHEEL)/bin/python
PACKAGE := $(shell sed -ne '/^name / { y/-/_/; s/^.*=\s*"\(.*\)"/\1/p }' pyproject.toml)

TEMPLATES_DIR = $(HOME)/src
TEMPLATE := $(shell realpath --relative-to=. $(TEMPLATES_DIR)/cookiecutter-python-cli)
TEMPLATE = $(eval TEMPLATE := $$(shell realpath --relative-to=. $$(TEMPLATES_DIR)/cookiecutter-python-cli))$(TEMPLATE)

.PHONY: venv-system-site-packages
## Setup ./.venv/ (--system-site-packages)
venv-system-site-packages:
$(MAKE) VENV_USE_SYSTEM_SITE_PACKAGES=1 venv

.PHONY: venv
## Setup ./.venv/
venv: $(VENV_DONE)

.PHONY: pipx
## Install locally using pipx
pipx:
pipx install --editable .

.PHONY: pipx-site-packages
## Install locally using pipx (--system-site-packages)
pipx-site-packages:
pipx install --system-site-packages --editable .

.PHONY: check
## Invoke all checks (lints, tests, readme)
check: lint test readme

.PHONY: lint
## Invoke lints
lint: lint-flake8 lint-mypy lint-isort

LINT_SOURCES = src/ tests/

.PHONY: lint-flake8
##
lint-flake8: $(VENV_DONE)
$(VENV_PYTHON) -m flake8 $(LINT_SOURCES)

.PHONY: lint-mypy
##
lint-mypy: $(VENV_DONE)
$(VENV_PYTHON) -m mypy --show-column-numbers $(LINT_SOURCES)

.PHONY: lint-isort
##
lint-isort: $(VENV_DONE)
$(VENV_PYTHON) -m isort --check $(LINT_SOURCES)

.PHONY: test
## Invoke tests
test: test-pytest test-prysk

.PHONY: test-pytest
##
test-pytest: $(VENV_DONE)
$(VENV_PYTHON) -m pytest $(PYTEST_FLAGS) tests/

.PHONY: readme
readme: README.md
git diff --exit-code $^

.PHONY: test-prysk
##
test-prysk: PRYSK_INTERACTIVE=$(shell [ -t 0 ] && echo --interactive)
test-prysk: $(VENV_DONE)
PATH="$(CURDIR)/$(VENV)/bin:$$PATH" \
Expand All @@ -70,37 +78,49 @@ test-prysk: $(VENV_DONE)
$(VENV_PYTHON) -m prysk --indent=4 --shell=/bin/bash $(PRYSK_INTERACTIVE) \
$(wildcard tests/*.md tests/*/*.md tests/*/*/*.md)

.PHONY: README.md
README.md: test-prysk
tests/include.py < $@ > $@.tmp
mv -f $@.tmp $@
.PHONY: readme
## Update usage/examples in *.md and fail if it differs from version control
readme: $(wildcard *.md)
git diff --exit-code $^

.PHONY: $(wildcard *.md)
$(wildcard *.md): $(VENV_DONE) test-prysk
$(VENV_PYTHON) tests/include-preproc.py --comment-start="<!-- " --comment-end=" -->" $@

.PHONY: dist
## Build distribution artifacts (tar, wheel)
dist: $(VENV_DONE)
rm -rf dist/
$(VENV_PYTHON) -m build --outdir dist

.PHONY: twine-upload
## Release to PyPI
twine-upload: dist
$(VENV_PYTHON) -m twine upload $(wildcard dist/*)

.PHONY: ipython
## Invoke IPython in venv (not installed by default)
ipython: $(VENV_DONE)
$(VENV_PYTHON) -m IPython

.PHONY: clean
## Clean all gitignored files/directories
clean:
git clean -ffdX

.PHONY: template-update
## Re-render cookiecutter template into the template branch
template-update:
$(TEMPLATE)/update.sh -t $(TEMPLATE) -p . -b template -i .cookiecutter.json

.PHONY: template-merge
## Re-render cookiecutter template and merge into the current branch
template-merge: template-update
git merge template

.PHONY: check-wheel
## Check that the wheel we build works in a completely empty venv
## (i.e. check for unspecified dependencies)
check-wheel: dist
$(PYTHON) -m venv --clear --without-pip $(VENV_WHEEL)
cd $(VENV_WHEEL) && $(PYTHON) -m pip --isolated download pip
Expand All @@ -121,7 +141,7 @@ endef
# workaround for https://bugs.debian.org/cgi-bin/bugreport.cgi?bug=1003252 and/or https://github.com/pypa/pip/issues/6264
ifneq ($(VENV_USE_SYSTEM_SITE_PACKAGES),)
ifneq ($(shell test -f /etc/debian_version && python3 -c 'import sys; exit(not(sys.version_info < (3, 10)))' && echo x),)
$(info XXX: using SETUPTOOLS_USE_DISTUTILS=stdlib workaround)
$(warning XXX: using SETUPTOOLS_USE_DISTUTILS=stdlib workaround)

Check failure on line 144 in Makefile

View workflow job for this annotation

GitHub Actions / check-distro (debian:oldstable)

XXX: using SETUPTOOLS_USE_DISTUTILS=stdlib workaround

Check failure on line 144 in Makefile

View workflow job for this annotation

GitHub Actions / check-distro (debian:oldstable)

XXX: using SETUPTOOLS_USE_DISTUTILS=stdlib workaround

Check failure on line 144 in Makefile

View workflow job for this annotation

GitHub Actions / check-distro (debian:oldstable)

XXX: using SETUPTOOLS_USE_DISTUTILS=stdlib workaround

Check failure on line 144 in Makefile

View workflow job for this annotation

GitHub Actions / check-distro (debian:oldstable)

XXX: using SETUPTOOLS_USE_DISTUTILS=stdlib workaround

Check failure on line 144 in Makefile

View workflow job for this annotation

GitHub Actions / check-distro (debian:oldstable)

XXX: using SETUPTOOLS_USE_DISTUTILS=stdlib workaround

Check failure on line 144 in Makefile

View workflow job for this annotation

GitHub Actions / check-distro (debian:oldstable)

XXX: using SETUPTOOLS_USE_DISTUTILS=stdlib workaround
$(VENV_DONE): export SETUPTOOLS_USE_DISTUTILS := stdlib
endif
endif
Expand All @@ -130,3 +150,5 @@ $(VENV_DONE): $(MAKEFILE_LIST) pyproject.toml
$(if $(VENV_USE_SYSTEM_SITE_PACKAGES),$(VENV_CREATE_SYSTEM_SITE_PACKAGES),$(VENV_CREATE))
$(VENV_PYTHON) -m pip install -e $(VENV_PIP_INSTALL)
touch $@

include _help.mk
29 changes: 24 additions & 5 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -120,7 +120,7 @@ pip install strava-offline
--config FILE Read configuration from FILE. [default:
/home/user/.config/strava_offline/config.yaml]
--help Show this message and exit.
<!-- end include -->
<!-- end include tests/readme/help.md -->

### Mirror activities as GPX

Expand Down Expand Up @@ -160,7 +160,7 @@ least once to let strava-offline reuse these downloaded files.
--config FILE Read configuration from FILE. [default: /ho
me/user/.config/strava_offline/config.yaml]
--help Show this message and exit.
<!-- end include -->
<!-- end include tests/readme/help-gpx.md -->

### Reports

Expand All @@ -169,7 +169,7 @@ least once to let strava-offline reuse these downloaded files.
report-bikes Show all-time report by bike
report-yearly Show yearly report by activity type
report-yearly-bikes Show yearly report by bike
<!-- end include -->
<!-- end include tests/readme/help-report.md -->

```
$ strava-offline report-yearly 2020
Expand Down Expand Up @@ -225,7 +225,7 @@ Sample config file can be generated using the `--config-sample` flag:

# '_strava4_session' cookie value
strava_cookie_strava4_session: TEXT
<!-- end include -->
<!-- end include tests/readme/config-sample.md -->

### Note about incremental synchronization

Expand All @@ -243,7 +243,26 @@ API supports webhooks so that a service can subscribe to be notified of new
activities and changes to existing activities, but `strava-offline` is not a
web service, it's a local tool, so it can't do that.)

## Donations (♥ = €)
## Contributing

### Code

We welcome bug fixes, (reasonable) new features, documentation improvements,
and more. Submit these as GitHub pull requests. Use GitHub issues to report
bugs and discuss non-trivial code improvements; alternatively, get in touch
via [IRC/Matrix/Fediverse](https://work.lisk.in/contact/).

See [CONTRIBUTING.md](CONTRIBUTING.md) for more details about the code base
(including running tests locally).

Note that this project was born out of a desire to solve a problem I was
facing. While I'm excited to share it with the world, keep in mind that I'll
be prioritizing features and bug fixes that align with my personal use cases.
There may be times when I'm busy with other commitments and replies to
contributions might be delayed, or even occasionally missed. Progress may come
in bursts. Adjust your expectations accordingly.

### Donations (♥ = €)

If you like this tool and wish to support its development and maintenance,
please consider [a small donation](https://www.paypal.me/lisknisi/10EUR) or
Expand Down
15 changes: 15 additions & 0 deletions _help.mk
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
# orig src: https://github.com/liskin/dotfiles/blob/home/_help.mk

.PHONY: help
## Display this help
help: COLUMNS=$(shell tput cols)
help:
@$(MAKE) --silent help-src \
| perl -Mfeature=say -MText::Wrap -0777 -ne 'while(/((?:^##(?:| .*)$$(?#)\n)+)(^.*:)/gm) { my ($$t, $$h) = ($$2, $$1); $$h =~ s/^## ?//gm; $$h =~ s/\s+/ /g; $$h =~ s/^\s+|\s+$$//g; say "$$t $$h"; }' | fmt $(if $(COLUMNS),-$(COLUMNS)) -t

.PHONY: help-src
help-src: help-src-makefiles

.PHONY: help-src-makefiles
help-src-makefiles:
@cat $(MAKEFILE_LIST)
54 changes: 54 additions & 0 deletions tests/include-preproc.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,54 @@
#!/usr/bin/env python3

# orig src: https://github.com/liskin/dotfiles/blob/home/bin/liskin-include-preproc.py

from __future__ import annotations # python 3.8 compat

from dataclasses import dataclass
from pathlib import Path
import re

import click


@dataclass
class Subst:
comment_start: str
comment_end: str

def include(self, m: re.Match[str]) -> str:
filename = m[1]

content = self.includes(Path(filename).expanduser().read_text())
nl = "\n" if not content.endswith("\n") else ""

cs = self.comment_start
ce = self.comment_end
return f"{cs}include {filename}{ce}\n{content}{nl}{cs}end include {filename}{ce}"

def includes(self, s: str) -> str:
cs = re.escape(self.comment_start)
ce = re.escape(self.comment_end)
regex = f"^{cs}include (\\S+){ce}$.*?^{cs}end include \\1{ce}$"
return re.sub(regex, self.include, s, flags=re.DOTALL | re.MULTILINE)


@click.command(context_settings={"show_default": True})
@click.option("--comment-start", type=str, default="## ")
@click.option("--comment-end", type=str, default="")
@click.argument("filename", type=click.Path(exists=True, allow_dash=True))
def main(comment_start, comment_end, filename):
"""
Simple preprocessor for including files in one another.
Substitution is done in-place: the input file is modified and directives are retained so it can
serve as an input again.
"""
with click.open_file(filename, "r") as f:
input = f.read()
output = Subst(comment_start=comment_start, comment_end=comment_end).includes(input)
with click.open_file(filename, "w", atomic=True) as f:
f.write(output)


if __name__ == "__main__":
main()
21 changes: 0 additions & 21 deletions tests/include.py

This file was deleted.

Loading

0 comments on commit a9e45f1

Please sign in to comment.