summaryrefslogtreecommitdiff
path: root/xmake/core/project/addons.lua
diff options
context:
space:
mode:
Diffstat (limited to 'xmake/core/project/addons.lua')
-rw-r--r--xmake/core/project/addons.lua140
1 files changed, 140 insertions, 0 deletions
diff --git a/xmake/core/project/addons.lua b/xmake/core/project/addons.lua
new file mode 100644
index 000000000..c979a6f8d
--- /dev/null
+++ b/xmake/core/project/addons.lua
@@ -0,0 +1,140 @@
+--!A cross-platform build utility based on Lua
+--
+-- Licensed under the Apache License, Version 2.0 (the "License");
+-- you may not use this file except in compliance with the License.
+-- You may obtain a copy of the License at
+--
+-- http://www.apache.org/licenses/LICENSE-2.0
+--
+-- Unless required by applicable law or agreed to in writing, software
+-- distributed under the License is distributed on an "AS IS" BASIS,
+-- WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+-- See the License for the specific language governing permissions and
+-- limitations under the License.
+--
+-- Copyright (C) 2015-present, Xmake Open Source Community.
+--
+-- @author ruki
+-- @file addons.lua
+--
+
+-- define module
+local addons = addons or {}
+
+-- load modules
+local os = require("base/os")
+local io = require("base/io")
+local path = require("base/path")
+local table = require("base/table")
+local semver = require("base/semver")
+local addon = require("package/addon")
+
+-- the lock file of the declared addons, e.g. <projectdir>/xmake-addons.lock
+--
+-- @note it's independent of `xmake-requires.lock`, the addons are always locked,
+-- they provide the build scripts and we should never change them silently
+--
+function addons.lockfile(projectdir)
+ return path.join(projectdir or os.projectdir(), "xmake-addons.lock")
+end
+
+-- get the format version of the addons lock file
+--
+-- @see xmake/core/project/project.lua, project.requireslock_version()
+--
+function addons.lockfile_version()
+ return "1.0"
+end
+
+-- check the addons which a project declares, e.g. add_addons("esp32-devel 1.0.x")
+--
+-- @return true, or false and errors
+--
+function addons.validate(requires)
+ local declared = {}
+ for _, requirestr in ipairs(requires) do
+ local name = addons.requirename(requirestr)
+ if name == "addon" or name == "self" then
+ return false, string.format("add_addons(%s): the name is reserved by xmake for the addon references, please rename it!", name)
+ end
+ if name == "." or name == ".." or name:find("[/\\:]") then
+ return false, string.format("add_addons(%s): invalid addon name!", name)
+ end
+
+ -- we can only install one version of an addon for a project
+ if declared[name] then
+ return false, string.format("add_addons(%s): it is declared twice, e.g. `%s` and `%s`, please merge them!",
+ name, declared[name], requirestr)
+ end
+ declared[name] = requirestr
+ end
+ return true
+end
+
+-- split the given declaration into the name and the version range
+--
+-- @note the version range can contain spaces, so everything after the name belongs to it,
+-- e.g. "esp32-devel 1.0.x", "esp32-devel >=1.0 <2.0", "esp32-devel master || >1.4",
+-- @see xmake/modules/private/utils/package.lua
+--
+function addons.requirename(requirestr)
+ local splitinfo = requirestr:split("%s+", {limit = 2})
+ return splitinfo[1], splitinfo[2]
+end
+
+-- is the locked version still valid for the given declaration?
+--
+-- @note the declaration is authoritative, the lock only pins a version inside it,
+-- so we need to resolve it again if the user has changed the declared version
+--
+function addons.locked_valid(requirestr, lockinfo)
+ if not lockinfo or not lockinfo.version then
+ return false
+ end
+ local _, range = addons.requirename(requirestr)
+ if range then
+ -- @note we can only compare the semantic versions, e.g. the local addons are always `latest`
+ return semver.is_valid(lockinfo.version) and semver.satisfies(lockinfo.version, range)
+ end
+ return true
+end
+
+-- get the locked addons, e.g. {["esp32-devel"] = {version = "1.0.3"}}
+function addons.locked(projectdir)
+ local lockfile = addons.lockfile(projectdir)
+ if os.isfile(lockfile) then
+ local lockinfo = io.load(lockfile)
+ if lockinfo then
+ lockinfo.__meta__ = nil
+ return lockinfo
+ end
+ end
+end
+
+-- are all the declared addons installed already?
+--
+-- @note we need to check it in-process for every command which loads the project,
+-- so we only check the locked versions here, the installer will resolve them again
+--
+function addons.satisfied(requires, projectdir)
+ local locked = addons.locked(projectdir)
+ if not locked then
+ return false
+ end
+ local installed = addon.addons()
+ for _, requirestr in ipairs(requires) do
+ local name = addons.requirename(requirestr)
+ local lockinfo = locked[name]
+ if not addons.locked_valid(requirestr, lockinfo) then
+ return false
+ end
+ local addoninfo = installed[addon.dirname(name)]
+ if not addoninfo or addoninfo.version ~= lockinfo.version then
+ return false
+ end
+ end
+ return true
+end
+
+-- return module
+return addons