diff options
-rw-r--r-- | Makefile | 12 | ||||
-rw-r--r-- | luaotfload-database.lua | 103 | ||||
-rwxr-xr-x | luaotfload-tool.lua | 154 | ||||
-rwxr-xr-x | mktests | 69 |
4 files changed, 300 insertions, 38 deletions
@@ -60,6 +60,9 @@ MANDIR = $(TEXMFROOT)/doc/man/man1/ SRCDIR = $(TEXMFROOT)/source/$(FORMAT)/$(NAME) TEXMFROOT = $(shell kpsewhich --var-value TEXMFHOME) +# CTAN-friendly subdirectory for packaging +DISTDIR = ./luaotfload + CTAN_ZIP = $(NAME).zip TDS_ZIP = $(NAME).tds.zip ZIPS = $(CTAN_ZIP) $(TDS_ZIP) @@ -110,10 +113,16 @@ $(UNPACKED): $(DTX) $(MAN): $(MANSOURCE) $(DO_DOCUTILS) +define make-ctandir +@$(RM) -rf $(DISTDIR) +@mkdir -p $(DISTDIR) && cp $(SOURCE) $(COMPILED) $(DISTDIR) +endef + $(CTAN_ZIP): $(SOURCE) $(COMPILED) $(TDS_ZIP) @echo "Making $@ for CTAN upload." @$(RM) -- $@ - @zip -9 $@ $^ >/dev/null + $(make-ctandir) + @zip -r -9 $@ $(TDS_ZIP) $(DISTDIR) >/dev/null define run-install @mkdir -p $(SCRIPTDIR) && cp $(SCRIPTSTATUS) $(SCRIPTDIR) @@ -164,4 +173,5 @@ clean: mrproper: clean @$(RM) -- $(GENERATED) $(ZIPS) $(GLYPHSOURCE) $(TESTDIR)/*.pdf + @$(RM) -r -- $(DISTDIR) diff --git a/luaotfload-database.lua b/luaotfload-database.lua index 1b75458..a49e575 100644 --- a/luaotfload-database.lua +++ b/luaotfload-database.lua @@ -117,6 +117,10 @@ end local report = logs.names_report +local trailingslashes = P"/"^1 * P(-1) +local stripslashes = C((1 - trailingslashes)^0) +names.patterns = { stripslashes = stripslashes } + --[[doc-- We use the functions in the cache.* namespace that come with the fontloader (see luat-basics-gen). it’s safe to use for the most part @@ -139,6 +143,7 @@ if caches then luaotfload.error ("Impossible to find a suitable writeable cache...") else + prefix = lpegmatch (stripslashes, prefix) report ("log", 0, "db", "root cache directory is " .. prefix) end @@ -1438,7 +1443,9 @@ process_dir_tree = function (acc, dirs) then dirs[#dirs+1] = fullpath elseif lfsisfile (fullpath) then - if lpegmatch (p_font_extensions, stringlower(ent)) then + if lpegmatch (p_font_extensions, + stringlower (ent)) + then newfiles[#newfiles+1] = fullpath end end @@ -1450,10 +1457,38 @@ process_dir_tree = function (acc, dirs) return process_dir_tree (acc, dirs) end ---- string -> string list -local find_font_files = function (root) +local process_dir = function (dir) + local pwd = lfscurrentdir () + if lfschdir (dir) then + lfschdir (pwd) + + local files = { } + local blacklist = names.blacklist + for ent in lfsdir (dir) do + if ent ~= "." and ent ~= ".." and not blacklist[ent] then + local fullpath = dir .. "/" .. ent + if lfsisfile (fullpath) then + if lpegmatch (p_font_extensions, + stringlower (ent)) + then + files[#files+1] = fullpath + end + end + end + end + return files + end + return { } +end + +--- string -> bool -> string list +local find_font_files = function (root, recurse) if lfsisdir (root) then - return process_dir_tree ({}, { root }) + if recurse == true then + return process_dir_tree ({}, { root }) + else --- kpathsea already delivered the necessary subdirs + return process_dir (root) + end end end @@ -1478,7 +1513,7 @@ local scan_dir = function (dirname, fontnames, newfontnames, --- ignore return 0, 0 end - local found = find_font_files (dirname) + local found = find_font_files (dirname, texmf ~= true) if not found then report ("both", 3, "db", "No such directory: %q; skipping.", dirname) @@ -1511,23 +1546,55 @@ local scan_dir = function (dirname, fontnames, newfontnames, return n_found, n_new end +--- string list -> string list +local filter_out_pwd = function (dirs) + local result = { } + local pwd = path_normalize (lpegmatch (stripslashes, + lfscurrentdir ())) + for i = 1, #dirs do + --- better safe than sorry + local dir = path_normalize (lpegmatch (stripslashes, dirs[i])) + if not (dir == "." or dir == pwd) then + result[#result+1] = dir + end + end + return result +end + +--[[doc-- + scan_texmf_fonts() scans all fonts in the texmf tree through the + kpathsea variables OPENTYPEFONTS and TTFONTS of texmf.cnf. + The current working directory comes as “.” (texlive) or absolute + path (miktex) and will always be filtered out. +--doc]]-- + --- dbobj -> dbobj -> bool? -> (int * int) local scan_texmf_fonts = function (fontnames, newfontnames, dry_run) - local n_scanned, n_new = 0, 0 - --[[ - This function scans all fonts in the texmf tree, through kpathsea - variables OPENTYPEFONTS and TTFONTS of texmf.cnf - ]] - if stringis_empty(kpseexpand_path("$OSFONTDIR")) then - report("info", 2, "db", "Scanning TEXMF fonts...") + local n_scanned, n_new, fontdirs = 0, 0 + local osfontdir = kpseexpand_path "$OSFONTDIR" + if stringis_empty (osfontdir) then + report ("info", 2, "db", "Scanning TEXMF fonts...") else - report("info", 2, "db", "Scanning TEXMF and OS fonts...") + report ("info", 2, "db", "Scanning TEXMF and OS fonts...") + if logs.get_loglevel () > 3 then + local osdirs = filesplitpath (osfontdir) + report ("info", 0, "db", + "$OSFONTDIR has %d entries:", #osdirs) + for i = 1, #osdirs do + report ("info", 0, "db", "[%d] %s", i, osdirs[i]) + end + end end - local fontdirs = stringgsub(kpseexpand_path("$OPENTYPEFONTS"), "^%.", "") - fontdirs = fontdirs .. stringgsub(kpseexpand_path("$TTFONTS"), "^%.", "") - if not stringis_empty(fontdirs) then - for _,d in next, filesplitpath(fontdirs) do - local found, new = scan_dir(d, fontnames, newfontnames, dry_run, true) + fontdirs = kpseexpand_path "$OPENTYPEFONTS" + fontdirs = fontdirs .. (ostype == "windows" and ";" or ":") + .. kpseexpand_path "$TTFONTS" + if not stringis_empty (fontdirs) then + local tasks = filter_out_pwd (filesplitpath (fontdirs)) + report ("info", 3, "db", + "Initiating scan of %d directories.", #tasks) + for _, d in next, tasks do + local found, new = scan_dir (d, fontnames, newfontnames, + dry_run, true) n_scanned = n_scanned + found n_new = n_new + new end diff --git a/luaotfload-tool.lua b/luaotfload-tool.lua index 801ae72..cd64a75 100755 --- a/luaotfload-tool.lua +++ b/luaotfload-tool.lua @@ -42,13 +42,17 @@ kpse.set_program_name "luatex" local ioopen = io.open local iowrite = io.write local kpsefind_file = kpse.find_file +local kpseexpand_var = kpse.expand_var +local kpseexpand_path = kpse.expand_path local lfsattributes = lfs.attributes local lfsisfile = lfs.isfile local lfsreadlink = lfs.readlink local md5sumhexa = md5.sumhexa local next = next local osdate = os.date +local osgetenv = os.getenv local osremove = os.remove +local osname = os.name local ostype = os.type local stringexplode = string.explode local stringformat = string.format @@ -136,13 +140,13 @@ config.lualibs.prefer_merged = true config.lualibs.load_extended = true require "lualibs" ---- dofile "util-jsn.lua" --- awaiting fix -local lua_of_json = utilities.json.tolua +local fileisreadable = file.isreadable +local fileiswritable = file.iswritable +local filesplitpath = file.splitpath local ioloaddata = io.loaddata +local lua_of_json = utilities.json.tolua local tabletohash = table.tohash -local fileiswritable = file.iswritable -local fileisreadable = file.isreadable --[[doc-- \fileent{luatex-basics-gen.lua} calls functions from the @@ -690,6 +694,7 @@ local action_sequence = { "blacklist", "cache", "flush", "generate", "list", "query", } + local action_pending = tabletohash(action_sequence, false) action_pending.loglevel = true --- always set the loglevel @@ -1028,8 +1033,7 @@ do return lpegmatch (p_permissions, raw) end - local trailingslashes = P"/"^1 * P(-1) - local stripslashes = C((1 - trailingslashes)^0) + local stripslashes = names.patterns.stripslashes local get_permissions = function (t, location) if stringsub (location, #location) == "/" then @@ -1334,7 +1338,136 @@ do end --- github api stuff end - local anamneses = { "files", "repository", "permissions" } + local print_envvar = function (var) + local val = osgetenv (var) + if val then + out ("%20s: %q", stringformat ("$%s", var), val) + return val + else + out ("%20s: <unset>", stringformat ("$%s", var)) + end + end + + local print_path = function (var) + local val = osgetenv (var) + if val then + local paths = filesplitpath (val) + if paths then + local npaths = #paths + if npaths == 1 then + out ("%20s: %q", stringformat ("$%s", var), val) + elseif npaths > 1 then + out ("%20s: <%d items>", stringformat ("$%s", var), npaths) + for i = 1, npaths do + out (" +: %q", paths[i]) + end + else + out ("%20s: <empty>") + end + end + else + out ("%20s: <unset>", stringformat ("$%s", var)) + end + end + + local print_kpsevar = function (var) + var = "$" .. var + local val = kpseexpand_var (var) + if val and val ~= var then + out ("%20s: %q", var, val) + return val + else + out ("%20s: <empty or unset>", var) + end + end + + local print_kpsepath = function (var) + var = "$" .. var + local val = kpseexpand_path (var) + if val and val ~= "" then + local paths = filesplitpath (val) + if paths then + local npaths = #paths + if npaths == 1 then + out ("%20s: %q", var, paths[1]) + elseif npaths > 1 then + out ("%20s: <%d items>", var, npaths) + for i = 1, npaths do + out (" +: %q", paths[i]) + end + else + out ("%20s: <empty>") + end + end + else + out ("%20s: <empty or unset>", var) + end + end + + --- this test first if a variable is set and then expands the + --- paths; this is necessitated by the fact that expand-path will + --- return the empty string both if the variable is unset and if + --- the directory does not exist + + local print_kpsepathvar = function (var) + local vvar = "$" .. var + local val = kpseexpand_var (vvar) + if val and val ~= vvar then + out ("%20s: %q", vvar, val) + print_kpsepath (var) + else + out ("%20s: <empty or unset>", var) + end + end + + local check_environment = function (errcnt) + out "============ environment settings =============" + out ("system: %s/%s", ostype, osname) + if ostype == "unix" and io.popen then + local chan = io.popen ("uname -a", "r") + if chan then + out ("info: %s", chan:read "*all") + chan:close () + end + end + + out "1) *shell environment*" + print_envvar "SHELL" + print_path "PATH" + print_path "OSFONTDIR" + print_envvar "USER" + if ostype == "windows" then + print_envvar "WINDIR" + print_envvar "CD" + print_path "TEMP" + elseif ostype == "unix" then + print_envvar "HOME" + print_envvar "PWD" + print_path "TMPDIR" + end + + out "2) *kpathsea*" + print_kpsepathvar "OPENTYPEFONTS" + print_kpsepathvar "TTFONTS" + + print_kpsepathvar "TEXMFCACHE" + print_kpsepathvar "TEXMFVAR" + + --- the expansion of these can be quite large; as they aren’t + --- usually essential to luaotfload, we won’t dump every single + --- path + print_kpsevar "LUAINPUTS" + print_kpsevar "CLUAINPUTS" + + return errcnt + end + + local anamneses = { + "environment", + "files", + "repository", + "permissions" + } actions.diagnose = function (job) local errcnt = 0 @@ -1346,14 +1479,21 @@ do asked = tabletohash (asked, true) end + if asked.environment == true then + errcnt = check_environment (errcnt) + asked.environment = nil + end + if asked.files == true then errcnt = verify_files (errcnt, status) asked.files = nil end + if asked.permissions == true then errcnt = check_permissions (errcnt) asked.permissions = nil end + if asked.repository == true then check_upstream (status.notes.revision) asked.repository = nil @@ -57,6 +57,12 @@ local pprint_result = function (name, failed, total) end end +local pprint_spec = function (spec) + return string.format ("%s*%.2fpt", + spec.specification, + spec.optsize) +end + ----------------------------------------------------------------------- --- font tests ----------------------------------------------------------------------- @@ -72,8 +78,31 @@ local infer_regular_style = { { "Garamond Premier Pro", "GaramondPremrPro-Capt.otf" }, } +local choose_optical_size = { + { { name = "Latin Modern Roman", optsize = 0 }, "lmroman5-regular.otf" }, + { { name = "Latin Modern Roman", optsize = 10 }, "lmroman10-regular.otf" }, + { { name = "Latin Modern Roman", optsize = 12 }, "lmroman12-regular.otf" }, + { { name = "Latin Modern Roman", optsize = 42 }, "lmroman17-regular.otf" }, + { { name = "EB Garamond", optsize = 0 }, "EBGaramond08-Regular.otf" }, + { { name = "EB Garamond", optsize = 8 }, "EBGaramond08-Regular.otf" }, + { { name = "EB Garamond", optsize = 12 }, "EBGaramond12-Regular.otf" }, + { { name = "EB Garamond", optsize = 42 }, "EBGaramond12-Regular.otf" }, + { { name = "Garamond Premier Pro", optsize = 0 }, "GaramondPremrPro-Capt.otf" }, + { { name = "Garamond Premier Pro", optsize = 10 }, "GaramondPremrPro.otf" }, + { { name = "Garamond Premier Pro", optsize = 15 }, "GaramondPremrPro-Subh.otf" }, + { { name = "Garamond Premier Pro", optsize = 42 }, "GaramondPremrPro-Disp.otf" }, +} + local font_name_tests = { - infer_regular_style, + infer_regular_style, + choose_optical_size, +} + +local default_spec = { + name = false, + lookup = "name", + specification = false, + optsize = 0, } local resolve_font_name = function () @@ -81,21 +110,37 @@ local resolve_font_name = function () local resolve_name = names.resolve for nset = 1, #font_name_tests do local set = font_name_tests[nset] + for ntest = 1, #set do local test = set[ntest] local input, output = test[1], test[2] - local input_spec = { - name = input, - lookup = "name", - specification = "name:" .. input, - optsize = 0, - } - local result = resolve_name (nil, nil, input_spec) == output - total = total + 1 - if not result then - failed = failed + 1 + + if type (input) == "string" then + local input_spec = table.copy (default_spec) + input_spec.name = input + input_spec.specification = input_spec.lookup .. ":" .. input + local result = resolve_name (nil, nil, input_spec) == output + total = total + 1 + if not result then + failed = failed + 1 + end + pprint_resolve (input, output, result) + + else + local input_spec, output = test[1], test[2] + input_spec.specification = (input_spec.lookup + or default_spec.lookup) + .. ":" .. input_spec.name + input_spec.optsize = input_spec.optsize or default_spec.optsize + --print( resolve_name (nil, nil, input_spec) ) + local result = resolve_name (nil, nil, input_spec) == output + total = total + 1 + if not result then + failed = failed + 1 + end + pprint_resolve (pprint_spec (input_spec), output, result) end - pprint_resolve (input, output, result) + end end return failed, total |