aur.rb 0.1.0 → 0.2.0
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/ChangeLog.md +136 -2
- data/LICENSE.txt +1 -1
- data/README.md +21 -1
- data/Rakefile +7 -10
- data/TODO.md +69 -0
- data/aur.rb.gemspec +1 -0
- data/bin/aur.rb +6 -0
- data/lib/aur.rb +43 -1853
- data/lib/aur/aur_rpc.rb +178 -0
- data/lib/aur/cli.rb +334 -0
- data/lib/aur/config.rb +330 -0
- data/lib/aur/db.rb +328 -0
- data/lib/aur/devtools.rb +258 -0
- data/lib/aur/helpers.rb +56 -0
- data/lib/aur/install_packages.rb +158 -0
- data/lib/aur/load_config.rb +5 -0
- data/lib/aur/makepkg.rb +445 -0
- data/lib/aur/no_load_config.rb +5 -0
- data/lib/aur/packages.rb +599 -0
- data/lib/aur/repos.rb +343 -0
- data/lib/aur/version.rb +1 -1
- data/lib/aur/versions.rb +186 -0
- metadata +22 -5
data/lib/aur/config.rb
ADDED
@@ -0,0 +1,330 @@
|
|
1
|
+
require 'aur/helpers'
|
2
|
+
require 'aur/packages'
|
3
|
+
require 'aur/install_packages'
|
4
|
+
require 'aur/makepkg'
|
5
|
+
|
6
|
+
module Archlinux
|
7
|
+
|
8
|
+
class Config
|
9
|
+
def self.create(v)
|
10
|
+
v.is_a?(self) ? v : self.new(v)
|
11
|
+
end
|
12
|
+
|
13
|
+
attr_accessor :opts
|
14
|
+
Archlinux.delegate_h(self, :@opts)
|
15
|
+
include SH::ShConfig
|
16
|
+
include DR::PPHelper
|
17
|
+
|
18
|
+
# pass nil to prevent loading a config file
|
19
|
+
def initialize(file="aur.rb", **opts)
|
20
|
+
@file=file
|
21
|
+
if file
|
22
|
+
file=Pathname.new(file)
|
23
|
+
file=Pathname.new(ENV["XDG_CONFIG_HOME"] || "#{ENV['HOME']}/.config") + file if file.relative?
|
24
|
+
end
|
25
|
+
file_config= file&.readable? ? file.read : (SH.logger.error "Error: Config file '#{file}' unreadable" unless file.nil?; '{}')
|
26
|
+
wrap=eval("Proc.new { |config| #{file_config} }")
|
27
|
+
@opts=default_config.deep_merge(opts)
|
28
|
+
user_conf=wrap.call(self)
|
29
|
+
@opts.deep_merge!(user_conf) if user_conf.is_a?(Hash)
|
30
|
+
end
|
31
|
+
|
32
|
+
def to_pp
|
33
|
+
@file.to_s
|
34
|
+
end
|
35
|
+
|
36
|
+
def sh_config
|
37
|
+
@opts[:sh_config]
|
38
|
+
end
|
39
|
+
|
40
|
+
def default_config
|
41
|
+
{
|
42
|
+
cache: "arch_aur", #where we dl PKGBUILDs; if relative will be in XDG_CACHE_HOME
|
43
|
+
db: 'aur', #if relative the db will be in cache dir
|
44
|
+
aur_url: "https://aur.archlinux.org/", #base aur url
|
45
|
+
chroot: {
|
46
|
+
root: "/var/lib/aurbuild/x86_64", #chroot root
|
47
|
+
active: false, #do we use the chroot?
|
48
|
+
update: 'pacman -Syu --noconfirm', #how to update an existing chroot
|
49
|
+
packages: ['base-devel'], #the packages that are installed in the chroto
|
50
|
+
# It can make sense to add %w(python ruby nodejs go-pie rust git)...
|
51
|
+
},
|
52
|
+
default_packages_class: PackageList,
|
53
|
+
# default_install_list_class: AurMakepkgCache,
|
54
|
+
default_install_packages_class: AurPackageList,
|
55
|
+
default_install_list_class: AurCache,
|
56
|
+
default_get_class: Git, #we use git to fetch PKGBUILD from aur
|
57
|
+
sign: true, #can be made more atomic, cf the sign method
|
58
|
+
config_files: {
|
59
|
+
default: {
|
60
|
+
pacman: "/etc/pacman.conf", #default pacman-conf
|
61
|
+
makepkg: "/etc/makepkg.conf",
|
62
|
+
},
|
63
|
+
chroot: {
|
64
|
+
pacman: "/usr/share/devtools/pacman-extra.conf", #pacman.conf for chroot build
|
65
|
+
makepkg: "/usr/share/devtools/makepkg-x86_64.conf",
|
66
|
+
},
|
67
|
+
local: {
|
68
|
+
pacman: "/etc/pacman.conf", # pacman-conf for local makepkg build
|
69
|
+
},
|
70
|
+
},
|
71
|
+
sh_config: { #default programs options, called each time
|
72
|
+
makepkg: {default_opts: []},
|
73
|
+
makechrootpkg: {default_opts: ["-cu"]},
|
74
|
+
# So on fist thought, we do not need -u since we update 'root' before ourselves; but if we build several packages we may need the previous ones in the db, and since we only update 'root' once, they won't be available on 'copy'; so we still need '-u'
|
75
|
+
},
|
76
|
+
makepkg: {
|
77
|
+
build_args: ["-crs", "--needed"], #only used when building
|
78
|
+
},
|
79
|
+
view: "vifm -c view! -c tree -c 0", #can also be a Proc
|
80
|
+
sudo_loop: {
|
81
|
+
command: "sudo -v",
|
82
|
+
interval: 30,
|
83
|
+
active: true,
|
84
|
+
}
|
85
|
+
}
|
86
|
+
end
|
87
|
+
|
88
|
+
# packages to check
|
89
|
+
def default_packages(use_db: db != false, use_foreign: true)
|
90
|
+
if @default_packages.nil?
|
91
|
+
# by default this is the db packages + foreign packages
|
92
|
+
default=use_db ? db.packages : to_packages([])
|
93
|
+
default.merge(RepoPkgs.new(Repo.foreign_list, config: self).packages) if use_foreign
|
94
|
+
default=yield default if block_given?
|
95
|
+
@default_packages=to_packages(default.l, install: true)
|
96
|
+
else
|
97
|
+
@default_packages
|
98
|
+
end
|
99
|
+
end
|
100
|
+
|
101
|
+
def get_config_file(name, type: :default)
|
102
|
+
dig(:config_files, type, name) || dig(:config_files, :default, name)
|
103
|
+
end
|
104
|
+
|
105
|
+
def view(dir)
|
106
|
+
view=@opts[:view]
|
107
|
+
SH.sh_or_proc(view, dir)
|
108
|
+
end
|
109
|
+
|
110
|
+
def cachedir
|
111
|
+
global_cache=Pathname.new(ENV["XDG_CACHE_HOME"] || "#{ENV['HOME']}/.cache")
|
112
|
+
cache=global_cache+@opts[:cache]
|
113
|
+
cache.mkpath
|
114
|
+
cache
|
115
|
+
end
|
116
|
+
|
117
|
+
# add our default db to the list of repos
|
118
|
+
private def setup_pacman_conf(conf)
|
119
|
+
pacman=PacmanConf.create(conf, config: self)
|
120
|
+
aur=self.db(false)
|
121
|
+
if aur and !pacman[:repos].include?(aur.repo_name)
|
122
|
+
require 'uri'
|
123
|
+
pacman[:repos][aur.repo_name]={Server: ["file://#{DR::URIEscape.escape(aur.dir.to_s)}"]}
|
124
|
+
end
|
125
|
+
pacman
|
126
|
+
end
|
127
|
+
|
128
|
+
def default_pacman_conf
|
129
|
+
@default_pacman_conf ||= if (conf=get_config_file(:pacman))
|
130
|
+
PacmanConf.new(conf, config: self)
|
131
|
+
else
|
132
|
+
PacmanConf.new(config: self)
|
133
|
+
end
|
134
|
+
end
|
135
|
+
|
136
|
+
def chroot_devtools
|
137
|
+
unless @chroot_devtools
|
138
|
+
devtools_pacman=PacmanConf.new(get_config_file(:pacman, type: :chroot))
|
139
|
+
makepkg_conf=get_config_file(:makepkg, type: :chroot)
|
140
|
+
my_pacman=default_pacman_conf
|
141
|
+
devtools_pacman[:repos].merge!(my_pacman.non_official_repos)
|
142
|
+
devtools_pacman=setup_pacman_conf(devtools_pacman)
|
143
|
+
@chroot_devtools = Devtools.new(pacman_conf: devtools_pacman, makepkg_conf: makepkg_conf, config: self)
|
144
|
+
end
|
145
|
+
@chroot_devtools
|
146
|
+
end
|
147
|
+
|
148
|
+
def local_devtools
|
149
|
+
unless @local_devtools
|
150
|
+
makepkg_pacman=get_config_file(:pacman, type: :local)
|
151
|
+
makepkg_conf=get_config_file(:makepkg, type: :local)
|
152
|
+
makepkg_pacman=setup_pacman_conf(makepkg_pacman)
|
153
|
+
@local_devtools = Devtools.new(pacman_conf: makepkg_pacman, makepkg_conf: makepkg_conf, config: self)
|
154
|
+
end
|
155
|
+
@local_devtools
|
156
|
+
end
|
157
|
+
|
158
|
+
def db=(name)
|
159
|
+
case name
|
160
|
+
when DB
|
161
|
+
@db=name
|
162
|
+
when Pathname
|
163
|
+
@db=DB.new(name, config: self)
|
164
|
+
when String
|
165
|
+
if DB.db_file?(name)
|
166
|
+
@db=DB.new(name, config: self)
|
167
|
+
else
|
168
|
+
@db=DB.new(cachedir+".db"+"#{name}.db.tar.gz", config: self)
|
169
|
+
end
|
170
|
+
when true
|
171
|
+
@db=DB.new(cachedir+".db"+"aur.db.tar.gz", config: self)
|
172
|
+
when false, nil
|
173
|
+
@db=name #false for false, nil to reset
|
174
|
+
else
|
175
|
+
SH.logger.warn("Database name #{name} not suitable, fallback to default")
|
176
|
+
@db=nil
|
177
|
+
end
|
178
|
+
# reset these so the pacman_conf gets the correct db name
|
179
|
+
@makepkg_config=nil
|
180
|
+
@devtools_config=nil
|
181
|
+
end
|
182
|
+
|
183
|
+
def db(create=true)
|
184
|
+
@db.nil? and self.db=@opts[:db]
|
185
|
+
if create and @db
|
186
|
+
@db.create
|
187
|
+
end
|
188
|
+
@db
|
189
|
+
end
|
190
|
+
|
191
|
+
# if changing a setting, we may need to reset the rest
|
192
|
+
def reset
|
193
|
+
self.db=nil
|
194
|
+
end
|
195
|
+
|
196
|
+
# note: since 'true' is frozen, we cannot extend it and keep a
|
197
|
+
# @sudo_loop_thread. Moreover we only want one sudo loop active, so we
|
198
|
+
# will call it ourselves
|
199
|
+
def sudo(arg=true)
|
200
|
+
if dig(:sudo_loop, :active)
|
201
|
+
opts=dig(:sudo_loop).clone
|
202
|
+
opts.delete(:active)
|
203
|
+
self.extend(SH::SudoLoop.configure(**opts))
|
204
|
+
self.sudo_loop
|
205
|
+
end
|
206
|
+
arg
|
207
|
+
end
|
208
|
+
|
209
|
+
def stop_sudo_loop
|
210
|
+
stop_sudo_loop if respond_to?(:stop_sudo_loop)
|
211
|
+
end
|
212
|
+
|
213
|
+
def to_packages(l=[], install: false)
|
214
|
+
Archlinux.create_class(
|
215
|
+
install ? @opts[:default_install_packages_class] :
|
216
|
+
@opts[:default_packages_class],
|
217
|
+
l, config: self)
|
218
|
+
end
|
219
|
+
|
220
|
+
#:package, :db
|
221
|
+
def use_sign?(mode)
|
222
|
+
opt_sign=@opts[:sign]
|
223
|
+
if opt_sign.is_a?(Hash)
|
224
|
+
opt_sign[mode]
|
225
|
+
else
|
226
|
+
opt_sign
|
227
|
+
end
|
228
|
+
end
|
229
|
+
|
230
|
+
# output a list of sign names, or [] if we want to sign with the default sign name, false if we don't
|
231
|
+
def sign_names
|
232
|
+
opt_sign=@opts[:sign]
|
233
|
+
signs=if opt_sign.is_a?(Hash)
|
234
|
+
opt_sign.values
|
235
|
+
else
|
236
|
+
[*opt_sign]
|
237
|
+
end
|
238
|
+
names=signs.select {|s| s.is_a?(String)}
|
239
|
+
names = false if names.empty? and ! signs.any?
|
240
|
+
return names
|
241
|
+
end
|
242
|
+
|
243
|
+
# return the files that were signed
|
244
|
+
def sign(*files, sign_name: nil, force: false)
|
245
|
+
sign_name=use_sign?(sign_name) if sign_name.is_a?(Symbol)
|
246
|
+
files.map do |file|
|
247
|
+
sig="#{file}.sig"
|
248
|
+
if !Pathname.new(file).file?
|
249
|
+
SH.logger.error "Invalid file to sign #{file}"
|
250
|
+
next
|
251
|
+
end
|
252
|
+
if Pathname.new(sig).file?
|
253
|
+
if force
|
254
|
+
SH.logger.verbose2 "Signature #{sig} already exits, overwriting"
|
255
|
+
else
|
256
|
+
SH.logger.verbose2 "Signature #{sig} already exits, skipping"
|
257
|
+
next
|
258
|
+
end
|
259
|
+
end
|
260
|
+
args=['--detach-sign', '--no-armor']
|
261
|
+
args+=['-u', sign_name] if sign_name.is_a?(String)
|
262
|
+
launch(:gpg, *args, file) do |*args|
|
263
|
+
suc, _r=SH.sh(*args)
|
264
|
+
suc ? file : nil
|
265
|
+
end
|
266
|
+
end.compact
|
267
|
+
end
|
268
|
+
|
269
|
+
def verify_sign(*files)
|
270
|
+
args=['--verify']
|
271
|
+
files.map do |file|
|
272
|
+
file="#{file}.sig" unless file.to_s =~ /(.sig|.asc)/
|
273
|
+
launch(:gpg, *args, file) do |*args|
|
274
|
+
suc, _r=SH.sh(*args)
|
275
|
+
[file, suc]
|
276
|
+
end
|
277
|
+
end.to_h
|
278
|
+
end
|
279
|
+
|
280
|
+
def install_list
|
281
|
+
@install_list ||= Archlinux.create_class(@opts[:default_install_list_class], config: self)
|
282
|
+
end
|
283
|
+
|
284
|
+
def pre_install(*args, **opts)
|
285
|
+
names=sign_names
|
286
|
+
if names
|
287
|
+
cargs=["--detach-sign", "-o", "/dev/null", "/dev/null"]
|
288
|
+
if names.empty?
|
289
|
+
launch(:gpg, *cargs)
|
290
|
+
else
|
291
|
+
args=names.map { |name| ['-u', name] }.flatten+cargs
|
292
|
+
launch(:gpg, *args)
|
293
|
+
end
|
294
|
+
end
|
295
|
+
end
|
296
|
+
|
297
|
+
def post_install(pkgs, install: false, **opts)
|
298
|
+
if (db=self.db)
|
299
|
+
if install
|
300
|
+
tools=local_devtools
|
301
|
+
# info=opts[:pkgs_info]
|
302
|
+
# to_install=info[:all_pkgs].select {|_k,v| v[:op]==:install}.
|
303
|
+
# map {|_k,v| v[:out_pkg]}
|
304
|
+
# tools.sync_db(db.repo_name, install: to_install)
|
305
|
+
|
306
|
+
# Let's just install anything and let pacman handle it
|
307
|
+
m=opts[:makepkg_list]
|
308
|
+
if m
|
309
|
+
# we need to update the package versions with the ones
|
310
|
+
# provided by the current makepkg (which may be more recent than
|
311
|
+
# the one from aur's rpc in case of devel packages)
|
312
|
+
ipkgs=pkgs.map do |pkg|
|
313
|
+
found=m.packages.find(Query.strip(pkg))
|
314
|
+
found || pkg
|
315
|
+
end
|
316
|
+
else
|
317
|
+
ipkgs=pkgs
|
318
|
+
end
|
319
|
+
tools.sync_db(db.repo_name, install: %w(--needed) + ipkgs)
|
320
|
+
end
|
321
|
+
end
|
322
|
+
end
|
323
|
+
|
324
|
+
def parser(parser) #to add cli options in the config file
|
325
|
+
end
|
326
|
+
end
|
327
|
+
|
328
|
+
self.singleton_class.attr_accessor :config
|
329
|
+
@config ||= Config.new("aur.rb")
|
330
|
+
end
|
data/lib/aur/db.rb
ADDED
@@ -0,0 +1,328 @@
|
|
1
|
+
require 'aur/config'
|
2
|
+
require 'aur/packages'
|
3
|
+
require 'aur/repos'
|
4
|
+
require 'time'
|
5
|
+
|
6
|
+
module Archlinux
|
7
|
+
class DB
|
8
|
+
extend CreateHelper
|
9
|
+
|
10
|
+
def self.db_file?(name)
|
11
|
+
case name
|
12
|
+
when Pathname
|
13
|
+
true
|
14
|
+
when String
|
15
|
+
if name.include?('/') or name.match(/\.db(\..*)?$/)
|
16
|
+
true
|
17
|
+
else
|
18
|
+
false #Usually we assume this is a repo name
|
19
|
+
end
|
20
|
+
end
|
21
|
+
end
|
22
|
+
|
23
|
+
attr_accessor :file, :config
|
24
|
+
def initialize(file, config: Archlinux.config)
|
25
|
+
@orig_file=Pathname.new(file)
|
26
|
+
@file=@orig_file.realdirpath rescue @orig_file.abs_path
|
27
|
+
@config=config
|
28
|
+
end
|
29
|
+
|
30
|
+
def mkpath
|
31
|
+
@file.dirname.mkpath
|
32
|
+
end
|
33
|
+
|
34
|
+
def path
|
35
|
+
if file.exist?
|
36
|
+
file.realpath
|
37
|
+
else
|
38
|
+
file
|
39
|
+
end
|
40
|
+
end
|
41
|
+
|
42
|
+
def repo_name
|
43
|
+
@file.basename.to_s.sub(/\.db(\..*)?$/,'')
|
44
|
+
end
|
45
|
+
|
46
|
+
def create
|
47
|
+
mkpath
|
48
|
+
unless @file.exist?
|
49
|
+
call(:'repo-add', path)
|
50
|
+
end
|
51
|
+
self
|
52
|
+
end
|
53
|
+
|
54
|
+
def to_s
|
55
|
+
@file.to_s
|
56
|
+
end
|
57
|
+
|
58
|
+
# a db is a tar.gz archive of packages/desc, like yay-8.998-1/descr
|
59
|
+
def bsdcat_list
|
60
|
+
res= SH.run_simple("bsdcat #{@file.shellescape}", chomp: :lines) {return nil}
|
61
|
+
list=[]; pkg={}; mode=nil
|
62
|
+
flush = lambda do
|
63
|
+
# catch old deps files which don't specify the full infos
|
64
|
+
unless pkg[:name].nil? and pkg[:base].nil?
|
65
|
+
pkg[:repo]||=path
|
66
|
+
list << pkg
|
67
|
+
end
|
68
|
+
end
|
69
|
+
res.each do |l|
|
70
|
+
next if l.empty? or l.match(/^\u0000*$/)
|
71
|
+
if (m=l.match(/(\u0000+.*\u0000+)?%([A-Z0-9]*)%$/))
|
72
|
+
mode=m[2].downcase.to_sym
|
73
|
+
if m[1] #new db entry
|
74
|
+
flush.call #store old db entry
|
75
|
+
pkg={}
|
76
|
+
end
|
77
|
+
else
|
78
|
+
l=l.to_i if mode==:csize or mode==:isize
|
79
|
+
l=Time.at(l.to_i) if mode==:builddate
|
80
|
+
Archlinux.add_to_hash(pkg, mode, l)
|
81
|
+
end
|
82
|
+
end
|
83
|
+
flush.call #don't forget the last one
|
84
|
+
list
|
85
|
+
end
|
86
|
+
|
87
|
+
def list
|
88
|
+
res= SH.run_simple("bsdtar -xOf #{@file.shellescape} '*/desc'", chomp: :lines) {return nil}
|
89
|
+
list=[]; pkg={}; mode=nil
|
90
|
+
flush = lambda do
|
91
|
+
unless pkg.empty?
|
92
|
+
pkg[:repo]||=path
|
93
|
+
list << pkg
|
94
|
+
end
|
95
|
+
end
|
96
|
+
res.each do |l|
|
97
|
+
next if l.empty?
|
98
|
+
if (m=l.match(/^%([A-Z0-9]*)%$/))
|
99
|
+
mode=m[1].downcase.to_sym
|
100
|
+
if mode==:filename #new db entry
|
101
|
+
flush.call #store old db entry
|
102
|
+
pkg={}
|
103
|
+
end
|
104
|
+
else
|
105
|
+
l=l.to_i if mode==:csize or mode==:isize
|
106
|
+
l=Time.at(l.to_i) if mode==:builddate
|
107
|
+
Archlinux.add_to_hash(pkg, mode, l)
|
108
|
+
end
|
109
|
+
end
|
110
|
+
flush.call #don't forget the last one
|
111
|
+
list
|
112
|
+
end
|
113
|
+
|
114
|
+
def files(absolute=true)
|
115
|
+
list.map do |pkg|
|
116
|
+
file=Pathname.new(pkg[:filename])
|
117
|
+
absolute ? dir + file : file
|
118
|
+
end
|
119
|
+
end
|
120
|
+
# def files
|
121
|
+
# packages.l.map {|pkg| dir+Pathname.new(pkg[:filename])}
|
122
|
+
# end
|
123
|
+
|
124
|
+
def dir
|
125
|
+
# # we memoize this because if we get called again in a dir.chdir
|
126
|
+
# # call, then the realpath will fail
|
127
|
+
# @dir ||= @file.dirname.realpath
|
128
|
+
@file.dirname
|
129
|
+
end
|
130
|
+
|
131
|
+
def call(*args, **opts)
|
132
|
+
@config.launch(*args, **opts) do |*a, **o|
|
133
|
+
dir.chdir do
|
134
|
+
SH.sh(*a, **o)
|
135
|
+
end
|
136
|
+
end
|
137
|
+
end
|
138
|
+
|
139
|
+
def move_to_db(*files, op: :mv)
|
140
|
+
files=files.map {|f| Pathname.new(f).realpath}
|
141
|
+
dir=self.dir
|
142
|
+
SH.logger.verbose "#{op}: #{files.join(', ')} to #{dir}"
|
143
|
+
files.map do |f|
|
144
|
+
if f.dirname == dir
|
145
|
+
SH.logger.verbose2 "! #{f} already exists in #{dir}"
|
146
|
+
f
|
147
|
+
else
|
148
|
+
new=dir+f.basename
|
149
|
+
SH.logger.verbose2 "-> #{op} #{f} to #{new}"
|
150
|
+
f.send(op, new)
|
151
|
+
sig=Pathname.new(f.to_s+".sig") #mv .sig too
|
152
|
+
if sig.exist?
|
153
|
+
newsig=dir+sig.basename
|
154
|
+
SH.logger.verbose2 "-> #{op} #{sig} to #{newsig}"
|
155
|
+
sig.send(op, newsig)
|
156
|
+
end
|
157
|
+
new
|
158
|
+
end
|
159
|
+
end
|
160
|
+
end
|
161
|
+
|
162
|
+
def add(*files, cmd: :'repo-add', default_opts:[], sign: @config&.use_sign?(:db), force_sign: false, **opts)
|
163
|
+
default_opts+=['-s', '-v'] if sign
|
164
|
+
default_opts+=['--key', sign] if sign.is_a?(String)
|
165
|
+
dir.chdir do
|
166
|
+
files.map! {|f| Pathname.new(f)}
|
167
|
+
existing_files=files.select {|f| f.file?}
|
168
|
+
missing_files = files-existing_files
|
169
|
+
SH.logger.warn "In #{cmd}, missing files: #{missing_files.join(', ')}" unless missing_files.empty?
|
170
|
+
unless existing_files.empty?
|
171
|
+
sign_files = @config&.use_sign?(:package)
|
172
|
+
PackageFiles.new(*existing_files, config: @config).sign(sign_name: sign_files, force: force_sign) if sign_files
|
173
|
+
call(cmd, path, *existing_files, default_opts: default_opts, **opts)
|
174
|
+
@packages=nil #we need to refresh the list
|
175
|
+
end
|
176
|
+
end
|
177
|
+
files
|
178
|
+
end
|
179
|
+
|
180
|
+
def remove(*pkgnames, cmd: :'repo-remove', default_opts:[], sign: @config&.use_sign?(:db), **opts)
|
181
|
+
default_opts+=['-s', '-v'] if sign
|
182
|
+
default_opts+=['--key', sign] if sign.is_a?(String)
|
183
|
+
dir.chdir do
|
184
|
+
call(cmd, path, *pkgnames, default_opts: default_opts, **opts)
|
185
|
+
@packages=nil #we need to refresh the list
|
186
|
+
end
|
187
|
+
pkgnames
|
188
|
+
end
|
189
|
+
|
190
|
+
def packages(refresh=false)
|
191
|
+
@packages=nil if refresh
|
192
|
+
# @packages||=PackageList.new(list, config: @config)
|
193
|
+
@packages||=@config.to_packages(list)
|
194
|
+
end
|
195
|
+
|
196
|
+
def dir_packages_cls
|
197
|
+
PackageFiles.from_dir(dir, config: @config)
|
198
|
+
end
|
199
|
+
def dir_packages
|
200
|
+
dir_packages_cls.packages
|
201
|
+
end
|
202
|
+
|
203
|
+
def package_files_cls
|
204
|
+
PackageFiles.new(*files, config: @config)
|
205
|
+
end
|
206
|
+
def package_files
|
207
|
+
package_files_cls.packages
|
208
|
+
end
|
209
|
+
|
210
|
+
# sign the files in the db (return the list of signed file, by default
|
211
|
+
# unless force: true is passed this won't resign already signed files)
|
212
|
+
def sign_files(sign_name: :package, **opts)
|
213
|
+
@config&.sign(*files, sign_name: sign_name, **opts)
|
214
|
+
end
|
215
|
+
def sign_db(sign_name: :db, **opts)
|
216
|
+
@config&.sign(@file, sign_name: sign_name, **opts) if @file.file?
|
217
|
+
end
|
218
|
+
|
219
|
+
def verify_sign_db
|
220
|
+
@config&.verify_sign(@file)
|
221
|
+
end
|
222
|
+
def verify_sign_files
|
223
|
+
@config&.verify_sign(*files)
|
224
|
+
end
|
225
|
+
# check the inline signatures
|
226
|
+
def verify_sign_pkgs(*pkgs)
|
227
|
+
packages.get_packages(*pkgs).map do |pkg|
|
228
|
+
pgpsign=pkg[:pgpsig]
|
229
|
+
if pgpsign
|
230
|
+
require 'base64'
|
231
|
+
sig=Base64.decode64(pgpsign)
|
232
|
+
filename=dir+pkg[:filename]
|
233
|
+
@config.launch(:gpg, "--enable-special-filenames", "--verify", "-", filename, mode: :capture, stdin_data: sig) do |*args|
|
234
|
+
suc, _r=SH.sh(*args)
|
235
|
+
[pkg.name, suc]
|
236
|
+
end
|
237
|
+
else
|
238
|
+
[pkg.name, false]
|
239
|
+
end
|
240
|
+
end.to_h
|
241
|
+
end
|
242
|
+
|
243
|
+
# if we missed some signatures, resign them (and add them back to the
|
244
|
+
# db to get the signatures in the db). This override the sign:false
|
245
|
+
# config options.
|
246
|
+
def resign(**opts)
|
247
|
+
signed_files=sign_files(**opts)
|
248
|
+
add(*signed_files) #note that this may try to sign again, but since the signature exists it won't launch gpg
|
249
|
+
sign_db(**opts) #idem, normally the db will be signed by repo-add -v, but in case the signature was turned off in the config, this forces the signature
|
250
|
+
end
|
251
|
+
|
252
|
+
def check
|
253
|
+
packages.same?(package_files)
|
254
|
+
end
|
255
|
+
|
256
|
+
def check_update(other=dir_packages)
|
257
|
+
self.packages.check_updates(other)
|
258
|
+
# yield up if block_given?
|
259
|
+
# refresh=up.select {|_k, u| u[:op]==:upgrade or u[:op]==:downgrade}
|
260
|
+
# add=up.select {|_k, u| u[:op]==:install}
|
261
|
+
# remove=up.select {|_k, u| u[:op]==:obsolete}
|
262
|
+
# return {refresh: refresh, add: add, remove: remove}
|
263
|
+
end
|
264
|
+
|
265
|
+
def show_updates(other=dir_packages, **showopts)
|
266
|
+
c=check_update(other)
|
267
|
+
packages.show_updates(c, **showopts)
|
268
|
+
c
|
269
|
+
end
|
270
|
+
|
271
|
+
def update(other=dir_packages, add_for: %i(upgrade downgrade install), rm_for: %i(obsolete), **showopts)
|
272
|
+
c=show_updates(other, **showopts)
|
273
|
+
to_add=c.select {|_k, u| add_for.include?(u[:op])}
|
274
|
+
to_rm=c.select {|_k, u| rm_for.include?(u[:op])}
|
275
|
+
add(*to_add.map { |_k,v| other[v[:out_pkg]].path })
|
276
|
+
# remove(*(r[:remove].map {|_k,v| packages[v[:in_pkg]].file.shellescape}))
|
277
|
+
remove(* to_rm.map {|_k,v| Query.strip(v[:in_pkg])})
|
278
|
+
c
|
279
|
+
end
|
280
|
+
|
281
|
+
# move/copy files to db and add them
|
282
|
+
# if update==true, only add more recent packages
|
283
|
+
# pkgs should be a PackageFiles or a PackageList or a list of files
|
284
|
+
def add_to_db(pkgs, update: true, op: :cp)
|
285
|
+
if update
|
286
|
+
pkgs=PackageFiles.create(pkgs).packages unless pkgs.is_a? PackageList
|
287
|
+
up=self.packages.check_updates(pkgs)
|
288
|
+
pkgs=up.select {|_k, u| u[:op]==:upgrade or u[:op]==:install}.map do |_k,v|
|
289
|
+
pkgs[v[:out_pkg]].path
|
290
|
+
end
|
291
|
+
else
|
292
|
+
pkgs=pkgs.map {|_k,v| v.path } if pkgs.is_a?(PackageList)
|
293
|
+
end
|
294
|
+
SH.logger.mark "Updating #{pkgs} in #{self}"
|
295
|
+
cp_pkgs=move_to_db(*pkgs, op: op)
|
296
|
+
add(*cp_pkgs)
|
297
|
+
end
|
298
|
+
|
299
|
+
#remove from db and also remove the package files
|
300
|
+
def rm_from_db(*pkgs)
|
301
|
+
to_rm=packages.get_packages(*pkgs)
|
302
|
+
PackageFiles.rm_files(*to_rm.map {|pkg| pkg.path}, dir: self.dir)
|
303
|
+
remove(*pkgs)
|
304
|
+
end
|
305
|
+
|
306
|
+
# in clean_dir, we clean the dir packages which have a newer
|
307
|
+
# version (in the dir).
|
308
|
+
def clean_dir(dry_run: true)
|
309
|
+
files=dir_packages_cls
|
310
|
+
files.clean(dry_run: dry_run)
|
311
|
+
end
|
312
|
+
|
313
|
+
# In clean, we clean the dir packages which are newer or not present in
|
314
|
+
# the db. This is like the reverse of `update`. In particular be
|
315
|
+
# careful that this will delete newer versions or added versions
|
316
|
+
def clean(dry_run: true)
|
317
|
+
dir_pkgs=dir_packages_cls
|
318
|
+
dir_files=dir_pkgs.files
|
319
|
+
db_files=files
|
320
|
+
to_remove=dir_files - db_files
|
321
|
+
if dry_run
|
322
|
+
to_remove
|
323
|
+
else
|
324
|
+
PackageFiles.rm_files(*to_remove, dir: self.dir)
|
325
|
+
end
|
326
|
+
end
|
327
|
+
end
|
328
|
+
end
|