Skip to content

Commit 887b3ba

Browse files
committed
Add, 整合 xBar Plugins 仓库
1 parent 890211e commit 887b3ba

File tree

4 files changed

+209
-0
lines changed

4 files changed

+209
-0
lines changed

README.md

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4,3 +4,7 @@
44
- 直接在 macOS环境下使用的脚本
55

66
## Alfred Workflows
7+
8+
## xBar Plugins
9+
10+
### Services Mgr

xbar-plugins/README.md

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,10 @@
1+
# xbar-plugins
2+
3+
## Services Mgr
4+
5+
Configuration-driven service start/stop tool.
6+
7+
### Install
8+
9+
- copy `services-mgr.1d.py` into your xbar/swiftbar `plugins path`
10+
- copy `services-mgr.toml` into `plugins path` or `~/` or `~/.config`

xbar-plugins/services-mgr.1d.py

Lines changed: 151 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,151 @@
1+
#!/usr/bin/env python3
2+
# Metadata allows your plugin to show up in the app, and website.
3+
#
4+
# <xbar.title>Services Mgr</xbar.title>
5+
# <xbar.version>v1.0</xbar.version>
6+
# <xbar.author>Rex Zhang</xbar.author>
7+
# <xbar.author.github>rexzhang</xbar.author.github>
8+
# <xbar.desc>Configuration-driven service start/stop tool.</xbar.desc>
9+
# <xbar.image>http://www.hosted-somewhere/pluginimage</xbar.image>
10+
# <xbar.dependencies>python3.11+</xbar.dependencies>
11+
# <xbar.abouturl>https://github.com/rexzhang/xbar-plugins</xbar.abouturl>
12+
13+
14+
import re
15+
import subprocess
16+
import tomllib
17+
from dataclasses import dataclass, field
18+
from enum import Enum
19+
from pathlib import Path
20+
21+
SUDO_EXECUTABLE = "/usr/bin/sudo"
22+
CONFIG_FILE_NAME = "services-mgr.toml"
23+
CONFIG_FILE_PATHS = [
24+
Path(__file__).parent,
25+
Path.home(),
26+
Path.home().joinpath(".config"),
27+
]
28+
MENU_FORMAT_START_SERVICE = "-- Start | shell={} | terminal=False | refresh=True"
29+
MENU_FORMAT_STOP_SERVICE = "-- Stop | shell={} | terminal=False | refresh=True"
30+
31+
32+
class ServiceStatus(Enum):
33+
UNKNOW = "UNKNOW"
34+
ON = "ON"
35+
OFF = "OFF"
36+
ERROR = "ERROR"
37+
38+
39+
@dataclass
40+
class Service:
41+
name: str
42+
start_shell: list[str]
43+
stop_shell: list[str]
44+
45+
status: ServiceStatus = field(default=ServiceStatus.UNKNOW)
46+
status_shell: list[str] = field(default_factory=list)
47+
status_on_regex: str = field(default_factory=str)
48+
49+
50+
def load_config() -> list[Service]:
51+
data = None
52+
for cf_path in CONFIG_FILE_PATHS:
53+
cf_filename = cf_path.joinpath(CONFIG_FILE_NAME)
54+
try:
55+
with open(cf_filename, "rb") as f:
56+
try:
57+
data = tomllib.load(f)
58+
except tomllib.TOMLDecodeError:
59+
data = []
60+
61+
break
62+
63+
except FileNotFoundError:
64+
pass
65+
66+
if data is None:
67+
print(f"Can't found configuration file <{CONFIG_FILE_NAME}>")
68+
exit()
69+
70+
if "services" not in data:
71+
print(f"Configuration file format error <{cf_filename}>")
72+
exit()
73+
74+
services = list()
75+
for item in data["services"]:
76+
# TODO: do something, check it...
77+
try:
78+
services.append(Service(**item))
79+
except TypeError as e:
80+
raise TypeError(f"item:{str(item)}. {e}")
81+
82+
return services
83+
84+
85+
def get_services_status(services: list[Service]) -> list[Service]:
86+
for index in range(len(services)):
87+
service = services[index]
88+
if len(service.status_shell) == 0 or len(service.status_on_regex) == 0:
89+
continue
90+
91+
result = subprocess.run(service.status_shell, capture_output=True)
92+
m = re.search(service.status_on_regex, result.stdout.decode("utf-8"))
93+
if m is None:
94+
services[index].status = ServiceStatus.OFF
95+
else:
96+
services[index].status = ServiceStatus.ON
97+
98+
return services
99+
100+
101+
def _convert_shell_call_to_menu_str(shell_call: list[str]) -> str:
102+
if len(shell_call) == 0:
103+
return ""
104+
105+
result = f"'{shell_call[0]}'"
106+
for index in range(1, len(shell_call)):
107+
result += f" param{index}='{shell_call[index]}'"
108+
109+
return result
110+
111+
112+
def print_menu(services: list[Service]):
113+
print("Smgr")
114+
print("---")
115+
116+
for service in services:
117+
if service.status == ServiceStatus.UNKNOW:
118+
print(f"{service.name}")
119+
else:
120+
print(f"{service.name}: {service.status.name}")
121+
122+
if service.status == ServiceStatus.ON:
123+
print("-- Start")
124+
else:
125+
print(
126+
MENU_FORMAT_START_SERVICE.format(
127+
_convert_shell_call_to_menu_str(service.start_shell)
128+
)
129+
)
130+
131+
if service.status == ServiceStatus.OFF:
132+
print("-- Stop")
133+
else:
134+
print(
135+
MENU_FORMAT_STOP_SERVICE.format(
136+
_convert_shell_call_to_menu_str(service.stop_shell)
137+
)
138+
)
139+
140+
print("---")
141+
print("Refresh | refresh=true")
142+
143+
144+
def main():
145+
services = load_config()
146+
services = get_services_status(services)
147+
print_menu(services)
148+
149+
150+
if __name__ == "__main__":
151+
main()

xbar-plugins/services-mgr.toml

Lines changed: 44 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,44 @@
1+
[[services]]
2+
name = "ZeroTier"
3+
# You will need to add the following line to your sudoers file. Remember to edit
4+
# sudoers with `sudo visudo`.
5+
#
6+
# %admin ALL = NOPASSWD:/bin/launchctl
7+
start_shell = [
8+
"/usr/bin/sudo",
9+
"launchctl",
10+
"load",
11+
"/Library/LaunchDaemons/com.zerotier.one.plist",
12+
]
13+
stop_shell = [
14+
"/usr/bin/sudo",
15+
"launchctl",
16+
"unload",
17+
"/Library/LaunchDaemons/com.zerotier.one.plist",
18+
]
19+
status_shell = [
20+
"zerotier-cli",
21+
"info",
22+
]
23+
status_on_regex = "200 info [0-9a-z]+ (\\d+\\.)?(\\d+\\.)?(\\*|\\d+) ONLINE"
24+
25+
[[services]]
26+
name = "Redis"
27+
start_shell = [
28+
"brew",
29+
"services",
30+
"start",
31+
"redis",
32+
]
33+
stop_shell = [
34+
"brew",
35+
"services",
36+
"stop",
37+
"redis",
38+
]
39+
status_shell = [
40+
"redis-cli",
41+
"INFO",
42+
"server",
43+
] # redis-server --version
44+
status_on_regex = "redis_version:(\\d+\\.)?(\\d+\\.)?(\\*|\\d+)"

0 commit comments

Comments
 (0)