Skip to content

Commit

Permalink
Add environments and more utils
Browse files Browse the repository at this point in the history
  • Loading branch information
neoxelox committed Apr 6, 2022
1 parent bd4c162 commit aa2a553
Show file tree
Hide file tree
Showing 12 changed files with 248 additions and 42 deletions.
6 changes: 3 additions & 3 deletions superinvoke/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -4,8 +4,8 @@

import invoke

from .constants import Directories, Platforms, console
from . import utils
from .constants import Paths, Platforms, console
from .extensions.task import task
from .main import init
from .objects import Tags, Tool, Tools
from .utils import path
from .objects import Env, Envs, Tags, Tool, Tools
2 changes: 1 addition & 1 deletion superinvoke/collections/__init__.py
Original file line number Diff line number Diff line change
@@ -1 +1 @@
from . import misc, tool
from . import env, misc, tool
50 changes: 50 additions & 0 deletions superinvoke/collections/env.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,50 @@
from invoke import task
from rich.table import Table

from .. import constants, utils


@task(default=True)
def list(context):
"""List available enviroments."""
from ..main import __ENVS__

table = Table(show_header=True, header_style="bold white")
table.add_column("Name", justify="left")
table.add_column("Tags", style="dim", justify="right")

for env in __ENVS__.All:
table.add_row(
f"[bold green3]{env.name}[/bold green3]" if env == __ENVS__.Current else env.name,
", ".join(env.tags),
)

constants.console.print("Listing [bold green3]current[/bold green3] and other enviroments:\n")
constants.console.print(table)


@task(
help={
"enviroment": "Environment name to switch to. Example: dev",
}
)
def switch(context, enviroment):
"""Switch current environment."""
from ..main import __ENVS__

new_env = __ENVS__.ByName(enviroment)
old_env = __ENVS__.Current

if not new_env:
context.fail(f"{enviroment} is not a valid enviroment")

if new_env == old_env:
context.info(f"{enviroment} is already the current enviroment")
return

context.create(utils.path(constants.Paths.ENV), data=[new_env], dir=False)

if new_env != __ENVS__.Current:
context.fail(f"Cannot switch to enviroment {enviroment}")

context.print(f"Switched to enviroment [green3]{new_env}[/green3] from {old_env}")
2 changes: 1 addition & 1 deletion superinvoke/collections/tool.py
Original file line number Diff line number Diff line change
Expand Up @@ -134,7 +134,7 @@ def install(context, include, exclude="", yes=False):

with tempfile.TemporaryDirectory() as TMP:
TMP = utils.path(TMP)
context.create(utils.path(constants.Directories.TOOLS), dir=True)
context.create(utils.path(constants.Paths.TOOLS), dir=True)

for tool in tools:
if not context.has(tool, version=tool.version):
Expand Down
11 changes: 8 additions & 3 deletions superinvoke/constants.py
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@


# Different OS Platforms.
# TODO: Add architechtures.
class Platforms(utils.StrEnum):
LINUX = "linux"
WINDOWS = "win32"
Expand All @@ -16,13 +17,17 @@ def CURRENT(cls):
return Platforms(sys.platform)


# Different superinvoke directories.
class Directories(utils.StrEnum):
# Different superinvoke paths.
class Paths(utils.StrEnum):
CACHE = ".superinvoke_cache"

@utils.classproperty
def TOOLS(cls):
return f"{Directories.CACHE}/tools"
return f"{Paths.CACHE}/tools"

@utils.classproperty
def ENV(cls):
return f"{Paths.CACHE}/env"


# Global console instance.
Expand Down
38 changes: 22 additions & 16 deletions superinvoke/extensions/context.py
Original file line number Diff line number Diff line change
@@ -1,12 +1,9 @@
import os
import shutil
import sys
from typing import List, Optional
from typing import List, Literal, Optional

from download import download as fetch
from invoke.context import Context

from .. import constants
from .. import constants, utils


# Writes to stdout and flushes.
Expand Down Expand Up @@ -97,40 +94,47 @@ def changes(context: Context, scope: int = 1) -> List[str]:
# FILE DIR
# - copy
# - move X X
# - create X
# - create X X
# - remove
# - read
# - read X -
# - write
# - exists X X
# - extract X X
# - download X X

# Creates a file or a directory in the specified path.
def create(context: Context, path: str, data: List[str] = [""], dir: bool = False) -> None:
if dir:
os.makedirs(str(path), exist_ok=True)
utils.create(path, data, dir=dir)


# Reads a file in the specified path.
def read(context: Context, path: str) -> List[str]:
return utils.read(path)


# Checks if the specified path exists and whether it is a file or a directory.
def exists(context: Context, path: str) -> Optional[Literal["file", "dir"]]:
return utils.exists(path)


# Moves a file or a directory to the specified path.
def move(context: Context, source_path: str, dest_path: str) -> None:
shutil.move(str(source_path), str(dest_path))
utils.move(source_path, dest_path)


# Removes a file or a directory in the specified path.
def remove(context: Context, path: str, dir: bool = False) -> None:
if dir:
shutil.rmtree(str(path))
else:
os.remove(str(path))
utils.remove(path, dir=dir)


