summaryrefslogtreecommitdiff
path: root/luaotfload-tool.lua
diff options
context:
space:
mode:
Diffstat (limited to 'luaotfload-tool.lua')
-rwxr-xr-xluaotfload-tool.lua637
1 files changed, 32 insertions, 605 deletions
diff --git a/luaotfload-tool.lua b/luaotfload-tool.lua
index cd64a75..92483d6 100755
--- a/luaotfload-tool.lua
+++ b/luaotfload-tool.lua
@@ -4,11 +4,13 @@
-- DESCRIPTION: database functionality
-- REQUIREMENTS: luaotfload 2.2
-- AUTHOR: Khaled Hosny, Élie Roux, Philipp Gesang
--- VERSION: 2.3b
+-- VERSION: 2.4
-- LICENSE: GPL v2
--- MODIFIED: 2013-06-02 19:23:54+0200
+-- MODIFIED: 2013-07-28 13:12:04+0200
-----------------------------------------------------------------------
+local version = "2.4" --- <int: major>.<int: minor><alpha: fixes>
+
--[[doc--
This file was originally written (as \fileent{mkluatexfontdb.lua}) by
@@ -42,23 +44,12 @@ 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
local stringlower = string.lower
local stringrep = string.rep
-local stringsub = string.sub
local tableconcat = table.concat
local texiowrite_nl = texio.write_nl
local texiowrite = texio.write
@@ -79,7 +70,7 @@ else -- 5.2
end
-local C, Cg, Ct, P, S = lpeg.C, lpeg.Cg, lpeg.Ct, lpeg.P, lpeg.S
+local C, Ct, P, S = lpeg.C, lpeg.Ct, lpeg.P, lpeg.S
local lpegmatch = lpeg.match
local loader_file = "luatexbase.loader.lua"
@@ -111,6 +102,7 @@ to be the more appropriate.
config = config or { }
local config = config
config.luaotfload = config.luaotfload or { }
+config.luaotfload.version = config.luaotfload.version or version
config.luaotfload.names_dir = config.luaotfload.names_dir or "names"
config.luaotfload.cache_dir = config.luaotfload.cache_dir or "fonts"
config.luaotfload.index_file = config.luaotfload.index_file
@@ -140,26 +132,33 @@ config.lualibs.prefer_merged = true
config.lualibs.load_extended = true
require "lualibs"
-
-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
--[[doc--
\fileent{luatex-basics-gen.lua} calls functions from the
\luafunction{texio.*} library; too much for our taste.
We intercept them with dummies.
+
+Also, it sets up dummies in place of the tables created by the Context
+libraries. Since we have loaded the lualibs already this would cause
+collateral damage for some libraries whose namespace would be
+overridden. We employ our usual backup-restore strategy to work around
+this. (Postponing the loading of the lualibs code is not an option
+because the functionality is needed by basics-gen itself.)
--doc]]--
local dummy_function = function ( ) end
-local backup_write, backup_write_nl = texio.write, texio.write_nl
+local backup = {
+ write = texio.write,
+ write_nl = texio.write_nl,
+ utilities = utilities,
+}
texio.write, texio.write_nl = dummy_function, dummy_function
require"luaotfload-basics-gen.lua"
-texio.write, texio.write_nl = backup_write, backup_write_nl
+
+texio.write, texio.write_nl = backup.write, backup.write_nl
+utilities = backup.utilities
require"luaotfload-override.lua" --- this populates the logs.* namespace
require"luaotfload-database"
@@ -167,12 +166,11 @@ require"alt_getopt"
local names = fonts.names
-local status_file = "luaotfload-status"
-local status = require (status_file)
-
-local version = "2.3b"
+local status_file = "luaotfload-status"
+local status = require (status_file)
+config.luaotfload.status = status
-local sanitize_string = names.sanitize_string
+local sanitize_string = names.sanitize_string
local pathdata = names.path
local names_plain = pathdata.index.lua
@@ -830,10 +828,6 @@ local get_fields get_fields = function (entry, fields, acc, n)
return acc
end
-local comma = P","
-local noncomma = 1-comma
-local split_comma = Ct((C(noncomma^1) + comma)^1)
-
local separator = "\t" --- could be “,” for csv
local format_fields format_fields = function (fields, acc, n)
@@ -869,12 +863,14 @@ set_primary_field = function (fields, addme, acc, n)
return acc
end
+local splitcomma = names.patterns.splitcomma
+
actions.list = function (job)
local criterion = job.criterion
local asked_fields = job.asked_fields
if asked_fields then
- asked_fields = lpegmatch(split_comma, asked_fields)
+ asked_fields = lpegmatch(splitcomma, asked_fields)
else
--- some defaults
asked_fields = { "fullname", "version", }
@@ -959,579 +955,10 @@ actions.list = function (job)
return true, true
end
-do
- local out = function (...)
- logs.names_report (false, 0, "diagnose", ...)
- end
-
- local verify_files = function (errcnt, status)
- out "================ verify files ================="
- local hashes = status.hashes
- local notes = status.notes
- if not hashes or #hashes == 0 then
- out ("FAILED: cannot read checksums from %s.", status_file)
- return 1/0
- elseif not notes then
- out ("FAILED: cannot read commit metadata from %s.",
- status_file)
- return 1/0
- end
-
- out ("Luaotfload revision %s.", notes.revision)
- out ("Committed by %s.", notes.committer)
- out ("Timestamp %s.", notes.timestamp)
-
- local nhashes = #hashes
- out ("Testing %d files for integrity.", nhashes)
- for i = 1, nhashes do
- local fname, canonicalsum = unpack (hashes[i])
- local location = kpsefind_file (fname)
- or kpsefind_file (fname, "texmfscripts")
- if not location then
- errcnt = errcnt + 1
- out ("FAILED: file %s missing.", fname)
- else
- out ("File: %s.", location)
- local raw = ioloaddata (location)
- if not raw then
- errcnt = errcnt + 1
- out ("FAILED: file %d not readable.", fname)
- else
- local sum = md5sumhexa (raw)
- if sum ~= canonicalsum then
- errcnt = errcnt + 1
- out ("FAILED: checksum mismatch for file %s.",
- fname)
- out ("Expected %s.", canonicalsum)
- out ("Got %s.", sum)
- else
- out ("Ok, %s passed.", fname)
- end
- end
- end
- end
- return errcnt
- end
-
- local get_tentative_attributes = function (file)
- if not lfsisfile (file) then
- local chan = ioopen (file, "w")
- if chan then
- chan:close ()
- local attributes = lfsattributes (file)
- os.remove (file)
- return attributes
- end
- end
- end
-
- local p_permissions = Ct(Cg(Ct(C(1) * C(1) * C(1)), "u")
- * Cg(Ct(C(1) * C(1) * C(1)), "g")
- * Cg(Ct(C(1) * C(1) * C(1)), "o"))
-
- local analyze_permissions = function (raw)
- return lpegmatch (p_permissions, raw)
- end
-
- local stripslashes = names.patterns.stripslashes
-
- local get_permissions = function (t, location)
- if stringsub (location, #location) == "/" then
- --- strip trailing slashes (lfs idiosyncrasy on Win)
- location = lpegmatch (stripslashes, location)
- end
- local attributes = lfsattributes (location)
-
- if not attributes and t == "f" then
- attributes = get_tentative_attributes (location)
- if not attributes then
- return false
- end
- end
-
- local permissions
-
- if fileisreadable (location) then
- --- link handling appears to be unnecessary because
- --- lfs.attributes() will return the information on
- --- the link target.
- if mode == "link" then --follow and repeat
- location = lfsreadlink (location)
- attributes = lfsattributes (location)
- end
- end
-
- permissions = analyze_permissions (attributes.permissions)
-
- return {
- location = location,
- mode = attributes.mode,
- owner = attributes.uid, --- useless on windows
- permissions = permissions,
- attributes = attributes,
- }
- end
-
- local check_conformance = function (spec, permissions, errcnt)
- local uid = permissions.attributes.uid
- local gid = permissions.attributes.gid
- local raw = permissions.attributes.permissions
-
- out ("Owner: %d, group %d, permissions %s.", uid, gid, raw)
- if ostype == "unix" then
- if uid == 0 or gid == 0 then
- out "Owned by the superuser, permission conflict likely."
- errcnt = errcnt + 1
- end
- end
-
- local user = permissions.permissions.u
- if spec.r == true then
- if user[1] == "r" then
- out "Readable: ok."
- else
- out "Not readable: permissions need fixing."
- errcnt = errcnt + 1
- end
- end
-
- if spec.w == true then
- if user[2] == "w"
- or fileiswritable (permissions.location) then
- out "Writable: ok."
- else
- out "Not writable: permissions need fixing."
- errcnt = errcnt + 1
- end
- end
-
- return errcnt
- end
-
- local path = names.path
-
- local desired_permissions = {
- { "d", {"r","w"}, function () return caches.getwritablepath () end },
- { "d", {"r","w"}, path.globals.prefix },
- { "f", {"r","w"}, path.index.lua },
- { "f", {"r","w"}, path.index.luc },
- { "f", {"r","w"}, path.lookups.lua },
- { "f", {"r","w"}, path.lookups.luc },
- }
-
- local check_permissions = function (errcnt)
- out [[=============== file permissions ==============]]
- for i = 1, #desired_permissions do
- local t, spec, path = unpack (desired_permissions[i])
- if type (path) == "function" then
- path = path ()
- end
-
- spec = tabletohash (spec)
-
- out ("Checking permissions of %s.", path)
-
- local permissions = get_permissions (t, path)
- if permissions then
- --inspect (permissions)
- errcnt = check_conformance (spec, permissions, errcnt)
- else
- errcnt = errcnt + 1
- end
- end
- return errcnt
- end
-
- local check_upstream
-
- if kpsefind_file ("https.lua", "lua") == nil then
- check_upstream = function (errcnt)
- out [[============= upstream repository =============
- WARNING: Cannot retrieve repository data.
- Github API access requires the luasec library.
- Grab it from <https://github.com/brunoos/luasec>
- and retry.]]
- return errcnt
- end
- else
- --- github api stuff begin
- local https = require "ssl.https"
-
- local gh_api_root = [[https://api.github.com]]
- local release_url = [[https://github.com/lualatex/luaotfload/releases]]
- local luaotfload_repo = [[lualatex/luaotfload]]
- local user_agent = [[lualatex/luaotfload integrity check]]
- local shortbytes = 8
-
- local gh_shortrevision = function (rev)
- return stringsub (rev, 1, shortbytes)
- end
-
- local gh_encode_parameters = function (parameters)
- local acc = {}
- for field, value in next, parameters do
- --- unsafe, non-urlencoded coz it’s all ascii chars
- acc[#acc+1] = field .. "=" .. value
- end
- return "?" .. tableconcat (acc, "&")
- end
-
- local gh_make_url = function (components, parameters)
- local url = tableconcat ({ gh_api_root,
- unpack (components) },
- "/")
- if parameters then
- url = url .. gh_encode_parameters (parameters)
- end
- return url
- end
-
- local alright = [[HTTP/1.1 200 OK]]
-
- local gh_api_request = function (...)
- local args = {...}
- local nargs = #args
- local final = args[nargs]
- local request = {
- url = "",
- headers = { ["user-agent"] = user_agent },
- }
- if type (final) == "table" then
- args[nargs] = nil
- request = gh_make_url (args, final)
- else
- request = gh_make_url (args)
- end
-
- out ("Requesting <%s>.", request)
- local response, code, headers, status
- = https.request (request)
- if status ~= alright then
- out "Request failed!"
- return false
- end
- return response
- end
-
- local gh_api_checklimit = function (headers)
- local rawlimit = gh_api_request "rate_limit"
- local limitdata = lua_of_json (rawlimit)
- if not limitdata and limitdata.rate then
- out "Cannot parse API rate limit."
- return false
- end
- limitdata = limitdata.rate
-
- local limit = tonumber (limitdata.limit)
- local left = tonumber (limitdata.remaining)
- local reset = tonumber (limitdata.reset)
-
- out ("%d of %d Github API requests left.", left, limit)
- if left == 0 then
- out ("Cannot make any more API requests.")
- out ("Try again later at %s.", osdate ("%F %T", reset))
- end
- return true
- end
-
- local gh_tags = function ()
- out "Fetching tags from repository, please stand by."
- local rawtags = gh_api_request ("repos",
- luaotfload_repo,
- "tags")
- local taglist = lua_of_json (rawtags)
- if not taglist or #taglist == 0 then
- out "Cannot parse response."
- return false
- end
-
- local ntags = #taglist
- out ("Repository contains %d tags.", ntags)
- local _idx, latest = next (taglist)
- out ("The most recent release is %s (revision %s).",
- latest.name,
- gh_shortrevision (latest.commit.sha))
- return latest
- end
-
- local gh_compare = function (head, base)
- if base == nil then
- base = "HEAD"
- end
- out ("Fetching comparison between %s and %s, \z
- please stand by.",
- gh_shortrevision (head),
- gh_shortrevision (base))
- local comparison = base .. "..." .. head
- local rawstatus = gh_api_request ("repos",
- luaotfload_repo,
- "compare",
- comparison)
- local status = lua_of_json (rawstatus)
- if not status then
- out "Cannot parse response for status request."
- return false
- end
- return status
- end
-
- local gh_news = function (since)
- local compared = gh_compare (since)
- if not compared then
- return false
- end
- local behind_by = compared.behind_by
- local ahead_by = compared.ahead_by
- local status = compared.status
- out ("Comparison state: %s.", status)
- if behind_by > 0 then
- out ("Your Luaotfload is %d \z
- revisions behind upstream.",
- behind_by)
- return behind_by
- elseif status == "ahead" then
- out "Since you are obviously from the future \z
- I assume you already know the repository state."
- else
- out "Everything up to date. \z
- Luaotfload is in sync with upstream."
- end
- return false
- end
-
- local gh_catchup = function (current, latest)
- local compared = gh_compare (latest, current)
- local ahead_by = tonumber (compared.ahead_by)
- if ahead_by > 0 then
- local permalink_url = compared.permalink_url
- out ("Your Luaotfload is %d revisions \z
- behind the most recent release.",
- ahead_by)
- out ("To view the commit log, visit <%s>.",
- permalink_url)
- out ("You can grab an up to date tarball at <%s>.",
- release_url)
- return true
- else
- out "There weren't any new releases in the meantime."
- out "Luaotfload is up to date."
- end
- return false
- end
-
- check_upstream = function (current)
- out "============= upstream repository ============="
- local _succ = gh_api_checklimit ()
- local behind = gh_news (current)
- if behind then
- local latest = gh_tags ()
- local _behind = gh_catchup (current,
- latest.commit.sha,
- latest.name)
- end
- end
-
- --- trivium: diff since the first revision as pushed by Élie
- --- in 2009
- --- local firstrevision = "c3ccb3ee07e0a67171c24960966ae974e0dd8e98"
- --- check_upstream (firstrevision)
- end
- --- github api stuff end
-
- 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
- local asked = job.asked_diagnostics
- if asked == "all" or asked == "thorough" then
- asked = tabletohash (anamneses, true)
- else
- asked = lpegmatch(split_comma, asked)
- 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
- end
-
- local rest = next (asked)
- if rest ~= nil then --> something unknown
- out ("Unknown diagnostic %q.", rest)
- end
- if errcnt == 0 then --> success
- out ("Everything appears to be in order, \z
- you may sleep well.")
- return true, false
- end
- out ( [[===============================================
- WARNING
- ===============================================
-
- The diagnostic detected %d errors.
-
- This version of luaotfload may have been
- tampered with. Modified versions of the
- luaotfload source are unsupported. Read the log
- carefully and get a clean version from CTAN or
- github:
-
- × http://ctan.org/tex-archive/macros/luatex/generic/luaotfload
- × https://github.com/lualatex/luaotfload/releases
-
- If you are uncertain as to how to proceed, then
- ask on the lualatex mailing list:
-
- http://www.tug.org/mailman/listinfo/lualatex-dev
-
- ===============================================
-]], errcnt)
- return true, false
- end
+actions.diagnose = function (job)
+ --- diagnostics are loaded on demand
+ local diagnose = require "luaotfload-diagnostics.lua"
+ return diagnose (job)
end
--- stuff to be carried out prior to exit