[ADD]Devcontainer template
This commit is contained in:
32
devcontainer/devcontainer.json
Normal file
32
devcontainer/devcontainer.json
Normal file
@@ -0,0 +1,32 @@
|
|||||||
|
{
|
||||||
|
"name": "Frappe Bench",
|
||||||
|
"forwardPorts": [8000, 9000, 6787],
|
||||||
|
"remoteUser": "frappe",
|
||||||
|
"customizations": {
|
||||||
|
"vscode": {
|
||||||
|
"extensions": [
|
||||||
|
"ms-python.python",
|
||||||
|
"ms-vscode.live-server",
|
||||||
|
"grapecity.gc-excelviewer",
|
||||||
|
"mtxr.sqltools",
|
||||||
|
"visualstudioexptteam.vscodeintellicode"
|
||||||
|
],
|
||||||
|
"settings": {
|
||||||
|
"terminal.integrated.profiles.linux": {
|
||||||
|
"frappe bash": {
|
||||||
|
"path": "/bin/bash"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"terminal.integrated.defaultProfile.linux": "frappe bash",
|
||||||
|
"debug.node.autoAttach": "disabled"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"dockerComposeFile": "./docker-compose.yml",
|
||||||
|
"service": "frappe",
|
||||||
|
"workspaceFolder": "/workspace/development",
|
||||||
|
"shutdownAction": "stopCompose",
|
||||||
|
"mounts": [
|
||||||
|
"source=${localEnv:HOME}${localEnv:USERPROFILE}/.ssh,target=/home/frappe/.ssh,type=bind,consistency=cached"
|
||||||
|
]
|
||||||
|
}
|
||||||
90
devcontainer/docker-compose.yml
Normal file
90
devcontainer/docker-compose.yml
Normal file
@@ -0,0 +1,90 @@
|
|||||||
|
version: "3.7"
|
||||||
|
services:
|
||||||
|
mariadb:
|
||||||
|
image: docker.io/mariadb:11.8
|
||||||
|
command:
|
||||||
|
- --character-set-server=utf8mb4
|
||||||
|
- --collation-server=utf8mb4_unicode_ci
|
||||||
|
- --skip-character-set-client-handshake
|
||||||
|
- --skip-innodb-read-only-compressed # Temporary fix for MariaDB 10.6
|
||||||
|
environment:
|
||||||
|
MYSQL_ROOT_PASSWORD: 123
|
||||||
|
MARIADB_AUTO_UPGRADE: 1
|
||||||
|
volumes:
|
||||||
|
- mariadb-data:/var/lib/mysql
|
||||||
|
|
||||||
|
# Enable PostgreSQL only if you use it, see development/README.md for more information.
|
||||||
|
# postgresql:
|
||||||
|
# image: postgres:14
|
||||||
|
# environment:
|
||||||
|
# POSTGRES_PASSWORD: 123
|
||||||
|
# volumes:
|
||||||
|
# - postgresql-data:/var/lib/postgresql/data
|
||||||
|
|
||||||
|
# Enable Mailpit if you need to test outgoing mail services
|
||||||
|
# See https://mailpit.axllent.org/
|
||||||
|
# mailpit:
|
||||||
|
# image: axllent/mailpit
|
||||||
|
# volumes:
|
||||||
|
# - mailpit-data:/data
|
||||||
|
# ports:
|
||||||
|
# - 8025:8025
|
||||||
|
# - 1025:1025
|
||||||
|
# environment:
|
||||||
|
# MP_MAX_MESSAGES: 5000
|
||||||
|
# MP_DATA_FILE: /data/mailpit.db
|
||||||
|
# MP_SMTP_AUTH_ACCEPT_ANY: 1
|
||||||
|
# MP_SMTP_AUTH_ALLOW_INSECURE: 1
|
||||||
|
|
||||||
|
redis-cache:
|
||||||
|
image: docker.io/redis:alpine
|
||||||
|
|
||||||
|
redis-queue:
|
||||||
|
image: docker.io/redis:alpine
|
||||||
|
|
||||||
|
frappe:
|
||||||
|
image: docker.io/frappe/bench:latest
|
||||||
|
# If you want to build the current bench image the Containerfile is in this Repo.
|
||||||
|
# build: ../images/bench
|
||||||
|
command: sleep infinity
|
||||||
|
environment:
|
||||||
|
- SHELL=/bin/bash
|
||||||
|
volumes:
|
||||||
|
- ..:/workspace:cached
|
||||||
|
# Enable if you require git cloning
|
||||||
|
# - ${HOME}/.ssh:/home/frappe/.ssh
|
||||||
|
working_dir: /workspace/development
|
||||||
|
ports:
|
||||||
|
- 8000-8005:8000-8005
|
||||||
|
- 9000-9005:9000-9005
|
||||||
|
# enable the below service if you need Cypress UI Tests to be executed
|
||||||
|
# Before enabling ensure install_x11_deps.sh has been executed and display variable is exported.
|
||||||
|
# Run install_x11_deps.sh again if DISPLAY is not set
|
||||||
|
# ui-tester:
|
||||||
|
# # pass custom command to start Cypress otherwise it will use the entrypoint
|
||||||
|
# # specified in the Cypress Docker image.
|
||||||
|
# # also pass "--project <folder>" so that when Cypress opens
|
||||||
|
# # it can find file "cypress.json" and show integration specs
|
||||||
|
# # https://on.cypress.io/command-line#cypress-open
|
||||||
|
# entrypoint: 'sleep infinity'
|
||||||
|
# image: "docker.io/cypress/included:latest"
|
||||||
|
# environment:
|
||||||
|
# - SHELL=/bin/bash
|
||||||
|
# # get the IP address of the host machine and allow X11 to accept
|
||||||
|
# # incoming connections from that IP address
|
||||||
|
# # IP=$(ipconfig getifaddr en0) or mac or \
|
||||||
|
# # IP=$($(hostname -I | awk '{print $1}') ) for Ubuntu
|
||||||
|
# # /usr/X11/bin/xhost + $IP
|
||||||
|
# # then pass the environment variable DISPLAY to show Cypress GUI on the host system
|
||||||
|
# # DISPLAY=$IP:0
|
||||||
|
# - DISPLAY
|
||||||
|
# volumes:
|
||||||
|
# # for Cypress to communicate with the X11 server pass this socket file
|
||||||
|
# # in addition to any other mapped volumes
|
||||||
|
# - /tmp/.X11-unix:/tmp/.X11-unix
|
||||||
|
# - ..:/workspace:z,cached
|
||||||
|
# network_mode: "host"
|
||||||
|
volumes:
|
||||||
|
mariadb-data:
|
||||||
|
#postgresql-data:
|
||||||
|
#mailpit-data:
|
||||||
77
development/.vscode/launch.json
vendored
Normal file
77
development/.vscode/launch.json
vendored
Normal file
@@ -0,0 +1,77 @@
|
|||||||
|
{
|
||||||
|
// Use IntelliSense to learn about possible attributes.
|
||||||
|
// Hover to view descriptions of existing attributes.
|
||||||
|
// For more information, visit: https://go.microsoft.com/fwlink/?linkid=830387
|
||||||
|
"version": "0.2.0",
|
||||||
|
"configurations": [
|
||||||
|
{
|
||||||
|
"name": "Bench Web",
|
||||||
|
"type": "debugpy",
|
||||||
|
"request": "launch",
|
||||||
|
"program": "${workspaceFolder}/frappe-bench/apps/frappe/frappe/utils/bench_helper.py",
|
||||||
|
"args": [
|
||||||
|
"frappe",
|
||||||
|
"serve",
|
||||||
|
"--port",
|
||||||
|
"8000",
|
||||||
|
"--noreload",
|
||||||
|
"--nothreading"
|
||||||
|
],
|
||||||
|
"cwd": "${workspaceFolder}/frappe-bench/sites",
|
||||||
|
"env": {
|
||||||
|
"DEV_SERVER": "1"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "Bench Short Worker",
|
||||||
|
"type": "debugpy",
|
||||||
|
"request": "launch",
|
||||||
|
"program": "${workspaceFolder}/frappe-bench/apps/frappe/frappe/utils/bench_helper.py",
|
||||||
|
"args": ["frappe", "worker", "--queue", "short"],
|
||||||
|
"cwd": "${workspaceFolder}/frappe-bench/sites",
|
||||||
|
"env": {
|
||||||
|
"DEV_SERVER": "1"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "Bench Default Worker",
|
||||||
|
"type": "debugpy",
|
||||||
|
"request": "launch",
|
||||||
|
"program": "${workspaceFolder}/frappe-bench/apps/frappe/frappe/utils/bench_helper.py",
|
||||||
|
"args": ["frappe", "worker", "--queue", "default"],
|
||||||
|
"cwd": "${workspaceFolder}/frappe-bench/sites",
|
||||||
|
"env": {
|
||||||
|
"DEV_SERVER": "1"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "Bench Long Worker",
|
||||||
|
"type": "debugpy",
|
||||||
|
"request": "launch",
|
||||||
|
"program": "${workspaceFolder}/frappe-bench/apps/frappe/frappe/utils/bench_helper.py",
|
||||||
|
"args": ["frappe", "worker", "--queue", "long"],
|
||||||
|
"cwd": "${workspaceFolder}/frappe-bench/sites",
|
||||||
|
"env": {
|
||||||
|
"DEV_SERVER": "1"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "Honcho SocketIO Watch Schedule Worker",
|
||||||
|
"type": "debugpy",
|
||||||
|
"request": "launch",
|
||||||
|
"python": "/home/frappe/.pyenv/shims/python",
|
||||||
|
"program": "/home/frappe/.local/bin/honcho",
|
||||||
|
"cwd": "${workspaceFolder}/frappe-bench",
|
||||||
|
"console": "internalConsole",
|
||||||
|
"args": ["start", "socketio", "watch", "schedule", "worker"],
|
||||||
|
"postDebugTask": "Clean Honcho SocketIO Watch Schedule Worker"
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"compounds": [
|
||||||
|
{
|
||||||
|
"name": "Honcho + Web debug",
|
||||||
|
"configurations": ["Bench Web", "Honcho SocketIO Watch Schedule Worker"],
|
||||||
|
"stopAll": true
|
||||||
|
}
|
||||||
|
]
|
||||||
|
}
|
||||||
3
development/.vscode/settings.json
vendored
Normal file
3
development/.vscode/settings.json
vendored
Normal file
@@ -0,0 +1,3 @@
|
|||||||
|
{
|
||||||
|
"python.defaultInterpreterPath": "${workspaceFolder}/frappe-bench/env/bin/python"
|
||||||
|
}
|
||||||
22
development/.vscode/tasks.json
vendored
Normal file
22
development/.vscode/tasks.json
vendored
Normal file
@@ -0,0 +1,22 @@
|
|||||||
|
{
|
||||||
|
// See https://go.microsoft.com/fwlink/?LinkId=733558
|
||||||
|
// for the documentation about the tasks.json format
|
||||||
|
"version": "2.0.0",
|
||||||
|
"tasks": [
|
||||||
|
{
|
||||||
|
"label": "Clean Honcho SocketIO Watch Schedule Worker",
|
||||||
|
"detail": "When stopping the debug process from vscode window, the honcho won't receive the SIGINT signal. This task will send the SIGINT signal to the honcho processes.",
|
||||||
|
"type": "shell",
|
||||||
|
"command": "pkill -SIGINT -f bench; pkill -SIGINT -f socketio",
|
||||||
|
"isBackground": false,
|
||||||
|
"presentation": {
|
||||||
|
"echo": true,
|
||||||
|
"reveal": "silent",
|
||||||
|
"focus": false,
|
||||||
|
"panel": "shared",
|
||||||
|
"showReuseMessage": false,
|
||||||
|
"close": true
|
||||||
|
}
|
||||||
|
}
|
||||||
|
]
|
||||||
|
}
|
||||||
6
development/apps-example.json
Normal file
6
development/apps-example.json
Normal file
@@ -0,0 +1,6 @@
|
|||||||
|
[
|
||||||
|
{
|
||||||
|
"url": "https://github.com/frappe/erpnext.git",
|
||||||
|
"branch": "version-15"
|
||||||
|
}
|
||||||
|
]
|
||||||
245
development/installer.py
Executable file
245
development/installer.py
Executable file
@@ -0,0 +1,245 @@
|
|||||||
|
#!/usr/bin/env python3
|
||||||
|
import argparse
|
||||||
|
import os
|
||||||
|
import subprocess
|
||||||
|
|
||||||
|
|
||||||
|
def cprint(*args, level: int = 1):
|
||||||
|
"""
|
||||||
|
logs colorful messages
|
||||||
|
level = 1 : RED
|
||||||
|
level = 2 : GREEN
|
||||||
|
level = 3 : YELLOW
|
||||||
|
|
||||||
|
default level = 1
|
||||||
|
"""
|
||||||
|
CRED = "\033[31m"
|
||||||
|
CGRN = "\33[92m"
|
||||||
|
CYLW = "\33[93m"
|
||||||
|
reset = "\033[0m"
|
||||||
|
message = " ".join(map(str, args))
|
||||||
|
if level == 1:
|
||||||
|
print(CRED, message, reset) # noqa: T001, T201
|
||||||
|
if level == 2:
|
||||||
|
print(CGRN, message, reset) # noqa: T001, T201
|
||||||
|
if level == 3:
|
||||||
|
print(CYLW, message, reset) # noqa: T001, T201
|
||||||
|
|
||||||
|
|
||||||
|
def main():
|
||||||
|
parser = get_args_parser()
|
||||||
|
args = parser.parse_args()
|
||||||
|
init_bench_if_not_exist(args)
|
||||||
|
create_site_in_bench(args)
|
||||||
|
|
||||||
|
|
||||||
|
def get_args_parser():
|
||||||
|
parser = argparse.ArgumentParser()
|
||||||
|
parser.add_argument(
|
||||||
|
"-j",
|
||||||
|
"--apps-json",
|
||||||
|
action="store",
|
||||||
|
type=str,
|
||||||
|
help="Path to apps.json, default: apps-example.json",
|
||||||
|
default="apps-example.json",
|
||||||
|
) # noqa: E501
|
||||||
|
parser.add_argument(
|
||||||
|
"-b",
|
||||||
|
"--bench-name",
|
||||||
|
action="store",
|
||||||
|
type=str,
|
||||||
|
help="Bench directory name, default: frappe-bench",
|
||||||
|
default="frappe-bench",
|
||||||
|
) # noqa: E501
|
||||||
|
parser.add_argument(
|
||||||
|
"-s",
|
||||||
|
"--site-name",
|
||||||
|
action="store",
|
||||||
|
type=str,
|
||||||
|
help="Site name, should end with .localhost, default: development.localhost", # noqa: E501
|
||||||
|
default="development.localhost",
|
||||||
|
)
|
||||||
|
parser.add_argument(
|
||||||
|
"-r",
|
||||||
|
"--frappe-repo",
|
||||||
|
action="store",
|
||||||
|
type=str,
|
||||||
|
help="frappe repo to use, default: https://github.com/frappe/frappe", # noqa: E501
|
||||||
|
default="https://github.com/frappe/frappe",
|
||||||
|
)
|
||||||
|
parser.add_argument(
|
||||||
|
"-t",
|
||||||
|
"--frappe-branch",
|
||||||
|
action="store",
|
||||||
|
type=str,
|
||||||
|
help="frappe repo to use, default: version-15", # noqa: E501
|
||||||
|
default="version-15",
|
||||||
|
)
|
||||||
|
parser.add_argument(
|
||||||
|
"-p",
|
||||||
|
"--py-version",
|
||||||
|
action="store",
|
||||||
|
type=str,
|
||||||
|
help="python version, default: Not Set", # noqa: E501
|
||||||
|
default=None,
|
||||||
|
)
|
||||||
|
parser.add_argument(
|
||||||
|
"-n",
|
||||||
|
"--node-version",
|
||||||
|
action="store",
|
||||||
|
type=str,
|
||||||
|
help="node version, default: Not Set", # noqa: E501
|
||||||
|
default=None,
|
||||||
|
)
|
||||||
|
parser.add_argument(
|
||||||
|
"-v",
|
||||||
|
"--verbose",
|
||||||
|
action="store_true",
|
||||||
|
help="verbose output", # noqa: E501
|
||||||
|
)
|
||||||
|
parser.add_argument(
|
||||||
|
"-a",
|
||||||
|
"--admin-password",
|
||||||
|
action="store",
|
||||||
|
type=str,
|
||||||
|
help="admin password for site, default: admin", # noqa: E501
|
||||||
|
default="admin",
|
||||||
|
)
|
||||||
|
parser.add_argument(
|
||||||
|
"-d",
|
||||||
|
"--db-type",
|
||||||
|
action="store",
|
||||||
|
type=str,
|
||||||
|
help="Database type to use (e.g., mariadb or postgres)",
|
||||||
|
default="mariadb", # Set your default database type here
|
||||||
|
)
|
||||||
|
return parser
|
||||||
|
|
||||||
|
|
||||||
|
def init_bench_if_not_exist(args):
|
||||||
|
if os.path.exists(args.bench_name):
|
||||||
|
cprint("Bench already exists. Only site will be created", level=3)
|
||||||
|
return
|
||||||
|
try:
|
||||||
|
env = os.environ.copy()
|
||||||
|
if args.py_version:
|
||||||
|
env["PYENV_VERSION"] = args.py_version
|
||||||
|
init_command = ""
|
||||||
|
if args.node_version:
|
||||||
|
init_command = f"nvm use {args.node_version};"
|
||||||
|
if args.py_version:
|
||||||
|
init_command += f"PYENV_VERSION={args.py_version} "
|
||||||
|
init_command += "bench init "
|
||||||
|
init_command += "--skip-redis-config-generation "
|
||||||
|
init_command += "--verbose " if args.verbose else " "
|
||||||
|
init_command += f"--frappe-path={args.frappe_repo} "
|
||||||
|
init_command += f"--frappe-branch={args.frappe_branch} "
|
||||||
|
init_command += f"--apps_path={args.apps_json} "
|
||||||
|
init_command += args.bench_name
|
||||||
|
command = [
|
||||||
|
"/bin/bash",
|
||||||
|
"-i",
|
||||||
|
"-c",
|
||||||
|
init_command,
|
||||||
|
]
|
||||||
|
subprocess.call(command, env=env, cwd=os.getcwd())
|
||||||
|
cprint("Configuring Bench ...", level=2)
|
||||||
|
cprint("Set db_host", level=3)
|
||||||
|
if args.db_type:
|
||||||
|
cprint(f"Setting db_type to {args.db_type}", level=3)
|
||||||
|
subprocess.call(
|
||||||
|
["bench", "set-config", "-g", "db_type", args.db_type],
|
||||||
|
cwd=os.path.join(os.getcwd(), args.bench_name),
|
||||||
|
)
|
||||||
|
|
||||||
|
cprint("Set redis_cache to redis://redis-cache:6379", level=3)
|
||||||
|
subprocess.call(
|
||||||
|
[
|
||||||
|
"bench",
|
||||||
|
"set-config",
|
||||||
|
"-g",
|
||||||
|
"redis_cache",
|
||||||
|
"redis://redis-cache:6379",
|
||||||
|
],
|
||||||
|
cwd=os.getcwd() + "/" + args.bench_name,
|
||||||
|
)
|
||||||
|
cprint("Set redis_queue to redis://redis-queue:6379", level=3)
|
||||||
|
subprocess.call(
|
||||||
|
[
|
||||||
|
"bench",
|
||||||
|
"set-config",
|
||||||
|
"-g",
|
||||||
|
"redis_queue",
|
||||||
|
"redis://redis-queue:6379",
|
||||||
|
],
|
||||||
|
cwd=os.getcwd() + "/" + args.bench_name,
|
||||||
|
)
|
||||||
|
cprint(
|
||||||
|
"Set redis_socketio to redis://redis-queue:6379 for backward compatibility", # noqa: E501
|
||||||
|
level=3,
|
||||||
|
)
|
||||||
|
subprocess.call(
|
||||||
|
[
|
||||||
|
"bench",
|
||||||
|
"set-config",
|
||||||
|
"-g",
|
||||||
|
"redis_socketio",
|
||||||
|
"redis://redis-queue:6379",
|
||||||
|
],
|
||||||
|
cwd=os.getcwd() + "/" + args.bench_name,
|
||||||
|
)
|
||||||
|
cprint("Set developer_mode", level=3)
|
||||||
|
subprocess.call(
|
||||||
|
["bench", "set-config", "-gp", "developer_mode", "1"],
|
||||||
|
cwd=os.getcwd() + "/" + args.bench_name,
|
||||||
|
)
|
||||||
|
except subprocess.CalledProcessError as e:
|
||||||
|
cprint(e.output, level=1)
|
||||||
|
|
||||||
|
|
||||||
|
def create_site_in_bench(args):
|
||||||
|
if "mariadb" == args.db_type:
|
||||||
|
cprint("Set db_host", level=3)
|
||||||
|
subprocess.call(
|
||||||
|
["bench", "set-config", "-g", "db_host", "mariadb"],
|
||||||
|
cwd=os.getcwd() + "/" + args.bench_name,
|
||||||
|
)
|
||||||
|
new_site_cmd = [
|
||||||
|
"bench",
|
||||||
|
"new-site",
|
||||||
|
f"--db-root-username=root",
|
||||||
|
f"--db-host=mariadb", # Should match the compose service name
|
||||||
|
f"--db-type={args.db_type}", # Add the selected database type
|
||||||
|
f"--mariadb-user-host-login-scope=%",
|
||||||
|
f"--db-root-password=123", # Replace with your MariaDB password
|
||||||
|
f"--admin-password={args.admin_password}",
|
||||||
|
]
|
||||||
|
else:
|
||||||
|
cprint("Set db_host", level=3)
|
||||||
|
subprocess.call(
|
||||||
|
["bench", "set-config", "-g", "db_host", "postgresql"],
|
||||||
|
cwd=os.getcwd() + "/" + args.bench_name,
|
||||||
|
)
|
||||||
|
new_site_cmd = [
|
||||||
|
"bench",
|
||||||
|
"new-site",
|
||||||
|
f"--db-root-username=root",
|
||||||
|
f"--db-host=postgresql", # Should match the compose service name
|
||||||
|
f"--db-type={args.db_type}", # Add the selected database type
|
||||||
|
f"--db-root-password=123", # Replace with your PostgreSQL password
|
||||||
|
f"--admin-password={args.admin_password}",
|
||||||
|
]
|
||||||
|
apps = os.listdir(f"{os.getcwd()}/{args.bench_name}/apps")
|
||||||
|
apps.remove("frappe")
|
||||||
|
for app in apps:
|
||||||
|
new_site_cmd.append(f"--install-app={app}")
|
||||||
|
new_site_cmd.append(args.site_name)
|
||||||
|
cprint(f"Creating Site {args.site_name} ...", level=2)
|
||||||
|
subprocess.call(
|
||||||
|
new_site_cmd,
|
||||||
|
cwd=os.getcwd() + "/" + args.bench_name,
|
||||||
|
)
|
||||||
|
|
||||||
|
|
||||||
|
if __name__ == "__main__":
|
||||||
|
main()
|
||||||
Reference in New Issue
Block a user