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.
@@ -0,0 +1,178 @@
1
+ require 'json'
2
+ require 'time'
3
+ require 'net/http'
4
+ require 'aur/config'
5
+ require 'aur/packages'
6
+
7
+ module Archlinux
8
+
9
+ AurQueryError=Class.new(ArchlinuxError)
10
+
11
+ # aur query but with a local config parameter
12
+ class AurQueryCustom
13
+ extend CreateHelper
14
+ attr_accessor :config
15
+
16
+ def initialize(config: AurQuery.config)
17
+ @config=config
18
+ end
19
+
20
+ def packages(*pkgs)
21
+ @config.to_packages(infos(*pkgs))
22
+ end
23
+
24
+ # AurQuery.query(type: "info", arg: pacaur)
25
+ # AurQuery.query(type: "info", :"arg[]" => %w(cower pacaur))
26
+ # AurQuery.query(type: "search", by: "name", arg: "aur")
27
+ # by name (search by package name only)
28
+ # *name-desc* (search by package name and description)
29
+ # maintainer (search by package maintainer)
30
+ # depends (search for packages that depend on keywords)
31
+ # makedepends (search for packages that makedepend on keywords)
32
+ # optdepends (search for packages that optdepend on keywords)
33
+ # checkdepends (search for packages that checkdepend on keywords)
34
+ # => search result:
35
+ # {"ID"=>514909,
36
+ # "Name"=>"pacaur",
37
+ # "PackageBaseID"=>49145,
38
+ # "PackageBase"=>"pacaur",
39
+ # "Version"=>"4.7.90-1",
40
+ # "Description"=>"An AUR helper that minimizes user interaction",
41
+ # "URL"=>"https://github.com/rmarquis/pacaur",
42
+ # "NumVotes"=>1107,
43
+ # "Popularity"=>7.382043,
44
+ # "OutOfDate"=>nil,
45
+ # "Maintainer"=>"Spyhawk",
46
+ # "FirstSubmitted"=>1305666963,
47
+ # "LastModified"=>1527690065,
48
+ # "URLPath"=>"/cgit/aur.git/snapshot/pacaur.tar.gz"},
49
+ # => info result adds:
50
+ # "Depends"=>["cower", "expac", "sudo", "git"],
51
+ # "MakeDepends"=>["perl"],
52
+ # "License"=>["ISC"],
53
+ # "Keywords"=>["AUR", "helper", "wrapper"]}]
54
+
55
+ def query(h, url: @config[:aur_url])
56
+ uri=URI("#{url}/rpc/")
57
+ params = {v:5}.merge(h)
58
+ uri.query = URI.encode_www_form(params)
59
+ SH.logger.debug "! AurQuery: new query '#{uri}'"
60
+ res = Net::HTTP.get_response(uri)
61
+ if res.is_a?(Net::HTTPSuccess)
62
+ r= res.body
63
+ else
64
+ raise AurQueryError.new("AUR: Got error response for query #{h}")
65
+ end
66
+ data = JSON.parse(r)
67
+ case data['type']
68
+ when 'error'
69
+ raise AurQueryError.new("Error: #{data['results']}")
70
+ when 'search','info','multiinfo'
71
+ return data['results']
72
+ else
73
+ raise AurQueryError.new("Error in response data #{data}")
74
+ end
75
+ end
76
+
77
+ # Outdated packages: Aur.search(nil, by: "maintainer")
78
+ def search(arg, by: nil)
79
+ r={type: "search", arg: arg}
80
+ r[:by]=by if by
81
+ # if :by is not specified, aur defaults to name-desc
82
+ self.query(r)
83
+ end
84
+
85
+ def infos(*pkgs, slice: 150)
86
+ search=[]
87
+ pkgs.each_slice(slice) do |pkgs_slice|
88
+ r={type: "info", :"arg[]" => pkgs_slice}
89
+ search+=self.query(r)
90
+ end
91
+ search.each { |pkg| pkg[:repo]=:aur }
92
+ search
93
+ end
94
+
95
+ # try to use infos if possible
96
+ def info(pkg)
97
+ r={type: "info", arg: pkg}
98
+ self.query(r).first
99
+ end
100
+
101
+ def pkglist(type="packages", delay: 3600, query: :auto, cache: @config.cachedir) #type=pkgbase
102
+ require 'zlib'
103
+ file=cache+"#{type}.gz"
104
+ in_epoch=nil
105
+ if file.exist?
106
+ # intime=file.read.each_line.first
107
+ file.open do |io|
108
+ Zlib::GzipReader.wrap(io) do |gz|
109
+ intime=gz.each_line.first
110
+ intime.match(/^# AUR package list, generated on (.*)/) do |m|
111
+ in_epoch=Time.parse(m[1]).to_i
112
+ end
113
+ end
114
+ end
115
+ end
116
+ if query
117
+ Net::HTTP.get_response(URI("#{@config[:aur_url]}/#{type}.gz")) do |res|
118
+ date=res["date"] #There are no 'Last-Modified' field, cf https://bugs.archlinux.org/task/49092
119
+ update=true
120
+ if date
121
+ epoch=Time.parse(date).to_i
122
+ update=false if epoch and in_epoch and (epoch-in_epoch < delay) and !query==true
123
+ end
124
+ if update
125
+ file.open('w') do |io|
126
+ Zlib::GzipWriter.wrap(io) do |gz|
127
+ res.read_body(gz)
128
+ end
129
+ end
130
+ end
131
+ end
132
+ end
133
+ file.open do |io|
134
+ Zlib::GzipReader.wrap(io) do |gz|
135
+ return gz.each_line.map(&:chomp).drop(1)
136
+ end
137
+ end
138
+ end
139
+ end
140
+
141
+ AurQuery=AurQueryCustom.new(config: Archlinux.config)
142
+
143
+ class AurQueryCache < AurQueryCustom
144
+
145
+ attr_accessor :search_cache, :info_cache
146
+ def initialize(*args,**kwds)
147
+ super
148
+ @search_cache={}
149
+ @info_cache={}
150
+ end
151
+
152
+ def search(arg, by: nil)
153
+ r={type: "search", arg: arg}
154
+ r[:by]=by if by
155
+ if @search_cache.key?(r)
156
+ @search_cache[r]
157
+ else
158
+ res=super
159
+ res
160
+ end
161
+ end
162
+
163
+ def infos(*pkgs, slice: 150)
164
+ got = pkgs & @info_cache.keys
165
+ pkgs = pkgs - got
166
+ res=super(*pkgs, slice: slice)
167
+ res.each do |pkg|
168
+ @info_cache[pkg["Name"]]=pkg
169
+ end
170
+ pkgs.each do |name|
171
+ @info_cache[name]||=nil #missing packages
172
+ end
173
+ @info_cache.values_at(*got, *pkgs).compact
174
+ end
175
+ end
176
+
177
+ GlobalAurCache = AurQueryCache.new(config: AurQuery.config)
178
+ end
@@ -0,0 +1,334 @@
1
+ require 'cmdparse'
2
+ require 'aur/version'
3
+ require 'simplecolor'
4
+ SimpleColor.mix_in_string
5
+ #SH::Sh.default_sh_options[:log_level_exectue]="debug3" #was debug
6
+
7
+ module Archlinux
8
+ def self.cli
9
+ parser = CmdParse::CommandParser.new(handle_exceptions: :no_help)
10
+ parser.main_options.program_name = "aur.rb"
11
+ parser.main_options.banner = "Helper to manage aur (Version #{VERSION})"
12
+ parser.main_options.version = VERSION
13
+
14
+ parser.global_options do |opt|
15
+ parser.data[:color]=@config.fetch(:color, true)
16
+ parser.data[:debug]=@config.fetch(:debug, false)
17
+ parser.data[:loglevel]=@config.fetch(:loglevel, "info")
18
+ SH.log_options(opt, parser.data)
19
+
20
+ #opt.on("--[no-]db=[dbname]", "Specify database", "Default to #{@config.db}") do |v|
21
+ opt.on("--[no-]db=[dbname]", "Specify database", "Default to #{@config.db}") do |v|
22
+ @config.db=v
23
+ end
24
+ end
25
+
26
+ add_install_option = ->(cmd) do
27
+ cmd.options do |opt|
28
+ opt.on("-i", "--[no-]install", "Install the package afterwards", "Defaults to #{!! cmd.data[:install]}") do |v|
29
+ cmd.data[:install]=v
30
+ end
31
+
32
+ opt.on("--[no-]chroot[=path]", "Use a chroot", "Defaults to #{@config.opts[:chroot][:active] && @config.opts[:chroot][:root]}") do |v|
33
+ if v
34
+ @config.opts[:chroot][:active]=true
35
+ @config.opts[:chroot][:root]=v if v.is_a?(String)
36
+ else
37
+ @config.opts[:chroot][:active]=v
38
+ end
39
+ end
40
+
41
+ opt.on("--local", "Local mode", "Shortcut for --no-db --no-chroot") do |v|
42
+ @config.opts[:chroot][:active]=false
43
+ @config.db=false
44
+ end
45
+ end
46
+ end
47
+
48
+ parser.main_options do |opt|
49
+ opt.on("--config=config_file", "Set config file") do |v|
50
+ @config=Config.new(v)
51
+ end
52
+ end
53
+
54
+ parser.add_command(CmdParse::HelpCommand.new, default: true)
55
+ parser.add_command(CmdParse::VersionCommand.new)
56
+
57
+ parser.add_command('aur') do |aur_cmd|
58
+ aur_cmd.add_command('search') do |cmd|
59
+ cmd.takes_commands(false)
60
+ cmd.short_desc("Search aur")
61
+ cmd.long_desc(<<-EOS)
62
+ Search aur
63
+ EOS
64
+ cmd.argument_desc(search: "search terms")
65
+ cmd.action do |*search|
66
+ search.each do |s|
67
+ SH.logger.mark(s+":")
68
+ r=GlobalAurCache.search(s)
69
+ r.each do |pkg|
70
+ name_version="#{pkg["Name"]} (#{pkg["Version"]})"
71
+ SH.logger.info("#{name_version.color(:yellow)}: #{pkg["Description"]}")
72
+ end
73
+ end
74
+ end
75
+ end
76
+
77
+ aur_cmd.add_command('info') do |cmd|
78
+ cmd.takes_commands(false)
79
+ cmd.short_desc("Info on packages")
80
+ cmd.long_desc(<<-EOS)
81
+ Get infos on packages
82
+ EOS
83
+ cmd.argument_desc(packages: "packages names")
84
+ cmd.action do |*packages|
85
+ r=GlobalAurCache.infos(*packages)
86
+ r.each do |pkg|
87
+ name_version="#{pkg["Name"]} (#{pkg["Version"]})"
88
+ SH.logger.info("#{name_version.color(:yellow)}: #{pkg["Description"]}")
89
+ end
90
+ end
91
+ end
92
+ end
93
+
94
+ parser.add_command('build') do |build_cmd|
95
+ build_cmd.takes_commands(false)
96
+ build_cmd.short_desc("Build packages")
97
+ build_cmd.long_desc("Build existing PKGBUILD. To download pkgbuild use 'install' instead")
98
+ add_install_option.call(build_cmd)
99
+ build_cmd.action do |*pkgbuild_dirs|
100
+ mkpkg=Archlinux::MakepkgList.new(pkgbuild_dirs, cache: nil)
101
+ mkpkg.build(install: build_cmd.data[:install])
102
+ end
103
+ end
104
+
105
+ parser.add_command('install') do |install_cmd|
106
+ install_cmd.takes_commands(false)
107
+ install_cmd.short_desc("Install packages")
108
+ install_cmd.long_desc(<<-EOS)
109
+ Install of update packages
110
+ EOS
111
+ install_cmd.data={install: true}
112
+ add_install_option.call(install_cmd)
113
+ install_cmd.options do |opt|
114
+ opt.on("-u", "--[no-]update", "Update existing packages too") do |v|
115
+ install_cmd.data[:update]=v
116
+ end
117
+ end
118
+ install_cmd.options do |opt|
119
+ opt.on("-c", "--[no-]check", "Only check updates/install") do |v|
120
+ install_cmd.data[:check]=v
121
+ end
122
+ end
123
+ install_cmd.options do |opt|
124
+ opt.on("--[no-]rebuild=[mode]", "Rebuild given packages", "with --rebuild=full also rebuild their deps") do |v|
125
+ install_cmd.data[:rebuild]=v
126
+ end
127
+ end
128
+ install_cmd.options do |opt|
129
+ opt.on("--[no-]devel", "Also check/update devel packages") do |v|
130
+ install_cmd.data[:devel]=v
131
+ end
132
+ end
133
+ install_cmd.options do |opt|
134
+ opt.on("--[no-]obsolete", "Also show obsolete packages", "Not that you will get false obsolete packages unless you specifically upgrade everything") do |v|
135
+ install_cmd.data[:obsolete]=v
136
+ end
137
+ end
138
+ install_cmd.argument_desc(packages: "packages names")
139
+ install_cmd.action do |*packages|
140
+ if install_cmd.data[:devel]
141
+ Archlinux.config[:default_install_list_class]=AurMakepkgCache
142
+ end
143
+ aur=Archlinux.config.default_packages
144
+ opts={update: install_cmd.data[:update], rebuild: install_cmd.data[:rebuild]}
145
+ opts[:no_show]=[] if install_cmd.data[:obsolete]
146
+ if install_cmd.data[:check]
147
+ aur.install?(*packages, **opts)
148
+ else
149
+ opts[:install]=install_cmd.data[:install]
150
+ aur.install(*packages, **opts)
151
+ end
152
+ end
153
+ end
154
+
155
+ %w(pacman makepkg nspawn mkarchroot makechrootpkg).each do |cmd|
156
+ parser.add_command(cmd) do |devtools_cmd|
157
+ devtools_cmd.takes_commands(false)
158
+ devtools_cmd.short_desc("Launch #{cmd}")
159
+ case cmd
160
+ when "pacman"
161
+ devtools_cmd.long_desc(<<-EOS)
162
+ Launch pacman with a custom config file which makes the db accessible.
163
+ EOS
164
+ end
165
+ devtools_cmd.argument_desc(args: "#{cmd} arguments")
166
+ devtools_cmd.action do |*args|
167
+ devtools=Archlinux.config.local_devtools
168
+ devtools.public_send(cmd,*args, sudo: @config.sudo)
169
+ end
170
+ end
171
+ end
172
+
173
+ parser.add_command('db') do |db_cmd|
174
+ db_cmd.add_command('list') do |cmd|
175
+ cmd.takes_commands(false)
176
+ cmd.short_desc("List the content of the db")
177
+ cmd.options do |opt|
178
+ opt.on("-v", "--[no-]version", "Add the package version") do |v|
179
+ cmd.data[:version]=v
180
+ end
181
+ opt.on("-q", "--quiet", "Machine mode") do |v|
182
+ cmd.data[:quiet]=v
183
+ end
184
+ end
185
+ cmd.action do ||
186
+ db=Archlinux.config.db
187
+ if cmd.data[:quiet]
188
+ pkgs=db.packages
189
+ l= cmd.data[:version] ? pkgs.keys.sort : pkgs.names.sort
190
+ SH.logger.info l.join(' ')
191
+ else
192
+ SH.logger.mark "#{db.file}:"
193
+ db.packages.list(cmd.data[:version])
194
+ end
195
+ end
196
+ end
197
+
198
+ db_cmd.add_command('update') do |cmd|
199
+ cmd.takes_commands(false)
200
+ cmd.short_desc("Update the db")
201
+ cmd.long_desc(<<-EOS)
202
+ Update the db according to the packages present in its folder
203
+ EOS
204
+ cmd.options do |opt|
205
+ opt.on("-c", "--[no-]check", "Only check updates") do |v|
206
+ cmd.data[:check]=v
207
+ end
208
+ end
209
+ cmd.action do ||
210
+ db=Archlinux.config.db
211
+ if cmd.data[:check]
212
+ db.show_updates
213
+ else
214
+ db.update
215
+ end
216
+ end
217
+ end
218
+
219
+ db_cmd.add_command('add') do |cmd|
220
+ cmd.takes_commands(false)
221
+ cmd.short_desc("Add files to the db")
222
+ cmd.options do |opt|
223
+ opt.on("-f", "--[no-]force", "Force adding files that are older than the ones in the db") do |v|
224
+ cmd.data[:force]=v
225
+ end
226
+ end
227
+ cmd.action do |*files|
228
+ db=Archlinux.config.db
229
+ db.add_to_db(files, update: !cmd.data[:force])
230
+ end
231
+ end
232
+
233
+ db_cmd.add_command('rm') do |cmd|
234
+ cmd.takes_commands(false)
235
+ cmd.short_desc("Remove packages from db")
236
+ cmd.options do |opt|
237
+ opt.on("-f", "--[no-]force", "Also remove the package themselves") do |v|
238
+ cmd.data[:force]=v
239
+ end
240
+ end
241
+ cmd.action do |*files|
242
+ db=Archlinux.config.db
243
+ if cmd.data[:force]
244
+ db.rm_from_db(*files)
245
+ else
246
+ db.remove(*files)
247
+ end
248
+ end
249
+ end
250
+
251
+ db_cmd.add_command('clean') do |cmd|
252
+ cmd.takes_commands(false)
253
+ cmd.short_desc("Clean old files in the db repository")
254
+ cmd.options do |opt|
255
+ opt.on("-f", "--[no-]force", "Force clean (default to dry-run)") do |v|
256
+ cmd.data[:force]=v
257
+ end
258
+ end
259
+ cmd.action do ||
260
+ db=Archlinux.config.db
261
+ paths=db.clean(dry_run: !cmd.data[:force])
262
+ if cmd.data[:force]
263
+ SH.logger.mark "Cleaned:"
264
+ else
265
+ SH.logger.mark "To clean:"
266
+ end
267
+ SH.logger.info paths.map {|p| "- #{p}"}.join("\n")
268
+ end
269
+ end
270
+ end
271
+
272
+ parser.add_command('pkgs') do |pkgs_cmd|
273
+ pkgs_cmd.add_command('list') do |cmd|
274
+ cmd.takes_commands(false)
275
+ cmd.short_desc("List packages")
276
+ cmd.long_desc("The listed package can be '@db' (the current db), '@dbdir' (the packages in the db directory), ':core' (a pacman repo name), :local (the local repo), a file (/var/cache/pacman/pkg/linux-5.3.13.1-1-x86_64.pkg.tar.xz) or a package dir (/var/cache/pacman/pkg); @get(foo1,foo2) (query the aur), @rget(foo1,foo2) (recursively query the aur) ")
277
+ cmd.options do |opt|
278
+ opt.on("-v", "--[no-]version", "Add the package version") do |v|
279
+ cmd.data[:version]=v
280
+ end
281
+ end
282
+ cmd.action do |*repos|
283
+ pkgs=PackageClass.packages(*repos)
284
+ pkgs.list(cmd.data[:version])
285
+ end
286
+ end
287
+
288
+ pkgs_cmd.add_command('compare') do |cmd|
289
+ cmd.takes_commands(false)
290
+ cmd.short_desc("Compare packages")
291
+ cmd.long_desc(<<-EOS)
292
+ Use '--' to separate the two lists
293
+ Exemple: `compare @db -- @dbdir` is essentially the same as `db update -c`
294
+ Exemple: `compare @db -- @get(yay)` is like checking for a yay update
295
+ EOS
296
+ cmd.action do |*repos|
297
+ pkg1, pkg2 = PackageClass.packages_list(*repos)
298
+ pkg1.get_updates(pkg2)
299
+ end
300
+ end
301
+ end
302
+
303
+ parser.add_command('sign') do |cmd|
304
+ cmd.takes_commands(false)
305
+ cmd.short_desc("Sign files")
306
+ cmd.options do |opt|
307
+ opt.on("-f", "--[no-]force", "Overwrite existing signatures") do |v|
308
+ cmd.data[:force]=v
309
+ end
310
+ opt.on("-v", "--verify", "Verify signatures") do |v|
311
+ cmd.data[:verify]=v
312
+ end
313
+ end
314
+ cmd.action do |*files|
315
+ if cmd.data[:verify]
316
+ Archlinux.config.verify_sign(*files)
317
+ else
318
+ Archlinux.config.sign(*files, force: cmd.data[:force])
319
+ end
320
+ end
321
+ end
322
+
323
+ def parser.parse(*args, &b)
324
+ super(*args) do |lvl, cmd|
325
+ SH.process_log_options(self.data)
326
+ b.call(lvl, cmd) if b
327
+ end
328
+ end
329
+
330
+ @config.parser(parser)
331
+
332
+ parser
333
+ end
334
+ end