summaryrefslogtreecommitdiff
path: root/xmake/actions/require/impl
diff options
context:
space:
mode:
authorruki <[email protected]>2021-02-12 22:53:12 +0800
committerruki <[email protected]>2021-02-12 22:53:12 +0800
commitcc7678dfae7d945b34b8abc70f18e26b8045fd9e (patch)
tree8f5959fb0ac52b39677530b40ad522e2aff385d2 /xmake/actions/require/impl
parentb29d4891a97dda8bc7a8b805651a77c0bb7698c0 (diff)
move require impl
Diffstat (limited to 'xmake/actions/require/impl')
-rw-r--r--xmake/actions/require/impl/actions/download.lua268
-rw-r--r--xmake/actions/require/impl/actions/download_resources.lua96
-rw-r--r--xmake/actions/require/impl/actions/install.lua273
-rw-r--r--xmake/actions/require/impl/actions/patch_sources.lua112
-rw-r--r--xmake/actions/require/impl/actions/test.lua59
-rw-r--r--xmake/actions/require/impl/environment.lua73
-rw-r--r--xmake/actions/require/impl/package.lua1106
-rw-r--r--xmake/actions/require/impl/repository.lua113
-rw-r--r--xmake/actions/require/impl/utils/filter.lua146
-rw-r--r--xmake/actions/require/impl/utils/get_requires.lua57
-rw-r--r--xmake/actions/require/impl/utils/url_filename.lua25
11 files changed, 0 insertions, 2328 deletions
diff --git a/xmake/actions/require/impl/actions/download.lua b/xmake/actions/require/impl/actions/download.lua
deleted file mode 100644
index af1c96b75..000000000
--- a/xmake/actions/require/impl/actions/download.lua
+++ /dev/null
@@ -1,268 +0,0 @@
---!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 download.lua
---
-
--- imports
-import("core.base.option")
-import("core.base.tty")
-import("core.base.hashset")
-import("core.project.config")
-import("core.package.package", {alias = "core_package"})
-import("lib.detect.find_file")
-import("lib.detect.find_directory")
-import(".utils.filter")
-import(".utils.url_filename")
-import("net.http")
-import("devel.git")
-import("utils.archive")
-
--- checkout codes from git
-function _checkout(package, url, sourcedir, url_alias)
-
- -- use previous source directory if exists
- local packagedir = path.join(sourcedir, package:name())
- if os.isdir(packagedir) and
- not (option.get("force") and package:branch()) then -- we need disable cache if we force to clone from the given branch
-
- -- clean the previous build files
- git.clean({repodir = packagedir, force = true, all = true})
- -- reset the previous modified files
- git.reset({repodir = packagedir, hard = true})
- tty.erase_line_to_start().cr()
- return
- end
-
- -- we can use local package from the search directories directly if network is too slow
- local localdir = find_directory(package:name() .. archive.extension(url), core_package.searchdirs())
- if localdir and os.isdir(localdir) then
- git.clean({repodir = localdir, force = true, all = true})
- tty.erase_line_to_start().cr()
- return
- end
-
- -- remove temporary directory
- os.rm(sourcedir .. ".tmp")
-
- -- download package from branches?
- packagedir = path.join(sourcedir .. ".tmp", package:name())
- if package:branch() then
-
- -- only shadow clone this branch
- git.clone(url, {depth = 1, recursive = true, branch = package:branch(), outputdir = packagedir})
-
- -- download package from revision or tag?
- else
-
- -- clone whole history and tags
- git.clone(url, {outputdir = packagedir, recursive = true})
-
- -- attempt to checkout the given version
- git.checkout(package:revision(url_alias) or package:tag() or package:version_str(), {repodir = packagedir})
- end
-
- -- move to source directory
- os.rm(sourcedir)
- os.mv(sourcedir .. ".tmp", sourcedir)
-
- -- trace
- tty.erase_line_to_start().cr()
- cprint("${yellow} => ${clear}clone %s %s .. ${color.success}${text.success}", url, package:version_str())
-end
-
--- download codes from ftp/http/https
-function _download(package, url, sourcedir, url_alias, url_excludes)
-
- -- get package file
- local packagefile = url_filename(url)
-
- -- get sourcehash from the given url
- --
- -- we need not sourcehash and skip checksum to try download it directly if no version list in package()
- -- @see https://github.com/xmake-io/xmake/issues/930
- -- https://github.com/xmake-io/xmake/issues/1009
- --
- local sourcehash = package:sourcehash(url_alias)
- assert(not package:verify() or not package:get("versions") or sourcehash, "cannot get source hash of %s in package(%s)", url, package:name())
-
- -- the package file have been downloaded?
- local cached = true
- if not os.isfile(packagefile) or sourcehash ~= hash.sha256(packagefile) then
-
- -- no cached
- cached = false
-
- -- attempt to remove package file first
- os.tryrm(packagefile)
-
- -- download or copy package file
- local localfile = find_file(path.filename(packagefile), core_package.searchdirs())
- if os.isfile(url) then
- os.cp(url, packagefile)
- elseif localfile and os.isfile(localfile) then
- -- we can use local package from the search directories directly if network is too slow
- os.cp(localfile, packagefile)
- else
- http.download(url, packagefile)
- end
-
- -- check hash
- if sourcehash and sourcehash ~= hash.sha256(packagefile) then
- raise("unmatched checksum!")
- end
- end
-
- -- extract package file
- os.rm(sourcedir .. ".tmp")
- if archive.extract(packagefile, sourcedir .. ".tmp", {excludes = url_excludes}) then
- -- move to source directory
- os.rm(sourcedir)
- os.mv(sourcedir .. ".tmp", sourcedir)
- else
- -- create an empty source directory if do not extract package file
- os.tryrm(sourcedir)
- os.mkdir(sourcedir)
- end
-
- -- save original file path
- package:originfile_set(path.absolute(packagefile))
-
- -- trace
- tty.erase_line_to_start().cr()
- if not cached then
- cprint("${yellow} => ${clear}download %s .. ${color.success}${text.success}", url)
- end
-end
-
--- get sorted urls
-function _urls(package)
-
- -- sort urls from the version source
- local urls = {{}, {}}
- for _, url in ipairs(package:urls()) do
- if git.checkurl(url) then
- table.insert(urls[1], url)
- elseif not package:verify() or not package:get("versions") or package:sourcehash(package:url_alias(url)) then
- table.insert(urls[2], url)
- end
- end
- if package:gitref() then
- return table.join(urls[1], urls[2])
- else
- return table.join(urls[2], urls[1])
- end
-end
-
--- download the given package
-function main(package)
-
- -- get working directory of this package
- local workdir = package:cachedir()
-
- -- ensure the working directory first
- os.mkdir(workdir)
-
- -- enter the working directory
- local oldir = os.cd(workdir)
-
- -- lock this package
- package:lock()
-
- -- get urls
- local urls = _urls(package)
- assert(#urls > 0, "cannot get url of package(%s)", package:name())
-
- -- download package from urls
- local ok = false
- local urls_failed = {}
- for idx, url in ipairs(urls) do
-
- -- get url alias
- local url_alias = package:url_alias(url)
-
- -- get url excludes
- local url_excludes = package:url_excludes(url)
-
- -- filter url
- url = filter.handle(url, package)
-
- -- download url
- ok = try
- {
- function ()
-
- -- download package
- local sourcedir = "source"
- if git.checkurl(url) then
- _checkout(package, url, sourcedir, url_alias)
- else
- _download(package, url, sourcedir, url_alias, url_excludes)
- end
- return true
- end,
- catch
- {
- function (errors)
-
- -- show or save the last errors
- if errors and (option.get("verbose") or option.get("diagnosis")) then
- cprint("${dim color.error}error: ${clear}%s", errors)
- end
-
- -- trace
- tty.erase_line_to_start().cr()
- if git.checkurl(url) then
- cprint("${yellow} => ${clear}clone %s %s .. ${color.failure}${text.failure}", url, package:version_str())
- else
- cprint("${yellow} => ${clear}download %s .. ${color.failure}${text.failure}", url)
- end
- table.insert(urls_failed, url)
-
- -- failed? break it
- if idx == #urls and not package:optional() then
- if #urls_failed > 0 then
- print("")
- print("we can also download these packages manually:")
- local searchnames = hashset.new()
- for _, url_failed in ipairs(urls_failed) do
- cprint(" ${yellow}- %s", url_failed)
- searchnames:insert(url_filename(url_failed))
- end
- cprint("to the local search directories: ${bright}%s", table.concat(table.wrap(core_package.searchdirs()), path.envsep()))
- cprint(" ${bright}- %s", table.concat(searchnames:to_array(), ", "))
- cprint("and we can run `xmake g --pkg_searchdirs=/xxx` to set the search directories.")
- end
- raise("download failed!")
- end
- end
- }
- }
-
- -- ok? break it
- if ok then break end
- end
-
- -- unlock this package
- package:unlock()
-
- -- leave working directory
- os.cd(oldir)
- return ok
-end
-
-
diff --git a/xmake/actions/require/impl/actions/download_resources.lua b/xmake/actions/require/impl/actions/download_resources.lua
deleted file mode 100644
index 6447b3ea2..000000000
--- a/xmake/actions/require/impl/actions/download_resources.lua
+++ /dev/null
@@ -1,96 +0,0 @@
---!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 download_resources.lua
---
-
--- imports
-import("core.base.option")
-import("core.package.package", {alias = "core_package"})
-import("lib.detect.find_file")
-import("net.http")
-import("utils.archive")
-
--- download resources
-function _download(package, resource_name, resource_url, resource_hash)
-
- -- trace
- vprint("downloading resource(%s: %s) to %s-%s ..", resource_name, resource_url, package:name(), package:version_str())
-
- -- get the resource file
- local resource_file = assert(package:resourcefile(resource_name), "invalid resource file!")
-
- -- ensure lower hash
- if resource_hash then
- resource_hash = resource_hash:lower()
- end
-
- -- the package file have been downloaded?
- local cached = true
- if option.get("force") or not os.isfile(resource_file) or resource_hash ~= hash.sha256(resource_file) then
-
- -- no cached
- cached = false
-
- -- attempt to remove the previous file first
- os.tryrm(resource_file)
-
- -- download or copy the resource file
- local localfile = find_file(path.filename(resource_file), core_package.searchdirs())
- if localfile and os.isfile(localfile) then
- -- we can use local resource from the search directories directly if network is too slow
- os.cp(localfile, resource_file)
- elseif resource_url:find(string.ipattern("https-://")) or resource_url:find(string.ipattern("ftps-://")) then
- http.download(resource_url, resource_file)
- else
- raise("invalid resource url(%s)", resource_url)
- end
-
- -- check hash
- if resource_hash and resource_hash ~= hash.sha256(resource_file) then
- raise("resource(%s): unmatched checksum!", resource_url)
- end
- end
-
- -- extract the resource file
- local resourcedir = package:resourcedir(resource_name)
- local resourcedir_tmp = resourcedir .. ".tmp"
- os.tryrm(resourcedir_tmp)
- if archive.extract(resource_file, resourcedir_tmp) then
- os.tryrm(resourcedir)
- os.mv(resourcedir_tmp, resourcedir)
- else
- os.tryrm(resourcedir_tmp)
- end
-end
-
--- download all resources of the given package
-function main(package)
-
- -- no resources?
- local resources = package:resources()
- if not resources then
- return
- end
-
- -- download all resources
- for name, resourceinfo in pairs(resources) do
- -- we use wrap to support urls table and only get the first url now
- -- TODO maybe we will download resource from the multiple urls in the future
- _download(package, name, table.wrap(resourceinfo.url)[1], resourceinfo.sha256)
- end
-end
diff --git a/xmake/actions/require/impl/actions/install.lua b/xmake/actions/require/impl/actions/install.lua
deleted file mode 100644
index 4b077b373..000000000
--- a/xmake/actions/require/impl/actions/install.lua
+++ /dev/null
@@ -1,273 +0,0 @@
---!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.lua
---
-
--- imports
-import("core.base.option")
-import("core.base.tty")
-import("core.project.target")
-import("lib.detect.find_file")
-import("test")
-import("patch_sources")
-import("download_resources")
-import(".utils.filter")
-
--- patch pkgconfig if not exists
-function _patch_pkgconfig(package)
-
- -- only binary? need not pkgconfig
- if not package:is_library() then
- return
- end
-
- -- get lib/pkgconfig/*.pc file
- local pkgconfigdir = path.join(package:installdir(), "lib", "pkgconfig")
- local pcfile = os.isdir(pkgconfigdir) and find_file("*.pc", pkgconfigdir) or nil
- if pcfile then
- return
- end
-
- -- trace
- pcfile = path.join(pkgconfigdir, package:name() .. ".pc")
- vprint("patching %s ..", pcfile)
-
- -- fetch package
- local fetchinfo = package:fetchdeps()
- if not fetchinfo then
- return
- end
-
- -- get libs
- local libs = ""
- for _, linkdir in ipairs(fetchinfo.linkdirs) do
- libs = libs .. "-L" .. linkdir
- end
- libs = libs .. " -L${libdir}"
- for _, link in ipairs(fetchinfo.links) do
- libs = libs .. " -l" .. link
- end
- for _, link in ipairs(fetchinfo.syslinks) do
- libs = libs .. " -l" .. link
- end
-
- -- cflags
- local cflags = ""
- for _, includedir in ipairs(fetchinfo.includedirs) do
- cflags = cflags .. "-I" .. includedir
- end
- cflags = cflags .. " -I${includedir}"
-
- -- patch a *.pc file
- local file = io.open(pcfile, 'w')
- if file then
- file:print("prefix=%s", package:installdir())
- file:print("exec_prefix=${prefix}")
- file:print("libdir=${exec_prefix}/lib")
- file:print("includedir=${prefix}/include")
- file:print("")
- file:print("Name: %s", package:name())
- file:print("Description: %s", package:description())
- file:print("Version: %s", package:version_str())
- file:print("Libs: %s", libs)
- file:print("Libs.private: ")
- file:print("Cflags: %s", cflags)
- file:close()
- end
-end
-
--- install the given package
-function main(package)
-
- -- get working directory of this package
- local workdir = package:cachedir()
-
- -- lock this package
- package:lock()
-
- -- enter the working directory
- local oldir = nil
- if #package:urls() > 0 then
- -- only one root directory? skip it
- local filedirs = os.filedirs(path.join(workdir, "source", "*"))
- if #filedirs == 1 and os.isdir(filedirs[1]) then
- oldir = os.cd(filedirs[1])
- else
- oldir = os.cd(path.join(workdir, "source"))
- end
- end
- if not oldir then
- os.mkdir(workdir)
- oldir = os.cd(workdir)
- end
-
- -- init tipname
- local tipname = package:name()
- if package:version_str() then
- tipname = tipname .. "-" .. package:version_str()
- end
-
- -- install it
- try
- {
- function ()
-
- -- the package scripts
- local scripts =
- {
- package:script("install_before")
- , package:script("install")
- , package:script("install_after")
- }
-
- -- install the third-party package directly, e.g. brew::pcre2/libpcre2-8, conan::OpenSSL/1.0.2n@conan/stable
- local installed_now = false
- if package:is3rd() then
- local script = package:script("install")
- if script ~= nil then
- filter.call(script, package)
- end
- else
-
- -- build and install package to the install directory
- if option.get("force") or not package:manifest_load() then
-
- -- clean install directory first
- os.tryrm(package:installdir())
-
- -- enter the environments of all package dependencies
- for _, dep in ipairs(package:orderdeps()) do
- dep:envs_enter()
- end
-
- -- download package resources
- download_resources(package)
-
- -- patch source codes of package
- patch_sources(package)
-
- -- do install
- for i = 1, 3 do
- local script = scripts[i]
- if script ~= nil then
- filter.call(script, package)
- end
- end
-
- -- leave the environments of all package dependencies
- for _, dep in irpairs(package:orderdeps()) do
- dep:envs_leave()
- end
-
- -- save the package info to the manifest file
- package:manifest_save()
- installed_now = true
- end
- end
-
- -- enter the package environments
- for _, dep in ipairs(package:orderdeps()) do
- dep:envs_enter()
- end
- package:envs_enter()
-
- -- fetch package and force to flush the cache
- local fetchinfo = package:fetch({force = true})
- if option.get("verbose") or option.get("diagnosis") then
- print(fetchinfo)
- end
- assert(fetchinfo, "fetch %s failed!", tipname)
-
- -- this package is installed now
- if installed_now then
-
- -- patch pkg-config files for package
- _patch_pkgconfig(package)
-
- -- test it
- test(package)
- end
-
- -- leave the package environments
- package:envs_leave()
- for _, dep in irpairs(package:orderdeps()) do
- dep:envs_leave()
- end
-
- -- trace
- tty.erase_line_to_start().cr()
- cprint("${yellow} => ${clear}install %s %s .. ${color.success}${text.success}", package:displayname(), package:version_str() or "")
- end,
-
- catch
- {
- function (errors)
-
- -- show or save the last errors
- local errorfile = path.join(package:installdir("logs"), "install.txt")
- if errors then
- if (option.get("verbose") or option.get("diagnosis")) then
- cprint("${dim color.error}error: ${clear}%s", errors)
- else
- io.writefile(errorfile, errors .. "\n")
- end
- end
-
- -- trace
- tty.erase_line_to_start().cr()
- cprint("${yellow} => ${clear}install %s %s .. ${color.failure}${text.failure}", package:displayname(), package:version_str() or "")
-
- -- leave the package environments
- package:envs_leave()
-
- -- copy the invalid package directory to cache
- local installdir = package:installdir()
- if os.isdir(installdir) then
- local installdir_failed = path.join(package:cachedir(), "installdir.failed")
- os.tryrm(installdir_failed)
- if not os.isdir(installdir_failed) then
- os.cp(installdir, installdir_failed)
- end
- errorfile = path.join(installdir_failed, "logs", "install.txt")
- end
- os.tryrm(installdir)
-
- -- failed
- if not package:requireinfo().optional then
- if os.isfile(errorfile) then
- print("if you want to get verbose errors, please see:")
- cprint(" -> ${bright}%s", errorfile)
- end
- raise("install failed!")
- end
- end
- }
- }
-
- -- clean the empty package directory
- local installdir = package:installdir()
- if os.emptydir(installdir) then
- os.tryrm(installdir)
- end
-
- -- unlock this package
- package:unlock()
-
- -- leave source codes directory
- os.cd(oldir)
-end
diff --git a/xmake/actions/require/impl/actions/patch_sources.lua b/xmake/actions/require/impl/actions/patch_sources.lua
deleted file mode 100644
index 110330af0..000000000
--- a/xmake/actions/require/impl/actions/patch_sources.lua
+++ /dev/null
@@ -1,112 +0,0 @@
---!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 patch_sources.lua
---
-
--- imports
-import("core.base.option")
-import("net.http")
-import("devel.git")
-
--- check sha256
-function _check_sha256(patch_hash, patch_file)
- local ok = (patch_hash == hash.sha256(patch_file))
- if not ok and is_host("windows") then
- -- `git pull` maybe will replace lf to crlf in the patch text automatically on windows.
- -- so we need attempt to fix this sha256
- --
- -- @see
- -- https://github.com/xmake-io/xmake-repo/pull/67
- -- https://stackoverflow.com/questions/1967370/git-replacing-lf-with-crlf
- --
- local tmpfile = os.tmpfile(patch_file)
- os.cp(patch_file, tmpfile)
- local content = io.readfile(tmpfile, {encoding = "binary"})
- content = content:gsub('\r\n', '\n')
- io.writefile(tmpfile, content, {encoding = "binary"})
- ok = (patch_hash == hash.sha256(tmpfile))
- os.rm(tmpfile)
- end
- return ok
-end
-
--- do patch
-function _patch(package, patch_url, patch_hash)
-
- -- trace
- vprint("patching %s to %s-%s ..", patch_url, package:name(), package:version_str())
-
- -- get the patch file
- local patch_file = path.join(os.tmpdir(), "patches", package:name(), package:version_str(), (path.filename(patch_url):gsub("%?.+$", "")))
-
- -- ensure lower hash
- if patch_hash then
- patch_hash = patch_hash:lower()
- end
-
- -- the package file have been downloaded?
- local cached = true
- if option.get("force") or not os.isfile(patch_file) or not _check_sha256(patch_hash, patch_file) then
-
- -- no cached
- cached = false
-
- -- attempt to remove the previous file first
- os.tryrm(patch_file)
-
- -- download the patch file
- if patch_url:find(string.ipattern("https-://")) or patch_url:find(string.ipattern("ftps-://")) then
- http.download(patch_url, patch_file)
- else
- -- copy the patch file
- if os.isfile(patch_url) then
- os.cp(patch_url, patch_file)
- else
- local scriptdir = package:scriptdir()
- if scriptdir and os.isfile(path.join(scriptdir, patch_url)) then
- os.cp(path.join(scriptdir, patch_url), patch_file)
- else
- raise("patch(%s): not found!", patch_url)
- end
- end
- end
-
- -- check hash
- if patch_hash and not _check_sha256(patch_hash, patch_file) then
- raise("patch(%s): unmatched checksum!", patch_url)
- end
- end
-
- -- apply the patch file
- git.apply(patch_file)
-end
-
--- patch the given package
-function main(package)
-
- -- no patches?
- local patches = package:patches()
- if not patches then
- return
- end
-
- -- do all patches
- for _, patchinfo in ipairs(patches) do
- _patch(package, patchinfo.url, patchinfo.sha256)
- end
-end
diff --git a/xmake/actions/require/impl/actions/test.lua b/xmake/actions/require/impl/actions/test.lua
deleted file mode 100644
index 2cad6f689..000000000
--- a/xmake/actions/require/impl/actions/test.lua
+++ /dev/null
@@ -1,59 +0,0 @@
---!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 test.lua
---
-
--- imports
-import("core.base.option")
-import(".utils.filter")
-
--- test the given package
-function main(package)
-
- -- the package scripts
- local scripts =
- {
- package:script("test_before")
- , package:script("test")
- , package:script("test_after")
- }
-
- -- enter the test directory
- local testdir = path.join(os.tmpdir(), "pkgtest", package:name(), package:version_str() or "latest")
- if os.isdir(testdir) then
- os.tryrm(testdir)
- end
- if not os.isdir(testdir) then
- os.mkdir(testdir)
- end
- local oldir = os.cd(testdir)
-
- -- test it
- for i = 1, 3 do
- local script = scripts[i]
- if script ~= nil then
- filter.call(script, package)
- end
- end
-
- -- restore the current directory
- os.cd(oldir)
-
- -- remove the test directory
- os.tryrm(testdir)
-end
diff --git a/xmake/actions/require/impl/environment.lua b/xmake/actions/require/impl/environment.lua
deleted file mode 100644
index 89034fabf..000000000
--- a/xmake/actions/require/impl/environment.lua
+++ /dev/null
@@ -1,73 +0,0 @@
---!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 environment.lua
---
-
--- imports
-import("core.project.config")
-import("core.package.package", {alias = "core_package"})
-import("lib.detect.find_tool")
-import("private.action.require.packagenv")
-import("package")
-
--- enter environment
---
--- ensure that we can find some basic tools: git, unzip, ...
---
--- If these tools not exist, we will install it first.
---
-function enter()
-
- -- unzip or 7zip is necessary
- if not find_tool("unzip") and not find_tool("7z") then
- raise("unzip or 7zip not found! we need install it first")
- end
-
- -- enter the environments of git
- packagenv.enter("git")
-
- -- git not found? install it first
- local packages = {}
- if not find_tool("git") then
- table.join2(packages, package.install_packages("git"))
- end
-
- -- missing the necessary unarchivers for *.gz, *.7z? install them first, e.g. gzip, 7z, tar ..
- if not ((find_tool("gzip") and find_tool("tar")) or find_tool("7z")) then
- table.join2(packages, package.install_packages("7z"))
- end
-
- -- enter the environments of installed packages
- for _, instance in ipairs(packages) do
- instance:envs_enter()
- end
- _g._PACKAGES = packages
-end
-
--- leave environment
-function leave()
-
- -- leave the environments of installed packages
- for _, instance in irpairs(_g._PACKAGES) do
- instance:envs_leave()
- end
- _g._PACKAGES = nil
-
- -- leave the environments of git
- packagenv.leave("git")
-end
diff --git a/xmake/actions/require/impl/package.lua b/xmake/actions/require/impl/package.lua
deleted file mode 100644
index 17589aaf4..000000000
--- a/xmake/actions/require/impl/package.lua
+++ /dev/null
@@ -1,1106 +0,0 @@
---!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 package.lua
---
-
--- imports
-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("repository")
-
--- get memcache
-function _memcache()
- return memcache.cache("require.impl.package")
-end
-
---
--- parse require string
---
--- basic
--- - add_requires("zlib")
---
--- semver
--- - add_requires("tbox >=1.5.1", "zlib >=1.2.11")
---
--- git branch/tag
--- - add_requires("zlib master")
---
--- with the given repository
--- - add_requires("xmake-repo@tbox >=1.5.1")
---
--- with the given configs
--- - add_requires("aaa_bbb_ccc >=1.5.1 <1.6.0", {optional = true, alias = "mypkg", debug = true})
--- - add_requires("tbox", {config = {coroutine = true, abc = "xxx"}})
---
--- with namespace and the 3rd package manager
--- - add_requires("xmake::xmake-repo@tbox >=1.5.1")
--- - add_requires("vcpkg::ffmpeg")
--- - add_requires("conan::OpenSSL/1.0.2n@conan/stable")
--- - add_requires("conan::openssl/1.1.1g") -- new
--- - add_requires("brew::pcre2/libpcre2-8 10.x", {alias = "pcre2"})
---
--- clone as a standalone package with the different configs
--- we can install and use these three packages at the same time.
--- - add_requires("zlib")
--- - add_requires("zlib~debug", {debug = true})
--- - add_requires("zlib~shared", {configs = {shared = true}, alias = "zlib_shared"})
---
--- {system = nil/true/false}:
--- nil: get local or system packages
--- true: only get system package
--- false: only get local packages
---
---
-function _parse_require(require_str, requires_extra, parentinfo)
-
- -- split package and version info
- local splitinfo = require_str:split('%s+')
- assert(splitinfo and #splitinfo > 0, "require(\"%s\"): invalid!", require_str)
-
- -- get package info
- local packageinfo = splitinfo[1]
-
- -- get version
- --
- -- e.g.
- --
- -- latest
- -- >=1.5.1 <1.6.0
- -- master || >1.4
- -- ~1.2.3
- -- ^1.1
- --
- local version = "latest"
- if #splitinfo > 1 then
- version = table.concat(table.slice(splitinfo, 2), " ")
- end
- assert(version, "require(\"%s\"): unknown version!", require_str)
-
- -- require third-party packages? e.g. brew::pcre2/libpcre2-8
- local reponame = nil
- local packagename = nil
- if require_str:find("::", 1, true) then
- packagename = packageinfo
- else
-
- -- get repository name, package name and package url
- local pos = packageinfo:lastof('@', true)
- if pos then
-
- -- get package name
- packagename = packageinfo:sub(pos + 1)
-
- -- get reponame
- reponame = packageinfo:sub(1, pos - 1)
- else
- packagename = packageinfo
- end
- end
-
- -- check package name
- assert(packagename, "require(\"%s\"): the package name not found!", require_str)
-
- -- get require extra
- local require_extra = {}
- if requires_extra then
- require_extra = requires_extra[require_str] or {}
- end
-
- -- get required building configurations
- local require_build_configs = require_extra.configs or require_extra.config
- if require_extra.debug then
- require_build_configs = require_build_configs or {}
- require_build_configs.debug = true
- end
-
- -- require packge in the current host platform
- if require_extra.host then
- require_extra.plat = os.host()
- require_extra.arch = os.arch()
- end
-
- -- init required item
- local required = {}
- parentinfo = parentinfo or {}
- required.packagename = packagename
- required.requireinfo =
- {
- originstr = require_str,
- reponame = reponame,
- version = version,
- plat = require_extra.plat, -- require package in the given platform
- arch = require_extra.arch, -- require package in the given architecture
- targetos = require_extra.targetos, -- require package in the given target os
- kind = require_extra.kind, -- default: library, set package kind, e.g. binary, library, we can set `kind = "binary"` to only detect binary program and ignore library.
- alias = require_extra.alias, -- set package alias name
- group = require_extra.group, -- only uses the first package in same group
- system = require_extra.system, -- default: true, we can set it to disable system package manually
- option = require_extra.option, -- set and attach option
- configs = require_build_configs, -- the required building configurations
- default = require_extra.default, -- default: true, we can set it to disable package manually
- optional = parentinfo.optional or require_extra.optional, -- default: false, inherit parentinfo.optional
- verify = require_extra.verify, -- default: true, we can set false to ignore sha256sum and select any version
- external = require_extra.external, -- default: true, we use sysincludedirs/-isystem instead of -I/xxx
- }
- return required.packagename, required.requireinfo
-end
-
--- load package package from system
-function _load_package_from_system(packagename)
- return core_package.load_from_system(packagename)
-end
-
--- load package package from project
-function _load_package_from_project(packagename)
- return core_package.load_from_project(packagename)
-end
-
--- load package package from repositories
-function _load_package_from_repository(packagename, reponame)
- local packagedir, repo = repository.packagedir(packagename, reponame)
- if packagedir then
- return core_package.load_from_repository(packagename, repo, packagedir)
- 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.
---
--- a.deps = b
--- b.deps = c
---
--- orderdeps: c -> b -> a
---
-function _sort_packagedeps(package)
- local orderdeps = {}
- for _, dep in pairs(package:deps()) do
- table.join2(orderdeps, _sort_packagedeps(dep))
- table.insert(orderdeps, dep)
- end
- return orderdeps
-end
-
--- add some builtin configurations to package
-function _add_package_configurations(package)
- local toolchains
- if package:is_plat("cross") and package:is_library() then
- -- we only can set toolchains to library package
- toolchains = project.get("target.toolchains") or get_config("toolchain")
- end
- local vs_runtime = project.get("target.runtimes") or get_config("vs_runtime") or "MT"
- package:add("configs", "debug", {builtin = true, description = "Enable debug symbols.", default = false, type = "boolean"})
- package:add("configs", "shared", {builtin = true, description = "Enable shared library.", default = false, type = "boolean"})
- package:add("configs", "cflags", {builtin = true, description = "Set the C compiler flags."})
- package:add("configs", "cxflags", {builtin = true, description = "Set the C/C++ compiler flags."})
- package:add("configs", "cxxflags", {builtin = true, description = "Set the C++ compiler flags."})
- package:add("configs", "asflags", {builtin = true, description = "Set the assembler flags."})
- package:add("configs", "pic", {builtin = true, description = "Enable the position independent code.", default = true, type = "boolean"})
- package:add("configs", "vs_runtime", {builtin = true, description = "Set vs compiler runtime.", default = vs_runtime, values = {"MT", "MTd", "MD", "MDd"}})
- package:add("configs", "toolchains", {builtin = true, description = "Set package toolchains only for cross-compilation.", default = toolchains})
-end
-
--- select package version
-function _select_package_version(package, requireinfo)
-
- -- exists urls? otherwise be phony package (only as package group)
- if #package:urls() > 0 then
-
- -- has git url?
- local has_giturl = false
- for _, url in ipairs(package:urls()) do
- if git.checkurl(url) then
- has_giturl = true
- break
- end
- end
-
- -- select package version
- local source = nil
- local version = nil
- local require_version = requireinfo.version
- local require_verify = requireinfo.verify
- if (not package:get("versions") or require_verify == false) and semver.is_valid(require_version) then
- -- no version list in package() or need not verify sha256sum? try selecting this version directly
- -- @see https://github.com/xmake-io/xmake/issues/930
- -- https://github.com/xmake-io/xmake/issues/1009
- version = require_version
- source = "versions"
- elseif #package:versions() > 0 and (require_version == "latest" or require_version:find('.', 1, true)) then -- select version?
- version, source = semver.select(require_version, package:versions())
- elseif has_giturl then -- select branch?
- version, source = require_version ~= "latest" and require_version or "master", "branches"
- else
- raise("package(%s %s): not found!", package:displayname(), require_version)
- end
- return version, source
- end
-end
-
--- check the configurations of packages
---
--- package("pcre2")
--- add_configs("bitwidth", {description = "Set the code unit width.", default = "8", values = {"8", "16", "32"}})
--- add_configs("bitwidth", {type = "number", values = {8, 16, 32}})
--- add_configs("bitwidth", {restrict = function(value) if tonumber(value) < 100 then return true end})
---
-function _check_package_configurations(package)
- local configs_defined = {}
- for _, name in ipairs(package:get("configs")) do
- configs_defined[name] = package:extraconf("configs", name) or {}
- end
- for name, value in pairs(package:configs()) do
- local conf = configs_defined[name]
- if conf then
- local config_type = conf.type
- if config_type ~= nil and type(value) ~= config_type then
- raise("package(%s %s): invalid type(%s) for config(%s), need type(%s)!", package:displayname(), package:version_str(), type(value), name, config_type)
- end
- if conf.values then
- local found = false
- for _, config_value in ipairs(conf.values) do
- if tostring(value) == tostring(config_value) then
- found = true
- break
- end
- end
- if not found then
- raise("package(%s %s): invalid value(%s) for config(%s), please run `xmake require --info %s` to get all valid values!", package:displayname(), package:version_str(), value, name, package:name())
- end
- end
- if conf.restrict then
- if not conf.restrict(value) then
- raise("package(%s %s): invalid value(%s) for config(%s)!", package:displayname(), package:version_str(), value, name)
- end
- end
- else
- raise("package(%s %s): invalid config(%s), please run `xmake require --info %s` to get all configurations!", package:displayname(), package:version_str(), name, package:name())
- end
- end
-end
-
--- match require path
-function _match_requirepath(requirepath, requireconf)
-
- -- get pattern
- local function _get_pattern(pattern)
- pattern = pattern:gsub("([%+%.%-%^%$%(%)%%])", "%%%1")
- pattern = pattern:gsub("%*%*", "\001")
- pattern = pattern:gsub("%*", "\002")
- pattern = pattern:gsub("\001", ".*")
- pattern = pattern:gsub("\002", "[^.]*")
- pattern = string.ipattern(pattern, true)
- return pattern
- end
-
- -- get the excludes
- local excludes = requireconf:match("|.*$")
- if excludes then excludes = excludes:split("|", {plain = true}) end
-
- -- do match
- local pattern = requireconf:gsub("|.*$", "")
- pattern = _get_pattern(pattern)
- if (requirepath:match('^' .. pattern .. '$')) then
- -- exclude sub-deps, e.g. "libwebp.**|cmake|autoconf"
- local splitinfo = requirepath:split(".", {plain = true})
- if #splitinfo > 0 then
- local name = splitinfo[#splitinfo]
- for _, exclude in ipairs(excludes) do
- pattern = _get_pattern(exclude)
- if (name:match('^' .. pattern .. '$')) then
- return false
- end
- end
- end
- return true
- end
-end
-
--- merge requireinfo from `add_requireconfs()`
---
--- add_requireconfs("*", {system = false, configs = {vs_runtime = "MD"}})
--- add_requireconfs("lib*", {system = false, configs = {vs_runtime = "MD"}})
--- add_requireconfs("libwebp", {system = false, configs = {vs_runtime = "MD"}})
--- add_requireconfs("libpng.zlib", {system = false, override = true, configs = {cxflags = "-DTEST1"}, version = "1.2.10"})
--- add_requireconfs("libtiff.*", {system = false, configs = {cxflags = "-DTEST2"}})
--- add_requireconfs("libwebp.**|cmake|autoconf", {system = false, configs = {cxflags = "-DTEST3"}}) -- recursive deps
---
-function _merge_requireinfo(requireinfo, requirepath)
-
- -- only for project
- if not os.isfile(os.projectfile()) then
- return
- end
-
- -- find requireconf from the given requirepath
- local requireconf_result = {}
- local requireconfs, requireconfs_extra = project.requireconfs_str()
- if requireconfs then
- for _, requireconf in ipairs(requireconfs) do
- if _match_requirepath(requirepath, requireconf) then
- local requireconf_extra = requireconfs_extra[requireconf]
- table.insert(requireconf_result, {requireconf = requireconf, requireconf_extra = requireconf_extra})
- end
- end
- end
-
- -- append requireconf_extra into requireinfo
- -- and the configs of add_requires have a higher priority than add_requireconfs.
- --
- -- e.g.
- -- add_requireconfs("*", {configs = {debug = false}})
- -- add_requires("foo", "bar", {configs = {debug = true}})
- --
- -- foo and bar will be debug mode
- --
- -- we can also override the configs of add_requires
- --
- -- e.g.
- -- add_requires("zlib 1.2.11")
- -- add_requireconfs("zlib", {override = true, version = "1.2.10"})
- --
- -- we override the version of zlib to 1.2.10
- --
- if #requireconf_result == 1 then
- local requireconf_extra = requireconf_result[1].requireconf_extra
- if requireconf_extra then
- -- preprocess requireconf_extra, (debug, override ..)
- local override = requireconf_extra.override
- requireconf_extra.override = nil
- if requireconf_extra.debug then
- requireconf_extra.configs = requireconf_extra.configs or {}
- requireconf_extra.configs.debug = true
- requireconf_extra.debug = nil
- end
- -- append or override configs and extra options
- for k, v in pairs(requireconf_extra.configs) do
- requireinfo.configs = requireinfo.configs or {}
- if override or requireinfo.configs[k] == nil then
- requireinfo.configs[k] = v
- end
- end
- for k, v in pairs(requireconf_extra) do
- if k ~= "configs" then
- if override or requireinfo[k] == nil then
- requireinfo[k] = v
- end
- end
- end
- end
- elseif #requireconf_result > 1 then
- local confs = {}
- for _, item in ipairs(requireconf_result) do
- table.insert(confs, item.requireconf)
- end
- raise("package(%s) will match multiple add_requireconfs(%s)!", requirepath, table.concat(confs, " "))
- end
-end
-
--- get package key
-function _get_packagekey(packagename, requireinfo, version)
- local key = packagename .. "/" .. (version or requireinfo.version)
- local configs = requireinfo.configs
- if configs then
- local configs_order = {}
- for k, v in pairs(configs) do
- table.insert(configs_order, k .. "=" .. tostring(v))
- end
- table.sort(configs_order)
- key = key .. ":" .. string.serialize(configs_order, true)
- end
- return key
-end
-
--- inherit some builtin configs of parent package if these config values are not default value
--- e.g. add_requires("libpng", {configs = {vs_runtime = "MD", pic = false}})
---
-function _inherit_parent_configs(requireinfo, parentinfo)
- local requireinfo_configs = requireinfo.configs or {}
- local parentinfo_configs = parentinfo.configs or {}
- if not requireinfo_configs.shared then
- if requireinfo_configs.vs_runtime == nil then
- requireinfo_configs.vs_runtime = parentinfo_configs.vs_runtime
- end
- if requireinfo_configs.pic == nil then
- requireinfo_configs.pic = parentinfo_configs.pic
- end
- end
- requireinfo.configs = requireinfo_configs
-end
-
--- load required packages
-function _load_package(packagename, requireinfo, opt)
-
- -- strip trailng ~tag, e.g. zlib~debug
- local displayname
- if packagename:find('~', 1, true) then
- displayname = packagename
- packagename = packagename:gsub("~.+$", "")
- requireinfo.alias = requireinfo.alias or displayname
- end
-
- -- load package from project first
- local package
- if os.isfile(os.projectfile()) then
- package = _load_package_from_project(packagename)
- end
-
- -- load package from repositories
- if not package then
- package = _load_package_from_repository(packagename, requireinfo.reponame)
- end
-
- -- load package from system
- if not package and opt.system ~= false then
- package = _load_package_from_system(packagename)
- end
-
- -- check
- assert(package, "package(%s) not found!", packagename)
-
- -- merge requireinfo from `add_requireconfs()`
- _merge_requireinfo(requireinfo, opt.requirepath)
-
- -- inherit some builtin configs of parent package, e.g. vs_runtime, pic
- if opt.parentinfo and package:is_library() then
- _inherit_parent_configs(requireinfo, opt.parentinfo)
- end
-
- -- select package version
- local version, source = _select_package_version(package, requireinfo)
- if version then
- package:version_set(version, source)
- end
-
- -- get package key
- local packagekey = _get_packagekey(packagename, requireinfo, version)
-
- -- It exists conflict for dependent packages for each root packages? resolve it first
- -- e.g.
- -- add_requires("foo") -> bar -> zlib 1.2.10
- -- -> xyz -> zlib 1.2.11 or other configs
- --
- -- add_requires("ddd") -> zlib
- --
- -- We assume that there is no conflict between `foo` and `ddd`.
- --
- -- Of course, conflicts caused by `add_packages("foo", "ddd")`
- -- cannot be detected at present and can only be resolved by the user
- --
- local rootkey = opt.rootkey
- local packagekey_prev = _memcache():get3("packages_root", rootkey, packagename)
- if packagekey_prev then
- if packagekey_prev and packagekey_prev ~= packagekey then
- raise("package(%s): conflict dependences with package(%s)!", packagekey, packagekey_prev)
- end
- end
- _memcache():set3("packages_root", rootkey, packagename, packagekey)
-
- -- get package from cache first
- local package_cached = _memcache():get2("packages", packagekey)
- if package_cached then
- return package_cached
- end
-
- -- save require info
- package:requireinfo_set(requireinfo)
-
- -- save display name
- if not displayname then
- local packageid = _memcache():get2("packageids", packagename)
- displayname = packagename
- if packageid then
- displayname = displayname .. "#" .. tostring(packageid)
- end
- _memcache():set2("packageids", packagename, (packageid or 0) + 1)
- end
- package:displayname_set(displayname)
-
- -- disable parallelize if the package cache directory conflicts
- local cachedirs = _memcache():get2("cachedirs", package:cachedir())
- if cachedirs then
- package:set("parallelize", false)
- end
- _memcache():set2("cachedirs", package:cachedir(), true)
-
- -- disable parallelize if this package is toolchain? we need install toolchain package first
- if package:is_toolchain() then
- package:set("parallelize", false)
- end
-
- -- add some builtin configurations to package
- _add_package_configurations(package)
-
- -- check package configurations
- _check_package_configurations(package)
-
- -- do load
- local on_load = package:script("load")
- if on_load then
- on_load(package)
- end
-
- -- load environments from the manifest to enable the environments of on_install()
- package:envs_load()
-
- -- save this package package to cache
- _memcache():set2("packages", packagekey, package)
- return package
-end
-
--- load all required packages
-function _load_packages(requires, opt)
-
- -- no requires?
- if not requires or #requires == 0 then
- return {}
- end
-
- -- load packages
- local packages = {}
- for _, requireitem in ipairs(load_requires(requires, opt.requires_extra, opt)) do
-
- -- load package
- local rootkey = opt.rootkey or requireitem.name
- local requireinfo = requireitem.info
- local requirepath = opt.requirepath and (opt.requirepath .. "." .. requireitem.name) or requireitem.name
- local package = _load_package(requireitem.name, requireinfo, table.join(opt, {rootkey = rootkey, requirepath = requirepath}))
-
- -- maybe package not found and optional
- if package then
-
- -- load dependent packages and save them first of this package
- if not package._DEPS then
- local deps = package:get("deps")
- if deps and opt.nodeps ~= true then
-
- -- load dependent packages and do not load system/3rd packages for package/deps()
- local packagedeps = {}
- for _, dep in ipairs(_load_packages(deps, {rootkey = rootkey,
- requirepath = requirepath,
- requires_extra = package:extraconf("deps") or {},
- parentinfo = requireinfo,
- nodeps = opt.nodeps,
- system = false})) do
- dep:parents_add(package)
- table.insert(packages, dep)
- packagedeps[dep:name()] = dep
- end
- package._DEPS = packagedeps
- package._ORDERDEPS = table.unique(_sort_packagedeps(package))
- end
- end
-
- -- save this package
- -- @note if this root package is toolchain, we need to move it to the beginning in order to install first
- if not opt.parentinfo and package:is_toolchain() then
- table.insert(packages, 1, package)
- else
- table.insert(packages, package)
- end
- end
- end
- 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")
-end
-
--- load requires
-function load_requires(requires, requires_extra, opt)
- opt = opt or {}
- local requireitems = {}
- for _, require_str in ipairs(requires) do
- local packagename, requireinfo = _parse_require(require_str, requires_extra, opt.parentinfo)
- table.insert(requireitems, {name = packagename, info = requireinfo})
- end
- return requireitems
-end
-
--- load all required packages
-function load_packages(requires, opt)
- opt = opt or {}
- local unique = {}
- local packages = {}
- for _, package in ipairs(_load_packages(requires, opt)) do
- local key = _get_packagekey(package:name(), package:requireinfo())
- if not unique[key] then
- table.insert(packages, package)
- unique[key] = true
- end
- end
- 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/actions/require/impl/repository.lua b/xmake/actions/require/impl/repository.lua
deleted file mode 100644
index 6fc72d49c..000000000
--- a/xmake/actions/require/impl/repository.lua
+++ /dev/null
@@ -1,113 +0,0 @@
---!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 repository.lua
---
-
--- imports
-import("core.package.repository")
-
--- get all repositories
-function repositories()
-
- -- get it from cache it
- if _g._REPOSITORIES then
- return _g._REPOSITORIES
- end
-
- -- get all repositories (local first)
- local repos = table.join(repository.repositories(false), repository.repositories(true))
-
- -- save repositories
- _g._REPOSITORIES = repos
-
- -- ok
- return repos
-end
-
--- the remote repositories have been pulled?
-function pulled()
- for _, repo in ipairs(repositories()) do
- -- repository not found? or xmake has been re-installed
- local updatefile = path.join(repo:directory(), "updated")
- if not os.isdir(repo:directory()) or (os.isfile(updatefile) and os.mtime(os.programfile()) > os.mtime(updatefile)) then
- return false
- end
- end
- return true
-end
-
--- get package directory from repositories
-function packagedir(packagename, reponame)
-
- -- strip trailng ~tag, e.g. zlib~debug
- if packagename:find('~', 1, true) then
- packagename = packagename:gsub("~.+$", "")
- end
-
- -- get it from cache it
- local packagedirs = _g._PACKAGEDIRS or {}
- local foundir = packagedirs[packagename]
- if foundir then
- return foundir[1], foundir[2]
- end
-
- -- find the package directory from repositories
- for _, repo in ipairs(repositories()) do
- local dir = path.join(repo:directory(), "packages", packagename:sub(1, 1):lower(), packagename)
- if os.isdir(dir) and (not reponame or reponame == repo:name()) then
- foundir = {dir, repo}
- break
- end
- end
-
- -- found?
- if foundir then
-
- -- save package directory
- packagedirs[packagename] = foundir
-
- -- update cache
- _g._PACKAGEDIRS = packagedirs
-
- -- ok
- return foundir[1], foundir[2]
- end
-end
-
--- search package directories from repositories
-function searchdirs(name)
-
- -- find the package directories from all repositories
- local unique = {}
- local packageinfos = {}
- for _, repo in ipairs(repositories()) do
- for _, file in ipairs(os.files(path.join(repo:directory(), "packages", "*", string.ipattern("*" .. name .. "*"), "xmake.lua"))) do
- local dir = path.directory(file)
- local subdirname = path.basename(path.directory(dir))
- if #subdirname == 1 then -- ignore l/luajit/port/xmake.lua
- local packagename = path.basename(dir)
- if not unique[packagename] then
- table.insert(packageinfos, {name = packagename, repo = repo, packagedir = path.directory(file)})
- unique[packagename] = true
- end
- end
- end
- end
- return packageinfos
-end
-
diff --git a/xmake/actions/require/impl/utils/filter.lua b/xmake/actions/require/impl/utils/filter.lua
deleted file mode 100644
index 11bdf70de..000000000
--- a/xmake/actions/require/impl/utils/filter.lua
+++ /dev/null
@@ -1,146 +0,0 @@
---!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 filter.lua
---
-
--- imports
-import("core.base.filter")
-import("core.base.option")
-import("core.base.global")
-import("core.project.config")
-import("core.project.project")
-import("core.sandbox.sandbox")
-
--- get filter
-function _filter()
-
- -- init filter
- if _g.filter == nil then
- _g.filter = filter.new()
- _g.filter:register("common", function (variable)
-
- -- attempt to get it directly from the configure
- local result = config.get(variable)
- if result == nil then
-
- -- init maps
- _g.common_maps = _g.common_maps or
- {
- host = os.host()
- , subhost = os.subhost()
- , tmpdir = function () return os.tmpdir() end
- , curdir = function () return os.curdir() end
- , scriptdir = function () return os.scriptdir() end
- , globaldir = global.directory()
- , configdir = config.directory()
- , projectdir = project.directory()
- , programdir = os.programdir()
- }
-
- -- map it
- result = _g.common_maps[variable]
- end
-
- -- is script? call it
- if type(result) == "function" then
- result = result()
- end
-
- -- ok?
- return result
- end)
- end
-
- -- ok
- return _g.filter
-end
-
--- the package handler
-function _handler(package, strval)
-
- -- @note cannot cache it, because the package instance will be changed
- return function (variable)
-
- -- init maps
- local maps =
- {
- version = function ()
- if strval then
- -- set_urls("https://sqlite.org/2018/sqlite-autoconf-$(version)000.tar.gz",
- -- {version = function (version) return version:gsub("%.", "") end})
- local version_filter = package:url_version(strval)
- if version_filter then
- local v = version_filter(package:version())
- if v ~= nil then
- -- may be semver version object
- v = tostring(v)
- end
- return v
- end
- end
- return package:version_str()
- end
- }
-
- -- get value
- local result = maps[variable]
- if type(result) == "function" then
- result = result()
- end
-
- -- ok?
- return result
- end
-end
-
--- attach filter to the given script and call it
-function call(script, package)
-
- -- get sandbox filter and handlers of the given script
- local sandbox_filter = sandbox.filter(script)
- local sandbox_handlers = sandbox_filter:handlers()
-
- -- switch to the handlers of the current filter
- sandbox_filter:set_handlers(_filter():handlers())
-
- -- register package handler
- sandbox_filter:register("package", _handler(package))
-
- -- call it
- script(package)
-
- -- restore handlers
- sandbox_filter:set_handlers(sandbox_handlers)
-end
-
--- handle the string value of package
-function handle(strval, package)
-
- -- register filter handler
- _filter():register("package", _handler(package, strval))
-
- -- handle string value
- strval = _filter():handle(strval)
-
- -- register filter handler
- _filter():register("package", nil)
-
- -- ok
- return strval
-end
-
diff --git a/xmake/actions/require/impl/utils/get_requires.lua b/xmake/actions/require/impl/utils/get_requires.lua
deleted file mode 100644
index 9a0ad76c1..000000000
--- a/xmake/actions/require/impl/utils/get_requires.lua
+++ /dev/null
@@ -1,57 +0,0 @@
---!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 get_requires.lua
---
-
--- imports
-import("core.base.option")
-import("core.project.project")
-
--- get requires and extra config
-function main(requires)
-
- -- init requires
- local requires_extra = nil
- if not requires then
- requires, requires_extra = project.requires_str()
- end
- if not requires or #requires == 0 then
- return
- end
-
- -- get extra info
- local extra = option.get("extra")
- local extrainfo = nil
- if extra then
- local v, err = string.deserialize(extra)
- if err then
- raise(err)
- else
- extrainfo = v
- end
- end
-
- -- force to use the given requires extra info
- if extrainfo then
- requires_extra = requires_extra or {}
- for _, require_str in ipairs(requires) do
- requires_extra[require_str] = extrainfo
- end
- end
- return requires, requires_extra
-end
diff --git a/xmake/actions/require/impl/utils/url_filename.lua b/xmake/actions/require/impl/utils/url_filename.lua
deleted file mode 100644
index e17e8673b..000000000
--- a/xmake/actions/require/impl/utils/url_filename.lua
+++ /dev/null
@@ -1,25 +0,0 @@
---!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 url_filename.lua
---
-
--- get filename from url
-function main(url)
- local urlpath = url:split('?', {plain = true})[1]
- return path.filename(urlpath)
-end