diff options
| author | ruki <[email protected]> | 2023-11-17 11:03:51 +0800 |
|---|---|---|
| committer | GitHub <[email protected]> | 2023-11-17 11:03:51 +0800 |
| commit | cf3afe37b546efb93079fd6314c0769884ca0fb1 (patch) | |
| tree | 732f74fe2fd2922f3c95e8542de82cb6ee108f1c | |
| parent | b6bb372d19bd2f6ac931d3e0e096b4fa07024cfb (diff) | |
| parent | e0f074c79be1f712d09df9f7b4b32245ba95f1c9 (diff) | |
Merge pull request #4392 from xmake-io/emptydirs
improve os.rm to support remove emptydirs
| -rw-r--r-- | core/src/demo/xmake.lua | 19 | ||||
| -rw-r--r-- | core/xpack.lua | 1 | ||||
| -rw-r--r-- | xmake/core/base/os.lua | 30 | ||||
| -rw-r--r-- | xmake/core/sandbox/modules/os.lua | 8 | ||||
| -rw-r--r-- | xmake/includes/xpack/xmake.lua | 4 | ||||
| -rw-r--r-- | xmake/modules/private/action/clean/remove_files.lua | 10 | ||||
| -rw-r--r-- | xmake/modules/private/utils/batchcmds.lua | 26 | ||||
| -rw-r--r-- | xmake/plugins/pack/nsis/main.lua | 72 | ||||
| -rw-r--r-- | xmake/scripts/xpack/nsis/makensis.nsi | 143 |
9 files changed, 215 insertions, 98 deletions
diff --git a/core/src/demo/xmake.lua b/core/src/demo/xmake.lua index 02466b31f..a45c82693 100644 --- a/core/src/demo/xmake.lua +++ b/core/src/demo/xmake.lua @@ -68,3 +68,22 @@ target("demo") add_installfiles("$(projectdir)/../scripts/xrepo.sh", {prefixdir = "bin", filename = "xrepo"}) end + before_installcmd(function (target, batchcmds, opt) + -- we need to avoid some old files interfering with xmake's module import. + if target:is_plat("windows") then + batchcmds:rmdir("actions") + batchcmds:rmdir("core") + batchcmds:rmdir("includes") + batchcmds:rmdir("languages") + batchcmds:rmdir("modules") + batchcmds:rmdir("platforms") + batchcmds:rmdir("plugins") + batchcmds:rmdir("repository") + batchcmds:rmdir("rules") + batchcmds:rmdir("templates") + batchcmds:rmdir("scripts") + batchcmds:rmdir("themes") + batchcmds:rmdir("toolchains") + end + end) + diff --git a/core/xpack.lua b/core/xpack.lua index 5cbff58e8..280b1365a 100644 --- a/core/xpack.lua +++ b/core/xpack.lua @@ -5,6 +5,7 @@ xpack("xmake") add_targets("demo") set_bindir(".") set_iconfile("src/demo/xmake.ico") + set_nsis_displayname("Xmake build utility ($(arch))") on_load(function (package) local arch = package:arch() diff --git a/xmake/core/base/os.lua b/xmake/core/base/os.lua index 7ae34ccc2..ed5490b7d 100644 --- a/xmake/core/base/os.lua +++ b/xmake/core/base/os.lua @@ -159,6 +159,19 @@ function os._rm(filedir) return true end +-- remove empty parent directories of this file path +function os._rm_empty_parentdirs(filepath) + local parentdir = path.directory(filepath) + while parentdir and os.isdir(parentdir) and os.emptydir(parentdir) do + local ok, errors = os._rm(parentdir) + if not ok then + return false, errors + end + parentdir = path.directory(parentdir) + end + return true +end + -- get the ramdisk root directory -- https://github.com/xmake-io/xmake/issues/3408 function os._ramdir() @@ -464,7 +477,7 @@ function os.mv(srcpath, dstpath, opt) end -- remove files or directories -function os.rm(filepath) +function os.rm(filepath, opt) -- check arguments if not filepath then @@ -472,16 +485,29 @@ function os.rm(filepath) end -- remove file or directories + opt = opt or {} filepath = tostring(filepath) local filepathes = os._match_wildcard_pathes(filepath) if type(filepathes) == "string" then - return os._rm(filepathes) + local ok, errors = os._rm(filepathes) + if not ok then + return false, errors + end + if opt.emptydirs then + return os._rm_empty_parentdirs(filepathes) + end else for _, _filepath in ipairs(filepathes) do local ok, errors = os._rm(_filepath) if not ok then return false, errors end + if opt.emptydirs then + ok, errors = os._rm_empty_parentdirs(filepath) + if not ok then + return false, errors + end + end end end return true diff --git a/xmake/core/sandbox/modules/os.lua b/xmake/core/sandbox/modules/os.lua index c23ffb261..9004f66ee 100644 --- a/xmake/core/sandbox/modules/os.lua +++ b/xmake/core/sandbox/modules/os.lua @@ -152,12 +152,12 @@ function sandbox_os.vmv(srcpath, dstpath, opt) end -- remove file or directory with the verbose info -function sandbox_os.vrm(filepath) +function sandbox_os.vrm(filepath, opt) assert(filepath) if option.get("verbose") then utils.cprint("${dim}> remove %s", filepath) end - return sandbox_os.rm(filepath) + return sandbox_os.rm(filepath, opt) end -- link file or directory with the verbose info @@ -182,9 +182,9 @@ function sandbox_os.trymv(srcpath, dstpath) end -- try to remove files or directories -function sandbox_os.tryrm(filepath) +function sandbox_os.tryrm(filepath, opt) assert(filepath) - return os.rm(vformat(filepath)) + return os.rm(vformat(filepath), opt) end -- change to directory diff --git a/xmake/includes/xpack/xmake.lua b/xmake/includes/xpack/xmake.lua index f7198600d..9021404f7 100644 --- a/xmake/includes/xpack/xmake.lua +++ b/xmake/includes/xpack/xmake.lua @@ -49,7 +49,9 @@ local apis = { -- set installed library directory, e.g. lib "xpack.set_libdir", -- set installed include directory, e.g. include - "xpack.set_includedir" + "xpack.set_includedir", + -- set nsis display name + "xpack.set_nsis_displayname" }, paths = { -- set the spec file path, support the custom variable pattern, e.g. set_specfile("", {pattern = "%${([^\n]-)}"}) diff --git a/xmake/modules/private/action/clean/remove_files.lua b/xmake/modules/private/action/clean/remove_files.lua index 606bb405d..3d62c6b78 100644 --- a/xmake/modules/private/action/clean/remove_files.lua +++ b/xmake/modules/private/action/clean/remove_files.lua @@ -25,14 +25,6 @@ import("core.base.option") function main(filedirs, opt) opt = opt or {} for _, filedir in ipairs(filedirs) do - os.tryrm(filedir) - if option.get("all") or opt.emptydir then - -- remove it if the parent directory is empty - local parentdir = path.directory(filedir) - while parentdir and os.isdir(parentdir) and os.emptydir(parentdir) do - os.tryrm(parentdir) - parentdir = path.directory(parentdir) - end - end + os.tryrm(filedir, {emptydirs = option.get("all") or opt.emptydir}) end end diff --git a/xmake/modules/private/utils/batchcmds.lua b/xmake/modules/private/utils/batchcmds.lua index fe518cbec..eda3887c8 100644 --- a/xmake/modules/private/utils/batchcmds.lua +++ b/xmake/modules/private/utils/batchcmds.lua @@ -140,15 +140,7 @@ end function _runcmd_rm(cmd, opt) local filepath = cmd.filepath if not opt.dryrun then - os.tryrm(filepath) - end -end - --- run command: os.tryrm -function _runcmd_tryrm(cmd, opt) - local filepath = cmd.filepath - if not opt.dryrun then - os.tryrm(filepath) + os.tryrm(filepath, opt) end end @@ -156,7 +148,7 @@ end function _runcmd_rmdir(cmd, opt) local dir = cmd.dir if not opt.dryrun and os.isdir(dir) then - os.tryrm(dir) + os.tryrm(dir, opt) end end @@ -197,7 +189,6 @@ function _runcmd(cmd, opt) rmdir = _runcmd_rmdir, cd = _runcmd_cd, rm = _runcmd_rm, - tryrm = _runcmd_tryrm, cp = _runcmd_cp, mv = _runcmd_mv, ln = _runcmd_ln @@ -352,18 +343,13 @@ function batchcmds:mkdir(dir) end -- add command: os.rmdir -function batchcmds:rmdir(dir) - table.insert(self:cmds(), {kind = "rmdir", dir = dir}) +function batchcmds:rmdir(dir, opt) + table.insert(self:cmds(), {kind = "rmdir", dir = dir, opt = opt}) end -- add command: os.rm -function batchcmds:rm(filepath) - table.insert(self:cmds(), {kind = "rm", filepath = filepath}) -end - --- add command: os.tryrm -function batchcmds:tryrm(filepath) - table.insert(self:cmds(), {kind = "tryrm", filepath = filepath}) +function batchcmds:rm(filepath, opt) + table.insert(self:cmds(), {kind = "rm", filepath = filepath, opt = opt}) end -- add command: os.cp diff --git a/xmake/plugins/pack/nsis/main.lua b/xmake/plugins/pack/nsis/main.lua index 02d31ac48..3c4fa3bbd 100644 --- a/xmake/plugins/pack/nsis/main.lua +++ b/xmake/plugins/pack/nsis/main.lua @@ -25,6 +25,7 @@ import("lib.detect.find_tool") import("private.utils.batchcmds") import("private.action.require.impl.packagenv") import("private.action.require.impl.install_packages") +import(".filter") -- get the makensis function _get_makensis() @@ -59,9 +60,9 @@ function _get_unique_tag(content) end -- get command string -function _get_command_strings(package, cmd) +function _get_command_strings(package, cmd, opt) + opt = table.join(cmd.opt or {}, opt) local result = {} - local opt = cmd.opt or {} local kind = cmd.kind if kind == "cp" then -- https://nsis.sourceforge.io/Reference/File @@ -84,25 +85,16 @@ function _get_command_strings(package, cmd) end elseif kind == "rm" then local filepath = path.normalize(path.join("$InstDir", cmd.filepath)) - table.insert(result, string.format("Delete \"%s\"", filepath)) - elseif kind == "tryrm" then - --[[ - IfFileExists "$InstDir\file" file_found file_not_found_or_end - file_found: - Delete "$InstDir\file" - goto file_not_found_or_end - file_not_found_or_end: - --]] - local filepath = path.normalize(path.join("$InstDir", cmd.filepath)) - local tag = _get_unique_tag(filepath) - table.insert(result, string.format("IfFileExists \"%s\" file_found_%s file_not_found_or_end_%s", filepath, tag, tag)) - table.insert(result, string.format("file_found_%s:", tag)) - table.insert(result, string.format(" Delete \"%s\"", filepath)) - table.insert(result, string.format(" goto file_not_found_or_end_%s", tag)) - table.insert(result, string.format("file_not_found_or_end_%s:", tag)) + table.insert(result, string.format("${%s} \"%s\"", opt.install and "RMFileIfExists" or "unRMFileIfExists", filepath)) + if opt.emptydirs then + table.insert(result, string.format("${%s} \"%s\"", opt.install and "RMEmptyParentDirs" or "unRMEmptyParentDirs", filepath)) + end elseif kind == "rmdir" then local dir = path.normalize(path.join("$InstDir", cmd.dir)) - table.insert(result, string.format("RMDir /r \"%s\"", dir)) + table.insert(result, string.format("${%s} \"%s\"", opt.install and "RMDirIfExists" or "unRMDirIfExists", dir)) + if opt.emptydirs then + table.insert(result, string.format("${%s} \"%s\"", opt.install and "RMEmptyParentDirs" or "unRMEmptyParentDirs", dir)) + end elseif kind == "mv" then local srcpath = path.normalize(path.join("$InstDir", cmd.srcpath)) local dstpath = path.normalize(path.join("$InstDir", cmd.dstpath)) @@ -118,10 +110,10 @@ function _get_command_strings(package, cmd) end -- get commands string -function _get_commands_string(package, cmds) +function _get_commands_string(package, cmds, opt) local cmdstrs = {} for _, cmd in ipairs(cmds) do - table.join2(cmdstrs, _get_command_strings(package, cmd)) + table.join2(cmdstrs, _get_command_strings(package, cmd, opt)) end return table.concat(cmdstrs, "\n ") end @@ -173,7 +165,7 @@ end function _uninstall_headers(target, batchcmds_, includedir) local _, dstheaders = target:headerfiles(includedir, {installonly = true}) for _, dstheader in ipairs(dstheaders) do - batchcmds_:rm(dstheader) + batchcmds_:rm(dstheader, {emptydirs = true}) end end @@ -182,7 +174,7 @@ function _uninstall_shared_for_package(target, pkg, batchcmds_, outputdir) for _, dllpath in ipairs(table.wrap(pkg:get("libfiles"))) do if dllpath:endswith(".dll") then local dllname = path.filename(dllpath) - batchcmds_:rm(path.join(outputdir, dllname)) + batchcmds_:rm(path.join(outputdir, dllname), {emptydirs = true}) end end end @@ -311,14 +303,14 @@ function _on_target_uninstallcmd_binary(target, batchcmds_, opt) local bindir = package:bindir() -- uninstall target file - batchcmds_:rm(path.join(bindir, target:filename())) - batchcmds_:tryrm(path.join(bindir, path.filename(target:symbolfile()))) + batchcmds_:rm(path.join(bindir, target:filename()), {emptydirs = true}) + batchcmds_:rm(path.join(bindir, path.filename(target:symbolfile())), {emptydirs = true}) -- remove the dependent shared/windows (*.dll) target -- @see https://github.com/xmake-io/xmake/issues/961 for _, dep in ipairs(target:orderdeps()) do if dep:is_shared() then - batchcmds_:rm(path.join(bindir, path.filename(dep:targetfile()))) + batchcmds_:rm(path.join(bindir, path.filename(dep:targetfile())), {emptydirs = true}) end _uninstall_shared_for_packages(dep, batchcmds_, bindir) end @@ -335,13 +327,13 @@ function _on_target_uninstallcmd_shared(target, batchcmds_, opt) local includedir = package:includedir() -- uninstall target file - batchcmds_:rm(path.join(bindir, target:filename())) - batchcmds_:tryrm(path.join(bindir, path.filename(target:symbolfile()))) + batchcmds_:rm(path.join(bindir, target:filename()), {emptydirs = true}) + batchcmds_:rm(path.join(bindir, path.filename(target:symbolfile())), {emptydirs = true}) -- remove *.lib for shared/windows (*.dll) target -- @see https://github.com/xmake-io/xmake/issues/714 local targetfile = target:targetfile() - batchcmds_:rm(path.join(libdir, path.basename(targetfile) .. (target:is_plat("mingw") and ".dll.a" or ".lib"))) + batchcmds_:rm(path.join(libdir, path.basename(targetfile) .. (target:is_plat("mingw") and ".dll.a" or ".lib")), {emptydirs = true}) -- remove headers from the include directory _uninstall_headers(target, batchcmds_, includedir) @@ -357,8 +349,8 @@ function _on_target_uninstallcmd_static(target, batchcmds_, opt) local includedir = package:includedir() -- uninstall target file - batchcmds_:rm(path.join(libdir, target:filename())) - batchcmds_:tryrm(path.join(libdir, path.filename(target:symbolfile()))) + batchcmds_:rm(path.join(libdir, target:filename()), {emptydirs = true}) + batchcmds_:rm(path.join(libdir, path.filename(target:symbolfile())), {emptydirs = true}) -- remove headers from the include directory _uninstall_headers(target, batchcmds_, includedir) @@ -389,7 +381,7 @@ function _on_target_uninstallcmd(target, batchcmds_, opt) -- uninstall target files local _, dstfiles = target:installfiles(".") for _, dstfile in ipairs(dstfiles) do - batchcmds_:rm(dstfile) + batchcmds_:rm(dstfile, {emptydirs = true}) end end @@ -474,7 +466,7 @@ end function _on_uninstallcmd(package, batchcmds_) local _, dstfiles = package:installfiles(".") for _, dstfile in ipairs(dstfiles) do - batchcmds_:rm(dstfile) + batchcmds_:rm(dstfile, {emptydirs = true}) end for _, target in ipairs(package:targets()) do _get_target_uninstallcmds(target, batchcmds_, {package = package}) @@ -499,7 +491,7 @@ function _get_installcmds(package) end -- generate command string - return _get_commands_string(package, batchcmds_:cmds()) + return _get_commands_string(package, batchcmds_:cmds(), {install = true}) end -- get uninstall commands @@ -520,7 +512,16 @@ function _get_uninstallcmds(package) end -- generate command string - return _get_commands_string(package, batchcmds_:cmds()) + return _get_commands_string(package, batchcmds_:cmds(), {install = false}) +end + +-- get value and filter it +function _get_filter_value(package, name) + local value = package:get(name) + if type(value) == "string" then + value = filter.handle(value, package) + end + return value end -- get specvars @@ -535,6 +536,7 @@ function _get_specvars(package) specvars.PACKAGE_UNINSTALLCMDS = function () return _get_uninstallcmds(package) end + specvars.PACKAGE_NSIS_DISPLAY_NAME = _get_filter_value(package, "nsis_displayname") or package:name() specvars.PACKAGE_NSIS_INSTALL_SECTIONS = function () local result = {} local cmds = package:get("nsis_installcmds") diff --git a/xmake/scripts/xpack/nsis/makensis.nsi b/xmake/scripts/xpack/nsis/makensis.nsi index 5d1a99dc0..ffcb39c7c 100644 --- a/xmake/scripts/xpack/nsis/makensis.nsi +++ b/xmake/scripts/xpack/nsis/makensis.nsi @@ -120,40 +120,128 @@ VIAddVersionKey /LANG=0 ProductVersion "${VERSION_FULL}" ; helper functions Function TrimQuote - Exch $R1 ; Original string - Push $R2 + Exch $R1 ; Original string + Push $R2 Loop: - StrCpy $R2 "$R1" 1 - StrCmp "$R2" "'" TrimLeft - StrCmp "$R2" "$\"" TrimLeft - StrCmp "$R2" "$\r" TrimLeft - StrCmp "$R2" "$\n" TrimLeft - StrCmp "$R2" "$\t" TrimLeft - StrCmp "$R2" " " TrimLeft - GoTo Loop2 + StrCpy $R2 "$R1" 1 + StrCmp "$R2" "'" TrimLeft + StrCmp "$R2" "$\"" TrimLeft + StrCmp "$R2" "$\r" TrimLeft + StrCmp "$R2" "$\n" TrimLeft + StrCmp "$R2" "$\t" TrimLeft + StrCmp "$R2" " " TrimLeft + GoTo Loop2 TrimLeft: - StrCpy $R1 "$R1" "" 1 - Goto Loop + StrCpy $R1 "$R1" "" 1 + Goto Loop Loop2: - StrCpy $R2 "$R1" 1 -1 - StrCmp "$R2" "'" TrimRight - StrCmp "$R2" "$\"" TrimRight - StrCmp "$R2" "$\r" TrimRight - StrCmp "$R2" "$\n" TrimRight - StrCmp "$R2" "$\t" TrimRight - StrCmp "$R2" " " TrimRight - GoTo Done + StrCpy $R2 "$R1" 1 -1 + StrCmp "$R2" "'" TrimRight + StrCmp "$R2" "$\"" TrimRight + StrCmp "$R2" "$\r" TrimRight + StrCmp "$R2" "$\n" TrimRight + StrCmp "$R2" "$\t" TrimRight + StrCmp "$R2" " " TrimRight + GoTo Done TrimRight: - StrCpy $R1 "$R1" -1 - Goto Loop2 + StrCpy $R1 "$R1" -1 + Goto Loop2 Done: - Pop $R2 - Exch $R1 + Pop $R2 + Exch $R1 FunctionEnd +; remove directory if it exists +Function RMDirIfExists +!define RMDirIfExists '!insertmacro RMDirIfExistsCall' +!macro RMDirIfExistsCall _PATH + push '${_PATH}' + Call RMDirIfExists +!macroend + Exch $0 + IfFileExists "$0" 0 fileDoesNotExist + RMDir /r "$0" + fileDoesNotExist: +FunctionEnd + +Function unRMDirIfExists +!define unRMDirIfExists '!insertmacro un.RMDirIfExistsCall' +!macro unRMDirIfExistsCall _PATH + push '${_PATH}' + Call un.RMDirIfExists +!macroend + Exch $0 + IfFileExists "$0" 0 fileDoesNotExist + RMDir /r "$0" + fileDoesNotExist: +FunctionEnd + +; remove file if it exists +Function RMFileIfExists +!define RMFileIfExists '!insertmacro RMFileIfExistsCall' +!macro RMFileIfExistsCall _PATH + push '${_PATH}' + Call RMFileIfExists +!macroend + Exch $0 + IfFileExists "$0" 0 fileDoesNotExist + Delete "$0" + fileDoesNotExist: +FunctionEnd + +Function un.RMFileIfExists +!define unRMFileIfExists '!insertmacro unRMFileIfExistsCall' +!macro unRMFileIfExistsCall _PATH + push '${_PATH}' + Call un.RMFileIfExists +!macroend + Exch $0 + IfFileExists "$0" 0 fileDoesNotExist + Delete "$0" + fileDoesNotExist: +FunctionEnd + +; remove it's parent directories if they are empty +Function RMEmptyParentDirs +!define RMEmptyParentDirs '!insertmacro RMEmptyParentDirsCall' +!macro RMEmptyParentDirsCall _PATH + push '${_PATH}' + Call RMEmptyParentDirs +!macroend + ClearErrors + + Exch $0 + RMDir "$0\.." + + IfErrors Skip + ${RMEmptyParentDirs} "$0\.." + Skip: + + Pop $0 +FunctionEnd + +Function un.RMEmptyParentDirs +!define unRMEmptyParentDirs '!insertmacro unRMEmptyParentDirsCall' +!macro unRMEmptyParentDirsCall _PATH + push '${_PATH}' + Call un.RMEmptyParentDirs +!macroend + ClearErrors + + Exch $0 + RMDir "$0\.." + + IfErrors Skip + ${unRMEmptyParentDirs} "$0\.." + Skip: + + Pop $0 +FunctionEnd + + ; setup installer Var BinDir Var NoAdmin @@ -208,7 +296,7 @@ Section "${PACKAGE_NAME} (required)" InstallExeutable ; Write the uninstall keys for Windows !macro AddReg RootKey WriteRegStr ${RootKey} ${RegUninstall} "NoAdmin" "$NoAdmin" - WriteRegStr ${RootKey} ${RegUninstall} "DisplayName" "${PACKAGE_NAME} (${PACKAGE_ARCH})" + WriteRegStr ${RootKey} ${RegUninstall} "DisplayName" "${PACKAGE_NSIS_DISPLAY_NAME}" WriteRegStr ${RootKey} ${RegUninstall} "DisplayIcon" '"$InstDir\${PACKAGE_BINDIR}\${PACKAGE_FILENAME}"' ; TODO WriteRegStr ${RootKey} ${RegUninstall} "Comments" "${PACKAGE_DESCRIPTION}" WriteRegStr ${RootKey} ${RegUninstall} "Publisher" "${PACKAGE_COPYRIGHT}" @@ -282,7 +370,6 @@ Function un.onInit !else StrCpy $BinDir "$InstDir\${PACKAGE_BINDIR}" !endif - FunctionEnd Section "Uninstall" @@ -304,6 +391,8 @@ Section "Uninstall" ${EndIf} ; remove uninstall.exe - Delete "$InstDir\uninstall.exe" + ${unRMFileIfExists} "$InstDir\uninstall.exe" + ${unRMEmptyParentDirs} "$InstDir\uninstall.exe" + SectionEnd |
