Skip to content

Commit 6bea1f0

Browse files
author
Anycodes
committed
feat: fully automatic installation on pip install
1 parent a4f98d4 commit 6bea1f0

File tree

3 files changed

+139
-103
lines changed

3 files changed

+139
-103
lines changed

.github/workflows/test.yml

Lines changed: 28 additions & 31 deletions
Original file line numberDiff line numberDiff line change
@@ -26,50 +26,47 @@ jobs:
2626
with:
2727
python-version: ${{ matrix.python-version }}
2828

29-
- name: Install package
29+
- name: Set up Node.js (required for Serverless Devs)
30+
uses: actions/setup-node@v4
31+
with:
32+
node-version: '18'
33+
34+
- name: Install package (will auto-install Serverless Devs)
3035
run: |
3136
python -m pip install --upgrade pip
3237
pip install -e .
3338
34-
- name: Test Python import
39+
- name: Verify Python package
3540
run: |
36-
python -c "import serverless_devs; print('Package version:', serverless_devs.__version__)"
41+
python -c "import serverless_devs; print('Package version:', serverless_devs.__version__)"
3742
38-
- name: Test s-install command availability
43+
- name: Verify Serverless Devs installation
3944
shell: bash
4045
run: |
41-
if command -v s-install &> /dev/null; then
42-
echo "✓ s-install command found"
43-
else
44-
echo "✗ s-install command not found"
45-
exit 1
46+
# 等待一下,确保安装完成
47+
sleep 5
48+
49+
# 在某些系统上可能需要刷新环境
50+
if [ "$RUNNER_OS" == "macOS" ] || [ "$RUNNER_OS" == "Linux" ]; then
51+
export PATH="$HOME/.local/bin:$PATH"
52+
# 检查常见的安装位置
53+
if [ -f "$HOME/.s/bin/s" ]; then
54+
export PATH="$HOME/.s/bin:$PATH"
55+
fi
4656
fi
47-
48-
- name: Install Serverless Devs
49-
shell: bash
50-
run: |
51-
echo "Installing Serverless Devs..."
52-
s-install
53-
continue-on-error: true # 允许在 CI 环境中失败
54-
55-
- name: Check s command (if installed)
56-
shell: bash
57-
run: |
57+
58+
# 检查 s 命令
5859
if command -v s &> /dev/null; then
5960
echo "✓ s command found"
6061
s --version
6162
else
62-
echo "ℹ s command not installed (may fail in CI environment)"
63+
echo "✗ s command not found in PATH"
64+
echo "Checking npm global bin..."
65+
npm root -g
66+
npm list -g @serverless-devs/s || true
67+
exit 1
6368
fi
64-
continue-on-error: true
6569
66-
- name: Test npm availability (for debugging)
67-
shell: bash
70+
- name: Test s command via Python wrapper
6871
run: |
69-
if command -v npm &> /dev/null; then
70-
echo "✓ npm is available"
71-
npm --version
72-
else
73-
echo "ℹ npm is not available"
74-
fi
75-
continue-on-error: true
72+
python -m serverless_devs --version

serverless_devs/installer.py

Lines changed: 97 additions & 62 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,7 @@
11
"""
22
Serverless Devs 安装器
33
使用官方安装脚本自动安装最新版本(包含 Node.js 环境)
4+
支持非交互式自动安装
45
"""
56

67
import os
@@ -38,37 +39,30 @@ def check_existing_installation():
3839
pass
3940
return False, None
4041

41-
def install_on_windows():
42+
def install_on_windows(non_interactive=False):
4243
"""在 Windows 上安装 Serverless Devs"""
4344
print("检测到 Windows 系统...")
44-
print("\n推荐安装方式:")
45-
print(" 1. 通过 npm 安装 (推荐):")
46-
print(" npm install -g @serverless-devs/s")
47-
print("\n 2. 下载二进制文件:")
48-
print(" 访问 https://github.com/Serverless-Devs/Serverless-Devs/releases")
49-
print(" 下载 s-*-win.exe.zip 并解压到 PATH 目录")
50-
print("\n正在尝试通过 npm 安装...")
5145

5246
# 检查 npm 是否可用
5347
if not is_command_available('npm'):
54-
print("\n✗ 未检测到 npm,请先安装 Node.js:")
48+
print("\n✗ 未检测到 npm,正在尝试安装 Node.js...")
49+
print(" Windows 用户请手动安装 Node.js:")
5550
print(" 下载地址: https://nodejs.org/")
5651
return False
5752

