Skip to content

Commit

Permalink
Merge pull request #195 from ThePorgs/dev Release 4.3.0
Browse files Browse the repository at this point in the history
Release 4.3.0
  • Loading branch information
Dramelac authored Dec 22, 2023
2 parents 5428a7a + d82056e commit 1ae9ec4
Show file tree
Hide file tree
Showing 39 changed files with 1,366 additions and 499 deletions.
2 changes: 1 addition & 1 deletion .github/ISSUE_TEMPLATE/bug_report.yml
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
name: 🐞 Bug report [WRAPPER]
description: Report a bug in Exegol WRAPPER to help us improve it
title: "[BUG] <title>"
title: "<title>"
labels:
- bug
body:
Expand Down
5 changes: 4 additions & 1 deletion .github/workflows/entrypoint_nightly.yml
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,10 @@ jobs:
build-n-publish:
name: Build and publish Python 🐍 distributions to TestPyPI 📦
runs-on: ubuntu-latest
environment: nightly
permissions:
# IMPORTANT: this permission is mandatory for trusted publishing
id-token: write
needs: test
steps:
- uses: actions/checkout@master
Expand All @@ -33,6 +37,5 @@ jobs:
- name: Publish distribution 📦 to Test PyPI
uses: pypa/gh-action-pypi-publish@release/v1
with:
password: ${{ secrets.TEST_PYPI_API_TOKEN }}
repository-url: https://test.pypi.org/legacy/
skip-existing: true
25 changes: 22 additions & 3 deletions .github/workflows/entrypoint_prerelease.yml
Original file line number Diff line number Diff line change
Expand Up @@ -4,19 +4,38 @@ on:
pull_request:
branches:
- "master"
paths-ignore:
paths-ignore: # not always respected. See https://github.com/actions/runner/issues/2324#issuecomment-1703345084
- ".github/**"
- "**.md"

jobs:
test:
preprod_test:
name: Pre-prod code testing
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@master
with:
submodules: false
- name: Set up Python
uses: actions/setup-python@v4
with:
python-version: "3.10"
- name: Find spawn.sh script version
run: egrep '^# Spawn Version:[0-9ab]+$' ./exegol/utils/imgsync/spawn.sh | cut -d ':' -f2
- name: Check for prod readiness of spawn.sh script version
run: egrep '^# Spawn Version:[0-9]+$' ./exegol/utils/imgsync/spawn.sh
- name: Check package version (alpha and beta version cannot be released)
run: python3 -c 'from exegol.config.ConstantConfig import ConstantConfig; print(ConstantConfig.version); exit(any(c in ConstantConfig.version for c in ["a", "b"]))'

code_test:
name: Python tests and checks
needs: preprod_test
uses: ./.github/workflows/sub_testing.yml

build:
name: Build Python 🐍 distributions
runs-on: ubuntu-latest
needs: test
needs: code_test
steps:
- uses: actions/checkout@master
with:
Expand Down
2 changes: 1 addition & 1 deletion .github/workflows/entrypoint_pull_request.yml
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@ on:
pull_request:
branches-ignore:
- "master"
paths-ignore:
paths-ignore: # not always respected. See https://github.com/actions/runner/issues/2324#issuecomment-1703345084
- ".github/**"
- "**.md"
push:
Expand Down
7 changes: 4 additions & 3 deletions .github/workflows/entrypoint_release.yml
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,10 @@ jobs:
build-n-publish:
name: Build and publish Python 🐍 distributions to PyPI 📦
runs-on: ubuntu-latest
environment: release
permissions:
# IMPORTANT: this permission is mandatory for trusted publishing
id-token: write
needs: test
steps:
- uses: actions/checkout@master
Expand All @@ -31,10 +35,7 @@ jobs:
- name: Publish distribution 📦 to Test PyPI
uses: pypa/gh-action-pypi-publish@release/v1
with:
password: ${{ secrets.TEST_PYPI_API_TOKEN }}
repository-url: https://test.pypi.org/legacy/
skip-existing: true
- name: Publish distribution 📦 to PyPI (prod)
uses: pypa/gh-action-pypi-publish@release/v1
with:
password: ${{ secrets.PYPI_API_TOKEN }}
12 changes: 8 additions & 4 deletions .github/workflows/sub_testing.yml
Original file line number Diff line number Diff line change
Expand Up @@ -14,11 +14,15 @@ jobs:
- name: Set up Python
uses: actions/setup-python@v4
with:
python-version: "3.10"
python-version: "3.12"
- name: Install requirements
run: python -m pip install --user mypy types-requests types-PyYAML
- name: Run code analysis
- name: Run code analysis (package)
run: mypy ./exegol/ --ignore-missing-imports --check-untyped-defs --pretty # TODO add --disallow-untyped-defs
- name: Run code analysis (source)
run: mypy ./exegol.py --ignore-missing-imports --check-untyped-defs --pretty # TODO add --disallow-untyped-defs
- name: Find spawn.sh script version
run: egrep '^# Spawn Version:[0-9ab]+$' ./exegol/utils/imgsync/spawn.sh | cut -d ':' -f2

