ruaur 0.1.0
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +7 -0
- data/bin/ruaur +201 -0
- data/lib/ruaur/aur.rb +263 -0
- data/lib/ruaur/error/aur_error.rb +5 -0
- data/lib/ruaur/error/failed_to_compile_error.rb +6 -0
- data/lib/ruaur/error/failed_to_download_error.rb +6 -0
- data/lib/ruaur/error/failed_to_extract_error.rb +6 -0
- data/lib/ruaur/error/missing_dependency_error.rb +6 -0
- data/lib/ruaur/error/package_not_found_error.rb +6 -0
- data/lib/ruaur/error/package_not_installed_error.rb +6 -0
- data/lib/ruaur/error/ruaur_already_running_error.rb +5 -0
- data/lib/ruaur/error.rb +11 -0
- data/lib/ruaur/package.rb +95 -0
- data/lib/ruaur/pacman.rb +124 -0
- data/lib/ruaur.rb +82 -0
- data/lib/string.rb +48 -0
- metadata +120 -0
checksums.yaml
ADDED
@@ -0,0 +1,7 @@
|
|
1
|
+
---
|
2
|
+
SHA1:
|
3
|
+
metadata.gz: 50ebe39558c3e6efd9953ae693863c8d7e7686c5
|
4
|
+
data.tar.gz: f4be7e20aa56a689686470120d08c4a82d6ef496
|
5
|
+
SHA512:
|
6
|
+
metadata.gz: 35750a58dd7ba7b56e899b47504db601d8c8d211b6c0464efd5e2b50471eacdc630196b3e47e2e670b78ffd6534cee85869f83f1106d2aee18695fc3b93a6072
|
7
|
+
data.tar.gz: da1963ce9bb15df155d8b012b74d1cca7cb6a24964607fb9623a46838ba2b5e4306a4f7b7916f41497aa1e221bf734273ddc80f554fdcb48c76943fa9ee5371b
|
data/bin/ruaur
ADDED
@@ -0,0 +1,201 @@
|
|
1
|
+
#!/usr/bin/env ruby
|
2
|
+
|
3
|
+
require "optparse"
|
4
|
+
require "ruaur"
|
5
|
+
require "string"
|
6
|
+
|
7
|
+
class RuAURExit
|
8
|
+
GOOD = 0
|
9
|
+
INVALID_OPTION = 1
|
10
|
+
INVALID_ARGUMENT = 2
|
11
|
+
MISSING_ARGUMENT = 3
|
12
|
+
INVALID_OPERATION = 4
|
13
|
+
MULTIPLE_OPERATIONS = 5
|
14
|
+
EXCEPTION = 6
|
15
|
+
end
|
16
|
+
|
17
|
+
class Operation
|
18
|
+
REMOVE = 1
|
19
|
+
SYNC = 2
|
20
|
+
end
|
21
|
+
|
22
|
+
def parse(args)
|
23
|
+
options = Hash.new
|
24
|
+
options["operation"] = nil
|
25
|
+
|
26
|
+
# Sync options
|
27
|
+
options["clean"] = false
|
28
|
+
options["noconfirm"] = false
|
29
|
+
options["search"] = false
|
30
|
+
options["upgrade"] = false
|
31
|
+
|
32
|
+
# Remove options
|
33
|
+
options["nosave"] = false
|
34
|
+
|
35
|
+
parser = OptionParser.new do |opts|
|
36
|
+
opts.banner =
|
37
|
+
"Usage: #{File.basename($0)} <operation> [OPTIONS] [pkgs]"
|
38
|
+
|
39
|
+
opts.on("", "OPERATIONS")
|
40
|
+
|
41
|
+
opts.on("-h", "--help", "Display this help message") do
|
42
|
+
puts opts
|
43
|
+
exit
|
44
|
+
end
|
45
|
+
|
46
|
+
opts.on("-R", "--remove", "Remove packages") do
|
47
|
+
if (options["operation"])
|
48
|
+
puts opts
|
49
|
+
exit RuAURExit::MULTIPLE_OPERATIONS
|
50
|
+
end
|
51
|
+
options["operation"] = Operation::REMOVE
|
52
|
+
end
|
53
|
+
|
54
|
+
opts.on("-S", "--sync", "Synchronize packages") do
|
55
|
+
if (options["operation"])
|
56
|
+
puts opts
|
57
|
+
exit RuAURExit::MULTIPLE_OPERATIONS
|
58
|
+
end
|
59
|
+
options["operation"] = Operation::SYNC
|
60
|
+
end
|
61
|
+
|
62
|
+
opts.on("", "SYNC OPTIONS")
|
63
|
+
|
64
|
+
opts.on("-c", "--clean", "Remove packages from the cache") do
|
65
|
+
options["clean"] = true
|
66
|
+
end
|
67
|
+
|
68
|
+
opts.on(
|
69
|
+
"--noconfirm",
|
70
|
+
"Bypass any and all \"Are you sure?\" messages."
|
71
|
+
) do
|
72
|
+
options["noconfirm"] = true
|
73
|
+
end
|
74
|
+
|
75
|
+
opts.on(
|
76
|
+
"-s",
|
77
|
+
"--search",
|
78
|
+
"Search the sync database and AUR for packages"
|
79
|
+
) do
|
80
|
+
options["search"] = true
|
81
|
+
end
|
82
|
+
|
83
|
+
opts.on("-u", "--sysupgrade", "Upgrade all packages") do
|
84
|
+
options["upgrade"] = true
|
85
|
+
end
|
86
|
+
|
87
|
+
opts.on("", "REMOVE OPTIONS")
|
88
|
+
|
89
|
+
opts.on("-n", "--nosave", "Completely remove package") do
|
90
|
+
options["nosave"] = true
|
91
|
+
end
|
92
|
+
end
|
93
|
+
|
94
|
+
begin
|
95
|
+
parser.parse!
|
96
|
+
rescue OptionParser::InvalidOption => e
|
97
|
+
puts e.message
|
98
|
+
puts parser
|
99
|
+
exit RuAURExit::INVALID_OPTION
|
100
|
+
rescue OptionParser::InvalidArgument => e
|
101
|
+
puts e.message
|
102
|
+
puts parser
|
103
|
+
exit RuAURExit::INVALID_ARGUMENT
|
104
|
+
rescue OptionParser::MissingArgument => e
|
105
|
+
puts e.message
|
106
|
+
puts parser
|
107
|
+
exit RuAURExit::MISSING_ARGUMENT
|
108
|
+
end
|
109
|
+
|
110
|
+
if (!validate(options))
|
111
|
+
puts parser
|
112
|
+
exit RuAURExit::INVALID_OPERATION
|
113
|
+
end
|
114
|
+
|
115
|
+
options["packages"] = args
|
116
|
+
|
117
|
+
return options
|
118
|
+
end
|
119
|
+
|
120
|
+
def validate(options)
|
121
|
+
case options["operation"]
|
122
|
+
when Operation::REMOVE
|
123
|
+
if (
|
124
|
+
options["clean"] ||
|
125
|
+
options["noconfirm"] ||
|
126
|
+
options["search"] ||
|
127
|
+
options["upgrade"]
|
128
|
+
)
|
129
|
+
return false
|
130
|
+
end
|
131
|
+
when Operation::SYNC
|
132
|
+
return false if (options["nosave"])
|
133
|
+
|
134
|
+
if (options["clean"])
|
135
|
+
if (
|
136
|
+
options["noconfirm"] ||
|
137
|
+
options["search"] ||
|
138
|
+
options["upgrade"]
|
139
|
+
)
|
140
|
+
return false
|
141
|
+
end
|
142
|
+
elsif (options["noconfirm"])
|
143
|
+
if (
|
144
|
+
options["clean"] ||
|
145
|
+
options["search"] ||
|
146
|
+
options["upgrade"]
|
147
|
+
)
|
148
|
+
return false
|
149
|
+
end
|
150
|
+
elsif (options["search"])
|
151
|
+
if (
|
152
|
+
options["clean"] ||
|
153
|
+
options["noconfirm"] ||
|
154
|
+
options["upgrade"]
|
155
|
+
)
|
156
|
+
return false
|
157
|
+
end
|
158
|
+
elsif (options["upgrade"])
|
159
|
+
if (
|
160
|
+
options["clean"] ||
|
161
|
+
options["noconfirm"] ||
|
162
|
+
options["search"]
|
163
|
+
)
|
164
|
+
return false
|
165
|
+
end
|
166
|
+
end
|
167
|
+
else
|
168
|
+
return false
|
169
|
+
end
|
170
|
+
|
171
|
+
return true
|
172
|
+
end
|
173
|
+
|
174
|
+
# Parse CLI args
|
175
|
+
options = parse(ARGV)
|
176
|
+
|
177
|
+
begin
|
178
|
+
ruaur = RuAUR.new
|
179
|
+
|
180
|
+
case options["operation"]
|
181
|
+
when Operation::REMOVE
|
182
|
+
ruaur.remove(options["packages"], options["nosave"])
|
183
|
+
when Operation::SYNC
|
184
|
+
if (options["clean"])
|
185
|
+
ruaur.clean(options["noconfirm"])
|
186
|
+
elsif (options["search"])
|
187
|
+
puts ruaur.search(options["packages"].join(" "))
|
188
|
+
elsif (options["upgrade"])
|
189
|
+
ruaur.upgrade(options["noconfirm"])
|
190
|
+
else
|
191
|
+
ruaur.install(options["packages"], options["noconfirm"])
|
192
|
+
end
|
193
|
+
end
|
194
|
+
exit RuAURExit::GOOD
|
195
|
+
rescue RuAUR::Error => e
|
196
|
+
puts e.message.red
|
197
|
+
exit RuAURExit::EXCEPTION
|
198
|
+
rescue Interrupt => e
|
199
|
+
# ^C
|
200
|
+
puts
|
201
|
+
end
|
data/lib/ruaur/aur.rb
ADDED
@@ -0,0 +1,263 @@
|
|
1
|
+
require "archive/tar/minitar"
|
2
|
+
require "fileutils"
|
3
|
+
require "io/wait"
|
4
|
+
require "json"
|
5
|
+
require "scoobydoo"
|
6
|
+
require "typhoeus"
|
7
|
+
require "zlib"
|
8
|
+
|
9
|
+
class RuAUR::AUR
|
10
|
+
def clean
|
11
|
+
puts "Cleaning AUR cache...".white
|
12
|
+
Dir.chdir(@cache) do
|
13
|
+
FileUtils.rm_rf(Dir["*"])
|
14
|
+
end
|
15
|
+
end
|
16
|
+
|
17
|
+
def compile(package)
|
18
|
+
puts "Compiling #{package.name}...".white
|
19
|
+
if (Process.uid == 0)
|
20
|
+
system("chown -R nobody:nobody .")
|
21
|
+
system("su -s /bin/sh nobody -c \"makepkg -sr\"")
|
22
|
+
else
|
23
|
+
system("makepkg -sr")
|
24
|
+
end
|
25
|
+
|
26
|
+
compiled = Dir["#{package.name}*.pkg.tar.xz"]
|
27
|
+
if (compiled.empty?)
|
28
|
+
raise RuAUR::Error::FailedToCompileError.new(package.name)
|
29
|
+
end
|
30
|
+
|
31
|
+
return compiled
|
32
|
+
end
|
33
|
+
private :compile
|
34
|
+
|
35
|
+
def download(package)
|
36
|
+
FileUtils.rm_f(Dir["#{package.name}.tar.gz*"])
|
37
|
+
|
38
|
+
puts "Downloading #{package.name}...".white
|
39
|
+
tarball(package.name, package.url, "#{package.name}.tar.gz")
|
40
|
+
|
41
|
+
tgz = Pathname.new("#{package.name}.tar.gz").expand_path
|
42
|
+
if (!tgz.exist?)
|
43
|
+
raise RuAUR::Error::FailedToDownloadError.new(
|
44
|
+
package.name
|
45
|
+
)
|
46
|
+
end
|
47
|
+
end
|
48
|
+
private :download
|
49
|
+
|
50
|
+
def edit_pkgbuild(package, noconfirm = false)
|
51
|
+
return false if (noconfirm)
|
52
|
+
|
53
|
+
print "Do you want to edit the PKGBUILD y/[n]/q?: "
|
54
|
+
answer = nil
|
55
|
+
while (answer.nil?)
|
56
|
+
begin
|
57
|
+
system("stty raw -echo")
|
58
|
+
if ($stdin.ready?)
|
59
|
+
answer = $stdin.getc
|
60
|
+
else
|
61
|
+
sleep 0.1
|
62
|
+
end
|
63
|
+
ensure
|
64
|
+
system("stty -raw echo")
|
65
|
+
end
|
66
|
+
end
|
67
|
+
puts
|
68
|
+
|
69
|
+
case answer
|
70
|
+
when "y", "Y"
|
71
|
+
editor = ENV["EDITOR"]
|
72
|
+
editor = ScoobyDoo.where_are_you("vim") if (editor.nil?)
|
73
|
+
editor = ScoobyDoo.where_are_you("vi") if (editor.nil?)
|
74
|
+
system("#{editor} PKGBUILD")
|
75
|
+
when "q", "Q", "\x03"
|
76
|
+
# Quit or ^C
|
77
|
+
return true
|
78
|
+
end
|
79
|
+
return false
|
80
|
+
end
|
81
|
+
private :edit_pkgbuild
|
82
|
+
|
83
|
+
def extract(package)
|
84
|
+
FileUtils.rm_rf(package.name)
|
85
|
+
|
86
|
+
puts "Extracting #{package.name}...".white
|
87
|
+
File.open("#{package.name}.tar.gz", "rb") do |tgz|
|
88
|
+
tar = Zlib::GzipReader.new(tgz)
|
89
|
+
Archive::Tar::Minitar.unpack(tar, ".")
|
90
|
+
end
|
91
|
+
FileUtils.rm_f("pax_global_header")
|
92
|
+
|
93
|
+
dir = Pathname.new(package.name).expand_path
|
94
|
+
if (!dir.exist? || !dir.directory?)
|
95
|
+
raise RuAUR::Error::FailedToExtractError.new(package.name)
|
96
|
+
end
|
97
|
+
end
|
98
|
+
private :extract
|
99
|
+
|
100
|
+
def find_upgrades
|
101
|
+
puts "Checking for AUR updates...".white
|
102
|
+
|
103
|
+
upgrades = Hash.new
|
104
|
+
multiinfo(@installed.keys).each do |package|
|
105
|
+
if (
|
106
|
+
@installed.has_key?(package.name) &&
|
107
|
+
package.newer?(@installed[package.name])
|
108
|
+
)
|
109
|
+
upgrades[package.name] = [
|
110
|
+
@installed[package.name],
|
111
|
+
package.version
|
112
|
+
]
|
113
|
+
end
|
114
|
+
end
|
115
|
+
|
116
|
+
return upgrades
|
117
|
+
end
|
118
|
+
private :find_upgrades
|
119
|
+
|
120
|
+
def info(package)
|
121
|
+
return nil if (package.nil? || package.empty?)
|
122
|
+
|
123
|
+
query = "type=info&arg=#{package}"
|
124
|
+
body = JSON.parse(Typhoeus.get("#{@rpc_url}?#{query}").body)
|
125
|
+
|
126
|
+
if (body["type"] == "error")
|
127
|
+
raise RuAUR::Error::AURError.new(body["results"])
|
128
|
+
end
|
129
|
+
|
130
|
+
return nil if (body["results"].empty?)
|
131
|
+
return RuAUR::Package.new(body["results"])
|
132
|
+
end
|
133
|
+
|
134
|
+
def initialize(pacman, cache = "/tmp/ruaur-#{ENV["USER"]}")
|
135
|
+
@cache = Pathname.new(cache).expand_path
|
136
|
+
FileUtils.mkdir_p(@cache)
|
137
|
+
@installed = pacman.query_aur
|
138
|
+
@pacman = pacman
|
139
|
+
@rpc_url = "https://aur.archlinux.org/rpc.php"
|
140
|
+
end
|
141
|
+
|
142
|
+
def install(pkg_name, noconfirm = false)
|
143
|
+
package = info(pkg_name)
|
144
|
+
|
145
|
+
if (package.nil?)
|
146
|
+
raise RuAUR::Error::PackageNotFoundError.new(pkg_name)
|
147
|
+
end
|
148
|
+
|
149
|
+
if (
|
150
|
+
@installed.include?(pkg_name) &&
|
151
|
+
!package.newer?(@installed[pkg_name])
|
152
|
+
)
|
153
|
+
puts "Already installed: #{pkg_name}".yellow
|
154
|
+
return
|
155
|
+
end
|
156
|
+
|
157
|
+
Dir.chdir(@cache) do
|
158
|
+
download(package)
|
159
|
+
extract(package)
|
160
|
+
end
|
161
|
+
Dir.chdir("#{@cache}/#{package.name}") do
|
162
|
+
return if (edit_pkgbuild(package, noconfirm))
|
163
|
+
install_dependencies(package, noconfirm)
|
164
|
+
compiled = compile(package)
|
165
|
+
@pacman.install_local(compiled, noconfirm)
|
166
|
+
end
|
167
|
+
|
168
|
+
@installed.merge!(@pacman.query_aur(pkg_name))
|
169
|
+
end
|
170
|
+
|
171
|
+
def install_dependencies(package, noconfirm)
|
172
|
+
pkgbuild = File.read("PKGBUILD")
|
173
|
+
|
174
|
+
pkgbuild.match(/^depends\=\(([^\)]+)\)/m) do |match|
|
175
|
+
match.captures.each do |cap|
|
176
|
+
cap.gsub(/\n/, " ").scan(/[^' ]+/) do |scan|
|
177
|
+
dep = scan.gsub(/(\<|\=|\>).*$/, "")
|
178
|
+
if (!@installed.has_key?(dep))
|
179
|
+
puts "Installing dependency: #{dep}".purple
|
180
|
+
if (@pacman.exist?(dep))
|
181
|
+
@pacman.install(dep, noconfirm)
|
182
|
+
else
|
183
|
+
install(dep, noconfirm)
|
184
|
+
end
|
185
|
+
end
|
186
|
+
end
|
187
|
+
end
|
188
|
+
end
|
189
|
+
end
|
190
|
+
private :install_dependencies
|
191
|
+
|
192
|
+
def multiinfo(pkgs)
|
193
|
+
results = Array.new
|
194
|
+
return results if (pkgs.nil? || pkgs.empty?)
|
195
|
+
|
196
|
+
query = "type=multiinfo&arg[]=#{pkgs.join("&arg[]=")}"
|
197
|
+
body = JSON.parse(Typhoeus.get("#{@rpc_url}?#{query}").body)
|
198
|
+
|
199
|
+
if (body["type"] == "error")
|
200
|
+
raise RuAUR::Error::AURError.new(body["results"])
|
201
|
+
end
|
202
|
+
|
203
|
+
body["results"].each do |result|
|
204
|
+
results.push(RuAUR::Package.new(result))
|
205
|
+
end
|
206
|
+
return results.sort
|
207
|
+
end
|
208
|
+
|
209
|
+
def search(string)
|
210
|
+
results = Array.new
|
211
|
+
return results if (string.nil? || string.empty?)
|
212
|
+
|
213
|
+
query = "type=search&arg=#{string}"
|
214
|
+
body = JSON.parse(Typhoeus.get("#{@rpc_url}?#{query}").body)
|
215
|
+
|
216
|
+
if (body["type"] == "error")
|
217
|
+
raise RuAUR::Error::AURError.new(body["results"])
|
218
|
+
end
|
219
|
+
|
220
|
+
body["results"].each do |result|
|
221
|
+
results.push(RuAUR::Package.new(result))
|
222
|
+
end
|
223
|
+
|
224
|
+
results.each do |package|
|
225
|
+
if (@installed.has_key?(package.name))
|
226
|
+
package.installed(@installed[package.name])
|
227
|
+
end
|
228
|
+
end
|
229
|
+
return results.sort
|
230
|
+
end
|
231
|
+
|
232
|
+
def tarball(name, url, file)
|
233
|
+
if (url.nil? || url.empty? || file.nil? || file.empty?)
|
234
|
+
return nil
|
235
|
+
end
|
236
|
+
|
237
|
+
tgz = File.open(file, "wb")
|
238
|
+
request = Typhoeus::Request.new(url)
|
239
|
+
request.on_headers do |response|
|
240
|
+
if (response.code != 200)
|
241
|
+
raise RuAUR::Error::FailedToDownloadError.new(name)
|
242
|
+
end
|
243
|
+
end
|
244
|
+
request.on_body do |chunk|
|
245
|
+
tgz.write(chunk)
|
246
|
+
end
|
247
|
+
request.on_complete do
|
248
|
+
tgz.close
|
249
|
+
end
|
250
|
+
request.run
|
251
|
+
end
|
252
|
+
private :tarball
|
253
|
+
|
254
|
+
def upgrade(noconfirm = false)
|
255
|
+
find_upgrades.each do |pkg_name, versions|
|
256
|
+
old, new = versions
|
257
|
+
|
258
|
+
puts "Upgrading #{pkg_name}...".white
|
259
|
+
puts "#{old.red} -> #{new.green}"
|
260
|
+
install(pkg_name, noconfirm)
|
261
|
+
end
|
262
|
+
end
|
263
|
+
end
|
data/lib/ruaur/error.rb
ADDED
@@ -0,0 +1,11 @@
|
|
1
|
+
class RuAUR::Error < RuntimeError
|
2
|
+
end
|
3
|
+
|
4
|
+
require "ruaur/error/aur_error"
|
5
|
+
require "ruaur/error/failed_to_compile_error"
|
6
|
+
require "ruaur/error/failed_to_download_error"
|
7
|
+
require "ruaur/error/failed_to_extract_error"
|
8
|
+
require "ruaur/error/missing_dependency_error"
|
9
|
+
require "ruaur/error/package_not_found_error"
|
10
|
+
require "ruaur/error/package_not_installed_error"
|
11
|
+
require "ruaur/error/ruaur_already_running_error"
|
@@ -0,0 +1,95 @@
|
|
1
|
+
require "string"
|
2
|
+
|
3
|
+
class RuAUR::Package
|
4
|
+
attr_accessor :description
|
5
|
+
attr_accessor :installed
|
6
|
+
attr_accessor :json
|
7
|
+
attr_accessor :name
|
8
|
+
attr_accessor :repo
|
9
|
+
attr_accessor :url
|
10
|
+
attr_accessor :version
|
11
|
+
attr_accessor :votes
|
12
|
+
|
13
|
+
def <=>(other)
|
14
|
+
if (self.name.downcase == other.name.downcase)
|
15
|
+
self_version = self.version.split(/\D+/).map(&:to_i)
|
16
|
+
other_version = self.version.split(/\D+/).map(&:to_i)
|
17
|
+
|
18
|
+
[self_version.size, other_version.size].max.times do |i|
|
19
|
+
cmp = self_version[i] <=> other_version[i]
|
20
|
+
return cmp if (cmp != 0)
|
21
|
+
end
|
22
|
+
end
|
23
|
+
return (self.name.downcase <=> other.name.downcase)
|
24
|
+
end
|
25
|
+
|
26
|
+
def initialize(json, repo = "aur")
|
27
|
+
@description = json["Description"]
|
28
|
+
@installed = nil
|
29
|
+
@json = json
|
30
|
+
@name = json["Name"]
|
31
|
+
@repo = repo
|
32
|
+
if (json["URLPath"])
|
33
|
+
@url = "https://aur.archlinux.org#{json["URLPath"]}"
|
34
|
+
else
|
35
|
+
@url = nil
|
36
|
+
end
|
37
|
+
@version = json["Version"]
|
38
|
+
@votes = nil
|
39
|
+
@votes = "(#{json["NumVotes"]})" if (json["NumVotes"])
|
40
|
+
end
|
41
|
+
|
42
|
+
def installed(version = nil)
|
43
|
+
@installed = version if (version)
|
44
|
+
@installed = @version if (version.nil?)
|
45
|
+
end
|
46
|
+
|
47
|
+
def newer?(ver)
|
48
|
+
self_version = @version.split(/\D+/).map(&:to_i)
|
49
|
+
other_version = ver.split(/\D+/).map(&:to_i)
|
50
|
+
|
51
|
+
[self_version.size, other_version.size].max.times do |i|
|
52
|
+
if (self_version[i] > other_version[i])
|
53
|
+
return true
|
54
|
+
end
|
55
|
+
end
|
56
|
+
return false
|
57
|
+
end
|
58
|
+
|
59
|
+
def older?(version)
|
60
|
+
self_version = @version.split(/\D+/).map(&:to_i)
|
61
|
+
other_version = version.split(/\D+/).map(&:to_i)
|
62
|
+
|
63
|
+
[self_version.size, other_version.size].max.times do |i|
|
64
|
+
if (self_version[i] < other_version[i])
|
65
|
+
return true
|
66
|
+
end
|
67
|
+
end
|
68
|
+
return false
|
69
|
+
end
|
70
|
+
|
71
|
+
def tarball(file)
|
72
|
+
return RuAUR::AUR.tarball(@url, file)
|
73
|
+
end
|
74
|
+
|
75
|
+
def to_s
|
76
|
+
out = Array.new
|
77
|
+
header = Array.new
|
78
|
+
|
79
|
+
header.push("#{@repo.blue}#{"/".blue}#{@name.cyan}")
|
80
|
+
if (@installed && newer?(@installed))
|
81
|
+
header.push(@installed.red)
|
82
|
+
header.push("->")
|
83
|
+
end
|
84
|
+
header.push(@version.green)
|
85
|
+
header.push(@votes.white) if (@votes)
|
86
|
+
header.push("[installed]".purple) if (@installed)
|
87
|
+
out.push(header.join(" "))
|
88
|
+
|
89
|
+
@description.word_wrap.each_line do |line|
|
90
|
+
out.push(" #{line.rstrip}")
|
91
|
+
end
|
92
|
+
|
93
|
+
return out.join("\n")
|
94
|
+
end
|
95
|
+
end
|
data/lib/ruaur/pacman.rb
ADDED
@@ -0,0 +1,124 @@
|
|
1
|
+
class RuAUR::Pacman
|
2
|
+
def clean(noconfirm = false)
|
3
|
+
puts "Cleaning pacman cache...".white
|
4
|
+
system("sudo #{@pac_clr} -Sc") if (!noconfirm)
|
5
|
+
system("sudo #{@pac_clr} -Sc --noconfirm") if (noconfirm)
|
6
|
+
end
|
7
|
+
|
8
|
+
def exist?(pkg_name)
|
9
|
+
return !%x(#{@pac_noclr} -Ss "^#{pkg_name}$").empty?
|
10
|
+
end
|
11
|
+
|
12
|
+
def initialize
|
13
|
+
@pac_noclr = "pacman --color=never"
|
14
|
+
@pac_clr = "pacman --color=always"
|
15
|
+
@installed = query
|
16
|
+
end
|
17
|
+
|
18
|
+
def install(pkg_name, noconfirm = false)
|
19
|
+
if (@installed.include?(pkg_name))
|
20
|
+
puts "Already installed: #{pkg_name}".yellow
|
21
|
+
return
|
22
|
+
end
|
23
|
+
|
24
|
+
puts "Installing #{pkg_name}...".white
|
25
|
+
if (!noconfirm)
|
26
|
+
system("sudo #{@pac_clr} -S #{pkg_name} --needed")
|
27
|
+
else
|
28
|
+
system(
|
29
|
+
"sudo #{@pac_clr} -S #{pkg_name} --needed --noconfirm"
|
30
|
+
)
|
31
|
+
end
|
32
|
+
|
33
|
+
@installed.merge!(query(pkg_name))
|
34
|
+
end
|
35
|
+
|
36
|
+
def install_local(pkgs, noconfirm = false)
|
37
|
+
pkgs.each do |pkg|
|
38
|
+
puts "Installing #{pkg}...".white
|
39
|
+
if (!noconfirm)
|
40
|
+
system("sudo #{@pac_clr} -U #{pkg}") if (!noconfirm)
|
41
|
+
else
|
42
|
+
system("sudo #{@pac_clr} -U #{pkg} --noconfirm")
|
43
|
+
end
|
44
|
+
end
|
45
|
+
end
|
46
|
+
|
47
|
+
def query(pkg_name = "")
|
48
|
+
results = Hash.new
|
49
|
+
%x(#{@pac_noclr} -Q #{pkg_name}).split("\n").map do |line|
|
50
|
+
line = line.split
|
51
|
+
results[line[0]] = line[1]
|
52
|
+
end
|
53
|
+
return results
|
54
|
+
end
|
55
|
+
|
56
|
+
def query_aur(pkg_name = "")
|
57
|
+
community = Pathname.new(
|
58
|
+
"/var/lib/pacman/sync/community"
|
59
|
+
).expand_path
|
60
|
+
|
61
|
+
results = Hash.new
|
62
|
+
%x(#{@pac_noclr} -Qm #{pkg_name}).split("\n").delete_if do |p|
|
63
|
+
# Skip packages in community
|
64
|
+
Dir["#{community}/#{p.split.join("-")}"].any?
|
65
|
+
end.map do |line|
|
66
|
+
line = line.split
|
67
|
+
results[line[0]] = line[1]
|
68
|
+
end
|
69
|
+
return results
|
70
|
+
end
|
71
|
+
|
72
|
+
def remove(pkg_names, nosave = false)
|
73
|
+
puts "Removing #{pkg_names.join(" ")}...".white
|
74
|
+
if (!nosave)
|
75
|
+
system("sudo #{@pac_clr} -R #{pkg_names.join(" ")}")
|
76
|
+
else
|
77
|
+
system("sudo #{@pac_clr} -Rn #{pkg_names.join(" ")}")
|
78
|
+
end
|
79
|
+
end
|
80
|
+
|
81
|
+
def search(pkg_names)
|
82
|
+
results = Array.new
|
83
|
+
return results if (pkg_names.nil? || pkg_names.empty?)
|
84
|
+
|
85
|
+
%x(#{@pac_noclr} -Ss #{pkg_names}).each_line do |line|
|
86
|
+
reg = "^([^\/ ]+)\/([^ ]+) ([^ ]+)( .*)?$"
|
87
|
+
match = line.match(/#{reg}/)
|
88
|
+
if (match)
|
89
|
+
repo, name, version, trailing = match.captures
|
90
|
+
repo.strip!
|
91
|
+
name.strip!
|
92
|
+
version.strip!
|
93
|
+
trailing = "" if (trailing.nil?)
|
94
|
+
trailing.strip!
|
95
|
+
|
96
|
+
results.push(
|
97
|
+
RuAUR::Package.new(
|
98
|
+
{
|
99
|
+
"Description" => "",
|
100
|
+
"Name" => name,
|
101
|
+
"NumVotes" => nil,
|
102
|
+
"URLPath" => nil,
|
103
|
+
"Version" => version
|
104
|
+
},
|
105
|
+
repo
|
106
|
+
)
|
107
|
+
)
|
108
|
+
if (trailing.include?("[installed]"))
|
109
|
+
results.last.installed
|
110
|
+
end
|
111
|
+
elsif (results.any?)
|
112
|
+
results.last.description += " #{line.strip}"
|
113
|
+
end
|
114
|
+
end
|
115
|
+
|
116
|
+
return results
|
117
|
+
end
|
118
|
+
|
119
|
+
def upgrade(noconfirm = false)
|
120
|
+
puts "Updating...".white
|
121
|
+
system("sudo #{@pac_clr} -Syyu") if (!noconfirm)
|
122
|
+
system("sudo #{@pac_clr} -Syyu --noconfirm") if (noconfirm)
|
123
|
+
end
|
124
|
+
end
|
data/lib/ruaur.rb
ADDED
@@ -0,0 +1,82 @@
|
|
1
|
+
require "fileutils"
|
2
|
+
require "scoobydoo"
|
3
|
+
|
4
|
+
class RuAUR
|
5
|
+
def check_and_lock
|
6
|
+
if (@lock.exist?)
|
7
|
+
raise RuAUR::Error::RuAURAlreadyRunningError.new
|
8
|
+
end
|
9
|
+
|
10
|
+
FileUtils.touch(@lock)
|
11
|
+
end
|
12
|
+
private :check_and_lock
|
13
|
+
|
14
|
+
def clean(noconfirm)
|
15
|
+
@pacman.clean(noconfirm)
|
16
|
+
@aur.clean
|
17
|
+
end
|
18
|
+
|
19
|
+
def initialize
|
20
|
+
[
|
21
|
+
"makepkg",
|
22
|
+
"pacman",
|
23
|
+
"su",
|
24
|
+
"sudo"
|
25
|
+
].each do |dep|
|
26
|
+
if (ScoobyDoo.where_are_you(dep).nil?)
|
27
|
+
raise RuAUR::Error::MissingDependencyError.new(dep)
|
28
|
+
end
|
29
|
+
end
|
30
|
+
|
31
|
+
@pacman = RuAUR::Pacman.new
|
32
|
+
@aur = RuAUR::AUR.new(@pacman)
|
33
|
+
@lock = Pathname.new("/tmp/ruaur.lock").expand_path
|
34
|
+
end
|
35
|
+
|
36
|
+
def install(pkg_names, noconfirm = false)
|
37
|
+
if (pkg_names.nil? || pkg_names.empty?)
|
38
|
+
raise RuAUR::Error::PackageNotFoundError.new
|
39
|
+
end
|
40
|
+
|
41
|
+
check_and_lock
|
42
|
+
|
43
|
+
pkg_names.each do |pkg_name|
|
44
|
+
if (@pacman.exist?(pkg_name))
|
45
|
+
@pacman.install(pkg_name, noconfirm)
|
46
|
+
else
|
47
|
+
@aur.install(pkg_name, noconfirm)
|
48
|
+
end
|
49
|
+
end
|
50
|
+
ensure
|
51
|
+
unlock
|
52
|
+
end
|
53
|
+
|
54
|
+
def remove(pkg_names, nosave = false)
|
55
|
+
check_and_lock
|
56
|
+
@pacman.remove(pkg_names, nosave)
|
57
|
+
ensure
|
58
|
+
unlock
|
59
|
+
end
|
60
|
+
|
61
|
+
def search(string)
|
62
|
+
return @pacman.search(string).concat(@aur.search(string))
|
63
|
+
end
|
64
|
+
|
65
|
+
def unlock
|
66
|
+
FileUtils.rm_f(@lock)
|
67
|
+
end
|
68
|
+
private :unlock
|
69
|
+
|
70
|
+
def upgrade(noconfirm = false)
|
71
|
+
check_and_lock
|
72
|
+
@pacman.upgrade(noconfirm)
|
73
|
+
@aur.upgrade(noconfirm)
|
74
|
+
ensure
|
75
|
+
unlock
|
76
|
+
end
|
77
|
+
end
|
78
|
+
|
79
|
+
require "ruaur/aur"
|
80
|
+
require "ruaur/error"
|
81
|
+
require "ruaur/package"
|
82
|
+
require "ruaur/pacman"
|
data/lib/string.rb
ADDED
@@ -0,0 +1,48 @@
|
|
1
|
+
# Redefine String class to allow for colorizing, rsplit, and word wrap
|
2
|
+
class String
|
3
|
+
def black
|
4
|
+
return colorize(30)
|
5
|
+
end
|
6
|
+
|
7
|
+
def blue
|
8
|
+
return colorize(34)
|
9
|
+
end
|
10
|
+
|
11
|
+
def colorize(color)
|
12
|
+
return "\e[#{color}m#{self}\e[0m"
|
13
|
+
end
|
14
|
+
|
15
|
+
def cyan
|
16
|
+
return colorize(36)
|
17
|
+
end
|
18
|
+
|
19
|
+
def green
|
20
|
+
return colorize(32)
|
21
|
+
end
|
22
|
+
|
23
|
+
def purple
|
24
|
+
return colorize(35)
|
25
|
+
end
|
26
|
+
|
27
|
+
def red
|
28
|
+
return colorize(31)
|
29
|
+
end
|
30
|
+
|
31
|
+
def rsplit(pattern)
|
32
|
+
ret = rpartition(pattern)
|
33
|
+
ret.delete_at(1)
|
34
|
+
return ret
|
35
|
+
end
|
36
|
+
|
37
|
+
def white
|
38
|
+
return colorize(37)
|
39
|
+
end
|
40
|
+
|
41
|
+
def word_wrap(width = 70)
|
42
|
+
return scan(/\S.{0,#{width}}\S(?=\s|$)|\S+/).join("\n")
|
43
|
+
end
|
44
|
+
|
45
|
+
def yellow
|
46
|
+
return colorize(33)
|
47
|
+
end
|
48
|
+
end
|
metadata
ADDED
@@ -0,0 +1,120 @@
|
|
1
|
+
--- !ruby/object:Gem::Specification
|
2
|
+
name: ruaur
|
3
|
+
version: !ruby/object:Gem::Version
|
4
|
+
version: 0.1.0
|
5
|
+
platform: ruby
|
6
|
+
authors:
|
7
|
+
- Miles Whittaker
|
8
|
+
autorequire:
|
9
|
+
bindir: bin
|
10
|
+
cert_chain: []
|
11
|
+
date: 2015-12-13 00:00:00.000000000 Z
|
12
|
+
dependencies:
|
13
|
+
- !ruby/object:Gem::Dependency
|
14
|
+
name: archive-tar-minitar
|
15
|
+
requirement: !ruby/object:Gem::Requirement
|
16
|
+
requirements:
|
17
|
+
- - "~>"
|
18
|
+
- !ruby/object:Gem::Version
|
19
|
+
version: '0.5'
|
20
|
+
- - ">="
|
21
|
+
- !ruby/object:Gem::Version
|
22
|
+
version: 0.5.2
|
23
|
+
type: :runtime
|
24
|
+
prerelease: false
|
25
|
+
version_requirements: !ruby/object:Gem::Requirement
|
26
|
+
requirements:
|
27
|
+
- - "~>"
|
28
|
+
- !ruby/object:Gem::Version
|
29
|
+
version: '0.5'
|
30
|
+
- - ">="
|
31
|
+
- !ruby/object:Gem::Version
|
32
|
+
version: 0.5.2
|
33
|
+
- !ruby/object:Gem::Dependency
|
34
|
+
name: scoobydoo
|
35
|
+
requirement: !ruby/object:Gem::Requirement
|
36
|
+
requirements:
|
37
|
+
- - "~>"
|
38
|
+
- !ruby/object:Gem::Version
|
39
|
+
version: '0.1'
|
40
|
+
- - ">="
|
41
|
+
- !ruby/object:Gem::Version
|
42
|
+
version: 0.1.1
|
43
|
+
type: :runtime
|
44
|
+
prerelease: false
|
45
|
+
version_requirements: !ruby/object:Gem::Requirement
|
46
|
+
requirements:
|
47
|
+
- - "~>"
|
48
|
+
- !ruby/object:Gem::Version
|
49
|
+
version: '0.1'
|
50
|
+
- - ">="
|
51
|
+
- !ruby/object:Gem::Version
|
52
|
+
version: 0.1.1
|
53
|
+
- !ruby/object:Gem::Dependency
|
54
|
+
name: typhoeus
|
55
|
+
requirement: !ruby/object:Gem::Requirement
|
56
|
+
requirements:
|
57
|
+
- - "~>"
|
58
|
+
- !ruby/object:Gem::Version
|
59
|
+
version: '0.8'
|
60
|
+
- - ">="
|
61
|
+
- !ruby/object:Gem::Version
|
62
|
+
version: 0.8.0
|
63
|
+
type: :runtime
|
64
|
+
prerelease: false
|
65
|
+
version_requirements: !ruby/object:Gem::Requirement
|
66
|
+
requirements:
|
67
|
+
- - "~>"
|
68
|
+
- !ruby/object:Gem::Version
|
69
|
+
version: '0.8'
|
70
|
+
- - ">="
|
71
|
+
- !ruby/object:Gem::Version
|
72
|
+
version: 0.8.0
|
73
|
+
description: RuAUR is a Ruby gem that allows searching and installing packages from
|
74
|
+
the Pacman sync database as well as the Arch User Repository (AUR).
|
75
|
+
email: mjwhitta@gmail.com
|
76
|
+
executables:
|
77
|
+
- ruaur
|
78
|
+
extensions: []
|
79
|
+
extra_rdoc_files: []
|
80
|
+
files:
|
81
|
+
- bin/ruaur
|
82
|
+
- lib/ruaur.rb
|
83
|
+
- lib/ruaur/aur.rb
|
84
|
+
- lib/ruaur/error.rb
|
85
|
+
- lib/ruaur/error/aur_error.rb
|
86
|
+
- lib/ruaur/error/failed_to_compile_error.rb
|
87
|
+
- lib/ruaur/error/failed_to_download_error.rb
|
88
|
+
- lib/ruaur/error/failed_to_extract_error.rb
|
89
|
+
- lib/ruaur/error/missing_dependency_error.rb
|
90
|
+
- lib/ruaur/error/package_not_found_error.rb
|
91
|
+
- lib/ruaur/error/package_not_installed_error.rb
|
92
|
+
- lib/ruaur/error/ruaur_already_running_error.rb
|
93
|
+
- lib/ruaur/package.rb
|
94
|
+
- lib/ruaur/pacman.rb
|
95
|
+
- lib/string.rb
|
96
|
+
homepage: https://mjwhitta.github.io/ruaur
|
97
|
+
licenses:
|
98
|
+
- GPL-3.0
|
99
|
+
metadata: {}
|
100
|
+
post_install_message:
|
101
|
+
rdoc_options: []
|
102
|
+
require_paths:
|
103
|
+
- lib
|
104
|
+
required_ruby_version: !ruby/object:Gem::Requirement
|
105
|
+
requirements:
|
106
|
+
- - ">="
|
107
|
+
- !ruby/object:Gem::Version
|
108
|
+
version: '0'
|
109
|
+
required_rubygems_version: !ruby/object:Gem::Requirement
|
110
|
+
requirements:
|
111
|
+
- - ">="
|
112
|
+
- !ruby/object:Gem::Version
|
113
|
+
version: '0'
|
114
|
+
requirements: []
|
115
|
+
rubyforge_project:
|
116
|
+
rubygems_version: 2.4.5.1
|
117
|
+
signing_key:
|
118
|
+
specification_version: 4
|
119
|
+
summary: Can search and install packages for Arch Linux
|
120
|
+
test_files: []
|