Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add FQDN support and other fixes #117

Merged
merged 17 commits into from
Feb 27, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
5 changes: 4 additions & 1 deletion Docker/frappe/Dockerfile
Original file line number Diff line number Diff line change
Expand Up @@ -126,7 +126,10 @@ RUN git clone --depth 1 https://github.com/pyenv/pyenv.git .pyenv \
&& pyenv global $PYTHON_VERSION \
&& echo 'export PYENV_ROOT="/opt/.pyenv"' >> "$USERZSHRC" \
&& echo 'command -v pyenv >/dev/null || export PATH="$PYENV_ROOT/bin:$PATH"' >> "$USERZSHRC" \
&& echo 'eval "$(pyenv init --path)"' >>"$USERZSHRC"
&& echo 'eval "$(pyenv init --path)"' >>"$USERZSHRC" \
# remove *.pyc and *.pyo as used here in official docker image to reduce size
# https://github.com/docker-library/python/blob/789d789e4a8db71d3d393667971c49b845ffdc3f/3.11/alpine3.19/Dockerfile#L106-L111
&& find /opt/.pyenv/versions -depth \( \( -type d -a \( -name test -o -name tests -o -name idle_test \) \) -o \( -type f -a \( -name '*.pyc' -o -name '*.pyo' -o -name 'libpython*.a' \) \) \) -exec rm -rf '{}' + ;

RUN pip install frappe-bench