compatibility:
name: Compatibility checks
Expand All @@ -27,7 +31,7 @@ jobs:
strategy:
fail-fast: false
matrix:
version: ["3.7", "3.8", "3.9", "3.10", "3.11"]
version: ["3.7", "3.8", "3.9", "3.10", "3.11", "3.12"]
os: [win32, linux, darwin]
steps:
- uses: actions/checkout@master
Expand All @@ -36,7 +40,7 @@ jobs:
- name: Set up Python
uses: actions/setup-python@v4
with:
python-version: "3.10"
python-version: "3.12"
- name: Install requirements
run: python -m pip install --user mypy types-requests types-PyYAML
- name: Check python compatibility for ${{ matrix.os }}/${{ matrix.version }}
Expand Down
4 changes: 2 additions & 2 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@
<br><br>
<a target="_blank" rel="noopener noreferrer" href="https://pypi.org/project/Exegol" title=""><img src="https://img.shields.io/pypi/v/Exegol?color=informational" alt="pip package version"></a>
<img alt="Python3.7" src="https://img.shields.io/badge/Python-3.7+-informational">
<a target="_blank" rel="noopener noreferrer" href="https://pepy.tech/project/exegol" title=""><img src="https://static.pepy.tech/personalized-badge/exegol?period=total&units=international_system&left_color=grey&right_color=brightgreen&left_text=Downloads" alt="pip stats"></a>
<img alt="latest commit on master" src="https://img.shields.io/docker/pulls/nwodtuhs/exegol.svg?label=downloads">
<br><br>
<img alt="latest commit on master" src="https://img.shields.io/github/last-commit/ThePorgs/Exegol/master?label=latest%20release">
<img alt="latest commit on dev" src="https://img.shields.io/github/last-commit/ThePorgs/Exegol/dev?label=latest%20dev">
Expand Down Expand Up @@ -37,7 +37,7 @@
# Getting started

