mtx-update.lua /size: 26 Kb    last modification: 2024-01-16 09:02
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    ["windows"]        = "win64",
167    ["windows-64"]     = "win64",
168    ["win64"]          = "win64",
169    --
170 -- ["linux"]          = "linux",
171 -- ["linux-32"]       = "linux",
172 -- ["linux32"]        = "linux",
173    --
174    ["linux"]          = "linux-64",
175    ["linux-64"]       = "linux-64",
176    ["linux64"]        = "linux-64",
177    --
178    ["linuxmusl"]      = "linuxmusl",
179    ["linuxmusl-64"]   = "linuxmusl-64",
180    --
181 -- ["linux-armhf"]    = "linux-armhf",
182    --
183    ["openbsd"]        = "openbsd-amd64",
184 -- ["openbsd-i386"]   = "openbsd7.3",
185    ["openbsd-amd64"]  = "openbsd-amd64",
186    --
187    ["freebsd"]        = "freebsd-amd64",
188 -- ["freebsd-i386"]   = "freebsd",
189    ["freebsd-amd64"]  = "freebsd-amd64",
190    --
191 -- ["kfreebsd"]       = "kfreebsd-i386",
192 -- ["kfreebsd-i386"]  = "kfreebsd-i386",
193 -- ["kfreebsd-amd64"] = "kfreebsd-amd64",
194    --
195 -- ["linux-ppc"]      = "linux-ppc",
196 -- ["ppc"]            = "linux-ppc",
197    --
198 -- ["osx"]            = "osx-intel",
199 -- ["macosx"]         = "osx-intel",
200 -- ["osx-intel"]      = "osx-intel",
201 -- ["osxintel"]       = "osx-intel",
202    --
203 -- ["osx-ppc"]        = "osx-ppc",
204 -- ["osx-powerpc"]    = "osx-ppc",
205 -- ["osxppc"]         = "osx-ppc",
206 -- ["osxpowerpc"]     = "osx-ppc",
207    --
208    ["macosx"]         = "osx-64",
209    ["osx"]            = "osx-64",
210    ["osx-intel"]      = "osx-64",
211    ["osx-64"]         = "osx-64",
212    ["osx-arm"]        = "osx-arm64",
213    ["osx-arm64"]      = "osx-arm64",
214    --
215 -- ["solaris-intel"]  = "solaris-intel",
216    --
217 -- ["solaris-sparc"]  = "solaris-sparc",
218 -- ["solaris"]        = "solaris-sparc",
219    --
220    ["unknown"]        = "unknown",
221}
222
223local windowsplatform = {
224    ["mswin"] = true, -- hm
225    ["win32"] = true, -- hm
226    ["win64"] = true,
227}
228
229update.selfscripts = {
230    "mtxrun",
231 -- "luatools",
232}
233
234-- the list is filled up later (when we know what modules to download)
235
236update.modules = {
237}
238
239update.fonts = {
240}
241
242function update.run(str)
243    -- important, otherwise formats fly to a weird place
244    -- (texlua sets luatex as the engine, we need to reset that or to fix texexec :)
245    os.setenv("engine",nil)
246    if environment.argument("force") then
247        report("run, %s",str)
248        os.execute(str)
249    else
250        report("dry run, %s",str)
251    end
252end
253
254function update.fullpath(path)
255    if file.is_rootbased_path(path) then
256        return path
257    else
258        return lfs.currentdir() .. "/" .. path
259    end
260end
261
262local function drive(d)
263    if update.rsyncvariant == "cygwin" then
264        d = gsub(d,[[([a-zA-Z]):/]], "/cygdrive/%1/")
265    else
266        d = gsub(d,[[([a-zA-Z]):/]], "/%1/")
267    end
268    return d
269end
270
271function update.synchronize()
272
273    report("update, start")
274
275    local texroot      = update.fullpath(states.get("paths.root"))
276    local engines      = states.get('engines') or { }
277    local platforms    = states.get('platforms') or { }
278    local repositories = states.get('repositories')      -- minimals
279    local bin          = states.get("rsync.program")     -- rsync
280    local url          = states.get("rsync.server")      -- contextgarden.net
281    local version      = states.get("context.version")   -- current (or beta)
282    local modules      = states.get("modules")           -- modules (third party)
283    local fonts        = states.get("fonts")             -- fonts (experimental or special)
284    local goodies      = states.get("goodies")           -- goodies (like editors)
285    local force        = environment.argument("force")
286    local silent       = environment.argument("silent") and "--silent" or ""
287    local quiet        = silent == "" and "" or "--quiet"
288
289    bin = gsub(bin,"\\","/")
290
291    if not find(url,"::$") then url = url .. "::" end
292    local ok = lfs.attributes(texroot,"mode") == "directory"
293    if not ok and force then
294        dir.mkdirs(texroot)
295        ok = lfs.attributes(texroot,"mode") == "directory"
296    end
297
298    if force then
299        dir.mkdirs(format("%s/%s", texroot, "texmf-cache"))
300        dir.mkdirs(format("%s/%s", texroot, "texmf-local"))
301        dir.mkdirs(format("%s/%s", texroot, "texmf-project"))
302        dir.mkdirs(format("%s/%s", texroot, "texmf-fonts"))
303        dir.mkdirs(format("%s/%s", texroot, "texmf-modules"))
304    end
305
306    if ok or not force then
307
308        local fetched, individual, osplatform = { }, { }, os.platform
309
310        -- takes a collection as argument and returns a list of folders
311
312        local function collection_to_list_of_folders(collection, platform)
313            local archives = {}
314            for i=1,#collection do
315                local archive = collection[i][1]
316                archive = gsub(archive,"<platform>",platform)
317                archive = gsub(archive,"<version>",version)
318                archives[#archives+1] = archive
319            end
320            return archives
321        end
322
323        -- takes a list of folders as argument and returns a string for rsync
324        -- sample input:
325        --     {'bin/common', 'bin/context'}
326        -- output:
327        --     'minimals/current/bin/common minimals/current/bin/context'
328
329        local function list_of_folders_to_rsync_string(list_of_folders)
330            local repository  = 'current'
331            local prefix = format("%s/%s/", states.get('rsync.module'), repository) -- minimals/current/
332
333            return prefix .. concat(list_of_folders, format(" %s", prefix))
334        end
335
336        -- example of usage: print(list_of_folders_to_rsync_string(collection_to_list_of_folders(update.base, os.platform)))
337
338        -- rename function and add some more functionality:
339        --   * recursive/non-recursive (default: non-recursive)
340        --   * filter folders or regular files only (default: no filter)
341        --   * grep for size of included files (with --stats switch)
342
343        local function get_list_of_files_from_rsync(list_of_folders)
344            -- temporary file to store the output of rsync (could be a more random name; watch for overwrites)
345            local temp_file = "rsync.tmp.txt"
346            -- a set of folders
347            local folders = {}
348            local command = format("%s %s'%s' > %s", bin, url, list_of_folders_to_rsync_string(list_of_folders), temp_file)
349            os.execute(command)
350            -- read output of rsync
351            local data = io.loaddata(temp_file) or ""
352            -- for every line extract the filename :  drwxr-sr-x          18 2013/10/06 06:16:10 libertine
353            for chmod, s in gmatch(data,"([d%-][rwxst%-]+).-(%S+)[\n\r]") do
354                -- skip "current" folder
355                if s ~= '.' and #chmod >= 10 then
356                    folders[#folders+1] = s
357                end
358            end
359            -- delete the file to which we have put output of rsync
360            os.remove(temp_file)
361            return folders
362        end
363
364        -- rsync://contextgarden.net/minimals/current/modules/
365
366        local available_platforms = get_list_of_files_from_rsync({"bin/luatex/"})
367
368        report("available platforms: % t",table.sorted(available_platforms))
369
370        if modules and type(modules) == "table" then
371            -- fetch the list of available modules from rsync server
372         -- local available_modules = get_list_of_files_from_rsync({"modules/"})
373            -- hash of requested modules
374            -- local h = table.tohash(modules:split(","))
375            local available_modules = get_list_of_files_from_rsync({"modules/"})
376            local asked = table.copy(modules)
377            asked.all = nil
378            report("available modules: %s",#available_modules)
379            for i=1,#available_modules do
380                local s = available_modules[i]
381                if modules.all or modules[s] then
382                    update.modules[#update.modules+1] = { format("modules/%s/",s), "texmf-modules" }
383                    report("+ %s",s)
384                else
385                    report("  %s",s)
386                end
387                asked[s] = nil
388            end
389            if next(asked) then
390                report("skipping unknown modules: %s",concat(table.sortedkeys(asked),", "))
391            end
392        end
393
394        -- rsync://contextgarden.net/minimals/current/fonts/extra/
395
396        if fonts and type(fonts) == "table" then
397            local available_fonts = get_list_of_files_from_rsync({"fonts/extra/"})
398            local asked = table.copy(fonts)
399            asked.all = nil
400            for i=1,#available_fonts do
401                local s = available_fonts[i]
402                if fonts.all or fonts[s] then
403                    update.fonts[#update.fonts+1] = { format("fonts/extra/%s/",s), "texmf" }
404                end
405                asked[s] = nil
406            end
407            if next(asked) then
408                report("skipping unknown fonts: %s",concat(table.sortedkeys(asked),", "))
409            end
410        end
411
412        local function add_collection(collection,platform)
413            if collection and platform then
414                platform = update.platforms[platform]
415                if platform then
416                    for i=1,#collection do
417                        local c = collection[i]
418                        local archive = gsub(c[1],"<platform>",platform)
419                        local destination = format("%s/%s", texroot, gsub(c[2],"<platform>", platform))
420                        destination = gsub(destination,"\\","/")
421                        archive = gsub(archive,"<version>",version)
422                        if osplatform == "windows" or osplatform == "mswin" or osplatform == "win64" then
423                            destination = drive(destination)
424                        end
425                        individual[#individual+1] = { archive, destination }
426                    end
427                end
428            end
429        end
430
431        for platform in table.sortedhash(platforms) do
432            add_collection(update.base,platform)
433        end
434        for platform in table.sortedhash(platforms) do
435            add_collection(update.modules,platform)
436        end
437        for platform in table.sortedhash(platforms) do
438            add_collection(update.fonts,platform)
439        end
440        for engine in table.sortedhash(engines) do
441            for platform in table.sortedhash(platforms) do
442                add_collection(update.engines[engine],platform)
443            end
444        end
445
446        if goodies and type(goodies) == "table" then
447            for goodie in table.sortedhash(goodies) do
448                for platform in table.sortedhash(platforms) do
449                    add_collection(update.goodies[goodie],platform)
450                end
451            end
452        end
453
454        local combined = { }
455        local update_repositories = update.repositories
456        for i=1,#update_repositories do
457            local repository = update_repositories[i]
458            if repositories[repository] then
459                for _, v in table.sortedhash(individual) do
460                    local archive, destination = v[1], v[2]
461                    local cd = combined[destination]
462                    if not cd then
463                        cd = { }
464                        combined[destination] = cd
465                    end
466                    cd[#cd+1] = format("%s/%s/%s",states.get('rsync.module'),repository,archive)
467                end
468            end
469        end
470        for destination, archive in table.sortedhash(combined) do
471            local archives, command = concat(archive," "), ""
472            local normalflags, deleteflags = states.get("rsync.flags.normal"), ""
473            if os.name == "windows" then
474                normalflags = normalflags .. " -L" -- no symlinks
475            end
476            local dryrunflags = ""
477            if not environment.argument("force") then
478                dryrunflags = "--dry-run"
479            end
480            if (find(destination,"texmf$") or find(destination,"texmf%-context$") or find(destination,"texmf%-modules$")) and (not environment.argument("keep")) then
481                deleteflags = states.get("rsync.flags.delete")
482            end
483            command = format("%s %s %s %s %s'%s' '%s'", bin, normalflags, deleteflags, dryrunflags, url, archives, drive(destination))
484            -- report("running command: %s",command)
485            if not fetched[command] then
486                update.run(command,true)
487                fetched[command] = command
488            end
489        end
490
491        local function update_script(script, platform)
492            local bin = gsub(bin,"\\","/")
493            local texroot = gsub(texroot,"\\","/")
494            platform = update.platforms[platform]
495            if platform then
496                local command
497                if windowsplatform[platform] then
498                    bin = drive(bin)
499                    texroot = drive(texroot)
500                    command = format([[%s -t "%s/texmf-context/scripts/context/lua/%s.lua" "%s/texmf-%s/bin/"]], bin, texroot, script, texroot, platform)
501                else
502                    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)
503                end
504                report("updating %s for %s: %s", script, platform, command)
505                update.run(command)
506            end
507        end
508
509        for platform in table.sortedhash(platforms) do
510            for i=1, #update.selfscripts do
511                update_script(update.selfscripts[i],platform)
512            end
513        end
514
515    else
516        report("no valid texroot: %s",texroot)
517    end
518    if not force then
519        report("use --force to really update files")
520    end
521
522    resolvers.load_tree(texroot) -- else we operate in the wrong tree
523
524    -- update filename database for pdftex/xetex
525    update.run(format('mtxrun --tree="%s" %s --direct --resolve mktexlsr %s',texroot,silent,quiet))
526    -- update filename database for luatex
527    update.run(format('mtxrun --tree="%s" %s --generate',texroot,silent))
528
529    report("update, done")
530end
531
532function table.fromhash(t)
533    local h = { }
534    for k, v in table.sortedhash(t) do -- not indexed
535        if v then h[#h+1] = k end
536    end
537    return h
538end
539
540-- make the ConTeXt formats
541function update.make()
542
543    report("make, start")
544
545    local force     = environment.argument("force")
546    local silent    = environment.argument("silent") and "--silent" or ""
547    local quiet     = silent == "" and "" or "--quiet"
548    local texroot   = update.fullpath(states.get("paths.root"))
549    local engines   = states.get('engines')
550    local goodies   = states.get('goodies')
551    local platforms = states.get('platforms')
552    local formats   = states.get('formats')
553
554    resolvers.load_tree(texroot)
555
556    update.run(format('mtxrun --tree="%s" %s --direct --resolve mktexlsr %s',texroot,silent,quiet))
557    update.run(format('mtxrun --tree="%s" %s --generate',texroot,silent))
558
559    local askedformats = formats
560    local texformats = table.tohash(update.texformats)
561 -- local mpformats = table.tohash(update.mpformats)
562    for k,v in table.sortedhash(texformats) do
563        if not askedformats[k] then
564            texformats[k] = nil
565        end
566    end
567 -- for k,v in table.sortedhash(mpformats) do
568 --     if not askedformats[k] then
569 --         mpformats[k] = nil
570 --     end
571 -- end
572    local formatlist = concat(table.fromhash(texformats), " ")
573    if formatlist ~= "" then
574        for engine in table.sortedhash(engines) do
575            if engine == "luatex" or engine == "luajittex" then
576                update.run(format('mtxrun --tree="%s" %s --script context --autogenerate --make %s',texroot,silent,silent))
577                update.run(format('mtxrun --tree="%s" %s --script context --autogenerate --make --engine=luajittex %s',texroot,silent,silent))
578            else
579             -- update.run(format('mtxrun --tree="%s" %s --script texexec --make --all %s --%s %s',texroot,silent,silent,engine,formatlist))
580                update.run(format('mtxrun --tree="%s" --resolve %s --script context --resolve --make %s --engine=%s %s',texroot,silent,silent,engine,formatlist))
581            end
582        end
583    end
584 -- local formatlist = concat(table.fromhash(mpformats), " ")
585 -- if formatlist ~= "" then
586 --     update.run(format('mtxrun --tree="%s" %s --script texexec --make --all %s %s',texroot,silent,silent,formatlist))
587 -- end
588    if not force then
589        report("make, use --force to really make formats")
590    end
591
592 -- update.run(format('mtxrun --tree="%s" %s --direct --resolve mktexlsr',texroot,silent)) -- needed for mpost
593    update.run(format('mtxrun --tree="%s" %s --generate',texroot,silent))
594
595    report("make, done")
596end
597
598scripts.savestate = true
599
600if scripts.savestate then
601
602    states.load("status-of-update.lua")
603
604    -- tag, value, default, persistent
605
606    statistics.starttiming(states)
607
608    states.set("info.version",0.1) -- ok
609    states.set("info.count",(states.get("info.count") or 0) + 1,1,false) -- ok
610    states.set("info.comment","this file contains the settings of the last 'mtxrun --script update' run",false) -- ok
611    states.set("info.date",os.date("!%Y-%m-%d %H:%M:%S")) -- ok
612
613    states.set("rsync.program", environment.argument("rsync"), "rsync", true) -- ok
614    states.set("rsync.server", environment.argument("server"), "contextgarden.net::", true) -- ok
615    states.set("rsync.module", environment.argument("module"), "minimals", true) -- ok
616    states.set("rsync.flags.normal", environment.argument("flags"), "-rpztlv", true) -- ok
617    states.set("rsync.flags.delete", nil, "--delete", true) -- ok
618
619    states.set("paths.root", environment.argument("texroot"), "tex", true) -- ok
620
621    states.set("context.version", environment.argument("context"), "current", true) -- ok
622
623    local valid = table.tohash(update.repositories)
624    for r in gmatch(environment.argument("repository") or "current","([^, ]+)") do
625        if valid[r] then states.set("   ." .. r, true) end
626    end
627
628    local valid = update.engines
629    local engine = environment.argument("engine") or ""
630    if engine == "" then
631        local e = states.get("engines")
632        if not e or not next(e) then
633            engine = update.defaultengine
634        end
635    end
636    if engine ~= "" then
637        for r in gmatch(engine,"([^, ]+)") do
638            if r == "all" then
639                for k, v in next, valid do
640                    if k ~= "all" then
641                        states.set("engines." .. k, true)
642                    end
643                end
644                break
645            elseif valid[r] then
646                states.set("engines." .. r, true)
647            end
648        end
649    end
650
651    -- old
652
653    local valid = update.platforms
654    for r in gmatch(environment.argument("platform") or os.platform,"([^, ]+)") do
655        if valid[r] then states.set("platforms." .. r, true) end
656    end
657
658    -- new
659
660--     local osplatform = environment.arguments.platform or nil
661--     local platform   = platforms[osplatform or os.platform or ""]
662--
663--     if (platform == "unknown" or platform == "" or not platform) and osplatform then
664--         -- catches openbsdN.M kind of specifications
665--         platform = osplatform
666--     elseif not osplatform then
667--         osplatform = platform
668--     end
669--     states.set("platforms." .. platform, true) end
670
671    -- so far
672
673    local valid = table.tohash(update.texformats)
674    for r in gmatch(environment.argument("formats") or "","([^, ]+)") do
675        if valid[r] then states.set("formats." .. r, true) end
676    end
677
678 -- local valid = table.tohash(update.mpformats)
679 -- for r in gmatch(environment.argument("formats") or "","([^, ]+)") do
680 --     if valid[r] then states.set("formats." .. r, true) end
681 -- end
682
683    states.set("formats.cont-en", true)
684    states.set("formats.cont-nl", true)
685 -- states.set("formats.metafun", true)
686
687    for r in gmatch(environment.argument("extras") or "","([^, ]+)") do -- for old times sake
688        if r ~= "all" and not find(r,"^[a-z]%-") then
689            r = "t-" .. r
690        end
691        states.set("modules." .. r, true)
692    end
693    for r in gmatch(environment.argument("modules") or "","([^, ]+)") do
694        if r ~= "all" and not find(r,"^[a-z]%-") then
695            r = "t-" .. r
696        end
697        states.set("modules." .. r, true)
698    end
699    for r in gmatch(environment.argument("fonts") or "","([^, ]+)") do
700        states.set("fonts." .. r, true)
701    end
702    for r in gmatch(environment.argument("goodies") or "","([^, ]+)") do
703        states.set("goodies." .. r, true)
704    end
705
706    report("state, loaded")
707    report()
708
709end
710
711if environment.argument("state") then
712    environment.setargument("update",true)
713    environment.setargument("force",true)
714    environment.setargument("make",true)
715end
716
717if environment.argument("mingw") then
718    update.rsyncvariant = "mingw"
719elseif environment.argument("cygwin") then
720    update.rsyncvariant = "cygwin"
721end
722
723if environment.argument("update") then
724    update.synchronize()
725    if environment.argument("make") then
726        update.make()
727    end
728elseif environment.argument("make") then
729    update.make()
730elseif environment.argument("exporthelp") then
731    application.export(environment.argument("exporthelp"),environment.files[1])
732else
733    application.help()
734end
735
736if scripts.savestate then
737    statistics.stoptiming(states)
738    states.set("info.runtime",tonumber(statistics.elapsedtime(states)))
739    if environment.argument("force") then
740        states.save()
741        report("state","saved")
742    end
743end
744