diff options
| author | ruki <[email protected]> | 2017-08-14 11:27:19 +0800 |
|---|---|---|
| committer | ruki <[email protected]> | 2017-08-14 11:29:30 +0800 |
| commit | dba45d143d8aff047da82cbe1a881056e6e4bc00 (patch) | |
| tree | 7b80d5de264c17b538a7c9d0fbb234ded39ac683 /xmake/actions/require/package.lua | |
| parent | 34706ba053dda9dd86902cacf42a6c1878c85234 (diff) | |
merge repo and require codes
Diffstat (limited to 'xmake/actions/require/package.lua')
| -rw-r--r-- | xmake/actions/require/package.lua | 360 |
1 files changed, 360 insertions, 0 deletions
diff --git a/xmake/actions/require/package.lua b/xmake/actions/require/package.lua new file mode 100644 index 000000000..6b401ab73 --- /dev/null +++ b/xmake/actions/require/package.lua @@ -0,0 +1,360 @@ +--!The Make-like Build Utility based on Lua +-- +-- Licensed to the Apache Software Foundation (ASF) under one +-- or more contributor license agreements. See the NOTICE file +-- distributed with this work for additional information +-- regarding copyright ownership. The ASF licenses this file +-- to you 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 - 2017, TBOOX Open Source Group. +-- +-- @author ruki +-- @file package.lua +-- + +-- imports +import("core.base.semver") +import("core.base.option") +import("core.base.global") +import("core.project.cache") +import("core.project.project") +import("core.package.package", {alias = "core_package"}) +import("devel.git") +import("net.fasturl") +import("repository") + +-- +-- parse require string +-- +-- add_requires("tboox.tbox >=1.5.1", "zlib >=1.2.11") +-- add_requires("zlib master") +-- add_requires("[email protected] >=1.5.1") +-- add_requires("https://github.com/tboox/[email protected] >=1.5.1") +-- add_requires("tboox.tbox >=1.5.1 <1.6.0 optional") +-- +function _parse_require(require_str) + + -- get it from cache first + local requires = _g._REQUIRES or {} + local required = requires[require_str] + if required then + return required.packagename, required.requireinfo + end + + -- split package and version info + local splitinfo = require_str:split('%s+') + assert(splitinfo and #splitinfo > 0, "require(\"%s\"): invalid!", require_str) + + -- get package info + local packageinfo = splitinfo[1] + + -- get mode at last position + -- + -- .e.g + -- + -- must + -- optional + -- + local mode = "must" + if #splitinfo > 1 then + + -- get mode + local modes = {must = true, optional = true} + local value = splitinfo[#splitinfo]:lower() + if modes[value] then + mode = value + table.remove(splitinfo) + end + end + + -- get version + -- + -- .e.g + -- + -- >=1.5.1 <1.6.0 + -- master || >1.4 + -- ~1.2.3 + -- ^1.1 + -- + local version = "master" + if #splitinfo > 1 then + version = table.concat(table.slice(splitinfo, 2), " ") + end + assert(version, "require(\"%s\"): unknown version!", require_str) + + -- get repository name, package name and package url + local reponame = nil + local packageurl = nil + local packagename = nil + local pos = packageinfo:find_last('@', true) + if pos then + + -- get package name + packagename = packageinfo:sub(pos + 1) + + -- get reponame or packageurl + local repo_or_pkgurl = packageinfo:sub(1, pos - 1) + + -- is package url? + if repo_or_pkgurl:find('[/\\]') then + packageurl = repo_or_pkgurl + else + reponame = repo_or_pkgurl + end + else + packagename = packageinfo + end + + -- check package name + assert(packagename, "require(\"%s\"): the package name not found!", require_str) + + -- init required item + local required = {} + required.packagename = packagename + required.requireinfo = {reponame = reponame, packageurl = packageurl, version = version, mode = mode} + + -- save this required item to cache + requires[require_str] = required + _g._REQUIRES = requires + + -- ok + return required.packagename, required.requireinfo +end + +-- load package instance from the given package url +function _load_package_from_url(packagename, packageurl) + + -- load it + return core_package.load_from_url(packagename, packageurl) +end + +-- load package instance from project +function _load_package_from_project(packagename) + + -- load it + return core_package.load_from_project(packagename) +end + +-- load package instance from repositories +function _load_package_from_repository(packagename, reponame) + + -- get package directory from the given package name + local packagedir, is_global = repository.packagedir(packagename, reponame) + if packagedir then + -- load it + return core_package.load_from_repository(packagename, is_global, packagedir) + end +end + +-- load required packages +function _load_package(packagename, requireinfo) + + -- attempt to get it from cache first + local packages = _g._PACKAGES or {} + local instance = packages[packagename] + if instance then + + -- satisfy required version? + if not semver.satisfies(instance:version(), requireinfo.version) then + raise("package(%s): version conflict, '%s' does not satisfy '%s'!", packagename, instance:version(), requireinfo.version) + end + + -- ok + return instance + end + + -- load package instance + instance = nil + if requireinfo.packageurl then + -- load package from the given package url + instance = _load_package_from_url(packagename, requireinfo.packageurl) + else + -- load package from project first + instance = _load_package_from_project(packagename) + if not instance then + -- load package from repositories + instance = _load_package_from_repository(packagename, requireinfo.reponame) + end + end + + -- check + assert(instance, "package(%s) not found!", packagename) + + -- save require info to package + instance:requireinfo_set(requireinfo) + + -- save this package instance to cache + packages[packagename] = instance + _g._PACKAGES = packages + + -- ok + return instance +end + +-- load all required packages +function _load_packages(requires) + + -- no requires? + if not requires or #requires == 0 then + return {} + end + + -- load packages + local packages = {} + for packagename, requireinfo in pairs(load_requires(requires)) do + + -- load package instance + local package = _load_package(packagename, requireinfo) + + -- load required packages and save them first of this package + requires = package:get("requires") + if requires then + table.join2(packages, _load_packages(requires)) + end + + -- save this package instance + table.insert(packages, package) + end + + -- ok? + return packages +end + +-- load all git refs from packages +function _load_packages_gitrefs(packages) + + -- enter cache scope + cache.enter("local.require") + + -- load cache + local gitrefs = nil + if option.get("force") then + gitrefs = {} + else + gitrefs = cache.get("gitrefs") or {} + end + + -- run tasks + local results = {} + process.runjobs(function (index) + local package = packages[index] + if package then + + -- attempt to get refs from cache first + local refs = gitrefs[package:name()] + if refs then + results[package:name()] = {tags = refs.tags, branches = refs.branches} + else + -- attempt to get refs from the git url + local tags = {} + local branches = {} + for _, url in ipairs(package:urls()) do + if git.checkurl(url) then + + -- fetch refs + tags, branches = git.refs(url) + + -- save result + results[package:name()] = {tags = tags, branches = branches} + + -- cache result + gitrefs[package:name()] = {tags = tags, branches = branches} + break + end + end + end + end + end, #packages) + + -- save cache + cache.set("gitrefs", gitrefs) + cache.flush() + + -- ok? + return results +end + +-- select package version +function _select_package_version(package, required_ver, gitrefs) + + -- get versions + local versions = package:get("versions") + + -- attempt to get tags and branches from the git url + local refs = {} + if gitrefs then + refs = gitrefs[package:name()] or {} + end + + -- select required version + return semver.select(required_ver, versions, refs.tags, refs.branches) +end + +-- the cache directory +function cachedir() + return path.join(global.directory(), "cache", "packages") +end + +-- load requires +function load_requires(requires) + + -- parse requires + local requireinfos = {} + for _, require_str in ipairs(requires) do + + -- parse require info + local packagename, requireinfo = _parse_require(require_str) + + -- save this required package + requireinfos[packagename] = requireinfo + end + + -- ok + return requireinfos +end + +-- load all required packages +function load_packages(requires) + + -- laod all required packages recursively + local packages = _load_packages(requires) + + -- add all urls to fasturl and prepare to sort them together + for _, package in ipairs(packages) do + fasturl.add(package:urls()) + end + + -- load git refs from packages + local gitrefs = _load_packages_gitrefs(packages) + + -- sort and update urls + for _, package in ipairs(packages) do + + -- sort package urls + package:urls_set(fasturl.sort(package:urls())) + + -- exists urls? otherwise be phony package (only as package group) + if #package:urls() > 0 then + + -- select package version + local version, source = _select_package_version(package, package:requireinfo().version, gitrefs) + + -- save version to package + package:version_set(version, source) + end + end + + -- ok + return packages +end + |
