521 lines
12 KiB
Lua
521 lines
12 KiB
Lua
local jsonProcessor = auRequire("Core/JSON").projectBase
|
|
|
|
-------------------------------------------------------
|
|
-- globals
|
|
-------------------------------------------------------
|
|
_auProjects = {}
|
|
_auProjectsBlocked = {}
|
|
_auNamespacesEmitted = {}
|
|
_auResolvedDep = {}
|
|
_auCurrentProject = {}
|
|
_auCurrentBaseProject = nil
|
|
_auFatalMsg = {}
|
|
|
|
-------------------------------------------------------
|
|
-- utils
|
|
-------------------------------------------------------
|
|
|
|
local function normalizeSourceRoot(path)
|
|
local backup = path
|
|
path = os.realpath(_G.path.join(os.getcwd(), path));
|
|
if (not path) then
|
|
print("path error, not found?", backup)
|
|
return
|
|
end
|
|
return path
|
|
end
|
|
|
|
local function extendInfo(this)
|
|
local type = this.projectType:lower()
|
|
this.isShared = type == "sharedlib"
|
|
this.isStatic = type == "staticlib"
|
|
this.isExec = type == "consoleapp" or type == 'windowedapp'
|
|
this.isConsole = type == "consoleapp"
|
|
this.isWindowed = type == "windowedapp"
|
|
end
|
|
|
|
-------------------------------------------------------
|
|
-- project loading
|
|
-------------------------------------------------------
|
|
|
|
local function addVisit(ina)
|
|
local args = {
|
|
namespace = ina.namespace,
|
|
name = ina.name, -- OPT: recommended
|
|
path = ina.path,
|
|
type = ina.type,
|
|
out = ina.out,
|
|
options = ina.options,
|
|
translations = ina.translations -- OPT: dictionary of dependency maps
|
|
}
|
|
|
|
local path = normalizeSourceRoot(args.path)
|
|
if (not path) then
|
|
return
|
|
end
|
|
|
|
local info = {
|
|
namespace = args.namespace,
|
|
path = path,
|
|
projectType = args.type,
|
|
out = args.out,
|
|
name = args.name,
|
|
translations = args.translations,
|
|
options = args.options
|
|
}
|
|
|
|
extendInfo(info)
|
|
|
|
local project = {
|
|
info = info,
|
|
processor = nil,
|
|
deps = {}
|
|
}
|
|
|
|
local cwd = auGetRoot()
|
|
|
|
local remoteLua = path .. "/Aurora.lua"
|
|
local remoteJson = path .. "/Aurora.json"
|
|
local localJson = cwd .. Aurora.Settings.sRelRepoScripts .. "/" .. args.name .. ".aurora.json"
|
|
local localLua = cwd .. Aurora.Settings.sRelRepoScripts .. "/" .. args.name .. ".aurora.lua"
|
|
|
|
if (os.isfile(localLua)) then
|
|
project.processor = auRequireAbs(localLua)(info)
|
|
elseif (os.isfile(localJson)) then
|
|
info.jpath = localJson
|
|
project.processor = jsonProcessor(info)
|
|
elseif (os.isfile(remoteLua)) then
|
|
project.processor = auRequireAbs(remoteLua)(info)
|
|
elseif (os.isfile(remoteJson)) then
|
|
info.jpath = remoteJson
|
|
project.processor = jsonProcessor(info)
|
|
else
|
|
print("Couldnt find Aurora build script for: ", path)
|
|
return
|
|
end
|
|
|
|
auRequire("Core").project.expendBaseProcessor(project)
|
|
|
|
_auProjects[info.name] = project
|
|
end
|
|
|
|
|
|
local function addScript(ina)
|
|
local args = {
|
|
namespace = ina.namespace,
|
|
script = ina.script,
|
|
path = ina.path,
|
|
type = ina.type,
|
|
out = ina.out,
|
|
options = ina.options,
|
|
translations = ina.translations
|
|
}
|
|
|
|
local path = normalizeSourceRoot(args.path)
|
|
if (not path) then
|
|
return
|
|
end
|
|
|
|
local info = {
|
|
namespace = args.namespace,
|
|
path = path,
|
|
projectType = args.type,
|
|
out = args.out,
|
|
translations = args.translations,
|
|
options = args.options
|
|
}
|
|
|
|
extendInfo(info)
|
|
|
|
local project = {
|
|
info = info,
|
|
processor = nil,
|
|
deps = {}
|
|
}
|
|
|
|
local procesor = userRequire(args.script)
|
|
if (not procesor) then
|
|
processor = auRequireAbs(args.script)
|
|
if (not procesor) then
|
|
print("missing project script:", args.script, path)
|
|
return
|
|
end
|
|
end
|
|
|
|
project.processor = procesor(info)
|
|
if (not project.processor) then
|
|
print("script error")
|
|
return
|
|
end
|
|
|
|
_auProjects[info.name] = project
|
|
end
|
|
|
|
local function pushProjectState(name, path, callback)
|
|
local cwd = os.getcwd()
|
|
local old = _auCurrentProject
|
|
|
|
_auCurrentProject = name
|
|
os.chdir(path)
|
|
|
|
callback()
|
|
|
|
os.chdir(cwd)
|
|
_auCurrentProject = old
|
|
end
|
|
|
|
local function pushProject(project, callback)
|
|
pushProjectState(project.info.name, project.info.path, callback)
|
|
end
|
|
|
|
_auLinkGuard = {}
|
|
|
|
-- private
|
|
local function processInit(project)
|
|
if (project.isInitialized) then
|
|
return
|
|
end
|
|
project.isInitialized = true
|
|
|
|
if (project.processor.init) then
|
|
pushProject(project, function()
|
|
project.processor:init()
|
|
end)
|
|
end
|
|
end
|
|
|
|
-- private
|
|
local function initializeDependencyTree(proj, resolveProject)
|
|
local name = proj.info.name
|
|
|
|
_auResolvedDep[name] = name
|
|
|
|
if (not proj.resolvedDeps) then
|
|
if (proj.processor.resolveDependencies) then
|
|
pushProject(proj, function()
|
|
local depRecursive = _auFatalMsg.deps or {}
|
|
_auFatalMsg.deps = depRecursive
|
|
|
|
local strA = "starting resolve dependencies" .. name
|
|
_auFatalMsg[strA] = nil
|
|
proj.processor:resolveDependencies(function(name, soft)
|
|
_auFatalMsg[strA] = nil
|
|
|
|
table.insert(proj.deps, name)
|
|
|
|
if (_auResolvedDep[name]) then
|
|
return
|
|
end
|
|
|
|
local projRootName = (auGetBaseProjectName() or auGetCurrentProject() or "")
|
|
local strB = "starting resolve specific " .. name .. " for " .. projRootName
|
|
local i = #depRecursive + 1
|
|
depRecursive[i] = strB
|
|
|
|
local depProj = _auProjects[name]
|
|
if (not depProj) then
|
|
if (not soft) then
|
|
auFatal("missing dependency: ", name)
|
|
else
|
|
return false
|
|
end
|
|
end
|
|
|
|
initializeDependencyTree(depProj, true)
|
|
depRecursive[i] = nil
|
|
end)
|
|
end)
|
|
end
|
|
proj.resolvedDeps = true
|
|
end
|
|
|
|
processInit(proj)
|
|
end
|
|
|
|
local processProject = {}
|
|
-- private
|
|
local function processNS(namespace)
|
|
local projs = {}
|
|
local projsIdxs = {}
|
|
|
|
auForEach(_auProjects, function(proj)
|
|
if (proj.info.namespace ~= namespace) then
|
|
return
|
|
end
|
|
|
|
local name = proj.info.name
|
|
projs[name] = proj
|
|
|
|
table.insert(projsIdxs, name)
|
|
end)
|
|
|
|
table.sort(projsIdxs, function(a, b)
|
|
return a:upper() < b:upper()
|
|
end)
|
|
|
|
|
|
_auFatalMsg = {}
|
|
_auFatalMsg["starting dependency tree"] = namespace
|
|
|
|
auForEach(projsIdxs, function(idx)
|
|
initializeDependencyTree(projs[idx], true)
|
|
end)
|
|
|
|
|
|
_auFatalMsg = {}
|
|
_auFatalMsg["starting projects"] = namespace
|
|
auForEach(projsIdxs, function(idx)
|
|
_auLinkGuard = {}
|
|
_auLinkGuard[projs[idx].info.name]= {}
|
|
processProject(projs[idx].info.name)
|
|
end)
|
|
end
|
|
|
|
local function processSolution()
|
|
local hack = {}
|
|
|
|
local hackIdx = {}
|
|
auForEach(_auProjects, function(proj)
|
|
table.insert(hackIdx, proj.info.namespace)
|
|
end)
|
|
|
|
table.sort(hackIdx, function(a, b)
|
|
return a:upper() < b:upper()
|
|
end)
|
|
|
|
auForEach(hackIdx, processNS)
|
|
end
|
|
|
|
local function attemptNS(ns)
|
|
local attemptLoad = false
|
|
if (not _auNamespacesEmitted[ns]) then
|
|
auStartGroup(ns) -- only print the group once
|
|
|
|
attemptLoad = true
|
|
end
|
|
|
|
group(ns)
|
|
return attemptLoad
|
|
end
|
|
|
|
processProject = function(name, required, noNs)
|
|
|
|
local a = _auProjects[name]
|
|
if (not a) then
|
|
if (required) then
|
|
auFatal("missing project: ", name)
|
|
else
|
|
return false
|
|
end
|
|
end
|
|
|
|
local oldBaeProjName = _auCurrentBaseProject
|
|
_auCurrentBaseProject = name;
|
|
|
|
-- ensure the project is initializd
|
|
processInit(a)
|
|
|
|
-- recursion protection
|
|
if (_auProjectsBlocked[name]) then
|
|
_auCurrentBaseProject = oldBaeProjName
|
|
return true
|
|
end
|
|
_auProjectsBlocked[name] = name
|
|
|
|
-- process all within the namespace before processing the requested project
|
|
local ns = a.info.namespace
|
|
local loadOthers = attemptNS(ns)
|
|
|
|
pushProject(a, function()
|
|
_auFatalMsg = {}
|
|
_auFatalMsg["processing project"] = a.info.name
|
|
a.processor:process()
|
|
_auFatalMsg = {}
|
|
end)
|
|
|
|
-- cont
|
|
if (loadOthers) then
|
|
_auNamespacesEmitted[ns] = "";
|
|
processNS(ns)
|
|
end
|
|
|
|
_auCurrentBaseProject = oldBaeProjName
|
|
|
|
return true
|
|
end
|
|
|
|
function isWeakCircularReference(depName)
|
|
local dep = _auProjects[depName]
|
|
if (not dep) then
|
|
return
|
|
end
|
|
|
|
-- TODO: recursion
|
|
for index, value in ipairs(dep.deps) do
|
|
if (value == _auCurrentProject or value == _auCurrentBaseProject) then
|
|
return true
|
|
end
|
|
end
|
|
|
|
return false
|
|
end
|
|
|
|
local function isProjectLoaded(name)
|
|
local a = _auProjects[name]
|
|
if (not a) then
|
|
return false
|
|
end
|
|
|
|
return a.isInitialized
|
|
end
|
|
|
|
local function getProjectProcessor(name)
|
|
if (not name) then
|
|
return
|
|
end
|
|
local scre = _auProjects[name]
|
|
if (not scre) then
|
|
return
|
|
end
|
|
return scre.processor
|
|
end
|
|
|
|
local function getProjectProcessorOrThrow(name)
|
|
local ret = getProjectProcessor(name)
|
|
|
|
if (not ret) then
|
|
auFatal("Missing project", name)
|
|
end
|
|
|
|
return ret
|
|
end
|
|
|
|
local function getCurrentProjectName()
|
|
return _auCurrentProject
|
|
end
|
|
|
|
local function getBaseProjectName()
|
|
return _auCurrentBaseProject
|
|
end
|
|
|
|
local function includeAuProject(dep, soft)
|
|
local processor = getProjectProcessor(dep)
|
|
if (not processor) then
|
|
return false
|
|
end
|
|
|
|
local processor = getProjectProcessor(dep)
|
|
if (not processor) then
|
|
return false
|
|
end
|
|
|
|
local a = _auProjects[dep]
|
|
if (not a) then
|
|
if (not soft) then
|
|
auFatal("missing project: ", dep)
|
|
else
|
|
return false
|
|
end
|
|
end
|
|
|
|
pushProject(a, function()
|
|
_auFatalMsg["processing project ref"] = a.info.name
|
|
processor:handleReference(isWeakCircularReference(dep))
|
|
_auFatalMsg["processing project ref"] = nil
|
|
end)
|
|
return true
|
|
end
|
|
|
|
local function linkAuProject(dep, soft)
|
|
local processor = getProjectProcessor(dep)
|
|
if (not processor) then
|
|
return false
|
|
end
|
|
|
|
local a = _auProjects[dep]
|
|
if (not a) then
|
|
if (not soft) then
|
|
auFatal("missing project: ", dep)
|
|
else
|
|
return false
|
|
end
|
|
end
|
|
|
|
local linkStart = false
|
|
|
|
if (auGetCurrentProjectMeta()) then
|
|
if (_auLinkGuard[dep] ) then
|
|
return
|
|
end
|
|
_auLinkGuard[dep] = dep
|
|
end
|
|
|
|
if (not _auLinkGuardStart) then
|
|
_auLinkGuardStart = true
|
|
linkStart = true
|
|
end
|
|
|
|
if (auGetBaseProjectName() ~= dep) then
|
|
|
|
dependson(dep)
|
|
|
|
--if (not processor:getMeta().isStatic) then
|
|
pushProject(a, function()
|
|
_auFatalMsg["processing project link"] = a.info.name
|
|
processor:handleLink()
|
|
_auFatalMsg["processing project link"] = nil
|
|
end)
|
|
--end
|
|
end
|
|
|
|
|
|
if (linkStart) then
|
|
_auLinkGuard = {}
|
|
_auLinkGuardStart = false
|
|
end
|
|
return true
|
|
end
|
|
|
|
local function importAndLinkProject(dep, soft)
|
|
local processor = getProjectProcessorOrThrow(dep)
|
|
|
|
includeAuProject(dep, soft)
|
|
|
|
local this = auGetCurrentProjectMeta()
|
|
if (this) then
|
|
if (this.isStatic) then
|
|
return true
|
|
end
|
|
end
|
|
|
|
linkAuProject(dep, soft)
|
|
return true
|
|
end
|
|
|
|
|
|
local function addFeature(feature)
|
|
--print("adding feature ", feature)
|
|
|
|
local script = Aurora.Settings.sAbsRoot .. Aurora.Settings.sRelScripts .. "/Features/" .. feature:lower() .. ".lua"
|
|
|
|
if (not os.isfile(script)) then
|
|
auFatal("missing feature", feature, script)
|
|
return
|
|
end
|
|
|
|
auRequireAbs(script)()
|
|
end
|
|
|
|
return {
|
|
addVisit = addVisit,
|
|
addScript = addScript,
|
|
addFeature = addFeature,
|
|
linkAuProject = linkAuProject,
|
|
includeAuProject = includeAuProject,
|
|
importAndLinkProject = importAndLinkProject,
|
|
getProjectProcessor = getProjectProcessor,
|
|
isProjectLoaded = isProjectLoaded,
|
|
getCurrentProjectName = getCurrentProjectName,
|
|
processSolution = processSolution,
|
|
getBaseProjectName = getBaseProjectName
|
|
} |