upm 0.1.6 → 0.1.7

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 CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: 5dd0714a5b73fc48e824d842aa8d4eb3f09f4c6cf3b72d3da04a9837bb8ce661
4
- data.tar.gz: b2b9f7acd21647b482ef8cc799fd5df72832a6500fad45a81026aa9cf567726f
3
+ metadata.gz: f8a190f9686ce55b16d74b0ff642047a17e19683187a40d40cebfc542262fcff
4
+ data.tar.gz: 470640b6500e070840f9f03131e0087d2b3fa3ab25d6450dee3d130463f082b8
5
5
  SHA512:
6
- metadata.gz: 3200e00ca2b898b2ed00c7505ddb005a9ec5bacd5a29fa7c53a89306cbd9264898259e32e46c44ec54d43c618300d54d6324a573ee224aed8005902e82bc55c5
7
- data.tar.gz: 56032bf6894c836b70ff22cfdd842b10d180778d362160bbb3156ab3f3a01e8be10c81b60edcfa332a38fb7936c1599ecb8c49285cccee2c0b503a169900edbb
6
+ metadata.gz: 39453d5478a636f20c45580e91f5a7c9251a0258274e1da16a9736e5b09a74ba7cf4204c65205f44430a35b4a2c7a316a518cd3f5eead7e448723afe747b8e28
7
+ data.tar.gz: 2b761cbb9ea039c2257e263b46302df7e3c55b4c31849366a5f535141224aa9b1e52a400b75fec88a55486f9cc35a21f96e0d8990a124eb2f0c695e0d873e66c
data/TODO.md CHANGED
@@ -1,18 +1,29 @@
1
1
  # TODO
2
2
 
3
+ ## Pipes and filters
4
+
5
+ * `Tool::DSL#run` is currently somewhat awkward; it would be simpler if returned an `Enumerator`, which could then be filtered (ie: highlight/grep), or concatenated to other `Enumerator`s.
6
+
7
+ ## Streaming pipes with colours
8
+
9
+ * Make the `run` command able to grep the output while streaming the results to the screen.
10
+ * Make run pretend to be a tty, so I don't need `--color=always`.
11
+ * Use spawn, like so:
12
+ ```
13
+ r,w = IO.pipe
14
+ spawn(*%w[echo hello world], out: w)
15
+ spawn(*%w[tr a-z A-Z], in: r)
16
+ ```
17
+
3
18
  ## More package managers
4
19
 
5
20
  Currently missing:
6
21
  * RedHat/Fedora/CentOS
7
22
  * OSX
8
- * FreeBSD
23
+ * <s>FreeBSD</s>
9
24
  * OpenBSD
10
25
  * SuSE
11
26
 
12
- ## Abbrev cmds
13
-
14
- * eg: upm install => upm i => u i
15
-
16
27
  ## Dependency-fetching features
17
28
 
18
29
  * Use upm to fetch dependencies for any library or script, across any language.
