101 lines
3.8 KiB
Python
101 lines
3.8 KiB
Python
#!/opt/miniconda3/bin/python3
|
|
import os
|
|
import sys
|
|
import socket
|
|
import http.server
|
|
import socketserver
|
|
import subprocess
|
|
from urllib.parse import urlparse
|
|
|
|
# 配置基础路径和端口(推荐使用 1024-65535 之间的端口,避免系统预留端口)
|
|
BUILD_DIR = os.path.join(os.path.expanduser('~'), 'Desktop', 'lx_uniapp', 'build')
|
|
DEFAULT_PORT = 8000 # 若仍失败,可改为 8080、9000 等
|
|
|
|
|
|
def check_port_available(port):
|
|
"""检查端口是否真的可用(比 lsof 更可靠)"""
|
|
with socket.socket(socket.AF_INET, socket.SOCK_STREAM) as s:
|
|
try:
|
|
s.bind(("", port)) # 尝试绑定端口,成功则可用
|
|
return True
|
|
except OSError:
|
|
return False
|
|
|
|
|
|
def free_port(port):
|
|
"""释放占用端口的进程"""
|
|
try:
|
|
result = subprocess.check_output(
|
|
f"lsof -i :{port} | grep LISTEN | awk '{{print $2}}'",
|
|
shell=True,
|
|
text=True,
|
|
stderr=subprocess.STDOUT # 忽略错误输出
|
|
)
|
|
pids = [pid.strip() for pid in result.split('\n') if pid.strip()]
|
|
if pids:
|
|
print(f"释放端口 {port} 占用的进程:{pids}")
|
|
for pid in pids:
|
|
subprocess.run(f"kill -9 {pid}", shell=True, check=True)
|
|
except subprocess.CalledProcessError:
|
|
pass # 无进程占用时正常
|
|
except Exception as e:
|
|
print(f"释放端口警告:{e}(可忽略)")
|
|
|
|
|
|
class IPARequestHandler(http.server.SimpleHTTPRequestHandler):
|
|
# 省略与之前相同的 do_GET 实现(保持不变)
|
|
def do_GET(self):
|
|
parsed_path = urlparse(self.path)
|
|
target_branch = parsed_path.path.strip('/')
|
|
|
|
if not target_branch:
|
|
self.send_response(400)
|
|
self.end_headers()
|
|
self.wfile.write("请指定分支名,例如: http://服务器IP:端口/sit".encode('utf-8'))
|
|
return
|
|
|
|
ipa_dir_name = f"{target_branch}_ipa_production"
|
|
ipa_path = os.path.join(BUILD_DIR, ipa_dir_name, "HBuilder.ipa")
|
|
|
|
if not os.path.exists(ipa_path):
|
|
self.send_response(404)
|
|
self.end_headers()
|
|
self.wfile.write(f"文件不存在: {ipa_path}".encode('utf-8'))
|
|
return
|
|
|
|
self.send_response(200)
|
|
self.send_header('Content-Type', 'application/octet-stream')
|
|
self.send_header('Content-Disposition', f'attachment; filename="HBuilder_{target_branch}.ipa"')
|
|
self.end_headers()
|
|
|
|
with open(ipa_path, 'rb') as f:
|
|
self.wfile.write(f.read())
|
|
|
|
|
|
if __name__ == '__main__':
|
|
# 1. 先尝试释放端口
|
|
free_port(DEFAULT_PORT)
|
|
|
|
# 2. 检查端口是否真的可用
|
|
if not check_port_available(DEFAULT_PORT):
|
|
print(f"端口 {DEFAULT_PORT} 仍被占用,尝试自动切换端口...")
|
|
# 自动切换到 8080 端口(若 8000 不可用)
|
|
DEFAULT_PORT = 8080
|
|
free_port(DEFAULT_PORT)
|
|
if not check_port_available(DEFAULT_PORT):
|
|
print(f"端口 {DEFAULT_PORT} 也被占用,请手动指定其他端口(如 9000)")
|
|
sys.exit(1)
|
|
|
|
# 3. 启动服务(增加错误捕获)
|
|
try:
|
|
# 禁用地址重用限制(解决 TIME_WAIT 状态导致的启动失败)
|
|
socketserver.TCPServer.allow_reuse_address = True
|
|
with socketserver.TCPServer(("", DEFAULT_PORT), IPARequestHandler) as httpd:
|
|
print(f"\nIPA 文件服务已启动,端口: {DEFAULT_PORT}")
|
|
print(f"访问格式: http://服务器IP:{DEFAULT_PORT}/目标分支名")
|
|
print(f"示例: http://25.64.32.152:{DEFAULT_PORT}/sit")
|
|
httpd.serve_forever()
|
|
except Exception as e:
|
|
print(f"服务启动失败:{str(e)}")
|
|
print("可能原因:权限不足(尝试非 1-1024 端口)或网络配置限制")
|
|
sys.exit(1) |