Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
freebsd
GitHub Repository: freebsd/portupgrade
Path: blob/master/lib/pkgtools/pkginfo.rb
102 views
1
# vim: set sts=2 sw=2 ts=8 et:
2
#
3
# Copyright (c) 2001-2004 Akinori MUSHA <[email protected]>
4
# Copyright (c) 2006-2008 Sergey Matveychuk <[email protected]>
5
# Copyright (c) 2009-2012 Stanislav Sedov <[email protected]>
6
# Copyright (c) 2012 Bryan Drewery <[email protected]>
7
#
8
# All rights reserved.
9
#
10
# Redistribution and use in source and binary forms, with or without
11
# modification, are permitted provided that the following conditions
12
# are met:
13
# 1. Redistributions of source code must retain the above copyright
14
# notice, this list of conditions and the following disclaimer.
15
# 2. Redistributions in binary form must reproduce the above copyright
16
# notice, this list of conditions and the following disclaimer in the
17
# documentation and/or other materials provided with the distribution.
18
#
19
# THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
20
# ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
21
# IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
22
# ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
23
# FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
24
# DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
25
# OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
26
# HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
27
# LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
28
# OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
29
# SUCH DAMAGE.
30
#
31
32
require 'pkgtools/pkgdb'
33
require 'pkgtools/pkgversion'
34
35
class PkgInfo
36
include Comparable
37
38
PKG_INFO_CMD = PkgDB::command(:pkg_info)
39
PKG_INFO_FLAGS = {
40
:prefix => 'p',
41
:comment => 'c',
42
:descr => 'd',
43
:message => 'D',
44
:plist => 'f',
45
:install => 'i',
46
:deinstall => 'k',
47
:req => 'r',
48
:required_by => 'R',
49
:mtree => 'm',
50
:files => 'L',
51
:totalsize => 's',
52
:origin => 'o',
53
}
54
55
PKG_QUERY_FLAGS = {
56
:prefix => '%p',
57
:comment => '%c',
58
:descr => nil,
59
:message => '%M',
60
:plist => nil,
61
:install => nil,
62
:deinstall => nil,
63
:req => '%dn-%dv',
64
:required_by => '%rn-%rv',
65
:mtree => nil,
66
:mtime => '%t',
67
:files => '%Fp',
68
:totalsize => '%sb',
69
:origin => '%o',
70
}
71
72
attr_accessor :name, :version
73
74
def initialize(pkgname)
75
if !pkgname.is_a?(String)
76
pkgname = pkgname.to_s
77
end
78
79
if /\s/ =~ pkgname
80
raise ArgumentError, "Must not contain whitespace."
81
end
82
83
if /^(.+)-([^-]+)$/ !~ pkgname
84
raise ArgumentError, "Not in due form: <name>-<version>"
85
end
86
87
@name = $1
88
@version = PkgVersion.new($2)
89
rescue => e
90
raise e, "#{pkgname}: #{e.message}"
91
end
92
93
def to_s
94
@name + '-' + @version.to_s
95
end
96
97
alias fullname to_s
98
99
def coerce(other)
100
case other
101
when PkgInfo
102
return other, self
103
when PkgVersion
104
return other, @version
105
when String
106
if /-/ =~ other
107
return PkgInfo.new(other), self
108
else
109
return PkgVersion.new(other), @version
110
end
111
else
112
raise TypeError, "Coercion between #{other.class} and #{self.class} is not supported."
113
end
114
end
115
116
def <=>(other)
117
other_name = nil
118
119
case other
120
when PkgInfo
121
other_name = other.name
122
other_version = other.version
123
when PkgVersion
124
other_version = other
125
when String
126
if /-/ =~ other
127
other = PkgInfo.new(other)
128
other_name = other.name
129
other_version = other.version
130
else
131
other_version = PkgVersion.new(other)
132
end
133
else
134
a, b = other.coerce(self)
135
136
return a <=> b
137
end
138
139
if other_name
140
cmp = @name <=> other_name
141
return cmp if cmp != 0
142
end
143
144
@version <=> other_version
145
end
146
147
def self.get_info(pkg, what)
148
opt = $pkgdb.with_pkgng? ? PKG_QUERY_FLAGS[what] : PKG_INFO_FLAGS[what]
149
150
if opt == nil
151
raise ArgumentError, "#{what.to_s}: Unsupported information."
152
end
153
154
chdir = ''
155
156
if pkg.include?('/')
157
chdir = "cd #{File.dirname(pkg)};"
158
end
159
160
if $pkgdb.with_pkgng?
161
info = `#{chdir}env PKG_PATH= #{PkgDB::command(:pkg)} query "#{opt}" #{pkg} 2>/dev/null`.chomp
162
else
163
info = `#{chdir}env PKG_PATH= #{PKG_INFO_CMD} -q#{opt} #{pkg} 2>/dev/null`.chomp
164
end
165
166
info.empty? ? nil : info
167
end
168
169
def get_info(what)
170
PkgInfo::get_info(fullname(), what)
171
end
172
173
PKG_INFO_FLAGS.each_key do |key|
174
case key
175
when :files, :required_by, :origin
176
next
177
end
178
179
module_eval %`
180
def #{key.to_s}
181
get_info(#{key.inspect})
182
end
183
`
184
end
185
186
def pkgdir()
187
PkgDB.instance.pkgdir fullname()
188
end
189
190
def pkgfile(filename)
191
PkgDB.instance.pkgfile fullname(), filename
192
end
193
194
def date_installed()
195
if $pkgdb.with_pkgng?
196
Time.at(get_info(:mtime).to_i)
197
else
198
File.mtime(pkg_comment) ||
199
File.mtime(pkg_descr) ||
200
File.mtime(pkg_contents) rescue Time.at(0)
201
end
202
end
203
204
def installed?()
205
PkgDB.instance.installed? fullname()
206
end
207
208
def required?()
209
PkgDB.instance.required? fullname()
210
end
211
212
def required_by()
213
PkgDB.instance.required_by fullname()
214
end
215
216
def pkgdep()
217
PkgDB.instance.pkgdep fullname()
218
end
219
220
def files()
221
str = get_info(:files) || ''
222
str.gsub!(%r"//+", '/') # tr is not multibyte-aware
223
str.split("\n")
224
end
225
226
def origin!()
227
get_info(:origin)
228
end
229
230
def origin()
231
PkgDB.instance.origin(fullname()) || origin!()
232
end
233
234
PkgDB::PKGDB_FILES.each_key do |key|
235
module_eval %{
236
def pkg_#{key.to_s}()
237
pkgfile #{key.inspect}
238
end
239
}
240
end
241
242
def date_cmp(str)
243
base = PkgDB.instance.date_installed(str) || PkgDB.parse_date(str)
244
245
date_installed <=> base
246
end
247
248
def match?(pattern)
249
case pattern
250
when true, '*'
251
true
252
when Regexp
253
pattern =~ fullname ? true : false
254
else
255
if /^([<>])(=?)(.*)/ =~ pattern
256
cmp = date_cmp($3)
257
258
($1 == '>' && cmp > 0) || ($1 == '<' && cmp < 0) || ($2 == '=' && cmp == 0)
259
else
260
File.fnmatch?(pattern, fullname) || @name == pattern
261
end
262
end
263
rescue => e
264
STDERR.puts e.message
265
return false
266
end
267
end
268
269
class PkgFileInfo < PkgInfo
270
def initialize(pkgfile)
271
@pkgfile = pkgfile
272
273
info = PkgInfo::get_info(pkgfile, :plist)
274
275
if info.nil?
276
raise ArgumentError, "#{pkgfilename}: Couldn't get package info."
277
end
278
279
info.each_line do |line|
280
if /^@name\s+(\S+)$/ =~ line
281
return super($1)
282
end
283
end
284
285
raise ArgumentError, "#{pkgfilename}: Couldn't get package name."
286
end
287
288
def get_info(what)
289
PkgInfo::get_info(@pkgfile, what)
290
end
291
end
292
293