mtx-update.lua /size: 26 Kb    last modification: 2021-10-28 13:50
1if not modules then modules = { } end modules ['mtx-update'] = {
2    version   = 1.002,
3    comment   = "companion to mtxrun.lua",
4    author    = "Hans Hagen, PRAGMA-ADE, Hasselt NL",
5    copyright = "PRAGMA ADE / ConTeXt Development Team",
6    license   = "see context related readme files"
7}
8
9-- This script is dedicated to Mojca Miklavec, who is the driving force behind
10-- moving minimal generation from our internal machines to the context garden.
11-- Together with Arthur Reutenauer she made sure that it worked well on all
12-- platforms that matter.
13
14-- LuaTeX and LuajitTeX are now always installed together.
15
16local helpinfo = [[
17<?xml version="1.0"?>
18<application>
19 <metadata>
20  <entry name="name">mtx-update</entry>
21  <entry name="detail">ConTeXt Minimals Updater</entry>
22  <entry name="version">1.03</entry>
23 </metadata>
24 <flags>
25  <category name="basic">
26   <subcategory>
27    <flag name="platform" value="string"><short>platform (windows, linux, linux-64, osx-intel, osx-ppc, linux-ppc)</short></flag>
28    <flag name="server" value="string"><short>repository url (rsync://contextgarden.net)</short></flag>
29    <flag name="module" value="string"><short>repository url (minimals)</short></flag>
30    <flag name="repository" value="string"><short>specify version (current, experimental)</short></flag>
31    <flag name="context" value="string"><short>specify version (current, latest, beta, yyyy.mm.dd)</short></flag>
32    <flag name="rsync" value="string"><short>rsync binary (rsync)</short></flag>
33    <flag name="texroot" value="string"><short>installation directory (not guessed for the moment)</short></flag>
34    <flag name="engine" value="string"><short>tex engine (luatex, pdftex, xetex)</short></flag>
35    <flag name="modules" value="string"><short>extra modules (can be list or 'all')</short></flag>
36    <flag name="fonts" value="string"><short>additional fonts (can be list or 'all')</short></flag>
37    <flag name="goodies" value="string"><short>extra binaries (like scite and texworks)</short></flag>
38    <flag name="force"><short>instead of a dryrun, do the real thing</short></flag>
39    <flag name="update"><short>update minimal tree</short></flag>
40    <flag name="make"><short>also make formats and generate file databases</short></flag>
41    <flag name="keep"><short>don't delete unused or obsolete files</short></flag>
42    <flag name="state"><short>update tree using saved state</short></flag>
43    <flag name="cygwin"><short>adapt drive specs to cygwin</short></flag>
44    <flag name="mingw"><short>assume mingw binaries being used</short></flag>
45    <flag name="silent"><short>less (or no) logging</short></flag>
46   </subcategory>
47  </category>
48 </flags>
49</application>
50]]
51
52local application = logs.application {
53    name     = "mtx-update",
54    banner   = "ConTeXt Minimals Updater 1.03",
55    helpinfo = helpinfo,
56}
57
58local report = application.report
59
60local format, concat, gmatch, gsub, find = string.format, table.concat, string.gmatch, string.gsub, string.find
61
62scripts         = scripts         or { }
63scripts.update  = scripts.update  or { }
64local update    = scripts.update
65
66minimals        = minimals        or { }
67minimals.config = minimals.config or { }
68
69-- this is needed under windows
70-- else rsync fails to set the right chmod flags to files
71
72os.setenv("CYGWIN","nontsec")
73
74update.texformats = {
75    "cont-en",
76    "cont-nl",
77    "cont-cz",
78    "cont-de",
79    "cont-fa",
80    "cont-it",
81    "cont-ro",
82    "cont-uk",
83    "cont-pe",
84 -- "cont-xp",
85    "mptopdf",
86    "plain"
87}
88
89-- update.mpformats = {
90--  -- "metafun",
91--  -- "mpost",
92-- }
93
94-- experimental is not functional at the moment
95
96update.repositories = {
97    "current",
98    "experimental"
99}
100
101-- list of basic folders that are needed to make a functional distribution
102
103update.base = {
104    { "base/tex/",                "texmf" },
105    { "base/metapost/",           "texmf" },
106    { "fonts/common/",            "texmf" },
107    { "fonts/other/",             "texmf" }, -- not *really* needed, but helpful
108    { "context/<version>/",       "texmf-context" },
109    { "misc/setuptex/",           "." },
110    { "misc/web2c",               "texmf" },
111    { "bin/common/<platform>/",   "texmf-<platform>" },
112    { "bin/context/<platform>/",  "texmf-<platform>" },
113    { "bin/metapost/<platform>/", "texmf-<platform>" },
114    { "bin/man/",                 "texmf-<platform>" },
115}
116
117-- binaries and font-related files
118-- for pdftex we don't need OpenType fonts, for LuaTeX/XeTeX we don't need TFM files
119
120update.defaultengine = "luatex"
121update.rsyncvariant  = "cygwin" -- will be come mingw
122
123update.engines = {
124    ["luatex"] = {
125        { "fonts/new/",               "texmf" },
126        { "bin/luatex/<platform>/",   "texmf-<platform>" },
127     -- { "bin/luajittex/<platform>/","texmf-<platform>" },
128    },
129    ["xetex"] = {
130        { "base/xetex/",              "texmf" },
131        { "fonts/new/",               "texmf" },
132        { "bin/luatex/<platform>/",   "texmf-<platform>" }, -- tools
133        { "bin/xetex/<platform>/",    "texmf-<platform>" },
134    },
135    ["pdftex"] = {
136        { "fonts/old/",               "texmf" },
137        { "bin/luatex/<platform>/",   "texmf-<platform>" }, -- tools
138        { "bin/pdftex/<platform>/",   "texmf-<platform>" },
139    },
140    ["all"] = {
141        { "fonts/new/",               "texmf" },
142        { "fonts/old/",               "texmf" },
143        { "base/xetex/",              "texmf" },
144        { "bin/luatex/<platform>/",   "texmf-<platform>" },
145     -- { "bin/luajittex/<platform>/","texmf-<platform>" },
146        { "bin/xetex/<platform>/",    "texmf-<platform>" },
147        { "bin/pdftex/<platform>/",   "texmf-<platform>" },
148    },
149}
150
151update.goodies = {
152    ["scite"] = {
153        { "bin/<platform>/scite/",    "texmf-<platform>" },
154    },
155    ["texworks"] = {
156        { "bin/<platform>/texworks/", "texmf-<platform>" },
157    },
158}
159
160update.platforms = {
161    ["mswin"]          = "mswin",
162    ["windows"]        = "mswin",
163    ["win32"]          = "mswin",
164    ["win"]            = "mswin",
165    --
166    ["mswin-64"]       = "win64",
167    ["windows-64"]     = "win64",
168    ["win64"]          = "win64",
169    --
170    ["linux"]          = "linux",
171    ["linux-32"]       = "linux",
172    ["linux32"]        = "linux",
173    --
174    ["linux-64"]       = "linux-64",
175    ["linux64"]        = "linux-64",
176    --
177    ["linuxmusl-64"]   = "linuxmusl-64",
178    --
179    ["linux-armhf"]    = "linux-armhf",
180    --
181    ["openbsd"]        = "openbsd7.0",
182    ["openbsd-i386"]   = "openbsd7.0",
183    ["openbsd-amd64"]  = "openbsd7.0-amd64",
184    --
185    ["freebsd"]        = "freebsd",
186    ["freebsd-i386"]   = "freebsd",
187    ["freebsd-amd64"]  = "freebsd-amd64",
188    --
189 -- ["kfreebsd"]       = "kfreebsd-i386",
190 -- ["kfreebsd-i386"]  = "kfreebsd-i386",
191 -- ["kfreebsd-amd64"] = "kfreebsd-amd64",
192    --
193 -- ["linux-ppc"]      = "linux-ppc",
194 -- ["ppc"]            = "linux-ppc",
195    --
196 -- ["osx"]            = "osx-intel",
197 -- ["macosx"]         = "osx-intel",
198 -- ["osx-intel"]      = "osx-intel",
199 -- ["osxintel"]       = "osx-intel",
200    --
201 -- ["osx-ppc"]        = "osx-ppc",
202 -- ["osx-powerpc"]    = "osx-ppc",
203 -- ["osxppc"]         = "osx-ppc",
204 -- ["osxpowerpc"]     = "osx-ppc",
205    --
206    ["macosx"]         = "osx-64",
207    ["osx"]            = "osx-64",
208    ["osx-64"]         = "osx-64",
209    ["osx-arm"]        = "osx-arm64",
210    ["osx-arm64"]      = "osx-arm64",
211    --
212 -- ["solaris-intel"]  = "solaris-intel",
213    --
214 -- ["solaris-sparc"]  = "solaris-sparc",
215 -- ["solaris"]        = "solaris-sparc",
216    --
217    ["unknown"]        = "unknown",
218}
219
220local windowsplatform = {
221    ["mswin"] = true,
222    ["win32"] = true,
223    ["win64"] = true,
224}
225
226update.selfscripts = {
227    "mtxrun",
228 -- "luatools",
229}
230
231-- the list is filled up later (when we know what modules to download)
232
233update.modules = {
234}
235
236update.fonts = {
237}
238
239function update.run(str)
240    -- important, otherwise formats fly to a weird place
241    -- (texlua sets luatex as the engine, we need to reset that or to fix texexec :)
242    os.setenv("engine",nil)
243    if environment.argument("force") then
244        report("run, %s",str)
245        os.execute(str)
246    else
247        report("dry run, %s",str)
248    end
249end
250
251function update.fullpath(path)
252    if file.is_rootbased_path(path) then
253        return path
254    else
255        return lfs.currentdir() .. "/" .. path
256    end
257end
258
259local function drive(d)
260    if update.rsyncvariant == "cygwin" then
261        d = gsub(d,[[([a-zA-Z]):/]], "/cygdrive/%1/")
262    else
263        d = gsub(d,[[([a-zA-Z]):/]], "/%1/")
264    end
265    return d
266end
267
268function update.synchronize()
269
270    report("update, start")
271
272    local texroot      = update.fullpath(states.get("paths.root"))
273    local engines      = states.get('engines') or { }
274    local platforms    = states.get('platforms') or { }
275    local repositories = states.get('repositories')      -- minimals
276    local bin          = states.get("rsync.program")     -- rsync
277    local url          = states.get("rsync.server")      -- contextgarden.net
278    local version      = states.get("context.version")   -- current (or beta)
279    local modules      = states.get("modules")           -- modules (third party)
280    local fonts        = states.get("fonts")             -- fonts (experimental or special)
281    local goodies      = states.get("goodies")           -- goodies (like editors)
282    local force        = environment.argument("force")
283    local silent       = environment.argument("silent") and "--silent" or ""
284    local quiet        = silent == "" and "" or "--quiet"
285
286    bin = gsub(bin,"\\","/")
287
288    if not find(url,"::$") then url = url .. "::" end
289    local ok = lfs.attributes(texroot,"mode") == "directory"
290    if not ok and force then
291        dir.mkdirs(texroot)
292        ok = lfs.attributes(texroot,"mode") == "directory"
293    end
294
295    if force then
296        dir.mkdirs(format("%s/%s", texroot, "texmf-cache"))
297        dir.mkdirs(format("%s/%s", texroot, "texmf-local"))
298        dir.mkdirs(format("%s/%s", texroot, "texmf-project"))
299        dir.mkdirs(format("%s/%s", texroot, "texmf-fonts"))
300        dir.mkdirs(format("%s/%s", texroot, "texmf-modules"))
301    end
302
303    if ok or not force then
304
305        local fetched, individual, osplatform = { }, { }, os.platform
306
307        -- takes a collection as argument and returns a list of folders
308
309        local function collection_to_list_of_folders(collection, platform)
310            local archives = {}
311            for i=1,#collection do
312                local archive = collection[i][1]
313                archive = gsub(archive,"<platform>",platform)
314                archive = gsub(archive,"<version>",version)
315                archives[#archives+1] = archive
316            end
317            return archives
318        end
319
320        -- takes a list of folders as argument and returns a string for rsync
321        -- sample input:
322        --     {'bin/common', 'bin/context'}
323        -- output:
324        --     'minimals/current/bin/common minimals/current/bin/context'
325
326        local function list_of_folders_to_rsync_string(list_of_folders)
327            local repository  = 'current'
328            local prefix = format("%s/%s/", states.get('rsync.module'), repository) -- minimals/current/
329
330            return prefix .. concat(list_of_folders, format(" %s", prefix))
331        end
332
333        -- example of usage: print(list_of_folders_to_rsync_string(collection_to_list_of_folders(update.base, os.platform)))
334
335        -- rename function and add some more functionality:
336        --   * recursive/non-recursive (default: non-recursive)
337        --   * filter folders or regular files only (default: no filter)
338        --   * grep for size of included files (with --stats switch)
339
340        local function get_list_of_files_from_rsync(list_of_folders)
341            -- temporary file to store the output of rsync (could be a more random name; watch for overwrites)
342            local temp_file = "rsync.tmp.txt"
343            -- a set of folders
344            local folders = {}
345            local command = format("%s %s'%s' > %s", bin, url, list_of_folders_to_rsync_string(list_of_folders), temp_file)
346            os.execute(command)
347            -- read output of rsync
348            local data = io.loaddata(temp_file) or ""
349            -- for every line extract the filename :  drwxr-sr-x          18 2013/10/06 06:16:10 libertine
350            for chmod, s in gmatch(data,"([d%-][rwxst%-]+).-(%S+)[\n\r]") do
351                -- skip "current" folder
352                if s ~= '.' and #chmod >= 10 then
353                    folders[#folders+1] = s
354                end
355            end
356            -- delete the file to which we have put output of rsync
357            os.remove(temp_file)
358            return folders
359        end
360
361        -- rsync://contextgarden.net/minimals/current/modules/
362
363        local available_platforms = get_list_of_files_from_rsync({"bin/luatex/"})
364
365        report("available platforms: % t",table.sorted(available_platforms))
366
367        if modules and type(modules) == "table" then
368            -- fetch the list of available modules from rsync server
369         -- local available_modules = get_list_of_files_from_rsync({"modules/"})
370            -- hash of requested modules
371            -- local h = table.tohash(modules:split(","))
372            local available_modules = get_list_of_files_from_rsync({"modules/"})
373            local asked = table.copy(modules)
374            asked.all = nil
375            report("available modules: %s",#available_modules)
376            for i=1,#available_modules do
377                local s = available_modules[i]
378                if modules.all or modules[s] then
379                    update.modules[#update.modules+1] = { format("modules/%s/",s), "texmf-modules" }
380                    report("+ %s",s)
381                else
382                    report("  %s",s)
383                end
384                asked[s] = nil
385            end
386            if next(asked) then
387                report("skipping unknown modules: %s",concat(table.sortedkeys(asked),", "))
388            end
389        end
390
391        -- rsync://contextgarden.net/minimals/current/fonts/extra/
392
393        if fonts and type(fonts) == "table" then
394            local available_fonts = get_list_of_files_from_rsync({"fonts/extra/"})
395            local asked = table.copy(fonts)
396            asked.all = nil
397            for i=1,#available_fonts do
398                local s = available_fonts[i]
399                if fonts.all or fonts[s] then
400                    update.fonts[#update.fonts+1] = { format("fonts/extra/%s/",s), "texmf" }
401                end
402                asked[s] = nil
403            end
404            if next(asked) then
405                report("skipping unknown fonts: %s",concat(table.sortedkeys(asked),", "))
406            end
407        end
408
409        local function add_collection(collection,platform)
410            if collection and platform then
411                platform = update.platforms[platform]
412                if platform then
413                    for i=1,#collection do
414                        local c = collection[i]
415                        local archive = gsub(c[1],"<platform>",platform)
416                        local destination = format("%s/%s", texroot, gsub(c[2],"<platform>", platform))
417                        destination = gsub(destination,"\\","/")
418                        archive = gsub(archive,"<version>",version)
419                        if osplatform == "windows" or osplatform == "mswin" or osplatform == "win64" then
420                            destination = drive(destination)
421                        end
422                        individual[#individual+1] = { archive, destination }
423                    end
424                end
425            end
426        end
427
428        for platform in table.sortedhash(platforms) do
429            add_collection(update.base,platform)
430        end
431        for platform in table.sortedhash(platforms) do
432            add_collection(update.modules,platform)
433        end
434        for platform in table.sortedhash(platforms) do
435            add_collection(update.fonts,platform)
436        end
437        for engine in table.sortedhash(engines) do
438            for platform in table.sortedhash(platforms) do
439                add_collection(update.engines[engine],platform)
440            end
441        end
442
443        if goodies and type(goodies) == "table" then
444            for goodie in table.sortedhash(goodies) do
445                for platform in table.sortedhash(platforms) do
446                    add_collection(update.goodies[goodie],platform)
447                end
448            end
449        end
450
451        local combined = { }
452        local update_repositories = update.repositories
453        for i=1,#update_repositories do
454            local repository = update_repositories[i]
455            if repositories[repository] then
456                for _, v in table.sortedhash(individual) do
457                    local archive, destination = v[1], v[2]
458                    local cd = combined[destination]
459                    if not cd then
460                        cd = { }
461                        combined[destination] = cd
462                    end
463                    cd[#cd+1] = format("%s/%s/%s",states.get('rsync.module'),repository,archive)
464                end
465            end
466        end
467        for destination, archive in table.sortedhash(combined) do
468            local archives, command = concat(archive," "), ""
469            local normalflags, deleteflags = states.get("rsync.flags.normal"), ""
470            if os.name == "windows" then
471                normalflags = normalflags .. " -L" -- no symlinks
472            end
473            local dryrunflags = ""
474            if not environment.argument("force") then
475                dryrunflags = "--dry-run"
476            end
477            if (find(destination,"texmf$") or find(destination,"texmf%-context$") or find(destination,"texmf%-modules$")) and (not environment.argument("keep")) then
478                deleteflags = states.get("rsync.flags.delete")
479            end
480            command = format("%s %s %s %s %s'%s' '%s'", bin, normalflags, deleteflags, dryrunflags, url, archives, drive(destination))
481            -- report("running command: %s",command)
482            if not fetched[command] then
483                update.run(command,true)
484                fetched[command] = command
485            end
486        end
487
488        local function update_script(script, platform)
489            local bin = gsub(bin,"\\","/")
490            local texroot = gsub(texroot,"\\","/")
491            platform = update.platforms[platform]
492            if platform then
493                local command
494                if windowsplatform[platform] then
495                    bin = drive(bin)
496                    texroot = drive(texroot)
497                    command = format([[%s -t "%s/texmf-context/scripts/context/lua/%s.lua" "%s/texmf-%s/bin/"]], bin, texroot, script, texroot, platform)
498                else
499                    command = format([[%s -tgo --chmod=a+x '%s/texmf-context/scripts/context/lua/%s.lua' '%s/texmf-%s/bin/%s']], bin, texroot, script, texroot, platform, script)
500                end
501                report("updating %s for %s: %s", script, platform, command)
502                update.run(command)
503            end
504        end
505
506        for platform in table.sortedhash(platforms) do
507            for i=1, #update.selfscripts do
508                update_script(update.selfscripts[i],platform)
509            end
510        end
511
512    else
513        report("no valid texroot: %s",texroot)
514    end
515    if not force then
516        report("use --force to really update files")
517    end
518
519    resolvers.load_tree(texroot) -- else we operate in the wrong tree
520
521    -- update filename database for pdftex/xetex
522    update.run(format('mtxrun --tree="%s" %s --direct --resolve mktexlsr %s',texroot,silent,quiet))
523    -- update filename database for luatex
524    update.run(format('mtxrun --tree="%s" %s --generate',texroot,silent))
525
526    report("update, done")
527end
528
529function table.fromhash(t)
530    local h = { }
531    for k, v in table.sortedhash(t) do -- not indexed
532        if v then h[#h+1] = k end
533    end
534    return h
535end
536
537-- make the ConTeXt formats
538function update.make()
539
540    report("make, start")
541
542    local force     = environment.argument("force")
543    local silent    = environment.argument("silent") and "--silent" or ""
544    local quiet     = silent == "" and "" or "--quiet"
545    local texroot   = update.fullpath(states.get("paths.root"))
546    local engines   = states.get('engines')
547    local goodies   = states.get('goodies')
548    local platforms = states.get('platforms')
549    local formats   = states.get('formats')
550
551    resolvers.load_tree(texroot)
552
553    update.run(format('mtxrun --tree="%s" %s --direct --resolve mktexlsr %s',texroot,silent,quiet))
554    update.run(format('mtxrun --tree="%s" %s --generate',texroot,silent))
555
556    local askedformats = formats
557    local texformats = table.tohash(update.texformats)
558 -- local mpformats = table.tohash(update.mpformats)
559    for k,v in table.sortedhash(texformats) do
560        if not askedformats[k] then
561            texformats[k] = nil
562        end
563    end
564 -- for k,v in table.sortedhash(mpformats) do
565 --     if not askedformats[k] then
566 --         mpformats[k] = nil
567 --     end
568 -- end
569    local formatlist = concat(table.fromhash(texformats), " ")
570    if formatlist ~= "" then
571        for engine in table.sortedhash(engines) do
572            if engine == "luatex" or engine == "luajittex" then
573                update.run(format('mtxrun --tree="%s" %s --script context --autogenerate --make %s',texroot,silent,silent))
574                update.run(format('mtxrun --tree="%s" %s --script context --autogenerate --make --engine=luajittex %s',texroot,silent,silent))
575            else
576             -- update.run(format('mtxrun --tree="%s" %s --script texexec --make --all %s --%s %s',texroot,silent,silent,engine,formatlist))
577                update.run(format('mtxrun --tree="%s" --resolve %s --script context --resolve --make %s --engine=%s %s',texroot,silent,silent,engine,formatlist))
578            end
579        end
580    end
581 -- local formatlist = concat(table.fromhash(mpformats), " ")
582 -- if formatlist ~= "" then
583 --     update.run(format('mtxrun --tree="%s" %s --script texexec --make --all %s %s',texroot,silent,silent,formatlist))
584 -- end
585    if not force then
586        report("make, use --force to really make formats")
587    end
588
589 -- update.run(format('mtxrun --tree="%s" %s --direct --resolve mktexlsr',texroot,silent)) -- needed for mpost
590    update.run(format('mtxrun --tree="%s" %s --generate',texroot,silent))
591
592    report("make, done")
593end
594
595scripts.savestate = true
596
597if scripts.savestate then
598
599    states.load("status-of-update.lua")
600
601    -- tag, value, default, persistent
602
603    statistics.starttiming(states)
604
605    states.set("info.version",0.1) -- ok
606    states.set("info.count",(states.get("info.count") or 0) + 1,1,false) -- ok
607    states.set("info.comment","this file contains the settings of the last 'mtxrun --script update' run",false) -- ok
608    states.set("info.date",os.date("!%Y-%m-%d %H:%M:%S")) -- ok
609
610    states.set("rsync.program", environment.argument("rsync"), "rsync", true) -- ok
611    states.set("rsync.server", environment.argument("server"), "contextgarden.net::", true) -- ok
612    states.set("rsync.module", environment.argument("module"), "minimals", true) -- ok
613    states.set("rsync.flags.normal", environment.argument("flags"), "-rpztlv", true) -- ok
614    states.set("rsync.flags.delete", nil, "--delete", true) -- ok
615
616    states.set("paths.root", environment.argument("texroot"), "tex", true) -- ok
617
618    states.set("context.version", environment.argument("context"), "current", true) -- ok
619
620    local valid = table.tohash(update.repositories)
621    for r in gmatch(environment.argument("repository") or "current","([^, ]+)") do
622        if valid[r] then states.set("   ." .. r, true) end
623    end
624
625    local valid = update.engines
626    local engine = environment.argument("engine") or ""
627    if engine == "" then
628        local e = states.get("engines")
629        if not e or not next(e) then
630            engine = update.defaultengine
631        end
632    end
633    if engine ~= "" then
634        for r in gmatch(engine,"([^, ]+)") do
635            if r == "all" then
636                for k, v in next, valid do
637                    if k ~= "all" then
638                        states.set("engines." .. k, true)
639                    end
640                end
641                break
642            elseif valid[r] then
643                states.set("engines." .. r, true)
644            end
645        end
646    end
647
648    -- old
649
650    local valid = update.platforms
651    for r in gmatch(environment.argument("platform") or os.platform,"([^, ]+)") do
652        if valid[r] then states.set("platforms." .. r, true) end
653    end
654
655    -- new
656
657--     local osplatform = environment.arguments.platform or nil
658--     local platform   = platforms[osplatform or os.platform or ""]
659--
660--     if (platform == "unknown" or platform == "" or not platform) and osplatform then
661--         -- catches openbsdN.M kind of specifications
662--         platform = osplatform
663--     elseif not osplatform then
664--         osplatform = platform
665--     end
666--     states.set("platforms." .. platform, true) end
667
668    -- so far
669
670    local valid = table.tohash(update.texformats)
671    for r in gmatch(environment.argument("formats") or "","([^, ]+)") do
672        if valid[r] then states.set("formats." .. r, true) end
673    end
674
675 -- local valid = table.tohash(update.mpformats)
676 -- for r in gmatch(environment.argument("formats") or "","([^, ]+)") do
677 --     if valid[r] then states.set("formats." .. r, true) end
678 -- end
679
680    states.set("formats.cont-en", true)
681    states.set("formats.cont-nl", true)
682 -- states.set("formats.metafun", true)
683
684    for r in gmatch(environment.argument("extras") or "","([^, ]+)") do -- for old times sake
685        if r ~= "all" and not find(r,"^[a-z]%-") then
686            r = "t-" .. r
687        end
688        states.set("modules." .. r, true)
689    end
690    for r in gmatch(environment.argument("modules") or "","([^, ]+)") do
691        if r ~= "all" and not find(r,"^[a-z]%-") then
692            r = "t-" .. r
693        end
694        states.set("modules." .. r, true)
695    end
696    for r in gmatch(environment.argument("fonts") or "","([^, ]+)") do
697        states.set("fonts." .. r, true)
698    end
699    for r in gmatch(environment.argument("goodies") or "","([^, ]+)") do
700        states.set("goodies." .. r, true)
701    end
702
703    report("state, loaded")
704    report()
705
706end
707
708if environment.argument("state") then
709    environment.setargument("update",true)
710    environment.setargument("force",true)
711    environment.setargument("make",true)
712end
713
714if environment.argument("mingw") then
715    update.rsyncvariant = "mingw"
716elseif environment.argument("cygwin") then
717    update.rsyncvariant = "cygwin"
718end
719
720if environment.argument("update") then
721    update.synchronize()
722    if environment.argument("make") then
723        update.make()
724    end
725elseif environment.argument("make") then
726    update.make()
727elseif environment.argument("exporthelp") then
728    application.export(environment.argument("exporthelp"),environment.files[1])
729else
730    application.help()
731end
732
733if scripts.savestate then
734    statistics.stoptiming(states)
735    states.set("info.runtime",tonumber(statistics.elapsedtime(states)))
736    if environment.argument("force") then
737        states.save()
738        report("state","saved")
739    end
740end
741