Skip to content
This repository has been archived by the owner on Jul 7, 2024. It is now read-only.

Commit

Permalink
File based tasks (#3)
Browse files Browse the repository at this point in the history
  • Loading branch information
SquidDev committed Dec 12, 2014
1 parent 6b1a694 commit 800fec7
Show file tree
Hide file tree
Showing 10 changed files with 484 additions and 151 deletions.
2 changes: 1 addition & 1 deletion Howl.lua
Original file line number Diff line number Diff line change
Expand Up @@ -19,7 +19,7 @@ options
:Alias "h"
:Description "Print this help"

local tasks = Task.Tasks()
local tasks = Runner.Factory()
local currentTask = options:Arguments()[1]

options:OnChanged(function(options)
Expand Down
32 changes: 25 additions & 7 deletions Howlfile.lua
Original file line number Diff line number Diff line change
@@ -1,6 +1,9 @@
Options:Default("trace")
Options:Default("with-minify")

local sources = Dependencies(CurrentDirectory)
sources:Main "Howl.lua"
:Depends "Task"
:Depends "Runner"
:Depends "ArgParse"
:Depends "HowlFile"

Expand All @@ -9,18 +12,29 @@ sources:Main "Howl.lua"
:Depends "Combiner"
:Depends "Depends"

-- Task files
sources:File "tasks/Context.lua"
:Name "Context"
:Depends "Utils"

sources:File "tasks/Task.lua"
:Name "Task"
:Depends "Utils"

sources:File "tasks/Runner.lua"
:Name "Runner"
:Depends "Utils"
:Depends "Task"
:Depends "Context"

sources:File "depends/Combiner.lua"
:Alias "Combiner"
:Depends "Depends"
:Depends "Task"
:Depends "Runner"

sources:File "tasks/Extensions.lua"
:Alias "Task.Extensions"
:Depends "Task"
:Depends "Runner"
:Depends "Utils"

sources:File "core/Utils.lua" :Name "Utils"
Expand Down Expand Up @@ -58,9 +72,13 @@ if Options:Get("with-minify") then

sources.mainFiles[1]
:Depends "Minify"

end

Tasks:Clean("clean", fs.combine(CurrentDirectory, "build"))
Tasks:Combine("combine", sources, "build/Howl.lua", {"clean"})
Tasks:Minify("minify", File "build/Howl.lua", File "build/Howl.min.lua", {"combine"})
Tasks:Clean("clean", File "build")
Tasks:Combine("combine", sources, File "build/Howl.lua", {"clean"})

Tasks:MinifyAll()

Tasks:AddTask "minify"
:Requires(File "build/Howl.min.lua")
:Description("Produces a minified version of the code")
5 changes: 4 additions & 1 deletion _Bootstrap.lua
Original file line number Diff line number Diff line change
Expand Up @@ -31,9 +31,12 @@ xpcall(setfenv(function()
Dump = doFile("core/Dump.lua")
Depends = doFile("depends/Depends.lua")

Context = doFile("tasks/Context.lua")
Task = doFile("tasks/Task.lua")
doFile("depends/Combiner.lua")
Runner = doFile("tasks/Runner.lua")
doFile("tasks/Extensions.lua")

doFile("depends/Combiner.lua")
HowlFile = doFile("core/HowlFileLoader.lua")

TokenList = doFile("lexer/TokenList.lua")
Expand Down
15 changes: 15 additions & 0 deletions core/Utils.lua
Original file line number Diff line number Diff line change
Expand Up @@ -76,6 +76,20 @@ local function CreateLookup(tbl)
return tbl
end

--- Checks if two tables are equal
-- @tparam table a
-- @tparam table b
-- @tparam boolean If they match
local function MatchTables(a, b)
local length = #a
if length ~= #b then return false end

for i=1, length do
if a[i] ~= b[i] then return false end
end
return true
end

-- Hacky docs for objects

--- Print messages
Expand All @@ -96,4 +110,5 @@ return {

EscapePattern = EscapePattern,
CreateLookup = CreateLookup,
MatchTables = MatchTables,
}
14 changes: 8 additions & 6 deletions depends/Combiner.lua
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
--- Combines multiple files into one file
-- Extends @{Depends.Dependencies} and @{Task.TaskRunner} classes
-- Extends @{Depends.Dependencies} and @{Runner.Runner} classes
-- @module Combiner

local functionLoaderName = "_W"
Expand All @@ -23,7 +23,7 @@ function Depends.Dependencies:Combiner(outputFile)
local path = self.path
local shouldExport = self.shouldExport

local output = fs.open(fs.combine(path, outputFile), "w")
local output = fs.open(outputFile, "w")
assert(output, "Could not create" .. outputFile)

output.writeLine(functionLoader)
Expand Down Expand Up @@ -77,10 +77,12 @@ end
-- @tparam @{Depends.Dependencies} dependencies The dependencies to compile
-- @tparam string outputFile The file to save to
-- @tparam table taskDepends A list of @{Task.Task|tasks} this task requires
-- @treturn Task.TaskRunner The task runner (for chaining)
-- @see Task.TaskRunner
function Task.TaskRunner:Combine(name, dependencies, outputFile, taskDepends)
-- @treturn Runner.Runner The task runner (for chaining)
-- @see Runner.Runner
function Runner.Runner:Combine(name, dependencies, outputFile, taskDepends)
return self:AddTask(name, taskDepends, function()
dependencies:Combiner(outputFile)
end):Description("Combines files into '" .. outputFile .. "'")
end)
:Description("Combines files into '" .. outputFile .. "'")
:Produces(outputFile)
end
44 changes: 32 additions & 12 deletions lexer/Tasks.lua
Original file line number Diff line number Diff line change
@@ -1,23 +1,43 @@
--- Tasks for the lexer
-- @module lexer.Tasks

local function MinifyFile(inputFile, outputFile)
local input = fs.open(inputFile, "r")
local contents = input.readAll()
input.close()

local contents = Rebuild.Minify(Parse.ParseLua(Parse.LexLua(contents)))

local result = fs.open(outputFile, "w")
result.write(contents)
result.close()
end


--- A task that minifies a source file
-- @tparam string name Name of the task
-- @tparam string inputFile The input file
-- @tparam string outputFile The file to save to
-- @tparam table taskDepends A list of @{Task.Task|tasks} this task requires
-- @treturn Task.TaskRunner The task runner (for chaining)
-- @see Task.TaskRunner
function Task.TaskRunner:Minify(name, inputFile, outputFile, taskDepends)
-- @treturn Runner.Runner The task runner (for chaining)
-- @see Runner.Runner
function Runner.Runner:Minify(name, inputFile, outputFile, taskDepends)
return self:AddTask(name, taskDepends, function()
local input = fs.open(inputFile, "r")
local contents = input.readAll()
input.close()

local contents = Rebuild.Minify(Parse.ParseLua(Parse.LexLua(contents)))
MinifyFile(inputFile, outputFile)
end)
:Description("Minifies '" .. fs.getName(inputFile) .. "'' into '" .. fs.getName(outputFile) .. "'")
:Requires(inputFile)
:Produces(outputFile)
end

local result = fs.open(outputFile, "w")
result.write(contents)
result.close()
end):Description("Minifies '" .. fs.getName(inputFile) .. "'' into '" .. fs.getName(outputFile) .. "'")
--- A task that minifies to a pattern instead
-- @tparam string name Name of the task
-- @tparam string inputPattern The pattern to read in
-- @tparam string outputPattern The pattern to produce
-- @treturn Runner.Runner The task runner (for chaining)
function Runner.Runner:MinifyAll(name, inputPattern, outputPattern)
name = name or "_minify"
return self:AddTask(name, {}, MinifyFile)
:Description("Minifies files")
:Maps(inputPattern or "wild:*.lua", outputPattern or "wild:*.min.lua")
end
162 changes: 162 additions & 0 deletions tasks/Context.lua
Original file line number Diff line number Diff line change
@@ -0,0 +1,162 @@
--- Manages the running of tasks
-- @module tasks.Context

--- Holds task contexts
-- @type Context
local Context = {}

function Context:DoRequire(path, quite)
if self.filesProduced[path] then return true end

-- Check for normal files
local task = self.producesCache[path]
if task then
self.filesProduced[path] = true
return self:Run(task)
end

-- Check for file mapping
task = self.normalMapsCache[path]
local from, name
local to = path
if task then
self.filesProduced[path] = true

-- Convert task.Pattern.From to path
-- (which should be task.Pattern.To)
name = task.Name
from = task.Pattern.From
end

for match, data in pairs(self.patternMapsCache) do
if path:match(match) then
-- Run task, replacing match with the replacement pattern
name = data.Name
from = path:gsub(match, data.Pattern.From)
break
end
end

if name then
local canCreate = self:DoRequire(from, quite)
if not canCreate and not fs.exists(from) then
if not quite then
Utils.PrintError("Cannot find '" .. from .. "'")
end
return false
end

return self:Run(name, from, to)
end


self.filesProduced[path] = true
if not quite then
Utils.PrintError("Cannot find a task matching '" .. path .. "'")
end
return false
end

--- Run a task
-- @tparam string|Task.Task task The name of the task or a Task object
-- @param ... The arguments to pass to it
-- @treturn boolean Success in running the task?
function Context:Run(name, ...)
if self.ran[task] then return true end

local task
if type(name) == "string" then
task = self.tasks[name]

if not task then
Utils.PrintError("Cannot find a task called '" .. name .."'")
return false
end
elseif not task or not task.Run then
Utils.PrintError("Cannot call task as it has no 'Run' method")
return false
end

self.ran[task] = true
return task:Run(self, ...)
end

--- Start the task process
-- @tparam string The name of the task (Optional)
-- @tretrn boolean Success in running the task?
function Context:Start(name)
local task
if name then
task = self.tasks[name]
else
task = self.default
name = "<default>"
end

if not task then
Utils.PrintError("Cannot find a task called '" .. name .. "'")
return false
end

return task:Run(self)
end

--- Build a cache of tasks
-- This is used to speed up finding file based tasks
-- @treturn Context The current context
function Context:BuildCache()
local producesCache = {}
local patternMapsCache = {}
local normalMapsCache = {}

self.producesCache = producesCache
self.patternMapsCache = patternMapsCache
self.normalMapsCache = normalMapsCache

for name, task in pairs(self.tasks) do
local produces = task.produces
if produces then
for _, file in ipairs(produces) do
local existing = producesCache[file]
if existing then
error(string.format("Both '%s' and '%s' produces '%s'", existing, name, file))
end
producesCache[file] = name
end
end

local maps = task.maps
if maps then
for _, pattern in ipairs(maps) do
-- We store two separate caches for each of them
local toMap = (pattern.Type == "Pattern" and patternMapsCache or normalMapsCache)
local match = pattern.To
local existing = toMap[match]
if existing then
error(string.format("Both '%s' and '%s' match '%s'", existing, name, match))
end
toMap[match] = {Name = name, Pattern = pattern}
end
end
end

return self
end

local function Factory(runner)
return setmetatable({
ran = {}, -- List of task already run
filesProduced = {},
tasks = runner.tasks,
default = runner.default,

Traceback = runner.Traceback,
ShowTime = runner.ShowTime,
}, {__index = Context}):BuildCache()
end

--- @export
return {
Factory = Factory,
Context = Context,
}
Loading

0 comments on commit 800fec7

Please sign in to comment.