Skip to content

Commit a9e45f1

Browse files
committed
Merge branch 'template'
2 parents a4f4f2f + d0f13c6 commit a9e45f1

File tree

8 files changed

+223
-37
lines changed

8 files changed

+223
-37
lines changed

.github/workflows/check.yaml

+1-1
Original file line numberDiff line numberDiff line change
@@ -133,7 +133,7 @@ jobs:
133133
apt update
134134
apt install -t unstable -y python3-flake8
135135
fi
136-
- name: Workaround for https://github.com/actions/checkout/pull/762 not persisting
136+
- name: Workaround for https://github.com/actions/checkout/issues/1169
137137
run: git config --global --add safe.directory "$PWD"
138138
- name: Install remaining dependencies
139139
run: make venv-system-site-packages

CONTRIBUTING.md

+67
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,67 @@
1+
# Contributing to strava-offline
2+
3+
## Development
4+
5+
Obtain the source code:
6+
7+
$ git clone https://github.com/liskin/strava-offline
8+
9+
Setup Python virtual env and install missing dependencies:
10+
11+
$ make
12+
13+
Make changes using your preferred editor.
14+
15+
Then invoke lints, tests, …:
16+
17+
$ make check
18+
19+
These checks are also invoked in [CI (GitHub Actions)][ci] (against multiple
20+
Python versions and also using different Linux distributions Python packages)
21+
whenever a branch is pushed or a pull request is opened. You may need to
22+
enable Actions in your fork's settings.
23+
24+
Other common tasks are available in the [Makefile](Makefile):
25+
26+
<!-- include tests/readme/make-help.md -->
27+
<!--
28+
$ cd "$TESTDIR"/../..
29+
30+
$ function make {
31+
> command make --no-print-directory COLUMNS=120 "$@" 2>/dev/null
32+
> }
33+
-->
34+
35+
$ make help
36+
venv-system-site-packages: Setup ./.venv/ (--system-site-packages)
37+
venv: Setup ./.venv/
38+
pipx: Install locally using pipx
39+
pipx-site-packages: Install locally using pipx (--system-site-packages)
40+
check: Invoke all checks (lints, tests, readme)
41+
lint: Invoke lints
42+
lint-flake8:
43+
lint-mypy:
44+
lint-isort:
45+
test: Invoke tests
46+
test-pytest:
47+
test-prysk:
48+
readme: Update usage/examples in *.md and fail if it differs from version control
49+
dist: Build distribution artifacts (tar, wheel)
50+
twine-upload: Release to PyPI
51+
ipython: Invoke IPython in venv (not installed by default)
52+
clean: Clean all gitignored files/directories
53+
template-update: Re-render cookiecutter template into the template branch
54+
template-merge: Re-render cookiecutter template and merge into the current branch
55+
check-wheel: Check that the wheel we build works in a completely empty venv (i.e. check for unspecified dependencies)
56+
help: Display this help
57+
<!-- end include tests/readme/make-help.md -->
58+
59+
[ci]: https://github.com/liskin/strava-offline/actions
60+
61+
## Style Guidelines
62+
63+
* Try to follow the existing style (where it's not already enforced by a
64+
linter). This applies to both code and git commits.
65+
66+
* Familiarise yourself with [the seven rules of a great Git commit
67+
message](https://cbea.ms/git-commit/#seven-rules).

Makefile

+32-10
Original file line numberDiff line numberDiff line change
@@ -13,55 +13,63 @@ VENV_WHEEL_PYTHON = $(VENV_WHEEL)/bin/python
1313
PACKAGE := $(shell sed -ne '/^name / { y/-/_/; s/^.*=\s*"\(.*\)"/\1/p }' pyproject.toml)
1414

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

1818
.PHONY: venv-system-site-packages
19+
## Setup ./.venv/ (--system-site-packages)
1920
venv-system-site-packages:
2021
$(MAKE) VENV_USE_SYSTEM_SITE_PACKAGES=1 venv
2122

2223
.PHONY: venv
24+
## Setup ./.venv/
2325
venv: $(VENV_DONE)
2426

2527
.PHONY: pipx
28+
## Install locally using pipx
2629
pipx:
2730
pipx install --editable .
2831

2932
.PHONY: pipx-site-packages
33+
## Install locally using pipx (--system-site-packages)
3034
pipx-site-packages:
3135
pipx install --system-site-packages --editable .
3236

3337
.PHONY: check
38+
## Invoke all checks (lints, tests, readme)
3439
check: lint test readme
3540

3641
.PHONY: lint
42+
## Invoke lints
3743
lint: lint-flake8 lint-mypy lint-isort
3844

3945
LINT_SOURCES = src/ tests/
4046

4147
.PHONY: lint-flake8
48+
##
4249
lint-flake8: $(VENV_DONE)
4350
$(VENV_PYTHON) -m flake8 $(LINT_SOURCES)
4451

4552
.PHONY: lint-mypy
53+
##
4654
lint-mypy: $(VENV_DONE)
4755
$(VENV_PYTHON) -m mypy --show-column-numbers $(LINT_SOURCES)
4856

4957
.PHONY: lint-isort
58+
##
5059
lint-isort: $(VENV_DONE)
5160
$(VENV_PYTHON) -m isort --check $(LINT_SOURCES)
5261

5362
.PHONY: test
63+
## Invoke tests
5464
test: test-pytest test-prysk
5565

5666
.PHONY: test-pytest
67+
##
5768
test-pytest: $(VENV_DONE)
5869
$(VENV_PYTHON) -m pytest $(PYTEST_FLAGS) tests/
5970

60-
.PHONY: readme
61-
readme: README.md
62-
git diff --exit-code $^
63-
6471
.PHONY: test-prysk
72+
##
6573
test-prysk: PRYSK_INTERACTIVE=$(shell [ -t 0 ] && echo --interactive)
6674
test-prysk: $(VENV_DONE)
6775
PATH="$(CURDIR)/$(VENV)/bin:$$PATH" \
@@ -70,37 +78,49 @@ test-prysk: $(VENV_DONE)
7078
$(VENV_PYTHON) -m prysk --indent=4 --shell=/bin/bash $(PRYSK_INTERACTIVE) \
7179
$(wildcard tests/*.md tests/*/*.md tests/*/*/*.md)
7280

73-
.PHONY: README.md
74-
README.md: test-prysk
75-
tests/include.py < $@ > $@.tmp
76-
mv -f $@.tmp $@
81+
.PHONY: readme
82+
## Update usage/examples in *.md and fail if it differs from version control
83+
readme: $(wildcard *.md)
84+
git diff --exit-code $^
85+
86+
.PHONY: $(wildcard *.md)
87+
$(wildcard *.md): $(VENV_DONE) test-prysk
88+
$(VENV_PYTHON) tests/include-preproc.py --comment-start="<!-- " --comment-end=" -->" $@
7789

7890
.PHONY: dist
91+
## Build distribution artifacts (tar, wheel)
7992
dist: $(VENV_DONE)
8093
rm -rf dist/
8194
$(VENV_PYTHON) -m build --outdir dist
8295

8396
.PHONY: twine-upload
97+
## Release to PyPI
8498
twine-upload: dist
8599
$(VENV_PYTHON) -m twine upload $(wildcard dist/*)
86100

87101
.PHONY: ipython
102+
## Invoke IPython in venv (not installed by default)
88103
ipython: $(VENV_DONE)
89104
$(VENV_PYTHON) -m IPython
90105

91106
.PHONY: clean
107+
## Clean all gitignored files/directories
92108
clean:
93109
git clean -ffdX
94110

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

99116
.PHONY: template-merge
117+
## Re-render cookiecutter template and merge into the current branch
100118
template-merge: template-update
101119
git merge template
102120

103121
.PHONY: check-wheel
122+
## Check that the wheel we build works in a completely empty venv
123+
## (i.e. check for unspecified dependencies)
104124
check-wheel: dist
105125
$(PYTHON) -m venv --clear --without-pip $(VENV_WHEEL)
106126
cd $(VENV_WHEEL) && $(PYTHON) -m pip --isolated download pip
@@ -121,7 +141,7 @@ endef
121141
# workaround for https://bugs.debian.org/cgi-bin/bugreport.cgi?bug=1003252 and/or https://github.com/pypa/pip/issues/6264
122142
ifneq ($(VENV_USE_SYSTEM_SITE_PACKAGES),)
123143
ifneq ($(shell test -f /etc/debian_version && python3 -c 'import sys; exit(not(sys.version_info < (3, 10)))' && echo x),)
124-
$(info XXX: using SETUPTOOLS_USE_DISTUTILS=stdlib workaround)
144+
$(warning XXX: using SETUPTOOLS_USE_DISTUTILS=stdlib workaround)
125145
$(VENV_DONE): export SETUPTOOLS_USE_DISTUTILS := stdlib
126146
endif
127147
endif
@@ -130,3 +150,5 @@ $(VENV_DONE): $(MAKEFILE_LIST) pyproject.toml
130150
$(if $(VENV_USE_SYSTEM_SITE_PACKAGES),$(VENV_CREATE_SYSTEM_SITE_PACKAGES),$(VENV_CREATE))
131151
$(VENV_PYTHON) -m pip install -e $(VENV_PIP_INSTALL)
132152
touch $@
153+
154+
include _help.mk

README.md

+24-5
Original file line numberDiff line numberDiff line change
@@ -120,7 +120,7 @@ pip install strava-offline
120120
--config FILE Read configuration from FILE. [default:
121121
/home/user/.config/strava_offline/config.yaml]
122122
--help Show this message and exit.
123-
<!-- end include -->
123+
<!-- end include tests/readme/help.md -->
124124

125125
### Mirror activities as GPX
126126

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

165165
### Reports
166166

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

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

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

230230
### Note about incremental synchronization
231231

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

246-
## Donations (♥ = €)
246+
## Contributing
247+
248+
### Code
249+
250+
We welcome bug fixes, (reasonable) new features, documentation improvements,
251+
and more. Submit these as GitHub pull requests. Use GitHub issues to report
252+
bugs and discuss non-trivial code improvements; alternatively, get in touch
253+
via [IRC/Matrix/Fediverse](https://work.lisk.in/contact/).
254+
255+
See [CONTRIBUTING.md](CONTRIBUTING.md) for more details about the code base
256+
(including running tests locally).
257+
258+
Note that this project was born out of a desire to solve a problem I was
259+
facing. While I'm excited to share it with the world, keep in mind that I'll
260+
be prioritizing features and bug fixes that align with my personal use cases.
261+
There may be times when I'm busy with other commitments and replies to
262+
contributions might be delayed, or even occasionally missed. Progress may come
263+
in bursts. Adjust your expectations accordingly.
264+
265+
### Donations (♥ = €)
247266

248267
If you like this tool and wish to support its development and maintenance,
249268
please consider [a small donation](https://www.paypal.me/lisknisi/10EUR) or

_help.mk

+15
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,15 @@
1+
# orig src: https://github.com/liskin/dotfiles/blob/home/_help.mk
2+
3+
.PHONY: help
4+
## Display this help
5+
help: COLUMNS=$(shell tput cols)
6+
help:
7+
@$(MAKE) --silent help-src \
8+
| 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
9+
10+
.PHONY: help-src
11+
help-src: help-src-makefiles
12+
13+
.PHONY: help-src-makefiles
14+
help-src-makefiles:
15+
@cat $(MAKEFILE_LIST)

tests/include-preproc.py

+54
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,54 @@
1+
#!/usr/bin/env python3
2+
3+
# orig src: https://github.com/liskin/dotfiles/blob/home/bin/liskin-include-preproc.py
4+
5+
from __future__ import annotations # python 3.8 compat
6+
7+
from dataclasses import dataclass
8+
from pathlib import Path
9+
import re
10+
11+
import click
12+
13+
14+
@dataclass
15+
class Subst:
16+
comment_start: str
17+
comment_end: str
18+
19+
def include(self, m: re.Match[str]) -> str:
20+
filename = m[1]
21+
22+
content = self.includes(Path(filename).expanduser().read_text())
23+
nl = "\n" if not content.endswith("\n") else ""
24+
25+
cs = self.comment_start
26+
ce = self.comment_end
27+
return f"{cs}include {filename}{ce}\n{content}{nl}{cs}end include {filename}{ce}"
28+
29+
def includes(self, s: str) -> str:
30+
cs = re.escape(self.comment_start)
31+
ce = re.escape(self.comment_end)
32+
regex = f"^{cs}include (\\S+){ce}$.*?^{cs}end include \\1{ce}$"
33+
return re.sub(regex, self.include, s, flags=re.DOTALL | re.MULTILINE)
34+
35+
36+
@click.command(context_settings={"show_default": True})
37+
@click.option("--comment-start", type=str, default="## ")
38+
@click.option("--comment-end", type=str, default="")
39+
@click.argument("filename", type=click.Path(exists=True, allow_dash=True))
40+
def main(comment_start, comment_end, filename):
41+
"""
42+
Simple preprocessor for including files in one another.
43+
Substitution is done in-place: the input file is modified and directives are retained so it can
44+
serve as an input again.
45+
"""
46+
with click.open_file(filename, "r") as f:
47+
input = f.read()
48+
output = Subst(comment_start=comment_start, comment_end=comment_end).includes(input)
49+
with click.open_file(filename, "w", atomic=True) as f:
50+
f.write(output)
51+
52+
53+
if __name__ == "__main__":
54+
main()

tests/include.py

-21
This file was deleted.

0 commit comments

Comments
 (0)