Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Cat Command #19

Merged
merged 3 commits into from
Jul 14, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
10 changes: 10 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,16 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0

## [Unreleased]

### Added

* Added `cat` command: Users can now see the source of an `install.cfg` file with `ibi cat`.


### Changed

* Switched to sandboxed rendering of template for security purposes.


## [0.4.0] - 2024-06-24

### Added
Expand Down
11 changes: 10 additions & 1 deletion README.md
Original file line number Diff line number Diff line change
Expand Up @@ -62,6 +62,7 @@ Options:
-h, --help Show this message and exit.

Commands:
cat Shows source of installation instructions config file.
install Installs with config and parameters given.
show Shows installation instructions for your specified config file...
```
Expand Down Expand Up @@ -91,7 +92,6 @@ Options are dynamically created with the schema part of the config file.
2. Add `pretty` and `description` keys.
3. Create lists like `key: Pretty Key`.
* `title` and `description` from within the schema overwrite `pretty` and `description` outside of the schema.
* For the package to set the default os to the running system, name the property `__os__`.

```yaml
schema:
Expand All @@ -110,6 +110,15 @@ description:
pip: Standard python package manager.
```

* For the package to set the default os to the running system, name the property `__os__`.

```yaml
__os__:
- windows
- linux
- macos
```


### Template

Expand Down
36 changes: 11 additions & 25 deletions installation_instruction/__main__.py
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,6 @@
# limitations under the License.

from sys import exit
from os.path import isfile, isdir
from subprocess import run
import platform

Expand All @@ -22,7 +21,7 @@
from .__init__ import __version__, __description__, __repository__, __author__, __author_email__, __license__
from .get_flags_and_options_from_schema import _get_flags_and_options
from .installation_instruction import InstallationInstruction
from .helpers import _make_pretty_print_line_breaks, _is_remote_git_repository, _clone_git_repo, _config_file_is_in_folder
from .helpers import _make_pretty_print_line_breaks, _red_echo, _get_install_config_file


VERSION_STRING = f"""Version: installation-instruction {__version__}
Expand Down Expand Up @@ -54,9 +53,6 @@ def _get_system(option_types):

return None

def _red_echo(text: str):
click.echo(click.style(text, fg="red"))


class ConfigReadCommand(click.MultiCommand):
"""
Expand All @@ -74,26 +70,7 @@ def __init__(self, *args, **kwargs):

def get_command(self, ctx, config_file: str) -> click.Command|None:

temp_dir = None
if _is_remote_git_repository(config_file):
try:
temp_dir = _clone_git_repo(config_file)
except Exception as e:
_red_echo("Error (cloning git repository):\n\n" + str(e))
exit(1)
config_file = temp_dir.name
if isdir(config_file):
if path := _config_file_is_in_folder(config_file):
config_file = path
else:
if temp_dir is not None:
_red_echo("Config file not found in repository.")
else:
_red_echo(f"Config file not found in folder {config_file}")
exit(1)
if not isfile(config_file):
_red_echo(f"{config_file} is not a file.")
exit(1)
(_temp_dir, config_file) = _get_install_config_file(config_file)

try:
instruction = InstallationInstruction.from_file(config_file)
Expand Down Expand Up @@ -138,6 +115,14 @@ def callback(**kwargs):
callback=callback,
)

@click.command(help="Shows source of installation instructions config file.")
@click.argument("path")
def cat(path):
(_temp_dir, config_file) = _get_install_config_file(path)
with open(config_file, "r") as file:
config_string = file.read()
print(config_string)

@click.command(cls=ConfigReadCommand, help="Shows installation instructions for your specified config file and parameters.")
@click.option("--raw", is_flag=True, help="Show installation instructions without pretty print.", default=False)
@click.pass_context
Expand All @@ -158,6 +143,7 @@ def install(ctx, verbose):
def main(ctx):
ctx.ensure_object(dict)

main.add_command(cat)
main.add_command(show)
main.add_command(install)

Expand Down
48 changes: 44 additions & 4 deletions installation_instruction/helpers.py
Original file line number Diff line number Diff line change
Expand Up @@ -13,16 +13,23 @@
# See the License for the specific language governing permissions and
# limitations under the License.

from tempfile import TemporaryDirectory
import os.path
from os.path import isfile, isdir
import re
from jinja2 import Environment, Template

from jinja2 import Template
from jinja2.sandbox import SandboxedEnvironment

import click
import git
from tempfile import TemporaryDirectory
import os.path

CONFIG_FILE_NAME = "install.cfg"
ALLOWED_GIT_URL_PREFIXES = ["http://", "https://", "git://", "ssh://", "ftp://", "ftps://"]

def _red_echo(text: str):
click.echo(click.style(text, fg="red"))

Check warning on line 31 in installation_instruction/helpers.py

View check run for this annotation

Codecov / codecov/patch

installation_instruction/helpers.py#L31

Added line #L31 was not covered by tests

def _is_remote_git_repository(url: str) -> bool:
"""
Checks if the given URL might be a remote git repository.
Expand Down Expand Up @@ -63,6 +70,39 @@
return install_cfg_path
return None

def _get_install_config_file(path: str) -> tuple[TemporaryDirectory|None, str]:
"""
Checks wether path is a git url or a dir, finds the config file and asserts that said file is a file.

:param path: Url, path to dir or file.
:type path: str
:return: Returns a tuple with a temporary dir needed for cloning a git repository (on distruction temporary dir is deleted), and the found config file path.
:rtype: tuple[TemporaryDirectory|None, str]
"""
config_file = path
temp_dir = None
if _is_remote_git_repository(config_file):
try:
temp_dir = _clone_git_repo(config_file)
except Exception as e:
_red_echo("Error (cloning git repository):\n\n" + str(e))
exit(1)
config_file = temp_dir.name
if isdir(config_file):
if path := _config_file_is_in_folder(config_file):
config_file = path

Check warning on line 93 in installation_instruction/helpers.py

View check run for this annotation

Codecov / codecov/patch

installation_instruction/helpers.py#L82-L93

Added lines #L82 - L93 were not covered by tests
else:
if temp_dir is not None:
_red_echo("Config file not found in repository.")

Check warning on line 96 in installation_instruction/helpers.py

View check run for this annotation

Codecov / codecov/patch

installation_instruction/helpers.py#L95-L96

Added lines #L95 - L96 were not covered by tests
else:
_red_echo(f"Config file not found in folder {config_file}")
exit(1)
if not isfile(config_file):
_red_echo(f"{config_file} is not a file.")
exit(1)

Check warning on line 102 in installation_instruction/helpers.py

View check run for this annotation

Codecov / codecov/patch

installation_instruction/helpers.py#L98-L102

Added lines #L98 - L102 were not covered by tests

return (temp_dir, config_file)

Check warning on line 104 in installation_instruction/helpers.py

View check run for this annotation

Codecov / codecov/patch

installation_instruction/helpers.py#L104

Added line #L104 was not covered by tests

def _make_pretty_print_line_breaks(string: str) -> str:
"""
Replaces `&& ` with a newline character.
Expand Down Expand Up @@ -128,7 +168,7 @@
:return: jinja2 Template object.
:rtype: jinja2.Template
"""
env = Environment(
env = SandboxedEnvironment(
trim_blocks=True,
lstrip_blocks=True
)
Expand Down
1 change: 0 additions & 1 deletion installation_instruction/installation_instruction.py
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,6 @@
from yaml import safe_load
import json
from jsonschema import validate, Draft202012Validator, exceptions
from jinja2 import Environment, Template
from jinja2.exceptions import UndefinedError

import installation_instruction.helpers as helpers
Expand Down