diff --git a/.cirrus.yml b/.cirrus.yml index 378771fe8..1b6c19e34 100644 --- a/.cirrus.yml +++ b/.cirrus.yml @@ -15,13 +15,13 @@ task: fingerprint_script: cat Makefile-fonts luarocks_cache: folder: /usr/local/lib/luarocks - fingerprint_script: cat sile-dev-1.rockspec + fingerprint_script: cat sile.rockspec.in luarocks_lua_cache: folder: /usr/local/share/lua - fingerprint_script: cat sile-dev-1.rockspec + fingerprint_script: cat sile.rockspec.in luarocks_lib_cache: folder: /usr/local/lib/lua - fingerprint_script: cat sile-dev-1.rockspec + fingerprint_script: cat sile.rockspec.in dependencies_script: - pkg install -y autoconf automake fontconfig GentiumPlus git gmake harfbuzz libtool pkgconf png - pkg install -y lua54 lua54-lpeg lua54-luafilesystem lua54-luarocks lua54-luasec lua54-luasocket diff --git a/.github/workflows/build.yml b/.github/workflows/build.yml index f9f35e4d9..034b41eb1 100644 --- a/.github/workflows/build.yml +++ b/.github/workflows/build.yml @@ -27,7 +27,7 @@ jobs: with: path: | lua_modules - key: luarocks-${{ hashFiles('Makefile-luarocks', 'sile-dev-1.rockspec') }} + key: luarocks-${{ hashFiles('Makefile-luarocks', 'sile.rockspec.in') }} - name: Fetch tags run: | git fetch --prune --tags ||: diff --git a/.github/workflows/coverage.yml b/.github/workflows/coverage.yml index 1b4ac17d4..9debdb9c7 100644 --- a/.github/workflows/coverage.yml +++ b/.github/workflows/coverage.yml @@ -31,7 +31,7 @@ jobs: with: path: | lua_modules - key: luarocks-luajit-${{ hashFiles('Makefile-luarocks', 'sile-dev-1.rockspec') }} + key: luarocks-luajit-${{ hashFiles('Makefile-luarocks', 'sile.rockspec.in') }} - name: Fetch tags run: | git fetch --prune --tags ||: diff --git a/.github/workflows/test.yml b/.github/workflows/test.yml index 5c4eda17c..0fccb5582 100644 --- a/.github/workflows/test.yml +++ b/.github/workflows/test.yml @@ -38,7 +38,7 @@ jobs: with: path: | lua_modules - key: luarocks-${{ matrix.luaVersion[0] }}-${{ hashFiles('Makefile-luarocks', 'sile-dev-1.rockspec') }} + key: luarocks-${{ matrix.luaVersion[0] }}-${{ hashFiles('Makefile-luarocks', 'sile.rockspec.in') }} - name: Fetch tags run: | git fetch --prune --tags ||: diff --git a/.gitignore b/.gitignore index 5afcaef87..76a9c3b23 100644 --- a/.gitignore +++ b/.gitignore @@ -76,6 +76,7 @@ tags Makefile-distfiles documentation/*.pdf gource.webm +*.rockspec .fonts/* .sources/* /sile @@ -87,6 +88,7 @@ sile.1 *.so core/version.lua core/features.lua +core/pathsetup.lua # Nix symlink to builds /result diff --git a/.luacheckrc b/.luacheckrc index 55574cc41..bb102010f 100644 --- a/.luacheckrc +++ b/.luacheckrc @@ -26,6 +26,8 @@ globals = { "luautf8", "pl", "fluent", + "extendSilePath", + "executablePath", "SYSTEM_SILE_PATH", "SHARED_LIB_EXT" } diff --git a/.luarc.json b/.luarc.json index 3b7cf8fcd..16515bea9 100644 --- a/.luarc.json +++ b/.luarc.json @@ -7,6 +7,8 @@ "luautf8", "pl", "fluent", + "extendSilePath", + "executablePath", "SYSTEM_SILE_PATH", "SHARED_LIB_EXT" ], diff --git a/Makefile.am b/Makefile.am index 5ffe5aac6..b9b52da31 100644 --- a/Makefile.am +++ b/Makefile.am @@ -50,7 +50,7 @@ _MANUAL = $(MANUAL) endif nobase_dist_pkgdata_DATA = $(SILEDATA) $(LUALIBRARIES) -nobase_nodist_pkgdata_DATA = core/features.lua core/version.lua $(LUAMODULES) +nobase_nodist_pkgdata_DATA = core/features.lua core/pathsetup.lua core/version.lua $(LUAMODULES) dist_man_MANS = sile.1 dist_doc_DATA = README.md CHANGELOG.md dist_pdf_DATA = $(_MANUAL) @@ -64,7 +64,7 @@ EXTRA_DIST += default.nix flake.nix flake.lock libtexpdf.git-rev shell.nix EXTRA_DIST += package.json # imported by both Nix and Docker EXTRA_DIST += $(MANUAL) -BUILT_SOURCES = .version core/features.lua core/version.lua Makefile-distfiles +BUILT_SOURCES = .version core/features.lua core/pathsetup.lua core/version.lua Makefile-distfiles CLEANFILES = $(bin_SCRIPTS) $(dist_man_MANS) $(BUILT_SOURCES) $(DEPFILES) $(ACTUALS) $(TESTPDFS) $(MANUAL) $(_BUILT_SUBDIRS) .version-prev diff --git a/build-aux/list-dist-files.sh.in b/build-aux/list-dist-files.sh.in index 3c0ae546a..c007dcb00 100755 --- a/build-aux/list-dist-files.sh.in +++ b/build-aux/list-dist-files.sh.in @@ -7,7 +7,7 @@ finder () { } printf '%s' "SILEDATA =" -finder core -name '*.lua' -not -name '*_spec.lua' -not -name 'version.lua' +finder core -name '*.lua' -not -name '*_spec.lua' -not -name 'version.lua' -not -name 'features.lua' -not -name 'pathsetup.lua' finder classes inputters languages outputters packages shapers typesetters pagebuilders -name '*.lua' -not -name '*_spec.lua' finder classes i18n packages -name '*.ftl' finder packages -name '*.svg' diff --git a/configure.ac b/configure.ac index 4981a75bc..91d041e16 100644 --- a/configure.ac +++ b/configure.ac @@ -245,11 +245,15 @@ adl_RECURSIVE_EVAL(["${libdir}/${TRANSFORMED_PACKAGE_NAME}"], [SILE_LIB_PATH]) AC_DEFINE_UNQUOTED([SILE_LIB_PATH],["${SILE_LIB_PATH}"],[Path for SILE libraries]) AC_SUBST([SILE_LIB_PATH]) +AC_SUBST([ROCKSPECWARNING], ["DO NOT EDIT! Modify template sile.rockspec.in"]) +AC_SUBST([ROCKREV], [1]) + AX_SUBST_MAN_DATE AC_CONFIG_FILES([build-aux/list-dist-files.sh], [chmod +x build-aux/list-dist-files.sh]) -AC_CONFIG_FILES([Makefile src/Makefile sile.1 core/features.lua core/version.lua]) +AC_CONFIG_FILES([Makefile src/Makefile sile.1 core/features.lua core/pathsetup.lua core/version.lua]) AC_CONFIG_FILES([sile tests/regressions.pl], [chmod +x sile tests/regressions.pl]) +AC_CONFIG_FILES([sile-dev-1.rockspec:sile.rockspec.in]) AC_ARG_PROGRAM diff --git a/core/cli.lua b/core/cli.lua index 2fc777046..423265de3 100644 --- a/core/cli.lua +++ b/core/cli.lua @@ -47,11 +47,6 @@ cli.parseArguments = function () opts.INPUT = "-" end SILE.input.filename = opts.INPUT - -- Turn slashes around in the event we get passed a path from a Windows shell - local filename = opts.INPUT:gsub("\\", "/") - -- Strip extension - SILE.masterFilename = string.match(filename, "(.+)%..-$") or filename - SILE.masterDir = SILE.masterFilename:match("(.-)[^%/]+$") end if opts.backend then SILE.backend = opts.backend diff --git a/core/pathsetup.lua.in b/core/pathsetup.lua.in new file mode 100644 index 000000000..ea9ad466f --- /dev/null +++ b/core/pathsetup.lua.in @@ -0,0 +1,72 @@ +local executable = debug.getinfo(3, "S").source +local luaversion = _VERSION:match("%d+%.%d+") + +-- Normalize possibly dirty Lua path formatting shortcut: /./ → / +-- Even leafo/gh-actions-luarocks takes this shortcut which inhibits duplicate cleanup +package.path = package.path:gsub("/%./", "/") +package.cpath = package.cpath:gsub("/%./", "/") + +local function prepend_and_dedup (segment, path) + local escaped = segment:gsub('[%-%.%+%[%]%(%)%$%^%%%?%*]','%%%1') -- copied from pl.utils.escape() which we can't load yet + local striped = path:gsub(("^%s"):format(escaped), ""):gsub((";%s"):format(escaped), "") + return ("%s;%s"):format(segment, striped) +end + +local function prependPath (path) + package.path = prepend_and_dedup(path .. "/?/init.lua", package.path) + package.path = prepend_and_dedup(path .. "/?.lua", package.path) +end + +local function prependCPath (path) + package.cpath = prepend_and_dedup(path .. "/?.@SHARED_LIB_EXT@", package.cpath) +end + +local function extendPaths (path, ours) + prependCPath(path) + prependPath(path) + if ours then + prependPath(path .. "/lua-libraries") + if "@SYSTEM_LUAROCKS_FALSE@" == "" then -- see ./configure --with[out]-system-luarocks + prependCPath(path .. "/lua_modules/lib/lua/" .. luaversion) + prependPath(path .. "/lua_modules/share/lua/" .. luaversion) + end + else + prependCPath(path .. "/sile") + prependPath(path .. "/sile") + end +end + +-- Facilitate loading SILE classes & packages from system LuaRocks +-- Also weed out CWD relative paths, we add them in a different order later +local luapath = {} +local extpath = {} +for path in package.path:gmatch("[^;]+") do + table.insert(extpath, tostring(path:gsub("%?", "sile/?"))) + table.insert(luapath, path) +end +package.path = table.concat(luapath, ";") + +extendPaths("@SILE_PATH@", true) +extendPaths("@SILE_LIB_PATH@", true) + +package.path = table.concat(extpath, ";") .. ";" .. package.path + +local pathvar = os.getenv("SILE_PATH") +if pathvar then + for path in string.gmatch(pathvar, "[^;]+") do + if not path:match("^./") and path:len() >= 1 then + extendPaths(path) + end + end +end + +local cwd = executable:gsub("(.*)(/.*)", "%1") +if cwd:match("^@") then -- Consider "ours" for the sake of Nix Flake + extendPaths(".", true) +else + if cwd ~= "./" then extendPaths(cwd) end + extendPaths(".") +end + +_G.extendSilePath = extendPaths +_G.executablePath = executable diff --git a/core/sile.lua b/core/sile.lua index d19f5cdf8..2a369b5a4 100644 --- a/core/sile.lua +++ b/core/sile.lua @@ -29,6 +29,9 @@ fluent = require("fluent")() -- Includes for _this_ scope local lfs = require("lfs") +-- Developer tooling profiler +local ProFi + SILE.utilities = require("core.utilities") SU = SILE.utilities -- regrettable global alias @@ -131,6 +134,14 @@ SILE.init = function () SILE.outputter = SILE.outputters.dummy() end SILE.pagebuilder = SILE.pagebuilders.base() + io.stdout:setvbuf("no") + if SU.debugging("profile") then + ProFi = require("ProFi") + ProFi:start() + end + if SILE.makeDeps then + SILE.makeDeps:add(executablePath) + end runEvals(SILE.input.evaluates, "evaluate") end @@ -306,6 +317,18 @@ function SILE.processFile (filename, format, options) filename = "STDIN" doc = io.stdin:read("*a") else + -- Turn slashes around in the event we get passed a path from a Windows shell + filename = filename:gsub("\\", "/") + if not SILE.masterFilename then + -- Strip extension + SILE.masterFilename = string.match(filename, "(.+)%..-$") or filename + end + if SILE.masterFilename and not SILE.masterDir then + SILE.masterDir = SILE.masterFilename:match("(.-)[^%/]+$") + end + if SILE.masterDir and SILE.masterDir:len() >= 1 then + extendSilePath(SILE.masterDir) + end filename = SILE.resolveFile(filename) if not filename then SU.error("Could not find file") @@ -356,7 +379,7 @@ function SILE.resolveFile (filename, pathprefix) candidates[#candidates+1] = "?" -- Iterate through the directory of the master file, the SILE_PATH variable, and the current directory -- Check for prefixed paths first, then the plain path in that fails - if SILE.masterFilename then + if SILE.masterDir then for path in SU.gtoke(SILE.masterDir..";"..tostring(os.getenv("SILE_PATH")), ";") do if path.string and path.string ~= "nil" then if pathprefix then candidates[#candidates+1] = pl.path.join(path.string, pathprefix, "?") end @@ -437,6 +460,13 @@ function SILE.finish () if not SILE.quiet then io.stderr:write("\n") end + if SU.debugging("profile") then + ProFi:stop() + ProFi:writeReport(SILE.masterFilename..'.profile.txt') + end + if SU.debugging("versions") then + SILE.shaper:debugVersions() + end end -- Internal libraries that run core SILE functions on load diff --git a/flake.lock b/flake.lock index d5602393a..04215e41a 100644 --- a/flake.lock +++ b/flake.lock @@ -17,12 +17,15 @@ } }, "flake-utils": { + "inputs": { + "systems": "systems" + }, "locked": { - "lastModified": 1667395993, - "narHash": "sha256-nuEHfE/LcWyuSWnS8t12N1wc105Qtau+/OdUAjtQ0rA=", + "lastModified": 1681202837, + "narHash": "sha256-H+Rh19JDwRtpVPAWp64F+rlEtxUWBAQW28eAi3SRSzg=", "owner": "numtide", "repo": "flake-utils", - "rev": "5aed5285a952e0b949eb3ba02c12fa4fcfef535f", + "rev": "cfacdce06f30d2b68473a46042957675eebb3401", "type": "github" }, "original": { @@ -53,11 +56,11 @@ }, "nixpkgs": { "locked": { - "lastModified": 1674487464, - "narHash": "sha256-Jgq50e4S4JVCYpWLqrabBzDp/1mfaxHCh8/OOorHTy0=", + "lastModified": 1682109806, + "narHash": "sha256-d9g7RKNShMLboTWwukM+RObDWWpHKaqTYXB48clBWXI=", "owner": "nixos", "repo": "nixpkgs", - "rev": "3954218cf613eba8e0dcefa9abe337d26bc48fd0", + "rev": "2362848adf8def2866fabbffc50462e929d7fffb", "type": "github" }, "original": { @@ -74,6 +77,21 @@ "gitignore": "gitignore", "nixpkgs": "nixpkgs" } + }, + "systems": { + "locked": { + "lastModified": 1681028828, + "narHash": "sha256-Vy1rq5AaRuLzOxct8nz4T6wlgyUR7zLU309k9mBC768=", + "owner": "nix-systems", + "repo": "default", + "rev": "da67096a3b9bf56a91d16901293e51ba5b49a27e", + "type": "github" + }, + "original": { + "owner": "nix-systems", + "repo": "default", + "type": "github" + } } }, "root": "root", diff --git a/sile-dev-1.rockspec b/sile-dev-1.rockspec deleted file mode 100644 index bd9ba0058..000000000 --- a/sile-dev-1.rockspec +++ /dev/null @@ -1,36 +0,0 @@ -package = "sile" -description = { - summary = "Simon’s Improved Layout Engine", - license = "MIT" -} -version = "dev-1" -source = { - url = "..." -} -dependencies = { - "lua >= 5.1", - "bit32", -- only required on Lua < 5.2, versions vary between Rock and VM provided - "cassowary == 2.3.2-1", - "cldr == 0.3.0-0", - "compat53 == 0.8-1", -- only required on Lua < 5.3 - "cosmo == 16.06.04-1", - "fluent == 0.2.0-0", - "linenoise == 0.9-1", - "loadkit == 1.1.0-1", - "lpeg == 1.0.2-1", - "lua-zlib == 1.2-2", - "lua_cliargs == 3.0-2", - "luaepnf == 0.3-2", - "luaexpat == 1.5.1-1", - "luafilesystem == 1.8.0-1", - "luarepl == 0.10-1", - "luasec == 1.3.1-1", - "luasocket == 3.1.0-1", - "luautf8 == 0.1.5-1", - "penlight == 1.13.1-1", - "vstruct == 2.1.1-1" -} -build = { - type = "builtin", - modules = {} -} diff --git a/sile.in b/sile.in index 94695fef6..e79b8647b 100755 --- a/sile.in +++ b/sile.in @@ -4,108 +4,32 @@ SYSTEM_SILE_PATH = "@SILE_PATH@" SHARED_LIB_EXT = "@SHARED_LIB_EXT@" -local executable = debug.getinfo(1, "S").source -local luaversion = _VERSION:match("%d+%.%d+") - --- Normalize possibly dirty Lua path formatting shortcut: /./ → / --- Even leafo/gh-actions-luarocks takes this shortcut which inhibits duplicate cleanup -package.path = package.path:gsub("/%./", "/") -package.cpath = package.cpath:gsub("/%./", "/") - -local function prepend_and_dedup (segment, path) - local escaped = segment:gsub('[%-%.%+%[%]%(%)%$%^%%%?%*]','%%%1') -- copied from pl.utils.escape() which we can't load yet - local striped = path:gsub(("^%s"):format(escaped), ""):gsub((";%s"):format(escaped), "") - return ("%s;%s"):format(segment, striped) -end - -local function prependPath (path) - package.path = prepend_and_dedup(path .. "/?/init.lua", package.path) - package.path = prepend_and_dedup(path .. "/?.lua", package.path) -end - -local function prependCPath (path) - package.cpath = prepend_and_dedup(path .. "/?.@SHARED_LIB_EXT@", package.cpath) -end - -local function extendPaths (path, ours) - prependCPath(path) - prependPath(path) - if ours then - prependPath(path .. "/lua-libraries") - if "@SYSTEM_LUAROCKS_FALSE@" == "" then -- see ./configure --with[out]-system-luarocks - prependCPath(path .. "/lua_modules/lib/lua/" .. luaversion) - prependPath(path .. "/lua_modules/share/lua/" .. luaversion) - end - else - prependCPath(path .. "/sile") - prependPath(path .. "/sile") - end -end - --- Facilitate loading SILE classes & packages from system LuaRocks --- Also weed out CWD relative paths, we add them in a different order later -local luapath = {} -local extpath = {} -for path in package.path:gmatch("[^;]+") do - table.insert(extpath, tostring(path:gsub("%?", "sile/?"))) - table.insert(luapath, path) -end -package.path = table.concat(luapath, ";") - -extendPaths("@SILE_PATH@", true) -extendPaths("@SILE_LIB_PATH@", true) - -package.path = table.concat(extpath, ";") .. ";" .. package.path - -local pathvar = os.getenv("SILE_PATH") -if pathvar then - for path in string.gmatch(pathvar, "[^;]+") do - if not path:match("^./") and path:len() >= 1 then - extendPaths(path) - end - end +-- At this point at run time we may or may not have anything useful in package.path, +-- so require() isn't something we can rely on. +local status = pcall(dofile, "@SILE_PATH@/core/pathsetup.lua") +if not status then + dofile("./core/pathsetup.lua") end -local cwd = executable:gsub("(.*)(/.*)", "%1") -if cwd:match("^@") then -- Consider "ours" for the sake of Nix Flake - extendPaths(".", true) -else - if cwd ~= "./" then extendPaths(cwd) end - extendPaths(".") +-- On FreeBSD, Lua's debug module doesn't give us info above the top of the stack. +-- Since our detection is currently burried in a module it doesn't tell us the executable. +if executablePath ~= "=[C]" then + executablePath = debug.getinfo(1, "S").source end -- This global is set here and *also* in the core library, since this -- effectively passes the same table they are interchangeable (for now). SILE = require("core.sile") -io.stdout:setvbuf 'no' - SILE.cli:parseArguments() if not os.getenv 'LUA_REPL_RLWRAP' and not SILE.quiet then io.stderr:write(SILE.full_version .. '\n') end -local ProFi -if SU.debugging("profile") then - ProFi = require("ProFi") -end - -if SILE.makeDeps then - SILE.makeDeps:add(executable) -end - SILE.init() -if SILE.masterFilename then - - if SILE.masterDir:len() >= 1 then - extendPaths(SILE.masterDir) - end - - if SU.debugging("profile") then - ProFi:start() - end +if SILE.input.filename and SILE.input.filename:len() > 0 then -- Deprecated, notice given in core.cli when argument used for _, path in ipairs(SILE.input.includes) do @@ -139,15 +63,6 @@ if SILE.masterFilename then SILE.finish() - if SU.debugging("profile") then - ProFi:stop() - ProFi:writeReport(SILE.masterFilename..'.profile.txt') - end - - if SU.debugging("versions") then - SILE.shaper:debugVersions() - end - else SILE.repl:enter() end diff --git a/sile.rockspec.in b/sile.rockspec.in new file mode 100644 index 000000000..24f2baf4d --- /dev/null +++ b/sile.rockspec.in @@ -0,0 +1,53 @@ +-- @ROCKSPECWARNING@ +rockspec_format = "3.0" +package = "@TRANSFORMED_PACKAGE_NAME@" +version = "dev-@ROCKREV@" + +source = { + url = "git+https://github.com/sile-typesetter/sile.git", + branch = "master" +} + +description = { + summary = "Simon’s Improved Layout Engine", + detailed = [[SILE is a typesetting system; its job is to produce beautiful printed documents. + Conceptually, SILE is similar to TeX—from which it borrows some concepts and even + syntax and algorithms—but the similarities end there. Rather than being a + derivative of the TeX family SILE is a new typesetting and layout engine written + from the ground up using modern technologies and borrowing some ideas from + graphical systems such as InDesign.]], + license = "MIT", + homepage = "https://github.com/sile-typesetter/fontproof", + issues_url = "https://github.com/sile-typesetter/fontproof/issues", + maintainer = "Caleb Maclennan ", + labels = { "typesetting" } +} + +dependencies = { + "lua >= 5.1", + "bit32", -- only required on Lua < 5.2, versions vary between Rock and VM provided + "cassowary == 2.3.2-1", + "cldr == 0.3.0-0", + "compat53 == 0.8-1", -- only required on Lua < 5.3 + "cosmo == 16.06.04-1", + "fluent == 0.2.0-0", + "linenoise == 0.9-1", + "loadkit == 1.1.0-1", + "lpeg == 1.0.2-1", + "lua-zlib == 1.2-2", + "lua_cliargs == 3.0-2", + "luaepnf == 0.3-2", + "luaexpat == 1.5.1-1", + "luafilesystem == 1.8.0-1", + "luarepl == 0.10-1", + "luasec == 1.3.1-1", + "luasocket == 3.1.0-1", + "luautf8 == 0.1.5-1", + "penlight == 1.13.1-1", + "vstruct == 2.1.1-1" +} + +build = { + type = "builtin", + modules = {} +}