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.
@@ -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