Skip to content

Commit

Permalink
Custom option
Browse files Browse the repository at this point in the history
  • Loading branch information
jlaurens committed Jul 8, 2024
1 parent d888be0 commit 8836641
Show file tree
Hide file tree
Showing 4 changed files with 252 additions and 13 deletions.
147 changes: 147 additions & 0 deletions build-pre.lua
Original file line number Diff line number Diff line change
@@ -0,0 +1,147 @@
-- Configuration script for LaTeX "l3build" files

do
-- this block is testing declare_option
-- we temporarily replace option_list to make tests
-- TODO: make it a separate test available with target `check``
-- using custom test types (forthcoming)
local function expect(torf,f, msg)
local old_option_list = option_list
option_list = {}
local status, err = pcall(f)
assert(not status == not torf, debug.traceback(msg or err, 2))
option_list = old_option_list
end
expect(true, function()end)
expect(false, function()error("")end)
expect(false,function()
declare_option(
1, {
type = "boolean",
})
end, "Names are strings.")
expect(false,function()
declare_option(
"", {
type = "boolean",
})
end, "Names are non void strings.")
expect(false,function()
declare_option(
"", {
type = "boolean",
})
end, "Long names should not start with '-'.")
expect(false,function()
declare_option(
"12", "")
end, "t should be a table.")
expect(false,function()
declare_option(
"12", {
})
end, "type field is required.")
expect(false,function()
declare_option(
"12", {
type = 0
})
end, "type field must be one of `boolean`, `string`, `table`.")
expect(true,function()
declare_option(
"12", {
type = "boolean",
foo = "bar",
})
assert(option_list["12"].type == "boolean")
assert(option_list["12"]["foo"] == "bar")
end)
expect(false,function()
declare_option(
"12", {
type = "boolean",
})
declare_option(
"12", {
type = "boolean",
})
end, "Name is already used")
-- update_option:
expect(false,function()
update_option(
"foo", "")
end, "Bad argument")
expect(false,function()
update_option(
"foo", {
type = "boolean",
})
end, "Only existing option")
expect(true,function()
declare_option(
"foo", {
type = "boolean",
})
update_option(
"foo", {
})
end)
expect(true,function()
declare_option(
"foo", {
type = "boolean",
})
update_option(
"foo", {
type = "boolean",
})
end)
expect(false,function()
declare_option(
"foo", {
type = "boolean",
})
update_option(
"foo", {
type = "list",
})
end, "Different types")
expect(true,function()
declare_option(
"foo", {
type = "boolean",
foo = "bar"
})
assert(option_list["foo"]["foo"] == "bar", "foo->bar")
update_option(
"foo", {
foo = "baz"
})
assert(option_list["foo"]["foo"] == "baz", "foo->baz")
end)
expect(true,function()
declare_option(
"foo", {
type = "boolean",
foo = "bar"
})
assert(option_list["foo"]["foo"] == "bar", "foo->bar")
assert(option_list["foo"]["bar"] == nil, "bar->nil")
update_option(
"foo", {
foo = "baz",
bar = "foo"
}, true)
assert(option_list["foo"]["foo"] == "bar", "foo->bar")
assert(option_list["foo"]["bar"] == "foo", "bar->foo")
end)
end

-- test if `custom_option` will be available in `build.lua`
declare_option(
"custom_option", {
type = "string",
desc = "Custom option"
})

print("File `build-pre.lua` loaded")
12 changes: 12 additions & 0 deletions build.lua
Original file line number Diff line number Diff line change
Expand Up @@ -144,6 +144,18 @@ function docinit_hook()
return 0
end

assert(option_list.custom_option.type == "string")
if options.custom_option then
print("custom_option: "..options.custom_option)
end
if options["target"] ~= "help" then
local cmd = "texlua ./" .. module .. ".lua --help"
local f = assert(io.popen(cmd,"r"))
local help_text = assert(f:read("*a"))
f:close()
assert(help_text:find("Custom option"),"No \"Custom option\" in the help")
end

if not release_date then
dofile("./l3build.lua")
end
75 changes: 68 additions & 7 deletions l3build-arguments.lua
Original file line number Diff line number Diff line change
Expand Up @@ -22,18 +22,21 @@ for those people who are interested.
--]]

local exit = os.exit
local stderr = io.stderr
local exit = os.exit
local stderr = io.stderr

local find = string.find
local gmatch = string.gmatch
local match = string.match
local sub = string.sub
local string = string
local find = string.find
local gmatch = string.gmatch
local match = string.match
local sub = string.sub

local insert = table.insert
local table = table
local insert = table.insert

-- Parse command line options

---@type {[string]: L3BOptionData}
option_list =
{
config =
Expand Down Expand Up @@ -163,6 +166,64 @@ option_list =
}
}

local function validate(fname, name, t)
assert(type(name)=="string" and #name>1 and name[1] ~= "-",
"Unexpected name in "..fname..": "..tostring(name)..'/'..type(name))
assert(type(t)=="table",
"Unexpected t in "..fname..": "..tostring(t)..'/'..type(t))
assert(t.short == nil or (type(t.short)=="string" and #t.short==1),
"Unexpected short value in "..fname..": "..tostring(t.short)..'/'..type(t.short))
assert(t.desc == nil or type(t.desc)=="string",
"Unexpected desc value in "..fname..": "..tostring(t.desc)..'/'..type(t.desc))
end

---Declare custom option
---@param name string the long name of the option
---@param t L3BOptionData the option data table as will be available from `option_list`
function declare_option(name, t)
validate("declare_option", name, t)
assert(t.type=="boolean" or t.type=="string" or t.type=="table",
"Unexpected type value in declare_option: "..tostring(t.type)..'/'..type(t.type))
local tt = option_list[name]
assert(not tt, "Unexpected name in declare_option: "..name.." aleady used.")
option_list[name] = t -- not a copy
end

---Update custom option
---@param name string the long name of the option, must have been used
---@param t L3BOptionUpdate the option update data table
---@param provide boolean?
function update_option(name, t, provide)
local tt = option_list[name]
assert(tt, "Unexpected name in update_option: missing `declare_option("..name..", ...)`")
assert(t.type == nil or t.type==tt.type,
"Unexpected type change in declare_option: option "..name.." has type "..tt.type)
assert(tt, "Unexpected name in update_option: missing `declare_option("..name..", ...)`")
if provide then -- replace each field
for k,v in pairs(t) do
if tt[k] == nil then
tt[k] = v
end
end
else -- add only missing fields
for k,v in pairs(t) do
tt[k] = v
end
end
end
-- load `build-pre.lua` if any.
-- actually this preparation file only concerns arguments.
do
local f = loadfile("build-pre.lua", "t")
if f then
f()
end
end

function declare_option(name, t) -- undefine declare_option
error("`declare_option` is only available in `pre-build.lua`")
end

-- This is done as a function (rather than do ... end) as it allows early
-- termination (break)
local function argparse()
Expand Down
31 changes: 25 additions & 6 deletions l3build.dtx
Original file line number Diff line number Diff line change
Expand Up @@ -1995,12 +1995,31 @@
% \end{itemize}
% The functions |func|, |bundle_func| and |pre| must return 0 on success.
%
% The list of options (switches) is controlled by the |option_list| table.
% The name of each entry in the table is the \enquote{long} version of the
% option. Each entry requires a |type|, one of |boolean|, |string| or
% |table|. As for targets, each entry should have a |desc| to construct
% the |help()|. It is also possible to provide a |short| name for the option:
% this should be a single letter.
% In order to add custom options, a preparation script file named
% |build-pre.lua| is put near |build.lua|.
% It contains
% \texttt{declare_option(\meta{name},\meta{table})} instructions where
% \meta{name} is the \enquote{long} version of the option.
% The \meta{table} requires a |type| key with value
% \begin{itemize}
% \item |"boolean"| for a switch like |--dry-run|,
% \item |"string"| for an option like |--message=|\meta{text} or
% \item |"list"| for an option like
% |--engine=|\meta{engine_1}|,|\meta{engine_2}|,|...
% \end{itemize}
% The value for optional key |short| is a one character long
% string for the \enquote{short} version of the option.
% The value for key |desc|, if any, is used to construct the |help()|.
% After such instruction, we have
% \texttt{option_list[\meta{name}]==\meta{table}}.
%
% The |declare_option| function is not available in |build.lua|, but
% instruction \texttt{update_option(\meta{name},\meta{other table},^^A
% \meta{provide})} allows to modify the initial option data in a consistent
% manner. Entries in \meta{other table}
% overwrite existing entries in \meta{table} except when the \meta{provide}
% argument is truthy. However, changing the |type| of an option is not allowed.
%
%
% \subsection{Customising the manifest file}
% \label{sec:manifest}
Expand Down

0 comments on commit 8836641

Please sign in to comment.