Skip to content

Commit

Permalink
fix(doc): add license and readme support to folders
Browse files Browse the repository at this point in the history
These resources are zipped with the object definition and will be written down in the
`.dependencies` folder also.

fix #92
  • Loading branch information
AntoineDao committed Jun 2, 2020
1 parent 17f35af commit 9b78c69
Show file tree
Hide file tree
Showing 6 changed files with 115 additions and 15 deletions.
12 changes: 11 additions & 1 deletion queenbee/cli/operator/new.py
Original file line number Diff line number Diff line change
Expand Up @@ -76,7 +76,17 @@ def new(name, path):

operator = Operator.parse_obj(input_dict)

# Readme
readme_string = f"""
# {name} Operator
A Queenbee Operator.
"""

# Create entire path to folder if it does not exist
os.makedirs(folder_path, exist_ok=True)

operator.to_folder(folder_path=folder_path)
operator.to_folder(
folder_path=folder_path,
readme_string=readme_string,
)
12 changes: 11 additions & 1 deletion queenbee/cli/recipe/new.py
Original file line number Diff line number Diff line change
Expand Up @@ -83,7 +83,17 @@ def new(name, path):

recipe = Recipe.parse_obj(input_dict)

# Readme
readme_string = f"""
# {name} Recipe
A Queenbee Recipe.
"""

# Create entire path to folder if it does not exist
os.makedirs(folder_path, exist_ok=True)

recipe.to_folder(folder_path=folder_path)
recipe.to_folder(
folder_path=folder_path,
readme_string=readme_string,
)
14 changes: 13 additions & 1 deletion queenbee/operator/operator.py
Original file line number Diff line number Diff line change
Expand Up @@ -137,7 +137,7 @@ def from_folder(cls, folder_path: str):

return cls.parse_obj(operator)

def to_folder(self, folder_path: str):
def to_folder(self, folder_path: str, readme_string: str = None, license_string: str = None):
"""Write an Operator to a folder
Note:
Expand All @@ -155,6 +155,10 @@ def to_folder(self, folder_path: str):
Arguments:
folder_path {str} -- Path to write the folder to
Keyword Arguments:
readme_string {str} -- The README file string (default: {None})
license_string {str} -- The LICENSE file string (default: {None})
"""
os.makedirs(os.path.join(folder_path, 'functions'))

Expand All @@ -170,3 +174,11 @@ def to_folder(self, folder_path: str):
os.path.join(folder_path, 'functions', f'{function.name}.yaml'),
exclude_unset=True
)

if readme_string is not None:
with open(os.path.join(folder_path, 'README.md'), 'w') as f:
f.write(readme_string)

if license_string is not None:
with open(os.path.join(folder_path, 'LICENSE'), 'w') as f:
f.write(license_string)
16 changes: 14 additions & 2 deletions queenbee/recipe/dependency.py
Original file line number Diff line number Diff line change
Expand Up @@ -157,6 +157,10 @@ def fetch(self, verifydigest: bool = True) -> Tuple[bytes, str]:

tar = tarfile.open(fileobj=filebytes)

file_bytes = None
readme_string = None
license_string = None

for member in tar.getmembers():
if member.name == 'resource.json':
file_bytes = tar.extractfile(member).read()
Expand All @@ -169,10 +173,18 @@ def fetch(self, verifydigest: bool = True) -> Tuple[bytes, str]:
f' {hashlib.sha256(file_bytes).hexdigest()}'
)
break
else:

elif member.name == 'README.md':
readme_string = tar.extractfile(member).read().decode('utf-8')
elif member.name == 'LICENSE':
license_string = tar.extractfile(member).read().decode('utf-8')

if file_bytes is None:
raise ValueError(
'package tar file did not contain a resource.json file so could not be'
' decoded.'
)

return file_bytes, self.digest


return file_bytes, self.digest, readme_string, license_string
24 changes: 19 additions & 5 deletions queenbee/recipe/recipe.py
Original file line number Diff line number Diff line change
Expand Up @@ -255,7 +255,7 @@ def write_dependency_file(self, folder_path: str):
)
)

def to_folder(self, folder_path: str):
def to_folder(self, folder_path: str, readme_string: str = None, license_string: str = None):
"""Write a Recipe to a folder
Note:
Expand Down Expand Up @@ -288,6 +288,10 @@ def to_folder(self, folder_path: str):
Arguments:
folder_path {str} -- The path to the Recipe folder
Keyword Arguments:
readme_string {str} -- The README file string (default: {None})
license_string {str} -- The LICENSE file string (default: {None})
"""

os.makedirs(os.path.join(folder_path, 'flow'))
Expand All @@ -304,6 +308,14 @@ def to_folder(self, folder_path: str):
exclude_unset=True
)

if readme_string is not None:
with open(os.path.join(folder_path, 'README.md'), 'w') as f:
f.write(readme_string)

if license_string is not None:
with open(os.path.join(folder_path, 'LICENSE'), 'w') as f:
f.write(license_string)

