-
Notifications
You must be signed in to change notification settings - Fork 0
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Create a prototype cli tool called crater. This tool is responsible for creating Hipaacrate files, which store all the information for a given Crate. To support this, create the Crate API, and include tests.
- Loading branch information
Miller Wilt
committed
Jul 24, 2018
1 parent
0aeb2d6
commit 0ae85d5
Showing
8 changed files
with
295 additions
and
1 deletion.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.
Oops, something went wrong.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,4 @@ | ||
from . import crate | ||
from . import version | ||
|
||
__version__ = version.__version__ |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,104 @@ | ||
import hashlib | ||
import os | ||
import tempfile | ||
|
||
import click | ||
from filelock import FileLock, Timeout | ||
|
||
from . import crate | ||
from . import version | ||
|
||
def _get_lock_file_name() -> str: | ||
return os.path.join( | ||
tempfile.gettempdir(), | ||
_hash_cwd(), | ||
) | ||
|
||
def _hash_cwd() -> str: | ||
return hashlib.sha256(os.getcwdb()).hexdigest() | ||
|
||
CRATE_FILE = "Hipaacrate" | ||
LOCK_FILE = FileLock(_get_lock_file_name(), timeout=0.1) | ||
|
||
@click.group() | ||
@click.version_option(version.__version__, prog_name="crater") | ||
def crater(): | ||
pass | ||
|
||
@crater.command() | ||
@click.argument("bundles", nargs=-1, metavar="BUNDLE [BUNDLE]...") | ||
@click.pass_context | ||
def add(ctx, bundles): | ||
if not bundles: | ||
ctx.fail("Expected one or more Bundle name") | ||
|
||
try: | ||
LOCK_FILE.acquire() | ||
c = crate.read_yaml(CRATE_FILE) | ||
except FileNotFoundError: | ||
ctx.fail("Could not open the Hipaacrate file - have you run 'crater init'?") | ||
except Timeout: | ||
ctx.fail("The Hipaacrate file is currently locked - a separate process must be using it") | ||
else: | ||
combined = set(c.bundles) | set(bundles) | ||
c.bundles = list(combined) | ||
c.bundles.sort() | ||
c.to_yaml(CRATE_FILE) | ||
LOCK_FILE.release() | ||
|
||
@crater.command() | ||
@click.option("-n", "--name", prompt=True, help="Crate name", metavar="NAME") | ||
@click.option("-v", "--version", prompt=True, help="Crate version", metavar="VERSION") | ||
@click.pass_context | ||
def init(ctx, name, version) -> None: | ||
try: | ||
LOCK_FILE.acquire() | ||
except Timeout: | ||
ctx.fail("The Hipaacrate file is currently locked - a separate process must be using it") | ||
else: | ||
c = crate.new(name, version) | ||
c.to_yaml(CRATE_FILE) | ||
LOCK_FILE.release() | ||
|
||
@crater.command() | ||
@click.argument("bundles", nargs=-1, metavar="BUNDLE [BUNDLE]...") | ||
@click.pass_context | ||
def remove(ctx, bundles): | ||
if not bundles: | ||
ctx.fail("Expected one or more Bundle name") | ||
|
||
try: | ||
LOCK_FILE.acquire() | ||
c = crate.read_yaml(CRATE_FILE) | ||
except FileNotFoundError: | ||
ctx.fail("Could not open the Hipaacrate file - have you run 'crater init'?") | ||
except Timeout: | ||
ctx.fail("The Hipaacrate file is currently locked - a separate process must be using it") | ||
else: | ||
to_remove = set(bundles) | ||
existing = set(c.bundles) | ||
if not existing >= to_remove: | ||
ctx.fail("No Bundles named {} added".format(", ".join(to_remove - existing))) | ||
else: | ||
c.bundles = list(existing - to_remove) | ||
c.bundles.sort() | ||
c.to_yaml(CRATE_FILE) | ||
LOCK_FILE.release() | ||
|
||
@crater.command() | ||
@click.argument("value", type=click.Choice(["author", "bundles", "name", "version"])) | ||
@click.pass_context | ||
def show(ctx, value) -> None: | ||
try: | ||
LOCK_FILE.acquire() | ||
c = crate.read_yaml(CRATE_FILE) | ||
except FileNotFoundError: | ||
ctx.fail("Could not open the Hipaacrate file - have you run 'crater init'?") | ||
except Timeout: | ||
ctx.fail("The Hipaacrate file is currently locked - a separate process must be using it") | ||
else: | ||
click.echo(getattr(c, value)) | ||
LOCK_FILE.release() | ||
|
||
if __name__ == '__main__': | ||
crater() |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,60 @@ | ||
from typing import Iterable, List | ||
|
||
import yaml | ||
|
||
class Crate(object): | ||
def __init__(self, name: str, version: str, author: str, bundles: List[str]) -> None: | ||
self.author = author | ||
self.bundles = bundles | ||
self.name = name | ||
self.version = version | ||
|
||
def __str__(self) -> str: | ||
return "Crate(name={}, version={}, author={}, bundles={}".format( | ||
self.name, self.version, self.author, self.bundles, | ||
) | ||
|
||
def to_yaml(self, filepath: str = None) -> str: | ||
yaml_text = yaml.safe_dump(dict( | ||
name=self.name, | ||
author=self.author, | ||
version=self.version, | ||
bundles=self.bundles, | ||
), default_flow_style=False) | ||
|
||
if filepath is not None: | ||
with open(filepath, "w") as f: | ||
f.write(yaml_text) | ||
|
||
return yaml_text | ||
|
||
def new(name: str, version: str, author: str = None, bundles: Iterable[str] = None) -> Crate: | ||
""" | ||
Create a new Crate | ||
""" | ||
if author is None: | ||
author = "" | ||
if bundles is None: | ||
bundles = [] | ||
else: | ||
bundles = list(bundles) | ||
return Crate(name=name, version=version, author=author, bundles=bundles) | ||
|
||
def parse(text: str) -> Crate: | ||
""" | ||
Parse and load a Crate from a YAML string | ||
""" | ||
parsed = yaml.safe_load(text) | ||
return Crate( | ||
name=parsed["name"], | ||
version=parsed["version"], | ||
author=parsed.get("author"), | ||
bundles=parsed.get("bundles") | ||
) | ||
|
||
def read_yaml(filepath: str) -> Crate: | ||
""" | ||
Load a Crate from a YAML file | ||
""" | ||
with open(filepath) as f: | ||
return parse(f.read()) |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,3 @@ | ||
"""Declare package version.""" | ||
|
||
__version__ = "0.0.1" |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,89 @@ | ||
import pytest | ||
import yaml | ||
|
||
from hipaacrates import crate | ||
|
||
def test_crate_creation_minimal(): | ||
name = "mycrate" | ||
version = "0.0.1" | ||
|
||
actual = crate.new(name=name, version=version) | ||
assert isinstance(actual, crate.Crate) | ||
|
||
assert actual.name == name | ||
assert actual.version == version | ||
assert actual.bundles == [] | ||
assert actual.author == "" | ||
|
||
def test_crate_creation_with_bundles(): | ||
name = "mycrate" | ||
version = "0.0.1" | ||
bundles = ["mybundle", "foobundle"] | ||
|
||
actual = crate.new(name=name, version=version, bundles=bundles) | ||
assert isinstance(actual, crate.Crate) | ||
|
||
assert actual.name == name | ||
assert actual.version == version | ||
assert actual.bundles == bundles | ||
assert actual.author == "" | ||
|
||
def test_crate_creation_with_author(): | ||
name = "mycrate" | ||
version = "0.0.1" | ||
author = "me" | ||
|
||
actual = crate.new(name=name, version=version, author=author) | ||
assert isinstance(actual, crate.Crate) | ||
|
||
assert actual.name == name | ||
assert actual.version == version | ||
assert actual.bundles == [] | ||
assert actual.author == author | ||
|
||
def test_crate_to_yaml(): | ||
name = "mycrate" | ||
version = "0.0.1" | ||
author = "me" | ||
bundles = ["mybundle", "foobundle"] | ||
|
||
c = crate.new(name=name, version=version, author=author, bundles=bundles) | ||
actual = c.to_yaml() | ||
|
||
items = [s.strip() for s in actual.splitlines()] | ||
assert "name: {}".format(name) in items | ||
assert "version: {}".format(version) in items | ||
assert "author: {}".format(author) in items | ||
assert "bundles:" in items | ||
assert "- mybundle" in items | ||
assert "- foobundle" in items | ||
|
||
@pytest.fixture | ||
def cratetext(): | ||
return """ | ||
name: mycrate | ||
version: 0.0.1 | ||
author: me | ||
bundles: | ||
- mybundle | ||
- foobundle | ||
""" | ||
|
||
def test_crate_parse(cratetext): | ||
c = crate.parse(cratetext) | ||
assert isinstance(c, crate.Crate) | ||
|
||
assert c.name == "mycrate" | ||
assert c.version == "0.0.1" | ||
assert c.author == "me" | ||
assert c.bundles == ["mybundle", "foobundle"] | ||
|
||
def test_read_yaml(tmpdir, cratetext): | ||
p = tmpdir.join("example.yaml") | ||
p.write(cratetext) | ||
|
||
c = crate.read_yaml(str(p)) | ||
assert c.name == "mycrate" | ||
assert c.version == "0.0.1" | ||
assert c.author == "me" | ||
assert c.bundles == ["mybundle", "foobundle"] |