Skip to content

Commit

Permalink
wip
Browse files Browse the repository at this point in the history
  • Loading branch information
faermanj committed Mar 21, 2024
1 parent 7c69a0c commit 9ea7249
Show file tree
Hide file tree
Showing 15 changed files with 177 additions and 39 deletions.
1 change: 1 addition & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -4,3 +4,4 @@ dist

.pyenv
__pycache__

2 changes: 1 addition & 1 deletion up_ansible/poetry.lock

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

2 changes: 1 addition & 1 deletion up_aws/poetry.lock

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

2 changes: 1 addition & 1 deletion up_demo/poetry.lock

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

2 changes: 1 addition & 1 deletion up_splat/poetry.lock

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

4 changes: 4 additions & 0 deletions upcli/ansible_version.sh
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
#!/bin/bash

# FROM cytopia/ansible:latest
ansible --version
4 changes: 4 additions & 0 deletions upcli/fedora_version.sh
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
#!/bin/bash

# FROM fedora:latest
cat /etc/os-release
3 changes: 3 additions & 0 deletions upcli/hello.sh
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
#!/bin/bash

echo "hello"
2 changes: 1 addition & 1 deletion upcli/poetry.lock

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

2 changes: 1 addition & 1 deletion upcli/up/main.py
Original file line number Diff line number Diff line change
Expand Up @@ -35,7 +35,7 @@ def cli_main():
context = {"executable": executable}
try:
prompt_without_options = setup_options(prompt)
print(prompt_without_options)
# print(prompt_without_options)
uplib.up_main(context, prompt_without_options)
except Exception as e:
log.error(e)
Expand Down
34 changes: 17 additions & 17 deletions uplib/poetry.lock

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

27 changes: 17 additions & 10 deletions uplib/uplib/containers.py
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,8 @@
from datetime import datetime
from . import settings_maps, options_map

import sys

# https://docker-py.readthedocs.io/en/stable/containers.html
@dataclass
class ContainerRun:
Expand All @@ -35,8 +37,11 @@ class ContainerRun:
class DockerContainers:
@classmethod
def volumes_of(cls, run: ContainerRun, prompt: str):
plugin_name = prompt.split()[0]
log.debug("loading volumes for plugin_name: %s", plugin_name)
plugin_name = "__NOT_FOUND__"
tokens = prompt.split()
if len(tokens):
plugin_name = tokens[0]
log.debug("loading volumes for prompt: %s", prompt)

plugin_settings = settings_maps.get(plugin_name, {})
default_volumes = plugin_settings.get("volumes", {})
Expand All @@ -56,14 +61,15 @@ def volumes_of(cls, run: ContainerRun, prompt: str):
}
}
options_volumes = options_map.get('volumes', {})
print(type(run.volumes))
print(run.volumes)
result = run.volumes | settings_vols | default_vols | options_volumes
return result

