[mojosetup] [2/13] Delete obsolete files and directories on upgrade.

Francois Gouget fgouget at codeweavers.com
Mon May 21 13:53:29 EDT 2012


We try to be careful when loading the old Lua manifest so that a corrupted file does not crash the installer and does not clobber our state information.
---

Leaving obsolete libraries behind could cause major trouble for 
instance. This requires reading the old manifest to know which files the 
previous version had installed.

 scripts/mojosetup_mainline.lua |   82 +++++++++++++++++++++++++++++++++++-----
 1 file changed, 73 insertions(+), 9 deletions(-)

diff --git a/scripts/mojosetup_mainline.lua b/scripts/mojosetup_mainline.lua
index 1cd8ed9..79489ec 100644
--- a/scripts/mojosetup_mainline.lua
+++ b/scripts/mojosetup_mainline.lua
@@ -105,6 +105,10 @@ local function manifest_add(man, fname, _key, ftype, mode, sums, lndest)
             checksums = sums,
             linkdest = lndest
         }
+
+        if MojoSetup.oldfiles[fname] ~= nil then
+            MojoSetup.oldfiles[fname].seen = true
+        end
     end
 end
 
@@ -505,6 +509,18 @@ local function install_parent_dirs(path, manifestkey)
 end
 
 
+local function backup_file(path)
+    local id = #MojoSetup.rollbacks + 1
+    local f = MojoSetup.rollbackdir .. "/" .. id
+    install_parent_dirs(f, MojoSetup.metadatakey)
+    MojoSetup.rollbacks[id] = path
+    if not MojoSetup.movefile(path, f) then
+        MojoSetup.fatal(MojoSetup.format(_("Couldn't backup '%0' to '%1' for rollback"), path, f))
+    end
+    MojoSetup.loginfo("Moved rollback #" .. id .. ": '" .. path .. "' -> '" .. f .. "'")
+end
+
+
 local function permit_write(dest, entinfo, file)
     local allowoverwrite = true
     if MojoSetup.platform.exists(dest) then
@@ -538,15 +554,7 @@ local function permit_write(dest, entinfo, file)
             -- !!! FIXME: Setup.File.mustoverwrite to override "never"?
 
             if allowoverwrite then
-                local id = #MojoSetup.rollbacks + 1
-                local f = MojoSetup.rollbackdir .. "/" .. id
-                install_parent_dirs(f, MojoSetup.metadatakey)
-                MojoSetup.rollbacks[id] = dest
-                if not MojoSetup.movefile(dest, f) then
-                    MojoSetup.fatal(_("Couldn't backup file for rollback"))
-                end
-                MojoSetup.loginfo("Moved rollback #" .. id .. ": '" .. dest .. "' -> '" .. f .. "'")
-
+                backup_file(dest)
                 -- Make sure this isn't already in the manifest...
                 if MojoSetup.manifest[dest] ~= nil then
                     manifest_delete(MojoSetup.manifest, dest)
@@ -1262,6 +1270,33 @@ local function stop_gui()
 end
 
 
+local function load_oldpackage()
+    local filename = MojoSetup.metadatadir .. "/manifest/" .. MojoSetup.install.id .. ".lua"
+    local fh, err = io.open(filename, "r")
+    if not fh then
+        MojoSetup.logerror("could not open '" .. filename .. "' for reading: " .. err)
+        return {}
+    end
+    local data = fh:read("*all")
+    fh:close()
+
+    local env = {MojoSetup = {}}
+    local lua_func, err = loadstring("function loadstring() end\n" .. data)
+    if not lua_func then
+        MojoSetup.logerror("could not parse '" .. filename .. "': " .. err)
+        return {}
+    end
+    setfenv(lua_func, env)
+
+    local ran, err = pcall(lua_func)
+    if not ran then
+        MojoSetup.logerror("could not run '" .. filename .. "' " .. err)
+        return {}
+    end
+    return env.MojoSetup.package
+end
+
+
 local function do_install(install)
     MojoSetup.forceoverwrite = nil
     MojoSetup.written = 0
@@ -1555,6 +1590,16 @@ local function do_install(install)
     --  This is not a GUI stage, it just needs to run between them.
     --  This gets a little hairy.
     stages[#stages+1] = function(thisstage, maxstage)
+        -- Load the list of files of the previous installation
+        --  (empty if this is a first time install)
+        MojoSetup.oldpackage = load_oldpackage()
+        MojoSetup.oldfiles = {}
+        if MojoSetup.oldpackage ~= nil and MojoSetup.oldpackage.manifest ~= nil then
+            for path,file in pairs(MojoSetup.oldpackage.manifest) do
+                MojoSetup.oldfiles[path] = file
+            end
+        end
+
         -- Make sure we install the destination dir, so it's in the manifest.
         if not MojoSetup.platform.exists(MojoSetup.destination) then
             install_parent_dirs(MojoSetup.destination, MojoSetup.metadatakey)
@@ -1794,6 +1839,14 @@ local function do_install(install)
             install_manifests(MojoSetup.metadatadesc, MojoSetup.metadatakey)
         end
 
+        -- Move away obsolete files so they get deleted
+        for path,file in pairs(MojoSetup.oldfiles) do
+            if file.seen == nil and file.type == 'file' then
+                MojoSetup.loginfo("Obsoleting file '" .. path .. "'")
+                backup_file(MojoSetup.destination .. "/" .. path)
+            end
+        end
+
         return 1   -- go to next stage.
     end
 
@@ -1845,6 +1898,17 @@ local function do_install(install)
     delete_files(MojoSetup.downloads)
     delete_scratchdirs()
 
+    -- Delete obsolete directories
+    table.sort(MojoSetup.oldfiles, function(a,b) return MojoSetup.strcmp(a,b) < 0 end)
+    for path,file in pairs(MojoSetup.oldfiles) do
+        if file.seen == nil and file.type == 'directory' then
+            MojoSetup.loginfo("Obsoleting directory '" .. path .. "'")
+            -- It's ok if this fails. Most likely it just means the directory
+            --  is not empty.
+            MojoSetup.platform.unlink(MojoSetup.destination .. "/" .. path)
+        end
+    end
+
     -- Don't let future errors delete files from successful installs...
     MojoSetup.downloads = nil
     MojoSetup.rollbacks = nil
-- 
1.7.10


More information about the mojosetup mailing list