File indexing completed on 2026-04-10 08:38:57
0001 import distutils
0002 import getpass
0003 import glob
0004 import grp
0005 import json
0006 import os
0007 import pwd
0008 import re
0009 import socket
0010 import stat
0011 import subprocess
0012 import sys
0013 import sysconfig
0014
0015 import requests
0016 from hatchling.builders.hooks.plugin.interface import BuildHookInterface
0017
0018 PACKAGE_EMOJI_PANDA = ":panda_face:"
0019 PACKAGE_EMOJI_JEDI = ":lightsaber:"
0020 PACKAGE_NAME = "panda-server"
0021
0022
0023 def get_user():
0024
0025 result = subprocess.run(["klist"], capture_output=True, text=True)
0026
0027
0028 for line in result.stdout.splitlines():
0029 if "Default principal" in line:
0030
0031 default_principal = line.split()[-1]
0032 default_principal = default_principal.split("@")[0]
0033 return default_principal
0034
0035 return ""
0036
0037
0038 def get_repo_info() -> object:
0039
0040 repo_url = subprocess.check_output(["git", "config", "--get", "remote.origin.url"]).strip().decode()
0041
0042
0043 match = re.match(r"https://github.com/(.*).git@(.*)", repo_url)
0044
0045 if match:
0046 repo_name = match.group(1)
0047 branch_name = match.group(2)
0048 else:
0049 repo_name = repo_url.removesuffix(".git")
0050 branch_name = subprocess.check_output(["git", "rev-parse", "--abbrev-ref", "HEAD"]).strip().decode()
0051 if branch_name in ("HEAD", "main", "master"):
0052 try:
0053
0054 account_name = repo_url.split("/")[-2]
0055 if account_name != "PanDAWMS":
0056 branch_name = account_name
0057 except Exception:
0058 pass
0059
0060 commit_hash = subprocess.check_output(["git", "rev-parse", "HEAD"]).strip().decode()
0061
0062 return repo_name, branch_name, commit_hash
0063
0064
0065 def mm_notification():
0066
0067 if os.environ.get("DISABLE_MM"):
0068 return
0069
0070
0071 user = get_user()
0072
0073
0074 repo_name, branch_name, commit_hash = get_repo_info()
0075
0076
0077 server_name = socket.gethostname()
0078
0079 file_path = os.path.expanduser("~/mm_webhook_url.txt")
0080 with open(file_path, "r") as file:
0081 mm_webhook_url = file.read().strip()
0082 if not mm_webhook_url:
0083 return
0084
0085
0086 jedi_config_path = "/etc/panda/panda_jedi.cfg"
0087 if os.path.exists(jedi_config_path):
0088 emoji_to_use = PACKAGE_EMOJI_JEDI
0089 else:
0090 emoji_to_use = PACKAGE_EMOJI_PANDA
0091
0092
0093
0094 mm_message = {
0095 "text": f"{emoji_to_use}**{PACKAGE_NAME}@{branch_name} upgrade on:** `{server_name}` by `{user}`.",
0096 "props": {
0097 "card": f"""
0098 | **Property** | **Value** |
0099 |--------------|-----------|
0100 | **Package** | {repo_name} |
0101 | **Branch** | [`{branch_name}`]({repo_name}/tree/{branch_name}) |
0102 | **Commit** | [`{commit_hash}`]({repo_name}/commit/{commit_hash}) |
0103 """
0104 },
0105 }
0106 headers = {"Content-Type": "application/json"}
0107 try:
0108 response = requests.post(mm_webhook_url, data=json.dumps(mm_message), headers=headers)
0109 except requests.exceptions.RequestException as e:
0110 pass
0111
0112
0113 class CustomBuildHook(BuildHookInterface):
0114 def initialize(self, version, build_data):
0115
0116 if os.getgid() == 0:
0117 panda_user = "atlpan"
0118 panda_group = "zp"
0119 else:
0120 panda_user = getpass.getuser()
0121 panda_group = grp.getgrgid(os.getgid()).gr_name
0122
0123
0124 self.params = {}
0125 self.params["install_dir"] = os.environ.get("PANDA_INSTALL_TARGET")
0126 if self.params["install_dir"]:
0127
0128 self.params["install_purelib"] = self.params["install_dir"]
0129 self.params["install_scripts"] = os.path.join(self.params["install_dir"], "bin")
0130 else:
0131 self.params["install_dir"] = sys.prefix
0132 try:
0133
0134 self.params["install_purelib"] = sysconfig.get_path("purelib")
0135 self.params["install_scripts"] = sysconfig.get_path("scripts")
0136 except Exception:
0137
0138 self.params["install_purelib"] = distutils.sysconfig.get_python_lib()
0139 self.params["install_scripts"] = os.path.join(sys.prefix, "bin")
0140 for k in self.params:
0141 path = self.params[k]
0142 self.params[k] = os.path.abspath(os.path.expanduser(path))
0143
0144
0145 self.params["panda_user"] = panda_user
0146 self.params["panda_group"] = panda_group
0147 self.params["python_exec_version"] = "%s.%s" % sys.version_info[:2]
0148 self.params["virtual_env"] = ""
0149 self.params["virtual_env_setup"] = ""
0150 if "VIRTUAL_ENV" in os.environ:
0151 self.params["virtual_env"] = os.environ["VIRTUAL_ENV"]
0152 self.params["virtual_env_setup"] = f"source {os.environ['VIRTUAL_ENV']}/bin/activate"
0153 elif sys.executable:
0154 venv_dir = os.path.dirname(os.path.dirname(sys.executable))
0155 py_venv_activate = os.path.join(venv_dir, "bin/activate")
0156 if os.path.exists(py_venv_activate):
0157 self.params["virtual_env"] = venv_dir
0158 self.params["virtual_env_setup"] = f"source {py_venv_activate}"
0159
0160
0161 for in_f in glob.glob("./templates/**", recursive=True):
0162 if not in_f.endswith(".template"):
0163 continue
0164 with open(in_f) as in_fh:
0165 file_data = in_fh.read()
0166
0167 for item in re.findall(r"@@([^@]+)@@", file_data):
0168 if item not in self.params:
0169 raise RuntimeError(f"unknown pattern {item} in {in_f}")
0170
0171 patt = self.params[item]
0172
0173 if item.startswith("install"):
0174 patt = os.path.abspath(patt)
0175
0176 patt = re.sub("build/[^/]+/dumb", "", patt)
0177
0178 patt = re.sub("/var/tmp/.*-buildroot", "", patt)
0179
0180 file_data = file_data.replace(f"@@{item}@@", patt)
0181 out_f = re.sub(r"(\.exe)*\.template$", "", in_f)
0182 with open(out_f, "w") as out_fh:
0183 out_fh.write(file_data)
0184
0185 if in_f.endswith(".exe.template"):
0186 tmp_st = os.stat(out_f)
0187 os.chmod(out_f, tmp_st.st_mode | stat.S_IEXEC | stat.S_IXUSR | stat.S_IXGRP | stat.S_IXOTH)
0188
0189 def finalize(self, version, build_data, artifact_path):
0190
0191 uid = pwd.getpwnam(self.params["panda_user"]).pw_uid
0192 gid = grp.getgrnam(self.params["panda_group"]).gr_gid
0193 for directory in ["/var/log/panda", "/var/log/panda/wsgisocks", "/var/log/panda/fastsocks"]:
0194 directory = self.params["virtual_env"] + directory
0195 if not os.path.exists(directory):
0196 os.makedirs(directory)
0197 os.chown(directory, uid, gid)
0198 if self.params["virtual_env"]:
0199 target_dir = os.path.join(self.params["virtual_env"], "etc/sysconfig")
0200 if not os.path.exists(target_dir):
0201 os.makedirs(target_dir)
0202 target = os.path.join(target_dir, "panda_server")
0203 try:
0204 os.symlink(os.path.join(self.params["virtual_env"], "etc/panda/panda_server.sysconfig"), target)
0205 except Exception:
0206 pass
0207
0208
0209 try:
0210 mm_notification()
0211 except:
0212 pass