本文已参与「新人创作礼」活动,一起开启掘金创作之路。
fabfile.py文件内容如下:
import functools
import os
import sys
from pathlib import Path
from typing import Callable, Optional
from dotenv import load_dotenv
from fabric import Connection, task
load_dotenv()
"""
to update code of server, run the following command:
$ fab pull
"""
USER = "my-username"
DOMAIN = "www.my-domain.com"
PROJECT = Path(__file__).parent.resolve().name
REPO = "~/coding/" + PROJECT
HOST = f"{USER}@{DOMAIN}"
def run_and_echo(cmd: str, func: Optional[Callable] = None) -> int:
print("-->", cmd)
if func is None:
func = os.system
return func(cmd)
def seconds_after_lock_updated() -> str:
"""print the seconds passed after `poetry.lock` last motified"""
s = """
from datetime import datetime
from os.path import getmtime, exists
fn = 'poetry.lock'
fname = fn if exists(fn) else 'pyproject.toml'
mtime = datetime.fromtimestamp(getmtime(fname))
passed = datetime.now() - mtime
print(passed.seconds)
"""
cmd = ";".join(i.strip() for i in s.strip().split("\n"))
return f"python3 -c {cmd!r}"
def parse_args(domain=None, host=None, port: int = 22):
if host is None:
if domain is None:
host = HOST
else:
user = os.getenv(f"{domain}_user")
host = f"{user}@{domain}"
if domain is None:
domain = host.split("@")[-1]
if p := os.getenv(f"{domain}_port"): # noqa: E231, E203
port = int(p or port)
return domain, host, port
def make_connection(domain=None, host=None, port: int = 22):
domain, host, port = parse_args(domain, host, port)
passwd = os.getenv(f"{domain}_passwd")
c = Connection(host, port=port, connect_kwargs={"password": passwd})
print(f"Success to make a connection with {host}")
return c
def git_push(func):
@functools.wraps(func)
def wrap(*args, **kwargs):
if run_and_echo("git push") != 0:
sys.exit()
return func(*args, **kwargs)
return wrap
@git_push
def remote_exec(repo: str, cmd: str) -> None:
c = make_connection()
with c.cd(repo):
run_and_echo(cmd, c.run)
print("Done!")
@task
def pull(c, repo=REPO):
_pull(c, repo)
def _pull(c, repo: str) -> None:
remote_exec(repo, "git pull")
@task
def gitpull(c, repo=REPO):
_pull(c, repo)
@task
def migrate(c, repo=REPO):
cmd = "git pull && poetry run python manage.py migrate"
remote_exec(repo, cmd)
@task
def restart(c, repo=REPO):
_restart(c, repo)
@task
def rs(c, repo=REPO):
_restart(c, repo)
def _restart(c, repo: str) -> None:
cmd = f"git pull && sudo supervisorctl restart {PROJECT}"
remote_exec(repo, cmd)
@task
def roll(c, repo=REPO):
cmd = "git reset --hard HEAD"
remote_exec(repo, cmd)
@task
def lock(c, repo=REPO):
cmd = "git pull && poetry lock && git commit -am 'poetry lock' && git push"
remote_exec(repo, cmd)
注:
- 需要Python3.8+
- pip install fabric --user
- pip install python-dotenv
- 要求项目部署在~/coding/目录下,且配置了--reload
如何使用
直接在虚拟环境中执行:
fab pull
如果报错说没有fab命令,可以通过pip install fabric安装
如果是Django项目,而且migrations有更新,可以执行fab migrate
如果是使用supervisor部署的,而且没有配置--reload,可以执行fab restart