#!/usr/bin/env texlua
-----------------------------------------------------------------------
--         FILE:  mkstatus.lua
--        USAGE:  ./mkstatus.lua
--  DESCRIPTION:  writes the repository state
-- REQUIREMENTS:  luatex, the lualibs package
--       AUTHOR:  Philipp Gesang (Phg), <phg42.2a@gmail.com>
--      VERSION:  1.0
--      CREATED:  2013-07-07 14:01:12+0200
-----------------------------------------------------------------------
--
-- This script generates a list of hashes that serves as the input
-- for the file integrity check (option --diagnose). md5 is all we can
-- assume in Luatex, so it’s really only a superficial test.

kpse.set_program_name "luatex"

local md5 = require "md5"

require "lualibs"

local stringformat = string.format
local md5sumhexa   = md5.sumhexa
local ioloaddata   = io.loaddata
local iosavedata   = io.savedata
local iopopen      = io.popen
local iowrite      = io.write
local lfsisdir     = lfs.isdir
local stringmatch  = string.match

-----------------------------------------------------------------------
-- settings
-----------------------------------------------------------------------

local verbose  = false
local filelist = "./build/luaotfload-status.lua" --- result

local names = {
  --- only the runtime files and scripts
  { "src",      "luaotfload-auxiliary.lua",   },
  { "src/fontloader/runtime",      "fontloader-basics-gen.lua",  },
  --{ "src/fontloader",      "fontloader-basics-nod.lua",  },
  { "build",    "luaotfload-characters.lua",  },
  { "src",      "luaotfload-colors.lua",      },
  { "src",      "luaotfload-database.lua",    },
  { "src",      "luaotfload-diagnostics.lua", },
  { "src",      "luaotfload-features.lua",    },
  --{ "src/fontloader",      "fontloader-fonts-cbk.lua",   },
  --{ "src/fontloader",      "fontloader-fonts-def.lua",   },
  --{ "src/fontloader",      "fontloader-fonts-enc.lua",   },
  --{ "src/fontloader",      "fontloader-fonts-ext.lua",   },
  --{ "src/fontloader",      "fontloader-fonts-lua.lua",   },
  --{ "src/fontloader",      "fontloader-fonts-tfm.lua",   },
  { "build",    "luaotfload-glyphlist.lua",   },
  { "src",      "luaotfload-letterspace.lua", },
  { "src",      "luaotfload-loaders.lua",     },
  { "src",      "luaotfload-log.lua",         },
  { "src",      "luaotfload-main.lua",        },
  { "src/fontloader/runtime",      "fontloader-reference.lua",  },
  --{ "src",      "luaotfload-override.lua",    }, --> part of init now
  { "src",      "luaotfload-parsers.lua",     },
  { "src",      "luaotfload-tool.lua",        },
  { "scripts",  "mkcharacters",               },
  { "scripts",  "mkglyphlist",                },
  { "scripts",  "mkstatus",                   },
}

-----------------------------------------------------------------------
-- helpers
-----------------------------------------------------------------------

local die = function (...)
  io.stderr:write "[fatal error]: "
  io.stderr:write (stringformat (...))
  io.stderr:write "\naborting.\n"
  os.exit (1)
end

local gitcmd = "git log -1 \z
                    --format=\"return {\z
                                %n  revision  = [[%H]],\z
                                %n  timestamp = [[%cd]],\z
                                %n  committer = [[%cn <%ce>]],\z
                                %n}\" \z
                    --date=iso"

local git_info = function ()
  --io.write (gitcmd)
  --io.write "\n"
  local chan = iopopen (gitcmd)
  if not chan then
    die ("this script needs to be run inside \z
          the luaotfload git repository")
  end

  local data = chan:read "*all"
  chan:close ()
  if data and type (data) == "string" and data ~= "" then
    data = load (data)
    if not data then
      die "cannot parse git information"
    end
    return data ()
  end
  die "cannot read from pipe"
end

-----------------------------------------------------------------------
-- functionality
-----------------------------------------------------------------------

local hash_file = function (fname)
  if not lfs.isfile (fname) then
    die ("cannot find %s.", fname)
  end
  local raw = ioloaddata (fname)
  if not raw then
    die ("cannot read from %s.", fname)
  end
  return md5sumhexa (raw)
end

local hash_all
hash_all = function (list, acc)
  if acc == nil then
    local base = table.fastcopy (names)
    return hash_all (table.append (base, list), { })
  end

  local finfo = list[#list]
  list[#list] = nil
  if finfo then
    local fpath, fname
    if type (finfo) == "table" then
      local d, f = finfo [1], finfo [2]
      if lfs.isdir (d) then
        fpath = file.join (d, f)
      else
        fpath = f
      end
      fname = f
    else
      fpath = finfo
    end
    if verbose then
      iowrite "· md5("
      iowrite (fpath)
    end
    local sum = hash_file (fpath)
    if verbose then
      iowrite ") = \""
      iowrite (sum)
      iowrite "\"\n"
    end
    acc[#acc+1] = { fname, sum }
    return hash_all (list, acc)
  end
  return acc
end

local handle_argv = function (argv)
  local ret  = { files = { }, loader = nil }
  local argc = #argv
  if argc < 1 then return ret end
  local argoff = 1
  if argv [1] == "-v" then
    verbose = true
    if argc == 1 then return ret end
    argoff  = 2
  end
  local aux aux = function (acc, i)
    if i > argc then return acc else
      local cur = argv[i]
      if type (cur) == "string" then
        local loader = stringmatch (cur, "--fontloader=(.+)$")
        if loader then
          cur = loader
          acc.loader = file.basename (cur)
        end
        if lfs.isfile (cur) then
          local files = acc.files
          files[#files + 1] = cur
        end
      else
        die ("file not found: %s", tostring (cur))
      end
      return aux (acc, i + 1)
    end
  end
  return aux (ret, argoff)
end

local add_files
add_files = function (lst, acc)
  if lst == nil then return end
  if acc == nil then return add_files (lst, { }) end
  local len   = #lst
  if len == 0 then return acc end
  local cur   = lst[len]
  local fname = file.basename (cur)
  local path  = file.dirname (cur)
  acc[#acc + 1] = { path, fname }
  lst[len] = nil
  return add_files (lst, acc)
end

local main = function ()
  local raw_extra   = handle_argv (arg)
  local cuit_extra  = add_files (raw_extra.files)
  local hashes      = hash_all (cuit_extra)
  local notes       = git_info ()
  notes.loader      = raw_extra.loader
  local serialized  = table.serialize ({ notes = notes,
                                         hashes = hashes }, true)
  local success     = io.savedata (filelist, serialized)
  if success == false then
    die ("could not write to %s.", filelist)
  end
  return 0
end

return main ()

--- vim:ft=lua:ts=2:et:sw=2