def write_dependencies(self, folder_path: str):
"""Fetch dependencies manifests and write them to the `.dependencies` folder
Expand All @@ -325,16 +337,18 @@ def write_dependencies(self, folder_path: str):

for dependency in self.dependencies:
if dependency.type == DependencyType.operator:
raw_dep, digest = dependency.fetch()
raw_dep, digest, readme_string, license_string = dependency.fetch()
dep = Operator.parse_raw(raw_dep)

elif dependency.type == DependencyType.recipe:
raw_dep, digest = dependency.fetch()
raw_dep, digest, readme_string, license_string = dependency.fetch()
dep = self.__class__.parse_raw(raw_dep)
dep.write_dependencies(folder_path)

dep.to_folder(
folder_path=os.path.join(folder_path, '.dependencies', dependency.type, dependency.ref_name)
folder_path=os.path.join(folder_path, '.dependencies', dependency.type, dependency.ref_name),
readme_string=readme_string,
license_string=license_string,
)


Expand Down Expand Up @@ -378,7 +392,7 @@ def from_recipe(cls, recipe: Recipe):
templates = []

for dependency in recipe.dependencies:
dep_bytes, dep_hash = dependency.fetch()
dep_bytes, dep_hash, _, _ = dependency.fetch()

if dependency.type == 'recipe':
dep = Recipe.parse_raw(dep_bytes)
Expand Down
52 changes: 47 additions & 5 deletions queenbee/repository/package.py
Original file line number Diff line number Diff line change
Expand Up @@ -67,7 +67,9 @@ def from_resource(cls, resource: Union[Operator, Recipe], package_path: str = No

@classmethod
def _package_resource(cls, resource: Union[Operator, Recipe], repo_folder: str,
path_to_readme: str = None, overwrite: bool = False):
path_to_readme: str = None, path_to_license: str = None,
overwrite: bool = False
):
"""Package a resource into a gzipped tar archive
Arguments:
Expand All @@ -78,6 +80,8 @@ def _package_resource(cls, resource: Union[Operator, Recipe], repo_folder: str,
Keyword Arguments:
path_to_readme {str} -- Path to the resource README.md file if it exists
(default: {None})
path_to_license {str} -- Path to the resource LICENSE file if it exists
(default: {None})
overwrite {bool} -- Overwrite a package with the same name (default: {False})
Raises:
Expand Down Expand Up @@ -119,6 +123,12 @@ def _package_resource(cls, resource: Union[Operator, Recipe], repo_folder: str,
filter=reset_tar
)

if path_to_license is not None:
tar.add(
os.path.abspath(path_to_license), arcname='LICENSE',
filter=reset_tar
)

tar.close()

# Delete original resource file
Expand Down Expand Up @@ -173,13 +183,36 @@ def path_to_readme(folder_path: str) -> str:

return path_to_readme

@staticmethod
def path_to_license(folder_path: str) -> str:
"""Infer the path to the license file within a folder
Arguments:
folder_path {str} -- Path to the folder where a license file should be found
Returns:
str -- Path to the found license file (or None if no license file is found)
"""
path_to_license = None

license_pattern = r'^license$'

for file in os.listdir(folder_path):
res = re.match(license_pattern, file, re.IGNORECASE)
if res is not None:
path_to_license = os.path.join(folder_path, file)

return path_to_license


class OperatorVersion(ResourceVersion, OperatorMetadata):
"""A version of an Operator"""

@classmethod
def package_resource(cls, resource: Operator, repo_folder: str,
path_to_readme: str = None, overwrite: bool = False):
path_to_readme: str = None, path_to_license: str = None,
overwrite: bool = False
):
"""Package an Operator into a gzipped tar file
Arguments:
Expand All @@ -190,6 +223,8 @@ def package_resource(cls, resource: Operator, repo_folder: str,
Keyword Arguments:
path_to_readme {str} -- Path to the operator README.md file if it exists
(default: {None})
path_to_license {str} -- Path to the resource LICENSE file if it exists
(default: {None})
overwrite {bool} -- Overwrite an operator with the same name
(default: {False})
Expand All @@ -198,7 +233,8 @@ def package_resource(cls, resource: Operator, repo_folder: str,
"""
return cls._package_resource(
resource=resource, repo_folder=repo_folder,
path_to_readme=path_to_readme, overwrite=overwrite
path_to_readme=path_to_readme, path_to_license=path_to_license,
overwrite=overwrite
)

@classmethod
Expand All @@ -223,6 +259,7 @@ def package_folder(cls, folder_path: str, repo_folder: str, overwrite: bool = Tr
resource=resource,
repo_folder=repo_folder,
path_to_readme=cls.path_to_readme(folder_path),
path_to_license=cls.path_to_license(folder_path),
overwrite=overwrite,
)

Expand All @@ -232,7 +269,9 @@ class RecipeVersion(ResourceVersion, RecipeMetadata):
@classmethod
def package_resource(
cls, resource: Recipe, repo_folder: str, check_deps: bool = True,
path_to_readme: str = None, overwrite: bool = False):
path_to_readme: str = None, path_to_license: str = None,
overwrite: bool = False
):
"""Package an Recipe into a gzipped tar file
Arguments:
Expand All @@ -245,6 +284,8 @@ def package_resource(
the recipe by baking it (default: {True})
path_to_readme {str} -- Path to the recipe README.md file if it exists
(default: {None})
path_to_license {str} -- Path to the resource LICENSE file if it exists
(default: {None})
overwrite {bool} -- Overwrite an recipe with the same name (default: {False})
Returns:
Expand All @@ -255,7 +296,7 @@ def package_resource(

return cls._package_resource(
resource=resource, repo_folder=repo_folder, path_to_readme=path_to_readme,
overwrite=overwrite
path_to_license=path_to_license, overwrite=overwrite
)

@classmethod
Expand Down Expand Up @@ -283,5 +324,6 @@ def package_folder(cls, folder_path: str, repo_folder: str, check_deps: bool = T
repo_folder=repo_folder,
check_deps=check_deps,
path_to_readme=cls.path_to_readme(folder_path),
path_to_license=cls.path_to_license(folder_path),
overwrite=overwrite,
)

0 comments on commit 9b78c69

Please sign in to comment.