58-
# 使用 npm 安装
53+
print("\n正在通过 npm 安装 Serverless Devs...")
54+
5955
try:
60-
print("\n执行: npm install -g @serverless-devs/s")
61-
6256
# 设置环境变量使用国内镜像
6357
env = os.environ.copy()
64-
if os.environ.get('USE_NPM_MIRROR', '').lower() in ['1', 'true', 'yes']:
58+
if os.environ.get('USE_MIRROR', '').lower() in ['1', 'true', 'yes']:
6559
env['NPM_CONFIG_REGISTRY'] = 'https://registry.npmmirror.com'
6660
print("(使用国内镜像加速)")
6761

6862
result = subprocess.run(
6963
['npm', 'install', '-g', '@serverless-devs/s'],
7064
env=env,
71-
capture_output=False, # 显示实时输出
65+
capture_output=not non_interactive, # 非交互模式下隐藏输出
7266
text=True
7367
)
7468

@@ -77,22 +71,22 @@ def install_on_windows():
7771
return True
7872
else:
7973
print("\n✗ npm 安装失败")
74+
if result.stderr:
75+
print(result.stderr)
8076
return False
8177

8278
except Exception as e:
8379
print(f"\n✗ 安装失败: {e}")
8480
return False
8581

86-
def install_on_unix():
82+
def install_on_unix(non_interactive=False):
8783
"""在 Unix 系统(Linux/macOS)上安装 Serverless Devs"""
8884
system = platform.system()
8985
print(f"检测到 {system} 系统...")
9086

9187
# 检查必要的命令
9288
if not is_command_available('curl') and not is_command_available('wget'):
9389
print("\n✗ 错误: 需要 curl 或 wget 命令")
94-
print("请先安装: sudo apt-get install curl # Debian/Ubuntu")
95-
print(" sudo yum install curl # CentOS/RHEL")
9690
return False
9791

9892
if not is_command_available('bash'):
@@ -102,14 +96,15 @@ def install_on_unix():
10296
# 选择下载工具
10397
download_cmd = 'curl' if is_command_available('curl') else 'wget'
10498

105-
# 选择安装脚本 URL(支持镜像)
99+
# 选择安装脚本 URL
106100
use_mirror = os.environ.get('USE_MIRROR', '').lower() in ['1', 'true', 'yes']
107101
script_url = INSTALL_SCRIPT_MIRROR if use_mirror else INSTALL_SCRIPT_URL
108102

109103
if use_mirror:
110104
print("使用国内镜像加速...")
111105

112-
print(f"\n正在下载安装脚本: {script_url}")
106+
if not non_interactive:
107+
print(f"\n正在下载安装脚本: {script_url}")
113108

