added support for invocation image

master
Gareth Rushgrove 4 years ago
parent 09f1683c8c
commit 90f1d3de62
  1. 21
      README.md
  2. 1
      cnab/__init__.py
  3. 81
      cnab/invocation_image.py
  4. 69
      cnab/test_invocation_image.py
  5. 0
      fixtures/invalidinvocationimage/cnab/INVALID
  6. 0
      fixtures/invalidinvocationimage/cnab/README.txt
  7. 0
      fixtures/invocationimage/cnab/LICENSE
  8. 0
      fixtures/invocationimage/cnab/README.md
  9. 0
      fixtures/invocationimage/cnab/app/run
  10. 2
      pyproject.toml
  11. 2
      pytest.ini

@ -100,6 +100,27 @@ with open("/home/garethr/.kube/config") as f:
Note that error handling for this is very work-in-progress.
## Working with invocation images
`pycnab` also has a class for working with invocation images.
```python
from cnab import CNABDirectory
directory = CNABDirectory("fixtures/invocationimage")
# Check whether the directory is valid
# Raises `InvalidCNABDirectory` exception if invalid
directory.valid()
# Returns the text of the associated README file if present
directory.readme()
# Returns the text of the associated LICENSE file if present
directory.license()
```
## Thanks
Thanks to [QuickType](https://quicktype.io/) for bootstrapping the creation of the Python code for manipulating `bundle.json` based on the current JSON Schema.

@ -12,3 +12,4 @@ from cnab.types import (
Bundle,
)
from cnab.cnab import CNAB
from cnab.invocation_image import CNABDirectory

@ -0,0 +1,81 @@
import os
from typing import Union
class InvalidCNABDirectoryError(Exception):
pass
class CNABDirectory(object):
path: str
def __init__(self, path: str):
self.path = path
def has_cnab_directory(self) -> bool:
cnab = os.path.join(self.path, "cnab")
return os.path.isdir(cnab)
def has_app_directory(self) -> bool:
app = os.path.join(self.path, "cnab", "app")
return os.path.isdir(app)
def has_no_misc_files_in_cnab_dir(self) -> bool:
cnab = os.path.join(self.path, "cnab")
for root, dirs, files in os.walk(cnab):
disallowed_dirs = [x for x in dirs if x not in ["app", "build"]]
disallowed_files = [
x for x in files if x not in ["LICENSE", "README.md", "README.txt"]
]
break
if disallowed_dirs or disallowed_files:
return False
else:
return True
def has_run(self) -> bool:
run = os.path.join(self.path, "cnab", "app", "run")
return os.path.isfile(run)
def has_executable_run(self) -> bool:
run = os.path.join(self.path, "cnab", "app", "run")
return os.access(run, os.X_OK)
def readme(self) -> Union[bool, str]:
readme = os.path.join(self.path, "cnab", "README")
txt = readme + ".txt"
md = readme + ".md"
if os.path.isfile(txt):
with open(txt, "r") as content:
return content.read()
elif os.path.isfile(md):
with open(md, "r") as content:
return content.read()
else:
return False
def license(self) -> Union[bool, str]:
license = os.path.join(self.path, "cnab", "LICENSE")
if os.path.isfile(license):
with open(license, "r") as content:
return content.read()
else:
return False
def valid(self) -> bool:
errors = []
if not self.has_executable_run():
errors.append("Run entrypoint is not executable")
if not self.has_run():
errors.append("Missing a run entrypoint")
if not self.has_app_directory():
errors.append("Missing the app directory")
if not self.has_cnab_directory():
errors.append("Missing the cnab directory")
if not self.has_no_misc_files_in_cnab_dir():
errors.append("Has additional files in the cnab directory")
if len(errors) == 0:
return True
else:
raise InvalidCNABDirectoryError(errors)

@ -0,0 +1,69 @@
import pytest # type: ignore
from cnab import CNABDirectory
from cnab.invocation_image import InvalidCNABDirectoryError
class SampleCNAB(object):
@pytest.fixture
def directory(self):
return CNABDirectory("fixtures/invocationimage")
class TestCNABDirectory(SampleCNAB):
def test_has_app_dir(self, directory):
assert directory.has_app_directory()
def test_has_cnab_dir(self, directory):
assert directory.has_cnab_directory()
def test_has_readme(self, directory):
assert isinstance(directory.readme(), str)
def test_has_license(self, directory):
assert isinstance(directory.license(), str)
def test_has_no_misc_files(self, directory):
assert directory.has_no_misc_files_in_cnab_dir()
def test_has_run(self, directory):
assert directory.has_run()
def test_has_executable(self, directory):
assert directory.has_executable_run()
def test_is_valid(self, directory):
assert directory.valid()
class InvalidCNAB(object):
@pytest.fixture
def directory(self):
return CNABDirectory("fixtures/invalidinvocationimage")
class TestInvalidCNABDirectory(InvalidCNAB):
def test_has_no_app_dir(self, directory):
assert not directory.has_app_directory()
def test_has_cnab_dir(self, directory):
assert directory.has_cnab_directory()
def test_has_readme(self, directory):
assert isinstance(directory.readme(), str)
def test_has_no_license(self, directory):
assert not directory.license()
def test_has_invalid_misc_files(self, directory):
assert not directory.has_no_misc_files_in_cnab_dir()
def test_has_no_run(self, directory):
assert not directory.has_run()
def test_has_no_executable(self, directory):
assert not directory.has_executable_run()
def test_is_invalid(self, directory):
with pytest.raises(InvalidCNABDirectoryError):
directory.valid()

@ -1,6 +1,6 @@
[tool.poetry]
name = "cnab"
version = "0.1.4"
version = "0.1.5"
description = "A module for working with Cloud Native Application Bundles in Python"
authors = ["Gareth Rushgrove <gareth@morethanseven.net>"]
license = "Apache-2.0"

@ -1,5 +1,7 @@
[pytest]
addopts = --black --mypy --verbose --ignore scratch --cov=cnab --cov-report term-missing
filterwarnings =
ignore::DeprecationWarning
markers =
docker: tests which rely on Docker

Loading…
Cancel
Save