From 5c1d484df602c892cb25f6d2cd22cfd64a5b6019 Mon Sep 17 00:00:00 2001 From: Xieyt Date: Thu, 21 Mar 2024 15:44:40 +0530 Subject: [PATCH 1/4] support for workdir in code command --- frappe_manager/commands.py | 3 ++- frappe_manager/site_manager/SiteManager.py | 6 +++--- 2 files changed, 5 insertions(+), 4 deletions(-) diff --git a/frappe_manager/commands.py b/frappe_manager/commands.py index 1e00de35..e38b365d 100644 --- a/frappe_manager/commands.py +++ b/frappe_manager/commands.py @@ -308,12 +308,13 @@ def code( ] = DEFAULT_EXTENSIONS, force_start: Annotated[bool, typer.Option("--force-start", "-f", help="Force start the site before attaching to container.")] = False, debugger: Annotated[bool, typer.Option("--debugger", "-d", help="Sync vscode debugger configuration.")] = False, + workdir: Annotated[str, typer.Option("--work-dir", "-w", help="Set working directory in vscode.")] = '/workspace/frappe-bench', ): """Open site in vscode.""" sites.init(sitename) if force_start: sites.start_site() - sites.attach_to_site(user, extensions, debugger) + sites.attach_to_site(user, extensions, workdir,debugger) @app.command() diff --git a/frappe_manager/site_manager/SiteManager.py b/frappe_manager/site_manager/SiteManager.py index 2705e6ab..b15ca18f 100644 --- a/frappe_manager/site_manager/SiteManager.py +++ b/frappe_manager/site_manager/SiteManager.py @@ -230,7 +230,7 @@ def stop_site(self): self.site.stop() richprint.print(f"Stopped site") - def start_site(self,force: bool = False): + def start_site(self, force: bool = False): """ Starts the site. """ @@ -239,7 +239,7 @@ def start_site(self,force: bool = False): self.site.frappe_logs_till_start(status_msg="Starting Site") self.site.sync_workers_compose() - def attach_to_site(self, user: str, extensions: List[str], debugger: bool = False): + def attach_to_site(self, user: str, extensions: List[str], workdir: str, debugger: bool = False): """ Attaches to a running site's container using Visual Studio Code Remote Containers extension. @@ -262,7 +262,7 @@ def attach_to_site(self, user: str, extensions: List[str], debugger: bool = Fals vscode_cmd = shlex.join( [ vscode_path, - f"--folder-uri=vscode-remote://attached-container+{container_hex}+/workspace/frappe-bench", + f"--folder-uri=vscode-remote://attached-container+{container_hex}+{workdir}", ] ) extensions.sort() From 811961edc64c67a6abac4e8eab53d273102c1c8d Mon Sep 17 00:00:00 2001 From: Xieyt Date: Thu, 21 Mar 2024 15:52:50 +0530 Subject: [PATCH 2/4] bump: v0.12.0 --- Docker/images-tag.json | 2 +- .../migrations/{migrate_0_11_1.py => migrate_0_12_0.py} | 4 ++-- frappe_manager/templates/docker-compose.tmpl | 6 +++--- frappe_manager/templates/docker-compose.workers.tmpl | 2 +- pyproject.toml | 2 +- 5 files changed, 8 insertions(+), 8 deletions(-) rename frappe_manager/migration_manager/migrations/{migrate_0_11_1.py => migrate_0_12_0.py} (98%) diff --git a/Docker/images-tag.json b/Docker/images-tag.json index c95efc15..b64a43b9 100644 --- a/Docker/images-tag.json +++ b/Docker/images-tag.json @@ -1,5 +1,5 @@ { - "frappe": "v0.11.1", + "frappe": "v0.12.0", "nginx": "v0.10.0", "mailhog": "v0.8.3" } diff --git a/frappe_manager/migration_manager/migrations/migrate_0_11_1.py b/frappe_manager/migration_manager/migrations/migrate_0_12_0.py similarity index 98% rename from frappe_manager/migration_manager/migrations/migrate_0_11_1.py rename to frappe_manager/migration_manager/migrations/migrate_0_12_0.py index 84c8e43d..e8dde160 100644 --- a/frappe_manager/migration_manager/migrations/migrate_0_11_1.py +++ b/frappe_manager/migration_manager/migrations/migrate_0_12_0.py @@ -11,8 +11,8 @@ from frappe_manager import CLI_DIR -class MigrationV0110(MigrationBase): - version = Version("0.11.1") +class MigrationV0120(MigrationBase): + version = Version("0.12.0") def __init__(self): super().init() diff --git a/frappe_manager/templates/docker-compose.tmpl b/frappe_manager/templates/docker-compose.tmpl index 6d043c17..7013bef3 100644 --- a/frappe_manager/templates/docker-compose.tmpl +++ b/frappe_manager/templates/docker-compose.tmpl @@ -1,7 +1,7 @@ version: "3.9" services: frappe: - image: ghcr.io/rtcamp/frappe-manager-frappe:v0.11.1 + image: ghcr.io/rtcamp/frappe-manager-frappe:v0.12.0 container_name: REPLACE_ME_WITH_CONTAINER_NAME environment: ADMIN_PASS: REPLACE_me_with_frappe_web_admin_pass @@ -72,7 +72,7 @@ services: global-backend-network: socketio: - image: ghcr.io/rtcamp/frappe-manager-frappe:v0.11.1 + image: ghcr.io/rtcamp/frappe-manager-frappe:v0.12.0 container_name: REPLACE_ME_WITH_CONTAINER_NAME environment: TIMEOUT: 60000 @@ -90,7 +90,7 @@ services: site-network: schedule: - image: ghcr.io/rtcamp/frappe-manager-frappe:v0.11.1 + image: ghcr.io/rtcamp/frappe-manager-frappe:v0.12.0 container_name: REPLACE_ME_WITH_CONTAINER_NAME environment: TIMEOUT: 60000 diff --git a/frappe_manager/templates/docker-compose.workers.tmpl b/frappe_manager/templates/docker-compose.workers.tmpl index 22dd52b5..1d43d6eb 100644 --- a/frappe_manager/templates/docker-compose.workers.tmpl +++ b/frappe_manager/templates/docker-compose.workers.tmpl @@ -1,6 +1,6 @@ services: worker-name: - image: ghcr.io/rtcamp/frappe-manager-frappe:v0.11.1 + image: ghcr.io/rtcamp/frappe-manager-frappe:v0.12.0 environment: TIMEOUT: 6000 CHANGE_DIR: /workspace/frappe-bench diff --git a/pyproject.toml b/pyproject.toml index ca6a5bb2..214d3f63 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -1,6 +1,6 @@ [tool.poetry] name = "frappe-manager" -version = "0.11.1" +version = "0.12.0" license = "MIT" repository = "https://github.com/rtcamp/frappe-manager" description = "A CLI tool based on Docker Compose to easily manage Frappe based projects. As of now, only suitable for development in local machines running on Mac and Linux based OS." From 6f09574e9e8dde7b99a2cd7f431d19f68b4cc3bb Mon Sep 17 00:00:00 2001 From: Xieyt Date: Thu, 21 Mar 2024 19:55:12 +0530 Subject: [PATCH 3/4] fix: frappe container some files permission issue --- Docker/frappe/entrypoint.sh | 10 ++++------ 1 file changed, 4 insertions(+), 6 deletions(-) diff --git a/Docker/frappe/entrypoint.sh b/Docker/frappe/entrypoint.sh index e83b942a..44d533bb 100755 --- a/Docker/frappe/entrypoint.sh +++ b/Docker/frappe/entrypoint.sh @@ -19,21 +19,19 @@ mkdir -p /opt/user/conf.d chown -R "$USERID":"$USERGROUP" /opt if [[ ! -d "/workspace/.oh-my-zsh" ]]; then - cp -r /opt/user/.oh-my-zsh /workspace/.oh-my-zsh + cp -pr /opt/user/.oh-my-zsh /workspace/ fi if [[ ! -f "/workspace/.zshrc" ]]; then - cat /opt/user/.zshrc > /workspace/.zshrc + cp -p /opt/user/.zshrc /workspace/ fi if [[ ! -f "/workspace/.profile" ]]; then - cat /opt/user/.profile > /workspace/.profile + cp -p /opt/user/.profile /workspace/ fi chown "$USERID":"$USERGROUP" /workspace /workspace/frappe-bench - -ls -p /workspace | grep -v 'frappe-bench/' | xargs -I{} chown -R "$USERID":"$USERGROUP" /workspace{} - +ls -pA /workspace | xargs -I{} chown -R "$USERID":"$USERGROUP" /workspace/{} & if [ "$#" -gt 0 ]; then gosu "$USERID":"$USERGROUP" "/scripts/$@" From 0409202e23763d0ee13a7c5a43cf42017cefb7b7 Mon Sep 17 00:00:00 2001 From: Xieyt Date: Thu, 21 Mar 2024 22:16:30 +0530 Subject: [PATCH 4/4] enable force recreate for workers --- frappe_manager/site_manager/site.py | 16 +++---- .../workers_manager/SiteWorker.py | 48 +++++++++---------- 2 files changed, 30 insertions(+), 34 deletions(-) diff --git a/frappe_manager/site_manager/site.py b/frappe_manager/site_manager/site.py index b3e16c91..04700e0c 100644 --- a/frappe_manager/site_manager/site.py +++ b/frappe_manager/site_manager/site.py @@ -43,7 +43,7 @@ def validate_sitename(self) -> bool: match = is_fqdn(sitename) if not match: - richprint.error(f"The {sitename} must follow Fully Qualified Domain Name (FQDN) format.",exception=SiteException(self, f"Valid FQDN site name not provided.")) + richprint.error(f"The {sitename} must follow Fully Qualified Domain Name (FQDN) format.", exception=SiteException(self, f"Valid FQDN site name not provided.")) return True @@ -199,7 +199,7 @@ def create_compose_dirs(self) -> bool: return True - def start(self,force: bool = False) -> bool: + def start(self, force: bool = False) -> bool: """ Starts the Docker containers for the site. @@ -210,16 +210,16 @@ def start(self,force: bool = False) -> bool: richprint.change_head(status_text) try: - output = self.docker.compose.up(detach=True, pull="never",force_recreate=force, stream=self.quiet) + output = self.docker.compose.up(detach=True, pull="never", force_recreate=force, stream=self.quiet) if self.quiet: richprint.live_lines(output, padding=(0, 0, 0, 2)) richprint.print(f"{status_text}: Done") except DockerException as e: - richprint.error(f"{status_text}: Failed",exception=e) + richprint.error(f"{status_text}: Failed", exception=e) # start workers if exists if self.workers.exists(): - self.workers.start() + self.workers.start(force=force) return True @@ -314,7 +314,7 @@ def stop(self) -> bool: richprint.live_lines(output, padding=(0, 0, 0, 2)) richprint.print(f"{status_text}: Done") except DockerException as e: - richprint.error(f"{status_text}: Failed",exception=e) + richprint.error(f"{status_text}: Failed", exception=e) # stopping worker containers if self.workers.exists(): @@ -346,7 +346,7 @@ def down(self, remove_ophans=True, volumes=True, timeout=5) -> bool: exit_code = richprint.live_lines(output, padding=(0, 0, 0, 2)) richprint.print(f"{status_text}: Done") except DockerException as e: - richprint.error(f"{status_text}: Failed",exception=e) + richprint.error(f"{status_text}: Failed", exception=e) def remove(self) -> bool: """ @@ -371,7 +371,7 @@ def remove(self) -> bool: exit_code = richprint.live_lines(output, padding=(0, 0, 0, 2)) richprint.print(f"Removing Containers: Done") except DockerException as e: - richprint.error(f"{status_text}: Failed",exception=e) + richprint.error(f"{status_text}: Failed", exception=e) richprint.change_head(f"Removing Dirs") diff --git a/frappe_manager/site_manager/workers_manager/SiteWorker.py b/frappe_manager/site_manager/workers_manager/SiteWorker.py index 4c34de16..01487870 100644 --- a/frappe_manager/site_manager/workers_manager/SiteWorker.py +++ b/frappe_manager/site_manager/workers_manager/SiteWorker.py @@ -9,24 +9,24 @@ from frappe_manager.docker_wrapper.DockerClient import DockerClient from frappe_manager.docker_wrapper.DockerException import DockerException + class SiteWorkers: - def __init__(self,site_path, site_name, quiet: bool = True): + def __init__(self, site_path, site_name, quiet: bool = True): self.compose_path = site_path / "docker-compose.workers.yml" - self.config_dir = site_path / 'workspace' / 'frappe-bench' / 'config' - self.supervisor_config_path = self.config_dir / 'supervisor.conf' + self.config_dir = site_path / "workspace" / "frappe-bench" / "config" + self.supervisor_config_path = self.config_dir / "supervisor.conf" self.site_name = site_name self.quiet = quiet self.init() def init(self): - self.composefile = ComposeFile( self.compose_path, template_name='docker-compose.workers.tmpl') + self.composefile = ComposeFile(self.compose_path, template_name="docker-compose.workers.tmpl") self.docker = DockerClient(compose_file_path=self.composefile.compose_path) def exists(self): return self.compose_path.exists() - def get_expected_workers(self)-> list[str]: - + def get_expected_workers(self) -> list[str]: richprint.change_head("Getting Workers info") workers_supervisor_conf_paths = [] @@ -34,15 +34,15 @@ def get_expected_workers(self)-> list[str]: for file_path in self.config_dir.iterdir(): file_path_abs = str(file_path.absolute()) if file_path.is_file(): - if file_path_abs.endswith('.workers.fm.supervisor.conf'): + if file_path_abs.endswith(".workers.fm.supervisor.conf"): workers_supervisor_conf_paths.append(file_path) workers_expected_service_names = [] for worker_name in workers_supervisor_conf_paths: worker_name = worker_name.name - worker_name = worker_name.replace("frappe-bench-frappe-","") - worker_name = worker_name.replace(".workers.fm.supervisor.conf","") + worker_name = worker_name.replace("frappe-bench-frappe-", "") + worker_name = worker_name.replace(".workers.fm.supervisor.conf", "") workers_expected_service_names.append(worker_name) workers_expected_service_names.sort() @@ -52,7 +52,6 @@ def get_expected_workers(self)-> list[str]: return workers_expected_service_names def is_expected_worker_same_as_template(self) -> bool: - if not self.composefile.is_template_loaded: prev_workers = self.composefile.get_services_list() prev_workers.sort() @@ -72,24 +71,25 @@ def generate_compose(self): # create compose file for workers self.composefile.yml = self.composefile.load_template() - template_worker_config = self.composefile.yml['services']['worker-name'] + template_worker_config = self.composefile.yml["services"]["worker-name"] - del self.composefile.yml['services']['worker-name'] + del self.composefile.yml["services"]["worker-name"] workers_expected_service_names = self.get_expected_workers() if len(workers_expected_service_names) > 0: import os + for worker in workers_expected_service_names: worker_config = deepcopy(template_worker_config) # setting environments - worker_config['environment']['WAIT_FOR'] = str(worker_config['environment']['WAIT_FOR']).replace("{worker-name}",worker) - worker_config['environment']['COMMAND'] = str(worker_config['environment']['COMMAND']).replace("{worker-name}",worker) - worker_config['environment']['USERID'] = os.getuid() - worker_config['environment']['USERGROUP'] = os.getgid() + worker_config["environment"]["WAIT_FOR"] = str(worker_config["environment"]["WAIT_FOR"]).replace("{worker-name}", worker) + worker_config["environment"]["COMMAND"] = str(worker_config["environment"]["COMMAND"]).replace("{worker-name}", worker) + worker_config["environment"]["USERID"] = os.getuid() + worker_config["environment"]["USERGROUP"] = os.getgid() - self.composefile.yml['services'][worker] = worker_config + self.composefile.yml["services"][worker] = worker_config self.composefile.set_container_names(get_container_name_prefix(self.site_name)) @@ -97,21 +97,21 @@ def generate_compose(self): self.composefile.set_version(fm_version) # set network name - self.composefile.yml["networks"]["site-network"]["name"] = (self.site_name.replace(".", "") + f"-network") + self.composefile.yml["networks"]["site-network"]["name"] = self.site_name.replace(".", "") + f"-network" self.composefile.write_to_file() else: richprint.error("Workers configuration not found.") - def start(self): + def start(self, force=False): status_text = "Starting Workers Containers" richprint.change_head(status_text) try: - output = self.docker.compose.up(detach=True, pull="never", stream=self.quiet) + output = self.docker.compose.up(detach=True, pull="never", force_recreate=force, stream=self.quiet) if self.quiet: richprint.live_lines(output, padding=(0, 0, 0, 2)) richprint.print(f"{status_text}: Done") except DockerException as e: - richprint.error (f"{status_text}: Failed Error: {e}") + richprint.error(f"{status_text}: Failed Error: {e}") raise e def stop(self) -> bool: @@ -130,15 +130,12 @@ def stop(self) -> bool: richprint.warning(f"{status_text}: Failed") def get_services_running_status(self) -> dict: - services = self.composefile.get_services_list() containers = self.composefile.get_container_names().values() services_status = {} try: - output = self.docker.compose.ps( - service=services, format="json", all=True, stream=True - ) + output = self.docker.compose.ps(service=services, format="json", all=True, stream=True) status: list = [] for source, line in output: if source == "stdout": @@ -156,7 +153,6 @@ def get_services_running_status(self) -> dict: except DockerException as e: return {} - def running(self) -> bool: """ The `running` function checks if all the services defined in a Docker Compose file are running.