summaryrefslogtreecommitdiff
path: root/luaotfload-database.lua
diff options
context:
space:
mode:
Diffstat (limited to 'luaotfload-database.lua')
-rw-r--r--luaotfload-database.lua266
1 files changed, 214 insertions, 52 deletions
diff --git a/luaotfload-database.lua b/luaotfload-database.lua
index 224fa61..60a7977 100644
--- a/luaotfload-database.lua
+++ b/luaotfload-database.lua
@@ -239,7 +239,7 @@ end
local crude_file_lookup
local crude_file_lookup_verbose
local find_closest
-local flush_cache
+local flush_lookup_cache
local font_fullinfo
local load_names
local load_lookups
@@ -259,8 +259,8 @@ local fonts_reloaded = false
--- limit output when approximate font matching (luaotfload-tool -F)
local fuzzy_limit = 1 --- display closest only
---- unit -> dbobj
-load_names = function ( )
+--- bool? -> dbobj
+load_names = function (dry_run)
local starttime = os.gettimeofday()
local foundname, data = load_lua_file(names.path.path)
@@ -273,8 +273,11 @@ load_names = function ( )
report("both", 0, "db",
[[Font names database not found, generating new one.
This can take several minutes; please be patient.]])
- data = update_names(fontnames_init(false))
- save_names(data)
+ data = update_names(fontnames_init(false), nil, dry_run)
+ local success = save_names(data)
+ if not success then
+ report("both", 0, "db", "Database creation unsuccessful.")
+ end
end
fonts_loaded = true
return data
@@ -443,7 +446,10 @@ resolve_cached = function (_, _, specification)
--- TODO this should trigger a save only once the
--- document is compiled (finish_pdffile callback?)
report("both", 5, "cache", "saving updated cache")
- save_lookups()
+ local success = save_lookups()
+ if not success then --- sad, but not critical
+ report("both", 0, "cache", "could not write to cache")
+ end
return filename, subfont, true
end
@@ -675,9 +681,12 @@ end --- resolve()
reload_db = function (why, caller, ...)
report("both", 1, "db", "reload initiated; reason: “%s”", why)
names.data = update_names()
- save_names()
- fonts_reloaded = true
- return caller(...)
+ local success = save_names()
+ if success then
+ fonts_reloaded = true
+ return caller(...)
+ end
+ report("both", 0, "db", "Database update unsuccessful.")
end
--- string -> string -> int
@@ -859,7 +868,9 @@ end
--- we return true if the fond is new or re-indexed
--- string -> dbobj -> dbobj -> bool
local load_font = function (fullname, fontnames, newfontnames)
- if not fullname then return false end
+ if not fullname then
+ return false
+ end
local newmappings = newfontnames.mappings
local newstatus = newfontnames.status
@@ -1061,15 +1072,20 @@ for key, value in next, font_extensions do
font_extensions_set[value] = true
end
---- string -> dbobj -> dbobj -> bool -> (int * int)
-local scan_dir = function (dirname, fontnames, newfontnames)
- --[[
- This function scans a directory and populates the list of fonts
+--[[doc--
+
+ scan_dir() scans a directory and populates the list of fonts
with all the fonts it finds.
- - dirname is the name of the directory to scan
- - names is the font database to fill -> no such term!!!
- - texmf used to be a boolean saying if we are scanning a texmf directory
- ]]
+
+ · dirname : name of the directory to scan
+ · fontnames : current font db object
+ · newnames : font db object to fill
+ · dry_run : don’t touch anything
+
+--doc]]--
+
+--- string -> dbobj -> dbobj -> bool -> (int * int)
+local scan_dir = function (dirname, fontnames, newfontnames, dry_run)
local n_scanned, n_new = 0, 0 --- total of fonts collected
report("both", 2, "db", "scanning directory %s", dirname)
for _,i in next, font_extensions do
@@ -1083,9 +1099,16 @@ local scan_dir = function (dirname, fontnames, newfontnames)
for j=1, n_found do
local fullname = found[j]
fullname = path_normalize(fullname)
- report("both", 4, "db", "loading font “%s”", fullname)
- local new = load_font(fullname, fontnames, newfontnames)
- if new then n_new = n_new + 1 end
+ local new
+ if dry_run == true then
+ report("both", 1, "db", "would have been loading “%s”", fullname)
+ else
+ report("both", 4, "db", "loading font “%s”", fullname)
+ local new = load_font(fullname, fontnames, newfontnames)
+ if new == true then
+ n_new = n_new + 1
+ end
+ end
end
end
end
@@ -1093,7 +1116,8 @@ local scan_dir = function (dirname, fontnames, newfontnames)
return n_scanned, n_new
end
-local function scan_texmf_fonts(fontnames, newfontnames)
+--- 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
@@ -1109,7 +1133,7 @@ local function scan_texmf_fonts(fontnames, newfontnames)
if not stringis_empty(fontdirs) then
for _,d in next, filesplitpath(fontdirs) do
report("info", 4, "db", "Entering directory %s", d)
- local found, new = scan_dir(d, fontnames, newfontnames)
+ local found, new = scan_dir(d, fontnames, newfontnames, dry_run)
n_scanned = n_scanned + found
n_new = n_new + new
end
@@ -1343,6 +1367,7 @@ do --- closure for read_fonts_conf()
end --- read_fonts_conf closure
--- TODO stuff those paths into some writable table
+--- unit -> string list
local function get_os_dirs()
if os.name == 'macosx' then
return {
@@ -1365,7 +1390,8 @@ local function get_os_dirs()
return {}
end
-local function scan_os_fonts(fontnames, newfontnames)
+--- dbobj -> dbobj -> bool? -> (int * int)
+local scan_os_fonts = function (fontnames, newfontnames, dry_run)
local n_scanned, n_new = 0, 0
--[[
This function scans the OS fonts through
@@ -1375,23 +1401,27 @@ local function scan_os_fonts(fontnames, newfontnames)
]]
report("info", 2, "db", "Scanning OS fonts...")
report("info", 3, "db", "Searching in static system directories...")
- for _,d in next, get_os_dirs() do
- local found, new = scan_dir(d, fontnames, newfontnames)
+ for _, d in next, get_os_dirs() do
+ local found, new = scan_dir(d, fontnames, newfontnames, dry_run)
n_scanned = n_scanned + found
n_new = n_new + new
end
return n_scanned, n_new
end
-flush_cache = function ()
+--- unit -> (bool, lookup_cache)
+flush_lookup_cache = function ()
if not names.lookups then names.lookups = load_lookups() end
names.lookups = { }
collectgarbage"collect"
return true, names.lookups
end
---- dbobj -> bool -> dbobj
-update_names = function (fontnames, force)
+--- force: dictate rebuild from scratch
+--- dry_dun: don’t write to the db, just scan dirs
+
+--- dbobj? -> bool? -> bool? -> dbobj
+update_names = function (fontnames, force, dry_run)
if config.luaotfload.update_live == false then
report("info", 2, "db",
"skipping database update")
@@ -1412,7 +1442,7 @@ update_names = function (fontnames, force)
fontnames = fontnames_init(false)
else
if not fontnames then
- fontnames = load_names()
+ fontnames = load_names(dry_run)
end
if fontnames.version ~= names.version then
report("both", 1, "db", "No font names database or old "
@@ -1424,11 +1454,11 @@ update_names = function (fontnames, force)
read_blacklist()
local scanned, new
- scanned, new = scan_texmf_fonts(fontnames, newfontnames)
+ scanned, new = scan_texmf_fonts(fontnames, newfontnames, dry_run)
n_scanned = n_scanned + scanned
n_new = n_new + new
- scanned, new = scan_os_fonts(fontnames, newfontnames)
+ scanned, new = scan_os_fonts(fontnames, newfontnames, dry_run)
n_scanned = n_scanned + scanned
n_new = n_new + new
@@ -1457,7 +1487,7 @@ end
--- file. As we update it after every single addition this saves us
--- quite some time.
---- unit -> string
+--- unit -> bool
save_lookups = function ( )
---- this is boilerplate and should be refactored into something
---- usable by both the db and the cache writers
@@ -1471,19 +1501,19 @@ save_lookups = function ( )
os.remove(lucname)
caches.compile(lookups, luaname, lucname)
report("both", 3, "cache", "Lookup cache saved")
- return names.path.lookup_path
+ return true
end
end
end
report("info", 0, "cache", "Could not write lookup cache")
- return nil
+ return false
end
--- save_names() is usually called without the argument
---- dbobj -> unit
+--- dbobj? -> bool
save_names = function (fontnames)
if not fontnames then fontnames = names.data end
- local path = ensure_names_path()
+ local path = ensure_names_path()
if fileiswritable(path) then
local luaname, lucname = make_name(names.path.path)
if luaname then
@@ -1492,38 +1522,170 @@ save_names = function (fontnames)
if lucname and type(caches.compile) == "function" then
os.remove(lucname)
caches.compile(fontnames, luaname, lucname)
- report("info", 0, "db", "Font names database saved")
- return names.path.path
+ report("info", 1, "db", "Font names database saved")
+ return true
end
end
end
report("both", 0, "db", "Failed to save names database")
- return nil
+ return false
end
-scan_external_dir = function (dir)
- local old_names, new_names
- if fonts_loaded then
- old_names = names.data
- else
- old_names = load_names()
+--[[doc--
+
+ Below set of functions is modeled after mtx-cache.
+
+--doc]]--
+
+--- string -> string -> string list -> string list -> string list -> unit
+local print_cache = function (category, path, luanames, lucnames, rest)
+ local report_indeed = function (...)
+ report("info", 0, "cache", ...)
end
- new_names = tablecopy(old_names)
- local n_scanned, n_new = scan_dir(dir, old_names, new_names)
- names.data = new_names
- return n_scanned, n_new
+ report_indeed("Luaotfload cache: %s", category)
+ report_indeed("location: %s", path)
+ report_indeed("[raw] %4i", #luanames)
+ report_indeed("[compiled] %4i", #lucnames)
+ report_indeed("[other] %4i", #rest)
+ report_indeed("[total] %4i", #luanames + #lucnames + #rest)
+end
+
+--- string -> string -> string list -> bool -> bool
+local purge_from_cache = function (category, path, list, all)
+ report("info", 2, "cache", "Luaotfload cache: %s %s",
+ (all and "erase" or "purge"), category)
+ report("info", 2, "cache", "location: %s",path)
+ local n = 0
+ for i=1,#list do
+ local filename = list[i]
+ if string.find(filename,"luatex%-cache") then -- safeguard
+ if all then
+ report("info", 5, "cache", "removing %s", filename)
+ os.remove(filename)
+ n = n + 1
+ else
+ local suffix = file.suffix(filename)
+ if suffix == "lua" then
+ local checkname = file.replacesuffix(
+ filename, "lua", "luc")
+ if lfs.isfile(checkname) then
+ report("info", 5, "cache", "removing %s", filename)
+ os.remove(filename)
+ n = n + 1
+ end
+ end
+ end
+ end
+ end
+ report("info", 2, "cache", "removed lua files : %i", n)
+ return true
+end
+--- string -> string list -> int -> string list -> string list -> string list ->
+--- (string list * string list * string list * string list)
+local collect_cache collect_cache = function (path, all, n, luanames,
+ lucnames, rest)
+ if not all then
+ local all = dirglob(path .. "/**/*")
+ local luanames, lucnames, rest = { }, { }, { }
+ return collect_cache(nil, all, 1, luanames, lucnames, rest)
+ end
+
+ local filename = all[n]
+ if filename then
+ local suffix = file.suffix(filename)
+ if suffix == "lua" then
+ luanames[#luanames+1] = filename
+ elseif suffix == "luc" then
+ lucnames[#lucnames+1] = filename
+ else
+ rest[#rest+1] = filename
+ end
+ return collect_cache(nil, all, n+1, luanames, lucnames, rest)
+ end
+ return luanames, lucnames, rest, all
end
+--- unit -> unit
+local purge_cache = function ( )
+ local writable_path = caches.getwritablepath()
+ local luanames, lucnames, rest = collect_cache(writable_path)
+ if logs.get_loglevel() > 1 then
+ print_cache("writable path", writable_path, luanames, lucnames, rest)
+ end
+ local success = purge_from_cache("writable path", writable_path, luanames, false)
+ return success
+end
+
+--- unit -> unit
+local erase_cache = function ( )
+ local writable_path = caches.getwritablepath()
+ local luanames, lucnames, rest, all = collect_cache(writable_path)
+ if logs.get_loglevel() > 1 then
+ print_cache("writable path", writable_path, luanames, lucnames, rest)
+ end
+ local success = purge_from_cache("writable path", writable_path, all, true)
+ return success
+end
+
+local separator = function ( )
+ report("info", 0, string.rep("-", 67))
+end
+
+--- unit -> unit
+local show_cache = function ( )
+ local readable_paths = caches.getreadablepaths()
+ local writable_path = caches.getwritablepath()
+ local luanames, lucnames, rest = collect_cache(writable_path)
+
+ separator()
+ print_cache("writable path", writable_path, luanames, lucnames, rest)
+ texiowrite_nl""
+ for i=1,#readable_paths do
+ local readable_path = readable_paths[i]
+ if readable_path ~= writable_path then
+ local luanames, lucnames = collect_cache(readable_path)
+ print_cache("readable path",
+ readable_path,luanames,lucnames,rest)
+ end
+ end
+ separator()
+ return true
+end
+
+--- is this used anywhere? we decided to comment it for the
+--- time being.
+--- https://github.com/lualatex/luaotfload/pull/61
+--scan_external_dir = function (dir)
+-- local old_names, new_names
+-- if fonts_loaded then
+-- old_names = names.data
+-- else
+-- old_names = load_names()
+-- end
+-- new_names = tablecopy(old_names)
+-- local n_scanned, n_new = scan_dir(dir, old_names, new_names)
+-- names.data = new_names
+-- return n_scanned, n_new
+--end
+
+-----------------------------------------------------------------------
--- export functionality to the namespace “fonts.names”
-names.flush_cache = flush_cache
+-----------------------------------------------------------------------
+
+names.flush_lookup_cache = flush_lookup_cache
names.save_lookups = save_lookups
names.load = load_names
names.save = save_names
-names.scan = scan_external_dir
+-----.scan = scan_external_dir
names.update = update_names
names.crude_file_lookup = crude_file_lookup
names.crude_file_lookup_verbose = crude_file_lookup_verbose
+--- font cache
+names.purge_cache = purge_cache
+names.erase_cache = erase_cache
+names.show_cache = show_cache
+
--- replace the resolver from luatex-fonts
if config.luaotfload.resolver == "cached" then
report("both", 2, "cache", "caching of name: lookups active")