Repository navigation
Expand file tree
/
Copy pathMakefile
More file actions
197 lines (163 loc) · 8.99 KB
/
Copy pathMakefile
File metadata and controls
197 lines (163 loc) · 8.99 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
.PHONY: bootstrap setup dist release docs samples test test-all coverage bench bench-quick bench-test
export PIPENV_VENV_IN_PROJECT=1
export PIPENV_CACHE_DIR ?= $(CURDIR)/.pipenv-cache
export PIP_CACHE_DIR ?= $(CURDIR)/.pip-cache
export all_proxy=
# No recipe below currently needs a bash-only feature -- the last one, brace
# expansion in the `isort:` target, went with #765's `find`-based fix (see
# that target and tests/project/test_isort_clean.py for why: a later revision
# of that same fix leaned on brace expansion plus a bash new enough for
# `shopt -s globstar`, which is a second, version-specific way bash-only
# reliance can go wrong beyond just needing bash at all). The pin stays
# anyway: one known shell to write recipes against, rather than whatever
# `/bin/sh` happens to be on a given machine, is worth keeping even with
# nothing bash-specific relying on it today, and it costs nothing to take
# from PATH rather than a fixed prefix, as Homebrew, Linuxbrew and system
# installs all put it somewhere different.
SHELL := $(shell command -v bash 2>/dev/null || echo /bin/bash)
VERSION = $(shell cat pcapkit/__init__.py | grep "^__version__" | sed "s/__version__ = '\(.*\)'/\1/")
# ``lxml`` needs libxml2/libxslt; on a brewed system they live under the brew
# prefix, which differs between macOS (/opt/homebrew, /usr/local) and Linuxbrew.
BREW ?= $(shell command -v brew 2>/dev/null)
ifneq ($(BREW),)
BREW_PREFIX ?= $(shell $(BREW) --prefix)/opt
else
BREW_PREFIX ?= /opt/homebrew/opt
endif
LIBXML2_PREFIX := $(BREW_PREFIX)/libxml2
LIBXSLT_PREFIX := $(BREW_PREFIX)/libxslt
ifneq ($(wildcard $(LIBXML2_PREFIX)/bin/xml2-config),)
export PATH := $(LIBXML2_PREFIX)/bin:$(PATH)
export CPPFLAGS := -I$(LIBXML2_PREFIX)/include $(CPPFLAGS)
export LDFLAGS := -L$(LIBXML2_PREFIX)/lib $(LDFLAGS)
export PKG_CONFIG_PATH := $(LIBXML2_PREFIX)/lib/pkgconfig:$(PKG_CONFIG_PATH)
export XML2_CONFIG := $(LIBXML2_PREFIX)/bin/xml2-config
endif
ifneq ($(wildcard $(LIBXSLT_PREFIX)/bin/xslt-config),)
export PATH := $(LIBXSLT_PREFIX)/bin:$(PATH)
export CPPFLAGS := -I$(LIBXSLT_PREFIX)/include $(CPPFLAGS)
export LDFLAGS := -L$(LIBXSLT_PREFIX)/lib $(LDFLAGS)
export PKG_CONFIG_PATH := $(LIBXSLT_PREFIX)/lib/pkgconfig:$(PKG_CONFIG_PATH)
export XSLT_CONFIG := $(LIBXSLT_PREFIX)/bin/xslt-config
endif
bootstrap: pipenv
setup: pipenv
update: pipenv vendor
dist: update isort dist-clean dist-build dist-upload
dist-clean:
mkdir -p sdist eggs wheels
[ -d dist ] && find dist -iname '*.egg' -exec mv {} eggs \; || true
[ -d dist ] && find dist -iname '*.whl' -exec mv {} wheels \; || true
[ -d dist ] && find dist -iname '*.tar.gz' -exec mv {} sdist \; || true
dist-build:
pipenv run python -m build
dist-upload:
pipenv run twine check dist/*
pipenv run twine upload dist/* -r pypi --skip-existing
pipenv run twine upload dist/* -r testpypi --skip-existing
git-tag:
git tag --sign "v$(VERSION)"
git push --tags
pipenv:
pipenv install --skip-lock --dev
vendor:
pipenv run pcapkit-vendor
# Sample captures under examples/captures/ are not tracked (see .gitignore);
# regenerate the ones the runtime, regression and integration tests read.
samples:
pipenv run python examples/generators/make_samples.py
# Mirrors the selection run by .github/workflows/unit-tests.yml, i.e. the tests
# that need no sample captures beyond the committed ones.
test:
pipenv run python -m pytest -q --ignore=tests/integration --ignore-glob='*_runtime.py' --ignore-glob='*_regression.py'
# Everything, including the fixture-dependent runtime/regression/integration tests.
test-all: samples
pipenv run python -m pytest -q
coverage: samples
pipenv run coverage run -m pytest -q
pipenv run coverage report
# The engine speed table in docs/source/index.rst -- every supported Python
# version, one image each, measured in containers so the host does not affect the
# result. Needs docker, and nothing else: deliberately not run through pipenv,
# since the whole point is that the measuring environments are the pinned ones
# inside the images rather than whatever is installed here.
#
# Expect around two hours at the defaults: five interpreters, seven environments,
# and almost all of the measuring time is pyshark, which spawns a tshark process
# per extraction. Cut it with --engines, --pythons, or --quick.
bench:
examples/benchmark/run.sh
# A smoke check that the harness works end to end, not a measurement -- two
# interpreters and the two cheapest engines, which is enough to exercise both
# virtualenvs, the matrix loop and both emitted tables. The full matrix at --quick
# would still build five images, and building is most of a quick run's cost.
bench-quick:
examples/benchmark/run.sh --quick --pythons 3.11,3.12 --engines default,dpkt
# The harness's own tests: ratio arithmetic, environment stitching, the per-version
# grid, and that the emitted reStructuredText parses under plain docutils. No
# docker needed.
bench-test:
pipenv run python -m pytest -q examples/benchmark/test_harness.py
docs:
PCAPKIT_SPHINX=1 pipenv run $(MAKE) -C docs html
docs-clean:
PCAPKIT_SPHINX=1 pipenv run $(MAKE) -C docs clean
docs-autobuild:
PCAPKIT_SPHINX=1 SPHINXOPTS="--watch ../pcapkit" pipenv run $(MAKE) -C docs livehtml
isort:
pipenv run isort -l100 -ppcapkit --skip-glob '**/__init__.py' pcapkit $(wildcard temp/sort.py)
pipenv run isort -l100 -ppcapkit $$(find pcapkit/const -mindepth 2 -name '*.py')
pipenv run isort -l100 -ppcapkit $$(find pcapkit/vendor -mindepth 2 -name '*.py')
pipenv run isort -l100 -ppcapkit util/*.py examples/generators/*.py
# The command prefix that puts the lint tools on PATH. Locally that is pipenv, as
# everywhere else in this file. The lint workflow installs the tools into the
# job's own interpreter instead and overrides this to empty (`make pylint RUN=`),
# which is the whole point of the variable: CI runs these recipes rather than
# restating their flags, so there is exactly one definition of each tool's flag
# set and "clean locally, red in CI" cannot start from the two drifting apart.
RUN ?= pipenv run
# Flag sets are variables rather than literals for the same reason -- `vermin`
# needs two recipes (see below) and would otherwise carry two copies of its
# flags. Note the `pcapkit` before the flags as well as after: that is how this
# recipe has always read, and vermin de-duplicates the paths (it reports 496
# files analyzed either way), so it is preserved verbatim rather than tidied.
VERMIN_FLAGS = --backport argparse --backport enum --backport importlib --backport ipaddress --backport typing --backport typing_extensions --no-parse-comments --eval-annotations -vv
# `pylint.extensions.emptystring` no longer exists (#767): the check it provided,
# `compare-to-empty-string`, was folded into the core `refactoring` checker at
# pylint 3.0 as `use-implicit-booleaness-not-comparison-to-string` (C1804), with
# `compare-to-empty-string` kept only as a message alias -- no plugin load needed
# any more (confirmed: it fires the same with or without the dead plugin
# reference, so it was never actually gated by it), so the entry is dropped
# rather than the check. `old-division`, `no-absolute-import` and
# `input-builtin` are dropped because pylint has genuinely removed them.
# `eq-without-hash` is dropped for a different reason: the extension module
# that still ships that check (`pylint.extensions.eq_without_hash`, `W1641`)
# was simply never named in `--load-plugins=`, so `--disable=eq-without-hash`
# was as unrecognised as if it had been removed -- same spurious Command-line
# message, not the same cause. See .github/workflows/lint.yml's header for
# the full account.
PYLINT_FLAGS = --load-plugins=pylint.extensions.check_elif,pylint.extensions.docstyle,pylint.extensions.overlapping_exceptions --disable=all --enable=F,E,W,R,basic,classes,format,imports,refactoring,else_if_used,docstyle,use-implicit-booleaness-not-comparison-to-string,overlapping-except --disable=blacklisted-name,invalid-name,missing-class-docstring,missing-function-docstring,missing-module-docstring,design,too-many-lines,too-many-nested-blocks,broad-except,singleton-comparison,ungrouped-imports --max-line-length=120 --init-import=yes
MYPY_FLAGS = --follow-imports=silent --ignore-missing-imports --show-column-numbers --show-error-codes
BANDIT_FLAGS = -r
vermin:
mkdir -p temp
$(RUN) vermin pcapkit $(VERMIN_FLAGS) pcapkit > temp/vermin.txt
command -v code >/dev/null && code temp/vermin.txt || cat temp/vermin.txt
# What CI runs. The `vermin` target above redirects into temp/ and then hands the
# file to an editor, so its exit status is the editor's (or `cat`'s) and a run
# that found violations still succeeds -- fine at a desk, useless as a check.
# This one writes to stdout and lets vermin's failure propagate, which is what
# `targets = 3.6` in vermin.ini is for: vermin exits non-zero when the target is
# not met, and the code's real floor is 3.11.
vermin-ci:
$(RUN) vermin pcapkit $(VERMIN_FLAGS) pcapkit
pylint:
$(RUN) pylint $(PYLINT_FLAGS) pcapkit
mypy:
$(RUN) mypy $(MYPY_FLAGS) pcapkit
bandit:
$(RUN) bandit $(BANDIT_FLAGS) pcapkit
profile:
$(MAKE) -C test profile
mypy-types:
pipenv run mypy --install-types