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
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 999e692d5181b3abf4c5d0649c456a7e4e717fd3f7b2a4b88d38d340a0bd9c45
|
4
|
+
data.tar.gz: 4a44d86a52faf23ce9fbf720b0b2875239e49307d0e80cad58bf48045a52b3e8
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 2f3d706085720f78e4fb7cb3d37d4fceb6a99982e11c80b8dc2a59678966824d0913c9becc59707b1823f7f37c9f1ccb2fc360a138d83b11744edabad26713e7
|
7
|
+
data.tar.gz: 70a7f785463661f9cd9412c4fb9f08ef74893fd0e2ce20b6cc28aeeb9779a835718601913b549f17297fad241b18b00c386353865291bb8743149855215c7530
|
data/ChangeLog.md
CHANGED
@@ -1,4 +1,138 @@
|
|
1
|
-
|
1
|
+
== Release v0.2.0 (2020-02-21) ==
|
2
2
|
|
3
|
-
*
|
3
|
+
* TODO++
|
4
|
+
* TODO.md
|
5
|
+
* config: fix sign_names
|
6
|
+
* config: use devtools makepkg in chroot
|
7
|
+
* pre build: pre sign an empty files to initialize keyring
|
8
|
+
* DR::URI is now DR::URIEscape
|
9
|
+
* Use back URI.escape (via a wrapper to disable warnings)
|
10
|
+
* Ruby 2.7 warning fixes
|
11
|
+
* Fixes for ruby 2.7
|
12
|
+
* Update for ruby 2.7
|
13
|
+
* packages: add @get() and @rget()
|
14
|
+
* config.rb: Bug fix
|
15
|
+
* Default packages: allow customisations
|
16
|
+
* cli: pkgs compare
|
17
|
+
* Bug fixes
|
18
|
+
* cli: aur.rb pkgs list ...
|
19
|
+
* Bug fix
|
20
|
+
* cli: db list, db rm
|
21
|
+
* better update infos
|
22
|
+
* db: clean up update code
|
23
|
+
* aur.rb: TODO + fix db rm bug
|
24
|
+
* cli: Add devtools commands
|
25
|
+
* cli: aur search => allow multiple terms
|
26
|
+
* cli: --no-chroot, --local
|
27
|
+
* makepkg: get list of built packages for post_install callback
|
28
|
+
* cli: --install/--no-install option
|
29
|
+
* Add build command
|
30
|
+
* config: use PPHelper
|
31
|
+
* Distinguish package list class from an install package list class
|
32
|
+
* Split packages into install_packages
|
33
|
+
* DB#clean_obsolete
|
34
|
+
* PackageFiles#rm_pkgs
|
35
|
+
* Documentation updates
|
36
|
+
* Doc updates
|
37
|
+
* Bug fixes, DB#show_updates
|
38
|
+
* Improve messages
|
39
|
+
* Fix verbosity level
|
40
|
+
* Fix logger invocations for new SH.logger api
|
41
|
+
* cli: use standard log options
|
42
|
+
* Logger: color mode
|
43
|
+
* Gemspec: add metadata
|
44
|
+
* Update Rakefile
|
45
|
+
* cli: sign
|
46
|
+
* TODO++
|
47
|
+
* Verbosity
|
48
|
+
* pretty_print: don't expand Config
|
49
|
+
* sign: bug fixes (+ reduce verbosity of exec)
|
50
|
+
* db: Move sig files
|
51
|
+
* makepkg: resign files when rebuilding
|
52
|
+
* repos.rb: clean return the paths too
|
53
|
+
* config.rb: post_install now install correct (updated) version
|
54
|
+
* packages.rb: fix --rebuild=true
|
55
|
+
* makepkg.rb: improve visibility of logging
|
56
|
+
* cli.rb: --verbose
|
57
|
+
* More debug informations
|
58
|
+
* cli.rb: debug and log level
|
59
|
+
* db: allow to return PackageFiles rather than Packages
|
60
|
+
* PackageFiles#clean
|
61
|
+
* add_to_db: bug fixes
|
62
|
+
* DB#add_to_db
|
63
|
+
* post_install: call with list of packages success
|
64
|
+
* cli.rb: --devel switch
|
65
|
+
* makepkg.rb: we need to use `reset --hard`
|
66
|
+
* packages.rb: Bug fix in AurMakepkgCache
|
67
|
+
* Add debug statements
|
68
|
+
* TODO++
|
69
|
+
* Helpers: create_class
|
70
|
+
* db.rb: use realdirpath and fallback to abs path
|
71
|
+
* cli.rb: `db update`
|
72
|
+
* A package already built is a success
|
73
|
+
* Implement --rebuild
|
74
|
+
* cli: pacman command
|
75
|
+
* config: default to not devel
|
76
|
+
* post_install
|
77
|
+
* packages: unify how to get a MakepkgList
|
78
|
+
* makepkg: missing require
|
79
|
+
* cli
|
80
|
+
* Use SH.log
|
81
|
+
* aur_rpc: rework class vs modules layout
|
82
|
+
* Global aur cache
|
83
|
+
* packages.rb: AurMakepkgCache preserve MakepkgList
|
84
|
+
* Package by package install method
|
85
|
+
* bug fixes + config.default_packages
|
86
|
+
* repos.rb: RepoPkgs, LocalRepo
|
87
|
+
* bugfixes + TODO++
|
88
|
+
* MakepkgList.from_dir, Repo.foreign_packages
|
89
|
+
* verify signatures
|
90
|
+
* db.rb: use bsdtar rather than bsdcat to parse db files
|
91
|
+
* packages.rb: add keys which have array values
|
92
|
+
* Makepkg: edit and edit_pkgbuild
|
93
|
+
* db and packages: more bug fixes
|
94
|
+
* Bug fixes
|
95
|
+
* no_load_config: don't read the user config file
|
96
|
+
* Bug fixes + update TODO list
|
97
|
+
* Bug fixes
|
98
|
+
* makepkg: methods now return success or failure
|
99
|
+
* Comments + api change
|
100
|
+
* PackageFiles: default to bsdtar rathern than expac
|
101
|
+
* More bug fixes
|
102
|
+
* Bug fixes and be less verbose
|
103
|
+
* makepkg: view before pkgver
|
104
|
+
* config: use deep_merge
|
105
|
+
* @config.sign: sign files rather than just a file
|
106
|
+
* makepkg: done_view and done_build
|
107
|
+
* makepkg: move git stuff to its own class
|
108
|
+
* devtools + makepkg: unify api
|
109
|
+
* sign: uniformise api
|
110
|
+
* Rework sudo_loop, put it in shell_helpers
|
111
|
+
* packages: chain queries
|
112
|
+
* makepkg: get options + db sign files
|
113
|
+
* makepkg: check pkgver
|
114
|
+
* More bug fixes
|
115
|
+
* Bug fixes
|
116
|
+
* Bug fixes
|
117
|
+
* VirtualMakepkgCache
|
118
|
+
* MakepkgList cache
|
119
|
+
* packages: to_ext_query
|
120
|
+
* aur_rpc: AurQueryCustom to set individual @config
|
121
|
+
* Pass along config and allow to specify the default PackageList class
|
122
|
+
* packages: fix ups
|
123
|
+
* packages: better api for do_install
|
124
|
+
* packages: ignore
|
125
|
+
* config.rb: sudo_loop, get_config_file
|
126
|
+
* config.rb: sudo loop + options
|
127
|
+
* Warn when a package was not built
|
128
|
+
* packages update/install: do it against another list
|
129
|
+
* Inject config
|
130
|
+
* Split into different files
|
131
|
+
|
132
|
+
== Release v0.1.0 (2018-09-07) ==
|
133
|
+
|
134
|
+
* Update library paths
|
135
|
+
* Add code + gemspec dependencies
|
136
|
+
* Update README.md
|
137
|
+
* Initial commit.
|
4
138
|
|
data/LICENSE.txt
CHANGED
data/README.md
CHANGED
@@ -24,8 +24,28 @@ installation.
|
|
24
24
|
|
25
25
|
$ gem install aur.rb
|
26
26
|
|
27
|
+
## Notes
|
28
|
+
|
29
|
+
There are three ways to install packages. The first is to simply use
|
30
|
+
`makepkg -si`. Here aur dependency packages built need to be installed
|
31
|
+
because `pacman` won't find them. So it may be cause for conflict.
|
32
|
+
|
33
|
+
The other way is to build dependency packages and add them to a database.
|
34
|
+
This allows further call to `makepkg -s` to find them if they are needed to
|
35
|
+
build a particular package. It may still cause conflict because they are
|
36
|
+
installed against the full system.
|
37
|
+
|
38
|
+
The last way is to build in a chroot. Here a database is needed too so the
|
39
|
+
chroot can access to the previously built dependency packages.
|
40
|
+
|
41
|
+
Adding a database require modifying `pacman.conf`, but `aur.rb` will
|
42
|
+
generate a temporary `pacman.conf` with the current database location
|
43
|
+
and use that when needed.
|
44
|
+
|
45
|
+
With this feature it is easy to simulate `checkupdates` too.
|
46
|
+
|
27
47
|
## Copyright
|
28
48
|
|
29
|
-
Copyright © 2018 Damien Robert
|
49
|
+
Copyright © 2018–2020 Damien Robert
|
30
50
|
|
31
51
|
MIT License. See [LICENSE.txt](./LICENSE.txt) for details.
|
data/Rakefile
CHANGED
@@ -1,15 +1,5 @@
|
|
1
1
|
require 'rake'
|
2
2
|
|
3
|
-
begin
|
4
|
-
require 'rubygems/tasks'
|
5
|
-
Gem::Tasks.new(sign: {checksum: true, pgp: true},
|
6
|
-
scm: {status: true}) do |tasks|
|
7
|
-
tasks.console.command = 'pry'
|
8
|
-
end
|
9
|
-
rescue LoadError => e
|
10
|
-
warn e.message
|
11
|
-
end
|
12
|
-
|
13
3
|
require 'rake/testtask'
|
14
4
|
Rake::TestTask.new do |test|
|
15
5
|
test.libs << 'test'
|
@@ -27,3 +17,10 @@ rescue LoadError => e
|
|
27
17
|
end
|
28
18
|
task :doc => :yard
|
29
19
|
|
20
|
+
begin
|
21
|
+
require 'dr/rake_gems'
|
22
|
+
Gem::MyTasks.new
|
23
|
+
rescue LoadError => e
|
24
|
+
warn e.message
|
25
|
+
end
|
26
|
+
|
data/TODO.md
ADDED
@@ -0,0 +1,69 @@
|
|
1
|
+
# Api
|
2
|
+
|
3
|
+
- tests
|
4
|
+
- check if splitpackages are handled correctly
|
5
|
+
- add doc
|
6
|
+
|
7
|
+
## Improvements
|
8
|
+
|
9
|
+
- replace AurMakepkgCache with a more generic aggregator
|
10
|
+
- using tsort in rget won't do a breadth first search, which would reduce
|
11
|
+
the number of aur queries. With tsort packages are queried one by one.
|
12
|
+
- split Makepkg into a class for downloading/viewing/querying and the
|
13
|
+
class for installing. This will allow to support both github and the aur
|
14
|
+
rpc.
|
15
|
+
- preference to decide which :provides to choose
|
16
|
+
(and favorise local packages for provides)
|
17
|
+
|
18
|
+
## UI
|
19
|
+
|
20
|
+
- view only when updated/new + add trusted PKGBUILD
|
21
|
+
- confirm before installing or updating pkgver (this is somewhat orthogonal to exiting when view return false since we may want to not view the files)
|
22
|
+
- due to vercmp, we need to reset packages before pulling
|
23
|
+
=> use stash?
|
24
|
+
|
25
|
+
# Bugs
|
26
|
+
|
27
|
+
- in `official` we need to also list packages provided by them, eg
|
28
|
+
libarchive provides libarchive.so (but libarchive.so does not exist
|
29
|
+
separately, but eg aurutils-git requires it)
|
30
|
+
- also when we have custom packages in our db (not in aur), we get missing
|
31
|
+
warnings for these packages
|
32
|
+
- when using AurMakepkgCache, missing packages info are repeated several times
|
33
|
+
- in `sync_db` setup a simily local cache so that the packages don't get copied twice (ie both in `/var/cache/pacman` and in `~/.cache/arch_aur/.db`).
|
34
|
+
- makechrootpkg does not propagate 'PKGEXT' setting. So if we use zstd in
|
35
|
+
our local makepkg.conf, `aur.rb` will expect a `zst` package to be
|
36
|
+
built, but an `xz` will be built instead (per the default
|
37
|
+
`makepkg.conf` in the chroot). Not sure how to fix this. The solution
|
38
|
+
is to specify devtool's `makepkg.conf` for chroot builds (cf the
|
39
|
+
config).
|
40
|
+
|
41
|
+
# CLI
|
42
|
+
|
43
|
+
- in db update, allow to be more atomic, same for clean
|
44
|
+
That is we want to be able to specify which packages we want to
|
45
|
+
update/clean
|
46
|
+
|
47
|
+
- in `aur install`:
|
48
|
+
- add --no-fetch and --fetch=only (or add an extra command specialised in
|
49
|
+
fetching PKGBUILD?);
|
50
|
+
- add --extra-db= to specify an external db
|
51
|
+
- add --buildopts="..." that gets passed to our build function
|
52
|
+
|
53
|
+
- Add packages informations:
|
54
|
+
- 'package info'
|
55
|
+
- 'package compare' [DONE]
|
56
|
+
- 'package list' [DONE]
|
57
|
+
|
58
|
+
- Expand around our temp pacman config features to remake `checkupdates` in
|
59
|
+
a more flexible way. For instance to only update our extra database on
|
60
|
+
interact with our `aur` database. Would need features to symlink the
|
61
|
+
local database too.
|
62
|
+
|
63
|
+
- Clean `~/.cache/arch_aur`. Essentially a wrapper to call
|
64
|
+
`for i in *(/); do git -C $i clean -ndx; done`
|
65
|
+
|
66
|
+
# Tools
|
67
|
+
|
68
|
+
- use https://github.com/falconindy/pkgbuild-introspection/ to speed up .SRCINFO
|
69
|
+
|
data/aur.rb.gemspec
CHANGED
data/bin/aur.rb
ADDED
data/lib/aur.rb
CHANGED
@@ -1,1861 +1,51 @@
|
|
1
1
|
require 'aur/version'
|
2
|
-
require '
|
3
|
-
require '
|
4
|
-
require '
|
5
|
-
require '
|
6
|
-
require '
|
7
|
-
require '
|
8
|
-
require '
|
2
|
+
require 'aur/config'
|
3
|
+
require 'aur/aur_rpc'
|
4
|
+
require 'aur/db'
|
5
|
+
require 'aur/repos'
|
6
|
+
require 'aur/versions'
|
7
|
+
require 'aur/devtools'
|
8
|
+
require 'aur/makepkg'
|
9
|
+
require 'aur/packages'
|
10
|
+
require 'aur/install_packages'
|
9
11
|
|
10
|
-
|
11
|
-
|
12
|
-
|
13
|
-
Pathname=::SH::Pathname
|
14
|
-
|
15
|
-
def self.delegate_h(klass, var)
|
16
|
-
klass.extend(Forwardable)
|
17
|
-
methods=[:[], :[]=, :any?, :assoc, :clear, :compact, :compact!, :delete, :delete_if, :dig, :each, :each_key, :each_pair, :each_value, :empty?, :fetch, :fetch_values, :has_key?, :has_value?, :include?, :index, :invert, :keep_if, :key, :key?, :keys, :length, :member?, :merge, :merge!, :rassoc, :reject, :reject!, :select, :select!, :shift, :size, :slice, :store, :to_a, :to_h, :to_s, :transform_keys, :transform_keys!, :transform_values, :transform_values!, :update, :value?, :values, :values_at]
|
18
|
-
klass.include(Enumerable)
|
19
|
-
klass.send(:def_delegators, var, *methods)
|
20
|
-
end
|
21
|
-
|
22
|
-
class Config
|
23
|
-
def self.create(v)
|
24
|
-
v.is_a?(self) ? v : self.new(v)
|
25
|
-
end
|
26
|
-
|
27
|
-
attr_accessor :opts
|
28
|
-
Archlinux.delegate_h(self, :@opts)
|
29
|
-
include SH::ShConfig
|
30
|
-
|
31
|
-
def initialize(file, **opts)
|
32
|
-
file=Pathname.new(file)
|
33
|
-
file=Pathname.new(ENV["XDG_CONFIG_HOME"] || "#{ENV['HOME']}/.config") + file if file.relative?
|
34
|
-
file_config= file.readable? ? file.read : '{}'
|
35
|
-
wrap=eval("Proc.new { |context| #{file_config} }")
|
36
|
-
@opts=default_config.merge(opts)
|
37
|
-
@opts.merge!(wrap.call(self))
|
38
|
-
end
|
39
|
-
|
40
|
-
def sh_config
|
41
|
-
@opts[:sh_config]
|
42
|
-
end
|
43
|
-
|
44
|
-
def default_config
|
45
|
-
{
|
46
|
-
cache: "arch_aur", #where we dl PKGBUILDs
|
47
|
-
db: 'aur', #if relative the db will be in cachedir
|
48
|
-
aur_url: "https://aur.archlinux.org/", #base aur url
|
49
|
-
chroot: "/var/lib/aurbuild/x86_64", #chroot root
|
50
|
-
build_chroot: false, #do we use the chroot?
|
51
|
-
chroot_update: 'pacman -Syu --noconfirm', #how to update an existing chroot
|
52
|
-
sign: true, #can be made more atomic, cf the sign method
|
53
|
-
devtools_pacman: "/usr/share/devtools/pacman-extra.conf", #pacman.conf for chroot build
|
54
|
-
pacman_conf: "/etc/pacman.conf", #default pacman-conf (for makepkg build)
|
55
|
-
sh_config: { #default programs options
|
56
|
-
makepkg: {default_opts: ["-crs", "--needed"]},
|
57
|
-
makechrootpkg: {default_opts: ["-cu"]},
|
58
|
-
},
|
59
|
-
view: "vifm -c view! -c tree -c 0",
|
60
|
-
git_update: "git pull",
|
61
|
-
git_clone: "git clone",
|
62
|
-
}
|
63
|
-
end
|
64
|
-
|
65
|
-
#:makepkg, :makechrootpkg, :repo (=repo-add, repo-remove)
|
66
|
-
def sign(mode)
|
67
|
-
opt_sign=@opts[:sign]
|
68
|
-
if opt_sign.is_a?(Hash)
|
69
|
-
opt_sign[mode]
|
70
|
-
else
|
71
|
-
opt_sign
|
72
|
-
end
|
73
|
-
end
|
74
|
-
|
75
|
-
def view(dir)
|
76
|
-
view=@opts[:view]
|
77
|
-
case view
|
78
|
-
when Proc
|
79
|
-
view.call(dir)
|
80
|
-
else
|
81
|
-
success, _rest=SH.sh("#{view} #{dir.shellescape}")
|
82
|
-
return success
|
83
|
-
end
|
84
|
-
end
|
85
|
-
|
86
|
-
def git_update
|
87
|
-
method=@opts[:git_update]
|
88
|
-
case method
|
89
|
-
when Proc
|
90
|
-
method.call(dir)
|
91
|
-
else
|
92
|
-
success, _rest=SH.sh(method)
|
93
|
-
return success
|
94
|
-
end
|
95
|
-
end
|
96
|
-
|
97
|
-
def git_clone(url, dir)
|
98
|
-
method=@opts[:git_clone]
|
99
|
-
case method
|
100
|
-
when Proc
|
101
|
-
method.call(url, dir)
|
102
|
-
else
|
103
|
-
success, _rest=SH.sh("#{method} #{url.shellescape} #{dir.shellescape}")
|
104
|
-
return success
|
105
|
-
end
|
106
|
-
end
|
107
|
-
|
108
|
-
def cachedir
|
109
|
-
global_cache=Pathname.new(ENV["XDG_CACHE_HOME"] || "#{ENV['HOME']}/.cache")
|
110
|
-
cache=global_cache+@opts[:cache]
|
111
|
-
cache.mkpath
|
112
|
-
cache
|
113
|
-
end
|
114
|
-
|
115
|
-
def setup_pacman_conf(conf)
|
116
|
-
pacman=PacmanConf.create(conf)
|
117
|
-
aur=self.db(false)
|
118
|
-
if aur and !pacman[:repos].include?(aur.repo_name)
|
119
|
-
pacman[:repos][aur.repo_name]={Server: ["file://#{URI.escape(aur.dir.to_s)}"]}
|
120
|
-
end
|
121
|
-
pacman
|
122
|
-
end
|
123
|
-
|
124
|
-
def default_pacman_conf
|
125
|
-
@default_pacman_conf ||= if (conf=@opts[:pacman_conf])
|
126
|
-
PacmanConf.new(conf)
|
127
|
-
else
|
128
|
-
PacmanConf
|
129
|
-
end
|
130
|
-
end
|
131
|
-
|
132
|
-
def devtools
|
133
|
-
unless @devtools_config
|
134
|
-
require 'uri'
|
135
|
-
# here we need the raw value, since this will be used by pacstrap
|
136
|
-
# which calls pacman --root; so the inferred path for DBPath and so
|
137
|
-
# on would not be correct since it is specified
|
138
|
-
devtools_pacman=PacmanConf.new(@opts[:devtools_pacman], raw: true)
|
139
|
-
# here we need to expand the config, so that Server =
|
140
|
-
# file://...$repo...$arch get their real values
|
141
|
-
my_pacman=default_pacman_conf
|
142
|
-
devtools_pacman[:repos].merge!(my_pacman.non_official_repos)
|
143
|
-
setup_pacman_conf(devtools_pacman)
|
144
|
-
@devtools_config = Devtools.new(pacman_conf: devtools_pacman)
|
145
|
-
end
|
146
|
-
@devtools_config
|
147
|
-
end
|
148
|
-
|
149
|
-
def makepkg_config
|
150
|
-
unless @makepkg_config
|
151
|
-
makepkg_pacman=default_pacman_conf
|
152
|
-
setup_pacman_conf(makepkg_pacman)
|
153
|
-
@makepkg_config = Devtools.new(pacman_conf: makepkg_pacman)
|
154
|
-
end
|
155
|
-
@makepkg_config
|
156
|
-
end
|
157
|
-
|
158
|
-
def db=(name)
|
159
|
-
case name
|
160
|
-
when DB
|
161
|
-
@db=name
|
162
|
-
when Pathname
|
163
|
-
@db=DB.new(name)
|
164
|
-
when String
|
165
|
-
if DB.db_file?(name)
|
166
|
-
@db=DB.new(name)
|
167
|
-
else
|
168
|
-
@db=DB.new(cachedir+".db"+"#{name}.db.tar.gz")
|
169
|
-
end
|
170
|
-
when true
|
171
|
-
@db=DB.new(cachedir+".db"+"aur.db.tar.gz")
|
172
|
-
when false, nil
|
173
|
-
@db=name #false for false, nil to reset
|
174
|
-
else
|
175
|
-
SH.logger.warn("Database name #{name} not suitable")
|
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
|
-
end
|
196
|
-
|
197
|
-
self.singleton_class.attr_accessor :config
|
198
|
-
@config=Config.new("aur.rb")
|
199
|
-
|
200
|
-
def self.add_to_hash(h, key, value)
|
201
|
-
case h[key]
|
202
|
-
when nil
|
203
|
-
h[key] = value
|
204
|
-
when Array
|
205
|
-
h[key] << value
|
206
|
-
else
|
207
|
-
h[key]=[h[key], value]
|
208
|
-
end
|
209
|
-
end
|
210
|
-
|
211
|
-
class Version
|
212
|
-
def self.create(v)
|
213
|
-
v.is_a?(self) ? v : self.new(v)
|
214
|
-
end
|
215
|
-
|
216
|
-
include Comparable
|
217
|
-
attr_reader :epoch, :version, :pkgrel
|
218
|
-
def initialize(v)
|
219
|
-
@v=v
|
220
|
-
parse(v)
|
221
|
-
end
|
222
|
-
|
223
|
-
private def parse(v)
|
224
|
-
if v.nil? or v.empty?
|
225
|
-
@epoch=-1 #any version is better than empty version
|
226
|
-
@version=Gem::Version.new(0)
|
227
|
-
@pkgrel=nil
|
228
|
-
return
|
229
|
-
end
|
230
|
-
epoch, rest = v.split(':', 2)
|
231
|
-
if rest.nil?
|
232
|
-
rest=epoch; epoch=0
|
233
|
-
@real_epoch=false
|
234
|
-
else
|
235
|
-
@real_epoch=true
|
236
|
-
end
|
237
|
-
@epoch=epoch
|
238
|
-
version, pkgrel=Utils.rsplit(rest, '-', 2)
|
239
|
-
version.tr!('+_','.')
|
240
|
-
@version=Gem::Version.new(version) rescue Gem::Version.new("0.#{version}")
|
241
|
-
@pkgrel=pkgrel
|
242
|
-
end
|
243
|
-
|
244
|
-
def <=>(w)
|
245
|
-
w=self.class.new(w.to_s)
|
246
|
-
r= @epoch <=> w.epoch
|
247
|
-
if r==0
|
248
|
-
r= @version <=> w.version
|
249
|
-
if r==0 and @pkgrel and w.pkgrel
|
250
|
-
r= @pkgrel <=> w.pkgrel
|
251
|
-
end
|
252
|
-
end
|
253
|
-
r
|
254
|
-
end
|
255
|
-
|
256
|
-
def to_s
|
257
|
-
@v
|
258
|
-
# r=""
|
259
|
-
# r << "#{@epoch}:" if @real_epoch
|
260
|
-
# r << "#{@version}"
|
261
|
-
# r << "-#{@pkgrel}" if @pkgrel
|
262
|
-
# r
|
263
|
-
end
|
264
|
-
|
265
|
-
# strip version information from a package name
|
266
|
-
def self.strip(v)
|
267
|
-
v.sub(/[><=]+[\w.\-+:]*$/,'')
|
268
|
-
end
|
269
|
-
end
|
270
|
-
|
271
|
-
# ex: pacman>=2.0.0
|
272
|
-
QueryError=Class.new(ArchlinuxError)
|
273
|
-
class Query
|
274
|
-
def self.create(v)
|
275
|
-
v.is_a?(self) ? v : self.new(v)
|
276
|
-
end
|
277
|
-
|
278
|
-
def self.strip(query)
|
279
|
-
self.create(query).name
|
280
|
-
end
|
281
|
-
|
282
|
-
include Comparable
|
283
|
-
attr_accessor :name, :op, :version, :op2, :version2
|
284
|
-
def initialize(query)
|
285
|
-
@query=query
|
286
|
-
@name, @op, version, @op2, version2=parse(query)
|
287
|
-
@version=Version.new(version)
|
288
|
-
@version2=Version.new(version2)
|
289
|
-
end
|
290
|
-
|
291
|
-
def to_s
|
292
|
-
@query
|
293
|
-
end
|
294
|
-
|
295
|
-
def max
|
296
|
-
strict=false
|
297
|
-
if @op=='<=' or @op=='='
|
298
|
-
max=@version
|
299
|
-
elsif @op=="<"
|
300
|
-
max=@version; strict=true
|
301
|
-
elsif @op2=="<="
|
302
|
-
max=@version2
|
303
|
-
elsif @op2=="<"
|
304
|
-
max=@version2; strict=true
|
305
|
-
end
|
306
|
-
return max, strict #nil means Float::INFINITY, ie no restriction
|
307
|
-
end
|
308
|
-
|
309
|
-
def min
|
310
|
-
strict=false
|
311
|
-
if @op=='>=' or @op=='='
|
312
|
-
min=@version
|
313
|
-
elsif @op==">"
|
314
|
-
min=@version; strict=true
|
315
|
-
elsif @op2==">="
|
316
|
-
min=@version2
|
317
|
-
elsif @op2==">"
|
318
|
-
min=@version2; strict=true
|
319
|
-
end
|
320
|
-
return min, strict
|
321
|
-
end
|
322
|
-
|
323
|
-
def <=>(other)
|
324
|
-
other=self.class.create(other)
|
325
|
-
min, strict=self.min
|
326
|
-
omin, ostrict=other.min
|
327
|
-
return 1 if min==omin and strict
|
328
|
-
return -1 if min==omin and ostrict
|
329
|
-
min <=> omin
|
330
|
-
end
|
331
|
-
|
332
|
-
# here we check if a package can satisfy a query
|
333
|
-
# note that other can itself be a query, think of a package that
|
334
|
-
# requires foo>=2.0 and bar which provides foo>=3
|
335
|
-
# satisfy? is symmetric, it means that the intersection of the
|
336
|
-
# available version ranges is non empty
|
337
|
-
def satisfy?(other)
|
338
|
-
case other
|
339
|
-
when Version
|
340
|
-
omin=other; omax=other; ominstrict=false; omaxstrict=false
|
341
|
-
oname=@name #we assume the name comparison was already done
|
342
|
-
else
|
343
|
-
other=self.class.create(other)
|
344
|
-
omax, omaxstrict=other.max
|
345
|
-
omin, ominstrict=other.min
|
346
|
-
oname=other.name
|
347
|
-
end
|
348
|
-
return false unless @name==oname
|
349
|
-
min, strict=self.min
|
350
|
-
return false if omax and min and (omax < min or omax == min && (strict or omaxstrict))
|
351
|
-
max, strict=self.max
|
352
|
-
return false if max and omin and (omin > max or omin == max && (strict or ominstrict))
|
353
|
-
true
|
354
|
-
end
|
355
|
-
|
356
|
-
private def parse(query)
|
357
|
-
if (m=query.match(/^([^><=]*)([><=]*)([\w.\-+:]*)([><=]*)([\w.\-+:]*)$/))
|
358
|
-
name=m[1]
|
359
|
-
op=m[2]
|
360
|
-
version=m[3]
|
361
|
-
op2=m[4]
|
362
|
-
version2=m[5]
|
363
|
-
if op.nil?
|
364
|
-
name, version=Utils.rsplit(name, '-', 2)
|
365
|
-
op="="; op2=nil; version2=nil
|
366
|
-
end
|
367
|
-
return name, op, version, op2, version2
|
368
|
-
else
|
369
|
-
raise QueryError.new("Bad query #{query}")
|
370
|
-
end
|
371
|
-
end
|
372
|
-
end
|
373
|
-
|
374
|
-
module AurQuery
|
375
|
-
extend self
|
376
|
-
attr_accessor :config
|
377
|
-
@config=Archlinux.config
|
378
|
-
|
379
|
-
AurQueryError=Class.new(ArchlinuxError)
|
380
|
-
|
381
|
-
# AurQuery.query(type: "info", arg: pacaur)
|
382
|
-
# AurQuery.query(type: "info", :"arg[]" => %w(cower pacaur))
|
383
|
-
# AurQuery.query(type: "search", by: "name", arg: "aur")
|
384
|
-
# by name (search by package name only)
|
385
|
-
# *name-desc* (search by package name and description)
|
386
|
-
# maintainer (search by package maintainer)
|
387
|
-
# depends (search for packages that depend on keywords)
|
388
|
-
# makedepends (search for packages that makedepend on keywords)
|
389
|
-
# optdepends (search for packages that optdepend on keywords)
|
390
|
-
# checkdepends (search for packages that checkdepend on keywords)
|
391
|
-
# => search result:
|
392
|
-
# {"ID"=>514909,
|
393
|
-
# "Name"=>"pacaur",
|
394
|
-
# "PackageBaseID"=>49145,
|
395
|
-
# "PackageBase"=>"pacaur",
|
396
|
-
# "Version"=>"4.7.90-1",
|
397
|
-
# "Description"=>"An AUR helper that minimizes user interaction",
|
398
|
-
# "URL"=>"https://github.com/rmarquis/pacaur",
|
399
|
-
# "NumVotes"=>1107,
|
400
|
-
# "Popularity"=>7.382043,
|
401
|
-
# "OutOfDate"=>nil,
|
402
|
-
# "Maintainer"=>"Spyhawk",
|
403
|
-
# "FirstSubmitted"=>1305666963,
|
404
|
-
# "LastModified"=>1527690065,
|
405
|
-
# "URLPath"=>"/cgit/aur.git/snapshot/pacaur.tar.gz"},
|
406
|
-
# => info result adds:
|
407
|
-
# "Depends"=>["cower", "expac", "sudo", "git"],
|
408
|
-
# "MakeDepends"=>["perl"],
|
409
|
-
# "License"=>["ISC"],
|
410
|
-
# "Keywords"=>["AUR", "helper", "wrapper"]}]
|
411
|
-
|
412
|
-
def query(h)
|
413
|
-
uri=URI("#{@config[:aur_url]}/rpc/")
|
414
|
-
params = {v:5}.merge(h)
|
415
|
-
uri.query = URI.encode_www_form(params)
|
416
|
-
res = Net::HTTP.get_response(uri)
|
417
|
-
if res.is_a?(Net::HTTPSuccess)
|
418
|
-
r= res.body
|
419
|
-
else
|
420
|
-
raise AurQueryError.new("AUR: Got error response for query #{h}")
|
421
|
-
end
|
422
|
-
data = JSON.parse(r)
|
423
|
-
case data['type']
|
424
|
-
when 'error'
|
425
|
-
raise AurQueryError.new("Error: #{data['results']}")
|
426
|
-
when 'search','info','multiinfo'
|
427
|
-
return data['results']
|
428
|
-
else
|
429
|
-
raise AurQueryError.new("Error in response data #{data}")
|
430
|
-
end
|
431
|
-
end
|
432
|
-
|
433
|
-
# Outdated packages: Aur.search(nil, by: "maintainer")
|
434
|
-
def search(arg, by: nil)
|
435
|
-
r={type: "search", arg: arg}
|
436
|
-
r[:by]=by if by
|
437
|
-
# if :by is not specified, aur defaults to name-desc
|
438
|
-
self.query(r)
|
439
|
-
end
|
440
|
-
|
441
|
-
def infos(*pkgs, slice: 150)
|
442
|
-
search=[]
|
443
|
-
pkgs.each_slice(slice) do |pkgs_slice|
|
444
|
-
r={type: "info", :"arg[]" => pkgs_slice}
|
445
|
-
search+=self.query(r)
|
446
|
-
end
|
447
|
-
search.each { |pkg| pkg[:repo]=:aur }
|
448
|
-
search
|
449
|
-
end
|
450
|
-
|
451
|
-
# try to use infos if possible
|
452
|
-
def info(pkg)
|
453
|
-
r={type: "info", arg: pkg}
|
454
|
-
self.query(r).first
|
455
|
-
end
|
456
|
-
|
457
|
-
def packages(*pkgs, klass: AurPackageList)
|
458
|
-
klass.new(infos(*pkgs))
|
459
|
-
end
|
460
|
-
|
461
|
-
def pkglist(type="packages", delay: 3600, query: :auto) #type=pkgbase
|
462
|
-
require 'zlib'
|
463
|
-
cache=self.cachedir
|
464
|
-
file=cache+"#{type}.gz"
|
465
|
-
in_epoch=nil
|
466
|
-
if file.exist?
|
467
|
-
# intime=file.read.each_line.first
|
468
|
-
file.open do |io|
|
469
|
-
Zlib::GzipReader.wrap(io) do |gz|
|
470
|
-
intime=gz.each_line.first
|
471
|
-
intime.match(/^# AUR package list, generated on (.*)/) do |m|
|
472
|
-
in_epoch=Time.parse(m[1]).to_i
|
473
|
-
end
|
474
|
-
end
|
475
|
-
end
|
476
|
-
end
|
477
|
-
if query
|
478
|
-
Net::HTTP.get_response(URI("#{@config[:aur_url]}/#{type}.gz")) do |res|
|
479
|
-
date=res["date"]
|
480
|
-
update=true
|
481
|
-
if date
|
482
|
-
epoch=Time.parse(date).to_i
|
483
|
-
update=false if epoch and in_epoch and (epoch-in_epoch < delay) and !query==true
|
484
|
-
end
|
485
|
-
if update
|
486
|
-
file.open('w') do |io|
|
487
|
-
Zlib::GzipWriter.wrap(io) do |gz|
|
488
|
-
res.read_body(gz)
|
489
|
-
end
|
490
|
-
end
|
491
|
-
end
|
492
|
-
end
|
493
|
-
end
|
494
|
-
file.open do |io|
|
495
|
-
Zlib::GzipReader.wrap(io) do |gz|
|
496
|
-
return gz.each_line.map(&:chomp).drop(1)
|
497
|
-
end
|
498
|
-
end
|
499
|
-
end
|
500
|
-
end
|
501
|
-
|
502
|
-
class DB
|
503
|
-
def self.create(v)
|
504
|
-
v.is_a?(self) ? v : self.new(v)
|
505
|
-
end
|
506
|
-
|
507
|
-
def self.db_file?(name)
|
508
|
-
case name
|
509
|
-
when Pathname
|
510
|
-
true
|
511
|
-
when String
|
512
|
-
if name.include?('/') or name.match(/\.db(\..*)?$/)
|
513
|
-
true
|
514
|
-
else
|
515
|
-
false #Usually we assume this is a repo name
|
516
|
-
end
|
517
|
-
end
|
518
|
-
end
|
519
|
-
|
520
|
-
attr_accessor :file, :config
|
521
|
-
def initialize(file, config: Archlinux.config)
|
522
|
-
@file=Pathname.new(file)
|
523
|
-
@config=config
|
524
|
-
end
|
525
|
-
|
526
|
-
def mkpath
|
527
|
-
@file.dirname.mkpath
|
528
|
-
end
|
529
|
-
|
530
|
-
def path
|
531
|
-
if file.exist?
|
532
|
-
file.realpath
|
533
|
-
else
|
534
|
-
file
|
535
|
-
end
|
536
|
-
end
|
537
|
-
|
538
|
-
def repo_name
|
539
|
-
@file.basename.to_s.sub(/\.db(\..*)?$/,'')
|
540
|
-
end
|
541
|
-
|
542
|
-
def create
|
543
|
-
mkpath
|
544
|
-
unless @file.exist?
|
545
|
-
call(:'repo-add', path.shellescape)
|
546
|
-
end
|
547
|
-
self
|
548
|
-
end
|
549
|
-
|
550
|
-
def to_s
|
551
|
-
@file.to_s
|
552
|
-
end
|
553
|
-
|
554
|
-
# a db is a tar.gz archive of packages/desc, like yay-8.998-1/descr
|
555
|
-
def list
|
556
|
-
require 'dr/sh'
|
557
|
-
res= SH.run_simple("bsdcat #{@file.shellescape}", chomp: :lines) {return nil}
|
558
|
-
list=[]; pkg={}; mode=nil
|
559
|
-
flush = lambda do
|
560
|
-
# catch old deps files which don't specify the full infos
|
561
|
-
unless pkg[:name].nil? and pkg[:base].nil?
|
562
|
-
pkg[:repo]||=path
|
563
|
-
list << pkg
|
564
|
-
end
|
565
|
-
end
|
566
|
-
res.each do |l|
|
567
|
-
next if l.empty? or l.match(/^\u0000*$/)
|
568
|
-
if (m=l.match(/(\u0000+.*\u0000+)?%([A-Z0-9]*)%$/))
|
569
|
-
mode=m[2].downcase.to_sym
|
570
|
-
if m[1] #new db entry
|
571
|
-
flush.call #store old db entry
|
572
|
-
pkg={}
|
573
|
-
end
|
574
|
-
else
|
575
|
-
l=l.to_i if mode==:csize or mode==:isize
|
576
|
-
l=Time.at(l.to_i) if mode==:builddate
|
577
|
-
Archlinux.add_to_hash(pkg, mode, l)
|
578
|
-
end
|
579
|
-
end
|
580
|
-
flush.call #don't forget the last one
|
581
|
-
list
|
582
|
-
end
|
583
|
-
|
584
|
-
def files(absolute=true)
|
585
|
-
list.map do |pkg|
|
586
|
-
file=Pathname.new(pkg[:filename])
|
587
|
-
absolute ? dir + file : file
|
588
|
-
end
|
589
|
-
end
|
590
|
-
# def files
|
591
|
-
# packages.l.map {|pkg| dir+Pathname.new(pkg[:filename])}
|
592
|
-
# end
|
593
|
-
|
594
|
-
def dir
|
595
|
-
@file.dirname.realpath
|
596
|
-
end
|
597
|
-
|
598
|
-
def call(*args)
|
599
|
-
@config.launch(*args) do |*args|
|
600
|
-
dir.chdir do
|
601
|
-
SH.sh(*args)
|
602
|
-
end
|
603
|
-
end
|
604
|
-
end
|
605
|
-
|
606
|
-
def move_to_db(*files, op: :mv)
|
607
|
-
files=files.map {|f| Pathname.new(f).realpath}
|
608
|
-
dir=self.dir
|
609
|
-
files.map do |f|
|
610
|
-
if f.dirname == dir
|
611
|
-
f
|
612
|
-
else
|
613
|
-
new=dir+f.basename
|
614
|
-
f.send(op, new)
|
615
|
-
new
|
616
|
-
end
|
617
|
-
end
|
618
|
-
files
|
619
|
-
end
|
620
|
-
|
621
|
-
def add(*files, cmd: :'repo-add', default_opts:[], sign: @config.sign(:repo), **opts)
|
622
|
-
default_opts+=['-s', '-v'] if sign
|
623
|
-
default_opts+=['--key', sign] if sign.is_a?(String)
|
624
|
-
unless files.empty?
|
625
|
-
call(cmd, path.shellescape, *files, default_opts: default_opts, **opts)
|
626
|
-
end
|
627
|
-
end
|
628
|
-
|
629
|
-
def remove(*args, **opts)
|
630
|
-
add(*args, cmd: :'repo-remove', **opts)
|
631
|
-
end
|
632
|
-
|
633
|
-
def packages(refresh=false)
|
634
|
-
@packages=nil if refresh
|
635
|
-
@packages||=PackageList.new(list)
|
636
|
-
end
|
637
|
-
|
638
|
-
def dir_packages
|
639
|
-
PackageFiles.from_dir(dir).packages
|
640
|
-
end
|
641
|
-
|
642
|
-
def package_files
|
643
|
-
PackageFiles.new(*files).packages
|
644
|
-
end
|
645
|
-
|
646
|
-
def check
|
647
|
-
packages.same?(package_files)
|
648
|
-
end
|
649
|
-
|
650
|
-
def check_update(other=dir_packages)
|
651
|
-
up=self.packages.check_updates(other)
|
652
|
-
refresh=up.select {|_k, u| u[:op]==:upgrade or u[:op]==:downgrade}
|
653
|
-
add=up.select {|_k, u| u[:op]==:install}
|
654
|
-
remove=up.select {|_k, u| u[:op]==:obsolete}
|
655
|
-
return {refresh: refresh, add: add, remove: remove}
|
656
|
-
end
|
657
|
-
|
658
|
-
def update(other=dir_packages)
|
659
|
-
r=check_update(other)
|
660
|
-
add(*(r[:refresh].merge(r[:add])).map {|_k,v| other[v[:out_pkg]].file.shellescape})
|
661
|
-
# remove(*(r[:remove].map {|_k,v| packages[v[:in_pkg]].file.shellescape}))
|
662
|
-
remove(*(r[:remove].map {|_k,v| Query.strip(v[:in_pkg])}))
|
663
|
-
r
|
664
|
-
end
|
665
|
-
end
|
666
|
-
|
667
|
-
class Repo
|
668
|
-
def self.create(v)
|
669
|
-
v.is_a?(self) ? v : self.new(v)
|
670
|
-
end
|
671
|
-
|
672
|
-
def initialize(name)
|
673
|
-
@repo=name
|
674
|
-
end
|
675
|
-
|
676
|
-
def list(mode: :pacsift)
|
677
|
-
command= case mode
|
678
|
-
when :pacman
|
679
|
-
"pacman -Slq #{@repo.shellescape}" #returns pkg
|
680
|
-
when :pacsift
|
681
|
-
"pacsift --exact --repo=#{@repo.shellescape} <&-" #returns repo/pkg
|
682
|
-
when :paclist
|
683
|
-
"paclist #{@repo.shellescape}" #returns pkg version
|
684
|
-
end
|
685
|
-
SH.run_simple(command, chomp: :lines) {return nil}
|
686
|
-
end
|
687
|
-
|
688
|
-
def packages(refresh=false)
|
689
|
-
@packages=nil if refresh
|
690
|
-
@packages ||= PackageList.new(self.class.info(*list))
|
691
|
-
end
|
692
|
-
|
693
|
-
def self.pacman_info(*pkgs, local: false) #local=true refers to the local db info
|
694
|
-
list=[]
|
695
|
-
to_list=lambda do |s|
|
696
|
-
return [] if s=="None"
|
697
|
-
s.split
|
698
|
-
end
|
699
|
-
# Note: core/pacman only works for -Sddp or -Si, not for -Qi
|
700
|
-
# Indeed local/pacman works for pacinfo, but not for pacman (needs
|
701
|
-
# the -Q options)
|
702
|
-
res=SH.run_simple({'COLUMNS' => '1000'}, "pacman -#{local ? 'Q': 'S'}i #{pkgs.shelljoin}", chomp: :lines)
|
703
|
-
key=nil; info={}
|
704
|
-
res.each do |l|
|
705
|
-
if key==:optional_deps and (m=l.match(/^\s+(\w*):\s+(.*)$/))
|
706
|
-
#here we cannot split(':') because we need to check for the leading space
|
707
|
-
info[key][m[1]]=m[2]
|
708
|
-
else
|
709
|
-
key, value=l.split(/\s*:\s*/,2)
|
710
|
-
if key.nil? #new package
|
711
|
-
list << info; key=nil; info={}
|
712
|
-
next
|
713
|
-
end
|
714
|
-
key=key.strip.downcase.gsub(' ', '_').to_sym
|
715
|
-
case key
|
716
|
-
when :optional_deps
|
717
|
-
dep, reason=value.split(/\s*:\s*/,2)
|
718
|
-
value={dep => reason}
|
719
|
-
when :groups, :provides, :depends_on, :required_by, :optional_for, :conflicts_with, :replaces
|
720
|
-
value=to_list.call(value)
|
721
|
-
when :install_script
|
722
|
-
value=false if value=="No"
|
723
|
-
value=true if value=="Yes"
|
724
|
-
when :install_date, :build_date
|
725
|
-
value=Time.parse(value)
|
726
|
-
end
|
727
|
-
info[key]=value
|
728
|
-
end
|
729
|
-
end
|
730
|
-
# no need to add the last info, pacman -Q/Si always end with a new line
|
731
|
-
list
|
732
|
-
end
|
733
|
-
|
734
|
-
def self.pacinfo(*pkgs) #this refers to the local db info
|
735
|
-
list=[]; info={}
|
736
|
-
res=SH.run_simple("pacinfo #{pkgs.shelljoin}", chomp: :lines)
|
737
|
-
res.each do |l|
|
738
|
-
key, value=l.split(/\s*:\s*/,2)
|
739
|
-
if key.nil? #next package
|
740
|
-
list << info; info={}
|
741
|
-
next
|
742
|
-
end
|
743
|
-
key=key.downcase.gsub(' ', '_').to_sym
|
744
|
-
case key
|
745
|
-
when :install_script
|
746
|
-
value=false if value=="No"
|
747
|
-
value=true if value=="Yes"
|
748
|
-
when :install_date, :build_date
|
749
|
-
value=Time.parse(value)
|
750
|
-
end
|
751
|
-
Archlinux.add_to_hash(info, key, value)
|
752
|
-
end
|
753
|
-
# no need to add at the end, pacinfo always end with a new line
|
754
|
-
list
|
755
|
-
end
|
756
|
-
|
757
|
-
def self.info(*packages)
|
758
|
-
if SH.find_executable("pacinfo")
|
759
|
-
pacinfo(*packages)
|
760
|
-
else
|
761
|
-
pacman_info(*packages)
|
762
|
-
end
|
763
|
-
end
|
764
|
-
|
765
|
-
def self.packages(*packages)
|
766
|
-
PackageList.new(info(*packages))
|
767
|
-
end
|
768
|
-
end
|
769
|
-
|
770
|
-
class PackageFiles
|
771
|
-
def self.create(v)
|
772
|
-
v.is_a?(self) ? v : self.new(v)
|
773
|
-
end
|
774
|
-
|
775
|
-
attr_accessor :files
|
776
|
-
def initialize(*files)
|
777
|
-
@files=files.map {|file| DR::Pathname.new(file)}
|
778
|
-
end
|
779
|
-
|
780
|
-
def infos(slice=200) #the command line should not be too long
|
781
|
-
format={
|
782
|
-
filename: "%f",
|
783
|
-
pkgname: "%n",
|
784
|
-
pkgbase: "%e",
|
785
|
-
version: "%v",
|
786
|
-
url: "%u",
|
787
|
-
description: "%d",
|
788
|
-
packager: "%p",
|
789
|
-
architecture: "%a",
|
790
|
-
build_date: "%b",
|
791
|
-
download_size: "%k",
|
792
|
-
install_size: "%m",
|
793
|
-
depends: "%D",
|
794
|
-
conflicts: "%H",
|
795
|
-
opt_depends: "%O",
|
796
|
-
provides: "%P",
|
797
|
-
replaces: "%T",
|
798
|
-
# format << "%r\n" #repo
|
799
|
-
}
|
800
|
-
total=format.keys.count
|
801
|
-
r=[]; delim=" , "
|
802
|
-
split=lambda do |l| l.split(delim) end
|
803
|
-
@files.each_slice(slice) do |files|
|
804
|
-
SH.run_simple("expac --timefmt=%s #{format.values.join("\n").shellescape} -l #{delim.shellescape} -p #{files.shelljoin}", chomp: :lines).each_slice(total).with_index do |l,i|
|
805
|
-
info={}
|
806
|
-
format.keys.each_with_index do |k, kk|
|
807
|
-
value=l[kk]
|
808
|
-
value=split[value] if %i(depends conflicts opt_depends provides replaces).include?(k)
|
809
|
-
value=nil if k==:pkgbase and value=="(null)"
|
810
|
-
value=Time.at(value.to_i) if k==:build_date
|
811
|
-
value=value.to_i if k==:download_size or k==:install_size
|
812
|
-
info[k]=value if value
|
813
|
-
end
|
814
|
-
info[:repo]=files[i]
|
815
|
-
r<<info
|
816
|
-
end
|
817
|
-
end
|
818
|
-
r
|
819
|
-
end
|
820
|
-
|
821
|
-
def packages(refresh=false)
|
822
|
-
@packages=nil if refresh
|
823
|
-
@packages ||= PackageList.new(self.infos)
|
824
|
-
end
|
825
|
-
|
826
|
-
def self.from_dir(dir)
|
827
|
-
dir=Pathname.new(dir)
|
828
|
-
self.new(*dir.glob('*.pkg.*').map {|g| next if g.to_s.end_with?('~') or g.to_s.end_with?('.sig'); f=dir+g; next unless f.readable?; f}.compact)
|
829
|
-
end
|
830
|
-
end
|
831
|
-
|
832
|
-
class Makepkg
|
833
|
-
def self.create(v)
|
834
|
-
v.is_a?(self) ? v : self.new(v)
|
835
|
-
end
|
836
|
-
|
837
|
-
attr_accessor :dir, :base, :env, :config, :asdeps
|
838
|
-
|
839
|
-
def initialize(dir, config: Archlinux.config, env: {}, asdeps: false)
|
840
|
-
@dir=DR::Pathname.new(dir)
|
841
|
-
@base=@dir.basename
|
842
|
-
@config=config
|
843
|
-
@env=env
|
844
|
-
@asdeps=asdeps
|
845
|
-
db=@config.db
|
846
|
-
@env['PKGDEST']=db.dir.to_s if db
|
847
|
-
end
|
848
|
-
|
849
|
-
def name
|
850
|
-
@base.to_s
|
851
|
-
end
|
852
|
-
|
853
|
-
def call(*args, run: :run_simple, **opts)
|
854
|
-
@config.launch(:makepkg, *args, **opts) do |*args, **opts|
|
855
|
-
@dir.chdir do
|
856
|
-
SH.public_send(run, @env, *args, **opts)
|
857
|
-
end
|
858
|
-
end
|
859
|
-
end
|
860
|
-
|
861
|
-
def info
|
862
|
-
stdin=call("--printsrcinfo", chomp: :lines)
|
863
|
-
mode=nil; r={}; current={}; pkgbase=nil; pkgname=nil
|
864
|
-
stdin.each do |l|
|
865
|
-
key, value=l.split(/\s*=\s*/,2)
|
866
|
-
next if key.nil?
|
867
|
-
if key=="pkgbase"
|
868
|
-
mode=:pkgbase; current[:pkgbase]=value
|
869
|
-
elsif key=="pkgname"
|
870
|
-
if mode==:pkgbase
|
871
|
-
r=current
|
872
|
-
r[:pkgs]={repo: @dir}
|
873
|
-
else
|
874
|
-
r[:pkgs][pkgname]=current
|
875
|
-
end
|
876
|
-
current={}; mode=:pkgname; pkgname=value
|
877
|
-
else
|
878
|
-
key=key.strip.to_sym
|
879
|
-
Archlinux.add_to_hash(current, key, value)
|
880
|
-
end
|
881
|
-
end
|
882
|
-
r[:pkgs][pkgname]=current #don't forget to update the last one
|
883
|
-
r
|
884
|
-
end
|
885
|
-
|
886
|
-
def packages(refresh=false)
|
887
|
-
@packages=nil if refresh
|
888
|
-
unless @packages
|
889
|
-
r=info
|
890
|
-
pkgs=r.delete(:pkgs)
|
891
|
-
r[:pkgbase]
|
892
|
-
base=Package.new(r)
|
893
|
-
list=pkgs.map do |name, pkg|
|
894
|
-
pkg[:name]=name
|
895
|
-
Package.new(pkg).merge(base)
|
896
|
-
end
|
897
|
-
@packages=PackageList.new(list)
|
898
|
-
end
|
899
|
-
@packages
|
900
|
-
end
|
901
|
-
|
902
|
-
def url
|
903
|
-
@config[:aur_url]+@base.to_s+".git"
|
904
|
-
end
|
905
|
-
|
906
|
-
def get(logdir: nil, view: false)
|
907
|
-
#SH.sh("vcs clone_or_update --diff #{url.shellescape} #{@dir.shellescape}")
|
908
|
-
if logdir
|
909
|
-
logdir=DR::Pathname.new(logdir)
|
910
|
-
logdir.mkpath
|
911
|
-
end
|
912
|
-
if @dir.exist?
|
913
|
-
# TODO: what if @dir exist but is not a git directory?
|
914
|
-
@dir.chdir do
|
915
|
-
unless @config.git_update
|
916
|
-
SH.logger.error("Error in updating #{@dir}")
|
917
|
-
end
|
918
|
-
if logdir
|
919
|
-
SH::VirtualFile.new("orderfile", "PKGBUILD").create(true) do |tmp|
|
920
|
-
patch=SH.run_simple("git diff -O#{tmp} HEAD@{1}")
|
921
|
-
(logdir+"#{@dir.basename}.patch").write(patch) unless patch.empty?
|
922
|
-
(logdir+"#{@dir.basename}").on_ln_s(@dir.realpath, rm: :symlink)
|
923
|
-
end
|
924
|
-
end
|
925
|
-
end
|
926
|
-
else
|
927
|
-
unless @config.git_clone(url, @dir)
|
928
|
-
SH.logger.error("Error in cloning #{url} to #{@dir}")
|
929
|
-
end
|
930
|
-
SH.sh("git clone #{url.shellescape} #{@dir.shellescape}")
|
931
|
-
if logdir
|
932
|
-
(logdir+"!#{@dir.basename}").on_ln_s(@dir.realpath)
|
933
|
-
end
|
934
|
-
end
|
935
|
-
if view
|
936
|
-
return @config.view(@dir)
|
937
|
-
else
|
938
|
-
return true
|
939
|
-
end
|
940
|
-
end
|
941
|
-
|
942
|
-
# raw call to makepkg
|
943
|
-
def makepkg(*args, **opts)
|
944
|
-
call(*args, run: :sh, **opts)
|
945
|
-
end
|
946
|
-
|
947
|
-
def make(*args, sign: config.sign(:makepkg), default_opts: [], force: false, asdeps: @asdeps, **opts)
|
948
|
-
default_opts << "--sign" if sign
|
949
|
-
default_opts << "--key=#{sign}" if sign.is_a?(String)
|
950
|
-
default_opts << "--force" if force
|
951
|
-
default_opts << "--asdeps" if asdeps
|
952
|
-
|
953
|
-
tools=@config.makepkg_config #this set up pacman and makepkg config files
|
954
|
-
success=false
|
955
|
-
@dir.chdir do
|
956
|
-
success=tools.makepkg(*args, default_opts: default_opts, env: @env, **opts)
|
957
|
-
end
|
958
|
-
success
|
959
|
-
end
|
960
|
-
|
961
|
-
def mkarchroot
|
962
|
-
@config.devtools.mkarchroot("base-devel")
|
963
|
-
end
|
964
|
-
|
965
|
-
def makechroot(*args, sign: @config.sign(:makechrootpkg), force: false, **opts)
|
966
|
-
unless force
|
967
|
-
if list.all? {|f| f.exist?}
|
968
|
-
SH.logger.info "Skipping #{@dir} since it is already built (use force=trye to override)"
|
969
|
-
return false
|
970
|
-
end
|
971
|
-
end
|
972
|
-
devtools=@config.devtools
|
973
|
-
success=false
|
974
|
-
@dir.chdir do
|
975
|
-
success=devtools.makechrootpkg(*args, env: @env, **opts)
|
976
|
-
end
|
977
|
-
self.sign(sign) if sign and success
|
978
|
-
success
|
979
|
-
end
|
980
|
-
|
981
|
-
def add_to_db(db=@config.db)
|
982
|
-
SH.logger.warn "Bad database #{db}" unless db.is_a?(DB)
|
983
|
-
db.add(*list.select {|l| l.exist?})
|
984
|
-
end
|
985
|
-
|
986
|
-
def build(*makepkg_args, mkarchroot: false, chroot: @config[:build_chroot], **opts)
|
987
|
-
SH.logger.info "=> Building #{@dir}"
|
988
|
-
if chroot
|
989
|
-
self.mkarchroot if mkarchroot
|
990
|
-
success, _r=makechroot(*makepkg_args, **opts)
|
991
|
-
else
|
992
|
-
success, _r=make(*makepkg_args, **opts)
|
993
|
-
end
|
994
|
-
if success and (db=@config.db)
|
995
|
-
add_to_db(db)
|
996
|
-
if !chroot #sync db
|
997
|
-
tools=@config.makepkg_config
|
998
|
-
tools.sync_db(db.repo_name)
|
999
|
-
end
|
1000
|
-
end
|
1001
|
-
end
|
1002
|
-
|
1003
|
-
def install(*args, view: true, **opts)
|
1004
|
-
r=get(view: view)
|
1005
|
-
build(*args, **opts) if r
|
1006
|
-
end
|
1007
|
-
|
1008
|
-
def list(**opts)
|
1009
|
-
call("--packagelist", chomp: :lines, err: "/dev/null", **opts).map {|f| Pathname.new(f)}
|
1010
|
-
end
|
1011
|
-
|
1012
|
-
def sign(sign, **opts)
|
1013
|
-
list(**opts).each do |pkg|
|
1014
|
-
if pkg.file?
|
1015
|
-
if (sig=Pathname.new("#{pkg}.sig")).file?
|
1016
|
-
SH.logger.warn "Signature #{sig} already exits, skipping"
|
1017
|
-
else
|
1018
|
-
SH.sh("gpg #{sign.is_a?(String) ? "-u #{sign}" : ""} --detach-sign --no-armor #{pkg.shellescape}")
|
1019
|
-
end
|
1020
|
-
end
|
1021
|
-
end
|
1022
|
-
end
|
1023
|
-
|
1024
|
-
end
|
1025
|
-
|
1026
|
-
class MakepkgList
|
1027
|
-
def self.create(v)
|
1028
|
-
v.is_a?(self) ? v : self.new(v)
|
1029
|
-
end
|
1030
|
-
|
1031
|
-
Archlinux.delegate_h(self, :@l)
|
1032
|
-
attr_accessor :config, :cache, :l
|
1033
|
-
|
1034
|
-
def initialize(l, config: Archlinux.config, cache: config.cachedir)
|
1035
|
-
@config=config
|
1036
|
-
@cache=Pathname.new(cache)
|
1037
|
-
@l={}
|
1038
|
-
l.each do |m|
|
1039
|
-
unless m.is_a?(Makepkg)
|
1040
|
-
m=Pathname.new(m)
|
1041
|
-
m = @cache+m if m.relative?
|
1042
|
-
v=Makepkg.new(m, config: @config)
|
1043
|
-
@l[v.name]=v
|
1044
|
-
end
|
1045
|
-
end
|
1046
|
-
end
|
1047
|
-
|
1048
|
-
def packages(refresh=false)
|
1049
|
-
@packages = nil if refresh
|
1050
|
-
@packages ||= @l.values.reduce do |list, makepkg|
|
1051
|
-
list.merge(makepkg.packages)
|
1052
|
-
end
|
1053
|
-
end
|
1054
|
-
|
1055
|
-
def get(*args, view: true)
|
1056
|
-
Dir.mktmpdir("aur_view") do |d|
|
1057
|
-
@l.values.each do |l|
|
1058
|
-
l.get(*args, logdir: d)
|
1059
|
-
end
|
1060
|
-
if view
|
1061
|
-
return @config.view(d)
|
1062
|
-
else
|
1063
|
-
return true
|
1064
|
-
end
|
1065
|
-
end
|
1066
|
-
end
|
1067
|
-
|
1068
|
-
def make(*args)
|
1069
|
-
@l.values.each do |l|
|
1070
|
-
l.make(*args)
|
1071
|
-
end
|
1072
|
-
end
|
1073
|
-
|
1074
|
-
def makechroot(*args)
|
1075
|
-
@l.values.each do |l|
|
1076
|
-
l.makechroot(*args)
|
1077
|
-
end
|
1078
|
-
end
|
1079
|
-
|
1080
|
-
def mkarchroot
|
1081
|
-
@config.devtools.mkarchroot("base-devel")
|
1082
|
-
end
|
1083
|
-
|
1084
|
-
def list
|
1085
|
-
@l.values.flat_map { |l| l.list }
|
1086
|
-
end
|
1087
|
-
|
1088
|
-
def add_to_db(db=@config.db)
|
1089
|
-
SH.logger.warn "Bad database #{db}" unless db.is_a?(DB)
|
1090
|
-
db.add(*list.select {|l| l.exist?})
|
1091
|
-
end
|
1092
|
-
|
1093
|
-
def build(*args, chroot: @config[:build_chroot], **opts)
|
1094
|
-
mkarchroot if chroot
|
1095
|
-
@l.values.each do |l|
|
1096
|
-
l.build(*args, chroot: chroot, **opts)
|
1097
|
-
end
|
1098
|
-
end
|
1099
|
-
|
1100
|
-
def install(*args, view: true, **opts)
|
1101
|
-
r=get(view: view)
|
1102
|
-
build(*args, **opts) if r
|
1103
|
-
end
|
1104
|
-
end
|
1105
|
-
|
1106
|
-
PackageError=Class.new(ArchlinuxError)
|
1107
|
-
class Package
|
1108
|
-
def self.create(v)
|
1109
|
-
v.is_a?(self) ? v : self.new(v)
|
1110
|
-
end
|
1111
|
-
|
1112
|
-
Archlinux.delegate_h(self, :@props)
|
1113
|
-
attr_reader :name, :props
|
1114
|
-
|
1115
|
-
def initialize(*args)
|
1116
|
-
case args.length
|
1117
|
-
when 2
|
1118
|
-
name, props=args
|
1119
|
-
when 1
|
1120
|
-
props=args.first
|
1121
|
-
name=nil
|
1122
|
-
else
|
1123
|
-
raise PackageError.new("Error the number of arguments should be 1 or 2")
|
1124
|
-
end
|
1125
|
-
@name=name
|
1126
|
-
@props={}
|
1127
|
-
self.props=(props)
|
1128
|
-
@name=@props[:name] || @props[:pkgname] || @props[:pkgbase] unless @name
|
1129
|
-
end
|
1130
|
-
|
1131
|
-
def props=(props)
|
1132
|
-
[:groups, :depends, :make_depends, :check_depends, :conflicts, :replaces, :provides, :depends_for, :opt_depends_for].each do |k|
|
1133
|
-
props.key?(k) or @props[k]=[]
|
1134
|
-
end
|
1135
|
-
@props[:opt_depends]||={}
|
1136
|
-
props.each do |k,v|
|
1137
|
-
k=Utils.to_snake_case(k.to_s).to_sym
|
1138
|
-
k=:opt_depends if k==:optdepends || k==:optional_deps
|
1139
|
-
k=:make_depends if k==:makedepends
|
1140
|
-
k=:check_depends if k==:checkdepends
|
1141
|
-
k=:build_date if k==:checkdepends
|
1142
|
-
k=:depends if k==:depends_on or k==:requires
|
1143
|
-
k=:conflicts if k==:conflicts_with
|
1144
|
-
k=:pkgbase if k==:base
|
1145
|
-
k=:depends_for if k==:required_by
|
1146
|
-
k=:opt_depends_for if k==:optional_for
|
1147
|
-
k=:description if k==:desc
|
1148
|
-
case k
|
1149
|
-
when :first_submitted, :last_modified, :out_of_date, :build_date, :install_date
|
1150
|
-
if v and !v.is_a?(Time)
|
1151
|
-
v= v.is_a?(Integer) ? Time.at(v) : Time.parse(v)
|
1152
|
-
end
|
1153
|
-
when :repository, :groups, :depends, :make_depends, :check_depends, :conflicts, :replaces, :provides, :depends_for, :opt_depends_for
|
1154
|
-
v=Array(v)
|
1155
|
-
when :opt_depends
|
1156
|
-
unless v.is_a?(Hash)
|
1157
|
-
w={}
|
1158
|
-
Array(v).each do |l|
|
1159
|
-
l.match(/(\w*)\s+:\s+(.*)/) do |m|
|
1160
|
-
w[m[1]]=m[2]
|
1161
|
-
end
|
1162
|
-
end
|
1163
|
-
v=w
|
1164
|
-
end
|
1165
|
-
end
|
1166
|
-
@props[k]=v
|
1167
|
-
end
|
1168
|
-
end
|
1169
|
-
|
1170
|
-
def merge(h)
|
1171
|
-
h.each do |k,v|
|
1172
|
-
if @props[k].nil? or ((k==:package_size or k==:download_size or k==:installed_size) and (@props[k]=="0.00 B" or @props[k]==0))
|
1173
|
-
@props[k]=v
|
1174
|
-
elsif k==:repository
|
1175
|
-
@props[k]=(Array(@props[k])+v).uniq
|
1176
|
-
end
|
1177
|
-
end
|
1178
|
-
self
|
1179
|
-
end
|
1180
|
-
|
1181
|
-
def dependencies(l=%i(depends))
|
1182
|
-
l.map {|i| a=@props[i]; a.is_a?(Hash) ? a.keys : Array(a)}.flatten.uniq
|
1183
|
-
end
|
1184
|
-
|
1185
|
-
def version
|
1186
|
-
Version.new(@props[:version])
|
1187
|
-
end
|
1188
|
-
|
1189
|
-
def name_version
|
1190
|
-
r=self.name
|
1191
|
-
version=self.version
|
1192
|
-
r+="="+version.to_s if version
|
1193
|
-
r
|
1194
|
-
end
|
1195
|
-
|
1196
|
-
def file
|
1197
|
-
Pathname.new(@props[:filename])
|
1198
|
-
end
|
1199
|
-
|
1200
|
-
def same?(other)
|
1201
|
-
# @props.slice(*(@props.keys - [:repo])) == other.props.slice(*(other.props.keys - [:repo]))
|
1202
|
-
slice=%i(version description depends provides opt_depends replaces conflicts)
|
1203
|
-
# p name, other.name, @props.slice(*slice), other.props.slice(*slice)
|
1204
|
-
name == other.name && @props.slice(*slice) == other.props.slice(*slice)
|
1205
|
-
end
|
1206
|
-
end
|
1207
|
-
|
1208
|
-
class PackageList
|
1209
|
-
def self.create(v)
|
1210
|
-
v.is_a?(self) ? v : self.new(v)
|
1211
|
-
end
|
1212
|
-
|
1213
|
-
Archlinux.delegate_h(self, :@l)
|
1214
|
-
attr_accessor :children_mode, :ext_query
|
1215
|
-
attr_reader :l, :versions, :provides_for
|
1216
|
-
|
1217
|
-
def initialize(list)
|
1218
|
-
@l={}
|
1219
|
-
@versions={} #hash of versions for quick look ups
|
1220
|
-
@provides_for={} #hash of provides for quick look ups
|
1221
|
-
@ext_query=nil #how to get missing packages, default
|
1222
|
-
@children_mode=%i(depends) #children, default
|
1223
|
-
@ignore=[] #ignore packages update
|
1224
|
-
@query_ignore=[] #query ignore packages (ie these won't be returned by a query)
|
1225
|
-
merge(list)
|
1226
|
-
end
|
1227
|
-
|
1228
|
-
def packages
|
1229
|
-
@versions.keys
|
1230
|
-
end
|
1231
|
-
|
1232
|
-
def name_of(pkg)
|
1233
|
-
pkg.name_version
|
1234
|
-
end
|
1235
|
-
|
1236
|
-
def same?(other)
|
1237
|
-
unless @l.keys == other.keys
|
1238
|
-
SH.logger.warn("Inconsistency in the package names")
|
1239
|
-
return false
|
1240
|
-
end
|
1241
|
-
r=true
|
1242
|
-
@l.each do |name, pkg|
|
1243
|
-
unless pkg.same?(other[name])
|
1244
|
-
SH.logger.warn("Inconsistensy for the package #{name}")
|
1245
|
-
r=false
|
1246
|
-
end
|
1247
|
-
end
|
1248
|
-
return r
|
1249
|
-
end
|
1250
|
-
|
1251
|
-
def merge(l)
|
1252
|
-
# l=l.values if l.is_a?(PackageList) # this is handled below
|
1253
|
-
l= case l
|
1254
|
-
when Hash
|
1255
|
-
l.values.compact
|
1256
|
-
when PackageList
|
1257
|
-
l.values
|
1258
|
-
else
|
1259
|
-
l.to_a
|
1260
|
-
end
|
1261
|
-
l.each do |pkg|
|
1262
|
-
pkg=Package.new(pkg) unless pkg.is_a?(Package)
|
1263
|
-
name=name_of(pkg)
|
1264
|
-
if @l.key?(name)
|
1265
|
-
@l[name].merge(pkg)
|
1266
|
-
else
|
1267
|
-
@l[name]=pkg
|
1268
|
-
end
|
1269
|
-
|
1270
|
-
@versions[pkg.name]||={}
|
1271
|
-
@versions[pkg.name][pkg.version.to_s]=name
|
1272
|
-
|
1273
|
-
pkg[:provides].each do |p|
|
1274
|
-
pkg=Query.strip(p)
|
1275
|
-
@provides_for[pkg]||={}
|
1276
|
-
@provides_for[pkg][p]=name #todo: do we pass the name or the full pkg?
|
1277
|
-
end
|
1278
|
-
end
|
1279
|
-
self
|
1280
|
-
end
|
1281
|
-
|
1282
|
-
def latest
|
1283
|
-
r={}
|
1284
|
-
@versions.each do |pkg, versions|
|
1285
|
-
v=versions.keys.max do |v1,v2|
|
1286
|
-
Version.create(v1) <=> Version.create(v2)
|
1287
|
-
end
|
1288
|
-
r[pkg]=@l[versions[v]]
|
1289
|
-
end
|
1290
|
-
r
|
1291
|
-
end
|
1292
|
-
|
1293
|
-
def find(q, **opts)
|
1294
|
-
return q if @l.key?(q)
|
1295
|
-
q=Query.create(q); pkg=q.name
|
1296
|
-
query(q, **opts) do |found, type|
|
1297
|
-
if type==:version
|
1298
|
-
unless found.empty? #we select the most up to date
|
1299
|
-
max = found.max { |v,w| Version.create(v) <=> Version.create(w) }
|
1300
|
-
return @versions[pkg][max]
|
1301
|
-
end
|
1302
|
-
elsif type==:provides
|
1303
|
-
max = found.max { |v,w| Query.create(v) <=> Query.create(w) }
|
1304
|
-
return @provides_for[pkg][max]
|
1305
|
-
end
|
1306
|
-
end
|
1307
|
-
return nil
|
1308
|
-
end
|
1309
|
-
|
1310
|
-
def query(q, provides: false, &b) #provides: do we check Provides?
|
1311
|
-
q=Query.new(q) unless q.is_a?(Query)
|
1312
|
-
matches=[]; pkg=q.name
|
1313
|
-
if @versions.key?(pkg)
|
1314
|
-
matches+=(found=@versions[pkg].keys.select {|v| q.satisfy?(Version.create(v))}).map {|k| @versions[pkg][k]}
|
1315
|
-
yield(found, :version) if block_given?
|
1316
|
-
end
|
1317
|
-
if provides and @provides_for.key?(pkg)
|
1318
|
-
matches+=(found=@provides_for[pkg].keys.select {|v| q.satisfy?(Query.create(v))}).map {|k| @provides_for[pkg][k]}
|
1319
|
-
yield(found, :provides) if block_given?
|
1320
|
-
end
|
1321
|
-
matches
|
1322
|
-
end
|
1323
|
-
|
1324
|
-
def to_a
|
1325
|
-
@l.values
|
1326
|
-
end
|
1327
|
-
|
1328
|
-
# here the arguments are Strings
|
1329
|
-
# return the arguments replaced by eventual provides + missing packages
|
1330
|
-
# are added to @l
|
1331
|
-
def resolve(*queries, provides: true, ext_query: @ext_query, fallback: true, **opts)
|
1332
|
-
got={}; missed=[]
|
1333
|
-
pkgs=queries.map {|p| Query.strip(p)}
|
1334
|
-
ignored = pkgs & @query_ignore
|
1335
|
-
queries.each do |query|
|
1336
|
-
if ignored.include?(Query.strip(query))
|
1337
|
-
got[query]=nil #=> means the query was ignored
|
1338
|
-
else
|
1339
|
-
pkg=self.find(query, provides: provides, **opts)
|
1340
|
-
if pkg
|
1341
|
-
got[query]=pkg
|
1342
|
-
else
|
1343
|
-
missed << query
|
1344
|
-
end
|
1345
|
-
end
|
1346
|
-
end
|
1347
|
-
# we do it this way to call ext_query in batch
|
1348
|
-
if ext_query and !missed.empty?
|
1349
|
-
found, new_pkgs=ext_query.call(*missed, provides: provides)
|
1350
|
-
self.merge(new_pkgs)
|
1351
|
-
got.merge!(found)
|
1352
|
-
missed-=found.keys
|
1353
|
-
end
|
1354
|
-
if fallback and !missed.empty?
|
1355
|
-
new_queries={}
|
1356
|
-
missed.each do |query|
|
1357
|
-
if (query_pkg=Query.strip(query)) != query
|
1358
|
-
new_queries[query]=query_pkg
|
1359
|
-
# missed.delete(query)
|
1360
|
-
end
|
1361
|
-
end
|
1362
|
-
unless new_queries.empty?
|
1363
|
-
SH.logger.warn "Trying fallback for packages: #{new_queries.keys.join(', ')}"
|
1364
|
-
fallback_got=self.resolve(*new_queries.values, provides: provides, ext_query: ext_query, fallback: false, **opts)
|
1365
|
-
got.merge!(fallback_got)
|
1366
|
-
SH.logger.warn "Missing packages: #{missed.map {|m| r=m; r<<" [fallback: #{fallback}]" if (fallback=fallback_got[new_queries[m]]); r}.join(', ')}"
|
1367
|
-
end
|
1368
|
-
else
|
1369
|
-
SH.logger.warn "Missing packages: #{missed.join(', ')}" if !missed.empty? and ext_query != false #ext_query=false is a hack to silence this message
|
1370
|
-
end
|
1371
|
-
got
|
1372
|
-
end
|
1373
|
-
|
1374
|
-
def get(*args)
|
1375
|
-
#compact because the resolution can be nil for an ignored package
|
1376
|
-
resolve(*args).values.compact
|
1377
|
-
end
|
1378
|
-
|
1379
|
-
def children(node, mode=@children_mode, verbose: false, **opts, &b)
|
1380
|
-
deps=@l.fetch(node).dependencies(mode)
|
1381
|
-
SH.logger.info "- #{node} => #{deps}" if verbose
|
1382
|
-
deps=get(*deps, **opts)
|
1383
|
-
SH.logger.info " => #{deps}" if verbose
|
1384
|
-
if b
|
1385
|
-
deps.each(&b)
|
1386
|
-
else
|
1387
|
-
deps
|
1388
|
-
end
|
1389
|
-
end
|
1390
|
-
|
1391
|
-
private def call_tsort(l, method: :tsort, **opts, &b)
|
1392
|
-
each_node=l.method(:each)
|
1393
|
-
s=self
|
1394
|
-
each_child = lambda do |node, &b|
|
1395
|
-
s.children(node, **opts, &b)
|
1396
|
-
end
|
1397
|
-
TSort.public_send(method, each_node, each_child, &b)
|
1398
|
-
end
|
1399
|
-
|
1400
|
-
def tsort(l, **opts, &b)
|
1401
|
-
if b
|
1402
|
-
call_tsort(l, method: :each_strongly_connected_component, **opts, &b)
|
1403
|
-
else
|
1404
|
-
r=call_tsort(l, method: :strongly_connected_components, **opts)
|
1405
|
-
cycles=r.select {|c| c.length > 1}
|
1406
|
-
SH.logger.warn "Cycles detected: #{cycles}" unless cycles.empty?
|
1407
|
-
r.flatten
|
1408
|
-
end
|
1409
|
-
end
|
1410
|
-
|
1411
|
-
# recursive get
|
1412
|
-
def rget(*pkgs)
|
1413
|
-
l=get(*pkgs)
|
1414
|
-
tsort(l)
|
1415
|
-
end
|
1416
|
-
|
1417
|
-
# check updates compared to another list
|
1418
|
-
def check_updates(l)
|
1419
|
-
l=self.class.create(l)
|
1420
|
-
a=self.latest; b=l.latest
|
1421
|
-
r={}
|
1422
|
-
b.each do |k, v|
|
1423
|
-
if a.key?(k)
|
1424
|
-
v1=a[k].version
|
1425
|
-
v2=v.version
|
1426
|
-
h={in: v1.to_s, out: v2.to_s, in_pkg: name_of(a[k]), out_pkg: name_of(v)}
|
1427
|
-
case v1 <=> v2
|
1428
|
-
when -1
|
1429
|
-
h[:op]=:upgrade
|
1430
|
-
when 0
|
1431
|
-
h[:op]=:equal
|
1432
|
-
when 1
|
1433
|
-
h[:op]=:downgrade
|
1434
|
-
end
|
1435
|
-
r[k]=h
|
1436
|
-
else
|
1437
|
-
#new installation
|
1438
|
-
r[k]={op: :install,
|
1439
|
-
in: nil,
|
1440
|
-
out: v.version.to_s, out_pkg: name_of(v)}
|
1441
|
-
end
|
1442
|
-
end
|
1443
|
-
(a.keys-b.keys).each do |k|
|
1444
|
-
r[k]={op: :obsolete,
|
1445
|
-
in: a[k].version.to_s,
|
1446
|
-
out: nil, in_pkg: name_of(a[k])}
|
1447
|
-
end
|
1448
|
-
r
|
1449
|
-
end
|
1450
|
-
|
1451
|
-
def select_updates(r)
|
1452
|
-
r.select {|_k,v| v[:op]==:upgrade or v[:op]==:install}.map {|_k, v| v[:out_pkg]}
|
1453
|
-
end
|
1454
|
-
|
1455
|
-
def get_updates(l, verbose: true, obsolete: true)
|
1456
|
-
c=check_updates(l)
|
1457
|
-
show_updates(c, obsolete: obsolete) if verbose
|
1458
|
-
select_updates(c)
|
1459
|
-
end
|
1460
|
-
|
1461
|
-
#take the result of check_updates and pretty print them
|
1462
|
-
def show_updates(r, obsolete: true)
|
1463
|
-
require 'simplecolor'
|
1464
|
-
r.each do |k,v|
|
1465
|
-
next if v[:op]==:equal
|
1466
|
-
next if obsolete and v[:op]==:obsolete
|
1467
|
-
vin= v[:in] ? v[:in] : "(none)"
|
1468
|
-
vout= v[:out] ? v[:out] : "(none)"
|
1469
|
-
op = "->"; op="<-" if v[:op]==:downgrade
|
1470
|
-
extra=""
|
1471
|
-
extra=" [#{v[:op]}]" if v[:op]!=:upgrade
|
1472
|
-
SH.logger.info SimpleColor.color(" -> #{k}: #{vin} #{op} #{vout}#{extra}", :black)
|
1473
|
-
end
|
1474
|
-
end
|
1475
|
-
|
1476
|
-
def check_update(ext_query=@ext_query)
|
1477
|
-
if ext_query
|
1478
|
-
_found, new_pkgs=ext_query.call(*packages)
|
1479
|
-
check_updates(new_pkgs)
|
1480
|
-
end
|
1481
|
-
end
|
1482
|
-
|
1483
|
-
def update(**opts)
|
1484
|
-
install(update: true, **opts)
|
1485
|
-
end
|
1486
|
-
|
1487
|
-
# take a list of packages to install
|
1488
|
-
def install(*packages, update: false, ext_query: @ext_query, verbose: true, obsolete: true)
|
1489
|
-
packages+=self.packages if update
|
1490
|
-
if ext_query
|
1491
|
-
_found, new_pkgs=ext_query.call(*packages)
|
1492
|
-
SH.logger.info "# Checking packages" if verbose
|
1493
|
-
u=get_updates(new_pkgs, verbose: verbose, obsolete: obsolete)
|
1494
|
-
new=self.class.new(l.values).merge(new_pkgs)
|
1495
|
-
# The updates or new packages may need new deps
|
1496
|
-
SH.logger.info "# Checking dependencies" if verbose
|
1497
|
-
full=new.rget(*u)
|
1498
|
-
full_updates=get_updates(new.values_at(*full), verbose: verbose, obsolete: obsolete)
|
1499
|
-
yield u, full_updates if block_given?
|
1500
|
-
full_updates
|
1501
|
-
else
|
1502
|
-
SH.logger.warn "External query not defined"
|
1503
|
-
end
|
1504
|
-
end
|
1505
|
-
end
|
1506
|
-
|
1507
|
-
class AurCache < PackageList
|
1508
|
-
def self.create(v)
|
1509
|
-
v.is_a?(self) ? v : self.new(v)
|
1510
|
-
end
|
1511
|
-
|
1512
|
-
def initialize(l)
|
1513
|
-
super
|
1514
|
-
@ext_query=method(:ext_query)
|
1515
|
-
@query_ignore=AurPackageList.official
|
1516
|
-
end
|
1517
|
-
|
1518
|
-
def ext_query(*queries, provides: false)
|
1519
|
-
pkgs=queries.map {|p| Query.strip(p)}
|
1520
|
-
# in a query like foo>1000, even if foo exist and was queried,
|
1521
|
-
# the query fails so it gets called in ext_query
|
1522
|
-
# remove these packages
|
1523
|
-
# TODO: do the same for a provides query
|
1524
|
-
pkgs-=self.packages
|
1525
|
-
if pkgs.empty?
|
1526
|
-
l=self.class.new([])
|
1527
|
-
else
|
1528
|
-
SH.logger.warn "! Calling aur for infos on: #{pkgs.join(', ')}"
|
1529
|
-
l=AurQuery.packages(*pkgs)
|
1530
|
-
@query_ignore += pkgs - l.packages #these don't exist in aur
|
1531
|
-
end
|
1532
|
-
r=l.resolve(*queries, ext_query: false, fallback: false)
|
1533
|
-
return r, l
|
1534
|
-
end
|
1535
|
-
end
|
1536
|
-
|
1537
|
-
class AurPackageList < PackageList
|
1538
|
-
def self.create(v)
|
1539
|
-
v.is_a?(self) ? v : self.new(v)
|
1540
|
-
end
|
1541
|
-
|
1542
|
-
def self.official
|
1543
|
-
@official||=%w(core extra community).map {|repo| Repo.new(repo).list(mode: :pacman)}.flatten.compact
|
1544
|
-
end
|
1545
|
-
|
1546
|
-
def self.cache
|
1547
|
-
@cache ||= AurCache.new([])
|
1548
|
-
end
|
1549
|
-
|
1550
|
-
def initialize(l)
|
1551
|
-
super
|
1552
|
-
@missed=[]
|
1553
|
-
@ext_query=method(:ext_query)
|
1554
|
-
@children_mode=%i(depends make_depends check_depends)
|
1555
|
-
end
|
1556
|
-
|
1557
|
-
def official
|
1558
|
-
self.class.official
|
1559
|
-
end
|
1560
|
-
|
1561
|
-
def ext_query(*queries, provides: false)
|
1562
|
-
cache=self.class.cache
|
1563
|
-
got=cache.resolve(*queries, fallback: false, provides: provides)
|
1564
|
-
return got, self.class.new(cache.l.slice(*got.values.compact))
|
1565
|
-
end
|
1566
|
-
|
1567
|
-
def do_update(**opts, &b)
|
1568
|
-
do_install(update: true, **opts)
|
1569
|
-
end
|
1570
|
-
|
1571
|
-
def do_install(*args, **opts)
|
1572
|
-
install_opts={}
|
1573
|
-
%i(update ext_query verbose obsolete).each do |key|
|
1574
|
-
opts.key?(key) && install_opts[key]=opts.delete(key)
|
1575
|
-
end
|
1576
|
-
deps=[]
|
1577
|
-
l=install(*args, **install_opts) do |orig, with_deps|
|
1578
|
-
deps=with_deps-orig
|
1579
|
-
end
|
1580
|
-
unless l.empty?
|
1581
|
-
m=MakepkgList.new(l.map {|p| Query.strip(p)})
|
1582
|
-
deps.each { |dep| m[Query.strip(dep)]&.asdeps=true }
|
1583
|
-
if block_given?
|
1584
|
-
yield m
|
1585
|
-
else
|
1586
|
-
m.install(**opts)
|
1587
|
-
end
|
1588
|
-
m
|
1589
|
-
end
|
1590
|
-
end
|
1591
|
-
end
|
1592
|
-
|
1593
|
-
class PacmanConf
|
1594
|
-
def self.create(v)
|
1595
|
-
v.is_a?(self) ? v : self.new(v, {}) #pass empty keywords so that a Hash is seen as an argument and not a list of keywords
|
1596
|
-
end
|
1597
|
-
|
1598
|
-
Archlinux.delegate_h(self, :@pacman_conf)
|
1599
|
-
attr_accessor :pacman_conf, :config
|
1600
|
-
|
1601
|
-
def initialize(conf="/etc/pacman.conf", config: Archlinux.config, **keys)
|
1602
|
-
@config=config
|
1603
|
-
if conf.is_a?(String) or conf.is_a?(Pathname)
|
1604
|
-
conf=parse(conf, **keys)
|
1605
|
-
end
|
1606
|
-
@pacman_conf=conf
|
1607
|
-
end
|
1608
|
-
|
1609
|
-
def self.parse(content)
|
1610
|
-
list=%i(HoldPkg IgnorePkg IgnoreGroup NoUpgrade NoExtract SigLevel LocalFileSigLevel RemoteFileSigLevel Usage Server)
|
1611
|
-
mode=:options
|
1612
|
-
config={options: {}, repos: {}}
|
1613
|
-
content=content.each_line if content.is_a?(String)
|
1614
|
-
content.each do |l|
|
1615
|
-
if (m=l.match(/^\[([\w-]+)\]$/))
|
1616
|
-
mode=m[1]
|
1617
|
-
if mode == "options"
|
1618
|
-
mode=:options
|
1619
|
-
else
|
1620
|
-
config[:repos][mode]||={}
|
1621
|
-
end
|
1622
|
-
else
|
1623
|
-
key, value=l.split(' = ', 2)
|
1624
|
-
key=key.to_sym
|
1625
|
-
h = mode==:options ? config[:options] : config[:repos][mode]
|
1626
|
-
if list.include?(key)
|
1627
|
-
h[key]||=[]
|
1628
|
-
h[key]<<value
|
1629
|
-
else
|
1630
|
-
h[key]=value
|
1631
|
-
end
|
1632
|
-
end
|
1633
|
-
end
|
1634
|
-
config
|
1635
|
-
end
|
1636
|
-
|
1637
|
-
def parse(file, raw: false, args: nil)
|
1638
|
-
unless args
|
1639
|
-
if raw
|
1640
|
-
args=[:'pacconf', "--raw", "--config=#{file}"]
|
1641
|
-
else
|
1642
|
-
args=[:'pacman-conf', "--config=#{file}"]
|
1643
|
-
end
|
1644
|
-
end
|
1645
|
-
output=@config.launch(*args) do |*args|
|
1646
|
-
SH.run_simple(*args, chomp: :lines)
|
1647
|
-
end
|
1648
|
-
self.class.parse(output)
|
1649
|
-
end
|
1650
|
-
|
1651
|
-
def non_official_repos
|
1652
|
-
repos=@pacman_conf[:repos]
|
1653
|
-
repos.slice(*(repos.keys - %i(core extra community multilib testing community-testing multilib-testing)))
|
1654
|
-
end
|
1655
|
-
|
1656
|
-
def to_s
|
1657
|
-
r=[]
|
1658
|
-
print_values=lambda do |h, section|
|
1659
|
-
r<<"[#{section}]" if section
|
1660
|
-
h.each do |k,v|
|
1661
|
-
case v
|
1662
|
-
when nil
|
1663
|
-
r << k
|
1664
|
-
when Array
|
1665
|
-
v.each { |vv| r << "#{k} = #{vv}" }
|
1666
|
-
else
|
1667
|
-
r << "#{k} = #{v}"
|
1668
|
-
end
|
1669
|
-
end
|
1670
|
-
end
|
1671
|
-
print_values.call(@pacman_conf[:options], "options")
|
1672
|
-
@pacman_conf[:repos].each do |section, props|
|
1673
|
-
print_values.call(props, section)
|
1674
|
-
end
|
1675
|
-
r.join("\n")+"\n"
|
1676
|
-
end
|
1677
|
-
|
1678
|
-
def tempfile
|
1679
|
-
SH::VirtualFile.new("pacman.conf", to_s)
|
1680
|
-
end
|
1681
|
-
end
|
1682
|
-
|
1683
|
-
class Devtools
|
1684
|
-
def self.create(v)
|
1685
|
-
v.is_a?(self) ? v : self.new(v)
|
1686
|
-
end
|
1687
|
-
Archlinux.delegate_h(self, :@opts)
|
1688
|
-
|
1689
|
-
attr_accessor :config, :opts
|
1690
|
-
def initialize(config: Archlinux.config, **opts)
|
1691
|
-
@config=config
|
1692
|
-
@opts=@config.opts.merge(opts)
|
1693
|
-
# %i(pacman_conf makepkg_conf).each do |key|
|
1694
|
-
# @opts[key]=@opts[key].tempfile.file if @opts[key].respond_to?(:tempfile)
|
1695
|
-
# end
|
1696
|
-
@opts[:chroot]=Pathname.new(@opts[:chroot]) if @opts[:chroot]
|
1697
|
-
add_binds
|
1698
|
-
end
|
1699
|
-
|
1700
|
-
def add_binds
|
1701
|
-
require 'uri'
|
1702
|
-
if (conf=@opts[:pacman_conf]).is_a?(PacmanConf)
|
1703
|
-
conf[:repos].each do |_name, opts|
|
1704
|
-
opts[:Server].each do |server|
|
1705
|
-
server.match(%r!file://(.*)!) do |m|
|
1706
|
-
@opts[:bind_ro]||=[]
|
1707
|
-
@opts[:bind_ro] << URI.unescape(m[1])
|
1708
|
-
end
|
1709
|
-
end
|
1710
|
-
end
|
1711
|
-
end
|
1712
|
-
end
|
1713
|
-
|
1714
|
-
def files
|
1715
|
-
%i(pacman_conf makepkg_conf).each do |key|
|
1716
|
-
if @opts[key]
|
1717
|
-
file=@opts[key]
|
1718
|
-
file=file.tempfile.file if file.respond_to?(:tempfile)
|
1719
|
-
yield key, file
|
1720
|
-
end
|
1721
|
-
end
|
1722
|
-
end
|
1723
|
-
|
1724
|
-
def pacman_config
|
1725
|
-
Pacman.create(@opts[:pacman_conf])
|
1726
|
-
end
|
1727
|
-
|
1728
|
-
def pacman(*args, default_opts: [], **opts)
|
1729
|
-
files do |key, file|
|
1730
|
-
default_opts += ["--config", file] if key==:pacman_conf
|
1731
|
-
end
|
1732
|
-
@config.launch(:pacman, *args, default_opts: default_opts, **opts) do |*args|
|
1733
|
-
SH.sh(*args)
|
1734
|
-
end
|
1735
|
-
end
|
1736
|
-
|
1737
|
-
def makepkg(*args, default_opts: [], **opts)
|
1738
|
-
files do |key, file|
|
1739
|
-
# trick to pass options to pacman
|
1740
|
-
args << "PACMAN_OPTS+=--config=#{file.shellescape}"
|
1741
|
-
default_opts += ["--config", file] if key==:makepkg_conf
|
1742
|
-
end
|
1743
|
-
@config.launch(:makepkg, *args, default_opts: default_opts, **opts) do |*args|
|
1744
|
-
SH.sh(*args)
|
1745
|
-
end
|
1746
|
-
end
|
1747
|
-
|
1748
|
-
|
1749
|
-
def nspawn(*args, root: @opts[:chroot]+'root', default_opts: [], **opts)
|
1750
|
-
files do |key, file|
|
1751
|
-
default_opts += ["-C", file] if key==:pacman_conf
|
1752
|
-
default_opts += ["-M", file] if key==:makepkg_conf
|
1753
|
-
end
|
1754
|
-
if (binds_ro=@opts[:bind_ro])
|
1755
|
-
binds_ro.each do |b|
|
1756
|
-
args.unshift("--bind-ro=#{b}")
|
1757
|
-
end
|
1758
|
-
end
|
1759
|
-
if (binds_rw=@opts[:bind_rw])
|
1760
|
-
binds_rw.each do |b|
|
1761
|
-
args.unshift("--bind=#{b}")
|
1762
|
-
end
|
1763
|
-
end
|
1764
|
-
args.unshift root
|
1765
|
-
|
1766
|
-
@config.launch(:'arch-nspawn', *args, default_opts: default_opts, **opts) do |*args|
|
1767
|
-
SH.sh(*args)
|
1768
|
-
end
|
1769
|
-
end
|
1770
|
-
|
1771
|
-
# this takes the same options as nspawn
|
1772
|
-
def mkarchroot(*args, nspawn: @config[:chroot_update], default_opts: [], **opts)
|
1773
|
-
files do |key, file|
|
1774
|
-
default_opts += ["-C", file] if key==:pacman_conf
|
1775
|
-
default_opts += ["-M", file] if key==:makepkg_conf
|
1776
|
-
end
|
1777
|
-
chroot=@opts[:chroot]
|
1778
|
-
chroot.sudo_mkpath unless chroot.directory?
|
1779
|
-
args.unshift(chroot+'root')
|
1780
|
-
if (chroot+'root'+'.arch-chroot').file?
|
1781
|
-
# Note that if nspawn is not called (and the chroot does not
|
1782
|
-
# exist), then the passed pacman.conf will not be replace the one
|
1783
|
-
# in the chroot. And when makechrootpkg calls nspawn, it does not
|
1784
|
-
# transmit the -C/-M options. So even if we don't want to update,
|
1785
|
-
# we should call a dummy bin like 'true'
|
1786
|
-
if nspawn
|
1787
|
-
nspawn=nspawn.shellsplit if nspawn.is_a?(String)
|
1788
|
-
self.nspawn(*nspawn, **opts)
|
1789
|
-
end
|
1790
|
-
else
|
1791
|
-
@config.launch(:mkarchroot, *args, default_opts: default_opts, escape: true, **opts) do |*args|
|
1792
|
-
SH.sh(*args)
|
1793
|
-
end
|
1794
|
-
end
|
1795
|
-
end
|
1796
|
-
|
1797
|
-
def makechrootpkg(*args, default_opts: [], **opts)
|
1798
|
-
default_opts+=['-r', @opts[:chroot]]
|
1799
|
-
if (binds_ro=@opts[:bind_ro])
|
1800
|
-
binds_ro.each do |b|
|
1801
|
-
default_opts += ["-D", b]
|
1802
|
-
end
|
1803
|
-
end
|
1804
|
-
if (binds_rw=@opts[:bind_rw])
|
1805
|
-
binds_rw.each do |b|
|
1806
|
-
default_opts += ["-d", b]
|
1807
|
-
end
|
1808
|
-
end
|
1809
|
-
|
1810
|
-
#makechrootpkg calls itself with sudo --preserve-env=SOURCE_DATE_EPOCH,GNUPGHOME so it does not keep PKGDEST..., work around this by providing our own sudo
|
1811
|
-
@config.launch(:makechrootpkg, *args, default_opts: default_opts, sudo: 'sudo --preserve-env=GNUPGHOME,PKGDEST,SOURCE_DATE_EPOCH', **opts) do |*args|
|
1812
|
-
SH.sh(*args)
|
1813
|
-
end
|
1814
|
-
end
|
1815
|
-
|
1816
|
-
def tmp_pacman(conf, **opts)
|
1817
|
-
PacmanConf.create(conf).tempfile.create(true) do |file|
|
1818
|
-
pacman=lambda do |*args, **pac_opts|
|
1819
|
-
@config.launch(:pacman, *args, default_opts: ["--config", file], **opts.merge(pac_opts)) do |*args|
|
1820
|
-
SH.sh(*args)
|
1821
|
-
end
|
1822
|
-
end
|
1823
|
-
yield pacman, file
|
1824
|
-
end
|
1825
|
-
end
|
1826
|
-
|
1827
|
-
def sync_db(*names)
|
1828
|
-
conf=PacmanConf.create(@opts[:pacman_conf])
|
1829
|
-
new_conf={options: conf[:options], repos: {}}
|
1830
|
-
repos=conf[:repos]
|
1831
|
-
names.each do |name|
|
1832
|
-
if repos[name]
|
1833
|
-
new_conf[:repos][name]=repos[name]
|
1834
|
-
else
|
1835
|
-
SH.logger.warn "sync_db: unknown repo #{name}"
|
1836
|
-
end
|
1837
|
-
end
|
1838
|
-
tmp_pacman(new_conf) do |pacman|
|
1839
|
-
if block_given?
|
1840
|
-
yield(pacman)
|
1841
|
-
else
|
1842
|
-
pacman['-Syu', sudo: true]
|
1843
|
-
end
|
1844
|
-
end
|
1845
|
-
end
|
12
|
+
=begin
|
13
|
+
# query aur
|
14
|
+
Archlinux::AurQuery.packages("pacaur")
|
1846
15
|
|
1847
|
-
|
1848
|
-
|
16
|
+
# Make a package
|
17
|
+
m=Archlinux::Makepkg.new("pacaur")
|
18
|
+
m.edit
|
19
|
+
m.makepkg("--geninteg") #update PKGBUILD (todo: add a function for that?)
|
20
|
+
m.install
|
1849
21
|
|
1850
|
-
|
22
|
+
# install a package
|
1851
23
|
aur=Archlinux::AurPackageList.new([])
|
1852
24
|
l=aur.install("pacaur")
|
1853
25
|
|
1854
|
-
|
1855
|
-
aur.
|
26
|
+
# check update and new installation compared to a db
|
27
|
+
aur=Archlinux.config.db.packages
|
28
|
+
aur=Archlinux.config.default_packages #or get default packages
|
29
|
+
aur.update?
|
30
|
+
aur.install?("pacaur", update: true)
|
31
|
+
|
32
|
+
# Clean/Change cache:
|
33
|
+
Archlinux.config.instance_variable_set(:@install_list, nil)
|
34
|
+
aur.install_list=Archlinux.config.install_list
|
35
|
+
|
36
|
+
|
37
|
+
# Update a db with the latest packages available on the local filesystem
|
38
|
+
db=Archlinux.config.db
|
39
|
+
db.check_udpate / db.update
|
40
|
+
# see package names
|
41
|
+
db.packages.l.keys
|
42
|
+
|
43
|
+
# Check for useless packages in the db
|
44
|
+
pkgs = Archlinux.config.db.packages
|
45
|
+
needed = pkgs.rget(*wanted_pkgs)
|
46
|
+
# present = pkgs.latest.keys ## we want the version
|
47
|
+
present = pkgs.l.keys
|
48
|
+
notneeded=present - needed
|
49
|
+
files=pkgs.slice(*notneeded).map {|k,v| v.file}
|
50
|
+
db.remove(*files)
|
1856
51
|
=end
|
1857
|
-
|
1858
|
-
# TODO:
|
1859
|
-
# --devel
|
1860
|
-
# aur provides
|
1861
|
-
# @ignore
|