# 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") { $local } else { [$local] } # 遍历 local 路径,获得映射 mut new_maps = [] for $local in $locals { # 解析原文件路径为绝对路径 let local = ($local | path expand -n) let dest = if ($type == "list") { # 对于文件列表(如 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 "" } }