arr-pm 0.0.6 → 0.0.11

Sign up to get free protection for your applications and to get access to all the features.

Potentially problematic release.


This version of arr-pm might be problematic. Click here for more details.

checksums.yaml ADDED
@@ -0,0 +1,7 @@
1
+ ---
2
+ SHA256:
3
+ metadata.gz: ceb08ab00b24c659ee4f0fd42d8f5c8ad77416ffff3f89e8ee18ec46ddc58383
4
+ data.tar.gz: b53d4d64c24362fb2cf27606842d8352e9f7d184f9ba3b76eb1e33b3e13b2775
5
+ SHA512:
6
+ metadata.gz: 441b7c7a0d0851c3c4cadaf7e2e0f20d32388ba4df722ee3f76bfb3a34bb072739daf63739cf19e9d8f221a40a80f999ca47b2825043ded493d1f3363dec3e54
7
+ data.tar.gz: 815d8fff66bc8672b7e212f6c138795a9029b5e78032d26051ac114e306084f97d01519060427aeb50e9bca29dd49af5d5567370904d8881fc99179184811cd3
data/.rubocop.yml ADDED
@@ -0,0 +1,73 @@
1
+ # Let's not argue over this...
2
+ StringLiterals:
3
+ Enabled: false
4
+
5
+ # I can't find a reason for raise vs fail.
6
+ SignalException:
7
+ Enabled: false
8
+
9
+ # I can't find a reason to prefer 'map' when 'collect' is what I mean.
10
+ # I'm collecting things from a list. Maybe someone can help me understand the
11
+ # semantics here.
12
+ CollectionMethods:
13
+ Enabled: false
14
+
15
+ # Why do you even *SEE* trailing whitespace? Because your editor was
16
+ # misconfigured to highlight trailing whitespace, right? Maybe turn that off?
17
+ # ;)
18
+ TrailingWhitespace:
19
+ Enabled: false
20
+
21
+ # Line length is another weird problem that somehow in the past 40 years of
22
+ # computing we don't seem to have solved. It's a display problem :(
23
+ LineLength:
24
+ Max: 9000
25
+
26
+ # %w() vs [ "x", "y", ... ]
27
+ # The complaint is on lib/pleaserun/detector.rb's map of OS=>Runner,
28
+ # i'll ignore it.
29
+ WordArray:
30
+ MinSize: 5
31
+
32
+ # A 20-line method isn't too bad.
33
+ MethodLength:
34
+ Max: 20
35
+
36
+ # Hash rockets (=>) forever. Why? Not all of my hash keys are static symbols.
37
+ HashSyntax:
38
+ EnforcedStyle: hash_rockets
39
+
40
+ # I prefer explicit return. It makes it clear in the code that the
41
+ # code author intended to return a value from a method.
42
+ RedundantReturn:
43
+ Enabled: false
44
+
45
+ # My view on a readable case statement seems to disagree with
46
+ # what rubocop wants and it doesn't let me configure it other than
47
+ # enable/disable.
48
+ CaseIndentation:
49
+ Enabled: false
50
+
51
+ # module This::Module::Definition is good.
52
+ Style/ClassAndModuleChildren:
53
+ Enabled: true
54
+ EnforcedStyle: compact
55
+
56
+ # "in interpolation #{use.some("double quotes is ok")}"
57
+ Style/StringLiteralsInInterpolation:
58
+ Enabled: true
59
+ EnforcedStyle: double_quotes
60
+
61
+ # Long-block `if !something ... end` are more readable to me than `unless something ... end`
62
+ Style/NegatedIf:
63
+ Enabled: false
64
+
65
+ Style/NumericLiterals:
66
+ MinDigits: 6
67
+
68
+ # This kind of style "useless use of %x" assumes code is write-once.
69
+ Style/UnneededPercentX:
70
+ Enabled: false
71
+
72
+ Style/FileName:
73
+ Enabled: false
data/Gemfile CHANGED
@@ -1 +1,3 @@
1
- source :rubygems
1
+ source "https://rubygems.org"
2
+
3
+ gemspec
data/Guardfile ADDED
@@ -0,0 +1,77 @@
1
+ # A sample Guardfile
2
+ # More info at https://github.com/guard/guard#readme
3
+
4
+ ## Uncomment and set this to only include directories you want to watch
5
+ # directories %w(app lib config test spec features)
6
+
7
+ ## Uncomment to clear the screen before every task
8
+ # clearing :on
9
+
10
+ ## Guard internally checks for changes in the Guardfile and exits.
11
+ ## If you want Guard to automatically start up again, run guard in a
12
+ ## shell loop, e.g.:
13
+ ##
14
+ ## $ while bundle exec guard; do echo "Restarting Guard..."; done
15
+ ##
16
+ ## Note: if you are using the `directories` clause above and you are not
17
+ ## watching the project directory ('.'), then you will want to move
18
+ ## the Guardfile to a watched dir and symlink it back, e.g.
19
+ #
20
+ # $ mkdir config
21
+ # $ mv Guardfile config/
22
+ # $ ln -s config/Guardfile .
23
+ #
24
+ # and, you'll have to watch "config/Guardfile" instead of "Guardfile"
25
+
26
+ # Note: The cmd option is now required due to the increasing number of ways
27
+ # rspec may be run, below are examples of the most common uses.
28
+ # * bundler: 'bundle exec rspec'
29
+ # * bundler binstubs: 'bin/rspec'
30
+ # * spring: 'bin/rspec' (This will use spring if running and you have
31
+ # installed the spring binstubs per the docs)
32
+ # * zeus: 'zeus rspec' (requires the server to be started separately)
33
+ # * 'just' rspec: 'rspec'
34
+
35
+ guard :rspec, cmd: "bundle exec rspec" do
36
+ require "guard/rspec/dsl"
37
+ dsl = Guard::RSpec::Dsl.new(self)
38
+
39
+ # Feel free to open issues for suggestions and improvements
40
+
41
+ # RSpec files
42
+ rspec = dsl.rspec
43
+ watch(rspec.spec_helper) { rspec.spec_dir }
44
+ watch(rspec.spec_support) { rspec.spec_dir }
45
+ watch(rspec.spec_files)
46
+
47
+ # Ruby files
48
+ ruby = dsl.ruby
49
+ dsl.watch_spec_files_for(ruby.lib_files)
50
+
51
+ # Rails files
52
+ rails = dsl.rails(view_extensions: %w(erb haml slim))
53
+ dsl.watch_spec_files_for(rails.app_files)
54
+ dsl.watch_spec_files_for(rails.views)
55
+
56
+ watch(rails.controllers) do |m|
57
+ [
58
+ rspec.spec.("routing/#{m[1]}_routing"),
59
+ rspec.spec.("controllers/#{m[1]}_controller"),
60
+ rspec.spec.("acceptance/#{m[1]}")
61
+ ]
62
+ end
63
+
64
+ # Rails config changes
65
+ watch(rails.spec_helper) { rspec.spec_dir }
66
+ watch(rails.routes) { "#{rspec.spec_dir}/routing" }
67
+ watch(rails.app_controller) { "#{rspec.spec_dir}/controllers" }
68
+
69
+ # Capybara features specs
70
+ watch(rails.view_dirs) { |m| rspec.spec.("features/#{m[1]}") }
71
+
72
+ # Turnip features and steps
73
+ watch(%r{^spec/acceptance/(.+)\.feature$})
74
+ watch(%r{^spec/acceptance/steps/(.+)_steps\.rb$}) do |m|
75
+ Dir[File.join("**/#{m[1]}.feature")][0] || "spec/acceptance"
76
+ end
77
+ end
data/Makefile CHANGED
@@ -3,25 +3,6 @@ VERSION=$(shell awk -F\" '/spec.version/ { print $$2 }' $(GEMSPEC))
3
3
  NAME=$(shell awk -F\" '/spec.name/ { print $$2 }' $(GEMSPEC))
4
4
  GEM=$(NAME)-$(VERSION).gem
5
5
 
6
- .PHONY: test
7
- test:
8
- sh notify-failure.sh ruby test/all.rb
9
-
10
- .PHONY: testloop
11
- testloop:
12
- while true; do \
13
- $(MAKE) test; \
14
- $(MAKE) wait-for-changes; \
15
- done
16
-
17
- .PHONY: serve-coverage
18
- serve-coverage:
19
- cd coverage; python -mSimpleHTTPServer
20
-
21
- .PHONY: wait-for-changes
22
- wait-for-changes:
23
- -inotifywait --exclude '\.swp' -e modify $$(find $(DIRS) -name '*.rb'; find $(DIRS) -type d)
24
-
25
6
  .PHONY: package
26
7
  package: | $(GEM)
27
8
 
data/arr-pm.gemspec CHANGED
@@ -2,7 +2,7 @@ Gem::Specification.new do |spec|
2
2
  files = %x{git ls-files}.split("\n")
3
3
 
4
4
  spec.name = "arr-pm"
5
- spec.version = "0.0.6"
5
+ spec.version = "0.0.11"
6
6
  spec.summary = "RPM reader and writer library"
7
7
  spec.description = "This library allows to you to read and write rpm " \
8
8
  "packages. Written in pure ruby because librpm is not available " \
@@ -16,6 +16,8 @@ Gem::Specification.new do |spec|
16
16
 
17
17
  spec.authors = ["Jordan Sissel"]
18
18
  spec.email = ["jls@semicomplete.com"]
19
+
20
+ spec.add_development_dependency "flores", ">0"
19
21
  #spec.homepage = "..."
20
22
  end
21
23
 
data/cpio.rb ADDED
@@ -0,0 +1,202 @@
1
+ class BoundedIO
2
+ attr_reader :length
3
+ attr_reader :remaining
4
+
5
+ def initialize(io, length, &eof_callback)
6
+ @io = io
7
+ @length = length
8
+ @remaining = length
9
+
10
+ @eof_callback = eof_callback
11
+ @eof = false
12
+ end
13
+
14
+ def read(size=nil)
15
+ return nil if eof?
16
+ size = @remaining if size.nil?
17
+ data = @io.read(size)
18
+ @remaining -= data.bytesize
19
+ eof?
20
+ data
21
+ end
22
+
23
+ def sysread(size)
24
+ raise EOFError, "end of file reached" if eof?
25
+ read(size)
26
+ end
27
+
28
+ def eof?
29
+ return false if @remaining > 0
30
+ return @eof if @eof
31
+
32
+ @eof_callback.call
33
+ @eof = true
34
+ end
35
+ end
36
+
37
+ module CPIO
38
+ FIELDS = [
39
+ :magic, :ino, :mode, :uid, :gid, :nlink, :mtime, :filesize, :devmajor,
40
+ :devminor, :rdevmajor, :rdevminor, :namesize, :check
41
+ ]
42
+ end
43
+
44
+ class CPIO::ASCIIReader
45
+ FIELD_SIZES = {
46
+ :magic => 6,
47
+ :ino => 8,
48
+ :mode => 8,
49
+ :uid => 8,
50
+ :gid => 8,
51
+ :nlink => 8,
52
+ :mtime => 8,
53
+ :filesize => 8,
54
+ :devmajor => 8,
55
+ :devminor => 8,
56
+ :rdevmajor => 8,
57
+ :rdevminor => 8,
58
+ :namesize => 8,
59
+ :check => 8
60
+ }
61
+ HEADER_LENGTH = FIELD_SIZES.reduce(0) { |m, (_, v)| m + v }
62
+ HEADER_PACK = FIELD_SIZES.collect { |_, v| "A#{v}" }.join
63
+
64
+ FIELD_ORDER = [
65
+ :magic, :ino, :mode, :uid, :gid, :nlink, :mtime, :filesize, :devmajor,
66
+ :devminor, :rdevmajor, :rdevminor, :namesize, :check
67
+ ]
68
+
69
+ def initialize(io)
70
+ @io = io
71
+ end
72
+
73
+ private
74
+
75
+ def io
76
+ @io
77
+ end
78
+
79
+ def each(&block)
80
+ while true
81
+ entry = read
82
+ break if entry.nil?
83
+ # The CPIO format has the end-of-stream marker as a file called "TRAILER!!!"
84
+ break if entry.name == "TRAILER!!!"
85
+ block.call(entry, entry.file)
86
+ verify_correct_read(entry) unless entry.directory?
87
+ end
88
+ end
89
+
90
+ def verify_correct_read(entry)
91
+ # Read and throw away the whole file if not read at all.
92
+ entry.file.tap do |file|
93
+ if file.nil? || file.remaining == 0
94
+ # All OK! :)
95
+ elsif file.remaining == file.length
96
+ file.read(16384) while !file.eof?
97
+ else
98
+ # The file was only partially read? This should be an error by the
99
+ # user.
100
+ consumed = file.length - file.remaining
101
+ raise BadState, "Only #{consumed} bytes were read of the #{file.length} byte file: #{entry.name}"
102
+ end
103
+ end
104
+ end
105
+
106
+ def read
107
+ entry = CPIOEntry.new
108
+ header = io.read(HEADER_LENGTH)
109
+ return nil if header.nil?
110
+ FIELD_ORDER.zip(header.unpack(HEADER_PACK)).each do |field, value|
111
+ entry.send("#{field}=", value.to_i(16))
112
+ end
113
+
114
+ entry.validate
115
+ entry.mtime = Time.at(entry.mtime)
116
+ read_name(entry, @io)
117
+ read_file(entry, @io)
118
+ entry
119
+ end
120
+
121
+ def read_name(entry, io)
122
+ entry.name = io.read(entry.namesize - 1) # - 1 for null terminator
123
+ nul = io.read(1)
124
+ raise ArgumentError, "Corrupt CPIO or bug? Name null terminator was not null: #{nul.inspect}" if nul != "\0"
125
+ padding_data = io.read(padding_name(entry))
126
+ # Padding should be all null bytes
127
+ if padding_data != ("\0" * padding_data.bytesize)
128
+ raise ArgumentError, "Corrupt CPIO or bug? Name null padding was #{padding_name(entry)} bytes: #{padding_data.inspect}"
129
+ end
130
+ end
131
+
132
+ def read_file(entry, io)
133
+ if entry.directory?
134
+ entry.file = nil
135
+ #read_file_padding(entry, io)
136
+ nil
137
+ else
138
+ entry.file = BoundedIO.new(io, entry.filesize) do
139
+ read_file_padding(entry, io)
140
+ end
141
+ end
142
+ end
143
+
144
+ def read_file_padding(entry, io)
145
+ padding_data = io.read(padding_file(entry))
146
+ if padding_data != ("\0" * padding_data.bytesize)
147
+ raise ArgumentError, "Corrupt CPIO or bug? File null padding was #{padding_file(entry)} bytes: #{padding_data.inspect}"
148
+ end
149
+ end
150
+
151
+ def padding_name(entry)
152
+ # name padding is padding up to a multiple of 4 after header+namesize
153
+ -(HEADER_LENGTH + entry.namesize) % 4
154
+ end
155
+
156
+ def padding_file(entry)
157
+ (-(HEADER_LENGTH + entry.filesize + 2) % 4)
158
+ end
159
+ public(:each)
160
+ end
161
+
162
+ class CPIOEntry
163
+ CPIO::FIELDS.each do |field|
164
+ attr_accessor field
165
+ end
166
+
167
+ attr_accessor :name
168
+ attr_accessor :file
169
+
170
+ DIRECTORY_FLAG = 0040000
171
+
172
+ def validate
173
+ raise "Invalid magic #{magic.inspect}" if magic != 0x070701
174
+ raise "Invalid ino #{ino.inspect}" if ino < 0
175
+ raise "Invalid mode #{mode.inspect}" if mode < 0
176
+ raise "Invalid uid #{uid.inspect}" if uid < 0
177
+ raise "Invalid gid #{gid.inspect}" if gid < 0
178
+ raise "Invalid nlink #{nlink.inspect}" if nlink < 0
179
+ raise "Invalid mtime #{mtime.inspect}" if mtime < 0
180
+ raise "Invalid filesize #{filesize.inspect}" if filesize < 0
181
+ raise "Invalid devmajor #{devmajor.inspect}" if devmajor < 0
182
+ raise "Invalid devminor #{devminor.inspect}" if devminor < 0
183
+ raise "Invalid rdevmajor #{rdevmajor.inspect}" if rdevmajor < 0
184
+ raise "Invalid rdevminor #{rdevminor.inspect}" if rdevminor < 0
185
+ raise "Invalid namesize #{namesize.inspect}" if namesize < 0
186
+ raise "Invalid check #{check.inspect}" if check < 0
187
+ end # def validate
188
+
189
+ def read(*args)
190
+ return nil if directory?
191
+ file.read(*args)
192
+ end
193
+
194
+ def directory?
195
+ mode & DIRECTORY_FLAG > 0
196
+ end
197
+ end
198
+
199
+ CPIO::ASCIIReader.new(STDIN).each do |entry, file|
200
+ puts entry.name
201
+ file.read unless entry.directory?
202
+ end
data/lib/arr-pm/file.rb CHANGED
@@ -2,6 +2,7 @@ require File.join(File.dirname(__FILE__), "namespace")
2
2
  require File.join(File.dirname(__FILE__), "file", "header")
3
3
  require File.join(File.dirname(__FILE__), "file", "lead")
4
4
  require File.join(File.dirname(__FILE__), "file", "tag")
5
+ require "fcntl"
5
6
 
6
7
  # Much of the code here is derived from knowledge gained by reading the rpm
7
8
  # source code, but mostly it started making more sense after reading this site:
@@ -99,7 +100,11 @@ class RPM::File
99
100
 
100
101
  extractor = IO.popen("#{tags[:payloadcompressor]} -d | (cd #{target}; cpio -i --quiet --make-directories)", "w")
101
102
  buffer = ""
102
- buffer.force_encoding("BINARY")
103
+ begin
104
+ buffer.force_encoding("BINARY")
105
+ rescue NoMethodError
106
+ # Do Nothing
107
+ end
103
108
  payload_fd = payload.clone
104
109
  loop do
105
110
  data = payload_fd.read(16384, buffer)
@@ -158,24 +163,28 @@ class RPM::File
158
163
  #
159
164
  # @return Array of [ [name, operator, version], ... ]
160
165
  def conflicts
161
- return relation(:conflicts)
166
+ return relation(:conflict)
162
167
  end # def conflicts
163
168
 
164
169
  # Get an array of provides defined in this package.
165
170
  #
166
171
  # @return Array of [ [name, operator, version], ... ]
167
172
  def provides
168
- return relation(:provides)
173
+ return relation(:provide)
169
174
  end # def provides
170
175
 
171
176
  # Get an array of config files
172
177
  def config_files
173
178
  # this stuff seems to be in the 'enum rpmfileAttrs_e' from rpm/rpmfi.h
174
179
  results = []
175
- tags[:fileflags].each_with_index do |flag, i|
176
- # The :fileflags (and other :file... tags) are an array, in order of
177
- # files in the rpm payload, we want a list of paths of config files.
178
- results << files[i] if mask?(flag, FLAG_CONFIG_FILE)
180
+ # short-circuit if there's no :fileflags tag
181
+ return results unless tags.include?(:fileflags)
182
+ if !tags[:fileflags].nil?
183
+ tags[:fileflags].each_with_index do |flag, i|
184
+ # The :fileflags (and other :file... tags) are an array, in order of
185
+ # files in the rpm payload, we want a list of paths of config files.
186
+ results << files[i] if mask?(flag, FLAG_CONFIG_FILE)
187
+ end
179
188
  end
180
189
  return results
181
190
  end # def config_files
@@ -190,7 +199,11 @@ class RPM::File
190
199
 
191
200
  lister = IO.popen("#{tags[:payloadcompressor]} -d | cpio -it --quiet", "r+")
192
201
  buffer = ""
193
- buffer.force_encoding("BINARY")
202
+ begin
203
+ buffer.force_encoding("BINARY")
204
+ rescue NoMethodError
205
+ # Do Nothing
206
+ end
194
207
  payload_fd = payload.clone
195
208
  output = ""
196
209
  loop do
@@ -202,12 +215,23 @@ class RPM::File
202
215
  begin
203
216
  output << lister.read_nonblock(16384)
204
217
  rescue Errno::EAGAIN
205
- # do nothing
218
+ # Nothing to read, move on!
206
219
  end
207
220
  end
208
221
  lister.close_write
222
+
209
223
  # Read remaining output
210
- output << lister.read
224
+ begin
225
+ output << lister.read
226
+ rescue Errno::EAGAIN
227
+ # Because read_nonblock enables NONBLOCK the 'lister' fd,
228
+ # and we may have invoked a read *before* cpio has started
229
+ # writing, let's keep retrying this read until we get an EOF
230
+ retry
231
+ rescue EOFError
232
+ # At EOF, hurray! We're done reading.
233
+ end
234
+
211
235
  # Split output by newline and strip leading "."
212
236
  @files = output.split("\n").collect { |s| s.gsub(/^\./, "") }
213
237
  return @files