From 60b16964ace5bbd1314c490c0b44d20338f7bf1d Mon Sep 17 00:00:00 2001 From: A2va <49582555+A2va@users.noreply.github.com> Date: Sun, 25 Feb 2024 21:33:53 +0100 Subject: [PATCH 01/15] Xpack: wix toolset --- xmake/plugins/pack/wix/main.lua | 192 ++++++++++++++++++++++++++++++++ xmake/plugins/pack/xpack.lua | 3 + xmake/scripts/xpack/wix/msi.wxs | 36 ++++++ 3 files changed, 231 insertions(+) create mode 100644 xmake/plugins/pack/wix/main.lua create mode 100644 xmake/scripts/xpack/wix/msi.wxs diff --git a/xmake/plugins/pack/wix/main.lua b/xmake/plugins/pack/wix/main.lua new file mode 100644 index 00000000000..acfd9ce833d --- /dev/null +++ b/xmake/plugins/pack/wix/main.lua @@ -0,0 +1,192 @@ +--!A cross-platform build utility based on Lua +-- +-- Licensed under the Apache License, Version 2.0 (the "License"); +-- you may not use this file except in compliance with the License. +-- You may obtain a copy of the License at +-- +-- http://www.apache.org/licenses/LICENSE-2.0 +-- +-- Unless required by applicable law or agreed to in writing, software +-- distributed under the License is distributed on an "AS IS" BASIS, +-- WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +-- See the License for the specific language governing permissions and +-- limitations under the License. +-- +-- Copyright (C) 2015-present, TBOOX Open Source Group. +-- +-- @author A2va +-- @file main.lua +-- + +import("lib.detect.find_tool") +import("private.action.require.impl.packagenv") +import("private.action.require.impl.install_packages") + +import(".batchcmds") + +-- get the wixtoolset +function _get_wix() + + -- enter the environments of wix + local oldenvs = packagenv.enter("wixtoolset") + + -- find makensis + local packages = {} + local wix = find_tool("wix", {require_version = ">=4.0.0"}) + if not wix then + table.join2(packages, install_packages("wixtoolset")) + end + + -- enter the environments of installed packages + for _, instance in ipairs(packages) do + instance:envs_enter() + end + + -- we need to force detect and flush detect cache after loading all environments + if not wix then + wix = find_tool("wix", {force = true}) + end + assert(wix, "wix not found (ensure that wix is up to date)!") + return wix, oldenvs +end + +-- get command string +function _get_command_strings(package, cmd, opt) + opt = table.join(cmd.opt or {}, opt) + local result = {} + local kind = cmd.kind + if kind == "cp" then + -- https://nsis.sourceforge.io/Reference/File + local srcfiles = os.files(cmd.srcpath) + for _, srcfile in ipairs(srcfiles) do + -- the destination is directory? append the filename + local dstfile = cmd.dstpath + if #srcfiles > 1 or path.islastsep(dstfile) then + if opt.rootdir then + dstfile = path.join(dstfile, path.relative(srcfile, opt.rootdir)) + else + dstfile = path.join(dstfile, path.filename(srcfile)) + end + end + srcfile = path.normalize(srcfile) + local dstname = path.filename(dstfile) + local dstdir = path.normalize(path.directory(dstfile)) + local relative_dstdir = path.relative(dstdir, package:install_rootdir()) + + local subdirectory = dstdir ~= package:install_rootdir() and string.format([[Subdirectory="%s"]], relative_dstdir) or "" + local component_string = string.format([["]], dstname, subdirectory) + local file_string = string.format([[]], srcfile, dstname) + + table.insert(result, component_string) + table.insert(result, file_string) + table.insert(result, "") + end + elseif kind == "rm" then + wprint("rm kind is not supported") + elseif kind == "rmdir" then + wprint("rmdir kind is not supported") + elseif kind == "mv" then + wprint("mv kind is not supported") + elseif kind == "cd" then + wprint("cd kind is not supported") + elseif kind == "mkdir" then + wprint("mkdir kind is not supported") + elseif kind == "wix" then + wprint("wix kind is not supported") + end + return result +end + +-- get commands string +function _get_commands_string(package, cmds, opt) + local cmdstrs = {} + for _, cmd in ipairs(cmds) do + table.join2(cmdstrs, _get_command_strings(package, cmd, opt)) + end + return table.concat(cmdstrs, "\n ") +end + +-- get install commands +function _get_installcmds(package) + return _get_commands_string(package, batchcmds.get_installcmds(package):cmds(), {install = true}) +end + +-- get uninstall commands +function _get_uninstallcmds(package) + return _get_commands_string(package, batchcmds.get_uninstallcmds(package):cmds(), {install = false}) +end + +-- get install commands of component +function _get_component_installcmds(component) + return _get_commands_string(component, batchcmds.get_installcmds(component):cmds(), {install = true}) +end + +-- get uninstall commands of component +function _get_component_uninstallcmds(component) + return _get_commands_string(component, batchcmds.get_uninstallcmds(component):cmds(), {install = false}) +end + +-- get specvars +function _get_specvars(package) + local specvars = table.clone(package:specvars()) + specvars.PACKAGE_INSTALLCMDS = function () + return _get_installcmds(package) + end + + specvars.PACKAGE_WIX_UPGRADECODE = hash.uuid(package:name()) + + -- company cannot be empty with wix + if package:get("company") == nil or package:get("company") == "" then + specvars.PACKAGE_COMPANY = package:name() + end + return specvars +end + +function _pack_wix(wix, package) + + -- install the initial specfile + local specfile = package:specfile() + if not os.isfile(specfile) then + local specfile_template = path.join(os.programdir(), "scripts", "xpack", "wix", "msi.wxs") + os.cp(specfile_template, specfile) + end + + -- replace variables in specfile + local specvars = _get_specvars(package) + local pattern = package:extraconf("specfile", "pattern") or "%${([^\n]-)}" + io.gsub(specfile, "(" .. pattern .. ")", function(_, name) + name = name:trim() + local value = specvars[name] + if type(value) == "function" then + value = value() + end + if value ~= nil then + dprint(" > replace %s -> %s", name, value) + end + if type(value) == "table" then + dprint("invalid variable value", value) + end + return value + end) + + -- make package + -- os.vrunv(wix, {specfile}) +end + +function main(package) + -- only for windows + if not is_host("windows") then + return + end + + cprint("packing %s", package:outputfile()) + + -- get wix + local wix, oldenvs = _get_wix() + + -- pack nsis package + _pack_wix(wix.program, package) + + -- done + os.setenvs(oldenvs) +end \ No newline at end of file diff --git a/xmake/plugins/pack/xpack.lua b/xmake/plugins/pack/xpack.lua index 0eae84a7acb..3dced3d1ece 100644 --- a/xmake/plugins/pack/xpack.lua +++ b/xmake/plugins/pack/xpack.lua @@ -230,6 +230,7 @@ function xpack:inputkind() local inputkind = self:get("inputkind") if inputkind == nil then local inputkinds = { + wix = "binary", nsis = "binary", zip = "binary", targz = "binary", @@ -361,6 +362,7 @@ end -- get the specfile path function xpack:specfile() local extensions = { + wix = ".wxs", nsis = ".nsi", srpm = ".spec", rpm = ".spec", @@ -375,6 +377,7 @@ function xpack:extension() local extension = self:get("extension") if extension == nil then local extensions = { + wix = ".msi", nsis = ".exe", zip = ".zip", targz = ".tar.gz", diff --git a/xmake/scripts/xpack/wix/msi.wxs b/xmake/scripts/xpack/wix/msi.wxs new file mode 100644 index 00000000000..1860df81053 --- /dev/null +++ b/xmake/scripts/xpack/wix/msi.wxs @@ -0,0 +1,36 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + ${PACKAGE_INSTALLCMDS} + + + \ No newline at end of file From de6b4494189ef2975d47450290f5618e65c11b21 Mon Sep 17 00:00:00 2001 From: A2va <49582555+A2va@users.noreply.github.com> Date: Wed, 6 Mar 2024 22:44:55 +0100 Subject: [PATCH 02/15] Split cp kind and other ones --- xmake/plugins/pack/wix/main.lua | 68 ++++++++++++++++++++++++--------- xmake/scripts/xpack/wix/msi.wxs | 4 ++ 2 files changed, 55 insertions(+), 17 deletions(-) diff --git a/xmake/plugins/pack/wix/main.lua b/xmake/plugins/pack/wix/main.lua index acfd9ce833d..51c3c1323d9 100644 --- a/xmake/plugins/pack/wix/main.lua +++ b/xmake/plugins/pack/wix/main.lua @@ -50,13 +50,17 @@ function _get_wix() return wix, oldenvs end --- get command string -function _get_command_strings(package, cmd, opt) +-- translate the file path +function _translate_filepath(package, filepath) + return path.relative(filepath, package:install_rootdir()) +end + +function _get_cp_command(package, cmd, opt) opt = table.join(cmd.opt or {}, opt) local result = {} local kind = cmd.kind + if kind == "cp" then - -- https://nsis.sourceforge.io/Reference/File local srcfiles = os.files(cmd.srcpath) for _, srcfile in ipairs(srcfiles) do -- the destination is directory? append the filename @@ -71,7 +75,7 @@ function _get_command_strings(package, cmd, opt) srcfile = path.normalize(srcfile) local dstname = path.filename(dstfile) local dstdir = path.normalize(path.directory(dstfile)) - local relative_dstdir = path.relative(dstdir, package:install_rootdir()) + local relative_dstdir = _translate_filepath(package, dstdir) local subdirectory = dstdir ~= package:install_rootdir() and string.format([[Subdirectory="%s"]], relative_dstdir) or "" local component_string = string.format([["]], dstname, subdirectory) @@ -81,27 +85,45 @@ function _get_command_strings(package, cmd, opt) table.insert(result, file_string) table.insert(result, "") end - elseif kind == "rm" then - wprint("rm kind is not supported") + end + return result +end + +function _get_other_commands(package, cmd, opt) + opt = table.join(cmd.opt or {}, opt) + local result = {} + local kind = cmd.kind + + if kind == "rm" then + local filepath = _translate_filepath(package, cmd.filepath) + local subdirectory = cmd.filepath ~= package:install_rootdir() and string.format([[Subdirectory="%s"]], filepath) or "" + local on = opt.install and [[On="install"]] or [[On="uninstall"]] + + local remove_file = string.format([[]], subdirectory, on) + table.insert(result, remove_file) elseif kind == "rmdir" then - wprint("rmdir kind is not supported") - elseif kind == "mv" then - wprint("mv kind is not supported") - elseif kind == "cd" then - wprint("cd kind is not supported") + local dir = _translate_filepath(package, cmd.dir) + local subdirectory = cmd.dir ~= package:install_rootdir() and string.format([[Subdirectory="%s"]], dir) or "" + local on = opt.install and [[On="install"]] or [[On="uninstall"]] + + local remove_dir = string.format([[]], subdirectory, on) + table.insert(result, remove_dir) elseif kind == "mkdir" then - wprint("mkdir kind is not supported") - elseif kind == "wix" then - wprint("wix kind is not supported") + local dir = _translate_filepath(package, cmd.dir) + local subdirectory = cmd.dir ~= package:install_rootdir() and string.format([[Subdirectory="%s"]], dir) or "" + local make_dir = string.format([[]], subdirectory) + table.insert(result, make_dir) + else + wprint("kind %s is not supported with wix", kind) end return result end -- get commands string -function _get_commands_string(package, cmds, opt) +function _get_commands_string(package, cmds, opt, func) local cmdstrs = {} for _, cmd in ipairs(cmds) do - table.join2(cmdstrs, _get_command_strings(package, cmd, opt)) + table.join2(cmdstrs, func(package, cmd, opt)) end return table.concat(cmdstrs, "\n ") end @@ -128,9 +150,21 @@ end -- get specvars function _get_specvars(package) + local specvars = table.clone(package:specvars()) + -- install + local installcmds = batchcmds.get_installcmds(package):cmds() specvars.PACKAGE_INSTALLCMDS = function () - return _get_installcmds(package) + return _get_commands_string(package, installcmds, {install = true}, _get_cp_command) + end + specvars.PACKAGE_WIX_FILE_OPERATION_INSTALL = function () + return _get_commands_string(package, installcmds, {install = true}, _get_other_commands) + end + + -- uninstall + local uninstallcmds = batchcmds.get_uninstallcmds(package):cmds() + specvars.PACKAGE_WIX_FILE_OPERATION_UNINSTALL = function () + return _get_commands_string(package, uninstallcmds, {install = false}, _get_other_commands) end specvars.PACKAGE_WIX_UPGRADECODE = hash.uuid(package:name()) diff --git a/xmake/scripts/xpack/wix/msi.wxs b/xmake/scripts/xpack/wix/msi.wxs index 1860df81053..79a5f1de6c3 100644 --- a/xmake/scripts/xpack/wix/msi.wxs +++ b/xmake/scripts/xpack/wix/msi.wxs @@ -30,6 +30,10 @@ + + ${PACKAGE_WIX_FILE_OPERATION_INSTALL} + ${PACKAGE_WIX_FILE_OPERATION_UNINSTALL} + ${PACKAGE_INSTALLCMDS} From 920d1187fa5392fa2363b170a202cb63e75d1c08 Mon Sep 17 00:00:00 2001 From: A2va <49582555+A2va@users.noreply.github.com> Date: Thu, 14 Mar 2024 23:00:43 +0100 Subject: [PATCH 03/15] Refactor cp cmd to output a better xml --- xmake/plugins/pack/wix/main.lua | 112 +++++++++++++++++--------------- xmake/scripts/xpack/wix/msi.wxs | 10 +-- 2 files changed, 63 insertions(+), 59 deletions(-) diff --git a/xmake/plugins/pack/wix/main.lua b/xmake/plugins/pack/wix/main.lua index 51c3c1323d9..466f584056a 100644 --- a/xmake/plugins/pack/wix/main.lua +++ b/xmake/plugins/pack/wix/main.lua @@ -55,19 +55,23 @@ function _translate_filepath(package, filepath) return path.relative(filepath, package:install_rootdir()) end -function _get_cp_command(package, cmd, opt) - opt = table.join(cmd.opt or {}, opt) - local result = {} - local kind = cmd.kind +-- get a table where the key is a directory and the value a list of files +function _get_cp_kind_table(package, cmds, opt) - if kind == "cp" then + local result = {} + for _, cmd in ipairs(cmds) do + if cmd.kind ~= "cp" then + goto continue + end + + local option = table.join(cmd.opt or {}, opt) local srcfiles = os.files(cmd.srcpath) for _, srcfile in ipairs(srcfiles) do -- the destination is directory? append the filename local dstfile = cmd.dstpath if #srcfiles > 1 or path.islastsep(dstfile) then - if opt.rootdir then - dstfile = path.join(dstfile, path.relative(srcfile, opt.rootdir)) + if option.rootdir then + dstfile = path.join(dstfile, path.relative(srcfile, option.rootdir)) else dstfile = path.join(dstfile, path.filename(srcfile)) end @@ -75,16 +79,15 @@ function _get_cp_command(package, cmd, opt) srcfile = path.normalize(srcfile) local dstname = path.filename(dstfile) local dstdir = path.normalize(path.directory(dstfile)) - local relative_dstdir = _translate_filepath(package, dstdir) - - local subdirectory = dstdir ~= package:install_rootdir() and string.format([[Subdirectory="%s"]], relative_dstdir) or "" - local component_string = string.format([["]], dstname, subdirectory) - local file_string = string.format([[]], srcfile, dstname) + dstdir = _translate_filepath(package, dstdir) - table.insert(result, component_string) - table.insert(result, file_string) - table.insert(result, "") + if result[dstdir] then + table.insert(result[dstdir], {srcfile, dstname}) + else + result[dstdir] = {{srcfile, dstname}} + end end + ::continue:: end return result end @@ -119,53 +122,60 @@ function _get_other_commands(package, cmd, opt) return result end --- get commands string -function _get_commands_string(package, cmds, opt, func) - local cmdstrs = {} - for _, cmd in ipairs(cmds) do - table.join2(cmdstrs, func(package, cmd, opt)) - end - return table.concat(cmdstrs, "\n ") +function _get_feature_string(name, opt) + local level = opt.default and 1 or 0 + local description = opt.description or "" + local allow_absent = opt.force and "false" or "true" + local allow_advertise = opt.force and "false" or "true" + local typical_default = opt.force and [[TypicalDefault=install"]] or "" + local feature = string.format([[]], name, name, description, level, allow_advertise, allow_absent, typical_default) + return feature end --- get install commands -function _get_installcmds(package) - return _get_commands_string(package, batchcmds.get_installcmds(package):cmds(), {install = true}) -end +function _get_component_string(id, subdirectory) + local subdirectory = (subdirectory ~= ".") and string.format([[Subdirectory="%s"]], subdirectory) or "" + return string.format([[]], id, hash.uuid(id), subdirectory) +end --- get uninstall commands -function _get_uninstallcmds(package) - return _get_commands_string(package, batchcmds.get_uninstallcmds(package):cmds(), {install = false}) -end +function _build_feature(package, opt) + opt = opt or {} + local default = opt.default or package:get("default") --- get install commands of component -function _get_component_installcmds(component) - return _get_commands_string(component, batchcmds.get_installcmds(component):cmds(), {install = true}) -end + local result = {} + table.insert(result, _get_feature_string(package:title(), {default = default, force = opt.force, description = package:description()})) --- get uninstall commands of component -function _get_component_uninstallcmds(component) - return _get_commands_string(component, batchcmds.get_uninstallcmds(component):cmds(), {install = false}) -end + local installcmds = batchcmds.get_installcmds(package):cmds() + local uninstallcmds = batchcmds.get_uninstallcmds(package):cmds() + + local cp_table = _get_cp_kind_table(package, installcmds, opt) + + for dir, files in pairs(cp_table) do + local d = path.join(package:install_rootdir(), dir) + table.insert(result, _get_component_string(d:gsub(path.sep(), "_"), dir)) + for _, file in ipairs(files) do + local srcfile = file[1] + local dstname = file[2] + table.insert(result, string.format([[]], srcfile, dstname)) + end + table.insert(result, "") + end + + table.insert(result, _get_component_string("OtherCmds")) + table.insert(result, "") + table.insert(result, "") + return result +end -- get specvars function _get_specvars(package) - local specvars = table.clone(package:specvars()) - -- install local installcmds = batchcmds.get_installcmds(package):cmds() - specvars.PACKAGE_INSTALLCMDS = function () - return _get_commands_string(package, installcmds, {install = true}, _get_cp_command) - end - specvars.PACKAGE_WIX_FILE_OPERATION_INSTALL = function () - return _get_commands_string(package, installcmds, {install = true}, _get_other_commands) - end + local specvars = table.clone(package:specvars()) - -- uninstall - local uninstallcmds = batchcmds.get_uninstallcmds(package):cmds() - specvars.PACKAGE_WIX_FILE_OPERATION_UNINSTALL = function () - return _get_commands_string(package, uninstallcmds, {install = false}, _get_other_commands) - end + local features = {} + table.join2(features, _build_feature(package, {default = true, force = true})) + + specvars.PACKAGE_CMDS = table.concat(features, "\n ") specvars.PACKAGE_WIX_UPGRADECODE = hash.uuid(package:name()) diff --git a/xmake/scripts/xpack/wix/msi.wxs b/xmake/scripts/xpack/wix/msi.wxs index 79a5f1de6c3..0e472711722 100644 --- a/xmake/scripts/xpack/wix/msi.wxs +++ b/xmake/scripts/xpack/wix/msi.wxs @@ -22,19 +22,13 @@ - + - - - ${PACKAGE_WIX_FILE_OPERATION_INSTALL} - ${PACKAGE_WIX_FILE_OPERATION_UNINSTALL} - - ${PACKAGE_INSTALLCMDS} - + ${PACKAGE_CMDS} \ No newline at end of file From 145c8946bb75cf4064f9b4ca295e4562e693ba12 Mon Sep 17 00:00:00 2001 From: A2va <49582555+A2va@users.noreply.github.com> Date: Tue, 19 Mar 2024 22:58:43 +0100 Subject: [PATCH 04/15] Support others cmds --- xmake/plugins/pack/wix/main.lua | 35 +++++++++++++++++++-------------- 1 file changed, 20 insertions(+), 15 deletions(-) diff --git a/xmake/plugins/pack/wix/main.lua b/xmake/plugins/pack/wix/main.lua index 466f584056a..74b1abf4d92 100644 --- a/xmake/plugins/pack/wix/main.lua +++ b/xmake/plugins/pack/wix/main.lua @@ -94,29 +94,27 @@ end function _get_other_commands(package, cmd, opt) opt = table.join(cmd.opt or {}, opt) - local result = {} + local result = "" local kind = cmd.kind if kind == "rm" then - local filepath = _translate_filepath(package, cmd.filepath) - local subdirectory = cmd.filepath ~= package:install_rootdir() and string.format([[Subdirectory="%s"]], filepath) or "" + local subdirectory = _translate_filepath(package, path.directory(cmd.filepath)) + subdirectory = subdirectory ~= "." and string.format([[Subdirectory="%s"]], subdirectory) or "" local on = opt.install and [[On="install"]] or [[On="uninstall"]] + local filename = path.filename(cmd.filepath) - local remove_file = string.format([[]], subdirectory, on) - table.insert(result, remove_file) + result = string.format([[]], filename, subdirectory, on) elseif kind == "rmdir" then local dir = _translate_filepath(package, cmd.dir) - local subdirectory = cmd.dir ~= package:install_rootdir() and string.format([[Subdirectory="%s"]], dir) or "" + local subdirectory = dir ~= "." and string.format([[Subdirectory="%s"]], dir) or "" local on = opt.install and [[On="install"]] or [[On="uninstall"]] - local remove_dir = string.format([[]], subdirectory, on) - table.insert(result, remove_dir) + result = string.format([[]], subdirectory, on) elseif kind == "mkdir" then local dir = _translate_filepath(package, cmd.dir) - local subdirectory = cmd.dir ~= package:install_rootdir() and string.format([[Subdirectory="%s"]], dir) or "" - local make_dir = string.format([[]], subdirectory) - table.insert(result, make_dir) - else + local subdirectory = dir ~= "." and string.format([[Subdirectory="%s"]], dir) or "" + result = string.format([[]], subdirectory) + elseif kind ~= "cp" then wprint("kind %s is not supported with wix", kind) end return result @@ -127,13 +125,13 @@ function _get_feature_string(name, opt) local description = opt.description or "" local allow_absent = opt.force and "false" or "true" local allow_advertise = opt.force and "false" or "true" - local typical_default = opt.force and [[TypicalDefault=install"]] or "" + local typical_default = opt.force and [[TypicalDefault="install"]] or "" local feature = string.format([[]], name, name, description, level, allow_advertise, allow_absent, typical_default) return feature end function _get_component_string(id, subdirectory) - local subdirectory = (subdirectory ~= ".") and string.format([[Subdirectory="%s"]], subdirectory) or "" + local subdirectory = (subdirectory ~= "." and subdirectory ~= nil) and string.format([[Subdirectory="%s"]], subdirectory) or "" return string.format([[]], id, hash.uuid(id), subdirectory) end @@ -161,11 +159,18 @@ function _build_feature(package, opt) end table.insert(result, _get_component_string("OtherCmds")) + for _, cmd in ipairs(installcmds) do + table.insert(result, _get_other_commands(package, cmd, {install = true})) + end + for _, cmd in ipairs(uninstallcmds) do + table.insert(result, _get_other_commands(package, cmd, {install = false})) + end + table.insert(result, "") - table.insert(result, "") return result end + -- get specvars function _get_specvars(package) From 06d823d3ee7066ce559b57a308d352e9828bf2e9 Mon Sep 17 00:00:00 2001 From: A2va <49582555+A2va@users.noreply.github.com> Date: Fri, 22 Mar 2024 18:02:54 +0100 Subject: [PATCH 05/15] Add to PATH --- xmake/plugins/pack/wix/main.lua | 24 ++++++++++++++++++++---- 1 file changed, 20 insertions(+), 4 deletions(-) diff --git a/xmake/plugins/pack/wix/main.lua b/xmake/plugins/pack/wix/main.lua index 74b1abf4d92..ed2fbe76073 100644 --- a/xmake/plugins/pack/wix/main.lua +++ b/xmake/plugins/pack/wix/main.lua @@ -56,6 +56,7 @@ function _translate_filepath(package, filepath) end -- get a table where the key is a directory and the value a list of files +-- used to regroup all files that are placed in the same directory under the same component. function _get_cp_kind_table(package, cmds, opt) local result = {} @@ -121,12 +122,13 @@ function _get_other_commands(package, cmd, opt) end function _get_feature_string(name, opt) - local level = opt.default and 1 or 0 + local level = opt.default and 1 or 2 local description = opt.description or "" local allow_absent = opt.force and "false" or "true" local allow_advertise = opt.force and "false" or "true" local typical_default = opt.force and [[TypicalDefault="install"]] or "" - local feature = string.format([[]], name, name, description, level, allow_advertise, allow_absent, typical_default) + local directory = opt.config_dir and [[ConfigurableDirectory="INSTALLFOLDER]] or "" + local feature = string.format([[]], name, name, description, level, allow_advertise, allow_absent, typical_default, directory) return feature end @@ -135,17 +137,19 @@ function _get_component_string(id, subdirectory) return string.format([[]], id, hash.uuid(id), subdirectory) end +-- build a feature from batchcmds function _build_feature(package, opt) opt = opt or {} local default = opt.default or package:get("default") local result = {} - table.insert(result, _get_feature_string(package:title(), {default = default, force = opt.force, description = package:description()})) + table.insert(result, _get_feature_string(package:title(), table.join(opt, {default = default, description = package:description()}))) local installcmds = batchcmds.get_installcmds(package):cmds() local uninstallcmds = batchcmds.get_uninstallcmds(package):cmds() - + local cp_table = _get_cp_kind_table(package, installcmds, opt) + table.remove_if(installcmds, function (_, cmd) return cmd.kind == "cp" end) for dir, files in pairs(cp_table) do local d = path.join(package:install_rootdir(), dir) @@ -171,6 +175,17 @@ function _build_feature(package, opt) return result end +-- add to path feature +function _add_to_path(package) + local result = {} + table.insert(result, _get_feature_string("PATH", {default = false, force = false, description = "Add to PATH", config_dir = false})) + table.insert(result, _get_component_string("PATH")) + table.insert(result, [[]]) + table.insert(result, "") + table.insert(result, "") + return result +end + -- get specvars function _get_specvars(package) @@ -179,6 +194,7 @@ function _get_specvars(package) local features = {} table.join2(features, _build_feature(package, {default = true, force = true})) + table.join2(features, _add_to_path(package)) specvars.PACKAGE_CMDS = table.concat(features, "\n ") From 007a8cc968097a24845dbf26fd3f6a3704c4b1b3 Mon Sep 17 00:00:00 2001 From: A2va <49582555+A2va@users.noreply.github.com> Date: Wed, 24 Apr 2024 23:04:32 +0200 Subject: [PATCH 06/15] Add components support --- xmake/plugins/pack/wix/main.lua | 9 ++++++--- 1 file changed, 6 insertions(+), 3 deletions(-) diff --git a/xmake/plugins/pack/wix/main.lua b/xmake/plugins/pack/wix/main.lua index ed2fbe76073..57c792d5a64 100644 --- a/xmake/plugins/pack/wix/main.lua +++ b/xmake/plugins/pack/wix/main.lua @@ -127,7 +127,7 @@ function _get_feature_string(name, opt) local allow_absent = opt.force and "false" or "true" local allow_advertise = opt.force and "false" or "true" local typical_default = opt.force and [[TypicalDefault="install"]] or "" - local directory = opt.config_dir and [[ConfigurableDirectory="INSTALLFOLDER]] or "" + local directory = opt.config_dir and [[ConfigurableDirectory="INSTALLFOLDER"]] or "" local feature = string.format([[]], name, name, description, level, allow_advertise, allow_absent, typical_default, directory) return feature end @@ -143,7 +143,7 @@ function _build_feature(package, opt) local default = opt.default or package:get("default") local result = {} - table.insert(result, _get_feature_string(package:title(), table.join(opt, {default = default, description = package:description()}))) + table.insert(result, _get_feature_string(opt.name or package:title(), table.join(opt, {default = default, description = package:description()}))) local installcmds = batchcmds.get_installcmds(package):cmds() local uninstallcmds = batchcmds.get_uninstallcmds(package):cmds() @@ -196,8 +196,11 @@ function _get_specvars(package) table.join2(features, _build_feature(package, {default = true, force = true})) table.join2(features, _add_to_path(package)) - specvars.PACKAGE_CMDS = table.concat(features, "\n ") + for name, component in table.orderpairs(package:components()) do + table.join2(features, _build_feature(component, {name = "Install " .. name})) + end + specvars.PACKAGE_CMDS = table.concat(features, "\n ") specvars.PACKAGE_WIX_UPGRADECODE = hash.uuid(package:name()) -- company cannot be empty with wix From 88e54f59fb02d94cbd669e03848b7c09057d66ae Mon Sep 17 00:00:00 2001 From: A2va <49582555+A2va@users.noreply.github.com> Date: Wed, 8 May 2024 13:22:21 +0200 Subject: [PATCH 07/15] Execute wixtoolset --- xmake/plugins/pack/wix/main.lua | 19 ++++++++++++++----- 1 file changed, 14 insertions(+), 5 deletions(-) diff --git a/xmake/plugins/pack/wix/main.lua b/xmake/plugins/pack/wix/main.lua index 57c792d5a64..5455b7cfcdf 100644 --- a/xmake/plugins/pack/wix/main.lua +++ b/xmake/plugins/pack/wix/main.lua @@ -115,12 +115,11 @@ function _get_other_commands(package, cmd, opt) local dir = _translate_filepath(package, cmd.dir) local subdirectory = dir ~= "." and string.format([[Subdirectory="%s"]], dir) or "" result = string.format([[]], subdirectory) - elseif kind ~= "cp" then - wprint("kind %s is not supported with wix", kind) end return result end +-- get the string of a wix feature function _get_feature_string(name, opt) local level = opt.default and 1 or 2 local description = opt.description or "" @@ -178,7 +177,7 @@ end -- add to path feature function _add_to_path(package) local result = {} - table.insert(result, _get_feature_string("PATH", {default = false, force = false, description = "Add to PATH", config_dir = false})) + table.insert(result, _get_feature_string("PATH", {default = false, force = false, description = "Add to PATH"})) table.insert(result, _get_component_string("PATH")) table.insert(result, [[]]) table.insert(result, "") @@ -193,7 +192,7 @@ function _get_specvars(package) local specvars = table.clone(package:specvars()) local features = {} - table.join2(features, _build_feature(package, {default = true, force = true})) + table.join2(features, _build_feature(package, {default = true, force = true, config_dir = true})) table.join2(features, _add_to_path(package)) for name, component in table.orderpairs(package:components()) do @@ -237,8 +236,18 @@ function _pack_wix(wix, package) return value end) + local argv = {"build", specfile} + table.join2(argv, {"-ext", "WixToolset.UI.wixext"}) + table.join2(argv, {"-o", package:outputfile()}) + + if package:arch() == "x64" then + table.join2(argv, {"-arch", "x64"}) + elseif package:arch() == "x86" then + table.join2(argv, {"-arch", "x86"}) + end + -- make package - -- os.vrunv(wix, {specfile}) + os.vrunv(wix, argv) end function main(package) From cd3b9b037ece3d8dce7711f4143351733ce2a2ba Mon Sep 17 00:00:00 2001 From: A2va <49582555+A2va@users.noreply.github.com> Date: Wed, 8 May 2024 13:36:40 +0200 Subject: [PATCH 08/15] Fixes --- xmake/plugins/pack/wix/main.lua | 6 +++--- xmake/scripts/xpack/wix/msi.wxs | 2 +- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/xmake/plugins/pack/wix/main.lua b/xmake/plugins/pack/wix/main.lua index 5455b7cfcdf..403ccca3ec9 100644 --- a/xmake/plugins/pack/wix/main.lua +++ b/xmake/plugins/pack/wix/main.lua @@ -125,7 +125,7 @@ function _get_feature_string(name, opt) local description = opt.description or "" local allow_absent = opt.force and "false" or "true" local allow_advertise = opt.force and "false" or "true" - local typical_default = opt.force and [[TypicalDefault="install"]] or "" + local typical_default = [[TypicalDefault="install"]] local directory = opt.config_dir and [[ConfigurableDirectory="INSTALLFOLDER"]] or "" local feature = string.format([[]], name, name, description, level, allow_advertise, allow_absent, typical_default, directory) return feature @@ -179,7 +179,7 @@ function _add_to_path(package) local result = {} table.insert(result, _get_feature_string("PATH", {default = false, force = false, description = "Add to PATH"})) table.insert(result, _get_component_string("PATH")) - table.insert(result, [[]]) + table.insert(result, [[]]) table.insert(result, "") table.insert(result, "") return result @@ -199,7 +199,7 @@ function _get_specvars(package) table.join2(features, _build_feature(component, {name = "Install " .. name})) end - specvars.PACKAGE_CMDS = table.concat(features, "\n ") + specvars.PACKAGE_WIX_CMDS = table.concat(features, "\n ") specvars.PACKAGE_WIX_UPGRADECODE = hash.uuid(package:name()) -- company cannot be empty with wix diff --git a/xmake/scripts/xpack/wix/msi.wxs b/xmake/scripts/xpack/wix/msi.wxs index 0e472711722..6bbab6457ba 100644 --- a/xmake/scripts/xpack/wix/msi.wxs +++ b/xmake/scripts/xpack/wix/msi.wxs @@ -29,6 +29,6 @@ - ${PACKAGE_CMDS} + ${PACKAGE_WIX_CMDS} \ No newline at end of file From ec28f1ef6eddce80c7cd86f1e57a19532d3e681c Mon Sep 17 00:00:00 2001 From: A2va <49582555+A2va@users.noreply.github.com> Date: Wed, 8 May 2024 14:53:25 +0200 Subject: [PATCH 09/15] Handle license --- xmake/plugins/pack/wix/main.lua | 27 ++++++++++++++++++++++++++- xmake/scripts/xpack/wix/msi.wxs | 1 + 2 files changed, 27 insertions(+), 1 deletion(-) diff --git a/xmake/plugins/pack/wix/main.lua b/xmake/plugins/pack/wix/main.lua index 403ccca3ec9..938cb424fcf 100644 --- a/xmake/plugins/pack/wix/main.lua +++ b/xmake/plugins/pack/wix/main.lua @@ -55,6 +55,20 @@ function _translate_filepath(package, filepath) return path.relative(filepath, package:install_rootdir()) end +function _to_rtf_string(str) + if str == "" then + return str + end + + local escape_text = str:gsub("\\", "\\\\") + escape_text = escape_text:gsub("{", "\\{") + escape_text = escape_text:gsub("}", "\\}") + + local rtf = "{\\rtf1\\ansi{\\fonttbl\\f0\\fswiss Helvetica;}\\f0\\pard "; + rtf = rtf .. escape_text:gsub("\r\n", " \\par ") .. "}" + return rtf +end + -- get a table where the key is a directory and the value a list of files -- used to regroup all files that are placed in the same directory under the same component. function _get_cp_kind_table(package, cmds, opt) @@ -199,6 +213,18 @@ function _get_specvars(package) table.join2(features, _build_feature(component, {name = "Install " .. name})) end + specvars.PACKAGE_LICENSEFILE = function () + local rtf_string = "" + local licensefile = package:get("licensefile") + if licensefile then + rtf_string = _to_rtf_string(io.readfile(licensefile)) + end + + local rtf_file = path.join(package:buildir(), "license.rtf") + io.writefile(rtf_file, rtf_string) + return rtf_file + end + specvars.PACKAGE_WIX_CMDS = table.concat(features, "\n ") specvars.PACKAGE_WIX_UPGRADECODE = hash.uuid(package:name()) @@ -257,7 +283,6 @@ function main(package) end cprint("packing %s", package:outputfile()) - -- get wix local wix, oldenvs = _get_wix() diff --git a/xmake/scripts/xpack/wix/msi.wxs b/xmake/scripts/xpack/wix/msi.wxs index 6bbab6457ba..82ec2e88a47 100644 --- a/xmake/scripts/xpack/wix/msi.wxs +++ b/xmake/scripts/xpack/wix/msi.wxs @@ -23,6 +23,7 @@ + From 0dbf9be2558b974a04624a0b85717804df68100c Mon Sep 17 00:00:00 2001 From: A2va <49582555+A2va@users.noreply.github.com> Date: Fri, 24 May 2024 17:29:48 +0200 Subject: [PATCH 10/15] Fix wix id --- xmake/plugins/pack/wix/main.lua | 31 +++++++++++++++++++++++++------ 1 file changed, 25 insertions(+), 6 deletions(-) diff --git a/xmake/plugins/pack/wix/main.lua b/xmake/plugins/pack/wix/main.lua index 938cb424fcf..7bad457862b 100644 --- a/xmake/plugins/pack/wix/main.lua +++ b/xmake/plugins/pack/wix/main.lua @@ -129,6 +129,8 @@ function _get_other_commands(package, cmd, opt) local dir = _translate_filepath(package, cmd.dir) local subdirectory = dir ~= "." and string.format([[Subdirectory="%s"]], dir) or "" result = string.format([[]], subdirectory) + elseif kind == "wix" then + table.insert(result, cmd.rawstr) end return result end @@ -141,22 +143,38 @@ function _get_feature_string(name, opt) local allow_advertise = opt.force and "false" or "true" local typical_default = [[TypicalDefault="install"]] local directory = opt.config_dir and [[ConfigurableDirectory="INSTALLFOLDER"]] or "" - local feature = string.format([[]], name, name, description, level, allow_advertise, allow_absent, typical_default, directory) + local feature = string.format([[]], name:gsub(" ", ""), name, description, level, allow_advertise, allow_absent, typical_default, directory) return feature end function _get_component_string(id, subdirectory) local subdirectory = (subdirectory ~= "." and subdirectory ~= nil) and string.format([[Subdirectory="%s"]], subdirectory) or "" - return string.format([[]], id, hash.uuid(id), subdirectory) + return string.format([[]], id:gsub(" ", ""), hash.uuid(id), subdirectory) end +-- for each id/guid in the file wix want them to be unique +-- so compute a hash for each directory based on the file that are inside +function _get_dir_id(cp_table) + local hashes = {} + for dir, files in pairs(cp_table) do + local s = "" + for _, file in ipairs(files) do + s = s .. table.concat(file, "") + end + -- wix required id to start with a letter and without any hyphen + hashes[dir] = "A".. hash.uuid(s):gsub("-", ".") + end + return hashes +end + -- build a feature from batchcmds function _build_feature(package, opt) opt = opt or {} local default = opt.default or package:get("default") local result = {} - table.insert(result, _get_feature_string(opt.name or package:title(), table.join(opt, {default = default, description = package:description()}))) + local name = opt.name or package:title() + table.insert(result, _get_feature_string(name, table.join(opt, {default = default, description = package:description()}))) local installcmds = batchcmds.get_installcmds(package):cmds() local uninstallcmds = batchcmds.get_uninstallcmds(package):cmds() @@ -164,9 +182,10 @@ function _build_feature(package, opt) local cp_table = _get_cp_kind_table(package, installcmds, opt) table.remove_if(installcmds, function (_, cmd) return cmd.kind == "cp" end) + local dir_id = _get_dir_id(cp_table) + for dir, files in pairs(cp_table) do - local d = path.join(package:install_rootdir(), dir) - table.insert(result, _get_component_string(d:gsub(path.sep(), "_"), dir)) + table.insert(result, _get_component_string(dir_id[dir], dir)) for _, file in ipairs(files) do local srcfile = file[1] local dstname = file[2] @@ -175,7 +194,7 @@ function _build_feature(package, opt) table.insert(result, "") end - table.insert(result, _get_component_string("OtherCmds")) + table.insert(result, _get_component_string(name.. "Cmds")) for _, cmd in ipairs(installcmds) do table.insert(result, _get_other_commands(package, cmd, {install = true})) end From fa333a9cc927abab2916d45bcf0fc068f035c484 Mon Sep 17 00:00:00 2001 From: A2va <49582555+A2va@users.noreply.github.com> Date: Fri, 24 May 2024 17:33:41 +0200 Subject: [PATCH 11/15] Use title instead of component name --- xmake/plugins/pack/wix/main.lua | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/xmake/plugins/pack/wix/main.lua b/xmake/plugins/pack/wix/main.lua index 7bad457862b..de5e5265273 100644 --- a/xmake/plugins/pack/wix/main.lua +++ b/xmake/plugins/pack/wix/main.lua @@ -136,14 +136,14 @@ function _get_other_commands(package, cmd, opt) end -- get the string of a wix feature -function _get_feature_string(name, opt) +function _get_feature_string(name, title, opt) local level = opt.default and 1 or 2 local description = opt.description or "" local allow_absent = opt.force and "false" or "true" local allow_advertise = opt.force and "false" or "true" local typical_default = [[TypicalDefault="install"]] local directory = opt.config_dir and [[ConfigurableDirectory="INSTALLFOLDER"]] or "" - local feature = string.format([[]], name:gsub(" ", ""), name, description, level, allow_advertise, allow_absent, typical_default, directory) + local feature = string.format([[]], name:gsub(" ", ""), title, description, level, allow_advertise, allow_absent, typical_default, directory) return feature end @@ -174,7 +174,7 @@ function _build_feature(package, opt) local result = {} local name = opt.name or package:title() - table.insert(result, _get_feature_string(name, table.join(opt, {default = default, description = package:description()}))) + table.insert(result, _get_feature_string(name, package:title(), table.join(opt, {default = default, description = package:description()}))) local installcmds = batchcmds.get_installcmds(package):cmds() local uninstallcmds = batchcmds.get_uninstallcmds(package):cmds() @@ -210,7 +210,7 @@ end -- add to path feature function _add_to_path(package) local result = {} - table.insert(result, _get_feature_string("PATH", {default = false, force = false, description = "Add to PATH"})) + table.insert(result, _get_feature_string("PATH", "Add to PATH", {default = false, force = false, description = "Add to PATH"})) table.insert(result, _get_component_string("PATH")) table.insert(result, [[]]) table.insert(result, "") From 28322db9b0c5ccee35c1445dfc567bea0d8ff072 Mon Sep 17 00:00:00 2001 From: A2va <49582555+A2va@users.noreply.github.com> Date: Fri, 24 May 2024 18:13:50 +0200 Subject: [PATCH 12/15] Add icon banner Then file icon is not working --- xmake/scripts/xpack/wix/msi.wxs | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/xmake/scripts/xpack/wix/msi.wxs b/xmake/scripts/xpack/wix/msi.wxs index 82ec2e88a47..dda4978a745 100644 --- a/xmake/scripts/xpack/wix/msi.wxs +++ b/xmake/scripts/xpack/wix/msi.wxs @@ -20,7 +20,11 @@ - + + + + + From 6072e5322a07588331cace47edd6022910094691 Mon Sep 17 00:00:00 2001 From: A2va <49582555+A2va@users.noreply.github.com> Date: Fri, 24 May 2024 18:14:04 +0200 Subject: [PATCH 13/15] Add wix format to tests --- tests/plugins/pack/xmake.lua | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/tests/plugins/pack/xmake.lua b/tests/plugins/pack/xmake.lua index 1ce179b3315..2506d2fc4be 100644 --- a/tests/plugins/pack/xmake.lua +++ b/tests/plugins/pack/xmake.lua @@ -19,7 +19,7 @@ target("foo") add_packages("zlib") xpack("test") - set_formats("nsis", "srpm", "rpm", "zip", "targz", "srczip", "srctargz", "runself") + set_formats("nsis", "srpm", "rpm", "zip", "targz", "srczip", "srctargz", "runself", "wix") set_title("hello") set_author("ruki") set_description("A test installer.") @@ -61,6 +61,11 @@ xpack_component("LongPath") set_title("Enable Long Path") set_description("Increases the maximum path length limit, up to 32,767 characters (before 256).") on_installcmd(function (component, batchcmds) + batchcmds:rawcmd("wix", [[ + + + + ]]) batchcmds:rawcmd("nsis", [[ ${If} $NoAdmin == "false" ; Enable long path From 962077210503076c8a45a2fc214ef068bfa3cd31 Mon Sep 17 00:00:00 2001 From: A2va <49582555+A2va@users.noreply.github.com> Date: Fri, 24 May 2024 23:31:42 +0200 Subject: [PATCH 14/15] Fix raw wix cmd --- xmake/plugins/pack/wix/main.lua | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/xmake/plugins/pack/wix/main.lua b/xmake/plugins/pack/wix/main.lua index de5e5265273..8fce6a2dc49 100644 --- a/xmake/plugins/pack/wix/main.lua +++ b/xmake/plugins/pack/wix/main.lua @@ -130,7 +130,7 @@ function _get_other_commands(package, cmd, opt) local subdirectory = dir ~= "." and string.format([[Subdirectory="%s"]], dir) or "" result = string.format([[]], subdirectory) elseif kind == "wix" then - table.insert(result, cmd.rawstr) + result = cmd.rawstr end return result end From 1f81152c5bc78bab1cc460e8b3fcba174312a22b Mon Sep 17 00:00:00 2001 From: ruki Date: Mon, 27 May 2024 15:52:16 +0800 Subject: [PATCH 15/15] Update xmake.lua --- xmake/plugins/pack/xmake.lua | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/xmake/plugins/pack/xmake.lua b/xmake/plugins/pack/xmake.lua index 0afa83cfff0..fa4408d78b2 100644 --- a/xmake/plugins/pack/xmake.lua +++ b/xmake/plugins/pack/xmake.lua @@ -32,7 +32,7 @@ task("pack") "e.g.", " - xmake pack -f nsis,deb,rpm", "values:", - values = {"nsis", "deb", "srpm", "rpm", "runself", "targz", "zip", "srctargz", "srczip"}}, + values = {"nsis", "wix", "deb", "srpm", "rpm", "runself", "targz", "zip", "srctargz", "srczip"}}, {}, {nil, "packages", "vs", nil, "The package names."} }