r411 - trunk/scripts

DONOTREPLY at icculus.org DONOTREPLY at icculus.org
Sun Jan 13 07:50:39 EST 2008


Author: icculus
Date: 2008-01-13 07:50:39 -0500 (Sun, 13 Jan 2008)
New Revision: 411

Removed:
   trunk/scripts/loki_setup_compat.lua
Modified:
   trunk/scripts/config.lua
   trunk/scripts/mojosetup_init.lua
   trunk/scripts/mojosetup_mainline.lua
Log:
Generate manifests for installs in various formats, and other cleanups
 related to that effort.


Modified: trunk/scripts/config.lua
===================================================================
--- trunk/scripts/config.lua	2008-01-13 12:48:19 UTC (rev 410)
+++ trunk/scripts/config.lua	2008-01-13 12:50:39 UTC (rev 411)
@@ -42,6 +42,7 @@
     superuser = false,
     destination = "/usr/local/bin",
     recommended_destinations = { "/opt/games", "/usr/local/games" },
+    updateurl = "http://localhost/updates/",
 
     -- Things named Setup.Something are internal functions we supply.
     --  Generally these return the table you pass to them, but they

Deleted: trunk/scripts/loki_setup_compat.lua
===================================================================
--- trunk/scripts/loki_setup_compat.lua	2008-01-13 12:48:19 UTC (rev 410)
+++ trunk/scripts/loki_setup_compat.lua	2008-01-13 12:50:39 UTC (rev 411)
@@ -1,100 +0,0 @@
--- MojoSetup; a portable, flexible installation application.
---
--- Please see the file LICENSE.txt in the source's root directory.
---
---  This file written by Ryan C. Gordon.
-
-
--- Compatibility with loki_setup and related tools.
---
--- You can cut-and-paste this file into your config script, or call this at
---  the start of it:  MojoSetup.runfile("loki_setup_compat")
--- This code is optional, and not otherwise referenced by MojoSetup. It could
---  be useful for those that need to integrate with loki_update, etc.
---
--- Using this code requires you to build with the Lua "io" runtime library.
---  (for now, at least).
-
-MojoSetup.Loki = {}
-
-
--- !!! FIXME: some of these are currently-undocumented MojoSetup.* methods...
-
-function MojoSetup.Loki.manifest(install, update_url)
-    local manifestdir = MojoSetup.destination .. "/.manifest"
-    MojoSetup.installed_files[#MojoSetup.installed_files+1] = manifestdir
-    if not MojoSetup.platform.mkdir(manifestdir) then
-        -- !!! FIXME: formatting
-        MojoSetup.logerror("Failed to create dir '" .. manifestdir .. "'")
-        MojoSetup.fatal(_("mkdir failed"))
-    end
-
-    local manifestfile = manifestdir .. "/" .. install.id .. ".xml"
-    MojoSetup.installed_files[#MojoSetup.installed_files+1] = manifestfile
-    local f, err = io.open(manifestfile, "a")
-    if f == nil then
-        MojoSetup.logerror("Couldn't create manifest: " .. err)
-        MojoSetup.fatal(_("Couldn't create manifest"))
-    end
-
-    if update_url ~= nil then
-        update_url = 'update_url="' .. update_url .. '"'
-    else
-        update_url = ''
-    end
-
-    -- !!! FIXME: check i/o errors
-    f:write('<?xml version="1.0" encoding="UTF-8"?>\n')
-    f:write('<product name="' .. install.id .. '" desc="' ..
-            install.description .. '" xmlversion="1.6" root="'
-            .. MojoSetup.destination .. '" ' .. update_url .. '>\n')
-    f:write('  <component name="Default" version="' .. install.version ..
-            '" default="yes">\n')
-
-    local destlen = string.len(MojoSetup.destination) + 2
-    for option,items in pairs(MojoSetup.manifest) do
-        f:write('    <option name="' .. option.description .. '">\n')
-        for i,item in ipairs(items) do
-            local type = item.type
-            if type == "dir" then
-                type = "directory"
-            end
-
-            local mode = item.mode
-            if mode == nil then
-                mode = "0600"   -- !!! FIXME
-            end
-
-            local path = item.path
-            if path ~= nil then
-                path = string.sub(path, destlen)  -- make it relative.
-            end
-
-            local xml = '      <' .. type
-
-            if type == "file" then
-                for k,v in pairs(item.checksums) do
-                    xml = xml .. ' ' .. k .. '="' .. v .. '"'
-                end
-                xml = xml .. ' mode="' .. mode .. '"'
-            elseif type == "directory" then
-                xml = xml .. ' mode="' .. mode .. '"'
-            elseif type == "symlink" then
-                xml = xml .. ' dest="' .. item.linkdest .. '" mode="0777"'
-            end
-
-            xml = xml .. '>' .. path .. "</" .. type .. ">\n"
-            f:write(xml)
-        end
-        f:write('    </option>\n')
-    end
-
-    f:write('  </component>\n')
-    f:write('</product>\n\n')
-
-    -- !!! FIXME: check i/o errors
-    f:close()
-end
-
--- end of loki_setup_compat.lua ...
-

Modified: trunk/scripts/mojosetup_init.lua
===================================================================
--- trunk/scripts/mojosetup_init.lua	2008-01-13 12:48:19 UTC (rev 410)
+++ trunk/scripts/mojosetup_init.lua	2008-01-13 12:50:39 UTC (rev 411)
@@ -339,7 +339,7 @@
         { "category", "Games", mustBeString, cantBeEmpty },
         { "promptoverwrite", true, mustBeBool },
         { "binarypath", nil, mustBeString, cantBeEmpty },
-        { "update_url", nil, mustBeString, mustBeUrl },
+        { "updateurl", nil, mustBeString, mustBeUrl },
         { "superuser", false, mustBeBool },
     })
 

