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,5 @@
1
+ module Archlinux
2
+ @config = {}
3
+ require 'aur/config'
4
+ @config = Config.new(nil)
5
+ end
@@ -0,0 +1,445 @@
1
+ require 'aur/config'
2
+ require 'aur/devtools'
3
+ require 'aur/packages'
4
+ require 'uri'
5
+ require 'tmpdir'
6
+
7
+ module Archlinux
8
+ # this is a get class; it should respond to update and clone
9
+ class Git
10
+ extend CreateHelper
11
+ attr_accessor :dir, :config, :logdir
12
+ attr_writer :url
13
+
14
+ def initialize(dir, url: nil, logdir: nil, config: Archlinux.config)
15
+ @dir=Pathname.new(dir)
16
+ @url=url
17
+ @config=config
18
+ @logdir=logdir
19
+ end
20
+
21
+ def url
22
+ url=URI.parse(@url)
23
+ url.relative? ? @config[:aur_url]+@url.to_s+".git" : url
24
+ end
25
+
26
+ def call(*args,**opts,&b)
27
+ opts[:method]||=:sh
28
+ @dir.chdir do
29
+ @config.launch(:git, *args, **opts, &b)
30
+ end
31
+ end
32
+
33
+ # callbacks called by makepkg
34
+ def done_view
35
+ call('branch', '-f', 'aur_view', 'HEAD')
36
+ end
37
+ def done_build
38
+ call('branch', '-f', 'aur_build', 'HEAD')
39
+ end
40
+
41
+ def write_patch(logdir)
42
+ (logdir+"#{@dir.basename}").on_ln_s(@dir.realpath, rm: :symlink)
43
+ if call("rev-parse", "--verify", "aur_view", method: :run_success, quiet: true)
44
+ SH::VirtualFile.new("orderfile", "PKGBUILD").create(true) do |tmp|
45
+ patch=call("diff", "-O#{tmp}", "aur_view", "HEAD", method: :run_simple)
46
+ (logdir+"#{@dir.basename}.patch").write(patch) unless patch.empty?
47
+ end
48
+ end
49
+ end
50
+
51
+ def do_update
52
+ # we need to hard reset, because vercmp may have changed our PKGBUILD
53
+ # todo: only reset when there is an update?
54
+ # lets try with a theirs merge strat
55
+ # call("reset", "--hard")
56
+ # -> still does not work: error: Your local changes to the following files would be overwritten by merge: PKGBUILD
57
+ ## suc, _r=call("pull", "-X", "theirs")
58
+ call("reset", "--hard")
59
+ suc, _r=call("pull")
60
+ suc
61
+ end
62
+
63
+ def do_clone(url)
64
+ #we cannot call 'call' here because the folder does not yet exist
65
+ suc, _r=@config.launch(:git, "clone", url, @dir, method: :sh)
66
+ suc
67
+ end
68
+
69
+ def update(logdir: nil)
70
+ if do_update
71
+ write_patch(logdir) if logdir
72
+ else
73
+ SH.logger.error("Error in updating #{@dir}")
74
+ end
75
+ end
76
+
77
+ def clone(url: self.url, logdir: nil)
78
+ if do_clone(url)
79
+ (logdir+"!#{@dir.basename}").on_ln_s(@dir.realpath) if logdir
80
+ else
81
+ SH.logger.error("Error in cloning #{url} to #{@dir}")
82
+ end
83
+ end
84
+ end
85
+
86
+ module MakepkgCommon
87
+ #functions common to Makepkg and MakepkgList
88
+
89
+ def add_to_db(db=@config.db, force_sign: false)
90
+ unless db.is_a?(DB)
91
+ SH.logger.error "Bad database #{db}, can't add to database"
92
+ else
93
+ db.add(*list.select {|l| r=l.exist?; SH.logger.warn "Package #{l} not built, not adding to the db #{db.repo_name}" unless r; r}, force_sign: force_sign)
94
+ true #do return false if there were errors
95
+ end
96
+ end
97
+
98
+ end
99
+
100
+ class Makepkg
101
+ extend CreateHelper
102
+ include MakepkgCommon
103
+ attr_accessor :dir, :base, :env, :config, :asdeps
104
+ attr_writer :get_pkg
105
+
106
+ def initialize(dir, config: Archlinux.config, env: {}, asdeps: false)
107
+ @dir=Pathname.new(dir)
108
+ @base=@dir.basename #the corresponding pkgbase
109
+ @config=config
110
+ @env=env
111
+ @asdeps=asdeps
112
+ db=@config.db
113
+ @env['PKGDEST']=db.dir.to_s if db
114
+ end
115
+
116
+ # should respond to clone, update
117
+ # and optionally done_view, done_build
118
+ def get_pkg
119
+ #@get_pkg||=@config[:default_get_class].new(@dir, url: name, config: @config)
120
+ @get_pkg ||= Archlinux.create_class(@config[:default_get_class], @dir, url: name, config: @config)
121
+ end
122
+
123
+ def name
124
+ @base.to_s
125
+ end
126
+
127
+ def pkgbuild
128
+ @dir+"PKGBUILD"
129
+ end
130
+
131
+ def exist?
132
+ pkgbuild.exist?
133
+ end
134
+
135
+ def raw_call(*args, method: :run_simple, **opts)
136
+ @config.launch(:makepkg, *args, **opts) do |*args, **opts|
137
+ @dir.chdir do
138
+ SH.public_send(method, @env, *args, **opts)
139
+ end
140
+ end
141
+ end
142
+
143
+ # raw call to makepkg
144
+ def makepkg(*args, **opts)
145
+ raw_call(*args, method: :sh, **opts)
146
+ end
147
+
148
+ def call(*args, **opts)
149
+ tools=@config.local_devtools #this set up pacman and makepkg config files
150
+ env=opts.delete(:env) || {}
151
+ opts[:method]||=:run_simple
152
+ @dir.chdir do
153
+ tools.makepkg(*args, env: @env.merge(env), **opts)
154
+ end
155
+ end
156
+
157
+ def info(get: false)
158
+ if get
159
+ get_options={}
160
+ get_options=get if get.is_a?(Hash)
161
+ self.get(**get_options)
162
+ end
163
+ stdin=call("--printsrcinfo", chomp: :lines)
164
+ mode=nil; r={}; current={}; pkgname=nil
165
+ stdin.each do |l|
166
+ key, value=l.split(/\s*=\s*/,2)
167
+ next if key.nil?
168
+ if key=="pkgbase"
169
+ mode=:pkgbase
170
+ current[:pkgbase]=value
171
+ current[:repo]=@dir
172
+ elsif key=="pkgname"
173
+ if mode==:pkgbase
174
+ r=current
175
+ r[:pkgs]={}
176
+ else
177
+ r[:pkgs][pkgname]=current
178
+ end
179
+ current={}; mode=:pkgname; pkgname=value
180
+ else
181
+ key=key.strip.to_sym
182
+ Archlinux.add_to_hash(current, key, value)
183
+ end
184
+ end
185
+ r[:pkgs][pkgname]=current #don't forget to update the last one
186
+ r
187
+ end
188
+
189
+ def packages(refresh=false, get: false)
190
+ @packages=nil if refresh
191
+ unless @packages
192
+ r=info(get: get)
193
+ pkgs=r.delete(:pkgs)
194
+ # r[:pkgbase]
195
+ base=Package.new(r)
196
+ list=pkgs.map do |name, pkg|
197
+ pkg[:name]=name
198
+ Package.new(pkg).merge(base)
199
+ end
200
+ @packages=@config.to_packages(list)
201
+ end
202
+ @packages
203
+ end
204
+
205
+ def get(logdir: nil, view: false, update: true, clone: true, pkgver: false)
206
+ if logdir
207
+ logdir=Pathname.new(logdir)
208
+ logdir.mkpath
209
+ end
210
+ get_pkg=self.get_pkg
211
+
212
+ if @dir.exist? and update
213
+ get_pkg.update(logdir: logdir)
214
+ elsif !@dir.exist? and clone
215
+ get_pkg.clone(logdir: logdir)
216
+ end
217
+ if view #view before calling pkgver
218
+ r=@config.view(@dir)
219
+ get_pkg.done_view if r and get_pkg.respond_to?(:done_view)
220
+ else
221
+ r=true
222
+ end
223
+ if r and pkgver and pkgver?
224
+ get_source
225
+ else
226
+ return r #abort pkgver
227
+ end
228
+ end
229
+
230
+ # shortcut
231
+ def edit
232
+ get(view: true, update: false, clone: true, pkgver: false)
233
+ end
234
+ def edit_pkgbuild
235
+ get(view: false, update: false, clone: true, pkgver: false)
236
+ #TODO: @config.view_file/view_dir?
237
+ @config.view(@dir+"PKGBUILD")
238
+ end
239
+
240
+ def pkgver?
241
+ exist? and pkgbuild.read.match(/^\s*pkgver()/)
242
+ end
243
+
244
+ def get_source
245
+ success, _r=call('--nodeps', '--nobuild', method: :sh)
246
+ success
247
+ end
248
+
249
+ def make(*args, sign: config&.use_sign?(:package), default_opts: [], force: false, asdeps: @asdeps, **opts)
250
+ default_opts << "--sign" if sign
251
+ default_opts << "--key=#{sign}" if sign.is_a?(String)
252
+ default_opts << "--force" if force
253
+ default_opts << "--asdeps" if asdeps
254
+ default_opts+=@config[:makepkg][:build_args]
255
+
256
+ # error=13 means the package is already built, we consider that a success
257
+ success, _r=call(*args, method: :sh, default_opts: default_opts, env: @env, expected: 13, **opts)
258
+ get_pkg.done_build if success and get_pkg.respond_to?(:done_build)
259
+ success
260
+ end
261
+
262
+ def mkarchroot
263
+ args=@config.dig(:chroot, :packages) || ["base-devel"]
264
+ @config.chroot_devtools.mkarchroot(*args)
265
+ end
266
+
267
+ def makechroot(*args, sign: @config&.use_sign?(:package), force: false, **opts)
268
+ unless force
269
+ if list.all? {|f| f.exist?}
270
+ SH.logger.info "Skipping #{@dir} since it is already built (use force=true to override)"
271
+ return true #consider this a success build
272
+ end
273
+ end
274
+ devtools=@config.chroot_devtools
275
+ success=false
276
+ @dir.chdir do
277
+ success=devtools.makechrootpkg(*args, env: @env, **opts)
278
+ end
279
+ ## signing should be done by 'build'
280
+ # self.sign(sign_name: sign) if sign and success
281
+ success
282
+ end
283
+
284
+ def build(*makepkg_args, mkarchroot: false, chroot: @config.dig(:chroot, :active), **opts)
285
+ force_sign = opts.delete(:rebuild) #when rebuilding we need to regenerate the signature
286
+ SH.logger.important "=> Building #{@dir}"
287
+ if chroot
288
+ self.mkarchroot if mkarchroot
289
+ success, _r=makechroot(*makepkg_args, **opts)
290
+ else
291
+ success, _r=make(*makepkg_args, **opts)
292
+ end
293
+ if success and (db=@config.db)
294
+ success=add_to_db(db, force_sign: force_sign)
295
+ if !chroot #sync db so that the new versions are available
296
+ tools=@config.local_devtools
297
+ tools.sync_db(db.repo_name)
298
+ end
299
+ end
300
+ if success
301
+ packages.l.keys #return the list of built package
302
+ # TODO better handling of split dirs
303
+ else
304
+ success
305
+ end
306
+ end
307
+
308
+ def install(*args, view: true, **opts)
309
+ r=get(view: view)
310
+ if r
311
+ build(*args, **opts)
312
+ else
313
+ r
314
+ end
315
+ end
316
+
317
+ def list(**opts)
318
+ call("--packagelist", chomp: :lines, err: "/dev/null", **opts).map {|f| Pathname.new(f)}
319
+ end
320
+
321
+ def sign(sign_name: :package, **opts)
322
+ @config.sign(*list.select {|f| f.file?}, sign_name: sign_name, **opts)
323
+ end
324
+
325
+ end
326
+
327
+ class MakepkgList
328
+ extend CreateHelper
329
+ include MakepkgCommon
330
+ Archlinux.delegate_h(self, :@l)
331
+ attr_accessor :config, :cache, :l
332
+
333
+ def self.from_dir(dir=nil, config: Archlinux.config)
334
+ l=[]
335
+ dir=config.cachedir if dir.nil?
336
+ dir.children.each do |child|
337
+ if child.directory? and (child+"PKGBUILD").file?
338
+ l << child
339
+ end
340
+ end
341
+ self.new(l, config: config)
342
+ end
343
+
344
+ def initialize(l=[], config: Archlinux.config, cache: config.cachedir)
345
+ @config=config
346
+ @cache=Pathname.new(cache) if cache #how relative filenames are resolved; pass nil to use current dir
347
+ @l={}
348
+ merge(l)
349
+ end
350
+
351
+ def merge(l)
352
+ l.each do |m|
353
+ unless m.is_a?(Makepkg)
354
+ m=Pathname.new(m)
355
+ m = @cache+m if m.relative? and @cache
356
+ m=Makepkg.new(m, config: @config)
357
+ end
358
+ @l[m.name]=m
359
+ end
360
+ end
361
+
362
+ def packages(refresh=false, get: false)
363
+ @packages = nil if refresh
364
+ if get
365
+ get_options={}
366
+ get_options=get if get.is_a?(Hash)
367
+ self.get(**get_options)
368
+ end
369
+ @packages ||= @l.values.reduce(@config.to_packages) do |list, makepkg|
370
+ list.merge(makepkg.packages(get: false))
371
+ end
372
+ end
373
+
374
+ def get(*_args, view: true, pkgver: false, **opts)
375
+ Dir.mktmpdir("aur_view") do |d|
376
+ @l.values.each do |l|
377
+ l.get(*_args, logdir: d, view: false, pkgver: false, **opts) #l.get does not take arguments, we put them here for arg/opt ruby confusion
378
+ end
379
+ if view
380
+ r=@config.view(d)
381
+ if r
382
+ @l.values.each do |l|
383
+ l.get_pkg.done_view if l.get_pkg.respond_to?(:done_view)
384
+ end
385
+ end
386
+ else
387
+ r=true
388
+ end
389
+ if r and pkgver
390
+ @l.values.map do |l| #all?
391
+ l.get_source if l.pkgver?
392
+ end
393
+ end
394
+ return r
395
+ end
396
+ end
397
+
398
+ def make(*args)
399
+ @l.values.each do |l|
400
+ l.make(*args)
401
+ end
402
+ end
403
+
404
+ def makechroot(*args)
405
+ @l.values.each do |l|
406
+ l.makechroot(*args)
407
+ end
408
+ end
409
+
410
+ def mkarchroot
411
+ args=@config.dig(:chroot, :packages) || ["base-devel"]
412
+ @config.chroot_devtools.mkarchroot(*args)
413
+ end
414
+
415
+ def list
416
+ @l.values.flat_map { |l| l.list }
417
+ end
418
+
419
+ def build(*args, chroot: @config.dig(:chroot, :active), install: false, **opts)
420
+ mkarchroot if chroot
421
+ @config.pre_install(*args, makepkg_list: self, install: install, **opts)
422
+ built=@l.values.map do |l|
423
+ l.build(*args, chroot: chroot, **opts)
424
+ end
425
+ l_success=built.flat_map { |pkgs| pkgs || []}
426
+ @config.post_install(l_success, makepkg_list: self, install: install, **opts)
427
+ built
428
+ end
429
+
430
+ # Note that in build @config.{pre,post}_install is called
431
+ def pre_build(*args, **opts)
432
+ end
433
+
434
+ def post_build(*args, **opts)
435
+ end
436
+
437
+
438
+ def install(*args, view: true, **opts)
439
+ r=get(view: view)
440
+ pre_build(*args, **opts)
441
+ build(*args, **opts) if r
442
+ post_build(*args, **opts)
443
+ end
444
+ end
445
+ end
@@ -0,0 +1,5 @@
1
+ module Archlinux
2
+ @config = {}
3
+ require 'aur/config'
4
+ @config = Config.new(nil)
5
+ end