summaryrefslogtreecommitdiff
path: root/love2dToAPK/tools/tools/zbstudio-win/lualibs/dist
diff options
context:
space:
mode:
authorJakob Stendahl <jakob.stendahl@outlook.com>2018-01-09 15:01:04 +0100
committerJakob Stendahl <jakob.stendahl@outlook.com>2018-01-09 15:01:04 +0100
commitbb6e704ab011a497ac8c735afc0fd4c52a1425ce (patch)
treebed462d18c4f976f30c690b529d6de8b2a6ba2ff /love2dToAPK/tools/tools/zbstudio-win/lualibs/dist
parentd2c375c015fe3e216234a887ab75e08d40f5f5db (diff)
downloadLove2dToAPK-bb6e704ab011a497ac8c735afc0fd4c52a1425ce.tar.gz
Love2dToAPK-bb6e704ab011a497ac8c735afc0fd4c52a1425ce.zip
Added old project
Diffstat (limited to 'love2dToAPK/tools/tools/zbstudio-win/lualibs/dist')
-rw-r--r--love2dToAPK/tools/tools/zbstudio-win/lualibs/dist/config.lua112
-rw-r--r--love2dToAPK/tools/tools/zbstudio-win/lualibs/dist/constraints.lua271
-rw-r--r--love2dToAPK/tools/tools/zbstudio-win/lualibs/dist/depends.lua770
-rw-r--r--love2dToAPK/tools/tools/zbstudio-win/lualibs/dist/git.lua306
-rw-r--r--love2dToAPK/tools/tools/zbstudio-win/lualibs/dist/init.lua349
-rw-r--r--love2dToAPK/tools/tools/zbstudio-win/lualibs/dist/logger.lua64
-rw-r--r--love2dToAPK/tools/tools/zbstudio-win/lualibs/dist/manifest.lua248
-rw-r--r--love2dToAPK/tools/tools/zbstudio-win/lualibs/dist/package.lua596
-rw-r--r--love2dToAPK/tools/tools/zbstudio-win/lualibs/dist/sys.lua386
-rw-r--r--love2dToAPK/tools/tools/zbstudio-win/lualibs/dist/utils.lua151
10 files changed, 3253 insertions, 0 deletions
diff --git a/love2dToAPK/tools/tools/zbstudio-win/lualibs/dist/config.lua b/love2dToAPK/tools/tools/zbstudio-win/lualibs/dist/config.lua
new file mode 100644
index 0000000..3139750
--- /dev/null
+++ b/love2dToAPK/tools/tools/zbstudio-win/lualibs/dist/config.lua
@@ -0,0 +1,112 @@
+-- Luadist configuration
+
+module ("dist.config", package.seeall)
+
+local sys = require "dist.sys"
+local utils = require "dist.utils"
+local win = (os.getenv('WINDIR') or (os.getenv('OS') or ''):match('[Ww]indows'))
+ and not (os.getenv('OSTYPE') or ''):match('cygwin') -- exclude cygwin
+
+-- System information ------------------------------------------------
+version = "0.2.7" -- Current LuaDist version
+-- set initial architecture as it's important for path separators
+arch = win and "Windows" or "Linux" -- Host architecture
+type = "x86" -- Host type
+
+-- Directories -------------------------------------------------------
+root_dir = os.getenv("DIST_ROOT") or utils.get_luadist_location() or sys.path_separator()
+temp_dir = "tmp"
+cache_dir = sys.make_path(temp_dir, "cache")
+distinfos_dir = sys.make_path("share", "luadist-git", "dists")
+test_dir = sys.make_path("share", "luadist-git", "test")
+
+-- Files -------------------------------------------------------------
+manifest_file = sys.make_path(cache_dir, ".gitmodules")
+dep_cache_file = sys.make_path(cache_dir, ".depcache")
+log_file = sys.make_path(temp_dir, "luadist.log")
+cache_file = ""
+
+-- Repositories ------------------------------------------------------
+repos = {
+ "git://github.com/LuaDist/Repository.git",
+}
+
+upload_url = "git@github.com:LuaDist" -- must not contain trailing '/'
+
+-- Settings ----------------------------------------------------------
+debug = false -- Use debug mode.
+verbose = false -- Print verbose output.
+simulate = false -- Only simulate installation of packages.
+binary = true -- Use binary version of modules.
+source = true -- Use source version of modules.
+test = false -- Run CTest before install.
+
+cache = true -- Use cache.
+cache_timeout = 3 * 60 * 60 -- Cache timeout in seconds.
+
+dep_cache = true -- Use cache for dependency information (tree functionality).
+
+-- Components (of modules) that will be installed.
+components = {
+ "Runtime", "Library", "Header", "Data", "Documentation", "Example", "Test", "Other", "Unspecified"
+}
+
+-- Available log levels are: DEBUG, INFO, WARN, ERROR, FATAL (see dist.logger for more information).
+print_log_level = "WARN" -- Minimum level for log messages to be printed (nil to disable).
+write_log_level = "INFO" -- Minimum level for log messages to be logged (nil to disable).
+
+
+-- CMake variables ---------------------------------------------------
+variables = {
+ --- Install defaults
+ INSTALL_BIN = "bin",
+ INSTALL_LIB = "lib",
+ INSTALL_INC = "include",
+ INSTALL_ETC = "etc",
+ INSTALL_LMOD = "lib/lua",
+ INSTALL_CMOD = "lib/lua",
+
+ --- LuaDist specific variables
+ DIST_VERSION = version,
+ DIST_ARCH = arch,
+ DIST_TYPE = type,
+
+ -- CMake specific setup
+ CMAKE_GENERATOR = win and "MinGW Makefiles" or "Unix Makefiles",
+ CMAKE_BUILD_TYPE = "MinSizeRel",
+
+ -- RPath functionality
+ CMAKE_SKIP_BUILD_RPATH = "FALSE",
+ CMAKE_BUILD_WITH_INSTALL_RPATH = "FALSE",
+ CMAKE_INSTALL_RPATH = "$ORIGIN/../lib",
+ CMAKE_INSTALL_RPATH_USE_LINK_PATH = "TRUE",
+ CMAKE_INSTALL_NAME_DIR = "@executable_path/../lib",
+
+ -- OSX specific
+ CMAKE_OSX_ARCHITECTURES = "",
+}
+
+-- Building ----------------------------------------------------------
+cmake = "cmake"
+ctest = "ctest"
+
+cache_command = cmake .. " -C cache.cmake"
+build_command = cmake .. " --build . --clean-first"
+
+install_component_command = " -DCOMPONENT=#COMPONENT# -P cmake_install.cmake"
+
+test_command = ctest .. " -V ."
+
+strip_option = " -DCMAKE_INSTALL_DO_STRIP=true"
+cache_debug_options = "-DCMAKE_VERBOSE_MAKEFILE=true -DCMAKE_BUILD_TYPE=Debug"
+build_debug_options = ""
+
+-- Add -j option to make in case of unix makefiles to speed up builds
+if (variables.CMAKE_GENERATOR == "Unix Makefiles") then
+ build_command = build_command .. " -- -j6"
+end
+
+-- Add -j option to make in case of MinGW makefiles to speed up builds
+if (variables.CMAKE_GENERATOR == "MinGW Makefiles") then
+ build_command = "set SHELL=cmd.exe && " .. build_command .. " -- -j"
+end
diff --git a/love2dToAPK/tools/tools/zbstudio-win/lualibs/dist/constraints.lua b/love2dToAPK/tools/tools/zbstudio-win/lualibs/dist/constraints.lua
new file mode 100644
index 0000000..1b5cfec
--- /dev/null
+++ b/love2dToAPK/tools/tools/zbstudio-win/lualibs/dist/constraints.lua
@@ -0,0 +1,271 @@
+-- Note: the code of this module is borrowed from the original LuaDist project
+
+
+
+--- LuaDist version constraints functions
+-- Peter Drahoš, LuaDist Project, 2010
+-- Original Code borrowed from LuaRocks Project
+
+--- Version constraints handling functions.
+-- Dependencies are represented in LuaDist through strings with
+-- a dist name followed by a comma-separated list of constraints.
+-- Each constraint consists of an operator and a version number.
+-- In this string format, version numbers are represented as
+-- naturally as possible, like they are used by upstream projects
+-- (e.g. "2.0beta3"). Internally, LuaDist converts them to a purely
+-- numeric representation, allowing comparison following some
+-- "common sense" heuristics. The precise specification of the
+-- comparison criteria is the source code of this module, but the
+-- test/test_deps.lua file included with LuaDist provides some
+-- insights on what these criteria are.
+
+module ("dist.constraints", package.seeall)
+
+
+local operators = {
+ ["=="] = "==",
+ ["~="] = "~=",
+ [">"] = ">",
+ ["<"] = "<",
+ [">="] = ">=",
+ ["<="] = "<=",
+ ["~>"] = "~>",
+ -- plus some convenience translations
+ [""] = "==",
+ ["-"] = "==",
+ ["="] = "==",
+ ["!="] = "~="
+}
+
+local deltas = {
+ scm = -100,
+ rc = -1000,
+ pre = -10000,
+ beta = -100000,
+ alpha = -1000000,
+ work = -10000000,
+}
+
+local version_mt = {
+ --- Equality comparison for versions.
+ -- All version numbers must be equal.
+ -- If both versions have revision numbers, they must be equal;
+ -- otherwise the revision number is ignored.
+ -- @param v1 table: version table to compare.
+ -- @param v2 table: version table to compare.
+ -- @return boolean: true if they are considered equivalent.
+ __eq = function(v1, v2)
+ if #v1 ~= #v2 then
+ return false
+ end
+ for i = 1, #v1 do
+ if v1[i] ~= v2[i] then
+ return false
+ end
+ end
+ if v1.revision and v2.revision then
+ return (v1.revision == v2.revision)
+ end
+ return true
+ end,
+ --- Size comparison for versions.
+ -- All version numbers are compared.
+ -- If both versions have revision numbers, they are compared;
+ -- otherwise the revision number is ignored.
+ -- @param v1 table: version table to compare.
+ -- @param v2 table: version table to compare.
+ -- @return boolean: true if v1 is considered lower than v2.
+ __lt = function(v1, v2)
+ for i = 1, math.max(#v1, #v2) do
+ local v1i, v2i = v1[i] or 0, v2[i] or 0
+ if v1i ~= v2i then
+ return (v1i < v2i)
+ end
+ end
+ if v1.revision and v2.revision then
+ return (v1.revision < v2.revision)
+ end
+ return false
+ end
+}
+
+local version_cache = {}
+setmetatable(version_cache, {
+ __mode = "kv"
+})
+
+--- Parse a version string, converting to table format.
+-- A version table contains all components of the version string
+-- converted to numeric format, stored in the array part of the table.
+-- If the version contains a revision, it is stored numerically
+-- in the 'revision' field. The original string representation of
+-- the string is preserved in the 'string' field.
+-- Returned version tables use a metatable
+-- allowing later comparison through relational operators.
+-- @param vstring string: A version number in string format.
+-- @return table or nil: A version table or nil
+-- if the input string contains invalid characters.
+function parseVersion(vstring)
+ if not vstring then return nil end
+ assert(type(vstring) == "string")
+
+ local cached = version_cache[vstring]
+ if cached then
+ return cached
+ end
+
+ local version = {}
+ local i = 1
+
+ local function add_token(number)
+ version[i] = version[i] and version[i] + number/100000 or number
+ i = i + 1
+ end
+
+ -- trim leading and trailing spaces
+ vstring = vstring:match("^%s*(.*)%s*$")
+ version.string = vstring
+ -- store revision separately if any
+ local main, revision = vstring:match("(.*)%-(%d+)$")
+ if revision then
+ vstring = main
+ version.revision = tonumber(revision)
+ end
+ while #vstring > 0 do
+ -- extract a number
+ local token, rest = vstring:match("^(%d+)[%.%-%_]*(.*)")
+ if token then
+ add_token(tonumber(token))
+ else
+ -- extract a word
+ token, rest = vstring:match("^(%a+)[%.%-%_]*(.*)")
+ if not token then
+ return nil
+ end
+ local last = #version
+ version[i] = deltas[token] or (token:byte() / 1000)
+ end
+ vstring = rest
+ end
+ setmetatable(version, version_mt)
+ version_cache[vstring] = version
+ return version
+end
+
+--- Utility function to compare version numbers given as strings.
+-- @param a string: one version.
+-- @param b string: another version.
+-- @return boolean: True if a > b.
+function compareVersions(a, b)
+ return parseVersion(a) > parseVersion(b)
+end
+
+--- Consumes a constraint from a string, converting it to table format.
+-- For example, a string ">= 1.0, > 2.0" is converted to a table in the
+-- format {op = ">=", version={1,0}} and the rest, "> 2.0", is returned
+-- back to the caller.
+-- @param input string: A list of constraints in string format.
+-- @return (table, string) or nil: A table representing the same
+-- constraints and the string with the unused input, or nil if the
+-- input string is invalid.
+local function parseConstraint(input)
+ assert(type(input) == "string")
+
+ local op, version, rest = input:match("^([<>=~!]*)%s*([%w%.%_%-]+)[%s,]*(.*)")
+ op = operators[op]
+ version = parseVersion(version)
+ if not op or not version then return nil end
+ return { op = op, version = version }, rest
+end
+
+--- Convert a list of constraints from string to table format.
+-- For example, a string ">= 1.0, < 2.0" is converted to a table in the format
+-- {{op = ">=", version={1,0}}, {op = "<", version={2,0}}}.
+-- Version tables use a metatable allowing later comparison through
+-- relational operators.
+-- @param input string: A list of constraints in string format.
+-- @return table or nil: A table representing the same constraints,
+-- or nil if the input string is invalid.
+function parseConstraints(input)
+ assert(type(input) == "string")
+
+ local constraints, constraint = {}, nil
+ while #input > 0 do
+ constraint, input = parseConstraint(input)
+ if constraint then
+ table.insert(constraints, constraint)
+ else
+ return nil
+ end
+ end
+ return constraints
+end
+
+--- A more lenient check for equivalence between versions.
+-- This returns true if the requested components of a version
+-- match and ignore the ones that were not given. For example,
+-- when requesting "2", then "2", "2.1", "2.3.5-9"... all match.
+-- When requesting "2.1", then "2.1", "2.1.3" match, but "2.2"
+-- doesn't.
+-- @param version string or table: Version to be tested; may be
+-- in string format or already parsed into a table.
+-- @param requested string or table: Version requested; may be
+-- in string format or already parsed into a table.
+-- @return boolean: True if the tested version matches the requested
+-- version, false otherwise.
+local function partialMatch(version, requested)
+ assert(type(version) == "string" or type(version) == "table")
+ assert(type(requested) == "string" or type(version) == "table")
+
+ if type(version) ~= "table" then version = parseVersion(version) end
+ if type(requested) ~= "table" then requested = parseVersion(requested) end
+ if not version or not requested then return false end
+
+ for i = 1, #requested do
+ if requested[i] ~= version[i] then return false end
+ end
+ if requested.revision then
+ return requested.revision == version.revision
+ end
+ return true
+end
+
+--- Check if a version satisfies a set of constraints.
+-- @param version table: A version in table format
+-- @param constraints table: An array of constraints in table format.
+-- @return boolean: True if version satisfies all constraints,
+-- false otherwise.
+function matchConstraints(version, constraints)
+ assert(type(version) == "table")
+ assert(type(constraints) == "table")
+ local ok = true
+ setmetatable(version, version_mt)
+ for _, constr in pairs(constraints) do
+ local constr_version = constr.version
+ setmetatable(constr.version, version_mt)
+ if constr.op == "==" then ok = version == constr_version
+ elseif constr.op == "~=" then ok = version ~= constr_version
+ elseif constr.op == ">" then ok = version > constr_version
+ elseif constr.op == "<" then ok = version < constr_version
+ elseif constr.op == ">=" then ok = version >= constr_version
+ elseif constr.op == "<=" then ok = version <= constr_version
+ elseif constr.op == "~>" then ok = partialMatch(version, constr_version)
+ end
+ if not ok then break end
+ end
+ return ok
+end
+
+--- Check if a version string is satisfied by a constraint string.
+-- @param version string: A version in string format
+-- @param constraints string: Constraints in string format.
+-- @return boolean: True if version satisfies all constraints,
+-- false otherwise.
+function constraint_satisfied(version, constraints)
+ local const = parseConstraints(constraints)
+ local ver = parseVersion(version)
+ if const and ver then
+ return matchConstraints(ver, const)
+ end
+ return nil, "Error parsing versions."
+end
diff --git a/love2dToAPK/tools/tools/zbstudio-win/lualibs/dist/depends.lua b/love2dToAPK/tools/tools/zbstudio-win/lualibs/dist/depends.lua
new file mode 100644
index 0000000..2a6b7f0
--- /dev/null
+++ b/love2dToAPK/tools/tools/zbstudio-win/lualibs/dist/depends.lua
@@ -0,0 +1,770 @@
+-- Utility functions for dependencies
+
+module ("dist.depends", package.seeall)
+
+local cfg = require "dist.config"
+local mf = require "dist.manifest"
+local sys = require "dist.sys"
+local const = require "dist.constraints"
+local utils = require "dist.utils"
+local package = require "dist.package"
+
+-- Return all packages with specified names from manifest.
+-- Names can also contain version constraint (e.g. 'copas>=1.2.3', 'saci-1.0' etc.).
+function find_packages(package_names, manifest)
+ if type(package_names) == "string" then package_names = {package_names} end
+ manifest = manifest or mf.get_manifest()
+ assert(type(package_names) == "table", "depends.find_packages: Argument 'package_names' is not a table or string.")
+ assert(type(manifest) == "table", "depends.find_packages: Argument 'manifest' is not a table.")
+
+ local packages_found = {}
+ -- find matching packages in manifest
+ for _, pkg_to_find in pairs(package_names) do
+ local pkg_name, pkg_constraint = split_name_constraint(pkg_to_find)
+ pkg_name = utils.escape_magic(pkg_name):gsub("%%%*",".*")
+ for _, repo_pkg in pairs(manifest) do
+ if string.match(repo_pkg.name, "^" .. pkg_name .. "$") and (not pkg_constraint or satisfies_constraint(repo_pkg.version, pkg_constraint)) then
+ table.insert(packages_found, repo_pkg)
+ end
+ end
+ end
+ return packages_found
+end
+
+-- Return manifest consisting of packages installed in specified deploy_dir directory
+function get_installed(deploy_dir)
+ deploy_dir = deploy_dir or cfg.root_dir
+ assert(type(deploy_dir) == "string", "depends.get_installed: Argument 'deploy_dir' is not a string.")
+ deploy_dir = sys.abs_path(deploy_dir)
+
+ local distinfos_path = sys.make_path(deploy_dir, cfg.distinfos_dir)
+ local manifest = {}
+
+ if not sys.is_dir(distinfos_path) then return {} end
+
+ -- from all directories of packages installed in deploy_dir
+ for dir in sys.get_directory(distinfos_path) do
+
+ if dir ~= "." and dir ~= ".." and sys.is_dir(sys.make_path(distinfos_path, dir)) then
+ local pkg_dist_dir = sys.make_path(distinfos_path, dir)
+
+ -- load the dist.info file
+ for file in sys.get_directory(pkg_dist_dir) do
+ local pkg_dist_file = sys.make_path(pkg_dist_dir, file)
+
+ if sys.is_file(pkg_dist_file) then
+ table.insert(manifest, mf.load_distinfo(pkg_dist_file))
+ end
+ end
+
+ end
+
+ end
+ return manifest
+end
+
+-- If 'pkg.selected' == true then returns 'selected' else 'installed'.
+-- Used in error messages.
+local function selected_or_installed(pkg)
+ assert(type(pkg) == "table", "depends.selected_or_installed: Argument 'pkg' is not a table.")
+ if pkg.selected == true then
+ return "selected"
+ else
+ return "installed"
+ end
+end
+
+-- Return whether the 'package_name' is installed according to the the manifest 'installed_pkgs'
+-- If optional 'version_wanted' constraint is specified, then installed packages must
+-- also satisfy specified version constraint.
+-- If package is installed but doesn't satisfy version constraint, error message
+-- is returned as the second value.
+function is_installed(package_name, installed_pkgs, version_wanted)
+ assert(type(package_name) == "string", "depends.is_installed: Argument 'package_name' is not a string.")
+ assert(type(installed_pkgs) == "table", "depends.is_installed: Argument 'installed_pkgs' is not a table.")
+ assert(type(version_wanted) == "string" or type(version_wanted) == "nil", "depends.is_installed: Argument 'version_wanted' is not a string or nil.")
+
+ local pkg_is_installed, err = false, nil
+
+ for _, installed_pkg in pairs(installed_pkgs) do
+
+ -- check if package_name is in installed
+ if package_name == installed_pkg.name then
+
+ -- check if package is installed in satisfying version
+ if not version_wanted or satisfies_constraint(installed_pkg.version, version_wanted) then
+ pkg_is_installed = true
+ break
+ else
+ err = "Package '" .. package_name .. (version_wanted and " " .. version_wanted or "") .. "' needed, but " .. selected_or_installed(installed_pkg) .. " at version '" .. installed_pkg.version .. "'."
+ break
+ end
+ end
+
+ end
+ return pkg_is_installed, err
+end
+
+-- Check whether the package 'pkg' conflicts with 'installed_pkg' and return
+-- false or error message.
+local function packages_conflicts(pkg, installed_pkg)
+ assert(type(pkg) == "table", "depends.packages_conflicts: Argument 'pkg' is not a table.")
+ assert(type(installed_pkg) == "table", "depends.packages_conflicts: Argument 'installed_pkg' is not a table.")
+
+ -- check if pkg doesn't provide an already installed_pkg
+ if pkg.provides then
+ -- for all of pkg's provides
+ for _, provided_pkg in pairs(get_provides(pkg)) do
+ if provided_pkg.name == installed_pkg.name then
+ return "Package '" .. pkg_full_name(pkg.name, pkg.version, pkg.was_scm_version) .. "' provides '" .. pkg_full_name(provided_pkg.name, provided_pkg.version) .. "' but package '" .. pkg_full_name(installed_pkg.name, installed_pkg.version) .. "' is already " .. selected_or_installed(installed_pkg) .. "."
+ end
+ end
+ end
+
+ -- check for conflicts of package to install with installed package
+ if pkg.conflicts then
+ for _, conflict in pairs (pkg.conflicts) do
+ if conflict == installed_pkg.name then
+ return "Package '" .. pkg_full_name(pkg.name, pkg.version, pkg.was_scm_version) .. "' conflicts with already " .. selected_or_installed(installed_pkg) .. " package '" .. pkg_full_name(installed_pkg.name, installed_pkg.version) .. "'."
+ end
+ end
+ end
+
+ -- check for conflicts of installed package with package to install
+ if installed_pkg.conflicts then
+
+ -- direct conflicts with 'pkg'
+ for _, conflict in pairs (installed_pkg.conflicts) do
+ if conflict == pkg.name then
+ return "Already " .. selected_or_installed(installed_pkg) .. " package '" .. pkg_full_name(installed_pkg.name, installed_pkg.version) .. "' conflicts with package '" .. pkg_full_name(pkg.name, pkg.version, pkg.was_scm_version) .. "'."
+ end
+ end
+
+ -- conflicts with 'provides' of 'pkg' (packages provided by package to install)
+ if pkg.provides then
+ for _, conflict in pairs (installed_pkg.conflicts) do
+ -- for all of pkg's provides
+ for _, provided_pkg in pairs(get_provides(pkg)) do
+ if conflict == provided_pkg.name then
+ return "Already '" .. selected_or_installed(installed_pkg) .. " package '" .. pkg_full_name(installed_pkg.name, installed_pkg.version) .. "' conflicts with package '" .. pkg_full_name(provided_pkg.name, provided_pkg.version) .. "' provided by '" .. pkg_full_name(pkg.name, pkg.version, pkg.was_scm_version) .. "'."
+ end
+ end
+ end
+ end
+ end
+
+ -- no conflicts found
+ return false
+end
+
+-- Return table of package dependencies 'depends' with OS specific dependencies extracted.
+--
+-- OS specific dependencies are stored in a subtable with 'arch' as a key.
+-- E.g. this table containing OS specific dependencies:
+-- depends = {
+-- "lua~>5.1",
+-- "luadist-git>=0.1",
+-- Linux = {
+-- "iup>=3.6",
+-- "wxlua>=2.8.10.0",
+-- },
+-- Windows = {
+-- "luagd>=2.0.33r2",
+-- "luacom>=1.4.1",
+-- },
+-- }
+--
+-- ...will be on the 'Linux' architecture (determined by cfg.arch) converted into:
+-- depends = {
+-- "lua~>5.1",
+-- "luadist-git>=0.1",
+-- "iup>=3.6",
+-- "wxlua>=2.8.10.0",
+-- }
+function extract_os_specific_depends(depends)
+ assert(type(depends) == "table", "depends.extract_os_specific_depends: Argument 'depends' is not a table.")
+ local extracted = {}
+ for k, depend in pairs(depends) do
+ -- if 'depend' is a table, then it must be a table of OS specific
+ -- dependencies, so extract it if it's for this architecture
+ if type(depend) == "table" then
+ if k == cfg.arch then
+ for _, os_specific_depend in pairs(depend) do
+ table.insert(extracted, os_specific_depend)
+ end
+ end
+ else
+ table.insert(extracted, depend)
+ end
+ end
+ return extracted
+end
+
+-- Return all packages needed in order to install package 'pkg'
+-- and with specified 'installed' packages in the system using 'manifest'.
+-- 'pkg' can also contain version constraint (e.g. 'copas>=1.2.3', 'saci-1.0' etc.).
+--
+-- This function also downloads packages to get information about their dependencies.
+-- Directory where the package was downloaded is stored in 'download_dir' attribute
+-- of that package in the table of packages returned by this function.
+--
+-- Optional argument 'dependency_manifest' is a table of dependencies examined
+-- from previous installations etc. It can be used to speed-up the dependency
+-- resolving procedure for example.
+--
+-- When optional 'force_no_download' parameter is set to true, then information
+-- about packages won't be downloaded during dependency resolving, assuming that
+-- entries in the provided manifest are already complete.
+--
+-- When optional 'suppress_printing' parameter is set to true, then messages
+-- for the user won't be printed during dependency resolving.
+--
+-- Optional argument 'deploy_dir' is used just as a temporary place to place
+-- the downloaded packages into.
+--
+-- 'dependency_parents' is table of all packages encountered so far when resolving dependencies
+-- and is used to detect and deal with circular dependencies. Leave it 'nil'
+-- and it will do its job just fine :-).
+--
+-- 'tmp_installed' is internal table used in recursion and should be left 'nil' when
+-- calling this function from other context. It is used for passing the changes
+-- in installed packages between the recursive calls of this function.
+--
+-- TODO: refactor this spaghetti code!
+local function get_packages_to_install(pkg, installed, manifest, dependency_manifest, force_no_download, suppress_printing, deploy_dir, dependency_parents, tmp_installed)
+ manifest = manifest or mf.get_manifest()
+ dependency_manifest = dependency_manifest or {}
+ force_no_download = force_no_download or false
+ suppress_printing = suppress_printing or false
+ deploy_dir = deploy_dir or cfg.root_dir
+ dependency_parents = dependency_parents or {}
+
+ -- set helper table 'tmp_installed'
+ tmp_installed = tmp_installed or utils.deepcopy(installed)
+
+ assert(type(pkg) == "string", "depends.get_packages_to_install: Argument 'pkg' is not a string.")
+ assert(type(installed) == "table", "depends.get_packages_to_install: Argument 'installed' is not a table.")
+ assert(type(manifest) == "table", "depends.get_packages_to_install: Argument 'manifest' is not a table.")
+ assert(type(dependency_manifest) == "table", "depends.get_packages_to_install: Argument 'dependency_manifest' is not a table.")
+ assert(type(force_no_download) == "boolean", "depends.get_packages_to_install: Argument 'force_no_download' is not a boolean.")
+ assert(type(suppress_printing) == "boolean", "depends.get_packages_to_install: Argument 'suppress_printing' is not a boolean.")
+ assert(type(deploy_dir) == "string", "depends.get_packages_to_install: Argument 'deploy_dir' is not a string.")
+ assert(type(dependency_parents) == "table", "depends.get_packages_to_install: Argument 'dependency_parents' is not a table.")
+ assert(type(tmp_installed) == "table", "depends.get_packages_to_install: Argument 'tmp_installed' is not a table.")
+ deploy_dir = sys.abs_path(deploy_dir)
+
+ --[[ for future debugging:
+ print('resolving: '.. pkg)
+ print(' installed: ', utils.table_tostring(installed))
+ print(' tmp_installed: ', utils.table_tostring(tmp_installed))
+ --]]
+
+ -- check if package is already installed
+ local pkg_name, pkg_constraint = split_name_constraint(pkg)
+ local pkg_is_installed, err = is_installed(pkg_name, tmp_installed, pkg_constraint)
+ if pkg_is_installed then return {} end
+ if err then return nil, err end
+
+ -- table of packages needed to be installed (will be returned)
+ local to_install = {}
+
+ -- find out available versions of 'pkg' and insert them into manifest
+ if not force_no_download then
+ local versions, err = package.retrieve_versions(pkg, manifest, suppress_printing)
+ if not versions then return nil, err end
+ for _, version in pairs(versions) do
+ table.insert(manifest, version)
+ end
+ end
+
+ -- find candidates & sort them
+ local candidates_to_install = find_packages(pkg, manifest)
+ if #candidates_to_install == 0 then
+ return nil, "No suitable candidate for '" .. pkg .. "' found."
+ end
+ candidates_to_install = sort_by_versions(candidates_to_install)
+
+ for _, pkg in pairs(candidates_to_install) do
+
+ --[[ for future debugging:
+ print(' candidate: '.. pkg.name..'-'..pkg.version)
+ print(' installed: ', utils.table_tostring(installed))
+ print(' tmp_installed: ', utils.table_tostring(tmp_installed))
+ print(' to_install: ', utils.table_tostring(to_install))
+ print(' -is installed: ', is_installed(pkg.name, tmp_installed, pkg_constraint))
+ --]]
+
+ -- if there's an error from the previous candidate, print the reason for trying another one
+ if not suppress_printing and err then print(" - trying another candidate due to: " .. err) end
+
+ -- clear the state from the previous candidate
+ pkg_is_installed, err = false, nil
+
+ -- check whether this package has already been added to 'tmp_installed' by another of its candidates
+ pkg_is_installed, err = is_installed(pkg.name, tmp_installed, pkg_constraint)
+ if pkg_is_installed then break end
+
+ -- preserve information about the 'scm' version, because pkg.version
+ -- will be rewritten by information taken from pkg's dist.info file
+ local was_scm_version = (pkg.version == "scm")
+
+ -- Try to obtain cached dependency information from the dependency manifest
+ if dependency_manifest[pkg.name .. "-" .. pkg.version] and cfg.dep_cache then
+ pkg = dependency_manifest[pkg.name .. "-" .. pkg.version]
+ else
+ -- download info about the package if not already downloaded and downloading not prohibited
+ if not (pkg.download_dir or force_no_download) then
+ local path_or_err
+ pkg, path_or_err = package.retrieve_pkg_info(pkg, deploy_dir, suppress_printing)
+ if not pkg then
+ err = "Error when resolving dependencies: " .. path_or_err
+ else
+ -- set path to downloaded package - used to indicate that the
+ -- package was already downloaded, to delete unused but downloaded
+ -- packages and also to install choosen packages
+ pkg.download_dir = path_or_err
+ end
+ end
+ end
+
+ if pkg and was_scm_version then pkg.was_scm_version = true end
+
+ -- check arch & type
+ if not err then
+ if not (pkg.arch == "Universal" or pkg.arch == cfg.arch) or
+ not (pkg.type == "all" or pkg.type == "source" or pkg.type == cfg.type) then
+ err = "Package '" .. pkg_full_name(pkg.name, pkg.version) .. "' doesn't have required arch and type."
+ end
+ end
+
+ -- checks for conflicts with other installed (or previously selected) packages
+ if not err then
+ for _, installed_pkg in pairs(tmp_installed) do
+ err = packages_conflicts(pkg, installed_pkg)
+ if err then break end
+ end
+ end
+
+ -- if pkg passed all of the above tests
+ if not err then
+
+ -- check if pkg's dependencies are satisfied
+ if pkg.depends then
+
+ -- insert pkg into the stack of circular dependencies detection
+ table.insert(dependency_parents, pkg.name)
+
+ -- extract all OS specific dependencies of pkg
+ pkg.depends = extract_os_specific_depends(pkg.depends)
+
+ -- for all dependencies of pkg
+ for _, depend in pairs(pkg.depends) do
+ local dep_name = split_name_constraint(depend)
+
+ -- detect circular dependencies using 'dependency_parents'
+ local is_circular_dependency = false
+ for _, parent in pairs(dependency_parents) do
+ if dep_name == parent then
+ is_circular_dependency = true
+ break
+ end
+ end
+
+ -- if circular dependencies not detected
+ if not is_circular_dependency then
+
+ -- recursively call this function on the candidates of this pkg's dependency
+ local depends_to_install, dep_err = get_packages_to_install(depend, installed, manifest, dependency_manifest, force_no_download, suppress_printing, deploy_dir, dependency_parents, tmp_installed)
+
+ -- if any suitable dependency packages were found, insert them to the 'to_install' table
+ if depends_to_install then
+ for _, depend_to_install in pairs(depends_to_install) do
+
+ -- add some meta information
+ if not depend_to_install.selected_by then
+ depend_to_install.selected_by = pkg.name .. "-" .. pkg.version
+ end
+
+ table.insert(to_install, depend_to_install)
+ table.insert(tmp_installed, depend_to_install)
+ table.insert(installed, depend_to_install)
+ end
+ else
+ err = "Error getting dependency of '" .. pkg_full_name(pkg.name, pkg.version) .. "': " .. dep_err
+ break
+ end
+
+ -- if circular dependencies detected
+ else
+ err = "Error getting dependency of '" .. pkg_full_name(pkg.name, pkg.version) .. "': '" .. dep_name .. "' is a circular dependency."
+ break
+ end
+ end
+
+ -- remove last package from the stack of circular dependencies detection
+ table.remove(dependency_parents)
+ end
+
+ -- if no error occured
+ if not err then
+ -- add pkg and it's provides to the fake table of installed packages, with
+ -- property 'selected' set, indicating that the package isn't
+ -- really installed in the system, just selected to be installed (this is used e.g. in error messages)
+ pkg.selected = true
+ table.insert(tmp_installed, pkg)
+ if pkg.provides then
+ for _, provided_pkg in pairs(get_provides(pkg)) do
+ provided_pkg.selected = true
+ table.insert(tmp_installed, provided_pkg)
+ end
+ end
+ -- add pkg to the table of packages to install
+ table.insert(to_install, pkg)
+
+ -- if some error occured
+ else
+ -- delete the downloaded package
+ if pkg.download_dir and not cfg.debug then sys.delete(pkg.download_dir) end
+
+ -- set tables of 'packages to install' and 'installed packages' to their original state
+
+ to_install = {}
+ tmp_installed = utils.deepcopy(installed)
+ -- add provided packages to installed ones
+ for _, installed_pkg in pairs(tmp_installed) do
+ for _, pkg in pairs(get_provides(installed_pkg)) do
+ table.insert(tmp_installed, pkg)
+ end
+ end
+ end
+
+ -- if error occured
+ else
+ -- delete the downloaded package
+ if pkg and pkg.download_dir and not cfg.debug then sys.delete(pkg.download_dir) end
+
+ -- if pkg is already installed, skip checking its other candidates
+ if pkg_is_installed then break end
+ end
+ end
+
+ -- if package is not installed and no suitable candidates were found, return the last error
+ if #to_install == 0 and not pkg_is_installed then
+ return nil, err
+ else
+ return to_install
+ end
+end
+
+-- Resolve dependencies and return all packages needed in order to install
+-- 'packages' into the system with already 'installed' packages, using 'manifest'.
+-- Also return the table of the dependencies determined during the process
+-- as the second return value.
+--
+-- Optional argument 'dependency_manifest' is a table of dependencies examined
+-- from previous installations etc. It can be used to speed-up the dependency
+-- resolving procedure for example.
+--
+-- Optional argument 'deploy_dir' is used as a temporary place to place the
+-- downloaded packages into.
+--
+-- When optional 'force_no_download' parameter is set to true, then information
+-- about packages won't be downloaded during dependency resolving, assuming that
+-- entries in manifest are complete.
+--
+-- When optional 'suppress_printing' parameter is set to true, then messages
+-- for the user won't be printed during dependency resolving.
+function get_depends(packages, installed, manifest, dependency_manifest, deploy_dir, force_no_download, suppress_printing)
+ if not packages then return {} end
+ manifest = manifest or mf.get_manifest()
+ dependency_manifest = dependency_manifest or {}
+ deploy_dir = deploy_dir or cfg.root_dir
+ force_no_download = force_no_download or false
+ suppress_printing = suppress_printing or false
+ if type(packages) == "string" then packages = {packages} end
+
+ assert(type(packages) == "table", "depends.get_depends: Argument 'packages' is not a table or string.")
+ assert(type(installed) == "table", "depends.get_depends: Argument 'installed' is not a table.")
+ assert(type(manifest) == "table", "depends.get_depends: Argument 'manifest' is not a table.")
+ assert(type(dependency_manifest) == "table", "depends.get_depends: Argument 'dependency_manifest' is not a table.")
+ assert(type(deploy_dir) == "string", "depends.get_depends: Argument 'deploy_dir' is not a string.")
+ assert(type(force_no_download) == "boolean", "depends.get_depends: Argument 'force_no_download' is not a boolean.")
+ assert(type(suppress_printing) == "boolean", "depends.get_depends: Argument 'suppress_printing' is not a boolean.")
+ deploy_dir = sys.abs_path(deploy_dir)
+
+ local tmp_installed = utils.deepcopy(installed)
+
+ -- add provided packages to installed ones
+ for _, installed_pkg in pairs(tmp_installed) do
+ for _, pkg in pairs(get_provides(installed_pkg)) do
+ table.insert(tmp_installed, pkg)
+ end
+ end
+
+ -- If 'pkg' contains valid (architecture specific) path separator,
+ -- it is treated like a path to already downloaded package and
+ -- we assume that user wants to use this specific version of the
+ -- module to be installed. Hence, we will add information about
+ -- this version into the manifest and also remove references to
+ -- any other versions of this module from the manifest. This will
+ -- enforce the version of the module required by the user.
+ for k, pkg in pairs(packages) do
+ if pkg:find(sys.path_separator()) then
+ local pkg_dir = sys.abs_path(pkg)
+ local pkg_info, err = mf.load_distinfo(sys.make_path(pkg_dir, "dist.info"))
+ if not pkg_info then return nil, err end
+
+ -- add information about location of the package, also to prevent downloading it again
+ pkg_info.download_dir = pkg_dir
+ -- mark package to skip deleting its directory after installation
+ pkg_info.preserve_pkg_dir = true
+
+ -- set default arch/type if not explicitly stated and package is of source type
+ if package.is_source_type(pkg_dir) then
+ pkg_info = package.ensure_source_arch_and_type(pkg_info)
+ elseif not (pkg_info.arch and pkg_info.type) then
+ return nil, pkg_dir .. ": binary package missing arch or type in 'dist.info'."
+ end
+
+ -- update manifest
+ manifest = utils.filter(manifest, function(p) return p.name ~= pkg_info.name and true end)
+ table.insert(manifest, pkg_info)
+
+ -- update packages to install
+ pkg = pkg_info.name .. "-" .. pkg_info.version
+ packages[k] = pkg
+ end
+ end
+
+ local to_install = {}
+
+ -- get packages needed to satisfy the dependencies
+ for _, pkg in pairs(packages) do
+
+ local needed_to_install, err = get_packages_to_install(pkg, tmp_installed, manifest, dependency_manifest, force_no_download, suppress_printing, deploy_dir)
+
+ -- if everything's fine
+ if needed_to_install then
+
+ for _, needed_pkg in pairs(needed_to_install) do
+
+ -- TODO: why not to use 'installed' instead of 'tmp_installed'?
+ -- It's because provides aren't searched for by find()
+ -- function inside the update_dependency_manifest().
+ dependency_manifest = update_dependency_manifest(needed_pkg, tmp_installed, needed_to_install, dependency_manifest)
+
+ table.insert(to_install, needed_pkg)
+ table.insert(tmp_installed, needed_pkg)
+ -- add provides of needed_pkg to installed ones
+ for _, provided_pkg in pairs(get_provides(needed_pkg)) do
+ -- copy 'selected' property
+ provided_pkg.selected = needed_pkg.selected
+ table.insert(tmp_installed, provided_pkg)
+ end
+ end
+ -- if error occured
+ else
+ -- delete already downloaded packages
+ for _, pkg in pairs(to_install) do
+ if pkg.download_dir and not cfg.debug then sys.delete(pkg.download_dir) end
+ end
+ return nil, "Cannot resolve dependencies for '" .. pkg .. "': ".. err
+ end
+ end
+
+ return to_install, dependency_manifest
+end
+
+-- Return table of packages provided by specified package (from it's 'provides' field)
+function get_provides(package)
+ assert(type(package) == "table", "depends.get_provides: Argument 'package' is not a table.")
+ if not package.provides then return {} end
+
+ local provided = {}
+ for _, provided_name in pairs(package.provides) do
+ local pkg = {}
+ pkg.name, pkg.version = split_name_constraint(provided_name)
+ pkg.type = package.type
+ pkg.arch = package.arch
+ pkg.provided = package.name .. "-" .. package.version
+ table.insert(provided, pkg)
+ end
+ return provided
+end
+
+-- Return package name and version constraint from full package version constraint specification
+-- E. g.:
+-- for 'luaexpat-1.2.3' return: 'luaexpat' , '1.2.3'
+-- for 'luajit >= 1.2' return: 'luajit' , '>=1.2'
+function split_name_constraint(version_constraint)
+ assert(type(version_constraint) == "string", "depends.split_name_constraint: Argument 'version_constraint' is not a string.")
+
+ local split = version_constraint:find("[%s=~<>-]+%d") or version_constraint:find("[%s=~<>-]+scm")
+
+ if split then
+ return version_constraint:sub(1, split - 1), version_constraint:sub(split):gsub("[%s-]", "")
+ else
+ return version_constraint, nil
+ end
+end
+
+-- Return only packages that can be installed on the specified architecture and type
+function filter_packages_by_arch_and_type(packages, req_arch, req_type)
+ assert(type(packages) == "table", "depends.filter_packages_by_arch_and_type: Argument 'packages' is not a table.")
+ assert(type(req_arch) == "string", "depends.filter_packages_by_arch_and_type: Argument 'req_arch' is not a string.")
+ assert(type(req_type) == "string", "depends.filter_packages_by_arch_and_type: Argument 'pkg_type' is not a string.")
+
+ return utils.filter(packages,
+ function (pkg)
+ return (pkg.arch == "Universal" or pkg.arch == req_arch) and
+ (pkg.type == "all" or pkg.type == "source" or pkg.type == req_type)
+ end)
+end
+
+-- Return only packages that contain one of the specified strings in their 'name-version'.
+-- Case is ignored. If no strings are specified, return all the packages.
+-- Argument 'search_in_desc' specifies if search also in description of packages.
+function filter_packages_by_strings(packages, strings, search_in_desc)
+ if type(strings) == "string" then strings = {strings} end
+ assert(type(packages) == "table", "depends.filter_packages_by_strings: Argument 'packages' is not a table.")
+ assert(type(strings) == "table", "depends.filter_packages_by_strings: Argument 'strings' is not a string or table.")
+
+ if #strings ~= 0 then
+ return utils.filter(packages,
+ function (pkg)
+ for _,str in pairs(strings) do
+ local name = pkg.name .. "-" .. pkg.version
+ if search_in_desc then
+ name = name .. " " .. (pkg.desc or "")
+ end
+ if string.find(string.lower(name), string.lower(str), 1 ,true) ~= nil then return true end
+ end
+ end)
+ else
+ return packages
+ end
+end
+
+
+-- Return full package name and version string (e.g. 'luajit-2.0'). When version
+-- is nil or '' then return only name (e.g. 'luajit') and when name is nil or ''
+-- then return '<unknown>'. Optional 'was_scm_version' argument is a boolean,
+-- stating whether the package was originally selected for installation as a 'scm' version.
+function pkg_full_name(name, version, was_scm_version)
+ name = name or ""
+ version = version or ""
+ was_scm_version = was_scm_version or false
+ if type(version) == "number" then version = tostring(version) end
+
+ assert(type(name) == "string", "depends.pkg_full_name: Argument 'name' is not a string.")
+ assert(type(version) == "string", "depends.pkg_full_name: Argument 'version' is not a string.")
+
+ if was_scm_version then version = version .. " [scm version]" end
+
+ if name == "" then
+ return "<unknown>"
+ else
+ return name .. ((version ~= "") and "-" .. version or "")
+ end
+end
+
+-- Return table of packages, sorted descendingly by versions (newer ones are moved to the top).
+function sort_by_versions(packages)
+ assert(type(packages) == "table", "depends.sort_by_versions: Argument 'packages' is not a table.")
+ return utils.sort(packages, function (a, b) return compare_versions(a.version, b.version) end)
+end
+
+-- Return table of packages, sorted alphabetically by name and then descendingly by version.
+function sort_by_names(packages)
+ assert(type(packages) == "table", "depends.sort_by_names: Argument 'packages' is not a table.")
+ return utils.sort(packages, function (a, b)
+ if a.name == b.name then
+ return compare_versions(a.version, b.version)
+ else
+ return a.name < b.name
+ end
+ end)
+end
+
+-- Return if version satisfies the specified constraint
+function satisfies_constraint(version, constraint)
+ assert(type(version) == "string", "depends.satisfies_constraint: Argument 'version' is not a string.")
+ assert(type(constraint) == "string", "depends.satisfies_constraint: Argument 'constraint' is not a string.")
+ return const.constraint_satisfied(version, constraint)
+end
+
+-- For package versions, return whether: 'version_a' > 'version_b'
+function compare_versions(version_a, version_b)
+ assert(type(version_a) == "string", "depends.compare_versions: Argument 'version_a' is not a string.")
+ assert(type(version_b) == "string", "depends.compare_versions: Argument 'version_b' is not a string.")
+ return const.compareVersions(version_a, version_b)
+end
+
+-- Returns 'dep_manifest' updated with information about the 'pkg'.
+-- 'installed' is table with installed packages
+-- 'to_install' is table with packages that are selected for installation
+-- Packages satisfying the dependencies will be searched for in these two tables.
+function update_dependency_manifest(pkg, installed, to_install, dep_manifest)
+ dep_manifest = dep_manifest or {}
+ assert(type(pkg) == "table", "depends.update_dependency_manifest: Argument 'pkg' is not a table.")
+ assert(type(installed) == "table", "depends.update_dependency_manifest: Argument 'installed' is not a table.")
+ assert(type(to_install) == "table", "depends.update_dependency_manifest: Argument 'to_install' is not a table.")
+ assert(type(dep_manifest) == "table", "depends.update_dependency_manifest: Argument 'dep_manifest' is not a table.")
+
+ local name_ver = pkg.name .. "-" .. (pkg.was_scm_version and "scm" or pkg.version)
+
+ -- add to manifest
+ if not dep_manifest[name_ver] then
+ dep_manifest[name_ver] = {}
+ dep_manifest[name_ver].name = pkg.name
+ dep_manifest[name_ver].version = pkg.version
+ dep_manifest[name_ver].was_scm_version = pkg.was_scm_version
+ dep_manifest[name_ver].arch = pkg.arch
+ dep_manifest[name_ver].type = pkg.type
+ dep_manifest[name_ver].path = pkg.path
+ dep_manifest[name_ver].depends = pkg.depends
+ dep_manifest[name_ver].conflicts = pkg.conflicts
+ dep_manifest[name_ver].provides = pkg.provides
+ dep_manifest[name_ver].license = pkg.license
+ dep_manifest[name_ver].desc = pkg.desc
+ dep_manifest[name_ver].url = pkg.url
+ dep_manifest[name_ver].author = pkg.author
+ dep_manifest[name_ver].maintainer = pkg.maintainer
+
+ -- add information which dependency is satisfied by which package
+ if pkg.depends then
+
+ -- TODO: Won't it be better to add OS-specific 'satisfied_by' metadata in a format like OS-specific 'depends' ?
+ local all_deps = extract_os_specific_depends(pkg.depends)
+
+ dep_manifest[name_ver].satisfied_by = {}
+ for _, depend in pairs(all_deps) do
+
+ -- find package satisfying the dependency
+ local satisfying = find_packages(depend, installed)[1] or find_packages(depend, to_install)[1]
+ satisfying = satisfying.name .. "-" .. satisfying.version
+ dep_manifest[name_ver].satisfied_by[depend] = satisfying
+
+ -- check whether the satisfying package isn't provided by other one
+ local provided_by = utils.filter(installed, function(pkg)
+ return pkg.provides and utils.contains(pkg.provides, satisfying)
+ end)
+ if #provided_by == 0 then
+ provided_by = utils.filter(to_install, function(pkg)
+ return pkg.provides and utils.contains(pkg.provides, satisfying)
+ end)
+ end
+
+ if #provided_by ~= 0 then
+ if not dep_manifest[name_ver].satisfying_provided_by then
+ dep_manifest[name_ver].satisfying_provided_by = {}
+ end
+ dep_manifest[name_ver].satisfying_provided_by[satisfying] = provided_by[1].name .. "-" .. provided_by[1].version
+ end
+ end
+
+ end
+ end
+
+ return dep_manifest
+end
diff --git a/love2dToAPK/tools/tools/zbstudio-win/lualibs/dist/git.lua b/love2dToAPK/tools/tools/zbstudio-win/lualibs/dist/git.lua
new file mode 100644
index 0000000..808f74d
--- /dev/null
+++ b/love2dToAPK/tools/tools/zbstudio-win/lualibs/dist/git.lua
@@ -0,0 +1,306 @@
+-- Encapsulated Git functionality
+
+module ("dist.git", package.seeall)
+
+require "git"
+local sys = require "dist.sys"
+local cfg = require "dist.config"
+
+
+-- Clone the repository from url to dest_dir
+function clone(repository_url, dest_dir, depth, branch)
+ assert(type(repository_url) == "string", "git.clone: Argument 'repository_url' is not a string.")
+ assert(type(dest_dir) == "string", "git.clone: Argument 'dest_dir' is not a string.")
+ dest_dir = sys.abs_path(dest_dir)
+
+ local command = "git clone " .. repository_url
+
+ if depth then
+ assert(type(depth) == "number", "git.clone: Argument 'depth' is not a number.")
+ command = command .. " --depth " .. depth
+ end
+
+ if branch then
+ assert(type(branch) == "string", "git.clone: Argument 'branch' is not a string.")
+ command = command .. " -b " .. branch
+ end
+
+ command = command .. " " .. sys.quote(dest_dir)
+ if sys.exists(dest_dir) then sys.delete(dest_dir) end
+ sys.make_dir(dest_dir)
+
+ -- change the current working directory to dest_dir
+ local prev_current_dir = sys.current_dir()
+ sys.change_dir(dest_dir)
+
+ -- execute git clone
+ if not cfg.debug then command = command .. " -q " end
+ local ok, err = sys.exec(command)
+
+ -- change the current working directory back
+ sys.change_dir(prev_current_dir)
+
+ return ok, err
+end
+
+-- Return table of all refs of the remote repository at the 'git_url'. Ref_type can be "tags" or "heads".
+local function get_remote_refs(git_url, ref_type)
+ assert(type(git_url) == "string", "git.get_remote_refs: Argument 'git_url' is not a string.")
+ assert(type(ref_type) == "string", "git.get_remote_refs: Argument 'ref_type' is not a string.")
+ assert(ref_type == "tags" or ref_type == "heads", "git.get_remote_refs: Argument 'ref_type' is not \"tags\" or \"heads\".")
+
+ local refs = {}
+
+ local ok, refs_or_err = pcall(git.protocol.remotes, git_url)
+ if not ok then return nil, "Error getting refs of the remote repository '" .. git_url .. "': " .. refs_or_err end
+
+ for ref, sha in pairs(refs_or_err) do
+ if ref:match("%S+/" .. ref_type .. "/%S+") and not ref:match("%^{}") then
+ table.insert(refs, ref:match("%S+/" .. ref_type .. "/(%S+)"))
+ end
+ end
+
+ return refs
+end
+
+-- Return table of all tags of the repository at the 'git_url'
+function get_remote_tags(git_url)
+ return get_remote_refs(git_url, "tags")
+end
+
+-- Return table of all branches of the repository at the 'git_url'
+function get_remote_branches(git_url)
+ return get_remote_refs(git_url, "heads")
+end
+
+-- Checkout specified ref in specified git_repo_dir
+function checkout_ref(ref, git_repo_dir, orphaned)
+ git_repo_dir = git_repo_dir or sys.current_dir()
+ orphaned = orphaned or false
+ assert(type(ref) == "string", "git.checkout_ref: Argument 'ref' is not a string.")
+ assert(type(git_repo_dir) == "string", "git.checkout_ref: Argument 'git_repo_dir' is not a string.")
+ assert(type(orphaned) == "boolean", "git.checkout_ref: Argument 'orphaned' is not a boolean.")
+ git_repo_dir = sys.abs_path(git_repo_dir)
+
+ local command = "git checkout "
+ if orphaned then command = command .. " --orphan " end
+ command = command .. " " .. ref .. " -f"
+ if not cfg.debug then command = command .. " -q " end
+
+ local ok, err
+ if git_repo_dir ~= sys.current_dir() then
+ local prev_current_dir = sys.current_dir()
+ sys.change_dir(git_repo_dir)
+ ok, err = sys.exec(command)
+ sys.change_dir(prev_current_dir)
+ else
+ ok, err = sys.exec(command)
+ end
+
+ return ok, err
+end
+
+-- Checkout specified sha in specified git_repo_dir
+function checkout_sha(sha, git_repo_dir)
+ git_repo_dir = git_repo_dir or sys.current_dir()
+ assert(type(sha) == "string", "git.checkout_sha: Argument 'sha' is not a string.")
+ assert(type(git_repo_dir) == "string", "git.checkout_sha: Argument 'git_repo_dir' is not a string.")
+ git_repo_dir = sys.abs_path(git_repo_dir)
+
+ local dir_changed, prev_current_dir
+
+ if git_repo_dir ~= sys.current_dir() then
+ prev_current_dir = sys.current_dir()
+ sys.change_dir(git_repo_dir)
+ dir_changed = true
+ end
+
+ local ok, repo_or_err = pcall(git.repo.open, git_repo_dir)
+ if not ok then return nil, "Error when opening the git repository '" .. git_repo_dir .. "': " .. repo_or_err end
+
+ local err
+ ok, err = pcall(repo_or_err.checkout, repo_or_err, sha, git_repo_dir)
+ if not ok then return nil, "Error when checking out the sha '" .. sha .. "' in the git repository '" .. git_repo_dir .. "': " .. err end
+
+ repo_or_err:close()
+ if dir_changed then sys.change_dir(prev_current_dir) end
+
+ return true
+end
+
+-- Create an empty git repository in given directory.
+function init(dir)
+ dir = dir or sys.current_dir()
+ assert(type(dir) == "string", "git.init: Argument 'dir' is not a string.")
+ dir = sys.abs_path(dir)
+
+ -- create the 'dir' first, since it causes 'git init' to fail on Windows
+ -- when the parent directory of 'dir' doesn't exist
+ local ok, err = sys.make_dir(dir)
+ if not ok then return nil, err end
+
+ local command = "git init " .. sys.quote(dir)
+ if not cfg.debug then command = command .. " -q " end
+ return sys.exec(command)
+end
+
+-- Add all files in the 'repo_dir' to the git index. The 'repo_dir' must be
+-- in the initialized git repository.
+function add_all(repo_dir)
+ repo_dir = repo_dir or sys.current_dir()
+ assert(type(repo_dir) == "string", "git.add_all: Argument 'repo_dir' is not a string.")
+ repo_dir = sys.abs_path(repo_dir)
+
+ local ok, prev_dir, msg
+ ok, prev_dir = sys.change_dir(repo_dir);
+ if not ok then return nil, err end
+
+ ok, msg = sys.exec("git add -A -f " .. sys.quote(repo_dir))
+ sys.change_dir(prev_dir)
+
+ return ok, msg
+end
+
+-- Commit all indexed files in 'repo_dir' with the given commit 'message'.
+-- The 'repo_dir' must be in the initialized git repository.
+function commit(message, repo_dir)
+ repo_dir = repo_dir or sys.current_dir()
+ message = message or "commit by luadist-git"
+ assert(type(message) == "string", "git.commit: Argument 'message' is not a string.")
+ assert(type(repo_dir) == "string", "git.commit: Argument 'repo_dir' is not a string.")
+ repo_dir = sys.abs_path(repo_dir)
+
+ local ok, prev_dir, msg
+ ok, prev_dir = sys.change_dir(repo_dir);
+ if not ok then return nil, err end
+
+ local command = "git commit -m " .. sys.quote(message)
+ if not cfg.debug then command = command .. " -q " end
+ ok, msg = sys.exec(command)
+ sys.change_dir(prev_dir)
+
+ return ok, msg
+end
+
+
+-- Rename branch 'old_name' to 'new_name'. -- The 'repo_dir' must be
+-- in the initialized git repository and the branch 'new_name' must
+-- not already exist in that repository.
+function rename_branch(old_name, new_name, repo_dir)
+ repo_dir = repo_dir or sys.current_dir()
+ assert(type(old_name) == "string", "git.rename_branch: Argument 'old_name' is not a string.")
+ assert(type(new_name) == "string", "git.rename_branch: Argument 'new_name' is not a string.")
+ assert(type(repo_dir) == "string", "git.rename_branch: Argument 'repo_dir' is not a string.")
+ repo_dir = sys.abs_path(repo_dir)
+
+ local ok, prev_dir, msg
+ ok, prev_dir = sys.change_dir(repo_dir);
+ if not ok then return nil, err end
+
+ ok, msg = sys.exec("git branch -m " .. old_name .. " " .. new_name)
+ sys.change_dir(prev_dir)
+
+ return ok, msg
+end
+
+-- Push the ref 'ref_name' from the 'repo_dir' to the remote git
+-- repository 'git_repo_url'. If 'all_tags' is set to true, all tags
+-- will be pushed, in addition to the explicitly given ref.
+-- If 'delete' is set to 'true' then the explicitly given remote ref
+-- will be deleted, not pushed.
+function push_ref(repo_dir, ref_name, git_repo_url, all_tags, delete)
+ repo_dir = repo_dir or sys.current_dir()
+ all_tags = all_tags or false
+ delete = delete or false
+ assert(type(repo_dir) == "string", "git.push_ref: Argument 'repo_dir' is not a string.")
+ assert(type(git_repo_url) == "string", "git.push_ref: Argument 'git_repo_url' is not a string.")
+ assert(type(ref_name) == "string", "git.push_ref: Argument 'ref_name' is not a string.")
+ assert(type(all_tags) == "boolean", "git.push_ref: Argument 'all_tags' is not a boolean.")
+ assert(type(delete) == "boolean", "git.push_ref: Argument 'delete' is not a boolean.")
+ repo_dir = sys.abs_path(repo_dir)
+
+ local ok, prev_dir, msg
+ ok, prev_dir = sys.change_dir(repo_dir);
+ if not ok then return nil, err end
+
+ local command = "git push " .. git_repo_url
+ if all_tags then command = command .. " --tags " end
+ if delete then command = command .. " --delete " end
+ command = command .. " " .. ref_name .. " -f "
+ if not cfg.debug then command = command .. " -q " end
+
+ ok, msg = sys.exec(command)
+ sys.change_dir(prev_dir)
+
+ return ok, msg
+end
+
+-- Creates the tag 'tag_name' in given 'repo_dir', which must be
+-- in the initialized git repository
+function create_tag(repo_dir, tag_name)
+ repo_dir = repo_dir or sys.current_dir()
+ assert(type(repo_dir) == "string", "git.create_tag: Argument 'repo_dir' is not a string.")
+ assert(type(tag_name) == "string", "git.create_tag: Argument 'tag_name' is not a string.")
+ repo_dir = sys.abs_path(repo_dir)
+
+ local ok, prev_dir, msg
+ ok, prev_dir = sys.change_dir(repo_dir);
+ if not ok then return nil, err end
+
+ ok, msg = sys.exec("git tag " .. tag_name .. " -f ")
+ sys.change_dir(prev_dir)
+
+ return ok, msg
+end
+
+-- Fetch given 'ref_name' from the remote 'git_repo_url' to the local repository
+-- 'repo_dir' and return its sha. 'ref_type' can be "tag" or "head".
+local function fetch_ref(repo_dir, git_repo_url, ref_name, ref_type)
+ repo_dir = repo_dir or sys.current_dir()
+ assert(type(repo_dir) == "string", "git.fetch_ref: Argument 'repo_dir' is not a string.")
+ assert(type(git_repo_url) == "string", "git.fetch_ref: Argument 'git_repo_url' is not a string.")
+ assert(type(ref_name) == "string", "git.fetch_ref: Argument 'ref_name' is not a string.")
+ assert(type(ref_type) == "string", "git.fetch_ref: Argument 'ref_type' is not a string.")
+ assert(ref_type == "tag" or ref_type == "head", "git.get_remote_refs: Argument 'ref_type' is not \"tag\" or \"head\".")
+ repo_dir = sys.abs_path(repo_dir)
+
+ local refstring = "refs/" .. ref_type .. "s/" .. ref_name
+
+ local suppress_fetch_progress = not cfg.debug
+ local ok, repo_or_err = pcall(git.repo.open, repo_dir)
+ if not ok then return nil, "Error when opening the git repository '" .. repo_dir .. "': " .. repo_or_err end
+
+ local ok, pack_or_err, sha = pcall(git.protocol.fetch, git_repo_url, repo_or_err, refstring, suppress_fetch_progress)
+ if not ok then return nil, "Error when fetching ref '" .. refstring .. "' from git repository '" .. git_repo_url .. "': " .. pack_or_err end
+
+ repo_or_err:close()
+ pack_or_err:close()
+
+ return sha
+end
+
+-- Fetch given 'tag_name' from the remote 'git_repo_url' to the local repository
+-- 'repo_dir' and save it as a tag with the same 'tag_name'.
+function fetch_tag(repo_dir, git_repo_url, tag_name)
+ return fetch_ref(repo_dir, git_repo_url, tag_name, "tag")
+end
+
+-- Fetch given 'branch_name' from the remote 'git_repo_url' to the local repository
+-- 'repo_dir' and save it as a branch with the same 'branch_name'.
+function fetch_branch(repo_dir, git_repo_url, branch_name)
+ return fetch_ref(repo_dir, git_repo_url, branch_name, "head")
+end
+
+-- Create the git repository and return the repo object (which can be used in checkout_sha etc.)
+-- If the 'dir' exists, it's deleted prior to creating the git repository.
+function create_repo(dir)
+ assert(type(dir) == "string", "git.create_repo: Argument 'dir' is not a string.")
+
+ if sys.exists(dir) then sys.delete(dir) end
+
+ local ok, repo_or_err = pcall(git.repo.create, dir)
+ if not ok then return nil, "Error when creating the git repository '" .. dir .. "': " .. repo_or_err end
+
+ repo_or_err:close()
+ return true
+end
diff --git a/love2dToAPK/tools/tools/zbstudio-win/lualibs/dist/init.lua b/love2dToAPK/tools/tools/zbstudio-win/lualibs/dist/init.lua
new file mode 100644
index 0000000..50c4b7e
--- /dev/null
+++ b/love2dToAPK/tools/tools/zbstudio-win/lualibs/dist/init.lua
@@ -0,0 +1,349 @@
+-- main API of LuaDist
+
+module ("dist", package.seeall)
+
+local cfg = require "dist.config"
+local depends = require "dist.depends"
+local git = require "dist.git"
+local sys = require "dist.sys"
+local package = require "dist.package"
+local mf = require "dist.manifest"
+local utils = require "dist.utils"
+
+-- Return the deployment directory.
+function get_deploy_dir()
+ return sys.abs_path(cfg.root_dir)
+end
+
+-- Return packages deployed in 'deploy_dir' also with their provides.
+function get_deployed(deploy_dir)
+ deploy_dir = deploy_dir or cfg.root_dir
+ assert(type(deploy_dir) == "string", "dist.get_deployed: Argument 'deploy_dir' is not a string.")
+ deploy_dir = sys.abs_path(deploy_dir)
+
+ local deployed = depends.get_installed(deploy_dir)
+ local provided = {}
+
+ for _, pkg in pairs(deployed) do
+ for _, provided_pkg in pairs(depends.get_provides(pkg)) do
+ provided_pkg.provided_by = pkg.name .. "-" .. pkg.version
+ table.insert(provided, provided_pkg)
+ end
+ end
+
+ for _, provided_pkg in pairs(provided) do
+ table.insert(deployed, provided_pkg)
+ end
+
+ deployed = depends.sort_by_names(deployed)
+ return deployed
+end
+
+-- Download new 'manifest_file' from repository and returns it.
+-- Return nil and error message on error.
+function update_manifest(deploy_dir)
+ deploy_dir = deploy_dir or cfg.root_dir
+ assert(type(deploy_dir) == "string", "dist.update_manifest: Argument 'deploy_dir' is not a string.")
+ deploy_dir = sys.abs_path(deploy_dir)
+
+ -- TODO: use 'deploy_dir' argument in manifest functions
+
+ -- retrieve the new manifest (forcing no cache use)
+ local manifest, err = mf.get_manifest(nil, true)
+
+ if manifest then
+ return manifest
+ else
+ return nil, err
+ end
+end
+
+-- Install 'package_names' to 'deploy_dir', using optional CMake 'variables'.
+function install(package_names, deploy_dir, variables)
+ if not package_names then return true end
+ deploy_dir = deploy_dir or cfg.root_dir
+ if type(package_names) == "string" then package_names = {package_names} end
+
+ assert(type(package_names) == "table", "dist.install: Argument 'package_names' is not a table or string.")
+ assert(type(deploy_dir) == "string", "dist.install: Argument 'deploy_dir' is not a string.")
+ deploy_dir = sys.abs_path(deploy_dir)
+
+ -- find installed packages
+ local installed = depends.get_installed(deploy_dir)
+
+ -- get manifest
+ local manifest, err = mf.get_manifest()
+ if not manifest then return nil, "Error getting manifest: " .. err end
+
+ -- get dependency manifest
+ -- TODO: Is it good that dep_manifest is deploy_dir-specific?
+ -- Probably it'd be better not to be specific, but then there're
+ -- problems with 'provides'. E.g. What to do if there's a module
+ -- installed, that is provided by two different modules in two deploy_dirs?
+ local dep_manifest_file = sys.abs_path(sys.make_path(deploy_dir, cfg.dep_cache_file))
+ local dep_manifest, status = {}
+ if sys.exists(dep_manifest_file) and not utils.cache_timeout_expired(cfg.cache_timeout, dep_manifest_file) then
+ status, dep_manifest = mf.load_manifest(dep_manifest_file)
+ if not dep_manifest then return nil, status end
+ end
+
+ -- resolve dependencies
+ local dependencies, dep_manifest_or_err = depends.get_depends(package_names, installed, manifest, dep_manifest, deploy_dir, false, false)
+ if not dependencies then return nil, dep_manifest_or_err end
+ if #dependencies == 0 then return nil, "No packages to install." end
+
+ -- save updated dependency manifest
+ local ok, err = sys.make_dir(sys.parent_dir(dep_manifest_file))
+ if not ok then return nil, err end
+ ok, err = mf.save_manifest(dep_manifest_or_err, dep_manifest_file)
+ if not ok then return nil, err end
+
+ -- fetch the packages from repository
+ local fetched_pkgs = {}
+ for _, pkg in pairs(dependencies) do
+ local fetched_pkg, err = package.fetch_pkg(pkg, sys.make_path(deploy_dir, cfg.temp_dir))
+ if not fetched_pkg then return nil, err end
+ table.insert(fetched_pkgs, fetched_pkg)
+ end
+
+ -- install fetched packages
+ for _, pkg in pairs(fetched_pkgs) do
+ local ok, err = package.install_pkg(pkg.download_dir, deploy_dir, variables, pkg.preserve_pkg_dir)
+ if not ok then return nil, err end
+ end
+
+ return true
+end
+
+-- Manually deploy packages from 'package_dirs' to 'deploy_dir', using optional
+-- CMake 'variables'. The 'package_dirs' are preserved (will not be deleted).
+function make(deploy_dir, package_dirs, variables)
+ deploy_dir = deploy_dir or cfg.root_dir
+ package_dirs = package_dirs or {}
+
+ assert(type(deploy_dir) == "string", "dist.make: Argument 'deploy_dir' is not a string.")
+ assert(type(package_dirs) == "table", "dist.make: Argument 'package_dirs' is not a table.")
+ deploy_dir = sys.abs_path(deploy_dir)
+
+ for _, dir in pairs(package_dirs) do
+ local ok, err = package.install_pkg(sys.abs_path(dir), deploy_dir, variables, true)
+ if not ok then return nil, err end
+ end
+ return true
+end
+
+-- Remove 'package_names' from 'deploy_dir' and return the number of removed
+-- packages.
+function remove(package_names, deploy_dir)
+ deploy_dir = deploy_dir or cfg.root_dir
+ if type(package_names) == "string" then package_names = {package_names} end
+
+ assert(type(package_names) == "table", "dist.remove: Argument 'package_names' is not a string or table.")
+ assert(type(deploy_dir) == "string", "dist.remove: Argument 'deploy_dir' is not a string.")
+ deploy_dir = sys.abs_path(deploy_dir)
+
+ local pkgs_to_remove = {}
+ local installed = depends.get_installed(deploy_dir)
+
+ -- find packages to remove
+ if #package_names == 0 then
+ pkgs_to_remove = installed
+ else
+ pkgs_to_remove = depends.find_packages(package_names, installed)
+ end
+
+ -- remove them
+ for _, pkg in pairs(pkgs_to_remove) do
+ local pkg_distinfo_dir = sys.make_path(cfg.distinfos_dir, pkg.name .. "-" .. pkg.version)
+ local ok, err = package.remove_pkg(pkg_distinfo_dir, deploy_dir)
+ if not ok then return nil, err end
+ end
+
+ return #pkgs_to_remove
+end
+
+-- Download 'pkg_names' to 'fetch_dir' and return the table of their directories.
+function fetch(pkg_names, fetch_dir)
+ fetch_dir = fetch_dir or sys.current_dir()
+ assert(type(pkg_names) == "table", "dist.fetch: Argument 'pkg_names' is not a string or table.")
+ assert(type(fetch_dir) == "string", "dist.fetch: Argument 'fetch_dir' is not a string.")
+ fetch_dir = sys.abs_path(fetch_dir)
+
+ local manifest = mf.get_manifest()
+
+ local pkgs_to_fetch = {}
+ for _, pkg_name in pairs(pkg_names) do
+
+ -- retrieve available versions
+ local versions, err = package.retrieve_versions(pkg_name, manifest)
+ if not versions then return nil, err end
+ for _, version in pairs(versions) do
+ table.insert(manifest, version)
+ end
+
+ local packages = depends.find_packages(pkg_name, manifest)
+ if #packages == 0 then return nil, "No packages found for '" .. pkg_name .. "'." end
+
+ packages = depends.sort_by_versions(packages)
+ table.insert(pkgs_to_fetch, packages[1])
+ end
+
+ local fetched_dirs = {}
+ for _, pkg in pairs(pkgs_to_fetch) do
+ local fetched_pkg, err = package.fetch_pkg(pkg, fetch_dir)
+ if not fetched_pkg then return nil, err end
+ table.insert(fetched_dirs, fetched_pkg.download_dir)
+ end
+
+ return fetched_dirs
+end
+
+-- Upload binary version of given modules installed in the specified
+-- 'deploy_dir' to the repository specified by provided base url.
+-- Return the number of uploaded packages.
+--
+-- Organization of uploaded modules and their repositories is subject
+-- to the following conventions:
+-- - destination repository is: 'DEST_GIT_BASE_URL/MODULE_NAME'
+-- - module will be uploaded to the branch: 'ARCH-TYPE' according
+-- to the arch and type of the user's machine
+-- - the module will be tagged as: 'VERSION-ARCH-TYPE' (if the tag already
+-- exists, it will be overwritten)
+--
+-- E.g. assume that the module 'lua-5.1.4' is installed on the 32bit Linux
+-- system (Linux-i686). When this function is called with the module name
+-- 'lua' and base url 'git@github.com:LuaDist', then the binary version
+-- of the module 'lua', that is installed on the machine, will be uploaded
+-- to the branch 'Linux-i686' of the repository 'git@github.com:LuaDist/lua.git'
+-- and tagged as '5.1.4-Linux-i686'.
+function upload_modules(deploy_dir, module_names, dest_git_base_url)
+ deploy_dir = deploy_dir or cfg.root_dir
+ if type(module_names) == "string" then module_names = {module_names} end
+ assert(type(deploy_dir) == "string", "dist.upload_module: Argument 'deploy_dir' is not a string.")
+ assert(type(module_names) == "table", "dist.upload_module: Argument 'module_name' is not a string or table.")
+ assert(type(dest_git_base_url) == "string", "dist.upload_module: Argument 'dest_git_base_url' is not a string.")
+ deploy_dir = sys.abs_path(deploy_dir)
+
+ local modules_to_upload = {}
+ local installed = depends.get_installed(deploy_dir)
+
+ -- find modules to upload
+ if #module_names == 0 then
+ modules_to_upload = installed
+ else
+ modules_to_upload = depends.find_packages(module_names, installed)
+ end
+
+ for _, installed_module in pairs(modules_to_upload) do
+
+ -- set names
+ local branch_name = cfg.arch .. "-" .. cfg.type
+ local tag_name = installed_module.version .. "-" .. branch_name
+ local full_name = installed_module.name .. "-" .. tag_name
+ local tmp_dir = sys.make_path(deploy_dir, cfg.temp_dir, full_name .. "-to-upload")
+ local dest_git_url = dest_git_base_url .. "/" .. installed_module.name .. ".git"
+ local distinfo_file = sys.make_path(deploy_dir, cfg.distinfos_dir, installed_module.name .. "-" .. installed_module.version, "dist.info")
+
+ -- create temporary directory (delete previous if already exists)
+ if sys.exists(tmp_dir) then sys.delete(tmp_dir) end
+ local ok, err = sys.make_dir(tmp_dir)
+ if not ok then return nil, err end
+
+ -- copy the module files for all enabled components
+ for _, component in ipairs(cfg.components) do
+ if installed_module.files[component] then
+ for _, file in ipairs(installed_module.files[component]) do
+ local file_path = sys.make_path(deploy_dir, file)
+ local dest_dir = sys.parent_dir(sys.make_path(tmp_dir, file))
+ if sys.is_file(file_path) then
+ sys.make_dir(dest_dir)
+ sys.copy(file_path, dest_dir)
+ end
+ end
+ end
+ end
+
+ -- add module's dist.info file
+ sys.copy(distinfo_file, tmp_dir)
+
+ -- create git repo
+ ok, err = git.init(tmp_dir)
+ if not ok then return nil, "Error initializing empty git repository in '" .. tmp_dir .. "': " .. err end
+
+ -- add all files
+ ok, err = git.add_all(tmp_dir)
+ if not ok then return nil, "Error adding all files to the git index in '" .. tmp_dir .. "': " .. err end
+
+ -- create commit
+ ok, err = git.commit("[luadist-git] add " .. full_name .. " [ci skip]", tmp_dir)
+ if not ok then return nil, "Error commiting changes in '" .. tmp_dir .. "': " .. err end
+
+ -- rename branch
+ ok, err = git.rename_branch("master", branch_name, tmp_dir)
+ if not ok then return nil, "Error renaming branch 'master' to '" .. branch_name .. "' in '" .. tmp_dir .. "': " .. err end
+
+ -- create tag
+ ok, err = git.create_tag(tmp_dir, tag_name)
+ if not ok then return nil, "Error creating tag '" .. tag_name .. "' in '" .. tmp_dir .. "': " .. err end
+
+ print("Uploading " .. full_name .. " to " .. dest_git_url .. "...")
+
+ -- push to the repository
+ ok, err = git.push_ref(tmp_dir, branch_name, dest_git_url, true)
+ if not ok then return nil, "Error when pushing branch '" .. branch_name .. "' and tag '" .. tag_name .. "' to '" .. dest_git_url .. "': " .. err end
+
+ -- delete temporary directory (if not in debug mode)
+ if not cfg.debug then sys.delete(tmp_dir) end
+ end
+
+ return #modules_to_upload
+end
+
+-- Returns table with information about module's dependencies, using the cache.
+function dependency_info(module, deploy_dir)
+ cache_file = cache_file or sys.abs_path(sys.make_path(cfg.root_dir, cfg.dep_cache_file))
+ assert(type(module) == "string", "dist.dependency_info: Argument 'module' is not a string.")
+ assert(type(deploy_dir) == "string", "dist.dependency_info: Argument 'deploy_dir' is not a string.")
+
+ -- get manifest
+ local manifest, err = mf.get_manifest()
+ if not manifest then return nil, "Error getting manifest: " .. err end
+
+ -- get dependency manifest
+ -- TODO: Is it good that dep_manifest is deploy_dir-specific?
+ -- Probably it'd be better not to be specific, but then there're
+ -- problems with 'provides'. E.g. What to do if there's a module
+ -- installed, that is provided by two different modules in two deploy_dirs?
+ local dep_manifest_file = sys.abs_path(sys.make_path(deploy_dir, cfg.dep_cache_file))
+ local dep_manifest, status = {}
+ if sys.exists(dep_manifest_file) and cfg.cache and not utils.cache_timeout_expired(cfg.cache_timeout, dep_manifest_file) then
+ status, dep_manifest = mf.load_manifest(dep_manifest_file)
+ if not dep_manifest then return nil, status end
+ end
+
+ -- force getting the dependency information
+ local installed = {}
+
+ -- resolve dependencies
+ local dependencies, dep_manifest_or_err = depends.get_depends(module, installed, manifest, dep_manifest, deploy_dir, false, true and not cfg.debug)
+ if not dependencies then return nil, dep_manifest_or_err end
+
+ -- save updated dependency manifest
+ local ok, err = sys.make_dir(sys.parent_dir(dep_manifest_file))
+ if not ok then return nil, err end
+ ok, err = mf.save_manifest(dep_manifest_or_err, dep_manifest_file)
+ if not ok then return nil, err end
+
+ -- collect just relevant dependencies from dependency manifest
+ local relevant_deps = {}
+ for _, dep in pairs(dependencies) do
+ local name_ver = dep.name .. "-" .. (dep.was_scm_version and "scm" or dep.version)
+ if dep_manifest_or_err[name_ver] then
+ table.insert(relevant_deps, dep_manifest_or_err[name_ver])
+ else
+ return nil, "Error: dependency information for '" .. name_ver .. "' not found in dependency manifest."
+ end
+ end
+
+ return relevant_deps
+end
diff --git a/love2dToAPK/tools/tools/zbstudio-win/lualibs/dist/logger.lua b/love2dToAPK/tools/tools/zbstudio-win/lualibs/dist/logger.lua
new file mode 100644
index 0000000..7843223
--- /dev/null
+++ b/love2dToAPK/tools/tools/zbstudio-win/lualibs/dist/logger.lua
@@ -0,0 +1,64 @@
+-- Simple logger for LuaDist.
+
+module ("dist.logger", package.seeall)
+
+local cfg = require "dist.config"
+local sys = require "dist.sys"
+
+-- Open 'log_file' and return a log, or nil and error msg on error.
+local function get_log(log_file)
+ log_file = log_file or cfg.log_file
+ assert(type(log_file) == "string", "log.get_log: Argument 'log_file' is not a string.")
+ log_file = sys.abs_path(log_file)
+
+ sys.make_dir(sys.parent_dir(log_file))
+ local log, err = io.open(log_file, "a")
+ if not log then
+ return nil, "Error: can't open a logfile '" .. log_file .. "': " .. err
+ else
+ return log
+ end
+end
+
+-- Set the default log.
+local log_file = get_log(cfg.log_file)
+
+-- Log levels used.
+local log_levels = {
+ DEBUG = 0, -- Fine-grained informational events that are most useful to debug an application.
+ INFO = 1, -- Informational messages that highlight the progress of the application at coarse-grained level.
+ WARN = 2, -- Potentially harmful situations.
+ ERROR = 3, -- Error events that might still allow the application to continue running.
+ FATAL = 4, -- Very severe error events that would presumably lead the application to abort.
+}
+
+-- Write 'message' with 'level' to 'log'.
+local function write(level, ...)
+ assert(type(level) == "string", "log.write: Argument 'level' is not a string.")
+ assert(#arg > 0, "log.write: No message arguments provided.")
+ assert(type(log_levels[level]) == "number", "log.write: Unknown log level used: '" .. level .. "'.")
+
+ level = level:upper()
+ local message = table.concat(arg, " ")
+
+ -- Check if writing for this log level is enabled.
+ if cfg.write_log_level and log_levels[level] >= log_levels[cfg.write_log_level] then
+ log_file:write(os.date("%Y-%m-%d %H:%M:%S") .. " [" .. level .. "]\t" .. message .. "\n")
+ log_file:flush()
+ end
+
+ -- Check if printing for this log level is enabled.
+ if cfg.print_log_level and log_levels[level] >= log_levels[cfg.print_log_level] then
+ print(message)
+ end
+end
+
+-- Functions with defined log levels for simple use.
+function debug(...) return write("DEBUG", ...) end
+function info(...) return write("INFO", ...) end
+function warn(...) return write("WARN", ...) end
+function error(...) return write("ERROR", ...) end
+function fatal(...) return write("FATAL", ...) end
+
+-- Function with explicitly specified log level.
+function log(level, ...) return write(level, ...) end
diff --git a/love2dToAPK/tools/tools/zbstudio-win/lualibs/dist/manifest.lua b/love2dToAPK/tools/tools/zbstudio-win/lualibs/dist/manifest.lua
new file mode 100644
index 0000000..ccaad13
--- /dev/null
+++ b/love2dToAPK/tools/tools/zbstudio-win/lualibs/dist/manifest.lua
@@ -0,0 +1,248 @@
+-- Working with manifest and dist.info files
+
+module ("dist.manifest", package.seeall)
+
+local cfg = require "dist.config"
+local git = require "dist.git"
+local sys = require "dist.sys"
+local utils = require "dist.utils"
+
+-- Return the manifest table from 'manifest_file'. If the manifest is in cache,
+-- then the cached version is used. You can set the cache timeout value in
+-- 'config.cache_timeout' variable.
+-- If optional 'force_no_cache' parameter is true, then the cache is not used.
+function get_manifest(manifest_file, force_no_cache)
+ manifest_file = manifest_file or sys.make_path(cfg.root_dir, cfg.manifest_file)
+ force_no_cache = force_no_cache or false
+
+ assert(type(manifest_file) == "string", "manifest.get_manifest: Argument 'manifest_file' is not a string.")
+ assert(type(force_no_cache) == "boolean", "manifest.get_manifest: Argument 'force_no_cache' is not a boolean.")
+ manifest_file = sys.abs_path(manifest_file)
+
+ -- download new manifest to the cache if not present or cache not used or cache expired
+ if not sys.exists(manifest_file) or force_no_cache or not cfg.cache or utils.cache_timeout_expired(cfg.cache_timeout, manifest_file) then
+ local manifest_dest = sys.parent_dir(manifest_file) or sys.current_dir()
+ local ok, err = download_manifest(manifest_dest, cfg.repos)
+ if not ok then return nil, "Error when downloading manifest: " .. err end
+ end
+
+ -- load manifest from cache
+ local status, ret = load_manifest(manifest_file)
+ if not status then return nil, "Error when loading manifest: " .. ret end
+
+ return ret
+end
+
+-- Download manifest from the table of git 'repository_urls' to 'dest_dir' and return true on success
+-- and nil and error message on error.
+function download_manifest(dest_dir, repository_urls)
+ dest_dir = dest_dir or sys.make_path(cfg.root_dir, cfg.cache_dir)
+ repository_urls = repository_urls or cfg.repos
+ if type(repository_urls) == "string" then repository_urls = {repository_urls} end
+
+ assert(type(dest_dir) == "string", "manifest.download_manifest: Argument 'dest_dir' is not a string.")
+ assert(type(repository_urls) == "table", "manifest.download_manifest: Argument 'repository_urls' is not a table or string.")
+ dest_dir = sys.abs_path(dest_dir)
+
+ -- define used files and directories
+ local manifest_filename = sys.extract_name(cfg.manifest_file)
+ local manifest_file = sys.make_path(dest_dir, manifest_filename)
+ local temp_dir = sys.make_path(cfg.root_dir, cfg.temp_dir)
+
+ -- ensure that destination directory exists
+ local ok, err = sys.make_dir(dest_dir)
+ if not ok then return nil, err end
+
+ -- retrieve manifests from repositories and collect them into one manifest table
+ local manifest = {}
+
+ if #repository_urls == 0 then return nil, "No repository url specified." end
+
+ print("Downloading repository information...")
+ for k, repo in pairs(repository_urls) do
+ local clone_dir = sys.make_path(temp_dir, "repository_" .. tostring(k))
+
+ -- clone the repo and add its '.gitmodules' file to the manifest table
+
+ ok, err = git.create_repo(clone_dir)
+
+ local sha
+ if ok then sha, err = git.fetch_branch(clone_dir, repo, "master") end
+ if sha then ok, err = git.checkout_sha(sha, clone_dir) end
+
+ if not (ok and sha) then
+ if not cfg.debug then sys.delete(clone_dir) end
+ return nil, "Error when downloading the manifest from repository with url: '" .. repo .. "': " .. err
+ else
+ for _, pkg in pairs(load_gitmodules(sys.make_path(clone_dir, ".gitmodules"))) do
+ table.insert(manifest, pkg)
+ end
+ end
+ if not cfg.debug then sys.delete(clone_dir) end
+ end
+
+ -- save the new manifest table to the file
+ ok, err = save_manifest(manifest, manifest_file)
+ if not ok then return nil, err end
+
+ return true
+end
+
+-- A secure loadfile function
+-- If file code chunk has upvalues, the first upvalue is set to the given
+-- environement, if that parameter is given, or to the value of the global environment.
+local function secure_loadfile(file, env)
+ assert(type(file) == "string", "secure_loadfile: Argument 'file' is not a string.")
+
+ -- use the given (or create a new) restricted environment
+ local env = env or {}
+
+ -- load the file and run in a protected call with the restricted env
+ -- setfenv is deprecated in lua 5.2 in favor of giving env in arguments
+ -- the additional loadfile arguments are simply ignored for previous lua versions
+ local f, err = loadfile(file, 'bt', env)
+ if f then
+ if setfenv ~= nil then
+ setfenv(f, env)
+ end
+ return pcall(f)
+ else
+ return nil, err
+ end
+end
+
+-- Load and return manifest table from the manifest file.
+-- If manifest file not present, return nil.
+function load_manifest(manifest_file)
+ manifest_file = manifest_file or sys.make_path(cfg.root_dir, cfg.manifest_file)
+
+ return secure_loadfile(sys.abs_path(manifest_file))
+end
+
+-- Load '.gitmodules' file and returns manifest table.
+-- If the file is not present, return nil.
+function load_gitmodules(gitmodules_file)
+ gitmodules_file = gitmodules_file or sys.make_path(cfg.root_dir, cfg.manifest_file)
+ assert(type(gitmodules_file) == "string", "manifest.load_gitmodules: Argument 'gitmodules_file' is not a string.")
+ gitmodules_file = sys.abs_path(gitmodules_file)
+
+ if sys.exists(gitmodules_file) then
+ -- load the .gitmodules file
+ local file, err = io.open(gitmodules_file, "r")
+ if not file then return nil, "Error when opening the .gitmodules file '" .. gitmodules_file .. "':" .. err end
+
+ local mf_text = file:read("*a")
+ file:close()
+ if not mf_text then return nil, "Error when reading the .gitmodules file '" .. gitmodules_file .. "':" .. err end
+
+ manifest = {}
+ for url in mf_text:gmatch("git://%S+/%S+") do
+ pkg = {name = url:match("git://%S+/(%S+)%.git") or url:match("git://%S+/(%S+)"), version = "scm", path = url}
+ table.insert(manifest, pkg)
+ end
+
+ return manifest
+ else
+ return nil, "Error when loading the .gitmodules: file '" .. gitmodules_file .. "' doesn't exist."
+ end
+end
+
+-- Save manifest table to the 'file'
+function save_manifest(manifest_table, file)
+ assert(type(manifest_table) == "table", "manifest.save_distinfo: Argument 'manifest_table' is not a table.")
+ assert(type(file) == "string", "manifest.save_distinfo: Argument 'file' is not a string.")
+ file = sys.abs_path(file)
+
+ -- Print table 'tbl' to io stream 'file'.
+ local function print_table(file, tbl, in_nested_table)
+ for k, v in pairs(tbl) do
+ -- print key
+ if in_nested_table then file:write("\t\t") end
+ if type(k) ~= "number" then
+ file:write("['" .. k .. "']" .. " = ")
+ end
+ -- print value
+ if type(v) == "table" then
+ file:write("{\n")
+ print_table(file, v, true)
+ if in_nested_table then file:write("\t") end
+ file:write("\t}")
+ else
+ if in_nested_table then file:write("\t") end
+ if type(v) == "string" then
+ file:write('[[' .. v .. ']]')
+ else
+ file:write(tostring(v))
+ end
+ end
+ file:write(",\n")
+ end
+ end
+
+ local manifest_file = io.open(file, "w")
+ if not manifest_file then return nil, "Error when saving manifest: cannot open the file '" .. file .. "'." end
+
+ manifest_file:write('return {\n')
+ print_table(manifest_file, manifest_table)
+ manifest_file:write('},\ntrue')
+ manifest_file:close()
+
+ return true
+end
+
+-- Load and return package info table from the distinfo_file file.
+-- If file not present, return nil.
+function load_distinfo(distinfo_file)
+ assert(type(distinfo_file) == "string", "manifest.load_distinfo: Argument 'distinfo_file' is not a string.")
+ distinfo_file = sys.abs_path(distinfo_file)
+
+ -- load the distinfo file
+ local distinfo_env = {}
+ local status, ret = secure_loadfile(distinfo_file, distinfo_env)
+ if not status then return nil, "Error when loading package info: " .. ret end
+
+ return distinfo_env
+end
+
+-- Save distinfo table to the 'file'
+function save_distinfo(distinfo_table, file)
+ assert(type(distinfo_table) == "table", "manifest.save_distinfo: Argument 'distinfo_table' is not a table.")
+ assert(type(file) == "string", "manifest.save_distinfo: Argument 'file' is not a string.")
+ file = sys.abs_path(file)
+
+ -- Print table 'tbl' to io stream 'file'.
+ local function print_table(file, tbl, in_nested_table)
+ for k, v in pairs(tbl) do
+ -- print key
+ if type(k) ~= "number" then
+ file:write(k .. " = ")
+ end
+ -- print value
+ if type(v) == "table" then
+ file:write("{\n")
+ print_table(file, v, true)
+ file:write("}\n")
+ elseif type(v) == "string" then
+ if in_nested_table then
+ file:write('[[' .. v .. ']]')
+ else
+ file:write('"' .. v .. '"')
+ end
+ else
+ file:write(v)
+ end
+ if in_nested_table then
+ file:write(",")
+ end
+ file:write("\n")
+ end
+ end
+
+ local distinfo_file = io.open(file, "w")
+ if not distinfo_file then return nil, "Error when saving dist-info table: cannot open the file '" .. file .. "'." end
+
+ print_table(distinfo_file, distinfo_table)
+ distinfo_file:close()
+
+ return true
+end
diff --git a/love2dToAPK/tools/tools/zbstudio-win/lualibs/dist/package.lua b/love2dToAPK/tools/tools/zbstudio-win/lualibs/dist/package.lua
new file mode 100644
index 0000000..da399c1
--- /dev/null
+++ b/love2dToAPK/tools/tools/zbstudio-win/lualibs/dist/package.lua
@@ -0,0 +1,596 @@
+-- Package functions
+
+module ("dist.package", package.seeall)
+
+local cfg = require "dist.config"
+local git = require "dist.git"
+local sys = require "dist.sys"
+local mf = require "dist.manifest"
+local utils = require "dist.utils"
+local depends = require "dist.depends"
+
+-- Return whether the package in given 'pkg_dir' is of a source type.
+function is_source_type(pkg_dir)
+ assert(type(pkg_dir) == "string", "package.is_source_type: Argument 'pkg_dir' is not a string.")
+ pkg_dir = sys.abs_path(pkg_dir)
+ return utils.to_boolean(sys.exists(sys.make_path(pkg_dir, "CMakeLists.txt")))
+end
+
+-- Ensure proper arch and type for the given source 'dist_info' table and return it.
+-- WARNING: this function should be used only for 'dist_info' tables of modules that are of a source type!
+function ensure_source_arch_and_type(dist_info)
+ assert(type(dist_info) == "table", "package.ensure_source_arch_and_type: Argument 'dist_info' is not a table.")
+ dist_info.arch = dist_info.arch or "Universal"
+ dist_info.type = dist_info.type or "source"
+ return dist_info
+end
+
+-- Remove package from 'pkg_distinfo_dir' of 'deploy_dir'.
+function remove_pkg(pkg_distinfo_dir, deploy_dir)
+ deploy_dir = deploy_dir or cfg.root_dir
+ assert(type(pkg_distinfo_dir) == "string", "package.remove_pkg: Argument 'pkg_distinfo_dir' is not a string.")
+ assert(type(deploy_dir) == "string", "package.remove_pkg: Argument 'deploy_dir' is not a string.")
+ deploy_dir = sys.abs_path(deploy_dir)
+
+ local abs_pkg_distinfo_dir = sys.make_path(deploy_dir, pkg_distinfo_dir)
+
+ -- check for 'dist.info'
+ local info, err = mf.load_distinfo(sys.make_path(abs_pkg_distinfo_dir, "dist.info"))
+ if not info then return nil, "Error removing package from '" .. pkg_distinfo_dir .. "' - it doesn't contain valid 'dist.info' file." end
+ if not info.files then return nil, "File '" .. sys.make_path(pkg_distinfo_dir, "dist.info") .."' doesn't contain list of installed files." end
+
+ -- remove files installed as components of this package
+ for _, component in ipairs(cfg.components) do
+ if info.files[component] then
+ for i = #info.files[component], 1, -1 do
+ local f = info.files[component][i]
+ f = sys.make_path(deploy_dir,f)
+ if sys.is_file(f) then
+ sys.delete(f)
+ elseif sys.is_dir(f) then
+ local dir_files, err = sys.get_file_list(f)
+ if not dir_files then return nil, "Error removing package in '" .. abs_pkg_distinfo_dir .. "': " .. err end
+ if #dir_files == 0 then sys.delete(f) end
+ end
+ -- delete also all parent directories if empty
+ local parents = sys.parents_up_to(f, deploy_dir)
+ for _, parent in ipairs(parents) do
+ if sys.is_dir(parent) then
+ local dir_files, err = sys.get_file_list(parent)
+ if not dir_files then return nil, "Error removing package in '" .. abs_pkg_distinfo_dir .. "': " .. err end
+ if #dir_files == 0 then
+ sys.delete(parent)
+ end
+ end
+ end
+ end
+ end
+ end
+
+ -- remove removed components also from 'dist.info'
+ for _, component in ipairs(cfg.components) do
+ info.files[component] = nil
+ end
+
+ -- delete the package information from deploy_dir
+ local ok = sys.delete(abs_pkg_distinfo_dir)
+ if not ok then return nil, "Error removing package in '" .. abs_pkg_distinfo_dir .. "'." end
+
+ -- if the package was not completely removed (e.g. some components remain),
+ -- save the new version of its 'dist.info'
+ local comp_num = 0
+ for _, _ in pairs(info.files) do comp_num = comp_num + 1 end
+ if comp_num ~= 0 then
+ sys.make_dir(abs_pkg_distinfo_dir)
+ local ok, err = mf.save_distinfo(info, sys.make_path(abs_pkg_distinfo_dir, "dist.info"))
+ if not ok then return nil, "Error resaving the 'dist.info': " .. err end
+ end
+
+ return ok
+end
+
+-- Install package from 'pkg_dir' to 'deploy_dir', using optional CMake 'variables'.
+-- Optional 'preserve_pkg_dir' argument specified whether to preserve the 'pkg_dir'.
+function install_pkg(pkg_dir, deploy_dir, variables, preserve_pkg_dir)
+ deploy_dir = deploy_dir or cfg.root_dir
+ variables = variables or {}
+ preserve_pkg_dir = preserve_pkg_dir or false
+
+ assert(type(pkg_dir) == "string", "package.install_pkg: Argument 'pkg_dir' is not a string.")
+ assert(type(deploy_dir) == "string", "package.install_pkg: Argument 'deploy_dir' is not a string.")
+ assert(type(variables) == "table", "package.install_pkg: Argument 'variables' is not a table.")
+ assert(type(preserve_pkg_dir) == "boolean", "package.install_pkg: Argument 'preserve_pkg_dir' is not a boolean.")
+
+ pkg_dir = sys.abs_path(pkg_dir)
+ deploy_dir = sys.abs_path(deploy_dir)
+
+ -- check for dist.info
+ local info, err = mf.load_distinfo(sys.make_path(pkg_dir, "dist.info"))
+ if not info then return nil, "Error installing: the directory '" .. pkg_dir .. "' doesn't exist or doesn't contain valid 'dist.info' file." end
+
+ -- check if the package is source
+ if is_source_type(pkg_dir) then info = ensure_source_arch_and_type(info) end
+
+ -- check package's architecture
+ if not (info.arch == "Universal" or info.arch == cfg.arch) then
+ return nil, "Error installing '" .. info.name .. "-" .. info.version .. "': architecture '" .. info.arch .. "' is not suitable for this machine."
+ end
+
+ -- check package's type
+ if not (info.type == "all" or info.type == "source" or info.type == cfg.type) then
+ return nil, "Error installing '" .. info.name .. "-" .. info.version .. "': architecture type '" .. info.type .. "' is not suitable for this machine."
+ end
+
+ local ok, err
+
+ -- if package is of binary type, just deploy it
+ if info.type ~= "source" then
+ ok, err = deploy_binary_pkg(pkg_dir, deploy_dir)
+
+ -- else build and then deploy
+ else
+
+ -- check if we have cmake
+ ok = utils.system_dependency_available("cmake", "cmake --version")
+ if not ok then return nil, "Error when installing: Command 'cmake' not available on the system." end
+
+ -- set cmake variables
+ local cmake_variables = {}
+
+ -- set variables from config file
+ for k, v in pairs(cfg.variables) do
+ cmake_variables[k] = v
+ end
+
+ -- set variables specified as argument
+ for k, v in pairs(variables) do
+ cmake_variables[k] = v
+ end
+
+ cmake_variables.CMAKE_INCLUDE_PATH = table.concat({cmake_variables.CMAKE_INCLUDE_PATH or "", sys.make_path(deploy_dir, "include")}, ";")
+ cmake_variables.CMAKE_LIBRARY_PATH = table.concat({cmake_variables.CMAKE_LIBRARY_PATH or "", sys.make_path(deploy_dir, "lib"), sys.make_path(deploy_dir, "bin")}, ";")
+ cmake_variables.CMAKE_PROGRAM_PATH = table.concat({cmake_variables.CMAKE_PROGRAM_PATH or "", sys.make_path(deploy_dir, "bin")}, ";")
+
+ -- build the package and deploy it
+ ok, err = build_pkg(pkg_dir, deploy_dir, cmake_variables)
+ if not ok then return nil, err end
+
+ end
+
+ -- delete directory of fetched package
+ if not (cfg.debug or preserve_pkg_dir) then sys.delete(pkg_dir) end
+
+ return ok, err
+end
+
+-- Build and deploy package from 'src_dir' to 'deploy_dir' using 'variables'.
+-- Return directory to which the package was built or nil on error.
+-- 'variables' is table of optional CMake variables.
+function build_pkg(src_dir, deploy_dir, variables)
+ deploy_dir = deploy_dir or cfg.root_dir
+ variables = variables or {}
+
+ assert(type(src_dir) == "string", "package.build_pkg: Argument 'src_dir' is not a string.")
+ assert(type(deploy_dir) == "string", "package.build_pkg: Argument 'deploy_dir' is not a string.")
+ assert(type(variables) == "table", "package.build_pkg: Argument 'variables' is not a table.")
+
+ src_dir = sys.abs_path(src_dir)
+ deploy_dir = sys.abs_path(deploy_dir)
+
+ -- check for dist.info
+ local info, err = mf.load_distinfo(sys.make_path(src_dir, "dist.info"))
+ if not info then return nil, "Error building package from '" .. src_dir .. "': it doesn't contain valid 'dist.info' file." end
+ local pkg_name = info.name .. "-" .. info.version
+
+ -- set machine information
+ info.arch = cfg.arch
+ info.type = cfg.type
+
+ -- create CMake build dir
+ local cmake_build_dir = sys.abs_path(sys.make_path(deploy_dir, cfg.temp_dir, pkg_name .. "-CMake-build"))
+ sys.make_dir(cmake_build_dir)
+
+ -- create cmake cache
+ variables["CMAKE_INSTALL_PREFIX"] = deploy_dir
+ local cache_file = io.open(sys.make_path(cmake_build_dir, "cache.cmake"), "w")
+ if not cache_file then return nil, "Error creating CMake cache file in '" .. cmake_build_dir .. "'" end
+
+ -- Fill in cache variables
+ for k,v in pairs(variables) do
+ cache_file:write("SET(" .. k .. " " .. sys.quote(v):gsub("\\+", "/") .. " CACHE STRING \"\" FORCE)\n")
+ end
+
+ -- If user cache file is provided then append it
+ if cfg.cache_file ~= "" then
+ local user_cache = io.open(sys.abs_path(cfg.cache_file), "r")
+ if user_cache then
+ cache_file:write(user_cache:read("*all").."\n")
+ user_cache:close()
+ end
+ end
+ cache_file:close()
+
+ src_dir = sys.abs_path(src_dir)
+ print("Building " .. sys.extract_name(src_dir) .. "...")
+
+ -- set cmake cache command
+ local cache_command = cfg.cache_command
+ if cfg.debug then cache_command = cache_command .. " " .. cfg.cache_debug_options end
+
+ -- set cmake build command
+ local build_command = cfg.build_command
+ if cfg.debug then build_command = build_command .. " " .. cfg.build_debug_options end
+
+ -- set the cmake cache
+ local ok = sys.exec("cd " .. sys.quote(cmake_build_dir) .. " && " .. cache_command .. " " .. sys.quote(src_dir))
+ if not ok then return nil, "Error preloading the CMake cache script '" .. sys.make_path(cmake_build_dir, "cache.cmake") .. "'" end
+
+ -- build with cmake
+ ok = sys.exec("cd " .. sys.quote(cmake_build_dir) .. " && " .. build_command)
+ if not ok then return nil, "Error building with CMake in directory '" .. cmake_build_dir .. "'" end
+
+ -- if this is only simulation, exit sucessfully, skipping the next actions
+ if cfg.simulate then
+ return true, "Simulated build and deployment of package '" .. pkg_name .. "' sucessfull."
+ end
+
+ -- table to collect files installed in the components
+ info.files = {}
+
+ -- install the components
+ for _, component in ipairs(cfg.components) do
+ local strip_option = ""
+ if not cfg.debug and component ~= "Library" then strip_option = cfg.strip_option end
+
+ local ok = sys.exec("cd " .. sys.quote(cmake_build_dir) .. " && " .. cfg.cmake .. " " .. strip_option .. " " ..cfg.install_component_command:gsub("#COMPONENT#", component))
+
+ if not ok then return nil, "Error when installing the component '" .. component .. "' with CMake in directory '" .. cmake_build_dir .. "'" end
+
+ local install_mf = sys.make_path(cmake_build_dir, "install_manifest_" .. component .. ".txt")
+ local mf, err
+ local component_files = {}
+
+ -- collect files installed in this component
+ if sys.exists(install_mf) then
+ mf, err = io.open(install_mf, "r")
+ if not mf then return nil, "Error when opening the CMake installation manifest '" .. install_mf .. "': " .. err end
+ for line in mf:lines() do
+ line = sys.check_separators(line)
+ local file = line:gsub(utils.escape_magic(deploy_dir .. sys.path_separator()), "")
+ table.insert(component_files, file)
+ end
+ mf:close()
+
+ -- add list of component files to the 'dist.info'
+ if #component_files > 0 then info.files[component] = component_files end
+ end
+ end
+-- if bookmark == 0 then return nil, "Package did not install any files!" end
+
+ -- test with ctest
+ if cfg.test then
+ print("Testing " .. sys.extract_name(src_dir) .. " ...")
+ ok = sys.exec("cd " .. sys.quote(deploy_dir) .. " && " .. cfg.test_command)
+ if not ok then return nil, "Error when testing the module '" .. pkg_name .. "' with CTest." end
+ end
+
+ -- save modified 'dist.info' file
+ local pkg_distinfo_dir = sys.make_path(deploy_dir, cfg.distinfos_dir, pkg_name)
+ sys.make_dir(pkg_distinfo_dir)
+ ok, err = mf.save_distinfo(info, sys.make_path(pkg_distinfo_dir, "dist.info"))
+ if not ok then return nil, err end
+
+ -- clean up
+ if not cfg.debug then sys.delete(cmake_build_dir) end
+
+ return true, "Package '" .. pkg_name .. "' successfully builded and deployed to '" .. deploy_dir .. "'."
+end
+
+-- Deploy binary package from 'pkg_dir' to 'deploy_dir' by copying.
+function deploy_binary_pkg(pkg_dir, deploy_dir)
+ deploy_dir = deploy_dir or cfg.root_dir
+
+ assert(type(pkg_dir) == "string", "package.deploy_binary_pkg: Argument 'pkg_dir' is not a string.")
+ assert(type(deploy_dir) == "string", "package.deploy_binary_pkg: Argument 'deploy_dir' is not a string.")
+
+ pkg_dir = sys.abs_path(pkg_dir)
+ deploy_dir = sys.abs_path(deploy_dir)
+
+ -- check for dist.info
+ local info, err = mf.load_distinfo(sys.make_path(pkg_dir, "dist.info"))
+ if not info then return nil, "Error deploying package from '" .. pkg_dir .. "': it doesn't contain valid 'dist.info' file." end
+ local pkg_name = info.name .. "-" .. info.version
+
+ -- if this is only simulation, exit sucessfully, skipping the next actions
+ if cfg.simulate then
+ return true, "Simulated deployment of package '" .. pkg_name .. "' sucessfull."
+ end
+
+ -- copy all components of the module to the deploy_dir
+ for _, component in ipairs(cfg.components) do
+ if info.files[component] then
+ for _, file in ipairs(info.files[component]) do
+ local dest_dir = sys.make_path(deploy_dir, sys.parent_dir(file))
+
+ local ok, err = sys.make_dir(dest_dir)
+ if not ok then return nil, "Error when deploying package '" .. pkg_name .. "': cannot create directory '" .. dest_dir .. "': " .. err end
+
+ ok, err = sys.copy(sys.make_path(pkg_dir, file), dest_dir)
+ if not ok then return nil, "Error when deploying package '" .. pkg_name .. "': cannot copy file '" .. file .. "' to the directory '" .. dest_dir .. "': " .. err end
+ end
+ end
+ end
+
+ -- copy dist.info to register the module as installed
+ local pkg_distinfo_dir = sys.make_path(deploy_dir, cfg.distinfos_dir, pkg_name)
+ sys.make_dir(pkg_distinfo_dir)
+ ok, err = mf.save_distinfo(info, sys.make_path(pkg_distinfo_dir, "dist.info"))
+ if not ok then return nil, err end
+
+ return true, "Package '" .. pkg_name .. "' successfully deployed to '" .. deploy_dir .. "'."
+end
+
+-- Fetch package (table 'pkg') to download_dir. Return the original 'pkg' table
+-- with 'pkg.download_dir' containing path to the directory of the
+-- downloaded package.
+--
+-- When optional 'suppress_printing' parameter is set to true, then messages
+-- for the user won't be printed during run of this function.
+--
+-- If the 'pkg' already contains the information about download directory (pkg.download_dir),
+-- we assume the package was already downloaded there and won't download it again.
+function fetch_pkg(pkg, download_dir, suppress_printing)
+ download_dir = download_dir or sys.current_dir()
+ suppress_printing = suppress_printing or false
+ assert(type(pkg) == "table", "package.fetch_pkg: Argument 'pkg' is not a table.")
+ assert(type(download_dir) == "string", "package.fetch_pkg: Argument 'download_dir' is not a string.")
+ assert(type(suppress_printing) == "boolean", "package.fetch_pkg: Argument 'suppress_printing' is not a boolean.")
+ assert(type(pkg.name) == "string", "package.fetch_pkg: Argument 'pkg.name' is not a string.")
+ assert(type(pkg.version) == "string", "package.fetch_pkg: Argument 'pkg.version' is not a string.")
+
+ -- if the package is already downloaded don't download it again
+ if pkg.download_dir then return pkg end
+
+ assert(type(pkg.path) == "string", "package.fetch_pkg: Argument 'pkg.path' is not a string.")
+ download_dir = sys.abs_path(download_dir)
+
+ local pkg_full_name = pkg.name .. "-" .. pkg.version
+ local repo_url = pkg.path
+ local clone_dir = sys.abs_path(sys.make_path(download_dir, pkg_full_name))
+ pkg.download_dir = clone_dir
+
+ -- check if download_dir already exists, assuming the package was already downloaded
+ if sys.exists(sys.make_path(clone_dir, "dist.info")) then
+ if cfg.cache and not utils.cache_timeout_expired(cfg.cache_timeout, clone_dir) then
+ if not suppress_printing then print("'" .. pkg_full_name .. "' already in cache, skipping downloading (use '-cache=false' to force download).") end
+ return pkg
+ else
+ sys.delete(sys.make_path(clone_dir))
+ end
+ end
+
+ local bin_tag = pkg.version .. "-" .. cfg.arch .. "-" .. cfg.type
+ local use_binary = false
+
+ if cfg.binary then
+ -- check if binary version of the module for this arch & type available
+ local avail_tags, err = git.get_remote_tags(repo_url)
+ if not avail_tags then return nil, err end
+
+ if utils.contains(avail_tags, bin_tag) then
+ use_binary = true
+ end
+ end
+
+ -- init the git repository
+ local ok, err = git.create_repo(clone_dir)
+ if not ok then return nil, err end
+
+ -- Fetch the desired ref (from the pkg's remote repo) and checkout into it.
+
+ if use_binary then
+
+ if not suppress_printing then print("Getting " .. pkg_full_name .. " (binary)...") end
+
+ -- We fetch the binary tag.
+ local sha
+ if ok then sha, err = git.fetch_tag(clone_dir, repo_url, bin_tag) end
+ if sha then ok, err = git.checkout_sha(sha, clone_dir) end
+
+ elseif cfg.source then
+
+ if not suppress_printing then print("Getting " .. pkg_full_name .. " (source)...") end
+
+ -- If we want the 'scm' version, we fetch the 'master' branch, otherwise
+ -- we fetch the tag, matching the desired package version.
+ if ok and pkg.version ~= "scm" then
+ local sha
+ sha, err = git.fetch_tag(clone_dir, repo_url, pkg.version)
+ if sha then ok, err = git.checkout_sha(sha, clone_dir) end
+ elseif ok then
+ local sha
+ sha, err = git.fetch_branch(clone_dir, repo_url, "master")
+ if sha then ok, err = git.checkout_sha(sha, clone_dir) end
+ end
+
+ else
+ ok = false
+ if cfg.binary then
+ err = "Binary version of module not available and using source modules disabled."
+ else
+ err = "Using both binary and source modules disabled."
+ end
+ end
+
+ if not ok then
+ -- clean up
+ if not cfg.debug then sys.delete(clone_dir) end
+ return nil, "Error fetching package '" .. pkg_full_name .. "' from '" .. pkg.path .. "' to '" .. download_dir .. "': " .. err
+ end
+
+ -- delete '.git' directory
+ if not cfg.debug then sys.delete(sys.make_path(clone_dir, ".git")) end
+
+ return pkg
+end
+
+-- Return table with information about available versions of 'package'.
+--
+-- When optional 'suppress_printing' parameter is set to true, then messages
+-- for the user won't be printed during run of this function.
+function retrieve_versions(package, manifest, suppress_printing)
+ suppress_printing = suppress_printing or false
+ assert(type(package) == "string", "package.retrieve_versions: Argument 'string' is not a string.")
+ assert(type(manifest) == "table", "package.retrieve_versions: Argument 'manifest' is not a table.")
+ assert(type(suppress_printing) == "boolean", "package.retrieve_versions: Argument 'suppress_printing' is not a boolean.")
+
+ -- get package table
+ local pkg_name = depends.split_name_constraint(package)
+ local tmp_packages = depends.find_packages(pkg_name, manifest)
+
+ if #tmp_packages == 0 then
+ return nil, "No suitable candidate for package '" .. package .. "' found."
+ else
+ package = tmp_packages[1]
+ end
+
+ -- if the package's already downloaded, we assume it's desired to install the downloaded version
+ if package.download_dir then
+ local pkg_type = "binary"
+ if is_source_type(package.download_dir) then pkg_type = "source" end
+ if not suppress_printing then print("Using " .. package.name .. "-" .. package.version .. " (" .. pkg_type .. ") provided by " .. package.download_dir) end
+ return {package}
+ end
+
+ if not suppress_printing then print("Finding out available versions of " .. package.name .. "...") end
+
+ -- get available versions
+ local tags, err = git.get_remote_tags(package.path)
+ if not tags then return nil, "Error when retrieving versions of package '" .. package.name .. "': " .. err end
+
+ -- filter out tags of binary packages
+ local versions = utils.filter(tags, function (tag) return tag:match("^[^%-]+%-?[^%-]*$") and true end)
+
+ packages = {}
+
+ -- create package information
+ for _, version in pairs(versions) do
+ pkg = {}
+ pkg.name = package.name
+ pkg.version = version
+ pkg.path = package.path
+ table.insert(packages, pkg)
+ end
+
+ return packages
+end
+
+-- Return table with information from package's dist.info and path to downloaded
+-- package. Optional argument 'deploy_dir' is used just as a temporary
+-- place to place the downloaded packages into.
+--
+-- When optional 'suppress_printing' parameter is set to true, then messages
+-- for the user won't be printed during the execution of this function.
+function retrieve_pkg_info(package, deploy_dir, suppress_printing)
+ deploy_dir = deploy_dir or cfg.root_dir
+ assert(type(package) == "table", "package.retrieve_pkg_info: Argument 'package' is not a table.")
+ assert(type(deploy_dir) == "string", "package.retrieve_pkg_info: Argument 'deploy_dir' is not a string.")
+ deploy_dir = sys.abs_path(deploy_dir)
+
+ local tmp_dir = sys.abs_path(sys.make_path(deploy_dir, cfg.temp_dir))
+
+ -- download the package
+ local fetched_pkg, err = fetch_pkg(package, tmp_dir, suppress_printing)
+ if not fetched_pkg then return nil, "Error when retrieving the info about '" .. package.name .. "': " .. err end
+
+ -- load information from 'dist.info'
+ local info, err = mf.load_distinfo(sys.make_path(fetched_pkg.download_dir, "dist.info"))
+ if not info then return nil, err end
+
+ -- add other attributes
+ if package.path then info.path = package.path end
+ if package.was_scm_version then info.was_scm_version = package.was_scm_version end
+
+ -- set default arch/type if not explicitly stated and package is of source type
+ if is_source_type(fetched_pkg.download_dir) then
+ info = ensure_source_arch_and_type(info)
+ elseif not (info.arch and info.type) then
+ return nil, fetched_pkg.download_dir .. ": binary package missing arch or type in 'dist.info'."
+ end
+
+ return info, fetched_pkg.download_dir
+end
+
+-- Return manifest, augmented with info about all available versions
+-- of package 'pkg'. Optional argument 'deploy_dir' is used just as a temporary
+-- place to place the downloaded packages into.
+-- Optional argument 'installed' is manifest of all installed packages. When
+-- specified, info from installed packages won't be downloaded from repo,
+-- but the dist.info from installed package will be used.
+function get_versions_info(pkg, manifest, deploy_dir, installed)
+ deploy_dir = deploy_dir or cfg.root_dir
+ assert(type(pkg) == "string", "package.get_versions_info: Argument 'pkg' is not a string.")
+ assert(type(manifest) == "table", "package.get_versions_info: Argument 'manifest' is not a table.")
+ assert(type(deploy_dir) == "string", "package.get_versions_info: Argument 'deploy_dir' is not a string.")
+ deploy_dir = sys.abs_path(deploy_dir)
+
+ -- find all available versions of package
+ local versions, err = retrieve_versions(pkg, manifest)
+ if not versions then return nil, err end
+
+ -- collect info about all retrieved versions
+ local infos = {}
+ for _, version in pairs(versions) do
+
+ local info, path_or_err
+ local installed_version = {}
+
+ -- find out whether this 'version' is installed so we can use it's dist.info
+ if type(installed) == "table" then installed_version = depends.find_packages(version.name .. "-" .. version.version, installed) end
+
+ -- get info
+ if #installed_version > 0 then
+ print("Using dist.info from installed " .. version.name .. "-" .. version.version)
+ info = installed_version[1]
+ info.path = version.path
+ info.from_installed = true -- flag that dist.info of installed package was used
+ else
+ info, path_or_err = retrieve_pkg_info(version, deploy_dir)
+ if not info then return nil, path_or_err end
+ sys.delete(path_or_err)
+ end
+ table.insert(infos, info)
+ end
+
+ -- found and add an implicit 'scm' version
+ local pkg_name = depends.split_name_constraint(pkg)
+ local found = depends.find_packages(pkg_name, manifest)
+ if #found == 0 then return nil, "No suitable candidate for package '" .. pkg .. "' found." end
+ local scm_info, path_or_err = retrieve_pkg_info({name = pkg_name, version = "scm", path = found[1].path})
+ if not scm_info then return nil, path_or_err end
+ sys.delete(path_or_err)
+ scm_info.version = "scm"
+ table.insert(infos, scm_info)
+
+ local tmp_manifest = utils.deepcopy(manifest)
+
+ -- add collected info to the temp. manifest, replacing existing tables
+ for _, info in pairs(infos) do
+ local already_in_manifest = false
+ -- find if this version is already in manifest
+ for idx, pkg in ipairs(tmp_manifest) do
+ -- if yes, replace it
+ if pkg.name == info.name and pkg.version == info.version then
+ tmp_manifest[idx] = info
+ already_in_manifest = true
+ break
+ end
+ end
+ -- if not, just normally add to the manifest
+ if not already_in_manifest then
+ table.insert(tmp_manifest, info)
+ end
+ end
+
+ return tmp_manifest
+end
diff --git a/love2dToAPK/tools/tools/zbstudio-win/lualibs/dist/sys.lua b/love2dToAPK/tools/tools/zbstudio-win/lualibs/dist/sys.lua
new file mode 100644
index 0000000..803df12
--- /dev/null
+++ b/love2dToAPK/tools/tools/zbstudio-win/lualibs/dist/sys.lua
@@ -0,0 +1,386 @@
+-- System functions
+
+module ("dist.sys", package.seeall)
+
+local cfg = require "dist.config"
+local utils = require "dist.utils"
+local lfs = require "lfs"
+
+-- Return the path separator according to the platform.
+function path_separator()
+ if cfg.arch == "Windows" then
+ return "\\"
+ else
+ return "/"
+ end
+end
+
+-- Return path with wrong separators replaced with the right ones.
+function check_separators(path)
+ assert(type(path) == "string", "sys.check_separators: Argument 'path' is not a string.")
+ if cfg.arch == "Windows" then
+ return path:gsub("/", "\\")
+ else
+ return path
+ end
+end
+
+-- Return the path with the unnecessary trailing separator removed.
+function remove_trailing(path)
+ assert(type(path) == "string", "sys.remove_trailing: Argument 'path' is not a string.")
+ if path:sub(-1) == path_separator() and not is_root(path) then path = path:sub(1,-2) end
+ return path
+end
+
+-- Return the path with the all occurences of '/.' or '\.' (representing
+-- the current directory) removed.
+function remove_curr_dir_dots(path)
+ assert(type(path) == "string", "sys.remove_curr_dir_dots: Argument 'path' is not a string.")
+ while path:match(path_separator() .. "%." .. path_separator()) do -- match("/%./")
+ path = path:gsub(path_separator() .. "%." .. path_separator(), path_separator()) -- gsub("/%./", "/")
+ end
+ return path:gsub(path_separator() .. "%.$", "") -- gsub("/%.$", "")
+end
+
+-- Return string argument quoted for a command line usage.
+function quote(argument)
+ assert(type(argument) == "string", "sys.quote: Argument 'argument' is not a string.")
+
+ -- TODO: This seems like a not very nice hack. Why is it needed?
+ -- Wouldn't it be better to fix the problem where it originates?
+ -- replace '/' path separators for '\' on Windows
+ if cfg.arch == "Windows" and argument:match("^[%u%U.]?:?[/\\].*") then
+ argument = argument:gsub("//","\\"):gsub("/","\\")
+ end
+
+ -- Windows doesn't recognize paths starting with two slashes or backslashes
+ -- so we double every backslash except for the first one
+ if cfg.arch == "Windows" and argument:match("^[/\\].*") then
+ local prefix = argument:sub(1,1)
+ argument = argument:sub(2):gsub("\\", "\\\\")
+ argument = prefix .. argument
+ else
+ argument = argument:gsub("\\", "\\\\")
+ end
+ argument = argument:gsub('"', '\\"')
+
+ return '"' .. argument .. '"'
+end
+
+-- Run the system command (in current directory).
+-- Return true on success, nil on fail and log string.
+-- When optional 'force_verbose' parameter is true, then the output will be shown
+-- even when not in debug or verbose mode.
+function exec(command, force_verbose)
+ force_verbose = force_verbose or false
+ assert(type(command) == "string", "sys.exec: Argument 'command' is not a string.")
+ assert(type(force_verbose) == "boolean", "sys.exec: Argument 'force_verbose' is not a boolean.")
+
+ if not (cfg.verbose or cfg.debug or force_verbose) then
+ if cfg.arch == "Windows" then
+ command = command .. " > NUL 2>&1"
+ else
+ command = command .. " > /dev/null 2>&1"
+ end
+ end
+
+ if cfg.debug then print("Executing the command: " .. command) end
+ local ok, str, status = os.execute(command)
+
+ -- os.execute returned values on failure are:
+ -- nil or true, "exit", n or true, "signal", n for lua >= 5.2
+ -- status ~= 0 for lua 5.x < 5.2
+ if ok == nil or (str == "exit" and status ~= 0) or str == "signal" or (ok ~= 0 and ok ~= true) then
+ return nil, "Error when running the command: " .. command
+ else
+ return true, "Sucessfully executed the command: " .. command
+ end
+end
+
+-- Execute the 'command' and returns its output as a string.
+function capture_output(command)
+ assert(type(command) == "string", "sys.exec: Argument 'command' is not a string.")
+
+ local executed, err = io.popen(command, "r")
+ if not executed then return nil, "Error running the command '" .. command .. "':" .. err end
+
+ local captured, err = executed:read("*a")
+ if not captured then return nil, "Error reading the output of command '" .. command .. "':" .. err end
+
+ executed:close()
+ return captured
+end
+
+-- Return whether the path is a root.
+function is_root(path)
+ assert(type(path) == "string", "sys.is_root: Argument 'path' is not a string.")
+ return utils.to_boolean(path:find("^[a-zA-Z]:[/\\]$") or path:find("^[/\\]$"))
+end
+
+-- Return whether the path is absolute.
+function is_abs(path)
+ assert(type(path) == "string", "sys.is_abs: Argument 'path' is not a string.")
+ return utils.to_boolean(path:find("^[a-zA-Z]:[/\\].*$") or path:find("^[/\\].*$"))
+end
+
+-- Return whether the specified file or directory exists.
+function exists(path)
+ assert(type(path) == "string", "sys.exists: Argument 'path' is not a string.")
+ local attr, err = lfs.attributes(path)
+ return utils.to_boolean(attr), err
+end
+
+-- Return whether the 'file' exists and is a file.
+function is_file(file)
+ assert(type(file) == "string", "sys.is_file: Argument 'file' is not a string.")
+ return lfs.attributes(file, "mode") == "file"
+end
+
+-- Return whether the 'dir' exists and is a directory.
+function is_dir(dir)
+ assert(type(dir) == "string", "sys.is_dir: Argument 'dir' is not a string.")
+ return lfs.attributes(dir, "mode") == "directory"
+end
+
+-- Return the current working directory
+function current_dir()
+ local dir, err = lfs.currentdir()
+ if not dir then return nil, err end
+ return dir
+end
+
+-- Return an iterator over the directory 'dir'.
+-- If 'dir' doesn't exist or is not a directory, return nil and error message.
+function get_directory(dir)
+ dir = dir or current_dir()
+ assert(type(dir) == "string", "sys.get_directory: Argument 'dir' is not a string.")
+ if is_dir(dir) then
+ return lfs.dir(dir)
+ else
+ return nil, "Error: '".. dir .. "' is not a directory."
+ end
+end
+
+-- Extract file or directory name from its path.
+function extract_name(path)
+ assert(type(path) == "string", "sys.extract_name: Argument 'path' is not a string.")
+ if is_root(path) then return path end
+
+ path = remove_trailing(path)
+ path = path:gsub("^.*" .. path_separator(), "")
+ return path
+end
+
+-- Return parent directory of the 'path' or nil if there's no parent directory.
+-- If 'path' is a path to file, return the directory the file is in.
+function parent_dir(path)
+ assert(type(path) == "string", "sys.parent_dir: Argument 'path' is not a string.")
+ path = remove_curr_dir_dots(path)
+ path = remove_trailing(path)
+
+ local dir = path:gsub(utils.escape_magic(extract_name(path)) .. "$", "")
+ if dir == "" then
+ return nil
+ else
+ return make_path(dir)
+ end
+end
+
+-- Returns the table of all parent directories of 'path' up to the directory
+-- specified by 'boundary_path' (exclusive).
+function parents_up_to(path, boundary_path)
+ assert(type(path) == "string", "sys.parents_up_to: Argument 'path' is not a string.")
+ assert(type(boundary_path) == "string", "sys.parents_up_to: Argument 'boundary_path' is not a string.")
+ boundary_path = remove_trailing(boundary_path)
+
+ -- helper function to recursively collect the parent directories
+ local function collect_parents(_path, _parents)
+ local _parent = parent_dir(_path)
+ if _parent and _parent ~= boundary_path then
+ table.insert(_parents, _parent)
+ return collect_parents(_parent, _parents)
+ else
+ return _parents
+ end
+ end
+
+ return collect_parents(path, {})
+end
+
+-- Compose path composed from specified parts or current
+-- working directory when no part specified.
+function make_path(...)
+ -- arg is deprecated in lua 5.2 in favor of table.pack we mimic here
+ local arg = {n=select('#',...),...}
+ local parts = arg
+ assert(type(parts) == "table", "sys.make_path: Argument 'parts' is not a table.")
+
+ local path, err
+ if parts.n == 0 then
+ path, err = current_dir()
+ else
+ path, err = table.concat(parts, path_separator())
+ end
+ if not path then return nil, err end
+
+ -- squeeze repeated occurences of a file separator
+ path = path:gsub(path_separator() .. "+", path_separator())
+
+ -- remove unnecessary trailing path separator
+ path = remove_trailing(path)
+
+ return path
+end
+
+-- Return absolute path from 'path'
+function abs_path(path)
+ assert(type(path) == "string", "sys.get_abs_path: Argument 'path' is not a string.")
+ if is_abs(path) then return path end
+
+ local cur_dir, err = current_dir()
+ if not cur_dir then return nil, err end
+
+ return make_path(cur_dir, path)
+end
+
+-- Returns path to the temporary directory of OS.
+function tmp_dir()
+ return os.getenv("TMPDIR") or os.getenv("TEMP") or os.getenv("TMP") or "/tmp"
+end
+
+-- Returns temporary file (or directory) path (with optional prefix).
+function tmp_name(prefix)
+ prefix = prefix or ""
+ assert(type(prefix) == "string", "sys.tmp_name: Argument 'prefix' is not a string.")
+ return make_path(tmp_dir(), prefix .. "luadist_" .. utils.rand(10000000000))
+end
+
+-- Return table of all paths in 'dir'
+function get_file_list(dir)
+ dir = dir or current_dir()
+ assert(type(dir) == "string", "sys.get_directory: Argument 'dir' is not a string.")
+ if not exists(dir) then return nil, "Error getting file list of '" .. dir .. "': directory doesn't exist." end
+
+ local function collect(path, all_paths)
+ for item in get_directory(path) do
+
+ local item_path = make_path(path, item)
+ local _, last = item_path:find(dir .. path_separator(), 1, true)
+ local path_to_insert = item_path:sub(last + 1)
+
+ if is_file(item_path) then
+ table.insert(all_paths, path_to_insert)
+ elseif is_dir(item_path) and item ~= "." and item ~= ".." then
+ table.insert(all_paths, path_to_insert)
+ collect(item_path, all_paths)
+ end
+ end
+ end
+
+ local all_paths = {}
+ collect(dir, all_paths)
+
+ return all_paths
+end
+
+-- Return time of the last modification of 'file'.
+function last_modification_time(file)
+ assert(type(file) == "string", "sys.last_modification_time: Argument 'file' is not a string.")
+ return lfs.attributes(file, "modification")
+end
+
+-- Return the current time (in seconds since epoch).
+function current_time()
+ return os.time()
+end
+
+-- Change the current working directory and return 'true' and previous working
+-- directory on success and 'nil' and error message on error.
+function change_dir(dir_name)
+ assert(type(dir_name) == "string", "sys.change_dir: Argument 'dir_name' is not a string.")
+ local prev_dir = current_dir()
+ local ok, err = lfs.chdir(dir_name)
+ if ok then
+ return ok, prev_dir
+ else
+ return nil, err
+ end
+end
+
+-- Make a new directory, making also all of its parent directories that doesn't exist.
+function make_dir(dir_name)
+ assert(type(dir_name) == "string", "sys.make_dir: Argument 'dir_name' is not a string.")
+ if exists(dir_name) then
+ return true
+ else
+ local par_dir = parent_dir(dir_name)
+ if par_dir then
+ local ok, err = make_dir(par_dir)
+ if not ok then return nil, err end
+ end
+ return lfs.mkdir(dir_name)
+ end
+end
+
+-- Move file (or directory) to the destination directory
+function move_to(file_or_dir, dest_dir)
+ assert(type(file_or_dir) == "string", "sys.move_to: Argument 'file_or_dir' is not a string.")
+ assert(type(dest_dir) == "string", "sys.move_to: Argument 'dest_dir' is not a string.")
+ assert(is_dir(dest_dir), "sys.move_to: Destination '" .. dest_dir .."' is not a directory.")
+
+ -- Extract file/dir name from its path
+ local file_or_dir_name = extract_name(file_or_dir)
+
+ return os.rename(file_or_dir, make_path(dest_dir, file_or_dir_name))
+end
+
+-- rename file (or directory) to the new name.
+function rename(file, new_name)
+ assert(type(file) == "string", "sys.rename: Argument 'file' is not a string.")
+ assert(type(new_name) == "string", "sys.rename: Argument 'new_name' is not a string.")
+ assert(not exists(new_name), "sys.rename: desired filename already exists.")
+
+ return os.rename(file, new_name)
+end
+
+-- Copy 'source' to the destination directory 'dest_dir'.
+-- If 'source' is a directory, then recursive copying is used.
+-- For non-recursive copying of directories use the make_dir() function.
+function copy(source, dest_dir)
+ assert(type(source) == "string", "sys.copy: Argument 'file_or_dir' is not a string.")
+ assert(type(dest_dir) == "string", "sys.copy: Argument 'dest_dir' is not a string.")
+ assert(is_dir(dest_dir), "sys.copy: destination '" .. dest_dir .."' is not a directory.")
+
+ if cfg.arch == "Windows" then
+ if is_dir(source) then
+ make_dir(make_path(dest_dir, extract_name(source)))
+ return exec("xcopy /E /I /Y /Q " .. quote(source) .. " " .. quote(dest_dir .. "\\" .. extract_name(source)))
+ else
+ return exec("copy /Y " .. quote(source) .. " " .. quote(dest_dir))
+ end
+ else
+ if is_dir(source) then
+ return exec("cp -fRH " .. quote(source) .. " " .. quote(dest_dir))
+ else
+ return exec("cp -fH " .. quote(source) .. " " .. quote(dest_dir))
+ end
+ end
+end
+
+-- Delete the specified file or directory
+function delete(path)
+ assert(type(path) == "string", "sys.delete: Argument 'path' is not a string.")
+ assert(is_abs(path), "sys.delete: Argument 'path' is not an absolute path.")
+
+ if cfg.arch == "Windows" then
+ if not exists(path) then
+ return true
+ elseif is_file(path) then
+ return os.remove(path)
+ else
+ return exec("rd /S /Q " .. quote(path))
+ end
+ else
+ return exec("rm -rf " .. quote(path))
+ end
+end
diff --git a/love2dToAPK/tools/tools/zbstudio-win/lualibs/dist/utils.lua b/love2dToAPK/tools/tools/zbstudio-win/lualibs/dist/utils.lua
new file mode 100644
index 0000000..392654c
--- /dev/null
+++ b/love2dToAPK/tools/tools/zbstudio-win/lualibs/dist/utils.lua
@@ -0,0 +1,151 @@
+-- System functions
+
+module ("dist.utils", package.seeall)
+
+local sys = require "dist.sys"
+
+-- Returns a deep copy of 'table' with reference to the same metadata table.
+-- Source: http://lua-users.org/wiki/CopyTable
+function deepcopy(object)
+ local lookup_table = {}
+ local function _copy(object)
+ if type(object) ~= "table" then
+ return object
+ elseif lookup_table[object] then
+ return lookup_table[object]
+ end
+ local new_table = {}
+ lookup_table[object] = new_table
+ for index, value in pairs(object) do
+ new_table[_copy(index)] = _copy(value)
+ end
+ return setmetatable(new_table, getmetatable(object))
+ end
+ return _copy(object)
+end
+
+-- Return deep copy of table 'array', containing only items for which 'predicate_fn' returns true.
+function filter(array, predicate_fn)
+ assert(type(array) == "table", "utils.filter: Argument 'array' is not a table.")
+ assert(type(predicate_fn) == "function", "utils.filter: Argument 'predicate_fn' is not a function.")
+ local filtered = {}
+ for _,v in pairs(array) do
+ if predicate_fn(v) == true then table.insert(filtered, deepcopy(v)) end
+ end
+ return filtered
+end
+
+-- Return deep copy of table 'array', sorted according to the 'compare_fn' function.
+function sort(array, compare_fn)
+ assert(type(array) == "table", "utils.sort: Argument 'array' is not a table.")
+ assert(type(compare_fn) == "function", "utils.sort: Argument 'compare_fn' is not a function.")
+ local sorted = deepcopy(array)
+ table.sort(sorted, compare_fn)
+ return sorted
+end
+
+-- Return whether the 'value' is in the table 'tbl'.
+function contains(tbl, value)
+ assert(type(tbl) == "table", "utils.contains: Argument 'tbl' is not a table.")
+ for _,v in pairs(tbl) do
+ if v == value then return true end
+ end
+ return false
+end
+
+-- Return single line string consisting of values in 'tbl' separated by comma.
+-- Used for printing the dependencies/provides/conflicts.
+function table_tostring(tbl, label)
+ assert(type(tbl) == "table", "utils.table_tostring: Argument 'tbl' is not a table.")
+ local str = ""
+ for k,v in pairs(tbl) do
+ if type(v) == "table" then
+ str = str .. table_tostring(v, k)
+ else
+ if label ~= nil then
+ str = str .. tostring(v) .. " [" .. tostring(label) .. "]" .. ", "
+ else
+ str = str .. tostring(v) .. ", "
+ end
+ end
+ end
+ return str
+end
+
+-- Return table made up from values of the string, separated by separator.
+function make_table(str, separator)
+ assert(type(str) == "string", "utils.make_table: Argument 'str' is not a string.")
+ assert(type(separator) == "string", "utils.make_table: Argument 'separator' is not a string.")
+
+ local tbl = {}
+ for val in str:gmatch("(.-)" .. separator) do
+ table.insert(tbl, val)
+ end
+ local last_val = str:gsub(".-" .. separator, "")
+ if last_val and last_val ~= "" then
+ table.insert(tbl, last_val)
+ end
+ return tbl
+end
+
+-- Return whether the 'cache_timeout' for 'file' has expired.
+function cache_timeout_expired(cache_timeout, file)
+ assert(type(cache_timeout) == "number", "utils.cache_timeout_expired: Argument 'cache_timeout' is not a number.")
+ assert(type(file) == "string", "utils.cache_timeout_expired: Argument 'file' is not a string.")
+ return sys.last_modification_time(file) + cache_timeout < sys.current_time()
+end
+
+-- Return the string 'str', with all magic (pattern) characters escaped.
+function escape_magic(str)
+ assert(type(str) == "string", "utils.escape: Argument 'str' is not a string.")
+ local escaped = str:gsub('[%-%.%+%[%]%(%)%^%%%?%*%^%$]','%%%1')
+ return escaped
+end
+
+-- Return the boolean representation of an 'arg'.
+function to_boolean(arg)
+ return not not arg
+end
+
+
+math.randomseed(os.time())
+
+-- Return pseudo-random number in range [0, 1], [1, n] or [n, m].
+function rand(...)
+ return math.random(...)
+end
+
+-- Perform check of system dependency, which isn't provided in the LuaDist
+-- installation itself and if it is missing, print instructions how
+-- to install it. The 'command' is used for testing, 'name' when printing
+-- information to the user.
+function system_dependency_available(name, command)
+ assert(type(name) == "string", "utils.system_dependency_available: Argument 'name' is not a string.")
+ assert(type(command) == "string", "utils.system_dependency_available: Argument 'command' is not a string.")
+
+ if not sys.exec(command) then
+ print("Error: command '" .. name .. "' not found on system. See installation instructions at\nhttps://github.com/LuaDist/Repository/wiki/Installation-of-System-Dependencies")
+ return false
+ end
+
+ return true
+end
+
+-- Obtain LuaDist location by checking available package locations
+function get_luadist_location()
+ local paths = {}
+ local path = package.path:gsub("([^;]+)", function(c) table.insert(paths, c) end)
+
+ for _, path in pairs(paths) do
+ if (sys.is_abs(path) and path:find("[/\\]lib[/\\]lua[/\\]%?.lua$")) then
+ -- Remove path to lib/lua
+ path = path:gsub("[/\\]lib[/\\]lua[/\\]%?.lua$", "")
+ -- Clean the path up a bit
+ path = path:gsub("[/\\]bin[/\\]%.[/\\]%.%.", "")
+ path = path:gsub("[/\\]bin[/\\]%.%.", "")
+ return path
+ end
+ end
+ return nil
+end
+