Modified: trunk/scripts/mojosetup_mainline.lua
===================================================================
--- trunk/scripts/mojosetup_mainline.lua	2008-01-13 12:48:19 UTC (rev 410)
+++ trunk/scripts/mojosetup_mainline.lua	2008-01-13 12:50:39 UTC (rev 411)
@@ -88,6 +88,26 @@
 end
 
 
+-- get a linear array of filenames in the manifest.
+local function flatten_manifest()
+    local man = MojoSetup.manifest
+    local files = {}
+
+    if man ~= nil then
+        for key,items in pairs(man) do
+            for i,item in ipairs(items) do
+                local path = item.path
+                if path ~= nil then
+                    files[#files+1] = path
+                end
+            end
+        end
+    end
+
+    return files
+end
+
+
 -- This gets called by fatal()...must be a global function.
 function MojoSetup.revertinstall()
     -- !!! FIXME: language.
@@ -99,7 +119,7 @@
 
     -- !!! FIXME: callbacks here.
     delete_files(MojoSetup.downloads)
-    delete_files(MojoSetup.installed_files)
+    delete_files(flatten_manifest())
     do_rollbacks()
     delete_scratchdirs()
 end
@@ -233,11 +253,11 @@
 end
 
 
-local function install_file(dest, archive, file, perms, option)
+local function install_file(dest, perms, writefn, desc, manifestkey)
     -- Upvalued so we don't look these up each time...
     local fname = string.gsub(dest, "^.*/", "", 1)  -- chop the dirs off...
     local ptype = _("Installing")  -- !!! FIXME: localization.
-    local component = option.description
+    local component = desc
     local keepgoing = true
     local callback = function(ticks, justwrote, bw, total)
         local percent = -1
@@ -251,8 +271,22 @@
         return keepgoing
     end
 
-    MojoSetup.installed_files[#MojoSetup.installed_files+1] = dest
-    local written, sums = MojoSetup.writefile(archive, dest, perms, callback)
+    -- Add to manifest first, so we can delete it during rollback if i/o fails.
+    local manifestentry =
+    {
+        type = "file",
+        path = dest,
+        mode = perms,    -- !!! FIXME: perms may be nil...we need a MojoSetup.defaultPermsString()...
+    }
+    if manifestkey ~= nil then
+        if MojoSetup.manifest[manifestkey] == nil then
+            MojoSetup.manifest[manifestkey] = {}
+        end
+        local manifest = MojoSetup.manifest[manifestkey]
+        manifest[#manifest+1] = manifestentry
+    end
+
+    local written, sums = writefn(callback)
     if not written then
         -- !!! FIXME: formatting!
         if not keepgoing then
@@ -264,39 +298,42 @@
         end
     end
 
-    -- !!! FIXME: perms may be null...we need a MojoSetup.defaultPermsString()...
+    manifestentry.checksums = sums
 
-    if option ~= nil then
-        if MojoSetup.manifest[option] == nil then
-            MojoSetup.manifest[option] = {}
-        end
-        local manifest = MojoSetup.manifest[option]
-        manifest[#manifest+1] =
-        {
-            type = "file",
-            path = dest,
-            checksums = sums,
-            mode = perms,
-        }
+    MojoSetup.loginfo("Created file '" .. dest .. "'")
+end
+
+
+local function install_file_from_archive(dest, archive, perms, desc, manifestkey)
+    local fn = function(callback)
+        return MojoSetup.writefile(archive, dest, perms, callback)
     end
+    return install_file(dest, perms, fn, desc, manifestkey)
+end
 
-    MojoSetup.loginfo("Created file '" .. dest .. "'")
+
+local function install_file_from_string(dest, string, perms, desc, manifestkey)
+    local fn = function(callback)
+        return MojoSetup.stringtofile(string, dest, perms, callback)
+    end
+    return install_file(dest, perms, fn, desc, manifestkey)
 end
 
 
-local function install_symlink(dest, lndest, option)
-    MojoSetup.installed_files[#MojoSetup.installed_files+1] = dest
+-- !!! FIXME: we should probably pump the GUI queue here, in case there are
+-- !!! FIXME:  thousands of symlinks in a row or something.
+local function install_symlink(dest, lndest, manifestkey)
     if not MojoSetup.platform.symlink(dest, lndest) then
         -- !!! FIXME: formatting!
         MojoSetup.logerror("Failed to create symlink '" .. dest .. "'")
         MojoSetup.fatal(_("symlink creation failed!"))
     end
 
-    if option ~= nil then
-        if MojoSetup.manifest[option] == nil then
-            MojoSetup.manifest[option] = {}
+    if manifestkey ~= nil then
+        if MojoSetup.manifest[manifestkey] == nil then
+            MojoSetup.manifest[manifestkey] = {}
         end
-        local manifest = MojoSetup.manifest[option]
+        local manifest = MojoSetup.manifest[manifestkey]
         manifest[#manifest+1] =
         {
             type = "symlink",
@@ -309,19 +346,20 @@
 end
 
 
-local function install_directory(dest, perms, option)
-    MojoSetup.installed_files[#MojoSetup.installed_files+1] = dest
+-- !!! FIXME: we should probably pump the GUI queue here, in case there are
+-- !!! FIXME:  thousands of dirs in a row or something.
+local function install_directory(dest, perms, manifestkey)
     if not MojoSetup.platform.mkdir(dest, perms) then
         -- !!! FIXME: formatting
         MojoSetup.logerror("Failed to create dir '" .. dest .. "'")
         MojoSetup.fatal(_("mkdir failed"))
     end
 
-    if option ~= nil then
-        if MojoSetup.manifest[option] == nil then
-            MojoSetup.manifest[option] = {}
+    if manifestkey ~= nil then
+        if MojoSetup.manifest[manifestkey] == nil then
+            MojoSetup.manifest[manifestkey] = {}
         end
-        local manifest = MojoSetup.manifest[option]
+        local manifest = MojoSetup.manifest[manifestkey]
         manifest[#manifest+1] =
         {
             type = "dir",
@@ -334,7 +372,7 @@
 end
 
 
-local function install_parent_dirs(path, option)
+local function install_parent_dirs(path, manifestkey)
     -- Chop any '/' chars from the end of the string...
     path = string.gsub(path, "/+$", "")
 
@@ -344,7 +382,7 @@
         if item ~= "" then
             fullpath = fullpath .. "/" .. item
             if not MojoSetup.platform.exists(fullpath) then
-                install_directory(fullpath, nil, option)
+                install_directory(fullpath, nil, manifestkey)
             end
         end
     end
@@ -386,7 +424,6 @@
             if allowoverwrite then
                 local id = #MojoSetup.rollbacks + 1
                 local f = MojoSetup.rollbackdir .. "/" .. id
-                -- !!! FIXME: don't add (f) to the installed_files table...
                 install_parent_dirs(f, nil)
                 MojoSetup.rollbacks[id] = dest
                 if not MojoSetup.movefile(dest, f) then
@@ -401,7 +438,6 @@
     return allowoverwrite
 end
 
-
 local function install_archive_entry(archive, ent, file, option)
     local entdest = ent.filename
     if entdest == nil then return end   -- probably can't happen...
@@ -429,7 +465,8 @@
         if permit_write(dest, ent, file) then
             install_parent_dirs(dest, option)
             if ent.type == "file" then
-                install_file(dest, archive, file, perms, option)
+                local desc = option.description
+                install_file_from_archive(dest, archive, perms, desc, option)
             elseif ent.type == "dir" then
                 install_directory(dest, perms, option)
             elseif ent.type == "symlink" then
@@ -569,6 +606,7 @@
     -- !!! FIXME: ".mojosetup_tmp" dirname may clash with install...?
     MojoSetup.loginfo("Install dest: '" .. dest .. "'")
     MojoSetup.destination = dest
+    MojoSetup.manifestdir = MojoSetup.destination .. "/.mojosetup_manifest"
     MojoSetup.scratchdir = MojoSetup.destination .. "/.mojosetup_tmp"
     MojoSetup.rollbackdir = MojoSetup.scratchdir .. "/rollbacks"
     MojoSetup.downloaddir = MojoSetup.scratchdir .. "/downloads"
@@ -585,6 +623,191 @@
 end
 
 
+-- The XML manifest is compatible with the loki_setup manifest schema, since
+--  it has a reasonable set of data, and allows you to use loki_update or
+--  loki_patch with a MojoSetup installation. Please note that we never ever
+--  look at this data! You are responsible for updating the other files if
+--  you think it'll be important. The Unix MojoSetup uninstaller uses the
+--  plain text manifest, for example (but loki_uninstall can use the xml one,
+--  so if you want, you can just drop in MojoSetup to replace loki_setup and
+--  use the Loki tools for everything else.
+local function build_xml_manifest()
+    local install = MojoSetup.install
+    local updateurl = install.updateurl
+    if updateurl ~= nil then
+        updateurl = 'update_url="' .. updateurl .. '"'
+    else
+        updateurl = ''
+    end
+
+    local retval =
+        '<?xml version="1.0" encoding="UTF-8"?>\n' ..
+        '<product name="' .. MojoSetup.install.id .. '" desc="' ..
+        install.description .. '" xmlversion="1.6" root="' ..
+        MojoSetup.destination .. '" ' .. updateurl .. '>\n' ..
+        '\t<component name="Default" version="' .. install.version ..
+        '" default="yes">\n'
+
+    local destlen = string.len(MojoSetup.destination) + 2
+    for option,items in pairs(MojoSetup.manifest) do
+        local desc = option
+        if type(desc) == "table" then  -- "meta" etc, or an option table.
+            desc = option.description
+        end
+
+        retval = retval .. '\t\t<option name="' .. desc .. '">\n'
+        for i,item in ipairs(items) do
+            local type = item.type
+            if type == "dir" then
+                type = "directory"
+            end
+
+            -- !!! FIXME: files from archives aren't filling item.mode in
+            -- !!! FIXME:  because it figures out the perms from the archive's
+            -- !!! FIXME:  C struct in native code. Need to get that into Lua.
+            -- !!! FIXME: (and get the perms uint16/string conversion cleaned up)
+            local mode = item.mode
+            if mode == nil then
+                mode = "0644"   -- !!! FIXME
+            end
+
+            local path = item.path
+            if path ~= nil then
+                path = string.sub(path, destlen)  -- make it relative.
+            end
+
+            retval = retval .. '\t\t\t<' .. type
+
+            if type == "file" then
+                if item.checksums ~= nil then
+                    for k,v in pairs(item.checksums) do
+                        retval = retval .. ' ' .. k .. '="' .. v .. '"'
+                    end
+                end
+                retval = retval .. ' mode="' .. mode .. '"'
+            elseif type == "directory" then
+                retval = retval .. ' mode="' .. mode .. '"'
+            elseif type == "symlink" then
+                retval = retval .. ' dest="' .. item.linkdest .. '" mode="0777"'
+            end
+
+            retval = retval .. '>' .. path .. "</" .. type .. ">\n"
+        end
+        retval = retval .. '\t\t</option>\n'
+    end
+
+    retval = retval .. '\t</component>\n'
+    retval = retval .. '</product>\n\n'
+
+    return retval
+end
+
+
+local function build_lua_manifest()
+    local indentation = 0  -- upvalue for serialize()
+    local function serialize(obj)
+        local retval = ''
+
+        indentation = indentation + 1
+
+        local objtype = type(obj)
+        if objtype == "number" then
+            retval = tostring(obj)
+        elseif objtype == "string" then
+            retval = string.format("%q", obj)
+        elseif objtype == "table" then
+            retval = "{\n"
+            local tab = string.rep("\t", indentation)
+            for k,v in pairs(obj) do
+                local key = k
+                if type(key) == "number" then
+                    key = '[' .. key .. ']'
+                elseif not string.match(key, "^[_a-zA-Z][_a-zA-Z0-9]*$") then
+                    key = '[' .. string.format("%q", key) .. ']'
+                end
+                retval = retval .. tab .. key .. " = " .. serialize(v) .. ",\n"
+            end
+            retval = retval .. string.rep("\t", indentation-1) .. "}"
+        else
+            MojoSetup.fatal(_("BUG: Unhandled data type"))
+        end
+
+        indentation = indentation - 1
+        return retval
+    end
+
+    local man = {}
+    for option,items in pairs(MojoSetup.manifest) do
+        local desc = option
+        if type(desc) == "table" then  -- "meta" etc, or an option table.
+            desc = option.description
+        end
+        man[desc] = items;
+    end
+
+    local install = MojoSetup.install
+    return 'package = ' .. serialize {
+        id = install.id,
+        description = install.description,
+        root = MojoSetup.destination,
+        update_url = install.updateurl,
+        version = install.version,
+        manifest = man,
+    } .. "\n\n"
+end
+
+
+local function build_txt_manifest()
+    local retval = ''
+    local destlen = string.len(MojoSetup.destination) + 2
+    local files = flatten_manifest()
+    for i,item in ipairs(files) do
+        local path = item
+        if path ~= nil then
+            path = string.sub(path, destlen)  -- make it relative.
+            retval = retval .. path .. "\n"
+        end
+    end
+    return retval
+end
+
+
+local function install_manifests()
+    -- We write out a Lua script as a data definition language, a
+    --  loki_setup-compatible XML manifest, and a straight text file of
+    --  all the filenames. Take your pick.
+    local key = ".mojosetup_metadata."
+
+    -- We have to cheat and just plug these into the manifest directly, since
+    --  they won't show up until after we write them out, otherwise.
+    -- Obviously, we don't have checksums for them, either, as we haven't
+    --  assembled the data yet!
+    local perms = "0644"  -- !!! FIXME
+    local basefname = MojoSetup.manifestdir .. "/" .. MojoSetup.install.id
+    local lua_fname = basefname .. ".lua"
+    local xml_fname = basefname .. ".xml"
+    local txt_fname = basefname .. ".txt"
+    if MojoSetup.manifest[key] == nil then
+        MojoSetup.manifest[key] = {}
+    end
+    local manifest = MojoSetup.manifest[key]
+    manifest[#manifest+1] = { type = "file", path = lua_fname, mode = perms }
+    manifest[#manifest+1] = { type = "file", path = xml_fname, mode = perms }
+    manifest[#manifest+1] = { type = "file", path = txt_fname, mode = perms }
+
+    -- These are probably all duplicated effort, but just in case...
+    install_parent_dirs(lua_fname, key)
+    install_parent_dirs(xml_fname, key)
+    install_parent_dirs(txt_fname, key)
+
+    -- now build these things...
+    local desc = _("Metadata")
+    install_file_from_string(lua_fname, build_lua_manifest(), perms, desc, nil)
+    install_file_from_string(xml_fname, build_xml_manifest(), perms, desc, nil)
+    install_file_from_string(txt_fname, build_txt_manifest(), perms, desc, nil)
+end
+
+
 local function do_install(install)
     MojoSetup.forceoverwrite = nil
     MojoSetup.written = 0
@@ -864,7 +1087,6 @@
             local id = 0
             for file,option in pairs(MojoSetup.files.downloads) do
                 local f = MojoSetup.downloaddir .. "/" .. id
-                -- !!! FIXME: don't add (f) to the installed_files table...
                 install_parent_dirs(f, nil)
                 id = id + 1
 
@@ -976,6 +1198,9 @@
         end
 
         run_config_defined_hook(install.postinstall, install)
+
+        install_manifests()   -- write out manifest.
+
         return 1   -- go to next stage.
     end
 
@@ -1004,7 +1229,6 @@
     MojoSetup.stages = stages
 
     MojoSetup.manifest = {}
-    MojoSetup.installed_files = {}
     MojoSetup.rollbacks = {}
     MojoSetup.downloads = {}
 
@@ -1033,15 +1257,12 @@
         end
     end
 
-    -- !!! FIXME: write out manifest.
-
     -- Successful install, so delete conflicts we no longer need to rollback.
     delete_rollbacks()
     delete_files(MojoSetup.downloads)
     delete_scratchdirs()
 
     -- Don't let future errors delete files from successful installs...
-    MojoSetup.installed_files = nil
     MojoSetup.downloads = nil
     MojoSetup.rollbacks = nil
 
@@ -1052,6 +1273,7 @@
     stages = nil
     MojoSetup.manifest = nil
     MojoSetup.destination = nil
+    MojoSetup.manifestdir = nil
     MojoSetup.scratchdir = nil
     MojoSetup.rollbackdir = nil
     MojoSetup.downloaddir = nil




More information about the mojosetup-commits mailing list