114109
try:
115110
# 创建临时文件
@@ -124,7 +119,7 @@ def install_on_unix():
124119
text=True,
125120
timeout=60
126121
)
127-
else: # wget
122+
else:
128123
download_result = subprocess.run(
129124
['wget', '-q', script_url, '-O', temp_script],
130125
capture_output=True,
@@ -140,14 +135,16 @@ def install_on_unix():
140135
print(" s-install")
141136
return False
142137

143-
print("✓ 下载完成")
138+
if not non_interactive:
139+
print("✓ 下载完成")
144140

145141
# 添加执行权限
146142
os.chmod(temp_script, 0o755)
147143

148144
# 执行安装脚本
149-
print("\n开始安装 Serverless Devs...")
150-
print("="*60)
145+
if not non_interactive:
146+
print("\n开始安装 Serverless Devs...")
147+
print("="*60)
151148

152149
env = os.environ.copy()
153150
if use_mirror:
@@ -156,6 +153,7 @@ def install_on_unix():
156153
install_result = subprocess.run(
157154
['bash', temp_script],
158155
env=env,
156+
capture_output=non_interactive, # 非交互模式下隐藏输出
159157
text=True
160158
)
161159

@@ -166,62 +164,77 @@ def install_on_unix():
166164
pass
167165

168166
if install_result.returncode == 0:
169-
print("="*60)
170-
print("✓ 安装成功!")
167+
if not non_interactive:
168+
print("="*60)
169+
print("✓ 安装成功!")
171170
return True
172171
else:
173-
print("="*60)
172+
if not non_interactive:
173+
print("="*60)
174174
print("✗ 安装失败")
175+
if non_interactive and install_result.stderr:
176+
print(install_result.stderr)
175177
return False
176178

177179
except subprocess.TimeoutExpired:
178180
print("\n✗ 下载超时,请检查网络连接")
179181
return False
180182
except Exception as e:
181183
print(f"\n✗ 安装过程出错: {e}")
182-
import traceback
183-
traceback.print_exc()
184184
return False
185185

186-
def install_serverless_devs():
186+
def install_serverless_devs(non_interactive=False):
187187
"""
188188
安装 Serverless Devs
189189
190+
Args:
191+
non_interactive: 是否非交互模式(自动安装,不询问)
192+
190193
Returns:
191194
bool: 是否安装成功
192195
"""
193-
print("="*60)
194-
print("Serverless Devs 安装器")
195-
print("="*60)
196+
if not non_interactive:
197+
print("="*60)
198+
print("Serverless Devs 安装器")
199+
print("="*60)
196200

197201
# 检查是否已安装
198202
is_installed, version = check_existing_installation()
199203
if is_installed:
200-
print(f"\n检测到已安装 Serverless Devs: {version}")
201-
response = input("\n是否重新安装? (y/N): ")
202-
if response.lower() != 'y':
203-
print("跳过安装")
204+
if non_interactive:
205+
# 非交互模式:已安装则跳过
206+
print(f"✓ Serverless Devs 已安装: {version}")
204207
return True
205-
print()
208+
else:
209+
# 交互模式:询问是否重新安装
210+
print(f"\n检测到已安装 Serverless Devs: {version}")
211+
response = input("\n是否重新安装? (y/N): ")
212+
if response.lower() != 'y':
213+
print("跳过安装")
214+
return True
215+
print()
206216

207217
# 根据系统选择安装方式
208218
if is_windows():
209-
success = install_on_windows()
219+
success = install_on_windows(non_interactive)
210220
else:
211-
success = install_on_unix()
221+
success = install_on_unix(non_interactive)
212222

213223
if success:
214224
# 验证安装
215-
print("\n验证安装...")
225+
if not non_interactive:
226+
print("\n验证安装...")
227+
216228
is_installed, version = check_existing_installation()
217229
if is_installed:
218230
print(f"✓ 验证成功! 已安装版本: {version}")
219-
print("\n" + "="*60)
220-
print("安装完成! 请运行以下命令开始使用:")
221-
print(" s --version # 查看版本")
222-
print(" s config add # 配置密钥")
223-
print(" s init # 初始化项目")
224-
print("="*60)
231+
if not non_interactive:
232+
print("\n" + "="*60)
233+
print("安装完成! 请运行以下命令开始使用:")
234+
print(" s --version # 查看版本")
235+
print(" s config add # 配置密钥")
236+
print(" s init # 初始化项目")
237+
print("="*60)
225238
return True
226239
else:
227240
print("✗ 验证失败: 找不到 s 命令")
@@ -231,26 +244,48 @@ def install_serverless_devs():
231244
print(" 3. 手动添加到 PATH")
232245
return False
233246
else:
234-
print("\n" + "="*60)
235-
print("安装失败,请尝试:")
236-
print("="*60)
237-
print("\n方式1: 使用 npm 直接安装")
238-
print(" npm install -g @serverless-devs/s")
239-
print("\n方式2: 使用国内镜像")
240-
if is_windows():
241-
print(" set USE_NPM_MIRROR=1")
242-
else:
243-
print(" export USE_MIRROR=1")
244-
print(" s-install")
245-
print("\n方式3: 手动安装")
246-
print(" 访问: https://docs.serverless-devs.com/getting-started/install")
247-
print("="*60)
247+
if not non_interactive:
248+
print("\n" + "="*60)
249+
print("安装失败,请尝试:")
250+
print("="*60)
251+
print("\n方式1: 使用 npm 直接安装")
252+
print(" npm install -g @serverless-devs/s")
253+
print("\n方式2: 使用国内镜像")
254+
if is_windows():
255+
print(" set USE_MIRROR=1")
256+
else:
257+
print(" export USE_MIRROR=1")
258+
print(" s-install")
259+
print("\n方式3: 手动安装")
260+
print(" 访问: https://docs.serverless-devs.com/getting-started/install")
261+
print("="*60)
248262
return False
249263

250264
def main():
251265
"""命令行入口"""
266+
import argparse
267+
268+
parser = argparse.ArgumentParser(description='Serverless Devs 安装器')
269+
parser.add_argument('--non-interactive', '-y',
270+
action='store_true',
271+
help='非交互模式,自动安装不询问')
272+
parser.add_argument('--help-install',
273+
action='store_true',
274+
help='显示安装帮助信息')
275+
276+
args = parser.parse_args()
277+
278+
if args.help_install:
279+
print("Serverless Devs 安装器")
280+
print("\n使用方法:")
281+
print(" s-install # 交互式安装")
282+
print(" s-install -y # 自动安装(非交互)")
283+
print("\n环境变量:")
284+
print(" USE_MIRROR=1 # 使用国内镜像加速")
285+
return
286+
252287
try:
253-
success = install_serverless_devs()
288+
success = install_serverless_devs(non_interactive=args.non_interactive)
254289
sys.exit(0 if success else 1)
255290
except KeyboardInterrupt:
256291
print("\n\n用户取消安装")
@@ -262,4 +297,4 @@ def main():
262297
sys.exit(1)
263298

264299
if __name__ == '__main__':
265-
main()
300+
main()

0 commit comments

Comments
 (0)