@classmethod
def ports_of(cls, prompt: str):
plugin_name = prompt.split()[0]
plugin_name = "__UNDEFINED__"
tokens = prompt.split()
if len(tokens):
plugin_name = tokens[0]
options_ports = options_map.get('ports', {})
default_ports = settings_maps.get(plugin_name, {}).get("ports", {})
ports = default_ports.to_dict() if default_ports else {}
Expand All @@ -89,9 +95,10 @@ def run(self, run: ContainerRun):
# user = "up_user"
user = run.user
working_dir = run.working_dir
console = Console()
console.log(f"Running container: {name}")
console.log({
up_console = Console(file=sys.stderr)
app_console = Console(file=sys.stdout)
up_console.log(f"Running container: {name}")
up_console.log({
"name": name,
"image": run.image,
"command": command,
Expand All @@ -116,15 +123,15 @@ def run(self, run: ContainerRun):
)
for line in container.logs(stream=True):
line = line.decode("utf-8").strip()
console.print(escape(line))
app_console.print(escape(line))
container.wait()
log.debug("container ended.")

except Exception as e:
log.error("Failed to run container")
log.debug("%s", run)
log.error("%s", e)
raise e
# raise e

_container_name_pattern = '[^a-zA-Z0-9_.-]'
def generate_container_name(run):
Expand Down
2 changes: 1 addition & 1 deletion uplib/uplib/logging.py
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@
def init_logging():
sys.set_int_max_str_digits(999999)
level = get_log_level()
print("Initializing logging with level "+str(level))
# print("Initializing logging with level "+str(level))
logging.basicConfig(
level=level
)
Expand Down
87 changes: 82 additions & 5 deletions uplib/uplib/main.py
Original file line number Diff line number Diff line change
@@ -1,11 +1,12 @@
import shlex
import os

from . import pm, Context, Prompt
from .containers import Containers, ContainerRun
from .plugins import load_plugins
from .logging import log
from .config import Config

from .parser import parse_doclets

def up_main(context: Context, prompt: Prompt):
log.info("*** %s", Config.welcome_message.get() + " ***")
Expand All @@ -29,16 +30,92 @@ def up_main(context: Context, prompt: Prompt):
def default_container(prompt):
return ContainerRun(
image=Config.default_image.get(),
working_dir="/tmp/up_cwd",
command=prompt)

def is_exec(exec: str) -> bool:
file_exists = os.path.exists(exec)
is_exec = os.access(exec, os.X_OK)
result = file_exists and is_exec
return result

def is_text_file(file_path, threshold=0.30):
"""
Checks if the given file is a text file.
Args:
- file_path: Path to the file to be checked.
- threshold: The fraction of non-text characters at which a file is considered binary.
Returns:
- True if the file is likely a text file, False otherwise.
"""
text_characters = bytearray({7, 8, 9, 10, 12, 13, 27} | set(range(0x20, 0x100)) - {0x7f})
is_binary = lambda bytes: bool(bytes.translate(None, text_characters))

with open(file_path, 'rb') as file:
# Read up to 1024 bytes from the file
block = file.read(1024)
if not block:
# Empty file are considered text files
return True
if is_binary(block):
return False

# Check the proportion of binary content in the block
num_binary = sum(is_binary(bytearray([b])) for b in block)
if num_binary / 1024 > threshold:
return False

return True

def containers_for_prompt(prompt) -> list[ContainerRun]:
lists = containers_from_plugins(prompt)
flat = [item for sublist in lists for item in sublist]
return flat

def containers_for_prompt(prompt: list[str]) -> list[ContainerRun]:
result = []
if (len(prompt) == 0):
return result
head = prompt[0]
if (is_exec(head)):
result= containers_from_exec(prompt)
else:
lists = containers_from_plugins(prompt)
result = [item for sublist in lists for item in sublist]
return result

def containers_from_plugins(prompt: list[str]) -> list[ContainerRun]:
result = pm.hook.containers_for_prompt(prompt=prompt)
if not result:
return []
return result

def containers_from_exec(prompt: list[str]) -> list[ContainerRun]:
result = []
head = prompt[0]
if (is_text_file(head)):
# log.error("CONTAINERS FROM TEXT "+str(prompt))
doclets = parse_doclets(head)

This comment has been minimized.

Copy link
@faermanj

faermanj Mar 21, 2024

Author Contributor

@fabiobarkoski aqui :)

# log.error(str(doclets))
run = ContainerRun()
run.command = prompt
run.working_dir = "/tmp/up_cwd/"
# iterate on doclets and set the run properties
for key in doclets:
if key == "FROM":
run.image = doclets[key]
if key == "CMD":
run.command = doclets[key]
if key == "WORKDIR":
run.working_dir = doclets[key]
if key == "ENV":
run.environment = doclets[key]
if key == "VOLUME":
run.volumes = doclets[key]
if key == "PORT":
run.ports = doclets[key]
if key == "USER":
run.user = doclets[key]
if key == "ENTRYPOINT":
run.command = doclets[key]

result = [run]
return result
42 changes: 42 additions & 0 deletions uplib/uplib/parser.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,42 @@
def parse_doclets(file_path):
# Define the list of Docker keywords
docker_keywords = [
"FROM", "LABEL", "RUN", "CMD", "EXPOSE", "ENV", "ADD", "COPY", "ENTRYPOINT",
"VOLUME", "USER", "WORKDIR", "ARG", "ONBUILD", "STOPSIGNAL", "HEALTHCHECK", "SHELL"
]

# Define the list of comment delimiters
comment_delimiters = ['#', '//', '*', '/*']

# Initialize an empty dictionary to hold the results
docker_declarations = {}

# Open the file and read it line by line
with open(file_path, 'r') as file:
for line in file:
# Check if the line starts with any of the comment delimiters
if any(line.lstrip().startswith(delimiter) for delimiter in comment_delimiters):
# Remove the comment delimiter and leading/trailing whitespace
uncommented_line = line.lstrip().lstrip(''.join(comment_delimiters)).strip()
tokens = uncommented_line.split()
# Split the uncommented line into words and get the first word
head = tokens[0] if tokens else None
# tail is the rest of line without first workd
tail = ' '.join(tokens[1:])
# Check if the first word is a Docker keyword

if head in docker_keywords:
# Add the uncommented line to the dictionary, keyed by the Docker keyword
# This allows for multiple comments for the same keyword to be concatenated

docker_declarations.setdefault(head, []).append(tail)

# Convert lists of lines back to single string entries for each keyword
for key in docker_declarations:
docker_declarations[key] = '\n'.join(docker_declarations[key])

return docker_declarations

# Example usage (you would replace 'example.txt' with your actual file path):
# docker_declarations = parse_docker_comments('example.txt')
# print(docker_declarations)

0 comments on commit 9ea7249

Please sign in to comment.