- initial import of revision 374 from cnc
[apt.git] / contrib / allow-duplicated / allow-duplicated.lua
1 -- This script will handle Allow-Duplicated packages when more
2 -- than one is available during an install operation, and will
3 -- also upgrade these packages in a dist-upgrade operation (if
4 -- they match a regex in RPM::Allow-Duplicated-Upgrade).
5 --
6 -- This script must be plugged in the following slots:
7 --
8 --   Scripts::AptGet::Install::SelectPackage
9 --   Scripts::AptGet::DistUpgrade
10 --   Scripts::Synaptic::DistUpgrade
11 --
12 -- Author: Gustavo Niemeyer <niemeyer@conectiva.com>
13
14 function realname(name)
15     local s, e, name = string.find(name, "(.+)#")
16     return name
17 end
18
19 if script_slot == "Scripts::AptGet::Install::SelectPackage" then
20     -- Automatically select the newest package if multiple
21     -- Allow-Duplicated packages are available.
22     local goodpkg = packages[1]
23     local goodpkgname = realname(pkgname(goodpkg))
24     if goodpkgname then
25         -- Check if every package has the same real name, and
26         -- leave only the one with the greatest version, if
27         -- that's the case.
28         for i = 2, table.getn(packages) do
29             local nextpkg = packages[i]
30             local nextpkgname = realname(pkgname(nextpkg))
31             if nextpkgname ~= goodpkgname then
32                 goodpkg = nil
33                 break
34             end
35             if not pkgvercand(goodpkg)
36                or pkgvercand(nextpkg) and
37                   verstrcmp(verstr(pkgvercand(goodpkg)),
38                     verstr(pkgvercand(nextpkg))) == -1 then
39                 goodpkg = nextpkg
40             end
41         end
42         if goodpkg and pkgvercand(goodpkg) then
43             selected = goodpkg
44         end
45     end
46     if not selected then
47         -- Strip #... from package names if we can't find a good solution.
48         for i, name in ipairs(packagenames) do
49             local name = realname(name)
50             if name and name ~= virtualname then
51                 packagenames[i] = name
52             end
53         end
54     end
55 end
56
57 if script_slot == "Scripts::AptGet::DistUpgrade" or
58    script_slot == "Scripts::Synaptic::DistUpgrade" then
59     -- Automatically install newer versions of all packages which
60     -- are registered in the Allow-Duplicated scheme and are matched
61     -- by the regular expressions in RPM::Allow-Duplicated-Upgrade.
62
63     -- Compile expressions with package names which should
64     -- be considered for upgrade.
65     local updatelist = confgetlist("RPM::Allow-Duplicated-Upgrade")
66     for i, expr in ipairs(updatelist) do
67         updatelist[i] = rex.new(expr)
68     end
69
70     if table.getn(updatelist) ~= 0 then
71
72         -- Gather information about Allow-Duplicated packges.
73         local canddups = {}
74         local curdups = {}
75         for i, pkg in pairs(pkglist()) do 
76             local name = realname(pkgname(pkg))
77             if name then
78                 if pkgvercur(pkg) then
79                     if not curdups[name] then
80                         curdups[name] = {}
81                     end
82                     table.insert(curdups[name],
83                              verstr(pkgvercur(pkg)))
84                 elseif pkgvercand(pkg) then
85                     if not canddups[name] then
86                         canddups[name] = {}
87                     end
88                     table.insert(canddups[name],
89                              verstr(pkgvercand(pkg)))
90                 end
91             end
92         end
93
94         -- Compile expressions with package names which should be hold.
95         local holdlist = confgetlist("RPM::Hold")
96         for i, expr in ipairs(holdlist) do
97             holdlist[i] = rex.new(expr)
98         end
99
100         -- Remove packages without any matches in updatelist, or with
101         -- any matches in holdlist.
102         for name, _ in pairs(curdups) do
103             local found = false
104             for i, expr in ipairs(updatelist) do
105                 if expr:match(name) then
106                     found = true
107                     break
108                 end
109             end
110             if found then
111                 for i, expr in ipairs(holdlist) do
112                     if expr:match(name) then
113                         found = false
114                         break
115                     end
116                 end
117             end
118             if not found then
119                 curdups[name] = nil
120             end
121         end
122
123         -- Mark the newest packages for installation.
124         for name, _ in pairs(curdups) do
125             if canddups[name] then
126                 -- Check the best candidate version.
127                 local bestver = nil
128                 for i, ver in ipairs(canddups[name]) do
129                     if not bestver or
130                        verstrcmp(ver, bestver) == -1 then
131                         bestver = ver
132                     end
133                 end
134
135                 -- Now check if it's newer than all installed
136                 -- versions.
137                 for i, ver in ipairs(curdups[name]) do
138                     if verstrcmp(ver, bestver) == 1 then
139                         bestver = nil
140                         break
141                     end
142                 end
143
144                 -- Finally, mark it for installation.
145                 if bestver then
146                     markinstall(name.."#"..bestver)
147                 end
148             end
149         end
150     end
151 end
152
153 -- vim:ts=4:sw=4:et