--!The Make-like Build Utility based on Lua
--
-- XMake is free software; you can redistribute it and/or modify
-- it under the terms of the GNU Lesser General Public License as published by
-- the Free Software Foundation; either version 2.1 of the License, or
-- (at your option) any later version.
--
-- XMake is distributed in the hope that it will be useful,
-- but WITHOUT ANY WARRANTY; without even the implied warranty of
-- MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
-- GNU Lesser General Public License for more details.
--
-- You should have received a copy of the GNU Lesser General Public License
-- along with XMake;
-- If not, see http://www.gnu.org/licenses/
--
-- Copyright (C) 2015 - 2016, ruki All rights reserved.
--
-- @author ruki
-- @file main.lua
--
-- imports
import("core.base.option")
import("core.project.cache")
import("core.project.config")
import("core.project.history")
-- the macro directories
function _directories()
return { path.join(config.directory(), "macros")
, path.join(os.scriptdir(), "macros")}
end
-- the macro directory
function _directory(macroname)
-- find macro directory
local macrodir = nil
for _, dir in ipairs(_directories()) do
-- found?
if os.isfile(path.join(dir, macroname .. ".lua")) then
macrodir = dir
break
end
end
-- check
assert(macrodir, "macro(%s) not found!", macroname)
-- ok
return macrodir
end
-- the readable macro file
function _rfile(macroname)
-- is anonymous?
if macroname == '.' then
macroname = "anonymous"
end
-- get it
return path.join(_directory(macroname), macroname .. ".lua")
end
-- the writable macro file
function _wfile(macroname)
-- is anonymous?
if macroname == '.' then
macroname = "anonymous"
end
-- get it
return path.join(path.join(config.directory(), "macros"), macroname .. ".lua")
end
-- list macros
function _list()
-- trace
cprint("${bright}macros:")
-- find all macros
for _, dir in ipairs(_directories()) do
local macrofiles = os.match(path.join(dir, "*.lua"))
for _, macrofile in ipairs(macrofiles) do
-- get macro name
local macroname = path.basename(macrofile)
if macroname == "anonymous" then
macroname = "."
end
-- show it
print(" " .. macroname)
end
end
end
-- show macro
function _show(macroname)
-- show it
local file = _rfile(macroname)
if os.isfile(file) then
io.cat(file)
else
raise("macro(%s) not found!", macroname)
end
end
-- clear all macros
function _clear()
-- clear all
os.rm(path.join(config.directory(), "macros"))
end
-- delete macro
function _delete(macroname)
-- remove it
if os.isfile(_wfile(macroname)) then
os.rm(_wfile(macroname))
elseif os.isfile(_rfile(macroname)) then
raise("macro(%s) cannot be deleted!", macroname)
else
raise("macro(%s) not found!", macroname)
end
-- trace
cprint("${bright}delete macro(%s) ok!", macroname)
end
-- import macro
function _import(macrofile, macroname)
-- import all macros
if os.isdir(macrofile) then
-- the macro directory
local macrodir = macrofile
local macrofiles = os.match(path.join(macrodir, "*.lua"))
for _, macrofile in ipairs(macrofiles) do
-- the macro name
macroname = path.basename(macrofile)
-- import it
os.cp(macrofile, _wfile(macroname))
-- trace
cprint("${bright}import macro(%s) ok!", macroname)
end
else
-- import it
os.cp(macrofile, _wfile(macroname))
-- trace
cprint("${bright}import macro(%s) ok!", macroname)
end
end
-- export macro
function _export(macrofile, macroname)
-- export all macros
if os.isdir(macrofile) then
-- the output directory
local outputdir = macrofile
-- export all macros
for _, dir in ipairs(_directories()) do
local macrofiles = os.match(path.join(dir, "*.lua"))
for _, macrofile in ipairs(macrofiles) do
-- export it
os.cp(macrofile, outputdir)
-- trace
cprint("${bright}export macro(%s) ok!", path.basename(macrofile))
end
end
else
-- export it
os.cp(_rfile(macroname), macrofile)
-- trace
cprint("${bright}export macro(%s) ok!", macroname)
end
end
-- begin to record macro
function _begin()
-- patch begin tag to the history: cmdlines
history.save("cmdlines", "__macro_begin__")
end
-- end to record macro
function _end(macroname)
-- load the history: cmdlines
local cmdlines = history.load("cmdlines")
-- get the last macro block
local begin = false
local block = {}
if cmdlines then
local total = #cmdlines
local index = total
while index ~= 0 do
-- the command line
local cmdline = cmdlines[index]
-- found begin? break it
if cmdline == "__macro_begin__" then
begin = true
break
end
-- found end? break it
if cmdline == "__macro_end__" then
break
end
-- ignore "xmake m .." and "xmake macro .."
if not cmdline:find("xmake%s+macro%s*") and not cmdline:find("xmake%s+m%s*") then
-- save this command line to block
table.insert(block, 1, cmdline)
end
-- the previous line
index = index - 1
end
end
-- the begin tag not found?
if not begin then
raise("please run: 'xmake macro --begin' first!")
end
-- patch end tag to the history: cmdlines
history.save("cmdlines", "__macro_end__")
-- open the macro file
local file = io.open(_wfile(macroname), "w")
-- save the macro begin
file:print("function main(argv)")
-- save the macro block
for _, cmdline in ipairs(block) do
-- save command line
file:print(" os.exec(\"%s\")", (cmdline:gsub("[\\\"]", function (w) return "\\" .. w end)))
end
-- save the macro end
file:print("end")
-- exit the macro file
file:close()
-- show this macro
_show(macroname)
-- trace
cprint("${bright}define macro(%s) ok!", macroname)
end
-- run macro
function _run(macroname)
-- is anonymous?
if macroname == '.' then
macroname = "anonymous"
end
-- load macro
local macro = import(macroname, {rootdir = _directory(macroname)})
-- run macro
macro.main(option.get("arguments") or {})
-- trace
cprint("${bright}run macro(%s) ok!", macroname)
end
-- main
function main()
-- list macros
if option.get("list") then
_list()
-- show macro
elseif option.get("show") then
_show(option.get("name"))
-- clear macro
elseif option.get("clear") then
_clear()
-- delete macro
elseif option.get("delete") then
_delete(option.get("name"))
-- import macro
elseif option.get("import") then
_import(option.get("import"), option.get("name"))
-- export macro
elseif option.get("export") then
_export(option.get("export"), option.get("name"))
-- begin to record macro
elseif option.get("begin") then
_begin()
-- end to record macro
elseif option.get("end") then
_end(option.get("name"))
-- run macro
else
_run(option.get("name"))
end
end