From a57595b58f28d7e77019f0b6120545fa87e3f8e0 Mon Sep 17 00:00:00 2001 From: Zachary Vance Date: Mon, 24 Mar 2025 20:13:55 -0400 Subject: [PATCH 1/7] Add release checklist for my own benefit --- Makefile | 2 +- docs/RELEASE_CHECKLIST | 21 ++++++++++++++++----- 2 files changed, 17 insertions(+), 6 deletions(-) diff --git a/Makefile b/Makefile index 26f0fbf..66bdc39 100644 --- a/Makefile +++ b/Makefile @@ -23,7 +23,7 @@ dist/qr-backup-${VERSION}.tar.gz: docs font src tests Makefile qr-backup require rm -f $@ gzip -9 dist/qr-backup-${VERSION}.tar dist/qr-backup-${VERSION}.tar.gz.sig: dist/qr-backup-${VERSION}.tar.gz - gpg --detach-sign --armor -o $@ $< + gpg --local-user 4F92E819BBDB4225ABE690437DA2C1641594B27F --detach-sign --armor -o $@ $< deb: dist/qr-backup-${VERSION}.tar.gz mkdir -p dist/debian cp dist/qr-backup-${VERSION}.tar.gz dist/debian/qr-backup_${VERSION}.orig.tar.gz diff --git a/docs/RELEASE_CHECKLIST b/docs/RELEASE_CHECKLIST index 17bfc8d..324eaac 100644 --- a/docs/RELEASE_CHECKLIST +++ b/docs/RELEASE_CHECKLIST @@ -1,12 +1,23 @@ 1. Make sure tests are currently passing 2. If needed, update example.png, MAN.txt, and qr-backup.1.man, and USAGE.md - a. ./qr-backup --generate-docs docs/example.txt + a. ./qr-backup --generate-docs docs/example.txt [see: https://github.com/za3k/qr-backup/issues/65] b. USAGE.md needs updated manually 3. Update CHANGELOG and CONTRIBUTORS 4. Update the version number in the code and CHANGELOG. 5. Commit and tag the code. -5. In github, generate a release from the tag. +6. Build the source packages (requires signing key) + make all +7. Build the debian package (requires debuild -- tests currently fail on debian so no package ATM) + make deb +8. In github, generate a release from the tag. a. Copy the release notes from CHANGELOG - b. Build the debian binary and attach it to the release - c. Update the arch package - + b. Attach qr-backup-XXXX.tar.gz + qr-backup-XXXX.tar.gz.sig + qr-backup_XXXX_all.deb +9. Update the arch package, since I'm the maintainer. + a. git clone ssh://aur@aur.archlinux.org/qr-backup.git + b. Edit PKGBUILD. Bump the version number, delete the SHA. + c. makepkg -g, add that to PKGBUILD + d. makepkg --printsrcinfo > .SRCINFO + e. Run makepkg, makepkg -i to make sure it's all good + f. git push From 9756bcff6efb04d6f8e776a5b9bf6c2fd785b5a2 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Julian=20R=C3=BCth?= Date: Thu, 20 Feb 2025 09:42:20 +0100 Subject: [PATCH 2/7] Treat a return code 0 as success --- docs/CHANGELOG | 2 ++ docs/CONTRIBUTORS.md | 1 + qr-backup | 2 +- 3 files changed, 4 insertions(+), 1 deletion(-) diff --git a/docs/CHANGELOG b/docs/CHANGELOG index 0ade249..b638c0f 100644 --- a/docs/CHANGELOG +++ b/docs/CHANGELOG @@ -1,5 +1,7 @@ (unreleased) - ("Added continuous integration" when done.) +- Fixed bugs + - Corrected return code when --check-restore is enabled [(PR #51)](https://github.com/za3k/qr-backup/pull/61) v1.1.4, 2025-03-24 - Improved note display diff --git a/docs/CONTRIBUTORS.md b/docs/CONTRIBUTORS.md index ead5822..21c230a 100644 --- a/docs/CONTRIBUTORS.md +++ b/docs/CONTRIBUTORS.md @@ -6,6 +6,7 @@ People who provided code: - [acuteangle](https://github.com/acuteaangle), nix packaging - [Antoine Beaupré](https://github.com/anarcat), debian packaging; notes +- [Julian Rüth](https://github.com/saraedum), bugfix - [vonProteus](https://github.com/vonProteus), docker support; documentation; OS X testing - [VzxPLnHqr](https://github.com/VzxPLnHqr), nix packaging diff --git a/qr-backup b/qr-backup index 259313a..ded758b 100755 --- a/qr-backup +++ b/qr-backup @@ -1490,7 +1490,7 @@ def self_test_restore(restore_cmd, input_path, output_path, output_buffer, origi if use_encryption: self_test_command += ["--encrypt", encryption_passphrase] self_test_returncode = subprocess.call(self_test_command, stdout=subprocess.DEVNULL, stderr=subprocess.DEVNULL) - self_test_success = (self_test_returncode) + self_test_success = self_test_returncode == 0 logging.info("Self-test command was: {}".format(self_test_command)) logging.info("Self-test exit code was: {}".format(self_test_returncode)) From 8d40ed3e88898e85561105dc755a5595b447adee Mon Sep 17 00:00:00 2001 From: Summer Tea Date: Sun, 23 Mar 2025 10:39:08 -0400 Subject: [PATCH 3/7] ci: add initial GitHub Actions integration Hopefully prevent future regressions such as gh-63. Closes: gh-62 This modifies qr-backup to make gzip reproducible. --- .github/workflows/tests.yaml | 22 ++++++++++++++++++++++ docs/CHANGELOG | 2 +- docs/CONTRIBUTORS.md | 2 +- qr-backup | 3 +++ 4 files changed, 27 insertions(+), 2 deletions(-) create mode 100644 .github/workflows/tests.yaml diff --git a/.github/workflows/tests.yaml b/.github/workflows/tests.yaml new file mode 100644 index 0000000..255f6cd --- /dev/null +++ b/.github/workflows/tests.yaml @@ -0,0 +1,22 @@ +name: Tests + +on: + - push + - pull_request + +jobs: + test: + name: Run tests + runs-on: ${{ matrix.os }} + strategy: + matrix: + os: +# - macos-latest + - ubuntu-latest + steps: + - name: Checkout code + uses: actions/checkout@v4 + - name: Install dependencies + run: sudo apt install -y ghostscript gnupg2 imagemagick zbar-tools && sudo pip install -r requirements.txt + - name: Run tests + run: make test diff --git a/docs/CHANGELOG b/docs/CHANGELOG index b638c0f..58b128a 100644 --- a/docs/CHANGELOG +++ b/docs/CHANGELOG @@ -1,5 +1,5 @@ (unreleased) -- ("Added continuous integration" when done.) +- Added continuous integration - Fixed bugs - Corrected return code when --check-restore is enabled [(PR #51)](https://github.com/za3k/qr-backup/pull/61) diff --git a/docs/CONTRIBUTORS.md b/docs/CONTRIBUTORS.md index 21c230a..69eebd1 100644 --- a/docs/CONTRIBUTORS.md +++ b/docs/CONTRIBUTORS.md @@ -4,9 +4,9 @@ Additional thanks to many contributors. People who provided code: -- [acuteangle](https://github.com/acuteaangle), nix packaging - [Antoine Beaupré](https://github.com/anarcat), debian packaging; notes - [Julian Rüth](https://github.com/saraedum), bugfix +- [Summer Tea](https://github.com/acuteaangle), nix packaging; continuous integration - [vonProteus](https://github.com/vonProteus), docker support; documentation; OS X testing - [VzxPLnHqr](https://github.com/VzxPLnHqr), nix packaging diff --git a/qr-backup b/qr-backup index ded758b..974f6ff 100755 --- a/qr-backup +++ b/qr-backup @@ -1191,6 +1191,9 @@ def main_backup(args): # (Gzip) Compression if use_compression: content = gzip.compress(content, mtime=0) + content = bytearray(content) + content[9] = 255 + content = bytes(content) # Encryption if use_encryption: From 7f04687a80b47281459aec8642d91b8bf5a209ba Mon Sep 17 00:00:00 2001 From: Zachary Vance Date: Mon, 24 Mar 2025 23:27:32 -0400 Subject: [PATCH 4/7] Readme typo --- docs/README.md | 2 +- qr-backup | 1 + 2 files changed, 2 insertions(+), 1 deletion(-) diff --git a/docs/README.md b/docs/README.md index 77801d3..b1da127 100644 --- a/docs/README.md +++ b/docs/README.md @@ -50,7 +50,7 @@ The restore process **does NOT require qr-backup**. It does require a command-li - [Should I back up to paper?](FAQ.md#should-i-back-up-to-paper) - [What are the advantages of paper backups?](FAQ.md#what-are-the-advantages-of-paper-backups) - [How much of my backup can I lose and still restore?](FAQ.md#how-much-of-my-backup-can-i-lose-and-still-restore) -- [Should I encrypt (FAQpassword-protect) my backups?](#should-i-encrypt-password-protect-my-backups) +- [Should I encrypt (password-protect) my backups?](FAQ.md#should-i-encrypt-password-protect-my-backups) - [How can I protect my paper backup?](FAQ.md#how-can-i-protect-my-paper-backup) ### Features diff --git a/qr-backup b/qr-backup index 974f6ff..506d023 100755 --- a/qr-backup +++ b/qr-backup @@ -1191,6 +1191,7 @@ def main_backup(args): # (Gzip) Compression if use_compression: content = gzip.compress(content, mtime=0) + # This makes CI tests pass, see https://github.com/python/cpython/issues/112346 content = bytearray(content) content[9] = 255 content = bytes(content) From ec8ab373110de62d2e1f6f47c9a34e9e1a73c571 Mon Sep 17 00:00:00 2001 From: Zachary Vance Date: Tue, 25 Mar 2025 18:37:57 -0400 Subject: [PATCH 5/7] Rename from 'regression' to 'reproducibility' tests --- Makefile | 5 +-- tests/{regression.pdf => 100zeros-good.pdf} | Bin tests/test.py | 35 +++++++++----------- 3 files changed, 17 insertions(+), 23 deletions(-) rename tests/{regression.pdf => 100zeros-good.pdf} (100%) diff --git a/Makefile b/Makefile index 66bdc39..1e3de39 100644 --- a/Makefile +++ b/Makefile @@ -35,11 +35,8 @@ clean: install: install -D qr-backup $(DESTDIR)$(PREFIX)$(BINDIR)/qr-backup install -D -m 644 docs/qr-backup.1.man $(DESTDIR)$(PREFIX)$(MANDIR)/man1/qr-backup.1 -test: tests/regression.pdf +test: python3 tests/test.py -tests/regression.pdf: - mkdir -p examples - dd if=/dev/zero bs=1 count=100 2>/dev/null | python3 qr-backup --skip-checks - --backup-date 2022-09-22 >tests/regression.pdf uninstall: rm -f $(DESTDIR)$(PREFIX)$(BINDIR)/qr-backup rm -f $(DESTDIR)$(PREFIX)$(MANDIR)/man1/qr-backup.1 diff --git a/tests/regression.pdf b/tests/100zeros-good.pdf similarity index 100% rename from tests/regression.pdf rename to tests/100zeros-good.pdf diff --git a/tests/test.py b/tests/test.py index c57744c..5d38611 100644 --- a/tests/test.py +++ b/tests/test.py @@ -11,7 +11,7 @@ Note: too-fast can also be reported, which means you have improved the test speed, and need to update the "target" running time -(3) Reproducibility: Backup regression test (backup-regession) +(3) Reproducibility: Backup reproducibility test (backup-not-reproducible) Is the output bitwise-identical to last time the tests were *blessed* blessed: marked correct by hand """ @@ -30,18 +30,18 @@ Because of this nice property, you should default to considering it worth fixing if reproducibilty tests fail (rather than rubber-stamping changes). -To narrow down what changed, compare the ouput of zeros.pdf (we just generated -it for you) with the file tests/regression.pdf (a known-good version). +To narrow down what changed, compare the ouput of 100zeros-test.pdf (we just generated +it for you) with the file tests/100zeros-good.pdf (a known-good version). My suggested process to get started: -1. 'git checkout' the last commit in which tests/regression.pdf was last +1. 'git checkout' the last commit in which tests/100zeros-good.pdf was last touched, and re-generate a new version using - dd if=/dev/zero count=1 bs=100 | python3 qr-backup - >regression2.pdf + dd if=/dev/zero bs=1 count=100 2>/dev/null | python3 qr-backup --skip-checks - --backup-date 2022-09-22 >100zeros-old.pdf - If the output is identical to regression.pdf, this confirms the change was - in the qr-backup repository. + If the output is identical to tests/100zeros-good.pdf, this confirms + the change was in the qr-backup repository. Either way, proceed with the steps 2 and on. @@ -55,7 +55,7 @@ Another possibility is differing output across runs. We once accidentally embedded the date in pdfs made during test runs. -2. Convert each of zeros.pdf and tests/regession.pdf to a png. Compare them +2. Convert each of 100zeros-test.pdf and tests/100zeros-good.pdf to a png. Compare them using a visual diff tool online. Have the QR codes changed, the instructions, or neither? @@ -199,8 +199,7 @@ def program_present(program): @only_once def make_pdf(): print_red(REPRODUCIBILITY_FAILING) - # Make a new regression.pdf for future generations - qr_command = " ".join(["python3", "qr-backup"] + DEFAULT_ARGS) + " >zeros.pdf" + qr_command = " ".join(["python3", "qr-backup"] + DEFAULT_ARGS) + " >100zeros-test.pdf" subprocess.run(qr_command, shell=True, input=zeros(100)) def do_test(test, new_blessed): @@ -218,11 +217,9 @@ def do_test(test, new_blessed): sha = hashlib.sha256(output_bytes).hexdigest() elapsed, power = math.ceil(elapsed), math.ceil(math.log(elapsed, 2)) - # TODO: "regression" should be called "reproducibility" + # TODO: Check the data inside the QR-codes as a second, much-less-flaky reproducibility suite. - # TODO: Check the data inside the QR-codes as a second, much-less-flaky regression suite. - - # TODO: Check the text inside the PDFs in a yet third, much-less-flaky regression suite. + # TODO: Check the text inside the PDFs in a yet third, much-less-flaky reproducibility suite. if expected_sha is None: # Some tests are non-deterministic (ones using encryption) pass @@ -232,9 +229,9 @@ def do_test(test, new_blessed): failures += 1 return failures, None elif sha == expected_sha: - print_green("backup-no-regression {} {}s".format(name, elapsed)) + print_green("backup-reproducible {} {}s".format(name, elapsed)) else: - print_red("backup-regression {} {}s".format(name, elapsed)) + print_red("backup-not-reproducible {} {}s".format(name, elapsed)) print(" command:", qr_command) print(" result:", sha, "!=", expected_sha) failures += 1 @@ -300,9 +297,9 @@ def test_assert_zeros_same(): assert BLESSED_OUTPUT['default options'] == BLESSED_OUTPUT['100b zeros'] def test_assert_reproducibile_current(): - out = subprocess.check_output(["sha256sum", "tests/regression.pdf"]) - expected = "{} tests/regression.pdf\n".format(BLESSED_OUTPUT['100b zeros']).encode("UTF8") - assert out == expected, "tests/regression.pdf does not match the expected SHA256 for the '100b zeros' test" + out = subprocess.check_output(["sha256sum", "tests/100zeros-good.pdf"]) + expected = "{} tests/100zeros-good.pdf\n".format(BLESSED_OUTPUT['100b zeros']).encode("UTF8") + assert out == expected, "tests/100zeros-good.pdf does not match the expected SHA256 for the '100b zeros' test" if __name__ == "__main__": if not program_present("zbarimg"): From e7d028eb4fddaa7f8628c88e1604d5e64f546389 Mon Sep 17 00:00:00 2001 From: Zachary Vance Date: Tue, 25 Mar 2025 19:57:31 -0400 Subject: [PATCH 6/7] Add --fast option to tests The new option (1) Runs tests in parallel (2) Omits tests which are intended for developers to spot reproducibility issues, rather than for end-users to verify a working install. This means --fast is also more reliable. The opposite of --fast is --full. Note that we're using a custom test runner, which is not ideal. It's because we're using generated tests, and the generated tests share a lot of redundant setup. But it's still not ideal. Closes issue #67. --- Makefile | 2 + tests/test.py | 229 ++++++++++++++++++++++++++++++++------------------ 2 files changed, 147 insertions(+), 84 deletions(-) diff --git a/Makefile b/Makefile index 1e3de39..e390771 100644 --- a/Makefile +++ b/Makefile @@ -37,6 +37,8 @@ install: install -D -m 644 docs/qr-backup.1.man $(DESTDIR)$(PREFIX)$(MANDIR)/man1/qr-backup.1 test: python3 tests/test.py +test-fast: + python3 tests/test.py --fast uninstall: rm -f $(DESTDIR)$(PREFIX)$(BINDIR)/qr-backup rm -f $(DESTDIR)$(PREFIX)$(MANDIR)/man1/qr-backup.1 diff --git a/tests/test.py b/tests/test.py index 5d38611..63928d6 100644 --- a/tests/test.py +++ b/tests/test.py @@ -15,6 +15,17 @@ Is the output bitwise-identical to last time the tests were *blessed* blessed: marked correct by hand """ +import argparse +import functools +import hashlib +import math +import multiprocessing +import operator +import random +import subprocess +import sys +import textwrap +import time REPRODUCIBILITY_FAILING = """ This is the most basic reproducibility test, so something has changed. @@ -82,15 +93,6 @@ not consistent even between runs, this is a bug in qr-backup. """ -import functools -import hashlib -import math -import random -import subprocess -import sys -import textwrap -import time - only_once = functools.cache # As long as it's called on a no-argument function :) def zeros(length): @@ -202,7 +204,23 @@ def make_pdf(): qr_command = " ".join(["python3", "qr-backup"] + DEFAULT_ARGS) + " >100zeros-test.pdf" subprocess.run(qr_command, shell=True, input=zeros(100)) -def do_test(test, new_blessed): +class Test: + def __init__(self, f, *args, **kwargs): + self.f = f + self.args = args + self.kwargs = kwargs + def __call__(self): + return self.f(*self.args, **self.kwargs) + +class BackupTest(Test): + def __init__(self, *args, **kwargs): + super().__init__(run_backup_tests, *args, **kwargs) + +class AssertionTest(Test): + def __init__(self, *args, **kwargs): + super().__init__(run_assertion_test, *args, **kwargs) + +def run_backup_tests(test, new_blessed, run_reproducibility=True, run_speed=True, run_restore=True): name, input_bytes, options, time_limit, restore_options, restore_time_limit = test expected_sha = BLESSED_OUTPUT.get(name, b'') @@ -221,61 +239,66 @@ def do_test(test, new_blessed): # TODO: Check the text inside the PDFs in a yet third, much-less-flaky reproducibility suite. - if expected_sha is None: # Some tests are non-deterministic (ones using encryption) - pass - elif result.returncode != 0: - print_red("failing-command {} {}s".format(name, elapsed)) - print_red(textwrap.indent(result.stderr.decode("utf8"), " ")) - failures += 1 - return failures, None - elif sha == expected_sha: - print_green("backup-reproducible {} {}s".format(name, elapsed)) - else: - print_red("backup-not-reproducible {} {}s".format(name, elapsed)) - print(" command:", qr_command) - print(" result:", sha, "!=", expected_sha) - failures += 1 - - if expected_sha == BLESSED_OUTPUT['100b zeros']: - make_pdf() - - if elapsed > time_limit*2: - print_red("too-slow", name, "{}s, <2^{}".format(elapsed, power)) - failures += 1 - elif elapsed <= time_limit / 3: - print("too-fast", name, "{}s, <2^{}".format(elapsed, power)) - pass - - restore_options = DEFAULT_RESTORE_ARGS + restore_options - restore_command = " ".join(["python3", "qr-backup", "--restore"] + restore_options) - start = time.time() - result2 = subprocess.run(restore_command, shell=True, capture_output=True, input=output_bytes) - elapsed = time.time() - start - restored_bytes = result2.stdout - elapsed, power = math.ceil(elapsed), math.ceil(math.log(elapsed, 2)) - - if result2.returncode != 0: - print_red("failing-command {} {}s".format(name, elapsed)) - print_red(textwrap.indent(result2.stderr.decode("utf8"), " ")) - failures += 1 - return failures, None - elif input_bytes == restored_bytes: - print_green("correct-restore {} {}s".format(name, elapsed)) - if expected_sha is not None and sha != expected_sha: - new_blessed[name] = sha - else: - print_red("incorrect-restore {} {}s".format(name, elapsed)) - print(" command:", restore_command) - #print(input_bytes, restored_bytes) - failures += 1 - if elapsed > restore_time_limit*2: - print_red("too-slow {} {}s, <2^{}".format(name, elapsed, power)) - failures += 1 - elif elapsed <= restore_time_limit / 3: - print("too-fast {} {}s, <2^{}".format(name, elapsed, power)) - pass - - return failures, sha + if run_reproducibility: + if expected_sha is None: # Some tests are non-deterministic (ones using encryption) + pass + elif result.returncode != 0: + print_red("failing-command {} {}s".format(name, elapsed)) + print_red(textwrap.indent(result.stderr.decode("utf8"), " ")) + failures += 1 + return failures, None + elif sha == expected_sha: + print_green("backup-reproducible {} {}s".format(name, elapsed)) + else: + print_red("backup-not-reproducible {} {}s".format(name, elapsed)) + print(" command:", qr_command) + print(" result:", sha, "!=", expected_sha) + failures += 1 + + if expected_sha == BLESSED_OUTPUT['100b zeros']: + make_pdf() + + if run_speed: + if elapsed > time_limit*2: + print_red("too-slow", name, "{}s, <2^{}".format(elapsed, power)) + failures += 1 + elif elapsed <= time_limit / 3: + print("too-fast", name, "{}s, <2^{}".format(elapsed, power)) + pass + + if run_restore: + restore_options = DEFAULT_RESTORE_ARGS + restore_options + restore_command = " ".join(["python3", "qr-backup", "--restore"] + restore_options) + start = time.time() + result2 = subprocess.run(restore_command, shell=True, capture_output=True, input=output_bytes) + elapsed = time.time() - start + restored_bytes = result2.stdout + elapsed, power = math.ceil(elapsed), math.ceil(math.log(elapsed, 2)) + + if result2.returncode != 0: + print_red("failing-command {} {}s".format(name, elapsed)) + print_red(textwrap.indent(result2.stderr.decode("utf8"), " ")) + failures += 1 + return failures, None + elif input_bytes == restored_bytes: + print_green("correct-restore {} {}s".format(name, elapsed)) + if expected_sha is not None and sha != expected_sha: + new_blessed[name] = sha + else: + print_red("incorrect-restore {} {}s".format(name, elapsed)) + print(" command:", restore_command) + #print(input_bytes, restored_bytes) + failures += 1 + + if run_restore and run_speed: + if elapsed > restore_time_limit*2: + print_red("too-slow {} {}s, <2^{}".format(name, elapsed, power)) + failures += 1 + elif elapsed <= restore_time_limit / 3: + print("too-fast {} {}s, <2^{}".format(name, elapsed, power)) + pass + + return failures def run_assertion_test(name, f): try: @@ -292,35 +315,55 @@ def run_assertion_test(name, f): print(" {}".format(e)) return 1 -def test_assert_zeros_same(): +def test_assert_full_zeros_same(): # Passing the default options and passing no options should be the same assert BLESSED_OUTPUT['default options'] == BLESSED_OUTPUT['100b zeros'] -def test_assert_reproducibile_current(): +def test_assert_full_reproducible_current(): out = subprocess.check_output(["sha256sum", "tests/100zeros-good.pdf"]) expected = "{} tests/100zeros-good.pdf\n".format(BLESSED_OUTPUT['100b zeros']).encode("UTF8") assert out == expected, "tests/100zeros-good.pdf does not match the expected SHA256 for the '100b zeros' test" -if __name__ == "__main__": - if not program_present("zbarimg"): - print_red("To run tests, install the packages: zbar") - sys.exit(6) +def test_runner(tests, parallel): + # Each "test" should print to stdout and return the number of failures + # Don't try to avoid interleaving stdout. Too hard. - failures = 0 - new_blessed = {} + if parallel: + with multiprocessing.Pool() as P: + results = P.map(operator.call, tests) + else: + results = map(operator.call, tests) + return sum(results) - # Additional, other tests that are not backup examples - for name, f in {(k,v) for k,v in globals().items() if k.startswith("test_assert")}: - failures += run_assertion_test(name, f) +def main(args): + run_reproducibility = args.full + run_speed = args.full + run_restore = True + parallel = not run_speed + + tests = [] + # Additional, other tests that are not backup examples + for name, f in {(k,v) for k,v in globals().items() if k.startswith("test_assert_")}: + if name.startswith("test_assert_full_"): + if not args.full: continue + name = name.removeprefix("test_assert_full_") + else: + name = name.removeprefix("test_assert_") + name = name.replace("_", "-") + tests.append(AssertionTest(name, f)) + + # Normal tests (several tests are run for each input) + new_blessed = {} for test in TESTS: - new_failures, sha = do_test(test, new_blessed) - failures += new_failures - if False and new_failures > 0: - with open("failure.bin", "wb") as f: - f.write(test[1]) - print("exit on first failure") - break + tests.append(BackupTest( + test, new_blessed, + run_reproducibility = run_reproducibility, + run_speed = run_speed, + run_restore = run_restore, + )) + + failures = test_runner(tests, parallel=parallel) if len(new_blessed) > 0: print("NEW BLESSED_OUTPUT = {") @@ -331,4 +374,22 @@ def test_assert_reproducibile_current(): print("{} failures".format(failures)) if failures > 0: print_red(__doc__) - sys.exit(1 if failures > 0 else 0) + return failures + +if __name__ == "__main__": + if not program_present("zbarimg"): + print_red("To run tests, install the packages: zbar") + sys.exit(6) + + parser = argparse.ArgumentParser( + prog="tests.py", + description="Run qr-backup tests", + ) + parser.add_argument("--full", action="store_true", default=True) + parser.add_argument("--fast", dest="full", action="store_false") + args = parser.parse_args() + + failures = main(args) + + if failures > 0: + sys.exit(1) From 9189bbdff195dcda3d0598825a5d92dd593a6ff5 Mon Sep 17 00:00:00 2001 From: Zachary Vance Date: Sat, 5 Apr 2025 23:52:09 -0400 Subject: [PATCH 7/7] Remove nix packaging This is now being added to upstream, via https://github.com/NixOS/nixpkgs/pull/392426 --- installers/flake.lock | 514 ------------------------------------------ installers/flake.nix | 50 ---- 2 files changed, 564 deletions(-) delete mode 100644 installers/flake.lock delete mode 100644 installers/flake.nix diff --git a/installers/flake.lock b/installers/flake.lock deleted file mode 100644 index 15c8455..0000000 --- a/installers/flake.lock +++ /dev/null @@ -1,514 +0,0 @@ -{ - "nodes": { - "cachix": { - "inputs": { - "devenv": "devenv_2", - "flake-compat": [ - "devenv", - "flake-compat" - ], - "nixpkgs": [ - "devenv", - "nixpkgs" - ], - "pre-commit-hooks": [ - "devenv", - "pre-commit-hooks" - ] - }, - "locked": { - "lastModified": 1712055811, - "narHash": "sha256-7FcfMm5A/f02yyzuavJe06zLa9hcMHsagE28ADcmQvk=", - "owner": "cachix", - "repo": "cachix", - "rev": "02e38da89851ec7fec3356a5c04bc8349cae0e30", - "type": "github" - }, - "original": { - "owner": "cachix", - "repo": "cachix", - "type": "github" - } - }, - "devenv": { - "inputs": { - "cachix": "cachix", - "flake-compat": "flake-compat_2", - "nix": "nix_2", - "nixpkgs": [ - "nixpkgs" - ], - "pre-commit-hooks": "pre-commit-hooks" - }, - "locked": { - "lastModified": 1713968789, - "narHash": "sha256-Gue8iwW3ZtCQs3EZKhk/i0uLaoUDfW1dpnaZ67MH64o=", - "owner": "cachix", - "repo": "devenv", - "rev": "b26b52a4dac68bdc305f6b9df948c97f49b2c3ee", - "type": "github" - }, - "original": { - "owner": "cachix", - "repo": "devenv", - "type": "github" - } - }, - "devenv_2": { - "inputs": { - "flake-compat": [ - "devenv", - "cachix", - "flake-compat" - ], - "nix": "nix", - "nixpkgs": "nixpkgs", - "poetry2nix": "poetry2nix", - "pre-commit-hooks": [ - "devenv", - "cachix", - "pre-commit-hooks" - ] - }, - "locked": { - "lastModified": 1708704632, - "narHash": "sha256-w+dOIW60FKMaHI1q5714CSibk99JfYxm0CzTinYWr+Q=", - "owner": "cachix", - "repo": "devenv", - "rev": "2ee4450b0f4b95a1b90f2eb5ffea98b90e48c196", - "type": "github" - }, - "original": { - "owner": "cachix", - "ref": "python-rewrite", - "repo": "devenv", - "type": "github" - } - }, - "flake-compat": { - "flake": false, - "locked": { - "lastModified": 1673956053, - "narHash": "sha256-4gtG9iQuiKITOjNQQeQIpoIB6b16fm+504Ch3sNKLd8=", - "owner": "edolstra", - "repo": "flake-compat", - "rev": "35bb57c0c8d8b62bbfd284272c928ceb64ddbde9", - "type": "github" - }, - "original": { - "owner": "edolstra", - "repo": "flake-compat", - "type": "github" - } - }, - "flake-compat_2": { - "flake": false, - "locked": { - "lastModified": 1696426674, - "narHash": "sha256-kvjfFW7WAETZlt09AgDn1MrtKzP7t90Vf7vypd3OL1U=", - "owner": "edolstra", - "repo": "flake-compat", - "rev": "0f9255e01c2351cc7d116c072cb317785dd33b33", - "type": "github" - }, - "original": { - "owner": "edolstra", - "repo": "flake-compat", - "type": "github" - } - }, - "flake-compat_3": { - "flake": false, - "locked": { - "lastModified": 1696426674, - "narHash": "sha256-kvjfFW7WAETZlt09AgDn1MrtKzP7t90Vf7vypd3OL1U=", - "owner": "edolstra", - "repo": "flake-compat", - "rev": "0f9255e01c2351cc7d116c072cb317785dd33b33", - "type": "github" - }, - "original": { - "owner": "edolstra", - "repo": "flake-compat", - "type": "github" - } - }, - "flake-utils": { - "inputs": { - "systems": "systems" - }, - "locked": { - "lastModified": 1689068808, - "narHash": "sha256-6ixXo3wt24N/melDWjq70UuHQLxGV8jZvooRanIHXw0=", - "owner": "numtide", - "repo": "flake-utils", - "rev": "919d646de7be200f3bf08cb76ae1f09402b6f9b4", - "type": "github" - }, - "original": { - "owner": "numtide", - "repo": "flake-utils", - "type": "github" - } - }, - "flake-utils_2": { - "inputs": { - "systems": "systems_2" - }, - "locked": { - "lastModified": 1710146030, - "narHash": "sha256-SZ5L6eA7HJ/nmkzGG7/ISclqe6oZdOZTNoesiInkXPQ=", - "owner": "numtide", - "repo": "flake-utils", - "rev": "b1d9ab70662946ef0850d488da1c9019f3a9752a", - "type": "github" - }, - "original": { - "owner": "numtide", - "repo": "flake-utils", - "type": "github" - } - }, - "flake-utils_3": { - "inputs": { - "systems": "systems_3" - }, - "locked": { - "lastModified": 1701680307, - "narHash": "sha256-kAuep2h5ajznlPMD9rnQyffWG8EM/C73lejGofXvdM8=", - "owner": "numtide", - "repo": "flake-utils", - "rev": "4022d587cbbfd70fe950c1e2083a02621806a725", - "type": "github" - }, - "original": { - "id": "flake-utils", - "type": "indirect" - } - }, - "gitignore": { - "inputs": { - "nixpkgs": [ - "devenv", - "pre-commit-hooks", - "nixpkgs" - ] - }, - "locked": { - "lastModified": 1709087332, - "narHash": "sha256-HG2cCnktfHsKV0s4XW83gU3F57gaTljL9KNSuG6bnQs=", - "owner": "hercules-ci", - "repo": "gitignore.nix", - "rev": "637db329424fd7e46cf4185293b9cc8c88c95394", - "type": "github" - }, - "original": { - "owner": "hercules-ci", - "repo": "gitignore.nix", - "type": "github" - } - }, - "nix": { - "inputs": { - "flake-compat": "flake-compat", - "nixpkgs": [ - "devenv", - "cachix", - "devenv", - "nixpkgs" - ], - "nixpkgs-regression": "nixpkgs-regression" - }, - "locked": { - "lastModified": 1712911606, - "narHash": "sha256-BGvBhepCufsjcUkXnEEXhEVjwdJAwPglCC2+bInc794=", - "owner": "domenkozar", - "repo": "nix", - "rev": "b24a9318ea3f3600c1e24b4a00691ee912d4de12", - "type": "github" - }, - "original": { - "owner": "domenkozar", - "ref": "devenv-2.21", - "repo": "nix", - "type": "github" - } - }, - "nix-github-actions": { - "inputs": { - "nixpkgs": [ - "devenv", - "cachix", - "devenv", - "poetry2nix", - "nixpkgs" - ] - }, - "locked": { - "lastModified": 1688870561, - "narHash": "sha256-4UYkifnPEw1nAzqqPOTL2MvWtm3sNGw1UTYTalkTcGY=", - "owner": "nix-community", - "repo": "nix-github-actions", - "rev": "165b1650b753316aa7f1787f3005a8d2da0f5301", - "type": "github" - }, - "original": { - "owner": "nix-community", - "repo": "nix-github-actions", - "type": "github" - } - }, - "nix_2": { - "inputs": { - "flake-compat": [ - "devenv", - "flake-compat" - ], - "nixpkgs": [ - "devenv", - "nixpkgs" - ], - "nixpkgs-regression": "nixpkgs-regression_2" - }, - "locked": { - "lastModified": 1712911606, - "narHash": "sha256-BGvBhepCufsjcUkXnEEXhEVjwdJAwPglCC2+bInc794=", - "owner": "domenkozar", - "repo": "nix", - "rev": "b24a9318ea3f3600c1e24b4a00691ee912d4de12", - "type": "github" - }, - "original": { - "owner": "domenkozar", - "ref": "devenv-2.21", - "repo": "nix", - "type": "github" - } - }, - "nixpkgs": { - "locked": { - "lastModified": 1692808169, - "narHash": "sha256-x9Opq06rIiwdwGeK2Ykj69dNc2IvUH1fY55Wm7atwrE=", - "owner": "NixOS", - "repo": "nixpkgs", - "rev": "9201b5ff357e781bf014d0330d18555695df7ba8", - "type": "github" - }, - "original": { - "owner": "NixOS", - "ref": "nixpkgs-unstable", - "repo": "nixpkgs", - "type": "github" - } - }, - "nixpkgs-python": { - "inputs": { - "flake-compat": "flake-compat_3", - "flake-utils": "flake-utils_3", - "nixpkgs": [ - "nixpkgs" - ] - }, - "locked": { - "lastModified": 1713539989, - "narHash": "sha256-/XaYRbYRYciZ4atdZmVdvHdoI7Avjt4pUMI6ZBZMl0s=", - "owner": "cachix", - "repo": "nixpkgs-python", - "rev": "462946481a3f4497c90103c92b5e7408e3c59f4f", - "type": "github" - }, - "original": { - "owner": "cachix", - "repo": "nixpkgs-python", - "type": "github" - } - }, - "nixpkgs-regression": { - "locked": { - "lastModified": 1643052045, - "narHash": "sha256-uGJ0VXIhWKGXxkeNnq4TvV3CIOkUJ3PAoLZ3HMzNVMw=", - "owner": "NixOS", - "repo": "nixpkgs", - "rev": "215d4d0fd80ca5163643b03a33fde804a29cc1e2", - "type": "github" - }, - "original": { - "owner": "NixOS", - "repo": "nixpkgs", - "rev": "215d4d0fd80ca5163643b03a33fde804a29cc1e2", - "type": "github" - } - }, - "nixpkgs-regression_2": { - "locked": { - "lastModified": 1643052045, - "narHash": "sha256-uGJ0VXIhWKGXxkeNnq4TvV3CIOkUJ3PAoLZ3HMzNVMw=", - "owner": "NixOS", - "repo": "nixpkgs", - "rev": "215d4d0fd80ca5163643b03a33fde804a29cc1e2", - "type": "github" - }, - "original": { - "owner": "NixOS", - "repo": "nixpkgs", - "rev": "215d4d0fd80ca5163643b03a33fde804a29cc1e2", - "type": "github" - } - }, - "nixpkgs-stable": { - "locked": { - "lastModified": 1710695816, - "narHash": "sha256-3Eh7fhEID17pv9ZxrPwCLfqXnYP006RKzSs0JptsN84=", - "owner": "NixOS", - "repo": "nixpkgs", - "rev": "614b4613980a522ba49f0d194531beddbb7220d3", - "type": "github" - }, - "original": { - "owner": "NixOS", - "ref": "nixos-23.11", - "repo": "nixpkgs", - "type": "github" - } - }, - "nixpkgs_2": { - "locked": { - "lastModified": 1713361204, - "narHash": "sha256-TA6EDunWTkc5FvDCqU3W2T3SFn0gRZqh6D/hJnM02MM=", - "owner": "cachix", - "repo": "devenv-nixpkgs", - "rev": "285676e87ad9f0ca23d8714a6ab61e7e027020c6", - "type": "github" - }, - "original": { - "owner": "cachix", - "ref": "rolling", - "repo": "devenv-nixpkgs", - "type": "github" - } - }, - "poetry2nix": { - "inputs": { - "flake-utils": "flake-utils", - "nix-github-actions": "nix-github-actions", - "nixpkgs": [ - "devenv", - "cachix", - "devenv", - "nixpkgs" - ] - }, - "locked": { - "lastModified": 1692876271, - "narHash": "sha256-IXfZEkI0Mal5y1jr6IRWMqK8GW2/f28xJenZIPQqkY0=", - "owner": "nix-community", - "repo": "poetry2nix", - "rev": "d5006be9c2c2417dafb2e2e5034d83fabd207ee3", - "type": "github" - }, - "original": { - "owner": "nix-community", - "repo": "poetry2nix", - "type": "github" - } - }, - "pre-commit-hooks": { - "inputs": { - "flake-compat": [ - "devenv", - "flake-compat" - ], - "flake-utils": "flake-utils_2", - "gitignore": "gitignore", - "nixpkgs": [ - "devenv", - "nixpkgs" - ], - "nixpkgs-stable": "nixpkgs-stable" - }, - "locked": { - "lastModified": 1713775815, - "narHash": "sha256-Wu9cdYTnGQQwtT20QQMg7jzkANKQjwBD9iccfGKkfls=", - "owner": "cachix", - "repo": "pre-commit-hooks.nix", - "rev": "2ac4dcbf55ed43f3be0bae15e181f08a57af24a4", - "type": "github" - }, - "original": { - "owner": "cachix", - "repo": "pre-commit-hooks.nix", - "type": "github" - } - }, - "root": { - "inputs": { - "devenv": "devenv", - "nixpkgs": "nixpkgs_2", - "nixpkgs-python": "nixpkgs-python", - "systems": "systems_4" - } - }, - "systems": { - "locked": { - "lastModified": 1681028828, - "narHash": "sha256-Vy1rq5AaRuLzOxct8nz4T6wlgyUR7zLU309k9mBC768=", - "owner": "nix-systems", - "repo": "default", - "rev": "da67096a3b9bf56a91d16901293e51ba5b49a27e", - "type": "github" - }, - "original": { - "owner": "nix-systems", - "repo": "default", - "type": "github" - } - }, - "systems_2": { - "locked": { - "lastModified": 1681028828, - "narHash": "sha256-Vy1rq5AaRuLzOxct8nz4T6wlgyUR7zLU309k9mBC768=", - "owner": "nix-systems", - "repo": "default", - "rev": "da67096a3b9bf56a91d16901293e51ba5b49a27e", - "type": "github" - }, - "original": { - "owner": "nix-systems", - "repo": "default", - "type": "github" - } - }, - "systems_3": { - "locked": { - "lastModified": 1681028828, - "narHash": "sha256-Vy1rq5AaRuLzOxct8nz4T6wlgyUR7zLU309k9mBC768=", - "owner": "nix-systems", - "repo": "default", - "rev": "da67096a3b9bf56a91d16901293e51ba5b49a27e", - "type": "github" - }, - "original": { - "owner": "nix-systems", - "repo": "default", - "type": "github" - } - }, - "systems_4": { - "locked": { - "lastModified": 1681028828, - "narHash": "sha256-Vy1rq5AaRuLzOxct8nz4T6wlgyUR7zLU309k9mBC768=", - "owner": "nix-systems", - "repo": "default", - "rev": "da67096a3b9bf56a91d16901293e51ba5b49a27e", - "type": "github" - }, - "original": { - "owner": "nix-systems", - "repo": "default", - "type": "github" - } - } - }, - "root": "root", - "version": 7 -} diff --git a/installers/flake.nix b/installers/flake.nix deleted file mode 100644 index 402d419..0000000 --- a/installers/flake.nix +++ /dev/null @@ -1,50 +0,0 @@ -{ - inputs = { - nixpkgs.url = "github:cachix/devenv-nixpkgs/rolling"; - systems.url = "github:nix-systems/default"; - devenv.url = "github:cachix/devenv"; - devenv.inputs.nixpkgs.follows = "nixpkgs"; - nixpkgs-python.url = "github:cachix/nixpkgs-python"; - nixpkgs-python.inputs = { nixpkgs.follows = "nixpkgs"; }; - }; - - nixConfig = { - extra-trusted-public-keys = "devenv.cachix.org-1:w1cLUi8dv3hnoSPGAuibQv+f9TZLr6cv/Hm9XgU50cw="; - extra-substituters = "https://devenv.cachix.org"; - }; - - outputs = { self, nixpkgs, devenv, systems, ... } @ inputs: - let - forEachSystem = nixpkgs.lib.genAttrs (import systems); - in - { - packages = forEachSystem (system: { - devenv-up = self.devShells.${system}.default.config.procfileScript; - }); - - devShells = forEachSystem - (system: - let - pkgs = nixpkgs.legacyPackages.${system}; - in - { - default = devenv.lib.mkShell { - inherit inputs pkgs; - modules = [ - { - packages = with pkgs; [ - zbar - dejavu_fonts - imagemagick - ]; - languages.python = { - enable = true; - venv.enable = true; - venv.requirements = ./requirements.txt; - }; - } - ]; - }; - }); - }; -} \ No newline at end of file