1 --[[------------------------------------------------------------------
2 -- $Id: DongleStub.lua 466 2007-06-23 19:17:46Z jnwhiteh $
4 -- DongleStub is a simple versioning stub that allows different
5 -- major versions of a library to exist alongside each other, while
6 -- providing a mechanism for library upgrades through minor version
9 -- The implementation of DongleStub, including the source code,
10 -- documentation and related data, is placed into the public domain.
12 -- The original author is James N. Whitehead II
14 -- THIS SOFTWARE IS PROVIDED AS-IS WITHOUT WARRANTY OF ANY KIND, NOT
15 -- EVEN THE IMPLIED WARRANTY OF MERCHANTABILITY. THE AUTHOR OF THIS
16 -- SOFTWARE, ASSUMES _NO_ RESPONSIBILITY FOR ANY CONSEQUENCE RESULTING
17 -- FROM THE USE, MODIFICATION, OR REDISTRIBUTION OF THIS SOFTWARE.
18 ------------------------------------------------------------------]]--
20 local major
= "DongleStub"
21 local minor
= tonumber(string.match("$Revision: 466 $", "(%d+)") or 1)
25 if not g
.DongleStub
or g
.DongleStub
:IsNewerVersion(major
, minor
) then
26 local lib
= setmetatable({}, {
27 __call
= function(t
,k
)
28 if type(t
.versions
) == "table" and t
.versions
[k
] then
29 return t
.versions
[k
].instance
31 error("Cannot find a library with name '"..tostring(k
).."'", 2)
36 function lib
:HasVersion(major
)
37 if type(major
) ~= "string" then
38 error("bad argument #2 to 'HasVersion' (string expected, got " .. type(major
) .. ")", 2)
41 local instance
= self
.versions
and self
.versions
[major
]
42 return instance
~= nil
45 function lib
:IsNewerVersion(major
, minor
)
46 local versionData
= self
.versions
and self
.versions
[major
]
47 if not versionData
then return true end
48 local oldmajor
,oldminor
= versionData
.instance
:GetVersion()
49 return minor
> oldminor
52 local function NilCopyTable(src
, dest
)
53 for k
,v
in pairs(dest
) do dest
[k
] = nil end
54 for k
,v
in pairs(src
) do dest
[k
] = v
end
57 function lib
:Register(newInstance
, activate
, deactivate
)
58 if type(newInstance
) ~= "table" then
59 error("bad argument #2 to 'Register' (table expected, got " .. type(newInstance
) .. ")", 2)
62 if type(newInstance
.GetVersion
) ~= "function" then
63 error("Attempt to register a library with DongleStub that does not have a 'GetVersion' method.", 2)
66 local major
,minor
= newInstance
:GetVersion()
67 if type(major
) ~= "string" then
68 error("Attempt to register a library with DongleStub that does not have a proper major version.", 2)
71 if type(minor
) ~= "number" then
72 error("Attempt to register a library with DongleStub that does not have a proper minor version.", 2)
75 -- Generate a log of all library registrations
76 if not self
.log then self
.log = {} end
77 table.insert(self
.log, string.format("Register: %s, %s", major
, minor
))
79 if not self
:IsNewerVersion(major
, minor
) then return false end
80 if not self
.versions
then self
.versions
= {} end
82 local versionData
= self
.versions
[major
]
83 if not versionData
then
86 ["instance"] = newInstance
,
87 ["deactivate"] = deactivate
,
90 self
.versions
[major
] = versionData
91 if type(activate
) == "function" then
92 table.insert(self
.log, string.format("Activate: %s, %s", major
, minor
))
98 local oldDeactivate
= versionData
.deactivate
99 local oldInstance
= versionData
.instance
101 versionData
.deactivate
= deactivate
104 if type(activate
) == "function" then
105 table.insert(self
.log, string.format("Activate: %s, %s", major
, minor
))
106 skipCopy
= activate(newInstance
, oldInstance
)
109 -- Deactivate the old libary if necessary
110 if type(oldDeactivate
) == "function" then
111 local major
, minor
= oldInstance
:GetVersion()
112 table.insert(self
.log, string.format("Deactivate: %s, %s", major
, minor
))
113 oldDeactivate(oldInstance
, newInstance
)
116 -- Re-use the old table, and discard the new one
118 NilCopyTable(newInstance
, oldInstance
)
123 function lib
:GetVersion() return major
,minor
end
125 local function Activate(new
, old
)
126 -- This code ensures that we'll move the versions table even
127 -- if the major version names are different, in the case of
129 if not old
then old
= g
.DongleStub
end
132 new
.versions
= old
.versions
138 -- Actually trigger libary activation here
139 local stub
= g
.DongleStub
or lib
140 lib
= stub
:Register(lib
, Activate
)