File usrmerge.lua of Package compat-usrmerge

usrmerge = { debug = nil } -- package

require("usrmerge_files")

-- for testing outside rpm
if posix == nil then
	posix = require("posix")
	function _symlink(old, new)
		os.execute("ln -vs " .. old .. " " .. new)
	end
	posix.symlink = _symlink
end

function _log(msg)
	if usrmerge.debug then
		print(usrmerge.debug .. ": " .. msg)
	end
end

function rootpath(path)
	_, _, p = string.find(path, "^/usr(/.*)")
	return p
end

function dirname(path)
	_, _, d, b = string.find(path, "^(.*)/([^/]*)")
	return d
end

function usrmerge._add(rp, relpath)
	if not usrmerge_files[rp] then return end
	if posix.stat(dirname(rp), "type") ~= "directory" then return end

	createit = false
	t = posix.stat(rp, "type")
	if t == nil then
		createit = true
	elseif t == "link" then
		dst = posix.readlink(rp)
		if dst ~= relpath then
			_log(rp .. ": fixing incorrect symlink (" .. dst .. " -> " .. relpath)
			os.remove(rp)
			createit = true
		end
	else
		_log(rp .. " exist but is no link, skipping")
	end
	if createit then
		_log("creating " .. rp .. " -> " .. relpath)
		posix.symlink(relpath, rp)
	end
end

function usrmerge.add(path)
	rp = rootpath(path)
	usrmerge._add(rp, ".." .. path)
end

-- if a legacy package with a file in /bin gets upgraded, it would
-- remove the link/file in /bin on uninstall. So we have to check
-- there and restore.
function usrmerge.add_postun(rp)
	if posix.stat("/usr" .. rp, "type") then
		usrmerge._add(rp, "../usr" .. rp)
	end
end

-- needed for the build system to install all links of packages that got
-- installed via rpm2cpio so didn't call triggers
function usrmerge.addexisting()
	for rp in pairs(usrmerge_files) do
		usrmerge.add_postun(rp)
	end
end

function usrmerge.remove(path)
	rp = rootpath(path)
	if not usrmerge_files[rp] then return end
	if posix.stat(dirname(rp), "type") ~= "directory" then return end

	t = posix.stat(path, "type")
	if t then
		_log(path .. " still exists, skipping")
		return
	end

	t = posix.stat(rp, "type")
	if t == "link" then
		relpath = ".." .. path
		dst = posix.readlink(rp)
		if dst == relpath then
			_log("remove " .. rp .. " -> " .. relpath)
			os.remove(rp)
		else
			_log(rp .. " incorrect link (".. dst .."), skipping")
		end
	elseif t then
		_log(rp .. " exist but is no link (".. t .."), skipping")
	end
end

function usrmerge.migrate(d)
	local errors = 0
	for i, name in ipairs(posix.dir(d)) do
		if name ~= '.' and name ~= '..' then
			local p = d .. "/" .. name
			local up = "/usr" .. p
			local t = posix.stat(p, "type")
			local ut = posix.stat(up, "type")
			if ut == nil or (ut == "link" and t ~= "link") then
				local f = posix.link
				if t == "directory" then
					-- can't hardlink dirs so move it
					f = posix.rename
				end
				if ut ~= nil then
					_log(" removing " .. up)
					posix.unlink(up)
				end
				local ok, err, e = f(p, up)
				if ok == nil then
					print("FAILED " .. p .. " -> " .. up .. ": " .. err)
					errors = errors + 1
				else
					_log(p .. " -> " .. up)
				end
			else
				if t == "directory" then
					print("BAD " .. p .. " is a directory but " .. up .. "exists")
					errors = errors + 1
				else
					_log("skipped " .. p)
				end
			end
		end
	end
	if errors > 0 then
		print("have to continue despire errors")
	end
	local ok, err, e = posix.rename(d, d .. ".merged")
	if ok == nil then
		print("FAILED to move " .. d .. " out of the way")
	else
		ok, err, e = posix.symlink("usr" ..d, d)
		if ok == nil then
			print("FAILED to recreate " .. d .. " as link. Now we're in deep shit, sorry :-/")
		end
	end
end
openSUSE Build Service is sponsored by