You can refer to the [Exegol documentations](https://exegol.readthedocs.io/en/latest/getting-started/install.html).
You can refer to the [Exegol documentation](https://exegol.readthedocs.io/en/latest/getting-started/install.html).

> Full documentation homepage: https://exegol.rtfd.io/.
Expand Down
2 changes: 1 addition & 1 deletion exegol-docker-build
2 changes: 1 addition & 1 deletion exegol-resources
Submodule exegol-resources updated 415 files
26 changes: 16 additions & 10 deletions exegol/config/ConstantConfig.py
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@
class ConstantConfig:
"""Constant parameters information"""
# Exegol Version
version: str = "4.2.5"
version: str = "4.3.0"

# Exegol documentation link
documentation: str = "https://exegol.rtfd.io/"
Expand All @@ -15,6 +15,10 @@ class ConstantConfig:
# Path of the Dockerfile
build_context_path_obj: Path
build_context_path: str
# Path of the entrypoint.sh
entrypoint_context_path_obj: Path
# Path of the spawn.sh
spawn_context_path_obj: Path
# Exegol config directory
exegol_config_path: Path = Path().home() / ".exegol"
# Docker Desktop for mac config file
Expand All @@ -33,13 +37,12 @@ class ConstantConfig:
EXEGOL_RESOURCES_REPO: str = "https://github.com/ThePorgs/Exegol-resources.git"

@classmethod
def findBuildContextPath(cls) -> Path:
"""Find the right path to the build context from Exegol docker images.
def findResourceContextPath(cls, resource_folder: str, source_path: str) -> Path:
"""Find the right path to the resources context from Exegol package.
Support source clone installation and pip package (venv / user / global context)"""
dockerbuild_folder_name = "exegol-docker-build"
local_src = cls.src_root_path_obj / dockerbuild_folder_name
if local_src.is_dir():
# If exegol is clone from github, build context is accessible from root src
local_src = cls.src_root_path_obj / source_path
if local_src.is_dir() or local_src.is_file():
# If exegol is clone from GitHub, build context is accessible from root src
return local_src
else:
# If install from pip
Expand All @@ -51,13 +54,16 @@ def findBuildContextPath(cls) -> Path:
possible_locations.append(Path(loc).parent.parent.parent)
# Find a good match
for test in possible_locations:
context_path = test / dockerbuild_folder_name
context_path = test / resource_folder
if context_path.is_dir():
return context_path
# Detect a venv context
return Path(site.PREFIXES[0]) / dockerbuild_folder_name
return Path(site.PREFIXES[0]) / resource_folder


# Dynamically built attribute must be set after class initialization
ConstantConfig.build_context_path_obj = ConstantConfig.findBuildContextPath()
ConstantConfig.build_context_path_obj = ConstantConfig.findResourceContextPath("exegol-docker-build", "exegol-docker-build")
ConstantConfig.build_context_path = str(ConstantConfig.build_context_path_obj)

ConstantConfig.entrypoint_context_path_obj = ConstantConfig.findResourceContextPath("exegol-imgsync", "exegol/utils/imgsync/entrypoint.sh")
ConstantConfig.spawn_context_path_obj = ConstantConfig.findResourceContextPath("exegol-imgsync", "exegol/utils/imgsync/spawn.sh")
17 changes: 16 additions & 1 deletion exegol/config/DataCache.py
Original file line number Diff line number Diff line change
Expand Up @@ -59,6 +59,21 @@ def get_images_data(self) -> ImagesCacheModel:

def update_image_cache(self, images: List):
"""Refresh image cache data"""
cache_images = [ImageCacheModel(img.getName(), img.getLatestVersion(), img.getLatestRemoteId(), "local" if img.isLocal() else "remote") for img in images]
logger.debug("Updating image cache data")
cache_images = []
for img in images:
name = img.getName()
version = img.getLatestVersion()
remoteid = img.getLatestRemoteId()
type = "local" if img.isLocal() else "remote"
logger.debug(f"└── {name} (version: {version})\t→ ({type}) {remoteid}")
cache_images.append(
ImageCacheModel(
name,
version,
remoteid,
type
)
)
self.__cache_data.images = ImagesCacheModel(cache_images)
self.save_updates()
30 changes: 7 additions & 23 deletions exegol/config/EnvInfo.py
Original file line number Diff line number Diff line change
@@ -1,8 +1,5 @@
import json
import platform
import re
import shutil
import subprocess
from enum import Enum
from typing import Optional, Any, List

Expand All @@ -24,7 +21,7 @@ class DockerEngine(Enum):
"""Dictionary class for static Docker engine name"""
WLS2 = "WSL2"
HYPERV = "Hyper-V"
MAC = "Docker desktop"
DOCKER_DESKTOP = "Docker desktop"
ORBSTACK = "Orbstack"
LINUX = "Kernel"

Expand Down Expand Up @@ -88,8 +85,8 @@ def initData(cls, docker_info):
cls.__docker_host_os = cls.HostOs.WINDOWS
elif cls.__is_docker_desktop:
# If docker desktop is detected but not a Windows engine/kernel, it's (probably) a mac
cls.__docker_engine = cls.DockerEngine.MAC
cls.__docker_host_os = cls.HostOs.MAC
cls.__docker_engine = cls.DockerEngine.DOCKER_DESKTOP
cls.__docker_host_os = cls.HostOs.MAC if cls.is_mac_shell else cls.HostOs.LINUX
elif is_orbstack:
# Orbstack is only available on Mac
cls.__docker_engine = cls.DockerEngine.ORBSTACK
Expand All @@ -99,6 +96,9 @@ def initData(cls, docker_info):
cls.__docker_engine = cls.DockerEngine.LINUX
cls.__docker_host_os = cls.HostOs.LINUX

if cls.__docker_engine == cls.DockerEngine.DOCKER_DESKTOP and cls.__docker_host_os == cls.HostOs.LINUX:
logger.warning(f"Using Docker Desktop on Linux is not officially supported !")

@classmethod
def getHostOs(cls) -> HostOs:
"""Return Host OS
Expand All @@ -114,24 +114,8 @@ def getWindowsRelease(cls) -> str:
if cls.is_windows_shell:
# From a Windows shell, python supply an approximate (close enough) version of windows
cls.__windows_release = platform.win32_ver()[1]
elif cls.current_platform == "WSL":
# From a WSL shell, we must create a process to retrieve the host's version
# Find version using MS-DOS command 'ver'
if not shutil.which("cmd.exe"):
logger.critical("cmd.exe is not accessible from your WSL environment!")
proc = subprocess.Popen(["cmd.exe", "/c", "ver"], stdout=subprocess.PIPE, stderr=subprocess.DEVNULL)
proc.wait()
assert proc.stdout is not None
# Try to match Windows version
matches = re.search(r"version (\d+\.\d+\.\d+)(\.\d*)?", proc.stdout.read().decode('utf-8'))
if matches:
# Select match 1 and apply to the attribute
cls.__windows_release = matches.group(1)
else:
# If there is any match, fallback to empty
cls.__windows_release = ""
else:
cls.__windows_release = ""
cls.__windows_release = "Unknown"
return cls.__windows_release

@classmethod
Expand Down
27 changes: 26 additions & 1 deletion exegol/config/UserConfig.py
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,7 @@ class UserConfig(DataFileUtils, metaclass=MetaSingleton):
# Static choices
start_shell_options = {'zsh', 'bash', 'tmux'}
shell_logging_method_options = {'script', 'asciinema'}
desktop_available_proto = {'http', 'vnc'}

def __init__(self):
# Defaults User config
Expand All @@ -25,11 +26,15 @@ def __init__(self):
self.default_start_shell: str = "zsh"
self.shell_logging_method: str = "asciinema"
self.shell_logging_compress: bool = True
self.desktop_default_enable: bool = False
self.desktop_default_localhost: bool = True
self.desktop_default_proto: str = "http"

super().__init__("config.yml", "yml")

def _build_file_content(self):
config = f"""# Exegol configuration
# Full documentation: https://exegol.readthedocs.io/en/latest/exegol-wrapper/advanced-uses.html#id1
# Volume path can be changed at any time but existing containers will not be affected by the update
volumes:
Expand Down Expand Up @@ -63,11 +68,22 @@ def _build_file_content(self):
# Enable automatic compression of log files (with gzip)
enable_log_compression: {self.shell_logging_compress}
# Configure your Exegol Desktop
desktop:
# Enables or not the desktop mode by default
# If this attribute is set to True, then using the CLI --desktop option will be inverted and will DISABLE the feature
enabled_by_default: {self.desktop_default_enable}
# Default desktop protocol,can be "http", or "vnc" (additional protocols to come in the future, check online documentation for updates).
default_protocol: {self.desktop_default_proto}
# Desktop service is exposed on localhost by default. If set to true, services will be exposed on localhost (127.0.0.1) otherwise it will be exposed on 0.0.0.0. This setting can be overwritten with --desktop-config
localhost_by_default: {self.desktop_default_localhost}
"""
# TODO handle default image selection
# TODO handle default start container
# TODO add custom build profiles path
return config

@staticmethod
Expand Down Expand Up @@ -105,6 +121,12 @@ def _process_data(self):
self.shell_logging_method = self._load_config_str(shell_logging_data, 'logging_method', self.shell_logging_method, choices=self.shell_logging_method_options)
self.shell_logging_compress = self._load_config_bool(shell_logging_data, 'enable_log_compression', self.shell_logging_compress)

# Desktop section
desktop_data = config_data.get("desktop", {})
self.desktop_default_enable = self._load_config_bool(desktop_data, 'enabled_by_default', self.desktop_default_enable)
self.desktop_default_proto = self._load_config_str(desktop_data, 'default_proto', self.desktop_default_proto, choices=self.desktop_available_proto)
self.desktop_default_localhost = self._load_config_bool(desktop_data, 'localhost_by_default', self.desktop_default_localhost)

def get_configs(self) -> List[str]:
"""User configs getter each options"""
configs = [
Expand All @@ -118,6 +140,9 @@ def get_configs(self) -> List[str]:
f"Default start shell: [blue]{self.default_start_shell}[/blue]",
f"Shell logging method: [blue]{self.shell_logging_method}[/blue]",
f"Shell logging compression: {boolFormatter(self.shell_logging_compress)}",
f"Desktop enabled by default: {boolFormatter(self.desktop_default_enable)}",
f"Desktop default protocol: [blue]{self.desktop_default_proto}[/blue]",
f"Desktop default host: [blue]{'localhost' if self.desktop_default_localhost else '0.0.0.0'}[/blue]",
]
# TUI can't be called from here to avoid circular importation
return configs
2 changes: 1 addition & 1 deletion exegol/console/ExegolPrompt.py
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@

def Confirm(question: str, default: bool) -> bool:
"""Quick function to format rich Confirmation and options on every exegol interaction"""
default_text = "[bright_magenta][Y/n][/bright_magenta]" if default else "[bright_magenta]\[y/N][/bright_magenta]"
default_text = "[bright_magenta][Y/n][/bright_magenta]" if default else "[bright_magenta][y/N][/bright_magenta]"
formatted_question = f"[bold blue][?][/bold blue] {question} {default_text}"
return rich.prompt.Confirm.ask(
formatted_question,
Expand Down
Loading

0 comments on commit 1ae9ec4

Please sign in to comment.