# Extracts a zip, tar, gztar, bztar, or xztar file in the specified path.
def extract(context: Context, source_path: str, dest_path: str) -> None:
shutil.unpack_archive(str(source_path), str(dest_path))
utils.extract(source_path, dest_path)


# Downloads a file to the specified path.
def download(context: Context, url: str, path: str) -> None:
fetch(str(url), str(path), progressbar=False, replace=True, verbose=False)
utils.download(url, path)


# Extends Pyinvoke's Context methods.
Expand All @@ -148,6 +152,8 @@ def init() -> None:
Context.branch = branch
Context.changes = changes
Context.create = create
Context.read = read
Context.exists = exists
Context.move = move
Context.remove = remove
Context.extract = extract
Expand Down
34 changes: 24 additions & 10 deletions superinvoke/main.py
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
import os
from typing import Optional

from invoke import Collection

Expand All @@ -7,9 +8,14 @@


# Superinvoke root collection initialization.
def init(tools: objects.Tools) -> Collection:
global __TOOLS__
__TOOLS__ = tools
def init(tools: Optional[objects.Tools] = None, envs: Optional[objects.Envs] = None) -> Collection:
if tools:
global __TOOLS__
__TOOLS__ = tools

if envs:
global __ENVS__
__ENVS__ = envs

context.init()

Expand All @@ -23,12 +29,20 @@ def init(tools: objects.Tools) -> Collection:
})
root.add_task(collections.misc.help)

# Tool collection
tool = Collection()
tool.add_task(collections.tool.install)
tool.add_task(collections.tool.list)
tool.add_task(collections.tool.remove)
tool.add_task(collections.tool.run)
root.add_collection(tool, name="tool")
if tools:
# Tool collection
tool = Collection()
tool.add_task(collections.tool.install)
tool.add_task(collections.tool.list)
tool.add_task(collections.tool.remove)
tool.add_task(collections.tool.run)
root.add_collection(tool, name="tool")

if envs:
# Environment collection
env = Collection()
env.add_task(collections.env.list)
env.add_task(collections.env.switch)
root.add_collection(env, name="env")

return root
4 changes: 3 additions & 1 deletion superinvoke/objects/__init__.py
Original file line number Diff line number Diff line change
@@ -1 +1,3 @@
from .tool import Tags, Tool, Tools
from .common import Tags
from .env import Env, Envs
from .tool import Tool, Tools
6 changes: 6 additions & 0 deletions superinvoke/objects/common.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
from .. import utils


# Represents the list of available tags.
class Tags(utils.StrEnum):
pass
68 changes: 68 additions & 0 deletions superinvoke/objects/env.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,68 @@
from typing import Any, Callable, List, Optional

from .. import constants, utils
from .common import Tags


# Represents an environment.
class Env:
name: str
tags: List[Tags]

def __init__(self, name: str, tags: List[Tags]):
self.name = name
self.tags = tags

def __str__(self) -> str:
return self.name

def __eq__(self, other: object) -> bool:
return (
isinstance(other, Env)
and self.name == other.name
and self.tags == other.tags
)

def __hash__(self) -> int:
return hash((self.name, tuple(self.tags)))


# Represents the list of available environments.
class Envs:
Default: Optional[Callable[[Any], Env]] = None

@utils.classproperty
def All(cls) -> List[Env]:
all = []

for env in dir(cls):
if env in ["All", "Default", "Current"]:
continue

env = getattr(cls, env)
if isinstance(env, Env):
all.append(env)

return all

@utils.classproperty
def Current(cls) -> Optional[Env]:
if utils.exists(utils.path(constants.Paths.ENV)) == "file":
return cls.ByName(utils.read(utils.path(constants.Paths.ENV))[0])

if hasattr(cls, "Default") and cls.Default is not None:
return cls.Default(cls)

return None

@classmethod
def ByTag(cls, tag) -> List[Env]:
return [env for env in cls.All if tag in env.tags]

@classmethod
def ByName(cls, name) -> Optional[Env]:
for env in cls.All:
if name == env.name:
return env

return None
14 changes: 7 additions & 7 deletions superinvoke/objects/tool.py
Original file line number Diff line number Diff line change
@@ -1,11 +1,7 @@
from typing import List, Optional

from .. import constants, utils


# Represents a tool tag.
class Tags(utils.StrEnum):
pass
from .common import Tags


# Represents an executable tool.
Expand All @@ -20,7 +16,7 @@ def __init__(self, name: str, version: Optional[str], tags: List[Tags], links: d
self.name = name
self.version = version
self.tags = tags
self.path = utils.path(f"{constants.Directories.TOOLS}/{self.name}")
self.path = utils.path(f"{constants.Paths.TOOLS}/{self.name}")
self.links = links

def __str__(self) -> str:
Expand All @@ -31,7 +27,11 @@ def link(self) -> tuple:
return self.links.get(constants.Platforms.CURRENT, constants.Platforms.LINUX)

def __eq__(self, other: object) -> bool:
return self.name == other.name and self.version == other.version
return (
isinstance(other, Tool)
and self.name == other.name
and self.version == other.version
)

def __hash__(self) -> int:
return hash((self.name, self.version))
Expand Down
Loading

0 comments on commit aa2a553

Please sign in to comment.