diff options
| author | ruki <[email protected]> | 2023-11-22 11:21:34 +0800 |
|---|---|---|
| committer | GitHub <[email protected]> | 2023-11-22 11:21:34 +0800 |
| commit | 3cf88c4347b0605396b3d5c75f0b34a1c67128ab (patch) | |
| tree | a5b4c18625db8cdf4b27acf4a26e42b73cf8c6dc | |
| parent | d3a27747a757200dc6d0454469a18e9469219f59 (diff) | |
| parent | 93101340da3886b608aefcacba66b20c6142be91 (diff) | |
Merge pull request #4406 from xmake-io/xpack
Support xpack components
| -rw-r--r-- | core/xpack.lua | 8 | ||||
| -rw-r--r-- | tests/plugins/pack/xmake.lua | 16 | ||||
| -rw-r--r-- | xmake/includes/xpack/xmake.lua | 42 | ||||
| -rw-r--r-- | xmake/modules/private/utils/batchcmds.lua | 5 | ||||
| -rw-r--r-- | xmake/plugins/pack/archive.lua | 5 | ||||
| -rw-r--r-- | xmake/plugins/pack/main.lua | 10 | ||||
| -rw-r--r-- | xmake/plugins/pack/nsis/main.lua | 63 | ||||
| -rw-r--r-- | xmake/plugins/pack/xpack.lua | 46 | ||||
| -rw-r--r-- | xmake/plugins/pack/xpack_component.lua | 273 | ||||
| -rw-r--r-- | xmake/scripts/xpack/nsis/makensis.nsi | 2 |
10 files changed, 405 insertions, 65 deletions
diff --git a/core/xpack.lua b/core/xpack.lua index 07e77c1ca..18b7073d0 100644 --- a/core/xpack.lua +++ b/core/xpack.lua @@ -1,5 +1,6 @@ xpack("xmake") set_homepage("https://xmake.io") +-- set_title("Xmake build utility ($(arch))") set_description("A cross-platform build utility based on Lua.") set_copyright("Copyright (C) 2015-present, TBOOX Open Source Group") set_licensefile("../LICENSE.md") @@ -7,7 +8,6 @@ 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() @@ -63,12 +63,6 @@ xpack("xmake") end end) - add_nsis_installcmds("Enable Long Path", [[ - ${If} $NoAdmin == "false" - ; Enable long path - WriteRegDWORD ${HKLM} "SYSTEM\CurrentControlSet\Control\FileSystem" "LongPathsEnabled" 1 - ${EndIf}]], {description = "Increases the maximum path length limit, up to 32,767 characters (before 256)."}) - xpack("xmakesrc") set_formats("src_zip", "src_targz") set_basename("xmake-v$(version)") diff --git a/tests/plugins/pack/xmake.lua b/tests/plugins/pack/xmake.lua index d10af4d54..a93fc18f6 100644 --- a/tests/plugins/pack/xmake.lua +++ b/tests/plugins/pack/xmake.lua @@ -20,12 +20,15 @@ target("foo") xpack("test") set_formats("nsis", "zip", "targz") - set_description("hello") + set_title("hello") + set_description("A test installer.") + set_homepage("https://xmake.io") set_licensefile("LICENSE.md") add_targets("test", "foo") set_basename("test-$(plat)-$(arch)-v$(version)") add_installfiles("src/(assets/*.png)", {prefixdir = "images"}) set_iconfile("src/assets/xmake.ico") + add_components("LongPath") after_installcmd(function (package, batchcmds) batchcmds:mkdir(package:installdir("resources")) @@ -38,9 +41,14 @@ xpack("test") batchcmds:rmdir(package:installdir("stub")) end) - add_nsis_installcmds("Enable Long Path", [[ +xpack_component("LongPath") + set_default(false) + 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("nsis", [[ ${If} $NoAdmin == "false" ; Enable long path WriteRegDWORD ${HKLM} "SYSTEM\CurrentControlSet\Control\FileSystem" "LongPathsEnabled" 1 - ${EndIf}]], {description = "Increases the maximum path length limit, up to 32,767 characters (before 256)."}) - + ${EndIf}]]) + end) diff --git a/xmake/includes/xpack/xmake.lua b/xmake/includes/xpack/xmake.lua index 3eb0d86cb..345431ffc 100644 --- a/xmake/includes/xpack/xmake.lua +++ b/xmake/includes/xpack/xmake.lua @@ -30,8 +30,10 @@ local apis = { values = { -- set package version, we will also get it from project/target "xpack.set_version", - -- set pacakge homepage url + -- set package homepage url "xpack.set_homepage", + -- set package title + "xpack.set_title", -- set package description "xpack.set_description", -- set package copyright @@ -47,6 +49,8 @@ local apis = { "xpack.set_extension", -- add targets to be packaged "xpack.add_targets", + -- add package components + "xpack.add_components", -- set installed binary directory, e.g. bin "xpack.set_bindir", -- set installed library directory, e.g. lib @@ -55,10 +59,14 @@ local apis = { "xpack.set_includedir", -- set prefix directory, e.g. prefixdir/bin, prefixdir/lib .. "xpack.set_prefixdir", - -- set nsis display name - "xpack.set_nsis_displayname", -- set nsis display icon - "xpack.set_nsis_displayicon" + "xpack.set_nsis_displayicon", + -- set package component title + "xpack_component.set_title", + -- set package component description + "xpack_component.set_description", + -- enable/disable this component by default + "xpack_component.set_default" }, paths = { -- set the spec file path, support the custom variable pattern, e.g. set_specfile("", {pattern = "%${([^\n]-)}"}) @@ -90,19 +98,25 @@ local apis = { -- add custom commands script after installing "xpack.after_installcmd", -- add custom commands script after uninstalling - "xpack.after_uninstallcmd" + "xpack.after_uninstallcmd", + -- add custom load script in component + "xpack_component.on_load", + -- add custom commands script before installing in component + "xpack_component.before_installcmd", + -- add custom commands script before uninstalling in component + "xpack_component.before_uninstallcmd", + -- rewrite custom install commands script in component, we will also get it from target/rules + "xpack_component.on_installcmd", + -- rewrite custom uninstall commands script in component, we will also get it from target/rules + "xpack_component.on_uninstallcmd", + -- add custom commands script after installing in component + "xpack_component.after_installcmd", + -- add custom commands script after uninstalling in component + "xpack_component.after_uninstallcmd" }, keyvalues = { -- set the spec variable - "xpack.set_specvar", - -- add nsis sections, e.g. - -- add NSIS install commands that will be added to the end of the install Section, e.g. - --[[ - add_nsis_installcmds("Enable Long Path", - 'WriteRegDWORD ${HKLM} "SYSTEM\CurrentControlSet\Control\FileSystem" "LongPathsEnabled" 1', - {description = "Increases the maximum path length limit, up to 32,767 characters (before 256)."}) - --]] - "xpack.add_nsis_installcmds" + "xpack.set_specvar" } } interp_add_scopeapis(apis) diff --git a/xmake/modules/private/utils/batchcmds.lua b/xmake/modules/private/utils/batchcmds.lua index eda3887c8..4fa2514c9 100644 --- a/xmake/modules/private/utils/batchcmds.lua +++ b/xmake/modules/private/utils/batchcmds.lua @@ -378,6 +378,11 @@ function batchcmds:show(format, ...) table.insert(self:cmds(), {kind = "show", showtext = showtext}) end +-- add raw command for the specific generator or xpack format +function batchcmds:rawcmd(kind, rawstr) + table.insert(self:cmds(), {kind = kind, rawstr = rawstr}) +end + -- add command: show progress function batchcmds:show_progress(progress, format, ...) if progress then diff --git a/xmake/plugins/pack/archive.lua b/xmake/plugins/pack/archive.lua index b48cdb7ed..818404345 100644 --- a/xmake/plugins/pack/archive.lua +++ b/xmake/plugins/pack/archive.lua @@ -28,6 +28,11 @@ function _pack_archive(package) -- do install batchcmds.get_installcmds(package):runcmds() + for _, component in table.orderpairs(package:components()) do + if component:get("default") ~= false then + batchcmds.get_installcmds(component):runcmds() + end + end -- archive install files local rootdir = package:rootdir() diff --git a/xmake/plugins/pack/main.lua b/xmake/plugins/pack/main.lua index 76cc77912..3f145cf86 100644 --- a/xmake/plugins/pack/main.lua +++ b/xmake/plugins/pack/main.lua @@ -27,6 +27,12 @@ import("actions.build.main", {rootdir = os.programdir(), alias = "build_action"} import("xpack") function _load_package(package) + + -- ensure build and output directories + os.tryrm(package:buildir()) + os.mkdir(package:outputdir()) + + -- load it local script = package:script("load") if script then script(package) @@ -39,10 +45,6 @@ end function _pack_package(package) - -- ensure build and output directories - os.tryrm(package:buildir()) - os.mkdir(package:outputdir()) - -- get need formats local formats_need = option.get("formats") if formats_need then diff --git a/xmake/plugins/pack/nsis/main.lua b/xmake/plugins/pack/nsis/main.lua index 854bc46e7..de091430d 100644 --- a/xmake/plugins/pack/nsis/main.lua +++ b/xmake/plugins/pack/nsis/main.lua @@ -137,6 +137,8 @@ function _get_command_strings(package, cmd, opt) elseif kind == "mkdir" then local dir = _translate_filepath(package, cmd.dir) table.insert(result, string.format("CreateDirectory \"%s\"", dir)) + elseif kind == "nsis" then + table.insert(result, cmd.rawstr) end return result end @@ -150,6 +152,16 @@ function _get_commands_string(package, cmds, opt) return table.concat(cmdstrs, "\n ") 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 install commands function _get_installcmds(package) return _get_commands_string(package, batchcmds.get_installcmds(package):cmds(), {install = true}) @@ -195,7 +207,6 @@ 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_DISPLAY_ICON = function () local iconpath = _get_filter_value(package, "nsis_displayicon") if iconpath then @@ -206,36 +217,32 @@ function _get_specvars(package) end return _translate_filepath(package, iconpath) end - specvars.PACKAGE_NSIS_INSTALL_SECTIONS = function () - local result = {} - local cmds = package:get("nsis_installcmds") - for name, cmd in pairs(cmds) do - local tag = "Install" .. _get_unique_tag(name) - table.insert(result, string.format('Section "%s" %s', name, tag)) - table.insert(result, cmd) - table.insert(result, "SectionEnd") - end - return table.concat(result, "\n ") - end - specvars.PACKAGE_NSIS_INSTALL_DESCS = function () - local result = {} - local cmds = package:get("nsis_installcmds") - for name, cmd in pairs(cmds) do - local tag = "Install" .. _get_unique_tag(name) - local description = package:extraconf("nsis_installcmds." .. name, cmd, "description") or name - table.insert(result, string.format('LangString DESC_%s ${LANG_ENGLISH} "%s"', tag, description)) + + -- install sections + local install_sections = {} + local install_descs = {} + local install_description_texts = {} + for name, component in table.orderpairs(package:components()) do + local installcmds = _get_component_installcmds(component) + if installcmds then + local tag = "Install" .. name + table.insert(install_sections, string.format('Section%s "%s" %s', component:get("default") == false and " /o" or "", component:title(), tag)) + table.insert(install_sections, installcmds) + table.insert(install_sections, "SectionEnd") + table.insert(install_descs, string.format('LangString DESC_%s ${LANG_ENGLISH} "%s"', tag, description)) + table.insert(install_description_texts, string.format('!insertmacro MUI_DESCRIPTION_TEXT ${%s} $(DESC_%s)', tag, tag)) end - return table.concat(result, "\n ") - end - specvars.PACKAGE_NSIS_INSTALL_DESCRIPTION_TEXTS = function () - local result = {} - local cmds = package:get("nsis_installcmds") - for name, _ in pairs(cmds) do - local tag = "Install" .. _get_unique_tag(name) - table.insert(result, string.format('!insertmacro MUI_DESCRIPTION_TEXT ${%s} $(DESC_%s)', tag, tag)) + local uninstallcmds = _get_component_uninstallcmds(component) + if uninstallcmds then + local tag = "Uninstall" .. name + table.insert(install_sections, string.format('Section "un.%s" %s', component:title(), tag)) + table.insert(install_sections, uninstallcmds) + table.insert(install_sections, "SectionEnd") end - return table.concat(result, "\n ") end + specvars.PACKAGE_NSIS_INSTALL_SECTIONS = table.concat(install_sections, "\n ") + specvars.PACKAGE_NSIS_INSTALL_DESCS = table.concat(install_descs, "\n ") + specvars.PACKAGE_NSIS_INSTALL_DESCRIPTION_TEXTS = table.concat(install_description_texts, "\n ") return specvars end diff --git a/xmake/plugins/pack/xpack.lua b/xmake/plugins/pack/xpack.lua index 07e162c67..e5829fd45 100644 --- a/xmake/plugins/pack/xpack.lua +++ b/xmake/plugins/pack/xpack.lua @@ -27,6 +27,7 @@ import("core.project.config") import("core.project.project") import("lib.detect.find_tool") import("filter") +import("xpack_component") -- define module local xpack = xpack or object {_init = {"_name", "_info"}} @@ -69,6 +70,15 @@ function xpack:license() return self:get("license") end +-- get the package title +function xpack:title() + local title = self:get("title") + if title == nil then + title = self:name() + end + return filter.handle(title, self) +end + -- get the package description function xpack:description() return self:get("description") @@ -251,6 +261,7 @@ function xpack:specvars() PACKAGE_ARCH = self:arch(), PACKAGE_PLAT = self:plat(), PACKAGE_NAME = self:name(), + PACKAGE_TITLE = self:title() or "", PACKAGE_DESCRIPTION = self:description() or "", PACKAGE_FILENAME = self:filename(), PACKAGE_HOMEPAGE = self:get("homepage") or "", @@ -497,9 +508,35 @@ function xpack:includedir() return self:installdir(includedir) end --- new a xpack +-- get the components +function xpack:components() + local components = _g.components + if components == nil then + components = {} + local xpack_component_scope = project.scope("xpack_component") + for _, component_name in ipairs(self:get("components")) do + local scope = xpack_component_scope[component_name] + if scope then + local instance = xpack_component.new(component_name, scope, self) + components[component_name] = instance + else + raise("unknown xpack component(%s) in xpack(%s)", component_name, self:name()) + end + end + _g.components = components + end + return components +end + +-- get the given component +function xpack:component(name) + return self:components()[name] +end + +-- new a xpack, and we need to clone scope info, +-- because two different format packages maybe have same scope function _new(name, info) - return xpack {name, info} + return xpack {name, info:clone()} end -- get xpack packages @@ -538,8 +575,3 @@ function packages() end return packages end - --- get the given package -function package(name) - return packages()[name] -end diff --git a/xmake/plugins/pack/xpack_component.lua b/xmake/plugins/pack/xpack_component.lua new file mode 100644 index 000000000..59d2fae8f --- /dev/null +++ b/xmake/plugins/pack/xpack_component.lua @@ -0,0 +1,273 @@ +--!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 ruki +-- @file xpack_component.lua +-- + +-- imports +import("core.base.object") +import("core.base.option") +import("core.project.config") +import("core.project.project") + +-- define module +local xpack_component = xpack_component or object {_init = {"_name", "_info", "_package"}} + +-- get name +function xpack_component:name() + return self._name +end + +-- get values +function xpack_component:get(name) + if self._info then + return self._info:get(name) + end +end + +-- set values +function xpack_component:set(name, ...) + if self._info then + self._info:apival_set(name, ...) + end +end + +-- add values +function xpack_component:add(name, ...) + if self._info then + self._info:apival_add(name, ...) + end +end + +-- get the extra configuration +function xpack_component:extraconf(name, item, key) + if self._info then + return self._info:extraconf(name, item, key) + end +end + +-- get the component title +function xpack_component:title() + return self:get("title") or self:name() +end + +-- get the component description +function xpack_component:description() + return self:get("description") +end + +-- get xxx_script +function xpack_component:script(name, generic) + + -- get script + local script = self:get(name) + local result = nil + if type(script) == "function" then + result = script + elseif type(script) == "table" then + + -- get plat and arch + local plat = self:plat() + local arch = self:arch() + + -- match pattern + -- + -- `@linux` + -- `@linux|x86_64` + -- `@macosx,linux` + -- `android@macosx,linux` + -- `android|armeabi-v7a@macosx,linux` + -- `android|armeabi-v7a@macosx,linux|x86_64` + -- `android|armeabi-v7a@linux|x86_64` + -- + for _pattern, _script in pairs(script) do + local hosts = {} + local hosts_spec = false + _pattern = _pattern:gsub("@(.+)", function (v) + for _, host in ipairs(v:split(',')) do + hosts[host] = true + hosts_spec = true + end + return "" + end) + if not _pattern:startswith("__") and (not hosts_spec or hosts[os.subhost() .. '|' .. os.subarch()] or hosts[os.subhost()]) + and (_pattern:trim() == "" or (plat .. '|' .. arch):find('^' .. _pattern .. '$') or plat:find('^' .. _pattern .. '$')) then + result = _script + break + end + end + + -- get generic script + result = result or script["__generic__"] or generic + end + + -- only generic script + return result or generic +end + +-- get targets +function xpack_component:targets() + local targets = self._targets + if not targets then + targets = {} + local targetnames = self:get("targets") + if targetnames then + for _, name in ipairs(targetnames) do + local target = project.target(name) + if target then + table.insert(targets, target) + else + raise("xpack_component(%s): target(%s) not found!", self:name(), name) + end + end + end + self._targets = targets + end + return targets +end + +-- get the given target +function xpack_component:target(name) + local targetnames = self:get("targets") + if targetnames and table.contains(table.wrap(targetnames), name) then + return project.target(name) + end +end + +-- get the copied files +function xpack_component:_copiedfiles(filetype, outputdir) + + -- no copied files? + local copiedfiles = self:get(filetype) + if not copiedfiles then return end + + -- get the extra information + local extrainfo = table.wrap(self:get("__extra_" .. filetype)) + + -- get the source paths and destinate paths + local srcfiles = {} + local dstfiles = {} + local fileinfos = {} + for _, copiedfile in ipairs(table.wrap(copiedfiles)) do + + -- get the root directory + local rootdir, count = copiedfile:gsub("|.*$", ""):gsub("%(.*%)$", "") + if count == 0 then + rootdir = nil + end + if rootdir and rootdir:trim() == "" then + rootdir = "." + end + + -- remove '(' and ')' + local srcpaths = copiedfile:gsub("[%(%)]", "") + if srcpaths then + + -- get the source paths + srcpaths = os.match(srcpaths) + if srcpaths and #srcpaths > 0 then + + -- add the source copied files + table.join2(srcfiles, srcpaths) + + -- the copied directory exists? + if outputdir then + + -- get the file info + local fileinfo = extrainfo[copiedfile] or {} + + -- get the prefix directory + local prefixdir = fileinfo.prefixdir + if fileinfo.rootdir then + rootdir = fileinfo.rootdir + end + + -- add the destinate copied files + for _, srcpath in ipairs(srcpaths) do + + -- get the destinate directory + local dstdir = outputdir + if prefixdir then + dstdir = path.join(dstdir, prefixdir) + end + + -- the destinate file + local dstfile = nil + if rootdir then + dstfile = path.absolute(path.relative(srcpath, rootdir), dstdir) + else + dstfile = path.join(dstdir, path.filename(srcpath)) + end + assert(dstfile) + + -- modify filename + if fileinfo.filename then + dstfile = path.join(path.directory(dstfile), fileinfo.filename) + end + + -- add it + table.insert(dstfiles, dstfile) + table.insert(fileinfos, fileinfo) + end + end + end + end + end + return srcfiles, dstfiles, fileinfos +end + +-- get the package +function xpack_component:package() + return self._package +end + +-- get the install files +function xpack_component:installfiles() + return self:_copiedfiles("installfiles", self:package():installdir()) +end + +-- get the root directory, this is just a temporary sandbox installation path, +-- we may replace it with the actual installation path in the specfile +function xpack_component:rootdir() + return self:package():rootdir() +end + +-- get the installed directory +function xpack_component:installdir(...) + return self:package():installdir(...) +end + +-- get the binary directory +function xpack_component:bindir() + return self:package():bindir() +end + +-- get the library directory +function xpack_component:libdir() + return self:package():libdir() +end + +-- get the include directory +function xpack_component:includedir() + return self:package():includedir() +end + +-- new a xpack_component +function new(name, info, package) + return xpack_component {name, info:clone(), package} +end + diff --git a/xmake/scripts/xpack/nsis/makensis.nsi b/xmake/scripts/xpack/nsis/makensis.nsi index 7be50dd0b..53cd82e99 100644 --- a/xmake/scripts/xpack/nsis/makensis.nsi +++ b/xmake/scripts/xpack/nsis/makensis.nsi @@ -287,7 +287,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_NSIS_DISPLAY_NAME}" + WriteRegStr ${RootKey} ${RegUninstall} "DisplayName" "${PACKAGE_TITLE}" !if "${PACKAGE_NSIS_DISPLAY_ICON}" != "" WriteRegStr ${RootKey} ${RegUninstall} "DisplayIcon" '"${PACKAGE_NSIS_DISPLAY_ICON}"' !endif |
