Skip to content

Commit

Permalink
Bugfixes to output
Browse files Browse the repository at this point in the history
  • Loading branch information
mverteuil committed Feb 22, 2020
1 parent 3f572d7 commit d83acd2
Show file tree
Hide file tree
Showing 4 changed files with 52 additions and 48 deletions.
16 changes: 7 additions & 9 deletions barbara/cli.py
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
import os
from pathlib import Path

import click
import poetry_version
Expand All @@ -16,30 +17,27 @@
type=click.BOOL,
help="Skip over any keys which already exist in the destination file",
)
@click.option("-d", "--destination", default="", type=str, help="Destination for serialized environment variables")
@click.option(
"-t", "--template", default="env-template.yml", type=click.File(), help="Source for environment and default values"
)
@click.option("-o", "--output", default=".env", type=Path, help="Destination for env-file")
@click.option("-t", "--template", default="env-template.yml", type=Path, help="Template for environment variables")
@click.option(
"-z", "--zero-input", is_flag=True, help="Skip prompts and use presets verbatim. Useful for CI environments."
)
@click.version_option(poetry_version.extract(source_file=__file__))
def barbara_develop(skip_existing, destination, template, zero_input):
def barbara_develop(skip_existing, output, template, zero_input):
"""Development mode which prompts for user input"""
if zero_input:
destination = ".env"
destination_handler = create_target_file
merge_strategy = merge_with_presets
else:
destination_handler = confirm_target_file
merge_strategy = merge_with_prompts

confirmed_target = destination if os.path.exists(destination) else destination_handler(destination)
confirmed_target = Path(output if output.exists() else destination_handler(output))

click.echo(f"Creating environment: {confirmed_target}")

TemplateReader = readers.get_reader(template)
environment_template = TemplateReader(template).read()
template_reader_class = readers.get_reader(template)
environment_template = template_reader_class(template).read()
existing_environment = readers.EnvReader(confirmed_target).read()
click.echo(f"Skip Existing: {skip_existing}")

Expand Down
20 changes: 12 additions & 8 deletions barbara/readers.py
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
import re
from collections import OrderedDict
from fnmatch import fnmatch
from functools import partial
from pathlib import Path
from typing import Dict, TextIO, Type, Union

import yaml
Expand All @@ -19,7 +19,7 @@ def __init_subclass__(cls, **kwargs):
TEMPLATE_READERS.append(cls)


def get_reader(file_or_name: Union[str, TextIO]) -> Type:
def get_reader(file_or_name: Path) -> Type:
"""Guess which reader to return using naive file-type check"""
filename = getattr(file_or_name, "name", file_or_name)
filename_matcher = partial(fnmatch, filename)
Expand Down Expand Up @@ -53,13 +53,17 @@ class YAMLTemplateReader(BaseTemplateReader):
def __init__(self, source: TextIO) -> None:
self.source = source

def _read(self) -> OrderedDict:
def _read(self) -> Dict:
"""Check configuration file for acceptable versions."""
source = yaml.safe_load(self.source.read())
if re.match(self.SCHEMA_VERSION_MATCH, str(source.get("schema-version", "NONE"))):
return source
else:
raise FileError(f"Version mismatch. Required 2, found: {source['schema-version']}")
source = yaml.safe_load(Path(self.source).read_text())
assert source, self.source
try:
if re.match(self.SCHEMA_VERSION_MATCH, str(source["schema-version"])):
return source
else:
raise TypeError
except TypeError:
raise TypeError(f"Version mismatch. Required 2, found: {source.get('schema-version')}")

def read(self) -> Dict[str, str]:
template = self._read()
Expand Down
23 changes: 12 additions & 11 deletions barbara/utils.py
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
import os
import sys
from collections import OrderedDict
from pathlib import Path
from typing import Dict

import click
from dotenv import find_dotenv
Expand All @@ -13,7 +14,7 @@
EMPTY = object()