Expand Down
1 change: 1 addition & 0 deletions Docker/frappe/bench-dev-server
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@
#!/bin/bash
trap "kill -- -$$" EXIT
fuser -k 80/tcp
bench serve --port 80
14 changes: 10 additions & 4 deletions Docker/frappe/bench-wrapper.sh
Original file line number Diff line number Diff line change
@@ -1,9 +1,15 @@
#!/bin/bash
after_command() {
supervisorctl -c /opt/user/supervisord.conf restart frappe-bench-dev:
restart_command() {
supervisorctl -c /opt/user/supervisord.conf restart frappe-bench-dev:
}
status_command() {
supervisorctl -c /opt/user/supervisord.conf status frappe-bench-dev:
}

if [[ "$@" =~ ^restart[[:space:]]* ]]; then
after_command
restart_command
elif [[ "$@" =~ ^status[[:space:]]* ]]; then
status_command
else
/opt/.pyenv/shims/bench "$@"
/opt/.pyenv/shims/bench "$@"
fi
4 changes: 3 additions & 1 deletion Docker/frappe/entrypoint.sh
Original file line number Diff line number Diff line change
Expand Up @@ -30,8 +30,10 @@ if [[ ! -f "/workspace/.profile" ]]; then
cat /opt/user/.profile > /workspace/.profile
fi

chown "$USERID":"$USERGROUP" /workspace /workspace/frappe-bench

ls -p /workspace | grep -v 'frappe-bench/' | xargs -I{} chown -R "$USERID":"$USERGROUP" /workspace{}

chown -R "$USERID":"$USERGROUP" /workspace

if [ "$#" -gt 0 ]; then
gosu "$USERID":"$USERGROUP" "/scripts/$@"
Expand Down
39 changes: 35 additions & 4 deletions Docker/frappe/helper-function.sh
Original file line number Diff line number Diff line change
Expand Up @@ -102,10 +102,10 @@ install_apps() {

if [[ "${branch_name:-}" ]]; then
echo "Installing app $app_name -> $branch_name"
$BENCH_COMMAND get-app --resolve-deps --overwrite --skip-assets --branch "${branch_name}" "${app_name}"
$BENCH_COMMAND get-app --overwrite --skip-assets --branch "${branch_name}" "${app_name}"
else
echo "Installing app $app_name"
$BENCH_COMMAND get-app --resolve-deps --overwrite --skip-assets "${app_name}"
$BENCH_COMMAND get-app --overwrite --skip-assets "${app_name}"
fi
done
else
Expand All @@ -126,10 +126,25 @@ install_apps() {
fi
done

# create apps_txt
local apps_list

apps_txt=$(mktemp)

apps_list=$(ls -1 apps|| exit 0)

for app_name in $(echo "$apps_list"); do
get_app_name "$app_name"
echo "$APP_NAME" >> "$apps_txt"
done

cat "$apps_txt" > sites/apps.txt

# create apps_json
for app_name in $(ls -1 apps | grep -v 'frappe' || exit 0); do
apps_json=$(echo "$apps_json" | jq -rc --arg app_name "${app_name}" '.+ [$app_name]')
for app_name in $(cat "$apps_txt" | grep -v 'frappe' || exit 0); do
apps_json=$(echo "$apps_json" | jq -rc --arg app_name "${APP_NAME}" '.+ [$app_name]')
done

update_common_site_config install_apps "$apps_json" 'true'
}

Expand Down Expand Up @@ -187,3 +202,19 @@ update_uid_gid() {

echo "UID and GID updated successfully."
}

# this return the list of apps
# input
# $1 -> app_name respective to apps dir
get_app_name(){
local app="$1"
hooks_py_path="/workspce/frappe-bench/apps/$app"

# Extract the app name from the hooks.py file
APP_NAME=$(awk -F'"' '/app_name/{print $2}' "$hooks_py_path" || exit 0)

if ! [[ "${APP_NAME:-}" ]]; then
# If the app name is not found, use app name from basename of the app dir
APP_NAME=${app##*/}
fi
}
68 changes: 60 additions & 8 deletions frappe_manager/commands.py
Original file line number Diff line number Diff line change
@@ -1,24 +1,32 @@
from copy import deepcopy
from re import template
from ruamel.yaml import serialize
from pathlib import Path
import typer
import os
import requests
import sys
import shutil
import importlib
import json

from typing import Annotated, List, Optional, Set
from frappe_manager.services_manager.services_exceptions import ServicesNotCreated
from frappe_manager.site_manager.SiteManager import SiteManager
from frappe_manager.display_manager.DisplayManager import richprint
from frappe_manager import CLI_DIR, default_extension, SiteServicesEnum, services_manager
from frappe_manager.docker_wrapper import DockerClient, DockerException
from frappe_manager.logger import log
from frappe_manager.docker_wrapper import DockerClient
from frappe_manager.services_manager.services import ServicesManager
from frappe_manager.migration_manager.migration_executor import MigrationExecutor
from frappe_manager.site_manager.site_exceptions import SiteException
from frappe_manager.utils.callbacks import apps_list_validation_callback, frappe_branch_validation_callback, version_callback
from frappe_manager.utils.helpers import get_container_name_prefix, is_cli_help_called, get_current_fm_version
from frappe_manager.services_manager.commands import services_app
from frappe_manager.sub_commands.self_commands import self_app
from frappe_manager.metadata_manager import MetadataManager
from frappe_manager.migration_manager.version import Version
from frappe_manager.compose_manager.ComposeFile import ComposeFile

app = typer.Typer(no_args_is_help=True,rich_markup_mode='rich')
app.add_typer(services_app, name="services", help="Handle global services.")
Expand Down Expand Up @@ -78,13 +86,57 @@ def app_callback(
if not DockerClient().server_running():
richprint.exit("Docker daemon not running. Please start docker service.")

if first_time_install :
from frappe_manager.metadata_manager import MetadataManager
from frappe_manager.migration_manager.version import Version
metadata_manager = MetadataManager()
current_version = Version(get_current_fm_version())
metadata_manager.set_version(current_version)
metadata_manager.save()
metadata_manager = MetadataManager()

# docker pull
if first_time_install:
if not metadata_manager.toml_file.exists():
richprint.print("🔍 It seems like the first installation. Pulling images... 🖼️")
site_composefile = ComposeFile(loadfile=Path('docker-compose.yml'))
services_composefile = ComposeFile(loadfile=Path('docker-compose.services.yml',template='docker-compose.services.tmpl'))
images_list = []
docker = DockerClient()

if site_composefile.is_template_loaded:
images = site_composefile.get_all_images()
images.update(services_composefile.get_all_images())

for service ,image_info in images.items():
image = f"{image_info['name']}:{image_info['tag']}"
images_list.append(image)

# remove duplicates
images_dict = dict.fromkeys(images_list)
images_list = deepcopy(images_dict).keys()
error = False

for image in images_list:
status = f"[blue]Pulling image[/blue] [bold][yellow]{image}[/yellow][/bold]"
richprint.change_head(status,style=None)
try:
output = docker.pull(container_name=image , stream=True)
richprint.live_lines(output, padding=(0, 0, 0, 2))
richprint.print(f"{status} : Done")
except DockerException as e:
error = True
images_dict[image] = e
continue

# richprint.error(f"[red][bold]Error :[/bold][/red] {e}")

if error:
print('')
richprint.error(f"[bold][red]Pulling images failed for these images[/bold][/red]")
for image,exception in images_dict.items():
if exception:
richprint.error(f'[bold][red]Image [/bold][/red]: {image}')
richprint.error(f'[bold][red]Error [/bold][/red]: {exception}')
shutil.rmtree(CLI_DIR)
richprint.exit("Aborting. [bold][blue]fm[/blue][/bold] will not be able to work without images. 🖼️")

current_version = Version(get_current_fm_version())
metadata_manager.set_version(current_version)
metadata_manager.save()

migrations = MigrationExecutor()
migration_status = migrations.execute()
Expand Down
3 changes: 2 additions & 1 deletion frappe_manager/docker_wrapper/DockerClient.py
Original file line number Diff line number Diff line change
Expand Up @@ -162,9 +162,10 @@ def rm(

def run(
self,
command: str,
image: str,
command: Optional[str] = None,
name: Optional[str] = None,
volume: Optional[str] = None,
detach: bool = False,
entrypoint: Optional[str] = None,
pull: Literal["missing", "never", "always"] = "missing",
Expand Down
10 changes: 7 additions & 3 deletions frappe_manager/main.py
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
import atexit
from frappe_manager.display_manager.DisplayManager import richprint
from frappe_manager.logger import log
from frappe_manager.utils.helpers import check_update, remove_zombie_subprocess_process
from frappe_manager.utils.helpers import check_update, remove_zombie_subprocess_process
from frappe_manager.utils.docker import process_opened
from frappe_manager.commands import app

Expand All @@ -11,8 +11,12 @@ def cli_entrypoint():
app()
except Exception as e:
logger = log.get_logger()
logger.exception(f"Exception: : {e}")
raise e
richprint.stop()
with richprint.stdout.capture() as capture:
richprint.stdout.print_exception(show_locals=True)
excep = capture.get()
logger.error(f"Exception Occured: : \n{excep}")

finally:
atexit.register(exit_cleanup)

Expand Down
16 changes: 11 additions & 5 deletions frappe_manager/site_manager/SiteManager.py
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@
import json
import shlex
from ruamel.yaml import serialize
from rich.prompt import Prompt
import typer
import shutil

Expand All @@ -14,6 +15,7 @@
from frappe_manager.docker_wrapper import DockerClient, DockerException
from frappe_manager import CLI_DIR
from rich.table import Table
from frappe_manager.utils.site import generate_services_table, domain_level

from frappe_manager.utils.site import generate_services_table

Expand All @@ -35,7 +37,7 @@ def init(self, sitename: str | None = None):
sitename (str | None): The name of the site. If None, the default site will be used.
"""
if sitename:
if not ".localhost" in sitename:
if domain_level(sitename) == 0:
sitename = sitename + ".localhost"
sitepath: Path = self.sitesdir / sitename

Expand Down Expand Up @@ -146,8 +148,9 @@ def create_site(self, template_inputs: dict,template_site: bool = False):
f"SITE_STATUS {self.site.name}: WORKING"
)
richprint.print(f"Started site")

self.info()
if not '.localhost' in self.site.name:
richprint.print(f"Please note that You will have to add a host entry to your system's hosts file to access the site locally.")
else:
self.typer_context.obj["logger"].error(f"{self.site.name}: NOT WORKING")

Expand All @@ -173,9 +176,12 @@ def remove_site(self):
"""
Removes the site.
"""
richprint.change_head(f"Removing Site")
self.site.remove_database_and_user()
self.site.remove()
richprint.stop()
continue_remove= Prompt.ask(f"🤔 Do you want to remove [bold][green]'{self.site.name}'[/bold][/green]", choices=["yes", "no"],default='no')
if continue_remove == 'yes':
richprint.start('Removing Site')
self.site.remove_database_and_user()
self.site.remove()

def list_sites(self):
"""
Expand Down
Loading