2
0
mirror of https://github.com/frappe/bench.git synced 2025-01-24 07:28:25 +00:00

style: chmod+x, format, space -> tabs

This commit is contained in:
Ankush Menat 2022-12-16 17:32:45 +05:30
parent 80b58d9999
commit a987c1e9ae

535
easy-install.py Normal file → Executable file
View File

@ -1,94 +1,95 @@
#!/usr/bin/env python3 #!/usr/bin/env python3
import argparse import argparse
import subprocess import logging
import os import os
import platform
import subprocess
import sys import sys
import time import time
import urllib.request import urllib.request
import logging from shutil import move, unpack_archive, which
import platform
from shutil import which, unpack_archive, move
from hashlib import sha224
from typing import Dict from typing import Dict
logging.basicConfig( logging.basicConfig(
filename="easy-install.log", filename="easy-install.log",
filemode="w", filemode="w",
format="%(asctime)s - %(levelname)s - %(message)s", format="%(asctime)s - %(levelname)s - %(message)s",
level=logging.INFO, level=logging.INFO,
) )
def cprint(*args, level: int = 1): def cprint(*args, level: int = 1):
""" """
logs colorful messages logs colorful messages
level = 1 : RED level = 1 : RED
level = 2 : GREEN level = 2 : GREEN
level = 3 : YELLOW level = 3 : YELLOW
default level = 1 default level = 1
""" """
CRED = "\033[31m" CRED = "\033[31m"
CGRN = "\33[92m" CGRN = "\33[92m"
CYLW = "\33[93m" CYLW = "\33[93m"
reset = "\033[0m" reset = "\033[0m"
message = " ".join(map(str, args)) message = " ".join(map(str, args))
if level == 1: if level == 1:
print(CRED, message, reset) print(CRED, message, reset)
if level == 2: if level == 2:
print(CGRN, message, reset) print(CGRN, message, reset)
if level == 3: if level == 3:
print(CYLW, message, reset) print(CYLW, message, reset)
def clone_frappe_docker_repo() -> None: def clone_frappe_docker_repo() -> None:
try: try:
urllib.request.urlretrieve( urllib.request.urlretrieve(
"https://github.com/frappe/frappe_docker/archive/refs/heads/main.zip", "https://github.com/frappe/frappe_docker/archive/refs/heads/main.zip",
"frappe_docker.zip", "frappe_docker.zip",
) )
logging.info("Downloaded frappe_docker zip file from GitHub") logging.info("Downloaded frappe_docker zip file from GitHub")
unpack_archive( unpack_archive(
"frappe_docker.zip", "." "frappe_docker.zip", "."
) # Unzipping the frappe_docker.zip creates a folder "frappe_docker-main" ) # Unzipping the frappe_docker.zip creates a folder "frappe_docker-main"
move("frappe_docker-main", "frappe_docker") move("frappe_docker-main", "frappe_docker")
logging.info("Unzipped and Renamed frappe_docker") logging.info("Unzipped and Renamed frappe_docker")
os.remove("frappe_docker.zip") os.remove("frappe_docker.zip")
logging.info("Removed the downloaded zip file") logging.info("Removed the downloaded zip file")
except Exception as e: except Exception as e:
logging.error("Download and unzip failed", exc_info=True) logging.error("Download and unzip failed", exc_info=True)
cprint("\nCloning frappe_docker Failed\n\n", "[ERROR]: ", e, level=1) cprint("\nCloning frappe_docker Failed\n\n", "[ERROR]: ", e, level=1)
def get_from_env(dir,file) -> Dict:
env_vars ={} def get_from_env(dir, file) -> Dict:
with open(os.path.join(dir,file)) as f: env_vars = {}
for line in f: with open(os.path.join(dir, file)) as f:
if line.startswith('#') or not line.strip(): for line in f:
continue if line.startswith("#") or not line.strip():
key, value = line.strip().split('=', 1) continue
env_vars[key] = value key, value = line.strip().split("=", 1)
return env_vars env_vars[key] = value
return env_vars
def write_to_env(wd: str, site: str, db_pass: str, admin_pass: str, email: str) -> None: def write_to_env(wd: str, site: str, db_pass: str, admin_pass: str, email: str) -> None:
site_name = site or "" site_name = site or ""
example_env = get_from_env(wd,"example.env") example_env = get_from_env(wd, "example.env")
with open(os.path.join(wd, ".env"), "w") as f: with open(os.path.join(wd, ".env"), "w") as f:
f.writelines( f.writelines(
[ [
f"FRAPPE_VERSION={example_env['FRAPPE_VERSION']}\n", # Defaults to latest version of Frappe f"FRAPPE_VERSION={example_env['FRAPPE_VERSION']}\n", # Defaults to latest version of Frappe
f"ERPNEXT_VERSION={example_env['ERPNEXT_VERSION']}\n", # defaults to latest version of ERPNext f"ERPNEXT_VERSION={example_env['ERPNEXT_VERSION']}\n", # defaults to latest version of ERPNext
f"DB_PASSWORD={db_pass}\n", f"DB_PASSWORD={db_pass}\n",
"DB_HOST=db\n", "DB_HOST=db\n",
"DB_PORT=3306\n", "DB_PORT=3306\n",
"REDIS_CACHE=redis-cache:6379\n", "REDIS_CACHE=redis-cache:6379\n",
"REDIS_QUEUE=redis-queue:6379\n", "REDIS_QUEUE=redis-queue:6379\n",
"REDIS_SOCKETIO=redis-socketio:6379\n", "REDIS_SOCKETIO=redis-socketio:6379\n",
f"LETSENCRYPT_EMAIL={email}\n", f"LETSENCRYPT_EMAIL={email}\n",
f"FRAPPE_SITE_NAME_HEADER={site_name}\n", f"FRAPPE_SITE_NAME_HEADER={site_name}\n",
f"SITE_ADMIN_PASS={admin_pass}", f"SITE_ADMIN_PASS={admin_pass}",
] ]
) )
def generate_pass(length: int = 12) -> str: def generate_pass(length: int = 12) -> str:
@ -103,221 +104,217 @@ def generate_pass(length: int = 12) -> str:
def check_repo_exists() -> bool: def check_repo_exists() -> bool:
return os.path.exists(os.path.join(os.getcwd(), "frappe_docker")) return os.path.exists(os.path.join(os.getcwd(), "frappe_docker"))
def setup_prod(project: str, sitename: str, email: str) -> None: def setup_prod(project: str, sitename: str, email: str) -> None:
if check_repo_exists(): if check_repo_exists():
compose_file_name = os.path.join( compose_file_name = os.path.join(os.path.expanduser("~"), f"{project}-compose.yml")
os.path.expanduser("~"), f"{project}-compose.yml" docker_repo_path = os.path.join(os.getcwd(), "frappe_docker")
) cprint(
docker_repo_path = os.path.join(os.getcwd(), "frappe_docker") "\nPlease refer to .example.env file in the frappe_docker folder to know which keys to set\n\n",
cprint( level=3,
"\nPlease refer to .example.env file in the frappe_docker folder to know which keys to set\n\n", )
level=3, admin_pass = ""
) db_pass = ""
admin_pass = "" with open(compose_file_name, "w") as f:
db_pass = "" # Writing to compose file
with open(compose_file_name, "w") as f: if not os.path.exists(os.path.join(docker_repo_path, ".env")):
# Writing to compose file admin_pass = generate_pass()
if not os.path.exists(os.path.join(docker_repo_path, ".env")): db_pass = generate_pass(9)
admin_pass = generate_pass() write_to_env(docker_repo_path, sitename, db_pass, admin_pass, email)
db_pass = generate_pass(9) cprint(
write_to_env(docker_repo_path, sitename, db_pass, admin_pass, email) "\nA .env file is generated with basic configs. Please edit it to fit to your needs \n",
cprint( level=3,
"\nA .env file is generated with basic configs. Please edit it to fit to your needs \n", )
level=3, with open(os.path.join(os.path.expanduser("~"), "passwords.txt"), "w") as en:
) en.writelines(f"ADMINISTRATOR_PASSWORD={admin_pass}\n")
with open( en.writelines(f"MARIADB_ROOT_PASSWORD={db_pass}\n")
os.path.join(os.path.expanduser("~"), "passwords.txt"), "w" else:
) as en: env = get_from_env(docker_repo_path, ".env")
en.writelines(f"ADMINISTRATOR_PASSWORD={admin_pass}\n") admin_pass = env["SITE_ADMIN_PASS"]
en.writelines(f"MARIADB_ROOT_PASSWORD={db_pass}\n") db_pass = env["DB_PASSWORD"]
else: try:
env = get_from_env(docker_repo_path,".env") # TODO: Include flags for non-https and non-erpnext installation
admin_pass = env['SITE_ADMIN_PASS'] subprocess.run(
db_pass = env['DB_PASSWORD'] [
try: which("docker"),
# TODO: Include flags for non-https and non-erpnext installation "compose",
subprocess.run( "--project-name",
[ project,
which("docker"), "-f",
"compose", "compose.yaml",
"--project-name", "-f",
project, "overrides/compose.mariadb.yaml",
"-f", "-f",
"compose.yaml", "overrides/compose.redis.yaml",
"-f", # "-f", "overrides/compose.noproxy.yaml", TODO: Add support for local proxying without HTTPs
"overrides/compose.mariadb.yaml", "-f",
"-f", "overrides/compose.erpnext.yaml",
"overrides/compose.redis.yaml", "-f",
# "-f", "overrides/compose.noproxy.yaml", TODO: Add support for local proxying without HTTPs "overrides/compose.https.yaml",
"-f", "--env-file",
"overrides/compose.erpnext.yaml", ".env",
"-f", "config",
"overrides/compose.https.yaml", ],
"--env-file", cwd=docker_repo_path,
".env", stdout=f,
"config", check=True,
], )
cwd=docker_repo_path,
stdout=f,
check=True,
)
except Exception as e: except Exception:
logging.error("Docker Compose generation failed", exc_info=True) logging.error("Docker Compose generation failed", exc_info=True)
cprint("\nGenerating Compose File failed\n") cprint("\nGenerating Compose File failed\n")
sys.exit(1) sys.exit(1)
try: try:
# Starting with generated compose file # Starting with generated compose file
subprocess.run( subprocess.run(
[ [
which("docker"), which("docker"),
"compose", "compose",
"-p", "-p",
project, project,
"-f", "-f",
compose_file_name, compose_file_name,
"up", "up",
"-d", "-d",
], ],
check=True, check=True,
) )
logging.info(f"Docker Compose file generated at ~/{project}-compose.yml") logging.info(f"Docker Compose file generated at ~/{project}-compose.yml")
except Exception as e: except Exception as e:
logging.error("Prod docker-compose failed", exc_info=True) logging.error("Prod docker-compose failed", exc_info=True)
cprint(" Docker Compose failed, please check the container logs\n", e) cprint(" Docker Compose failed, please check the container logs\n", e)
sys.exit(1) sys.exit(1)
cprint(f"\nCreating site: {sitename} \n", level=3) cprint(f"\nCreating site: {sitename} \n", level=3)
try: try:
subprocess.run( subprocess.run(
[ [
which("docker"), which("docker"),
"compose", "compose",
"-p", "-p",
project, project,
"exec", "exec",
"backend", "backend",
"bench", "bench",
"new-site", "new-site",
sitename, sitename,
"--db-root-password", "--db-root-password",
db_pass, db_pass,
"--admin-password", "--admin-password",
admin_pass, admin_pass,
"--install-app", "--install-app",
"erpnext", "erpnext",
"--set-default" "--set-default",
], ],
check=True, check=True,
) )
logging.info("New site creation completed") logging.info("New site creation completed")
except Exception as e: except Exception as e:
logging.error("Bench site creation failed", exc_info=True) logging.error("Bench site creation failed", exc_info=True)
cprint("Bench Site creation failed\n", e) cprint("Bench Site creation failed\n", e)
sys.exit(1) sys.exit(1)
else: else:
install_docker() install_docker()
clone_frappe_docker_repo() clone_frappe_docker_repo()
setup_prod(project, sitename, email) # Recursive setup_prod(project, sitename, email) # Recursive
def setup_dev_instance(project: str): def setup_dev_instance(project: str):
if check_repo_exists(): if check_repo_exists():
try: try:
subprocess.run( subprocess.run(
[ [
"docker", "docker",
"compose", "compose",
"-f", "-f",
"devcontainer-example/docker-compose.yml", "devcontainer-example/docker-compose.yml",
"--project-name", "--project-name",
project, project,
"up", "up",
"-d", "-d",
], ],
cwd=os.path.join(os.getcwd(), "frappe_docker"), cwd=os.path.join(os.getcwd(), "frappe_docker"),
check=True, check=True,
) )
cprint( cprint(
"Please go through the Development Documentation: https://github.com/frappe/frappe_docker/tree/main/development to fully complete the setup.", "Please go through the Development Documentation: https://github.com/frappe/frappe_docker/tree/main/development to fully complete the setup.",
level=2, level=2,
) )
logging.info("Development Setup completed") logging.info("Development Setup completed")
except Exception as e: except Exception as e:
logging.error("Dev Environment setup failed", exc_info=True) logging.error("Dev Environment setup failed", exc_info=True)
cprint("Setting Up Development Environment Failed\n", e) cprint("Setting Up Development Environment Failed\n", e)
else: else:
install_docker() install_docker()
clone_frappe_docker_repo() clone_frappe_docker_repo()
setup_dev_instance(project) # Recursion on goes brrrr setup_dev_instance(project) # Recursion on goes brrrr
def install_docker(): def install_docker():
if which("docker") is not None: if which("docker") is not None:
return return
cprint("Docker is not installed, Installing Docker...", level=3) cprint("Docker is not installed, Installing Docker...", level=3)
logging.info("Docker not found, installing Docker") logging.info("Docker not found, installing Docker")
if platform.system() == "Darwin" or platform.system() == "Windows": if platform.system() == "Darwin" or platform.system() == "Windows":
print( print(
f""" f"""
This script doesn't install Docker on {"Mac" if platform.system()=="Darwin" else "Windows"}. This script doesn't install Docker on {"Mac" if platform.system()=="Darwin" else "Windows"}.
Please go through the Docker Installation docs for your system and run this script again""" Please go through the Docker Installation docs for your system and run this script again"""
) )
logging.debug("Docker setup failed due to platform is not Linux") logging.debug("Docker setup failed due to platform is not Linux")
sys.exit(1) sys.exit(1)
try: try:
ps = subprocess.run( ps = subprocess.run(
["curl", "-fsSL", "https://get.docker.com"], ["curl", "-fsSL", "https://get.docker.com"],
capture_output=True, capture_output=True,
check=True, check=True,
) )
subprocess.run(["/bin/bash"], input=ps.stdout, capture_output=True) subprocess.run(["/bin/bash"], input=ps.stdout, capture_output=True)
subprocess.run( subprocess.run(
["sudo", "usermod", "-aG", "docker", str(os.getenv("USER"))], check=True ["sudo", "usermod", "-aG", "docker", str(os.getenv("USER"))], check=True
) )
cprint("Waiting Docker to start", level=3) cprint("Waiting Docker to start", level=3)
time.sleep(10) time.sleep(10)
subprocess.run(["sudo", "systemctl", "restart", "docker.service"], check=True) subprocess.run(["sudo", "systemctl", "restart", "docker.service"], check=True)
except Exception as e: except Exception as e:
logging.error("Installing Docker failed", exc_info=True) logging.error("Installing Docker failed", exc_info=True)
cprint("Failed to Install Docker\n", e) cprint("Failed to Install Docker\n", e)
cprint("\n Try Installing Docker Manually and re-run this script again\n") cprint("\n Try Installing Docker Manually and re-run this script again\n")
sys.exit(1) sys.exit(1)
if __name__ == "__main__": if __name__ == "__main__":
parser = argparse.ArgumentParser(description="Install Frappe with Docker") parser = argparse.ArgumentParser(description="Install Frappe with Docker")
parser.add_argument( parser.add_argument(
"-p", "--prod", help="Setup Production System", action="store_true" "-p", "--prod", help="Setup Production System", action="store_true"
) )
parser.add_argument( parser.add_argument(
"-d", "--dev", help="Setup Development System", action="store_true" "-d", "--dev", help="Setup Development System", action="store_true"
) )
parser.add_argument( parser.add_argument(
"-s", "-s",
"--sitename", "--sitename",
help="The Site Name for your production site", help="The Site Name for your production site",
default="site1.local", default="site1.local",
) )
parser.add_argument("-n", "--project", help="Project Name", default="frappe") parser.add_argument("-n", "--project", help="Project Name", default="frappe")
parser.add_argument( parser.add_argument(
"--email", help="Add email for the SSL.", required="--prod" in sys.argv "--email", help="Add email for the SSL.", required="--prod" in sys.argv
) )
args = parser.parse_args() args = parser.parse_args()
if args.dev: if args.dev:
cprint("\nSetting Up Development Instance\n", level=2) cprint("\nSetting Up Development Instance\n", level=2)
logging.info("Running Development Setup") logging.info("Running Development Setup")
setup_dev_instance(args.project) setup_dev_instance(args.project)
elif args.prod: elif args.prod:
cprint("\nSetting Up Production Instance\n", level=2) cprint("\nSetting Up Production Instance\n", level=2)
logging.info("Running Production Setup") logging.info("Running Production Setup")
if "example.com" in args.email: if "example.com" in args.email:
cprint("Emails with example.com not acceptable", level=1) cprint("Emails with example.com not acceptable", level=1)
sys.exit(1) sys.exit(1)
setup_prod(args.project, args.sitename, args.email) setup_prod(args.project, args.sitename, args.email)