183 lines
5.0 KiB
Plaintext
183 lines
5.0 KiB
Plaintext
# symlink.nu -- 软链接管理
|
||
#
|
||
# Copyright (C) 2022-2023 KAAAsS
|
||
|
||
use ../log.nu
|
||
use ../interactive.nu [confirm]
|
||
|
||
use global_conf.nu
|
||
use module.nu [filtered_modules]
|
||
|
||
# 获得链接的目标目录或目标文件的父目录
|
||
def get_base_dir [local: path, dest: path] {
|
||
let type = ($local | path type)
|
||
if ($type == dir) {
|
||
$dest
|
||
} else {
|
||
$dest | path dirname
|
||
}
|
||
}
|
||
|
||
# 声明文件及其目标路径
|
||
export def --env declare [
|
||
module: string, # 模块名称
|
||
local: any, # 本地路径,以项目根目录为起点的相对路径
|
||
dest: string, # 目标路径,以用户家目录为起点的相对路径
|
||
--local-only, # 是否是本地特有的文件。若文件不存在则会自动从 example 创建本地文件
|
||
] {
|
||
let type = ($local | describe)
|
||
let locals = if ($type == "list<string>") {
|
||
$local
|
||
} else {
|
||
[$local]
|
||
}
|
||
|
||
# 遍历 local 路径,获得映射
|
||
mut new_maps = []
|
||
for $local in $locals {
|
||
# 解析原文件路径为绝对路径
|
||
let local = ($local | path expand -n)
|
||
let dest = if ($type == "list<string>") {
|
||
# 对于文件列表(如 glob),把文件名追加在最后
|
||
$dest | path join ($local | path basename)
|
||
} else {
|
||
$dest
|
||
}
|
||
|
||
log debug $"声明文件: ($module) : ($local) --> ($dest)"
|
||
$new_maps = ($new_maps | append [ { local: $local, dest: $dest } ])
|
||
|
||
# 若本地文件不存在,则根据模板创建本地文件
|
||
if ($local_only and (not ($local | path exists))) {
|
||
let template = $"($local).example"
|
||
|
||
if ($template | path exists) {
|
||
log debug $"创建本地文件: ($local)"
|
||
mkdir ($local | path dirname)
|
||
cp $template $local
|
||
} else {
|
||
error make {
|
||
msg: $"本地文件 ($local) 的模板不存在!配置有误!",
|
||
}
|
||
}
|
||
}
|
||
}
|
||
|
||
# 合并新映射并设置
|
||
let old_map = (global_conf get_config $module "file_map" null)
|
||
|
||
global_conf set_config $module "file_map" (
|
||
$old_map | append $new_maps
|
||
)
|
||
}
|
||
|
||
# 列出模块的文件信息
|
||
export def list_files [
|
||
modules?: list
|
||
] {
|
||
# 获取模块列表
|
||
let modules = (filtered_modules $modules)
|
||
|
||
# 增加文件信息
|
||
$modules | each { |$module|
|
||
let file_map = (global_conf get_config $module "file_map")
|
||
|
||
if ($file_map != null) {
|
||
# dest 相对路径转为绝对
|
||
let file_map = (
|
||
$file_map | each { |$it|
|
||
{
|
||
local: $it.local,
|
||
dest: ($env.HOME_DIR | path join $it.dest),
|
||
}
|
||
}
|
||
)
|
||
|
||
# 增加模块名列
|
||
[ [ module, v ]; [ $module, $file_map ] ]
|
||
}
|
||
} | flatten | flatten --all
|
||
}
|
||
|
||
# 进行模块文件的符号链接
|
||
export def do_link [
|
||
modules?: list
|
||
] {
|
||
let module_files = (
|
||
list_files $modules | group-by module | transpose module files
|
||
)
|
||
|
||
# 遍历模块
|
||
for $it in $module_files {
|
||
let module = $it.module
|
||
let files = $it.files
|
||
|
||
log status $"链接模块 ($module)..."
|
||
|
||
# 遍历文件映射,执行软链接
|
||
for $it in $files {
|
||
let local = $it.local
|
||
let dest = $it.dest
|
||
let type = ($dest | path type)
|
||
|
||
if ($type == symlink) {
|
||
log info $"($dest) 已链接,跳过"
|
||
} else {
|
||
let link = if ($type != "") {
|
||
# 文件存在时进行询问
|
||
let agree = (confirm $"- 文件 ($dest) 已存在,是否强制覆盖?" "n")
|
||
if ($agree) {
|
||
log debug $"删除 ($dest)"
|
||
rm -rf $dest
|
||
true
|
||
} else { false }
|
||
} else {
|
||
# 不存在则直接链接
|
||
true
|
||
}
|
||
# 进行符号链接
|
||
if ($link) {
|
||
log info $"链接 ($local) --> ($dest)"
|
||
mkdir (get_base_dir $local $dest)
|
||
ln -s $local $dest
|
||
}
|
||
}
|
||
}
|
||
|
||
log info ""
|
||
}
|
||
}
|
||
|
||
# 删除模块文件的符号链接
|
||
export def do_unlink [
|
||
modules?: list
|
||
] {
|
||
let module_files = (
|
||
list_files $modules | group-by module | transpose module files
|
||
)
|
||
|
||
# 遍历模块
|
||
for $it in $module_files {
|
||
let module = $it.module
|
||
let files = $it.files
|
||
|
||
log status $"清理模块 ($module)..."
|
||
|
||
# 遍历文件映射,删除软链接
|
||
for $it in $files {
|
||
let dest = $it.dest
|
||
let type = ($dest | path type)
|
||
|
||
if ($type == symlink) {
|
||
log info $"清理 ($dest)"
|
||
rm -rf $dest
|
||
} else if ($type != "") {
|
||
log warn $"- ($dest) 非符号链接,跳过"
|
||
}
|
||
null
|
||
}
|
||
|
||
log info ""
|
||
}
|
||
}
|