summaryrefslogtreecommitdiff
path: root/scripts/context/lua/mtx-install.lua
diff options
context:
space:
mode:
Diffstat (limited to 'scripts/context/lua/mtx-install.lua')
-rw-r--r--scripts/context/lua/mtx-install.lua538
1 files changed, 538 insertions, 0 deletions
diff --git a/scripts/context/lua/mtx-install.lua b/scripts/context/lua/mtx-install.lua
new file mode 100644
index 000000000..66f1556c9
--- /dev/null
+++ b/scripts/context/lua/mtx-install.lua
@@ -0,0 +1,538 @@
+if not modules then modules = { } end modules ['mtx-install'] = {
+ version = 1.002,
+ comment = "companion to mtxrun.lua",
+ author = "Hans Hagen, PRAGMA-ADE, Hasselt NL",
+ copyright = "PRAGMA ADE / ConTeXt Development Team",
+ license = "see context related readme files"
+}
+
+-- todo: initial install from zip
+
+local helpinfo = [[
+<?xml version="1.0"?>
+<application>
+ <metadata>
+ <entry name="name">mtx-install</entry>
+ <entry name="detail">ConTeXt Installer</entry>
+ <entry name="version">2.00</entry>
+ </metadata>
+ <flags>
+ <category name="basic">
+ <subcategory>
+ <flag name="platform" value="string"><short>platform (windows, linux, linux-64, osx-intel, osx-ppc, linux-ppc)</short></flag>
+ <flag name="server" value="string"><short>repository url (rsync://contextgarden.net)</short></flag>
+ <flag name="modules" value="string"><short>extra modules (can be list or 'all')</short></flag>
+ <flag name="fonts" value="string"><short>additional fonts (can be list or 'all')</short></flag>
+ <flag name="goodies" value="string"><short>extra binaries (like scite and texworks)</short></flag>
+ <flag name="install"><short>install context</short></flag>
+ <flag name="update"><short>update context</short></flag>
+ <flag name="identify"><short>create list of files</short></flag>
+ </subcategory>
+ </category>
+ </flags>
+</application>
+]]
+
+local gsub, find, escapedpattern = string.gsub, string.find, string.escapedpattern
+local round = math.round
+local savetable, loadtable, sortedhash = table.save, table.load, table.sortedhash
+local copyfile, joinfile, filesize, dirname, addsuffix, basename = file.copy, file.join, file.size, file.dirname, file.addsuffix, file.basename
+local isdir, isfile, walkdir, pushdir, popdir, currentdir = lfs.isdir, lfs.isfile, lfs.dir, lfs.chdir, dir.push, dir.pop, currentdir
+local mkdirs, globdir = dir.mkdirs, dir.glob
+local osremove, osexecute, ostype = os.remove, os.execute, os.type
+local savedata = io.savedata
+local formatters = string.formatters
+
+local fetch = socket.http.request
+
+local application = logs.application {
+ name = "mtx-install",
+ banner = "ConTeXt Installer 2.00",
+ helpinfo = helpinfo,
+}
+
+local report = application.report
+
+scripts = scripts or { }
+scripts.install = scripts.install or { }
+local install = scripts.install
+
+local texformats = {
+ "cont-en",
+ "cont-nl",
+ "cont-cz",
+ "cont-de",
+ "cont-fa",
+ "cont-it",
+ "cont-ro",
+ "cont-uk",
+ "cont-pe",
+}
+
+local platforms = {
+ ["mswin"] = "mswin",
+ ["windows"] = "mswin",
+ ["win32"] = "mswin",
+ ["win"] = "mswin",
+ --
+ ["mswin-64"] = "win64",
+ ["windows-64"] = "win64",
+ ["win64"] = "win64",
+ --
+ ["linux"] = "linux",
+ ["linux-32"] = "linux",
+ ["linux32"] = "linux",
+ --
+ ["linux-64"] = "linux-64",
+ ["linux64"] = "linux-64",
+ --
+ ["linuxmusl-64"] = "linuxmusl-64",
+ --
+ ["linux-armhf"] = "linux-armhf",
+ --
+ ["freebsd"] = "freebsd",
+ --
+ ["freebsd-amd64"] = "freebsd-amd64",
+ --
+ ["kfreebsd"] = "kfreebsd-i386",
+ ["kfreebsd-i386"] = "kfreebsd-i386",
+ --
+ ["kfreebsd-amd64"] = "kfreebsd-amd64",
+ --
+ ["linux-ppc"] = "linux-ppc",
+ ["ppc"] = "linux-ppc",
+ --
+ ["osx"] = "osx-intel",
+ ["macosx"] = "osx-intel",
+ ["osx-intel"] = "osx-intel",
+ ["osxintel"] = "osx-intel",
+ --
+ ["osx-ppc"] = "osx-ppc",
+ ["osx-powerpc"] = "osx-ppc",
+ ["osxppc"] = "osx-ppc",
+ ["osxpowerpc"] = "osx-ppc",
+ --
+ ["osx-64"] = "osx-64",
+ --
+ ["solaris-intel"] = "solaris-intel",
+ --
+ ["solaris-sparc"] = "solaris-sparc",
+ ["solaris"] = "solaris-sparc",
+ --
+ ["unknown"] = "unknown",
+}
+
+function install.identify()
+
+ -- We have to be in "...../tex" where subdirectories are prefixed with
+ -- "texmf". We strip the "tex/texm*/" from the name in the list.
+
+ local function collect(root,tree)
+
+ local path = root .. "/" .. tree
+
+ if isdir(path) then
+
+ local prefix = path .. "/"
+ local files = globdir(prefix .. "**")
+ local pattern = escapedpattern("^" .. prefix)
+
+ local details = { }
+ local total = 0
+
+ for i=1,#files do
+ local name = files[i]
+ local size = filesize(name)
+ local base = gsub(name,pattern,"")
+ local stamp = md5.hex(io.loaddata(name))
+ details[i] = { base, size, stamp }
+ total = total + size
+ end
+ report("%-20s : %4i files, %3.0f MB",tree,#files,total/(1000*1000))
+
+ savetable(path .. ".tma",details)
+
+ end
+
+ end
+
+ local sourceroot = file.join(dir.current(),"tex")
+
+ for d in walkdir("./tex") do
+ if find(d,"%texmf") then
+ collect(sourceroot,d)
+ end
+ end
+
+ savetable("./tex/status.tma",{
+ name = "context",
+ version = "lmtx",
+ date = os.date("%Y-%m-%d"),
+ })
+
+end
+
+function install.update()
+
+ local function validdir(d)
+ local ok = isdir(d)
+ if not ok then
+ mkdirs(d)
+ ok = isdir(d)
+ end
+ return ok
+ end
+
+ local function download(what,url,target,total,done)
+ local data = fetch(url .. "/" .. target)
+ if data then
+ if total and done then
+ report("%-8s : %3i %% : %8i : %s",what,round(100*done/total),#data,target)
+ else
+ report("%-8s : %8i : %s",what,#data,target)
+ end
+ if validdir(dirname(target)) then
+ savedata(target,data)
+ else
+ -- message
+ end
+ end
+ end
+
+ local function remove(what,target)
+ report("%-8s : %8i : %s",what,filesize(target),target)
+ osremove(target)
+ end
+
+ local function ispresent(target)
+ return isfile(target)
+ end
+
+ local function hashed(list)
+ local hash = { }
+ for i=1,#list do
+ local l = list[i]
+ hash[l[1]] = l
+ end
+ return hash
+ end
+
+ local function run(fmt,...)
+ local command = formatters[fmt](...)
+ -- command = gsub(command,"/","\\")
+ report("running: %s",command)
+ osexecute(command)
+ end
+
+ local function prepare(tree)
+ tree = joinfile("tex",tree)
+ mkdirs(tree)
+ end
+
+ local function update(url,what,zipfile,skiplist)
+
+ local tree = joinfile("tex",what)
+
+ local ok = validdir(tree)
+ if not validdir(tree) then
+ report("invalid directory %a",tree)
+ return
+ end
+
+ local lua = tree .. ".tma"
+ local all = url .. "/" .. lua
+ local old = loadtable(lua)
+ local new = fetch(all)
+
+ if new then
+ new = loadstring(new)
+ if new then
+ new = new()
+ end
+ end
+
+ if not new then
+ report("invalid database %a",all)
+ return
+ end
+
+ local total = 0
+ local done = 0
+ local count = 0
+
+ if not old then
+
+ if zipfile then
+ zipfile = addsuffix(what,"zip")
+ end
+ if zipfile then
+ local zipurl = url .. "/" .. zipfile
+ report("fetching %a",zipurl)
+ local zipdata = fetch(zipurl)
+ if zipdata then
+ io.savedata(zipfile,zipdata)
+ else
+ zipfile = false
+ end
+ end
+
+ if type(zipfile) == "string" and isfile(zipfile) then
+
+ -- todo: pcall
+
+ report("unzipping %a",zipfile)
+
+ local specification = {
+ zipname = zipfile,
+ path = ".",
+ -- verbose = true,
+ verbose = "steps",
+ }
+
+ if utilities.zipfiles.unzipdir(specification) then
+ osremove(zipfile)
+ goto done
+ else
+ osremove(zipfile)
+ end
+
+ end
+
+ count = #new
+
+ report("installing %s, %i files",tree,count)
+
+ for i=1,count do
+ total = total + new[i][2]
+ end
+
+ for i=1,count do
+ local entry = new[i]
+ local name = entry[1]
+ local size = entry[2]
+ local target = joinfile(tree,name)
+ done = done + size
+ if not skiplist or not skiplist[basename(name)] then
+ download("new",url,target,total,done)
+ else
+ report("skipping %s",target)
+ end
+ end
+
+ ::done::
+
+ else
+
+ report("updating %s, %i files",tree,#new)
+
+ local hold = hashed(old)
+ local hnew = hashed(new)
+ local todo = { }
+
+ for newname, newhash in sortedhash(hnew) do
+ local target = joinfile(tree,newname)
+ if not skiplist or not skiplist[basename(newname)] then
+ local oldhash = hold[newname]
+ local action = nil
+ if not oldhash then
+ action = "added"
+ elseif oldhash[3] ~= newhash[3] then
+ action = "changed"
+ elseif not ispresent(joinfile(tree,newname)) then
+ action = "missing"
+ end
+ if action then
+ local size = newhash[2]
+ total = total + size
+ todo[#todo+1] = { action, target, size }
+ end
+ else
+ report("skipping %s",target)
+ end
+ end
+
+ count = #todo
+
+ for i=1,count do
+ local entry = todo[i]
+ download(entry[1],url,entry[2],total,done)
+ done = done + entry[3]
+ end
+
+ for oldname, oldhash in sortedhash(hold) do
+ local newhash = hnew[oldname]
+ local target = joinfile(tree,oldname)
+ if not newhash and ispresent(target) then
+ remove("removed",target)
+ end
+ end
+
+ end
+
+ savetable(lua,new)
+
+ return { tree, count, done }
+
+ end
+
+ local targetroot = dir.current()
+
+ local server = environment.arguments.server or ""
+ local instance = environment.arguments.instance or ""
+ local osplatform = os.platform
+ local platform = platforms[osplatform]
+
+ if server == "" then
+ server = "lmtx.contextgarden.net,lmtx.pragma-ade.com,lmtx.pragma-ade.nl,dmz.pragma-ade.nl"
+ end
+ if instance == "" then
+ instance = "install-lmtx"
+ end
+ if not platform then
+ report("unknown platform")
+ return
+ end
+
+ local list = utilities.parsers.settings_to_array(server)
+ local server = false
+
+ for i=1,#list do
+ local host = list[i]
+ local data, status, detail = fetch("http://" .. host .. "/" .. instance .. "/tex/status.tma")
+ if status == 200 and type(data) == "string" then
+ local t = loadstring(data)
+ if type(t) == "function" then
+ t = t()
+ end
+ if type(t) == "table" and t.name == "context" and t.version == "lmtx" then
+ server = host
+ break
+ end
+ end
+ end
+
+ if not server then
+ report("provide valid server and instance")
+ return
+ end
+
+ local url = "http://" .. server .. "/" .. instance .. "/"
+
+ local texmfplatform = "texmf-" .. platform
+
+ report("server : %s",server)
+ report("instance : %s",instance)
+ report("platform : %s",osplatform)
+ report("system : %s",ostype)
+
+ local status = { }
+ local skiplist = {
+ ["mtxrun"] = true,
+ ["context"] = true,
+ ["mtxrun.exe"] = true,
+ ["context.exe"] = true,
+ }
+
+ status[#status+1] = update(url,"texmf",true)
+ status[#status+1] = update(url,"texmf-context",true)
+ status[#status+1] = update(url,texmfplatform,false,skiplist)
+
+ prepare("texmf-cache")
+ prepare("texmf-project")
+ prepare("texmf-fonts")
+ prepare("texmf-local")
+ prepare("texmf-modules")
+
+ local binpath = joinfile(targetroot,"tex",texmfplatform,"bin")
+
+ local luametatex = "luametatex"
+ local mtxrun = "mtxrun"
+ local context = "context"
+
+ if ostype == "windows" then
+ luametatex = addsuffix(luametatex,"exe")
+ mtxrun = addsuffix(mtxrun,"exe")
+ context = addsuffix(context,"exe")
+ end
+
+ local luametatexbin = joinfile(binpath,luametatex)
+ local mtxrunbin = joinfile(binpath,mtxrun)
+ local contextbin = joinfile(binpath,context)
+
+ local cdir = currentdir()
+ local pdir = pushdir(binpath)
+
+ report("current : %S",cdir)
+ report("target : %S",pdir)
+
+ if pdir ~= cdir then
+
+ report("removing : %s",mtxrun)
+ report("removing : %s",context)
+
+ osremove(mtxrun)
+ osremove(context)
+
+ if isfile(luametatex) then
+ lfs.symlink(luametatex,mtxrun)
+ lfs.symlink(luametatex,context)
+ end
+
+ if isfile(mtxrun) then
+ report("linked : %s",mtxrun)
+ else
+ copyfile(luametatex,mtxrun)
+ report("copied : %s",mtxrun)
+ end
+ if isfile(context) then
+ report("linked : %s",context)
+ else
+ copyfile(luametatex,context)
+ report("copied : %s",context)
+ end
+
+ end
+
+ popdir()
+
+ if lfs.setexecutable(luametatexbin) then
+ report("xbit set : %s",luametatexbin)
+ else
+ -- report("xbit bad : %s",luametatexbin)
+ end
+ if lfs.setexecutable(mtxrunbin) then
+ report("xbit set : %s",mtxrunbin)
+ else
+ -- report("xbit bad : %s",mtxrunbin)
+ end
+ if lfs.setexecutable(contextbin) then
+ report("xbit set : %s",contextbin)
+ else
+ -- report("xbit bad : %s",contextbin)
+ end
+
+ run("%s --generate",mtxrunbin)
+ run("%s --make en", contextbin)
+
+ -- in calling script: update mtxrun.exe and mtxrun.lua
+
+ report("")
+ for i=1,#status do
+ report("%-20s : %4i files with %9i bytes installed",unpack(status[i]))
+ end
+ report("")
+
+ report("update, done")
+end
+
+if environment.argument("identify") then
+ install.identify()
+elseif environment.argument("install") then
+ install.update()
+elseif environment.argument("update") then
+ install.update()
+elseif environment.argument("exporthelp") then
+ application.export(environment.argument("exporthelp"),environment.files[1])
+else
+ application.help()
+end