]> git.e2factory.org Git - e2factory.git/commitdiff
rsync new-style args
authorTobias Ulmer <tu@emlix.com>
Mon, 18 Jul 2022 23:25:54 +0000 (01:25 +0200)
committerTobias Ulmer <tu@emlix.com>
Wed, 31 Aug 2022 22:22:17 +0000 (00:22 +0200)
Signed-off-by: Tobias Ulmer <tu@emlix.com>
generic/tools.lua
generic/transport.lua

index 494ad7062a8dfdfd7893cb326e4a461609e2acfa..dc2208eb4ef732ec8894957a3058f7ef3f21e506 100644 (file)
@@ -239,9 +239,10 @@ end
 -- @param optional Whether the tool is required (true) or optional (false).
 -- @param enable Whether the tool should be used or not.
 --               Only makes sense if optional. Defaults to true if not optional.
+-- @param detection Special function for feature/variant detection (optional).
 -- @return True on success, false on error.
 -- @return Error object on failure.
-function tools.add_tool(name, value, flags, optional, enable)
+function tools.add_tool(name, value, flags, optional, enable, detection)
     if type(name) ~= "string" or
         (value ~= nil and type(value) ~= "string") or
         (flags ~= nil and type(flags) ~= "string") or
@@ -283,6 +284,8 @@ function tools.add_tool(name, value, flags, optional, enable)
         -- flagstbl,
         optional = optional,
         enable = enable,
+        variant = nil,
+        detection = detection,
     }
 
     local t = toollist[name]
@@ -292,6 +295,81 @@ function tools.add_tool(name, value, flags, optional, enable)
     return true
 end
 
+local function rsync_version_detect(name)
+    local rc, re
+    local out, cmd, m
+    out = {}
+
+    local function capture(msg)
+        if #out < 1 then
+            -- we care only about the first line
+            table.insert(out, msg)
+        end
+    end
+
+    assert(type(toollist[name].path) == "string")
+    cmd = { toollist[name].path, "--version" }
+
+
+    rc, re = e2lib.callcmd_capture(cmd, capture)
+    if not rc then
+        return false, re
+    elseif rc ~= 0 then
+        return false, err.new("rsync --version returned error code")
+    end
+
+    out = table.concat(out)
+    e2lib.logf(4, "rsync --version returned: %q", out)
+
+    local major, minor, patch =
+        out:match("rsync%s+version%s+v?(%d+)%.(%d+)%.?(%d*)")
+    local proto = out:match("protocol%s+version%s+(%d+)")
+
+    if major == nil then
+        major = 3
+        minor = 2
+        patch = 4
+        e2lib.logf(3, "could not match rsync version, defaulting to 3.2.4")
+    else
+        major = tonumber(major)
+        minor = tonumber(minor)
+        -- not sure patch has ever been optional,
+        -- but fake something just in case.
+        if patch ~= "" then
+            patch = tonumber(patch)
+        else
+            patch = 0
+        end
+    end
+
+    if proto == nil then
+        e2lib.logf(3, "could not detect rsync protocol version, " ..
+            "defaulting to version 3.2.4")
+        proto = 31
+    else
+        proto = tonumber(proto)
+    end
+
+    -- argument parser change in 3.2.4
+    -- https://download.samba.org/pub/rsync/NEWS#3.2.4
+
+    local newargs = true
+    if (major < 3) or (major == 3 and minor < 2)
+        or (major == 3 and minor == 2 and patch < 4) then
+        newargs = false
+    end
+    e2lib.logf(4, "rsync: newstyle args detected: %s", tostring(newargs))
+
+    toollist[name].variant = {
+        newargs = newargs,
+        major = major,
+        minor = minor,
+        patch = patch,
+        proto = proto,
+    }
+    return true
+end
+
 --- Populate the tools module with the default tools.
 function tools.add_default_tools()
     local rc, re
@@ -299,7 +377,9 @@ function tools.add_default_tools()
         curl = { name = "curl", flags = "", optional = false },
         ssh = { name = "ssh", flags = "", optional = false },
         scp = { name = "scp", flags = "", optional = false },
-        rsync = { name = "rsync", flags = "", optional = false },
+        rsync = { name = "rsync", flags = "", optional = false,
+                  detection = rsync_version_detect,
+        },
         git = { name = "git", flags = "", optional = false },
         cvs = { name = "cvs", flags = "", optional = true },
         svn = { name = "svn", flags = "", optional = true },
@@ -316,7 +396,8 @@ function tools.add_default_tools()
     }
 
     for name, t in pairs(defaults) do
-        rc, re = tools.add_tool(name, t.name, t.flags, t.optional, t.enable)
+        rc, re = tools.add_tool(name, t.name, t.flags, t.optional, t.enable,
+            t.detection)
         if not rc then
             e2lib.abort(re)
         end
@@ -362,11 +443,33 @@ function tools.check_tool(name)
         end
 
         toollist[name].path = p
+
+        if toollist[name].detection then
+            rc, re = toollist[name].detection(name)
+            if not rc then
+                return false,
+                    err.new("tool '%s': special detection failed", name):cat(re)
+            end
+        end
     end
 
     return true
 end
 
+--- Special per tool information e.g. the installed version
+-- @param name Tool name
+-- @return False on error, defaults to empty table.
+-- @return Error object on failure.
+function tools.variant(name)
+    local rc, re
+
+    if not toollist[name] then
+        return false, err.new("tool '%s' is not registered in tool list", name)
+    end
+
+    return toollist[name].variant or {}
+end
+
 --- Query whether an optional tool is enabled or not.
 -- @param name Tool name.
 -- @return True if enabled, false on error or if not enabled.
index 4779820503cd911cf35187fa1600b55ef9fa8416..7f3c078d6722016bb20c418c4f9bd2a68b11a8d4 100644 (file)
@@ -83,6 +83,8 @@ local function rsync_quote_remote(user, server, dir)
     assert(user == nil or type(user) == "string")
     assert(type(server) == "string")
     assert(type(dir) == "string")
+    local v = tools.variant("rsync")
+    assert(v, "tools.variant(rsync) failed")
 
     if user then
         user = string.format("%s@", user)
@@ -90,7 +92,11 @@ local function rsync_quote_remote(user, server, dir)
         user = ""
     end
 
-    return string.format("%s%s:%s", user, server, e2lib.shquote(dir))
+    if v.newargs then
+        return string.format("%s%s:%s", user, server, dir)
+    else
+        return string.format("%s%s:%s", user, server, e2lib.shquote(dir))
+    end
 end
 
 --- create a remote directory by copying an empty directory using rsync