aur.rb 0.1.0 → 0.2.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- 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
|