Skip to content

Commit

Permalink
Make patches optional (#68)
Browse files Browse the repository at this point in the history
* add make_patch arg to Repository.add_bundle

* add a --skip-patch option to CLI

* refactor make_patch into skip_patch, for consistency
  • Loading branch information
dennisvang authored Feb 24, 2023
1 parent 0f95d31 commit 17cb4ba
Show file tree
Hide file tree
Showing 4 changed files with 49 additions and 8 deletions.
11 changes: 7 additions & 4 deletions src/tufup/repo/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -703,15 +703,18 @@ def add_bundle(
self,
new_bundle_dir: Union[pathlib.Path, str],
new_version: Optional[str] = None,
skip_patch: bool = False,
):
"""
Adds a new application bundle to the local repository.
An archive file is created from the app bundle, and this file is
added to the tuf repository. If a previous archive version is
found, a patch file is also created and added to the repository.
added to the tuf repository. If a previous archive version is found,
a patch file is also created and added to the repository, unless
`skip_patch` is True.
Note the changes are not published yet: call publish_changes() for that
Note the changes are not published yet: call `publish_changes()` for
that.
"""
# enforce path object
new_bundle_dir = pathlib.Path(new_bundle_dir)
Expand All @@ -734,7 +737,7 @@ def add_bundle(
# register new archive
self.roles.add_or_update_target(local_path=new_archive.path)
# create patch, if possible, and register that too
if latest_archive:
if latest_archive and not skip_patch:
patch_path = Patcher.create_patch(
src_path=self.targets_dir / latest_archive.path,
dst_path=self.targets_dir / new_archive.path,
Expand Down
12 changes: 11 additions & 1 deletion src/tufup/repo/cli.py
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,7 @@
),
targets_add_app_version='Application version (PEP440 compliant)',
targets_add_bundle_dir='Directory containing application bundle.',
targets_add_skip_patch='Skip patch creation.',
targets_remove_latest='Remove latest app bundle from the repository.',
keys_subcommands='Optional commands to add or replace keys.',
keys_new_key_name='Name of new private key (public key gets .pub suffix).',
Expand Down Expand Up @@ -80,6 +81,13 @@ def get_parser() -> argparse.ArgumentParser:
subparser_targets_add.add_argument(
'bundle_dir', help=HELP['targets_add_bundle_dir']
)
subparser_targets_add.add_argument(
'-s',
'--skip-patch',
action='store_true',
required=False,
help=HELP['targets_add_skip_patch'],
)
subparser_targets_remove = targets_subparsers.add_parser(
'remove-latest', help=HELP['targets_remove_latest']
)
Expand Down Expand Up @@ -274,7 +282,9 @@ def _cmd_targets(options: argparse.Namespace):
if hasattr(options, 'app_version') and hasattr(options, 'bundle_dir'):
_print_info('Adding bundle...')
repository.add_bundle(
new_version=options.app_version, new_bundle_dir=options.bundle_dir
new_version=options.app_version,
new_bundle_dir=options.bundle_dir,
skip_patch=options.skip_patch,
)
else:
_print_info('Removing latest bundle...')
Expand Down
25 changes: 24 additions & 1 deletion tests/test_repo.py
Original file line number Diff line number Diff line change
Expand Up @@ -27,7 +27,7 @@
from tufup.common import TargetMeta
import tufup.repo # for patching
from tufup.repo import (
Base, in_, Keys, make_gztar_archive, Repository, Roles, SUFFIX_PUB
Base, in_, Keys, make_gztar_archive, Repository, Roles, SUFFIX_PUB, SUFFIX_PATCH
)


Expand Down Expand Up @@ -680,6 +680,29 @@ def test_add_bundle(self):
repo.add_bundle(new_version='1.0', new_bundle_dir=bundle_dir)
self.assertTrue((repo.metadata_dir / 'targets.json').exists())

def test_add_bundle_no_patch(self):
# prepare
bundle_dir = self.temp_dir_path / 'dist' / 'test_app'
bundle_dir.mkdir(parents=True)
bundle_file = bundle_dir / 'dummy.exe'
bundle_file.write_text('this is version 1')
repo = Repository(
app_name='test',
keys_dir=self.temp_dir_path / 'keystore',
repo_dir=self.temp_dir_path / 'repo',
)
repo.initialize() # todo: make test independent...
repo.add_bundle(new_version='1.0', new_bundle_dir=bundle_dir)
# test
bundle_file.write_text('much has changed in version 2')
repo.add_bundle(
new_version='2.0', new_bundle_dir=bundle_dir, skip_patch=True
)
self.assertTrue((repo.metadata_dir / 'targets.json').exists())
target_keys = list(repo.roles.targets.signed.targets.keys())
self.assertEqual(2, len(target_keys))
self.assertFalse(any(key.endswith(SUFFIX_PATCH) for key in target_keys))

def test_remove_latest_bundle(self):
# prepare
bundle_dir = self.temp_dir_path / 'dist' / 'test_app'
Expand Down
9 changes: 7 additions & 2 deletions tests/test_repo_cli.py
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,7 @@ def test_get_parser(self):
'init --debug',
'targets add 1.0 c:\\my_bundle_dir c:\\private_keys',
'targets -d add 1.0 c:\\my_bundle_dir c:\\private_keys',
'targets -d add -s 1.0 c:\\my_bundle_dir c:\\private_keys',
'targets remove-latest c:\\private_keys',
'keys my-key-name -c -e',
'keys my-key-name add root c:\\private_keys d:\\more_private_keys',
Expand Down Expand Up @@ -114,13 +115,17 @@ def test__cmd_targets_add(self):
version = '1.0'
bundle_dir = 'dummy'
key_dirs = ['c:\\my_private_keys']
skip_patch = True
options = argparse.Namespace(
app_version=version, bundle_dir=bundle_dir, key_dirs=key_dirs
app_version=version,
bundle_dir=bundle_dir,
key_dirs=key_dirs,
skip_patch=skip_patch,
)
with patch('tufup.repo.cli.Repository', self.mock_repo_class):
tufup.repo.cli._cmd_targets(options=options)
self.mock_repo.add_bundle.assert_called_with(
new_version=version, new_bundle_dir=bundle_dir
new_version=version, new_bundle_dir=bundle_dir, skip_patch=skip_patch,
)
self.mock_repo.publish_changes.assert_called_with(
private_key_dirs=key_dirs
Expand Down

0 comments on commit 17cb4ba

Please sign in to comment.