diff options
| author | ruki <[email protected]> | 2021-02-13 00:39:27 +0800 |
|---|---|---|
| committer | ruki <[email protected]> | 2021-02-13 00:39:27 +0800 |
| commit | 5d26d21e31b9ba443208f1f027b5ac8b6cdc44df (patch) | |
| tree | 94eab07b083797ef561102759679a1893cee0511 | |
| parent | e66d6878040a80e6512db851750185b8ab35b127 (diff) | |
split impl.package
10 files changed, 675 insertions, 456 deletions
diff --git a/xmake/modules/private/action/require/export.lua b/xmake/modules/private/action/require/export.lua index 218a669c6..ef1ecf011 100644 --- a/xmake/modules/private/action/require/export.lua +++ b/xmake/modules/private/action/require/export.lua @@ -21,9 +21,9 @@ -- imports import("core.base.task") import("core.base.option") -import("private.action.require.impl.package") import("private.action.require.impl.repository") import("private.action.require.impl.environment") +import("private.action.require.impl.export_packages") import("private.action.require.impl.utils.get_requires") -- export the given packages @@ -46,7 +46,7 @@ function main(requires_raw) -- export packages local exportdir = option.get("exportdir") - local packages = package.export_packages(requires, {requires_extra = requires_extra, exportdir = exportdir}) + local packages = export_packages(requires, {requires_extra = requires_extra, exportdir = exportdir}) for _, instance in ipairs(packages) do print("export: %s%s ok!", instance:name(), instance:version_str() and ("-" .. instance:version_str()) or "") end diff --git a/xmake/modules/private/action/require/impl/export_packages.lua b/xmake/modules/private/action/require/impl/export_packages.lua new file mode 100644 index 000000000..a169a163f --- /dev/null +++ b/xmake/modules/private/action/require/impl/export_packages.lua @@ -0,0 +1,52 @@ +--!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 export_packages.lua +-- + +-- imports +import("private.action.require.impl.package") + +-- export packages +function main(requires, opt) + + -- init options + opt = opt or {} + + -- get the export directory + local exportdir = assert(opt.exportdir) + + -- export all packages + local packages = {} + for _, instance in ipairs(package.load_packages(requires, opt)) do + + -- get the exported name + local name = instance:name():lower():gsub("::", "_") + if instance:version_str() then + name = name .. "_" .. instance:version_str() + end + name = name .. "_" .. instance:buildhash() + + -- export this package + if instance:fetch() then + os.cp(instance:installdir(), path.join(exportdir, name)) + table.insert(packages, instance) + end + end + return packages +end + diff --git a/xmake/modules/private/action/require/impl/install_packages.lua b/xmake/modules/private/action/require/impl/install_packages.lua new file mode 100644 index 000000000..295c3bbbd --- /dev/null +++ b/xmake/modules/private/action/require/impl/install_packages.lua @@ -0,0 +1,393 @@ +--!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 install_packages.lua +-- + +-- imports +import("core.base.option") +import("core.base.hashset") +import("core.base.scheduler") +import("core.base.tty") +import("private.async.runjobs") +import("private.utils.progress") +import("actions.install", {alias = "action_install"}) +import("actions.download", {alias = "action_download"}) +import("net.fasturl") +import("private.action.require.impl.package") + +-- sort packages urls +function _sort_packages_urls(packages) + + -- add all urls to fasturl and prepare to sort them together + for _, instance in pairs(packages) do + fasturl.add(instance:urls()) + end + + -- sort and update urls + for _, instance in pairs(packages) do + instance:urls_set(fasturl.sort(instance:urls())) + end +end + +-- get package parents string +function _get_package_parents_str(instance) + local parents = instance:parents() + if parents then + local parentnames = {} + for _, parent in pairs(parents) do + table.insert(parentnames, parent:displayname()) + end + if #parentnames == 0 then + return + end + return table.concat(parentnames, ",") + end +end + +-- get package configs string +function _get_package_configs_str(instance) + local configs = {} + if instance:optional() then + table.insert(configs, "optional") + end + local requireinfo = instance:requireinfo() + if requireinfo then + for k, v in pairs(requireinfo.configs) do + if type(v) == "boolean" then + table.insert(configs, k .. ":" .. (v and "y" or "n")) + else + table.insert(configs, k .. ":" .. v) + end + end + end + local parents_str = _get_package_parents_str(instance) + if parents_str then + table.insert(configs, "from:" .. parents_str) + end + local configs_str = #configs > 0 and "[" .. table.concat(configs, ", ") .. "]" or "" + local limitwidth = os.getwinsize().width * 2 / 3 + if #configs_str > limitwidth then + configs_str = configs_str:sub(1, limitwidth) .. " ..)" + end + return configs_str +end + +-- get user confirm +function _get_confirm(packages) + + -- no confirmed packages? + if #packages == 0 then + return true + end + + -- get confirm + local confirm = utils.confirm({default = true, description = function () + + -- get packages for each repositories + local packages_repo = {} + local packages_group = {} + for _, instance in ipairs(packages) do + -- achive packages by repository + local reponame = instance:repo() and instance:repo():name() or (instance:isSys() and "system" or "") + if instance:is3rd() then + reponame = instance:name():lower():split("::")[1] + end + packages_repo[reponame] = packages_repo[reponame] or {} + table.insert(packages_repo[reponame], instance) + + -- achive packages by group + local group = instance:group() + if group then + packages_group[group] = packages_group[group] or {} + table.insert(packages_group[group], instance) + end + end + + -- show tips + cprint("${bright color.warning}note: ${clear}try installing these packages (pass -y to skip confirm)?") + for reponame, packages in pairs(packages_repo) do + if reponame ~= "" then + print("in %s:", reponame) + end + local packages_showed = {} + for _, instance in ipairs(packages) do + if not packages_showed[tostring(instance)] then + local group = instance:group() + if group and packages_group[group] and #packages_group[group] > 1 then + for idx, package_in_group in ipairs(packages_group[group]) do + cprint(" ${yellow}%s${clear} %s %s ${dim}%s", idx == 1 and "->" or " or", package_in_group:displayname(), package_in_group:version_str() or "", _get_package_configs_str(package_in_group)) + packages_showed[tostring(package_in_group)] = true + end + packages_group[group] = nil + else + cprint(" ${yellow}->${clear} %s %s ${dim}%s", instance:displayname(), instance:version_str() or "", _get_package_configs_str(instance)) + packages_showed[tostring(instance)] = true + end + end + end + end + end}) + return confirm +end + +-- install packages +function _install_packages(packages_install, packages_download) + + -- we need hide wait characters if is not a tty + local show_wait = io.isatty() + + -- do install + local progress_helper = show_wait and progress.new() or nil + local packages_installing = {} + local packages_downloading = {} + local packages_pending = table.copy(packages_install) + local packages_in_group = {} + local installing_count = 0 + local parallelize = true + runjobs("install_packages", function (index) + + -- fetch a new package + local instance = nil + while instance == nil and #packages_pending > 0 do + for idx, pkg in ipairs(packages_pending) do + + -- all dependences has been installed? we install it now + local ready = true + local dep_not_found = nil + for _, dep in ipairs(pkg:orderdeps()) do + if not dep:exists() then + ready = false + dep_not_found = dep + break + end + end + local group = pkg:group() + if ready and group then + -- this group has been installed? skip it + local group_status = packages_in_group[group] + if group_status == 1 then + table.remove(packages_pending, idx) + break + -- this group is installing? wait it + elseif group_status == 0 then + ready = false + end + end + + -- get a package with the ready status + if ready then + instance = pkg + table.remove(packages_pending, idx) + break + elseif installing_count == 0 then + if #packages_pending == 1 and dep_not_found then + raise("package(%s): cannot be installed, there are dependencies(%s) that cannot be installed!", pkg:displayname(), dep_not_found:displayname()) + elseif #packages_pending == 1 then + raise("package(%s): cannot be installed!", pkg:displayname()) + end + end + end + if instance == nil and #packages_pending > 0 then + scheduler.co_yield() + end + end + if instance then + + -- only install the first package in same group + local group = instance:group() + if not group or not packages_in_group[group] then + + -- disable parallelize? + if not instance:parallelize() then + parallelize = false + end + if not parallelize then + while installing_count > 0 do + scheduler.co_yield() + end + end + installing_count = installing_count + 1 + + -- mark this group as 'installing' + if group then + packages_in_group[group] = 0 + end + + -- download this package first + local downloaded = true + if packages_download[tostring(instance)] then + packages_downloading[index] =instance + downloaded = action_download(instance) + packages_downloading[index] = nil + end + + -- install this package + packages_installing[index] =instance + if downloaded then + action_install(instance) + end + packages_installing[index] = nil + + -- mark this group as 'installed' or 'failed' + if group then + packages_in_group[group] = instance:exists() and 1 or -1 + end + + -- enable parallelize + parallelize = true + installing_count = installing_count - 1 + end + end + packages_installing[index] = nil + packages_downloading[index] = nil + + end, {total = #packages_install, comax = (option.get("verbose") or option.get("diagnosis")) and 1 or 4, on_timer = function (running_jobs_indices) + + -- do not print progress info if be verbose + if option.get("verbose") or not show_wait then + return + end + + -- make installing and downloading packages list + local installing = {} + local downloading = {} + for _, index in ipairs(running_jobs_indices) do + local instance = packages_installing[index] + if instance then + table.insert(installing, instance:displayname()) + end + local instance = packages_downloading[index] + if instance then + table.insert(downloading, instance:displayname()) + end + end + + -- get waitobjs tips + local tips = nil + local waitobjs = scheduler.co_group_waitobjs("install_packages") + if waitobjs:size() > 0 then + local names = {} + for _, obj in waitobjs:keys() do + if obj:otype() == scheduler.OT_PROC then + table.insert(names, obj:name()) + elseif obj:otype() == scheduler.OT_SOCK then + table.insert(names, "sock") + elseif obj:otype() == scheduler.OT_PIPE then + table.insert(names, "pipe") + end + end + names = table.unique(names) + if #names > 0 then + names = table.concat(names, ",") + if #names > 16 then + names = names:sub(1, 16) .. ".." + end + tips = string.format("(%d/%s)", waitobjs:size(), names) + end + end + + -- trace + progress_helper:clear() + tty.erase_line_to_start().cr() + cprintf("${yellow} => ") + if #downloading > 0 then + cprintf("downloading ${magenta}%s", table.concat(downloading, ", ")) + end + if #installing > 0 then + cprintf("%sinstalling ${magenta}%s", #downloading > 0 and ", " or "", table.concat(installing, ", ")) + end + cprintf(" .. %s", tips and ("${dim}" .. tips .. "${clear} ") or "") + progress_helper:write() + end, exit = function(errors) + if errors then + tty.erase_line_to_start().cr() + io.flush() + end + end}) +end + +-- install packages +function main(requires, opt) + + -- init options + opt = opt or {} + + -- load packages + local packages = package.load_packages(requires, opt) + + -- fetch packages (with system) from local first + runjobs("fetch_packages", function (index) + local instance = packages[index] + if instance and (not option.get("force") or (option.get("shallow") and instance:parents())) then + instance:envs_enter() + instance:fetch() + instance:envs_leave() + end + end, {total = #packages}) + + -- filter packages + local packages_install = {} + local packages_download = {} + local packages_unsupported = {} + for _, instance in ipairs(packages) do + if not instance:exists() then + if instance:supported() then + if #instance:urls() > 0 then + packages_download[tostring(instance)] =instance + end + table.insert(packages_install, instance) + elseif not instance:optional() then + table.insert(packages_unsupported, instance) + end + end + end + + -- exists unsupported packages? + if #packages_unsupported > 0 then + -- show tips + cprint("${bright color.warning}note: ${clear}the following packages are unsupported for $(plat)/$(arch)!") + for _, instance in ipairs(packages_unsupported) do + print(" -> %s %s", instance:displayname(), instance:version_str() or "") + end + raise() + end + + -- get user confirm + if not _get_confirm(packages_install) then + local packages_must = {} + for _, instance in ipairs(packages_install) do + if not instance:optional() then + table.insert(packages_must, instance:displayname()) + end + end + if #packages_must > 0 then + raise("packages(%s): must be installed!", table.concat(packages_must, ", ")) + else + -- continue other actions + return + end + end + + -- sort package urls + _sort_packages_urls(packages_download) + + -- install all required packages from repositories + _install_packages(packages_install, packages_download) + return packages +end + diff --git a/xmake/modules/private/action/require/impl/package.lua b/xmake/modules/private/action/require/impl/package.lua index a3d69a982..38a3991b4 100644 --- a/xmake/modules/private/action/require/impl/package.lua +++ b/xmake/modules/private/action/require/impl/package.lua @@ -22,19 +22,12 @@ import("core.base.semver") import("core.base.option") import("core.base.global") -import("core.base.hashset") -import("core.base.scheduler") -import("core.base.tty") import("private.async.runjobs") import("private.utils.progress") import("core.cache.memcache") -import("core.cache.localcache") import("core.project.project") import("core.package.package", {alias = "core_package"}) -import("actions.install", {alias = "action_install"}) -import("actions.download", {alias = "action_download"}) import("devel.git") -import("net.fasturl") import("private.action.require.impl.repository") -- get memcache @@ -192,19 +185,6 @@ function _load_package_from_repository(packagename, reponame) end end --- search packages from repositories -function _search_packages(name) - - local packages = {} - for _, packageinfo in ipairs(repository.searchdirs(name)) do - local package = core_package.load_from_repository(packageinfo.name, packageinfo.repo, packageinfo.packagedir) - if package then - table.insert(packages, package) - end - end - return packages -end - -- sort package deps -- -- e.g. @@ -645,297 +625,6 @@ function _load_packages(requires, opt) return packages end --- sort packages urls -function _sort_packages_urls(packages) - - -- add all urls to fasturl and prepare to sort them together - for _, package in pairs(packages) do - fasturl.add(package:urls()) - end - - -- sort and update urls - for _, package in pairs(packages) do - package:urls_set(fasturl.sort(package:urls())) - end -end - --- get package parents string -function _get_package_parents_str(package) - local parents = package:parents() - if parents then - local parentnames = {} - for _, parent in pairs(parents) do - table.insert(parentnames, parent:displayname()) - end - if #parentnames == 0 then - return - end - return table.concat(parentnames, ",") - end -end - --- get package configs string -function _get_package_configs_str(package) - local configs = {} - if package:optional() then - table.insert(configs, "optional") - end - local requireinfo = package:requireinfo() - if requireinfo then - for k, v in pairs(requireinfo.configs) do - if type(v) == "boolean" then - table.insert(configs, k .. ":" .. (v and "y" or "n")) - else - table.insert(configs, k .. ":" .. v) - end - end - end - local parents_str = _get_package_parents_str(package) - if parents_str then - table.insert(configs, "from:" .. parents_str) - end - local configs_str = #configs > 0 and "[" .. table.concat(configs, ", ") .. "]" or "" - local limitwidth = os.getwinsize().width * 2 / 3 - if #configs_str > limitwidth then - configs_str = configs_str:sub(1, limitwidth) .. " ..)" - end - return configs_str -end - --- get user confirm -function _get_confirm(packages) - - -- no confirmed packages? - if #packages == 0 then - return true - end - - -- get confirm - local confirm = utils.confirm({default = true, description = function () - - -- get packages for each repositories - local packages_repo = {} - local packages_group = {} - for _, package in ipairs(packages) do - -- achive packages by repository - local reponame = package:repo() and package:repo():name() or (package:isSys() and "system" or "") - if package:is3rd() then - reponame = package:name():lower():split("::")[1] - end - packages_repo[reponame] = packages_repo[reponame] or {} - table.insert(packages_repo[reponame], package) - - -- achive packages by group - local group = package:group() - if group then - packages_group[group] = packages_group[group] or {} - table.insert(packages_group[group], package) - end - end - - -- show tips - cprint("${bright color.warning}note: ${clear}try installing these packages (pass -y to skip confirm)?") - for reponame, packages in pairs(packages_repo) do - if reponame ~= "" then - print("in %s:", reponame) - end - local packages_showed = {} - for _, package in ipairs(packages) do - if not packages_showed[tostring(package)] then - local group = package:group() - if group and packages_group[group] and #packages_group[group] > 1 then - for idx, package_in_group in ipairs(packages_group[group]) do - cprint(" ${yellow}%s${clear} %s %s ${dim}%s", idx == 1 and "->" or " or", package_in_group:displayname(), package_in_group:version_str() or "", _get_package_configs_str(package_in_group)) - packages_showed[tostring(package_in_group)] = true - end - packages_group[group] = nil - else - cprint(" ${yellow}->${clear} %s %s ${dim}%s", package:displayname(), package:version_str() or "", _get_package_configs_str(package)) - packages_showed[tostring(package)] = true - end - end - end - end - end}) - return confirm -end - --- install packages -function _install_packages(packages_install, packages_download) - - -- we need hide wait characters if is not a tty - local show_wait = io.isatty() - - -- do install - local progress_helper = show_wait and progress.new() or nil - local packages_installing = {} - local packages_downloading = {} - local packages_pending = table.copy(packages_install) - local packages_in_group = {} - local installing_count = 0 - local parallelize = true - runjobs("install_packages", function (index) - - -- fetch a new package - local package = nil - while package == nil and #packages_pending > 0 do - for idx, pkg in ipairs(packages_pending) do - - -- all dependences has been installed? we install it now - local ready = true - local dep_not_found = nil - for _, dep in ipairs(pkg:orderdeps()) do - if not dep:exists() then - ready = false - dep_not_found = dep - break - end - end - local group = pkg:group() - if ready and group then - -- this group has been installed? skip it - local group_status = packages_in_group[group] - if group_status == 1 then - table.remove(packages_pending, idx) - break - -- this group is installing? wait it - elseif group_status == 0 then - ready = false - end - end - - -- get a package with the ready status - if ready then - package = pkg - table.remove(packages_pending, idx) - break - elseif installing_count == 0 then - if #packages_pending == 1 and dep_not_found then - raise("package(%s): cannot be installed, there are dependencies(%s) that cannot be installed!", pkg:displayname(), dep_not_found:displayname()) - elseif #packages_pending == 1 then - raise("package(%s): cannot be installed!", pkg:displayname()) - end - end - end - if package == nil and #packages_pending > 0 then - scheduler.co_yield() - end - end - if package then - - -- only install the first package in same group - local group = package:group() - if not group or not packages_in_group[group] then - - -- disable parallelize? - if not package:parallelize() then - parallelize = false - end - if not parallelize then - while installing_count > 0 do - scheduler.co_yield() - end - end - installing_count = installing_count + 1 - - -- mark this group as 'installing' - if group then - packages_in_group[group] = 0 - end - - -- download this package first - local downloaded = true - if packages_download[tostring(package)] then - packages_downloading[index] = package - downloaded = action_download(package) - packages_downloading[index] = nil - end - - -- install this package - packages_installing[index] = package - if downloaded then - action_install(package) - end - packages_installing[index] = nil - - -- mark this group as 'installed' or 'failed' - if group then - packages_in_group[group] = package:exists() and 1 or -1 - end - - -- enable parallelize - parallelize = true - installing_count = installing_count - 1 - end - end - packages_installing[index] = nil - packages_downloading[index] = nil - - end, {total = #packages_install, comax = (option.get("verbose") or option.get("diagnosis")) and 1 or 4, on_timer = function (running_jobs_indices) - - -- do not print progress info if be verbose - if option.get("verbose") or not show_wait then - return - end - - -- make installing and downloading packages list - local installing = {} - local downloading = {} - for _, index in ipairs(running_jobs_indices) do - local package = packages_installing[index] - if package then - table.insert(installing, package:displayname()) - end - local package = packages_downloading[index] - if package then - table.insert(downloading, package:displayname()) - end - end - - -- get waitobjs tips - local tips = nil - local waitobjs = scheduler.co_group_waitobjs("install_packages") - if waitobjs:size() > 0 then - local names = {} - for _, obj in waitobjs:keys() do - if obj:otype() == scheduler.OT_PROC then - table.insert(names, obj:name()) - elseif obj:otype() == scheduler.OT_SOCK then - table.insert(names, "sock") - elseif obj:otype() == scheduler.OT_PIPE then - table.insert(names, "pipe") - end - end - names = table.unique(names) - if #names > 0 then - names = table.concat(names, ",") - if #names > 16 then - names = names:sub(1, 16) .. ".." - end - tips = string.format("(%d/%s)", waitobjs:size(), names) - end - end - - -- trace - progress_helper:clear() - tty.erase_line_to_start().cr() - cprintf("${yellow} => ") - if #downloading > 0 then - cprintf("downloading ${magenta}%s", table.concat(downloading, ", ")) - end - if #installing > 0 then - cprintf("%sinstalling ${magenta}%s", #downloading > 0 and ", " or "", table.concat(installing, ", ")) - end - cprintf(" .. %s", tips and ("${dim}" .. tips .. "${clear} ") or "") - progress_helper:write() - end, exit = function(errors) - if errors then - tty.erase_line_to_start().cr() - io.flush() - end - end}) -end - -- the cache directory function cachedir() return path.join(global.directory(), "cache", "packages") @@ -967,140 +656,3 @@ function load_packages(requires, opt) return packages end --- install packages -function install_packages(requires, opt) - - -- init options - opt = opt or {} - - -- load packages - local packages = load_packages(requires, opt) - - -- fetch packages (with system) from local first - runjobs("fetch_packages", function (index) - local package = packages[index] - if package and (not option.get("force") or (option.get("shallow") and package:parents())) then - package:envs_enter() - package:fetch() - package:envs_leave() - end - end, {total = #packages}) - - -- filter packages - local packages_install = {} - local packages_download = {} - local packages_unsupported = {} - for _, package in ipairs(packages) do - if not package:exists() then - if package:supported() then - if #package:urls() > 0 then - packages_download[tostring(package)] = package - end - table.insert(packages_install, package) - elseif not package:optional() then - table.insert(packages_unsupported, package) - end - end - end - - -- exists unsupported packages? - if #packages_unsupported > 0 then - -- show tips - cprint("${bright color.warning}note: ${clear}the following packages are unsupported for $(plat)/$(arch)!") - for _, package in ipairs(packages_unsupported) do - print(" -> %s %s", package:displayname(), package:version_str() or "") - end - raise() - end - - -- get user confirm - if not _get_confirm(packages_install) then - local packages_must = {} - for _, package in ipairs(packages_install) do - if not package:optional() then - table.insert(packages_must, package:displayname()) - end - end - if #packages_must > 0 then - raise("packages(%s): must be installed!", table.concat(packages_must, ", ")) - else - -- continue other actions - return - end - end - - -- sort package urls - _sort_packages_urls(packages_download) - - -- install all required packages from repositories - _install_packages(packages_install, packages_download) - - -- ok - return packages -end - --- uninstall packages -function uninstall_packages(requires, opt) - - -- init options - opt = opt or {} - - -- do not remove dependent packages - opt.nodeps = true - - -- clear the local cache - localcache.clear() - - -- remove all packages - local packages = {} - for _, instance in ipairs(load_packages(requires, opt)) do - if os.isfile(instance:manifest_file()) then - table.insert(packages, instance) - end - os.tryrm(instance:installdir()) - end - return packages -end - --- export packages -function export_packages(requires, opt) - - -- init options - opt = opt or {} - - -- get the export directory - local exportdir = assert(opt.exportdir) - - -- export all packages - local packages = {} - for _, instance in ipairs(load_packages(requires, opt)) do - - -- get the exported name - local name = instance:name():lower():gsub("::", "_") - if instance:version_str() then - name = name .. "_" .. instance:version_str() - end - name = name .. "_" .. instance:buildhash() - - -- export this package - if instance:fetch() then - os.cp(instance:installdir(), path.join(exportdir, name)) - table.insert(packages, instance) - end - end - return packages -end - --- search packages -function search_packages(names) - - -- search all names - local results = {} - for _, name in ipairs(names) do - local packages = _search_packages(name) - if packages then - results[name] = packages - end - end - return results -end diff --git a/xmake/modules/private/action/require/impl/register_packages.lua b/xmake/modules/private/action/require/impl/register_packages.lua new file mode 100644 index 000000000..d0128cf16 --- /dev/null +++ b/xmake/modules/private/action/require/impl/register_packages.lua @@ -0,0 +1,125 @@ +--!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 register_packages.lua +-- + +-- imports +import("core.project.project") + +-- register required package environments +-- envs: bin path for *.dll, program .. +function _register_required_package_envs(instance, envs) + for name, values in pairs(instance:envs()) do + if name == "PATH" or name == "LD_LIBRARY_PATH" or name == "DYLD_LIBRARY_PATH" then + for _, value in ipairs(values) do + envs[name] = envs[name] or {} + if path.is_absolute(value) then + table.insert(envs[name], value) + else + table.insert(envs[name], path.join(instance:installdir(), value)) + end + end + else + envs[name] = envs[name] or {} + table.join2(envs[name], values) + end + end +end + +-- register required package libraries +-- libs: includedirs, links, linkdirs ... +function _register_required_package_libs(instance, required_package, is_deps) + if instance:is_library() then + local fetchinfo = instance:fetch() + if fetchinfo then + fetchinfo.name = nil + if is_deps then + -- we need only reserve license for root package + -- + -- @note the license compatibility between the root package and + -- its dependent packages is guaranteed by the root package itself + -- + fetchinfo.license = nil + + -- we need only some infos for root package + fetchinfo.version = nil + fetchinfo.static = nil + fetchinfo.shared = nil + end + required_package:add(fetchinfo) + end + end +end + +-- register the base info of required package +function _register_required_package_base(instance, required_package) + if not instance:isSys() and not instance:is3rd() then + required_package:set("__installdir", instance:installdir()) + end +end + +-- register the required local package +function _register_required_package(instance, required_package) + + -- disable it if this package is missing + if not instance:exists() then + required_package:enable(false) + else + -- clear require info first + required_package:clear() + + -- add packages info with all dependencies + local envs = {} + _register_required_package_base(instance, required_package) + _register_required_package_libs(instance, required_package) + _register_required_package_envs(instance, envs) + local orderdeps = instance:orderdeps() + if orderdeps then + local total = #orderdeps + for idx, _ in ipairs(orderdeps) do + local dep = orderdeps[total + 1 - idx] + if dep then + _register_required_package_libs(dep, required_package, true) + _register_required_package_envs(dep, envs) + end + end + end + if #table.keys(envs) > 0 then + required_package:add({envs = envs}) + end + + -- enable this require info + required_package:enable(true) + end + + -- save this require info and flush the whole cache file + required_package:save() +end + +-- register all required local packages +function main(packages) + for _, instance in ipairs(packages) do + if not instance:parents() then + local required_package = project.required_package(instance:alias() or instance:name()) + if required_package then + _register_required_package(instance, required_package) + end + end + end +end + diff --git a/xmake/modules/private/action/require/impl/search_packages.lua b/xmake/modules/private/action/require/impl/search_packages.lua new file mode 100644 index 000000000..49183a6cc --- /dev/null +++ b/xmake/modules/private/action/require/impl/search_packages.lua @@ -0,0 +1,50 @@ +--!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 search_packages.lua +-- + +-- imports +import("core.package.package", {alias = "core_package"}) +import("private.action.require.impl.repository") + +-- search packages from repositories +function _search_packages(name) + + local packages = {} + for _, packageinfo in ipairs(repository.searchdirs(name)) do + local package = core_package.load_from_repository(packageinfo.name, packageinfo.repo, packageinfo.packagedir) + if package then + table.insert(packages, package) + end + end + return packages +end + +-- search packages +function main(names) + + -- search all names + local results = {} + for _, name in ipairs(names) do + local packages = _search_packages(name) + if packages then + results[name] = packages + end + end + return results +end diff --git a/xmake/modules/private/action/require/impl/uninstall_packages.lua b/xmake/modules/private/action/require/impl/uninstall_packages.lua new file mode 100644 index 000000000..a5185f868 --- /dev/null +++ b/xmake/modules/private/action/require/impl/uninstall_packages.lua @@ -0,0 +1,47 @@ +--!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 uninstall_packages.lua +-- + +-- imports +import("core.cache.localcache") +import("private.action.require.impl.package") + +-- uninstall packages +function main(requires, opt) + + -- init options + opt = opt or {} + + -- do not remove dependent packages + opt.nodeps = true + + -- clear the local cache + localcache.clear() + + -- remove all packages + local packages = {} + for _, instance in ipairs(package.load_packages(requires, opt)) do + if os.isfile(instance:manifest_file()) then + table.insert(packages, instance) + end + os.tryrm(instance:installdir()) + end + return packages +end + diff --git a/xmake/modules/private/action/require/install.lua b/xmake/modules/private/action/require/install.lua index f7be8b9b9..ae65772e6 100644 --- a/xmake/modules/private/action/require/install.lua +++ b/xmake/modules/private/action/require/install.lua @@ -23,9 +23,9 @@ import("core.base.option") import("core.base.task") import("core.project.project") import("lib.detect.find_tool") -import("private.action.require.impl.package") import("private.action.require.impl.repository") import("private.action.require.impl.environment") +import("private.action.require.impl.install_packages") import("private.action.require.impl.utils.get_requires") -- register required package environments @@ -195,7 +195,7 @@ function main(requires_raw) -- install packages environment.enter() - local packages = package.install_packages(requires, {requires_extra = requires_extra}) + local packages = install_packages(requires, {requires_extra = requires_extra}) if packages then -- check missing packages diff --git a/xmake/modules/private/action/require/search.lua b/xmake/modules/private/action/require/search.lua index 2637e6c36..7f76650b5 100644 --- a/xmake/modules/private/action/require/search.lua +++ b/xmake/modules/private/action/require/search.lua @@ -21,9 +21,9 @@ -- imports import("core.base.task") import("private.action.require.impl.utils.filter") -import("private.action.require.impl.package") import("private.action.require.impl.repository") import("private.action.require.impl.environment") +import("private.action.require.impl.search_packages") -- search the given packages function main(names) @@ -45,7 +45,7 @@ function main(names) print("The package names:") -- search packages - for name, packages in pairs(package.search_packages(names)) do + for name, packages in pairs(search_packages(names)) do if #packages > 0 then -- show name diff --git a/xmake/modules/private/action/require/uninstall.lua b/xmake/modules/private/action/require/uninstall.lua index 2d690614b..b3c2d1bce 100644 --- a/xmake/modules/private/action/require/uninstall.lua +++ b/xmake/modules/private/action/require/uninstall.lua @@ -21,9 +21,9 @@ -- imports import("core.base.task") import("core.base.option") -import("private.action.require.impl.package") import("private.action.require.impl.repository") import("private.action.require.impl.environment") +import("private.action.require.impl.uninstall_packages") import("private.action.require.impl.utils.get_requires") -- uninstall the given packages @@ -45,7 +45,7 @@ function main(requires_raw) end -- uninstall packages - local packages = package.uninstall_packages(requires, {requires_extra = requires_extra}) + local packages = uninstall_packages(requires, {requires_extra = requires_extra}) for _, instance in ipairs(packages) do print("uninstall: %s%s ok!", instance:name(), instance:version_str() and ("-" .. instance:version_str()) or "") end |
