1. 新增支持对于驱动器显示名称的获取,通过显示名称的匹配更加直观
2. 优化rpc pool的使用。 3. 新增保存配置的功能给其他的组件使用
This commit is contained in:
29
sscp_tool/setup.py
Normal file
29
sscp_tool/setup.py
Normal file
@ -0,0 +1,29 @@
|
||||
#!/usr/bin/env python3
|
||||
# -*- coding: utf-8 -*-
|
||||
|
||||
from setuptools import setup, find_packages
|
||||
|
||||
setup(
|
||||
name="sscp",
|
||||
version="0.1.0",
|
||||
description="从L3向L0传输文件的简化工具",
|
||||
author="Your Name",
|
||||
author_email="your.email@example.com",
|
||||
packages=find_packages(),
|
||||
py_modules=["sscp"],
|
||||
entry_points={
|
||||
"console_scripts": [
|
||||
"sscp=sscp:main",
|
||||
],
|
||||
},
|
||||
classifiers=[
|
||||
"Development Status :: 3 - Alpha",
|
||||
"Intended Audience :: Developers",
|
||||
"Programming Language :: Python :: 3",
|
||||
"Programming Language :: Python :: 3.6",
|
||||
"Programming Language :: Python :: 3.7",
|
||||
"Programming Language :: Python :: 3.8",
|
||||
"Programming Language :: Python :: 3.9",
|
||||
],
|
||||
python_requires=">=3.6",
|
||||
)
|
203
sscp_tool/sscp.py
Normal file
203
sscp_tool/sscp.py
Normal file
@ -0,0 +1,203 @@
|
||||
#!/usr/bin/env python3
|
||||
# -*- coding: utf-8 -*-
|
||||
|
||||
"""
|
||||
sscp - 简化从L3到L0的文件传输工具
|
||||
用法: sscp <源文件/目录> [<源文件/目录>...] <目标路径>
|
||||
"""
|
||||
|
||||
import os
|
||||
import sys
|
||||
import json
|
||||
import argparse
|
||||
import subprocess
|
||||
import re
|
||||
import shutil
|
||||
from pathlib import Path
|
||||
|
||||
def parse_arguments():
|
||||
"""解析命令行参数"""
|
||||
parser = argparse.ArgumentParser(description='从L3向L0传输文件的简化工具')
|
||||
parser.add_argument('sources', nargs='+', help='源文件或目录路径')
|
||||
parser.add_argument('target', help='目标路径')
|
||||
parser.add_argument('-v', '--verbose', action='store_true', help='显示详细信息')
|
||||
parser.add_argument('-r', '--recursive', action='store_true', help='递归处理目录')
|
||||
return parser.parse_args()
|
||||
|
||||
def get_mount_points():
|
||||
"""从配置文件获取挂载点信息"""
|
||||
config_path = Path.home() / ".config" / "sscp" / "config.json"
|
||||
|
||||
if not config_path.exists():
|
||||
print(f"警告: 找不到配置文件 {config_path},将使用默认挂载点 ~/mnt")
|
||||
return {str(Path.home() / "mnt"): "/l0"}
|
||||
|
||||
with open(config_path, 'r') as f:
|
||||
config = json.load(f)
|
||||
|
||||
# 从配置中提取挂载点信息
|
||||
mount_points = []
|
||||
mount_points = config['mounts'].copy()
|
||||
return mount_points
|
||||
def encode_path(path):
|
||||
"""
|
||||
对L0路径进行编码
|
||||
将 /l0x/path/to/file 编码为 l0x@path@to@file
|
||||
同时处理路径中已有的@符号
|
||||
"""
|
||||
# 先将已有的@符号替换为特殊序列
|
||||
path_escaped = path.replace('@', '@@')
|
||||
|
||||
# 将路径中的斜杠替换为@符号
|
||||
encoded_path = path_escaped.replace('/', '@')
|
||||
|
||||
# 确保路径以l0开头
|
||||
if not encoded_path.startswith('@l0'):
|
||||
raise ValueError(f"无法识别的L0路径格式: {path}")
|
||||
|
||||
# 移除开头的@
|
||||
return encoded_path[1:]
|
||||
|
||||
def create_symlink(source_path, encoded_path):
|
||||
"""创建源文件或目录到临时位置的软链接"""
|
||||
temp_dir = Path("/tmp/sscp")
|
||||
temp_dir.mkdir(exist_ok=True)
|
||||
|
||||
temp_link = temp_dir / encoded_path
|
||||
# 确保父目录存在
|
||||
temp_link.parent.mkdir(parents=True, exist_ok=True)
|
||||
|
||||
# 如果已存在,先删除
|
||||
if temp_link.exists():
|
||||
if temp_link.is_dir() and not temp_link.is_symlink():
|
||||
shutil.rmtree(temp_link)
|
||||
else:
|
||||
temp_link.unlink()
|
||||
|
||||
# 创建软链接
|
||||
os.symlink(os.path.abspath(source_path), temp_link)
|
||||
return temp_link
|
||||
|
||||
def call_ssbuild(encoded_path, verbose=False):
|
||||
"""调用ssbuild工具发送文件或目录"""
|
||||
try:
|
||||
cmd = ["ssbuild", str(encoded_path)]
|
||||
if verbose:
|
||||
print(f"执行命令: {' '.join(cmd)}")
|
||||
|
||||
result = subprocess.run(
|
||||
cmd,
|
||||
check=True,
|
||||
capture_output=True,
|
||||
text=True
|
||||
)
|
||||
return result.stdout
|
||||
except subprocess.CalledProcessError as e:
|
||||
print(f"调用ssbuild失败: {e}")
|
||||
print(f"错误输出: {e.stderr}")
|
||||
sys.exit(1)
|
||||
except FileNotFoundError:
|
||||
print("错误: 找不到ssbuild命令,请确保它已安装并在PATH中")
|
||||
sys.exit(1)
|
||||
|
||||
def is_mount_path(path, mount_points):
|
||||
"""检查路径是否在挂载点中"""
|
||||
path_str = str(path)
|
||||
for mount_point in mount_points:
|
||||
if path_str.startswith(mount_point):
|
||||
return mount_point
|
||||
return None
|
||||
|
||||
def process_source(source_path, target_path, mount_points, verbose=False):
|
||||
"""处理单个源文件或目录"""
|
||||
source_path = Path(source_path).resolve()
|
||||
target_path = Path(target_path)
|
||||
|
||||
# 检查源是否存在
|
||||
if not source_path.exists():
|
||||
print(f"错误: 源 '{source_path}' 不存在")
|
||||
return False
|
||||
|
||||
# 如果目标是目录,添加源文件名
|
||||
if target_path.is_dir() or (len(mount_points) > 0 and not target_path.suffix):
|
||||
final_target = target_path / source_path.name
|
||||
else:
|
||||
final_target = target_path
|
||||
|
||||
# 检查目标路径是否在挂载点中
|
||||
mount_point = is_mount_path(final_target, mount_points)
|
||||
if not mount_point:
|
||||
print(f"错误: 目标路径 '{final_target}' 不在已知的挂载目录中")
|
||||
print(f"有效的挂载点: {', '.join(mount_points.keys())}")
|
||||
return False
|
||||
|
||||
try:
|
||||
# 从挂载路径提取L0路径部分
|
||||
target_str = str(final_target)
|
||||
relative_path = target_str[len(mount_point):]
|
||||
|
||||
# 构建完整的L0路径
|
||||
l0_path = mount_points[mount_point] + relative_path
|
||||
|
||||
# 对L0路径进行编码
|
||||
encoded_path = encode_path(l0_path)
|
||||
|
||||
if verbose:
|
||||
print(f"源路径: {source_path}")
|
||||
print(f"目标路径: {final_target}")
|
||||
print(f"挂载点: {mount_point}")
|
||||
print(f"L0路径: {l0_path}")
|
||||
print(f"编码后的路径: {encoded_path}")
|
||||
|
||||
# 创建源的软链接
|
||||
temp_link = create_symlink(source_path, encoded_path)
|
||||
|
||||
if verbose:
|
||||
print(f"创建软链接: {source_path} -> {temp_link}")
|
||||
|
||||
# 调用ssbuild工具发送文件或目录
|
||||
print(f"正在发送: {source_path} -> {final_target}")
|
||||
output = call_ssbuild(temp_link, verbose)
|
||||
|
||||
if verbose and output:
|
||||
print(f"ssbuild输出: {output}")
|
||||
|
||||
print(f"已成功传输到 {final_target}")
|
||||
return True
|
||||
|
||||
except Exception as e:
|
||||
print(f"处理 {source_path} 时出错: {e}")
|
||||
return False
|
||||
|
||||
def main():
|
||||
args = parse_arguments()
|
||||
|
||||
# 获取挂载点信息
|
||||
mount_points = get_mount_points()
|
||||
|
||||
if args.verbose:
|
||||
print(f"已识别的挂载点: {mount_points}")
|
||||
|
||||
# 最后一个参数是目标路径
|
||||
target = args.sources.pop()
|
||||
sources = args.sources
|
||||
|
||||
if not sources:
|
||||
print("错误: 至少需要一个源文件或目录")
|
||||
sys.exit(1)
|
||||
|
||||
# 处理每个源文件或目录
|
||||
success_count = 0
|
||||
for source in sources:
|
||||
if process_source(source, target, mount_points, args.verbose):
|
||||
success_count += 1
|
||||
|
||||
# 报告结果
|
||||
if success_count == len(sources):
|
||||
print(f"所有 {len(sources)} 个文件/目录已成功传输")
|
||||
else:
|
||||
print(f"传输完成: {success_count}/{len(sources)} 个文件/目录成功")
|
||||
sys.exit(1)
|
||||
|
||||
if __name__ == "__main__":
|
||||
main()
|
Reference in New Issue
Block a user