def confirm_target_file(target_file: str = None) -> bool:
def confirm_target_file(target_file: Path = None) -> bool:
"""Determines which target file to use.
Strategy progresses as follows:
Expand All @@ -22,20 +23,20 @@ def confirm_target_file(target_file: str = None) -> bool:
- Offer to create one
- Quit
"""
target_file = target_file or find_dotenv() or DEFAULT_ENV_FILENAME
target_file = Path(target_file or find_dotenv() or DEFAULT_ENV_FILENAME)

if os.path.exists(target_file):
return click.prompt("Destination file", default=target_file)
if target_file.exists():
return click.prompt("Destination file", default=target_file.relative_to(os.getcwd()))
elif click.confirm(f"{target_file} does not exist. Create it?"):
return create_target_file(target_file)
else:
click.echo("Cannot continue without target file", color="R")
sys.exit(1)


def create_target_file(target_file: str = None) -> bool:
def create_target_file(target_file: Path = None) -> bool:
"""Creates an empty file at the target."""
click.open_file(target_file, "w").close()
target_file.touch()
return target_file


Expand All @@ -53,7 +54,7 @@ def prompt_user_for_value(env_variable) -> str:
return click.prompt(env_variable.name, default=env_variable.preset, type=str)


def merge_with_presets(existing: OrderedDict, template: OrderedDict, skip_existing: bool) -> OrderedDict:
def merge_with_presets(existing: Dict, template: Dict, skip_existing: bool) -> Dict:
"""Merge two ordered dicts and uses the presets for values along the way
If skipping existing keys, only newly discovered keys will be added. Once a key exists, the existing
Expand All @@ -77,10 +78,10 @@ def merge_with_presets(existing: OrderedDict, template: OrderedDict, skip_existi
else:
merged[key] = existing_value.template.format(**{k: v for k, v in existing_value.subvariables})

return OrderedDict(sorted(merged.items()))
return dict(sorted(merged.items()))


def merge_with_prompts(existing: OrderedDict, template: OrderedDict, skip_existing: bool) -> OrderedDict:
def merge_with_prompts(existing: Dict, template: Dict, skip_existing: bool) -> Dict:
"""Merge two ordered dicts and prompts the user for values along the way
If skipping existing keys, only newly discovered keys will be prompted for. Once a key exists, the existing
Expand All @@ -97,4 +98,4 @@ def merge_with_prompts(existing: OrderedDict, template: OrderedDict, skip_existi
preset = EnvVariable(key, existing.get(key)) if key in existing else template.get(key)
merged[key] = prompt_user_for_value(preset)

return OrderedDict(sorted(merged.items()))
return dict(sorted(merged.items()))
41 changes: 21 additions & 20 deletions pyproject.toml
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
[tool.poetry]
name = "barbara"
version = "2.0.0"
version = "2.0.1"
description = "Environment variable management"
authors = ["Matthew de Verteuil <onceuponajooks@gmail.com>"]
license = "GPL-3.0"
Expand All @@ -21,25 +21,6 @@ packages = [
{ include = "barbara" },
]

[tool.black]
line-length = 120
target-version = ['py36', 'py37', 'py38']
exclude = '''
/(
\.eggs
| \.git
| \.hg
| \.mypy_cache
| \.tox
| \.venv
| _build
| buck-out
| build
| dist
| setup.py
)/
'''

[tool.poetry.dependencies]
python = "==3.*,>=3.6.0"
click = "==7.*,>=7.0.0"
Expand All @@ -64,6 +45,26 @@ skip = "setup.py"
use_parentheses = true
verbose = true

[tool.black]
line-length = 120
target-version = ['py36', 'py37', 'py38']
exclude = '''
/(
\.eggs
| \.git
| \.hg
| \.mypy_cache
| \.tox
| \.venv
| _build
| buck-out
| build
| dist
| setup.py
)/
'''


[build-system]
requires = ["poetry>=0.12.16"]
build-backend = "poetry.masonry.api"

0 comments on commit d83acd2

Please sign in to comment.