@@ -37,17 +48,6 @@ Use fzf for "list" output (or other commands that require selecting, like "remov
37
48
  * upm install --help
38
49
  * upm help install
39
50
 
40
- ## Streaming pipes with colours
41
-
42
- * Make the `run` command able to grep the output while streaming the results to the screen.
43
- * Make run pretend to be a tty, so I don't need `--color=always`.
44
- * Use spawn, like so:
45
- ```
46
- r,w = IO.pipe
47
- spawn(*%w[echo hello world], out: w)
48
- spawn(*%w[tr a-z A-Z], in: r)
49
- ```
50
-
51
51
  ## Figure out how to integrate language package managers
52
52
 
53
53
  * The packages that you can get through gem/pip/luarocks/etc. are often duplicated in the OS-level package managers. Should there be a preference?
@@ -88,3 +88,12 @@ Don't print backtrace when ^C is pressed.
88
88
  ## Tests
89
89
 
90
90
  Create fake OS environments that you can chroot into and run upm to test it out.
91
+
92
+
93
+
94
+ # DONE
95
+
96
+ ## Abbrev cmds
97
+
98
+ * eg: upm install => upm i => u i
99
+
data/VERSION CHANGED
@@ -1 +1 @@
1
- 0.1.6
1
+ 0.1.7
data/bin/upm CHANGED
@@ -4,11 +4,18 @@ $LOAD_PATH.unshift(File.expand_path(File.join('..', 'lib'), bin_dir))
4
4
 
5
5
  require 'upm'
6
6
 
7
- tool = UPM::Tool.for_os
7
+ unless tool = UPM::Tool.for_os
8
+ $stderr.puts "Error: I don't recognize this OS, or its package manager."
9
+ exit 1
10
+ end
11
+
8
12
  command, *args = ARGV
9
13
 
10
14
  if command.nil?
11
15
  tool.help
12
16
  else
13
- tool.call_command command, *args
17
+ begin
18
+ tool.call_command command, *args
19
+ rescue Interrupt
20
+ end
14
21
  end
data/lib/upm/core_ext.rb CHANGED
@@ -5,21 +5,38 @@ class DateTime
5
5
  end
6
6
 
7
7
  class File
8
- def self.which(bin)
9
- ENV["PATH"].split(":").each do |dir|
10
- full_path = File.join(dir, bin)
11
- return full_path if File.exists? full_path
8
+
9
+ #
10
+ # Overly clever which(), which returns an array if more than one argument was supplied,
11
+ # or string/nil if only one argument was supplied.
12
+ #
13
+ def self.which(*bins)
14
+ results = []
15
+ bins = bins.flatten
16
+ paths = ENV["PATH"].split(":").map { |path| File.realpath(path) rescue nil }.compact.uniq
17
+
18
+ paths.each do |dir|
19
+ bins.each do |bin|
20
+
21
+ full_path = File.join(dir, bin)
22
+
23
+ if File.exists?(full_path)
24
+ if bins.size == 1
25
+ return full_path
26
+ else
27
+ results << full_path
28
+ end
29
+ end
30
+
31
+ end
12
32
  end
13
- nil
33
+
34
+ bins.size == 1 ? nil : results
14
35
  end
15
36
 
16
37
  def self.which_is_best?(*bins)
17
- bins.flatten.each do |bin|
18
- if location = which(bin)
19
- return location
20
- end
21
- end
22
- nil
38
+ result = which(*bins.flatten)
39
+ result.is_a?(Array) ? result.first : result
23
40
  end
24
41
  end
25
42
 
@@ -147,4 +164,4 @@ module Enumerable
147
164
  end
148
165
 
149
166
  alias_method :cut_between, :split_between
150
- end
167
+ end
data/lib/upm/lesspipe.rb CHANGED
@@ -33,6 +33,16 @@ def lesspipe(*args)
33
33
 
34
34
  output = args.first if args.any?
35
35
 
36
+ # Don't page, just output to STDOUT
37
+ if options[:disabled]
38
+ if output
39
+ puts output
40
+ else
41
+ yield STDOUT
42
+ end
43
+ return
44
+ end
45
+
36
46
  params = []
37
47
  params << "-R" unless options[:color] == false
38
48
  params << "-S" unless options[:wrap] == true
@@ -0,0 +1,124 @@
1
+ require 'zlib'
2
+ require 'digest/sha2'
3
+ require 'digest/md5'
4
+ require 'pp'
5
+
6
+ module UPM
7
+ class PacmanVerifier
8
+
9
+ SKIP_FILES = %w[
10
+ /.BUILDINFO
11
+ /.INSTALL
12
+ /.PKGINFO
13
+ /.CHANGELOG
14
+ ]
15
+
16
+ PACKAGE_ROOT = "/var/lib/pacman/local/"
17
+
18
+ def compare(key, a, b)
19
+ a == b ? nil : [key, a, b]
20
+ end
21
+
22
+ def verify!(*included)
23
+ $stderr.puts "Checking integrity of #{included.any? ? included.size : "installed"} packages..."
24
+
25
+ report = []
26
+
27
+ Dir.entries(PACKAGE_ROOT).each do |package_dir|
28
+ mtree_path = File.join(PACKAGE_ROOT, package_dir, "mtree")
29
+ next unless File.exists?(mtree_path)
30
+
31
+ chunks = package_dir.split("-")
32
+ version = chunks[-2..-1].join("-")
33
+ package = chunks[0...-2].join("-")
34
+
35
+ next unless included.any? and included.include?(package)
36
+
37
+ puts "<8>[<7>+<8>] <10>#{package} <3>#{version}".colorize
38
+
39
+ result = []
40
+ defaults = {}
41
+
42
+ Zlib::GzipReader.open(mtree_path) do |io|
43
+ lines = io.each_line.drop(1)
44
+
45
+ lines.each do |line|
46
+ path, *expected = line.split
47
+ expected = expected.map { |opt| opt.split("=") }.to_h
48
+
49
+ if path == "/set"
50
+ defaults = expected
51
+ next
52
+ end
53
+
54
+ path = path[1..-1] if path[0] == "."
55
+ path = path.gsub(/\\(\d{3})/) { |m| $1.to_i(8).chr } # unescape \### codes
56
+
57
+ # next if expected["type"] == "dir"
58
+ next if SKIP_FILES.include?(path)
59
+
60
+ expected = defaults.merge(expected)
61
+ lstat = File.lstat(path)
62
+
63
+ errors = expected.map do |key, val|
64
+ case key
65
+ when "type"
66
+ compare("type", lstat.ftype[0...val.size], val)
67
+ when "link"
68
+ next if val == "/dev/null"
69
+ compare("link", File.readlink(path), val)
70
+ when "gid"
71
+ compare("gid", lstat.gid, val.to_i)
72
+ when "uid"
73
+ compare("uid", lstat.uid, val.to_i)
74
+ when "mode"
75
+ compare("mode", "%o" % (lstat.mode & 0xFFF), val)
76
+ when "size"
77
+ compare("size", lstat.size, val.to_i)
78
+ when "time"
79
+ next if expected["type"] == "dir"
80
+ next if expected["link"] == "/dev/null"
81
+ compare("time", lstat.mtime.to_i, val.to_i)
82
+ when "sha256digest"
83
+ compare("sha256digest", Digest::SHA256.file(path).hexdigest, val)
84
+ when "md5digest"
85
+ next if expected["sha256digest"]
86
+ compare("md5digest", Digest::MD5.file(path).hexdigest, val)
87
+ else
88
+ raise "Unknown key: #{key}=#{val}"
89
+ end
90
+ end.compact
91
+
92
+ if errors.any?
93
+ puts " <4>[<12>*<4>] <11>#{path}".colorize
94
+ errors.each do |key, a, e| # a=actual, e=expected
95
+ puts " <7>expected <14>#{key} <7>to be <2>#{e} <7>but was <4>#{a}".colorize
96
+ result << [path, "expected #{key.inspect} to be #{e.inspect} but was #{a.inspect}"]
97
+ end
98
+ end
99
+ rescue Errno::EACCES
100
+ puts " <1>[<9>!<1>] <11>Can't read <7>#{path} <8>(<9>permission denied<8>)".colorize
101
+ result << [path, "permission denied"]
102
+ rescue Errno::ENOENT
103
+ puts " <4>[<12>?<4>] <12>Missing file <15>#{path}".colorize
104
+ result << [path, "missing"]
105
+ end
106
+ end # gzip
107
+
108
+ report << [package, result] if result.any?
109
+ end # mtree
110
+
111
+ puts
112
+ puts "#{report.size} packages with errors (#{report.map { |result| result.size }.sum} errors total)"
113
+ puts
114
+
115
+ if report.any?
116
+ puts "Packages with problems:"
117
+ report.each do |package, errors|
118
+ puts " #{package} (#{errors.size} errors)"
119
+ end
120
+ end
121
+ end # verify!
122
+
123
+ end # PacmanAuditor
124
+ end # UPM
data/lib/upm/tool.rb CHANGED
@@ -1,3 +1,5 @@
1
+ require 'upm/tool_dsl'
2
+ require 'upm/tool_class_methods'
1
3
 
2
4
  # os:<pkg> -- automatically select the package manager for the current unix distribution
3
5
  # deb:<pkg> (or d: u:)
@@ -10,6 +12,10 @@ module UPM
10
12
 
11
13
  class Tool
12
14
 
15
+ @@tools = {}
16
+
17
+ include UPM::Tool::DSL
18
+
13
19
  COMMAND_HELP = {
14
20
  "install" => "install a package",
15
21
  "remove/uninstall" => "remove a package",
@@ -18,17 +24,20 @@ module UPM
18
24
  "list" => "list installed packages (or search their names if extra arguments are supplied)",
19
25
  "info" => "show metadata about a package",
20
26
  "update/sync" => "retrieve the latest package list or manifest",
21
- "upgrade" => "install new versions of all packages",
27
+ "upgrade" => "update package list and install updates",
28
+ "download" => "download package list and updates, but don't insatall them",
22
29
  "pin" => "pinning a package means it won't be automatically upgraded",
23
30
  "rollback" => "revert to an earlier version of a package (including its dependencies)",
31
+ "verify/check" => "verify the integrity of packages' files on the filesystem",
32
+ "audit/vuln" => "show known vulnerabilities in installed packages",
24
33
  "log" => "show history of package installs",
25
34
  "packagers" => "detect installed package managers, and pick which ones upm should wrap",
26
35
  "mirrors/sources" => "manage remote repositories and mirrors",
27
- "verfiy" => "verify the integrity of installed files",
28
36
  "clean" => "clear out the local package cache",
29
37
  "monitor" => "ad-hoc package manager for custom installations (like instmon)",
30
38
  "keys" => "keyrings and package authentication",
31
39
  "default" => "configure the action to take when no arguments are passed to 'upm' (defaults to 'os:update')",
40
+ "stats" => "show statistics about package database(s)",
32
41
  }
33
42
 
34
43
  ALIASES = {
@@ -36,58 +45,17 @@ module UPM
36
45
  "sync" => "update",
37
46
  "sources" => "mirrors",
38
47
  "show" => "info",
48
+ "vuln" => "audit",
49
+ "vulns" => "audit",
50
+ "check" => "verify",
51
+ "u" => "upgrade",
52
+ "i" => "install",
53
+ "d" => "download",
54
+ "s" => "search",
55
+ "f" => "files",
56
+ "r" => "remove",
39
57
  }
40
58
 
41
- @@tools = {}
42
- def self.tools; @@tools; end
43
-
44
- def self.register_tools!
45
- Dir["#{__dir__}/tools/*.rb"].each { |lib| require_relative(lib) }
46
- end
47
-
48
- def self.os_release
49
- @os_release ||= begin
50
- open("/etc/os-release") do |io|
51
- io.read.scan(/^(\w+)="?(.+?)"?$/)
52
- end.to_h
53
- rescue Errno::ENOENT
54
- {}
55
- end
56
- end
57
-
58
- def self.current_os_names
59
- # ID=ubuntu
60
- # ID_LIKE=debian
61
- os_release.values_at("ID", "ID_LIKE").compact
62
- end
63
-
64
- def self.nice_os_name
65
- os_release.values_at("PRETTY_NAME", "NAME", "ID", "ID_LIKE").first ||
66
- (`uname -o`.chomp rescue nil)
67
- end
68
-
69
- def self.for_os(os_names=nil)
70
- os_names = os_names ? [os_names].flatten : current_os_names
71
-
72
- tool = nil
73
-
74
- if os_names.any?
75
- tool = @@tools.find { |name, tool| os_names.any? { |name| tool.os.include? name } }.last
76
- end
77
-
78
- if tool.nil?
79
- tool = @@tools.find { |name, tool| File.which(tool.identifying_binary) }.last
80
- end
81
-
82
- if tool.nil?
83
- puts "Error: couldn't find a package manager."
84
- end
85
-
86
- tool
87
- end
88
-
89
- ###################################################################
90
-
91
59
  def initialize(name, &block)
92
60
  @name = name
93
61
  instance_eval(&block)
@@ -95,117 +63,6 @@ module UPM
95
63
  @@tools[name] = self
96
64
  end
97
65
 
98
- def call_command(name, *args)
99
- if block = (@cmds[name] || @cmds[ALIASES[name]])
100
- block.call args
101
- else
102
- puts "Command #{name} not supported in #{@name}"
103
- end
104
- end
105
-
106
- def help
107
- if osname = Tool.nice_os_name
108
- puts " Detected OS: #{osname}"
109
- end
110
-
111
- puts "Package manager: #{@name}"
112
- puts
113
- puts "Available commands:"
114
- available = COMMAND_HELP.select do |name, desc|
115
- names = name.split("/")
116
- names.any? { |name| @cmds[name] }
117
- end
118
-
119
- max_width = available.map(&:first).map(&:size).max
120
- available.each do |name, desc|
121
- puts " #{name.rjust(max_width)} | #{desc}"
122
- end
123
- end
124
-
125
- ## DSL methods
126
-
127
- def identifying_binary(id_bin=nil)
128
- if id_bin
129
- @id_bin = id_bin
130
- else
131
- @id_bin || @name
132
- end
133
- end
134
-
135
- def prefix(name)
136
- @prefix = name
137
- end
138
-
139
- def command(name, shell_command=nil, root: false, paged: false, &block)
140
- @cmds ||= {}
141
-
142
- if block_given?
143
- @cmds[name] = block
144
- elsif shell_command
145
- if shell_command.is_a? String
146
- shell_command = shell_command.split
147
- elsif not shell_command.is_a? Array
148
- raise "Error: command argument must be a String or an Array; it was a #{cmd.class}"
149
- end
150
-
151
- @cmds[name] = proc { |args| run(*shell_command, *args, paged: paged, root: root) }
152
- end
153
- end
154
-
155
- def os(*names)
156
- names.any? ? @os = names : @os
157
- end
158
-
159
- ## Helpers
160
-
161
- def run(*args, root: false, paged: false, grep: nil)
162
- if root and File.which("sudo")
163
- args.unshift "sudo"
164
- end
165
-
166
- if !paged and !grep
167
- system(*args)
168
- else
169
-
170
- IO.popen(args, err: [:child, :out]) do |command_io|
171
-
172
- if grep
173
- pattern = grep.is_a?(Regexp) ? grep.source : grep.to_s
174
- grep_io = IO.popen(["grep", "--color=always", "-Ei", pattern], "w+")
175
- IO.copy_stream(command_io, grep_io)
176
- grep_io.close_write
177
- command_io = grep_io
178
- end
179
-
180
- if paged
181
- lesspipe do |less|
182
- IO.copy_stream(command_io, less)
183
- end
184
- else
185
- IO.copy_stream(command_io, STDOUT)
186
- end
187
-
188
- end
189
-
190
- $?.to_i == 0
191
- end
192
- end
193
-
194
- def print_files(*paths, include: nil, exclude: nil)
195
- lesspipe do |less|
196
- paths.each do |path|
197
- less.puts "<8>=== <11>#{path} <8>========".colorize
198
- open(path) do |io|
199
- enum = io.each_line
200
- enum = enum.grep(include) if include
201
- enum = enum.reject { |line| line[exclude] } if exclude
202
- enum.each { |line| less.puts line }
203
- end
204
- less.puts
205
- end
206
- end
207
- end
208
-
209
66
  end # class Tool
210
67
 
211
68
  end # module UPM
@@ -0,0 +1,59 @@
1
+ module UPM
2
+ class Tool
3
+ class << self
4
+
5
+ def tools; @@tools; end
6
+
7
+ def register_tools!
8
+ Dir["#{__dir__}/tools/*.rb"].each { |lib| require_relative(lib) }
9
+ end
10
+
11
+ def os_release
12
+ @os_release ||= begin
13
+ open("/etc/os-release") do |io|
14
+ io.read.scan(/^(\w+)="?(.+?)"?$/)
15
+ end.to_h
16
+ rescue Errno::ENOENT
17
+ {}
18
+ end
19
+ end
20
+
21
+ def current_os_names
22
+ # eg: ID=ubuntu, ID_LIKE=debian
23
+ if os_release
24
+ os_release.values_at("ID", "ID_LIKE").compact
25
+ else
26
+ # `uname -s` => Darwin|FreeBSD|OpenBSD
27
+ # `uname -o` => Android|Cygwin
28
+ [`uname -s`, `uname -o`].map(&:chomp).uniq
29
+ end
30
+ end
31
+
32
+ def nice_os_name
33
+ os_release.values_at("PRETTY_NAME", "NAME", "ID", "ID_LIKE").first ||
34
+ (`uname -o`.chomp rescue nil)
35
+ end
36
+
37
+ def installed
38
+ @@tools.select { |tool| File.which(tool.identifying_binary) }
39
+ end
40
+
41
+ def for_os(os_names=nil)
42
+ os_names = os_names ? [os_names].flatten : current_os_names
43
+
44
+ tool = nil
45
+
46
+ if os_names.any?
47
+ tool = @@tools.find { |name, tool| os_names.any? { |name| tool.os.include? name } }&.last
48
+ end
49
+
50
+ if tool.nil?
51
+ tool = @@tools.find { |name, tool| File.which(tool.identifying_binary) }&.last
52
+ end
53
+
54
+ tool
55
+ end
56
+
57
+ end
58
+ end
59
+ end
@@ -0,0 +1,144 @@
1
+ module UPM
2
+ class Tool
3
+ module DSL
4
+ def identifying_binary(id_bin=nil)
5
+ if id_bin
6
+ @id_bin = id_bin
7
+ else
8
+ @id_bin || @name
9
+ end
10
+ end
11
+
12
+ def prefix(name)
13
+ @prefix = name
14
+ end
15
+
16
+ def command(name, shell_command=nil, root: false, paged: false, highlight: nil, &block)
17
+ @cmds ||= {}
18
+
19
+ if block_given?
20
+ @cmds[name] = block
21
+ elsif shell_command
22
+ if shell_command.is_a? String
23
+ shell_command = shell_command.split
24
+ elsif not shell_command.is_a? Array
25
+ raise "Error: command argument must be a String or an Array; it was a #{cmd.class}"
26
+ end
27
+
28
+ @cmds[name] = proc do |args|
29
+ query = highlight && args.join(" ")
30
+ run(*shell_command, *args, paged: paged, root: root, highlight: query)
31
+ end
32
+ end
33
+ end
34
+
35
+ def os(*names)
36
+ names.any? ? @os = names : @os
37
+ end
38
+
39
+ ## Helpers
40
+
41
+ def run(*args, root: false, paged: false, grep: nil, highlight: nil)
42
+ if root
43
+ if Process.uid != 0
44
+ if File.which("sudo")
45
+ args.unshift "sudo"
46
+ elsif File.which("su")
47
+ args = ["su", "-c"] + args
48
+ else
49
+ raise "Error: You must be root to run this command. (And I couldn't find the 'sudo' *or* 'su' commands.)"
50
+ end
51
+ end
52
+ end
53
+
54
+ if !paged and !grep
55
+ system(*args)
56
+ else
57
+
58
+ IO.popen(args, err: [:child, :out]) do |command_io|
59
+
60
+ # if grep
61
+ # pattern = grep.is_a?(Regexp) ? grep.source : grep.to_s
62
+ # grep_io = IO.popen(["grep", "--color=always", "-Ei", pattern], "w+")
63
+ # IO.copy_stream(command_io, grep_io)
64
+ # grep_io.close_write
65
+ # command_io = grep_io
66
+ # end
67
+
68
+ # if paged
69
+ # lesspipe do |less|
70
+ # IO.copy_stream(command_io, less)
71
+ # end
72
+ # else
73
+ # IO.copy_stream(command_io, STDOUT)
74
+ # end
75
+
76
+ highlight_proc = if highlight
77
+ proc { |line| line.gsub(highlight) { |m| "\e[33;1m#{m}\e[0m" } }
78
+ else
79
+ proc { |line| line }
80
+ end
81
+
82
+ grep_proc = if grep
83
+ proc { |line| line[grep] }
84
+ else
85
+ proc { true }
86
+ end
87
+
88
+ lesspipe(disabled: !paged) do |less|
89
+ command_io.each_line do |line|
90
+ less.puts highlight_proc.(line) if grep_proc.(line)
91
+ end
92
+ end
93
+
94
+ end
95
+
96
+ $?.to_i == 0
97
+ end
98
+ end
99
+
100
+ def print_files(*paths, include: nil, exclude: nil)
101
+ lesspipe do |less|
102
+ paths.each do |path|
103
+ less.puts "<8>=== <11>#{path} <8>========".colorize
104
+ open(path) do |io|
105
+ enum = io.each_line
106
+ enum = enum.grep(include) if include
107
+ enum = enum.reject { |line| line[exclude] } if exclude
108
+ enum.each { |line| less.puts line }
109
+ end
110
+ less.puts
111
+ end
112
+ end
113
+ end
114
+
115
+ def call_command(name, *args)
116
+ if block = (@cmds[name] || @cmds[ALIASES[name]])
117
+ block.call args
118
+ else
119
+ puts "Command #{name} not supported in #{@name}"
120
+ end
121
+ end
122
+
123
+ def help
124
+ if osname = Tool.nice_os_name
125
+ puts " Detected OS: #{osname}"
126
+ end
127
+
128
+ puts "Package manager: #{@name}"
129
+ puts
130
+ puts "Available commands:"
131
+ available = COMMAND_HELP.select do |name, desc|
132
+ names = name.split("/")
133
+ names.any? { |name| @cmds[name] }
134
+ end
135
+
136
+ max_width = available.map(&:first).map(&:size).max
137
+ available.each do |name, desc|
138
+ puts " #{name.rjust(max_width)} | #{desc}"
139
+ end
140
+ end
141
+
142
+ end # DSL
143
+ end # Tool
144
+ end # UPM
@@ -1,3 +1,4 @@
1
+
1
2
  UPM::Tool.new "pacman" do
2
3
 
3
4
  os "arch"
@@ -9,17 +10,25 @@ UPM::Tool.new "pacman" do
9
10
  command "upgrade", [*bin, "-Syu"], root: true
10
11
  command "remove", [*bin, "-R"], root: true
11
12
 
13
+ # command "check", [*bin, "-Qkk"]
14
+ command "verify" do |args|
15
+ require 'upm/pacman_verifier'
16
+ UPM::PacmanVerifier.new.verify!(*args)
17
+ end
18
+
19
+ command "audit", "arch-audit", paged: true
12
20
  command "files", [*bin, "-Ql"], paged: true
13
21
  command "search", [*bin, "-Ss"], paged: true
14
22
 
23
+
15
24
  command "info" do |args|
16
- run(*bin, "-Qi", *args) || run(*bin, "-Si", *args)
25
+ run(*bin, "-Qi", *args, paged: true) || run(*bin, "-Si", *args, paged: true)
17
26
  end
18
27
 
19
28
  command "list" do |args|
20
29
  if args.any?
21
30
  query = args.join
22
- run(*bin, "-Q", grep: query, paged: true)
31
+ run(*bin, "-Q", grep: query, highlight: query, paged: true)
23
32
  else
24
33
  run(*bin, "-Q", paged: true)
25
34
  end
@@ -0,0 +1,24 @@
1
+ UPM::Tool.new "pkg" do
2
+
3
+ os "FreeBSD"
4
+
5
+ command "install", "pkg install", root: true
6
+ command "update", "pkg update", root: true
7
+ command "upgrade", "pkg upgrade", root: true
8
+ command "info", "pkg clean", root: true
9
+ command "check", "pkg check --checksums", root: true
10
+
11
+ command "files", "pkg list", paged: true
12
+ command "search", "pkg search", paged: true, highlight: true
13
+ command "info", "pkg info", paged: true
14
+
15
+ command "list" do |args|
16
+ if args.any?
17
+ query = args.join
18
+ run "pkg", "info", grep: query, highlight: query, paged: true
19
+ else
20
+ run "pkg", "info", paged: true
21
+ end
22
+ end
23
+
24
+ end
@@ -4,18 +4,19 @@ UPM::Tool.new "xbps" do
4
4
 
5
5
  identifying_binary "xbps-install"
6
6
 
7
- command "install", "xbps-install", root: true
8
- command "update", "xbps-install -S", root: true
9
- command "upgrade", "xbps-install -Su", root: true
10
- command "files", "xbps-query -f"
11
- command "search", "xbps-query --regex -Rs"
12
- # command "info", ""
7
+ command "install", "xbps-install", root: true
8
+ command "update", "xbps-install -S", root: true
9
+ command "upgrade", "xbps-install -Su", root: true
10
+
11
+ command "files", "xbps-query -f", paged: true
12
+ command "search", "xbps-query --regex -Rs", paged: true
13
13
 
14
14
  command "list" do |args|
15
15
  if args.any?
16
- run "xbps-query", "-f", *args
16
+ query = args.join
17
+ run "xbps-query", "-l", grep: query, paged: true
17
18
  else
18
- run "xbps-query", "-l"
19
+ run "xbps-query", "-l", paged: true
19
20
  end
20
21
  end
21
22
 
@@ -0,0 +1,18 @@
1
+ require_relative "spec_helper"
2
+ require "upm/core_ext"
3
+
4
+ describe File do
5
+
6
+ it "whiches" do
7
+ File.which("ls").should == "/usr/bin/ls"
8
+ File.which("ls", "rm").should == ["/usr/bin/ls", "/usr/bin/rm"]
9
+ File.which("zzzzzzzzzzzzzzzzzzzzzzzzzzzz").should == nil
10
+ end
11
+
12
+ it "which_is_best?s" do
13
+ File.which_is_best?("ls", "rm", "sudo").should == "/usr/bin/ls"
14
+ File.which_is_best?("sudo").should == "/usr/bin/sudo"
15
+ File.which_is_best?("zzzzzzzzzzzzzzzzzz").should == nil
16
+ end
17
+
18
+ end
@@ -0,0 +1 @@
1
+ $:.unshift File.join(__dir__, "../lib")
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: upm
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.1.6
4
+ version: 0.1.7
5
5
  platform: ruby
6
6
  authors:
7
7
  - epitron
8
8
  autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
- date: 2018-05-04 00:00:00.000000000 Z
11
+ date: 2018-05-19 00:00:00.000000000 Z
12
12
  dependencies: []
13
13
  description: Wrap all known command-line package tools with a consistent and pretty
14
14
  interface.
@@ -33,10 +33,16 @@ files:
33
33
  - lib/upm/core_ext.rb
34
34
  - lib/upm/lesspipe.rb
35
35
  - lib/upm/log_parser.rb
36
+ - lib/upm/pacman_verifier.rb
36
37
  - lib/upm/tool.rb
38
+ - lib/upm/tool_class_methods.rb
39
+ - lib/upm/tool_dsl.rb
37
40
  - lib/upm/tools/apt.rb
38
41
  - lib/upm/tools/pacman.rb
42
+ - lib/upm/tools/pkg.rb
39
43
  - lib/upm/tools/xbps.rb
44
+ - spec/core_ext_spec.rb
45
+ - spec/spec_helper.rb
40
46
  homepage: http://github.com/epitron/upm/
41
47
  licenses:
42
48
  - WTFPL