readorder 1.0.0 → 2.0.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.
data/HISTORY CHANGED
@@ -1,4 +1,13 @@
1
1
  = Changelog
2
+
3
+ == Version 2.0.0 - 2009-08-24
4
+
5
+ === Enhancements
6
+
7
+ * complete rewrite of internal file sorting and temporary storage enabling
8
+ the 'readordering' of large lists of files.
9
+ * switch to amalgalite instead of rbtree for sorting and storage
10
+
2
11
  == Version 1.0.0
3
12
 
4
13
  * Initial public release
data/gemspec.rb CHANGED
@@ -21,10 +21,10 @@ Readorder::GEM_SPEC = Gem::Specification.new do |spec|
21
21
 
22
22
  # add dependencies here
23
23
  spec.add_dependency("configuration", "~> 0.0.5")
24
- spec.add_dependency("rbtree", "~> 0.2.1")
24
+ spec.add_dependency("amalgalite", "~> 0.11.0")
25
25
  spec.add_dependency("main", "~> 2.8.3")
26
26
  spec.add_dependency("logging", "~> 1.1.4")
27
- spec.add_dependency("hitimes", "~> 1.0.1")
27
+ spec.add_dependency("hitimes", "~> 1.0.4")
28
28
 
29
29
  spec.add_development_dependency( "rake", "~> 0.8.3")
30
30
 
@@ -16,6 +16,13 @@ end
16
16
 
17
17
  require 'rubygems'
18
18
  require 'logging'
19
+
20
+ # require amalgalite explicitly before hitimes explicitly because of
21
+ # using flat namespace on OSX
22
+ # http://blade.nagaokaut.ac.jp/cgi-bin/scat.rb/ruby/ruby-talk/344658
23
+ require 'amalgalite'
24
+ require 'hitimes'
25
+
19
26
  require 'readorder/version'
20
27
  require 'readorder/paths'
21
28
  require 'readorder/cli'
@@ -1,6 +1,5 @@
1
- require 'hitimes'
2
1
  require 'readorder/datum'
3
- require 'rbtree'
2
+ require 'readorder/results'
4
3
 
5
4
  module Readorder
6
5
  #
@@ -8,34 +7,27 @@ module Readorder
8
7
  # appropriate Datum instances
9
8
  #
10
9
  class Analyzer
11
- # an Array of Datum instances for files that cannot be processed
12
- attr_accessor :bad_data
10
+ # number of bad_data items encountered
11
+ attr_accessor :bad_data_count
12
+
13
+ # number of good_data items encountered
14
+ attr_accessor :good_data_count
13
15
 
14
- # an Array of Datum instances in the order they were processed
15
- attr_accessor :good_data
16
-
17
- # an RBTree of Datum instances of those files that were analyzed
18
- # in order by phyiscal disc block number. This only has items if
19
- # the physical block number was obtained. It is empty otherwise
20
- attr_accessor :physical_order
21
-
22
- # an RBTree of Datum instances of those files that were analyzed
23
- # in order by inode
24
- attr_accessor :inode_order
16
+ # The Results handler
17
+ attr_accessor :results
25
18
 
26
19
  #
27
20
  # Initialize the Analyzer with the Filelist object and whether or
28
21
  # not to gather the physical block size.
29
22
  #
30
- def initialize( filelist, get_physical = true )
23
+ def initialize( filelist, results, get_physical = true )
31
24
  @filelist = filelist
32
- @bad_data = []
33
- @good_data = []
34
- @physical_order = ::MultiRBTree.new
35
- @inode_order = ::MultiRBTree.new
36
25
  @get_physical = get_physical
37
26
  @size_metric = ::Hitimes::ValueMetric.new( 'size' )
38
27
  @time_metric = ::Hitimes::TimedMetric.new( 'time' )
28
+ @results = results
29
+ @bad_data_count = 0
30
+ @good_data_count = 0
39
31
  end
40
32
 
41
33
  #
@@ -60,30 +52,35 @@ module Readorder
60
52
  logger.info "Begin data collection"
61
53
  original_order = 0
62
54
  @filelist.each_line do |fname|
63
- #logger.debug " analyzing #{fname.strip}"
55
+ next if @results.has_datum_for_filename?( fname )
56
+ logger.debug " analyzing #{fname.strip}"
64
57
  @time_metric.measure do
65
58
  d = Datum.new( fname )
66
- d.collect( @get_physical )
67
- d.original_order = original_order
68
- if d.valid? then
69
- @good_data << d
70
- @size_metric.measure d.stat.size
71
- @inode_order[d.inode_number] = d
72
- if @get_physical then
73
- @physical_order[d.first_physical_block_number] = d
59
+ begin
60
+ d.collect( @get_physical )
61
+ d.original_order = original_order
62
+
63
+ @results.add_datum( d )
64
+
65
+ if d.valid? then
66
+ @size_metric.measure d.stat.size
67
+ @good_data_count += 1
68
+ else
69
+ @bad_data_count += 1
74
70
  end
75
- else
76
- @bad_data << d
71
+ rescue => e
72
+ logger.error "#{e} : #{d.to_hash.inspect}"
77
73
  end
78
74
  end
79
75
 
80
76
  if @time_metric.count % 10_000 == 0 then
81
- logger.info " processed #{@time_metric.count} at #{"%0.3f" % @time_metric.rate} files/sec"
77
+ logger.info " processed #{@time_metric.count} at #{"%0.3f" % @time_metric.rate} files/sec ( #{@good_data_count} good, #{@bad_data_count} bad )"
82
78
  end
83
79
  original_order += 1
84
80
  end
81
+ @results.flush
85
82
  logger.info " processed #{@time_metric.count} at #{"%0.3f" % @time_metric.rate} files/sec"
86
- logger.info " yielded #{@good_data.size} data points"
83
+ logger.info " yielded #{@good_data_count} data points"
87
84
  logger.info "End data collection"
88
85
  nil
89
86
  end
@@ -112,30 +109,30 @@ module Readorder
112
109
  s.puts "Files analyzed : #{"%12d" % @time_metric.count}"
113
110
  s.puts "Elapsed time : #{"%12d" % @time_metric.duration} seconds"
114
111
  s.puts "Collection Rate : #{"%16.3f" % @time_metric.rate} files/sec"
115
- s.puts "Good files : #{"%12d" % @good_data.size}"
112
+ s.puts "Good files : #{"%12d" % @good_data_count}"
116
113
  s.puts " average size : #{"%16.3f" % @size_metric.mean} bytes"
117
114
  s.puts " minimum size : #{"%16.3f" % @size_metric.min} bytes"
118
115
  s.puts " maximum size : #{"%16.3f" % @size_metric.max} bytes"
119
116
  s.puts " sum of sizes : #{"%12d" % @size_metric.sum} bytes"
120
- s.puts "Bad files : #{"%12d" % @bad_data.size}"
117
+ s.puts "Bad files : #{"%12d" % @bad_data_count}"
121
118
  return s.string
122
119
  end
123
120
 
124
121
  #
125
122
  # call-seq:
126
- # analyzer.dump_data_to( IO ) -> nil
123
+ # analyzer.dump_errors_to( IO ) -> nil
127
124
  #
128
125
  # write a csv to the _IO_ object passed in. The format is:
129
126
  #
130
- # error reason,filename
127
+ # error_reason,filename
131
128
  #
132
129
  # If there are no bad Datum instances then do not write anything.
133
130
  #
134
- def dump_bad_data_to( io )
135
- if bad_data.size > 0 then
131
+ def dump_errors_to( io )
132
+ if results.error_count > 0 then
136
133
  io.puts "error_reason,filename"
137
- bad_data.each do |d|
138
- io.puts "#{d.error_reason},#{d.filename}"
134
+ results.each_error do |d|
135
+ io.puts "#{d['error_reason']},#{d['filename']}"
139
136
  end
140
137
  end
141
138
  nil
@@ -144,7 +141,7 @@ module Readorder
144
141
 
145
142
  #
146
143
  # call-seq:
147
- # analyzer.dump_good_data_to( IO ) -> nil
144
+ # analyzer.dump_valid_to( IO ) -> nil
148
145
  #
149
146
  # Write a csv fo the _IO_ object passed in. The format is:
150
147
  #
@@ -153,17 +150,18 @@ module Readorder
153
150
  # The last two fields *physical_block_count* and *first_physical_block_number* are
154
151
  # only written if the analyzer was able to gather physical block information
155
152
  #
156
- def dump_good_data_to( io )
153
+ def dump_valid_to( io )
157
154
  fields = %w[ filename size inode_number ]
155
+ by_field = 'inode_number'
158
156
  if @get_physical then
159
157
  fields << 'physical_block_count'
160
158
  fields << 'first_physical_block_number'
159
+ by_field = 'first_physical_block_number'
161
160
  end
162
-
163
161
  io.puts fields.join(",")
164
- good_data.each do |d|
165
- f = fields.collect { |f| d.send( f ) }
166
- io.puts f.join(",")
162
+ results.each_valid_by_field( by_field ) do |d|
163
+ f = fields.collect { |f| d[f] }
164
+ io.puts f.join(",")
167
165
  end
168
166
  end
169
167
  end
@@ -36,6 +36,7 @@ module Readorder
36
36
  mixin :argument_filelist
37
37
  mixin :option_output
38
38
  mixin :option_error_filelist
39
+ mixin :option_batch_size
39
40
 
40
41
  run { Cli.run_command_with_params( 'sort', params ) }
41
42
  }
@@ -51,6 +52,7 @@ module Readorder
51
52
  mixin :argument_filelist
52
53
  mixin :option_output
53
54
  mixin :option_error_filelist
55
+ mixin :option_batch_size
54
56
 
55
57
  option( 'data-csv' ) {
56
58
  description "Write the raw data collected to this csv file"
@@ -91,6 +93,7 @@ module Readorder
91
93
  mixin :option_output
92
94
  mixin :argument_filelist
93
95
  mixin :option_error_filelist
96
+ mixin :option_batch_size
94
97
 
95
98
  run { Cli.run_command_with_params( 'test', params ) }
96
99
  }
@@ -137,6 +140,15 @@ module Readorder
137
140
  validate { |f| File.directory?( File.dirname(File.expand_path( f ) ) ) }
138
141
  end
139
142
  end
143
+
144
+ mixin :option_batch_size do
145
+ option('batch-size' ) do
146
+ description "The number of files to queue before writing them to the db for storage"
147
+ argument :required
148
+ default 10_000
149
+ cast :integer
150
+ end
151
+ end
140
152
  }
141
153
 
142
154
 
@@ -32,6 +32,7 @@ module Readorder
32
32
  @filelist = nil
33
33
  @analyzer = nil
34
34
  @output = nil
35
+ @delete_results = true
35
36
  end
36
37
 
37
38
  def filelist
@@ -47,7 +48,21 @@ module Readorder
47
48
  end
48
49
 
49
50
  def analyzer
50
- @analyzer ||= Analyzer.new( filelist, self.get_physical? )
51
+ @analyzer ||= Analyzer.new( filelist, self.results, self.get_physical? )
52
+ end
53
+
54
+ def results_dbfile
55
+ if options['output'] then
56
+ output_dname = File.dirname( options['output'] )
57
+ output_bname = File.basename( options['output'], '.*' )
58
+ return File.join( output_dname, "#{output_bname}.db" )
59
+ else
60
+ return ":memory:"
61
+ end
62
+ end
63
+
64
+ def results
65
+ @results ||= Results.new( results_dbfile, options['batch-size'] )
51
66
  end
52
67
 
53
68
  def output
@@ -94,24 +109,32 @@ module Readorder
94
109
  end
95
110
 
96
111
  # called by the Runner if an error is encountered during the run method
97
- def error() nil; end
112
+ def error()
113
+ results.close
114
+ end
98
115
 
99
116
  # called by runner if a signal is hit
100
- def shutdown() nil; end
117
+ def shutdown()
118
+ results.close
119
+ @delete_results = false
120
+ end
101
121
 
102
122
  # called by runner when all is done
103
123
  def after()
104
- if output != $stdout then
105
- output.close
106
- end
107
124
  if options['error-filelist'] then
108
- if analyzer.bad_data.size > 0 then
125
+ if analyzer.bad_data_count > 0 then
109
126
  File.open( options['error-filelist'], "w+" ) do |f|
110
- analyzer.dump_bad_data_to( f )
127
+ analyzer.dump_errors_to( f )
111
128
  end
112
129
  logger.info "wrote error filelist to #{options['error-filelist']}"
113
130
  end
114
131
  end
132
+
133
+ if output != $stdout then
134
+ output.close
135
+ results.close
136
+ File.unlink( results_dbfile ) if @delete_results
137
+ end
115
138
  end
116
139
 
117
140
  class << self
@@ -7,18 +7,21 @@ module Readorder
7
7
  #
8
8
  class Sort < ::Readorder::Command
9
9
  def run
10
+
10
11
  analyzer.collect_data
11
12
  analyzer.log_summary_report
12
- data = nil
13
+
14
+ field = nil
13
15
  if get_physical? then
14
- logger.info "using physical order"
15
- data = analyzer.physical_order
16
+ logger.info "using first physical block number order"
17
+ field = 'first_physical_block_number'
16
18
  else
17
- logger.info "using inode order"
18
- data = analyzer.inode_order
19
+ logger.info "using inode number order"
20
+ field = 'inode_number'
19
21
  end
20
- data.values.each do |d|
21
- output.puts d.filename
22
+
23
+ analyzer.results.each_valid_by_field( field ) do |row|
24
+ output.puts row['filename']
22
25
  end
23
26
  end
24
27
  end
@@ -36,6 +36,10 @@ module Readorder
36
36
  @is_linux ||= ::Config::CONFIG['host_os'] =~ /linux/i
37
37
  end
38
38
 
39
+ def self.hash_keys
40
+ %w[ filename inode_number first_physical_block_number original_order size ]
41
+ end
42
+
39
43
  #
40
44
  # call-seq:
41
45
  # Datum.new( filename ) -> Datum
@@ -49,12 +53,39 @@ module Readorder
49
53
  @physical_block_count = 0
50
54
  @error_reason = nil
51
55
  @original_order = 0
56
+ @size = 0
52
57
 
53
58
  @stat = nil
54
59
  @valid = false
55
60
  @collected = false
56
61
  end
57
62
 
63
+ #
64
+ # call-seq:
65
+ # datum.to_csv
66
+ #
67
+ # return the datum as a CSV in the format:
68
+ #
69
+ # physical_id,inode_id,filename
70
+ #
71
+ def to_csv
72
+ "#{first_physical_block_number},#{inode_number},#{filename}"
73
+ end
74
+
75
+ #
76
+ # :call-seq;
77
+ # datum.to_hash -> Hash
78
+ #
79
+ # return all the tiems in the datum as a hash
80
+ #
81
+ def to_hash
82
+ h = {}
83
+ Datum.hash_keys.each do |k|
84
+ h[k] = self.send( k )
85
+ end
86
+ return h
87
+ end
88
+
58
89
  #
59
90
  # call-seq:
60
91
  # datum.size -> Integer
@@ -62,7 +93,7 @@ module Readorder
62
93
  # The number of bytes the file consumes
63
94
  #
64
95
  def size
65
- @stat.size
96
+ @size ||= @stat.size
66
97
  end
67
98
 
68
99
  #
@@ -0,0 +1,224 @@
1
+ require 'amalgalite'
2
+
3
+ module Readorder
4
+ # Results persists the results from a readorder run
5
+ # The results are persisted in an SQlite3 database which allows for ordering
6
+ # the results by whatever means are wanted.
7
+ class Results
8
+ def self.create_table_sql
9
+ sql = <<-SQL
10
+ CREATE TABLE readorder_valid (
11
+ original_order INTEGER PRIMARY KEY NOT NULL,
12
+ size INTEGER NOT NULL,
13
+ inode_number INTEGER NOT NULL UNIQUE,
14
+ first_physical_block_number INTEGER UNIQUE,
15
+ physical_block_count INTEGER,
16
+ filename TEXT NOT NULL UNIQUE
17
+ );
18
+
19
+ CREATE TABLE readorder_errors (
20
+ original_order INTEGER PRIMARY KEY NOT NULL,
21
+ filename TEXT NOT NULL UNIQUE,
22
+ error_reason TEXT NOT NULL
23
+ );
24
+ SQL
25
+ end
26
+
27
+ #
28
+ # :call-seq:
29
+ # Results.new( filename, 10_000 ) -> results
30
+ #
31
+ # Create a new Results object with a batch size. The batch size is how many
32
+ # items to queue up to run in a single transaction into the sqlite database.
33
+ #
34
+ # By default the batch size is 1 which is not very performant.
35
+ #
36
+ def initialize( filename, batch_size = 1 )
37
+ @db = Amalgalite::Database.new( filename )
38
+
39
+ unless @db.schema.tables['readorder_valid'] then
40
+ logger.info "Creating tables"
41
+ @db.execute_batch( Results.create_table_sql )
42
+ end
43
+ @db.reload_schema!
44
+ @batch_size = batch_size
45
+ @valid_queue = []
46
+ @error_queue = []
47
+ end
48
+
49
+ def close
50
+ flush
51
+ @db.close
52
+ end
53
+
54
+ def flush
55
+ flush_valid
56
+ flush_error
57
+ end
58
+
59
+ def logger
60
+ Logging::Logger[ self ]
61
+ end
62
+
63
+ #
64
+ # :call-seq:
65
+ # results.has_datum_for_filename?( filename )
66
+ #
67
+ # return true or false if the give filename is alread in the database
68
+ #
69
+ def has_datum_for_filename?( filename )
70
+ @db.first_value_from( "SELECT filename FROM readorder_valid WHERE filename = ?", filename )
71
+ end
72
+
73
+ #
74
+ # :call-seq:
75
+ # results.add_datum( datum )
76
+ #
77
+ # add a datum to the database, this will insert the datum into either valid
78
+ # or errors depending on the state of datum.valid?
79
+ #
80
+ def add_datum( datum )
81
+ if datum.valid?
82
+ @valid_queue << datum
83
+ else
84
+ @error_queue << datum
85
+ end
86
+ flush if ((@valid_queue.size + @error_queue.size) >= @batch_size )
87
+ end
88
+
89
+ #
90
+ # :call-seq:
91
+ # results.flush_valid
92
+ #
93
+ # Flush all the pending valid items to the sqlite database
94
+ #
95
+ def flush_valid
96
+ if @valid_queue.size > 0 then
97
+ logger.info "Flushing #{@valid_queue.size} valid items to disk"
98
+ sql = <<-insert
99
+ INSERT INTO readorder_valid ( original_order,
100
+ size,
101
+ inode_number,
102
+ first_physical_block_number,
103
+ physical_block_count,
104
+ filename )
105
+ VALUES( ?, ?, ?, ?, ?, ? );
106
+ insert
107
+ @db.transaction do |trans|
108
+ trans.prepare( sql ) do |stmt|
109
+ until @valid_queue.empty? do
110
+ datum = @valid_queue.shift
111
+ stmt.execute( datum.original_order,
112
+ datum.size,
113
+ datum.inode_number,
114
+ datum.first_physical_block_number,
115
+ datum.physical_block_count,
116
+ datum.filename)
117
+ end
118
+ end
119
+ end
120
+ end
121
+ end
122
+
123
+ # :call-seq:
124
+ # results.valid_count -> Integer
125
+ #
126
+ # return the number of valid result rows
127
+ #
128
+ def valid_count
129
+ @db.first_value_from( "SELECT count(original_order) FROM readorder_valid" )
130
+ end
131
+
132
+
133
+ #
134
+ # :call-seq:
135
+ # results.each_valid { |v| ... }
136
+ #
137
+ # Return each valid record without any predefined order
138
+ #
139
+ def each_valid( &block )
140
+ @db.execute( "SELECT * FROM readorder_valid" ) do |row|
141
+ yield row
142
+ end
143
+ end
144
+
145
+ #
146
+ # :call-seq:
147
+ # results.each_valid_by_physical_block_number { |v| ... }
148
+ #
149
+ # Return each valid record in physical block number order
150
+ #
151
+ def each_valid_by_first_physical_block_number( &block )
152
+ each_valid_by_field( 'first_physical_block_number' ) do |row|
153
+ block.call( row )
154
+ end
155
+ end
156
+
157
+ #
158
+ # :call-seq:
159
+ # results.each_valid_by_inode_number { |v| ... }
160
+ #
161
+ def each_valid_by_inode_number( &block )
162
+ each_valid_by_field( 'inode_number' ) do |row|
163
+ block.call( row )
164
+ end
165
+ end
166
+
167
+ #
168
+ # :call-seq:
169
+ # results.each_valid_by_field( field ) { |v| ... }
170
+ #
171
+ def each_valid_by_field( field, &block )
172
+ @db.execute( "SELECT * from readorder_valid ORDER BY #{field} ASC" ) do |row|
173
+ yield row
174
+ end
175
+ end
176
+
177
+ # :call-seq:
178
+ # results.flush_error
179
+ #
180
+ # Flush all the error items to disk
181
+ #
182
+ def flush_error
183
+ if @error_queue.size > 0 then
184
+ logger.info "Flushing #{@error_queue.size} error items to disk"
185
+ sql = <<-insert
186
+ INSERT INTO readorder_errors ( original_order, filename, error_reason )
187
+ VALUES( ?, ?, ? );
188
+ insert
189
+ @db.transaction do |trans|
190
+ trans.prepare( sql ) do |stmt|
191
+ until @error_queue.empty? do
192
+ datum = @error_queue.shift
193
+ stmt.execute( datum.original_order,
194
+ datum.filename,
195
+ datum.error_reason )
196
+ end
197
+ end
198
+ end
199
+ end
200
+ end
201
+
202
+ # :call-seq:
203
+ # results.error_count -> Integer
204
+ #
205
+ # return the number of errors
206
+ #
207
+ def error_count
208
+ @db.first_value_from( "SELECT count(original_order) FROM readorder_errors" )
209
+ end
210
+
211
+ #
212
+ # :call-seq:
213
+ # results.each_error { |e| ... }
214
+ #
215
+ # Return each error record without any predefined order
216
+ #
217
+ def each_error( &block )
218
+ @db.execute( "SELECT * FROM readorder_errors" ) do |row|
219
+ yield row
220
+ end
221
+ end
222
+
223
+ end
224
+ end
@@ -5,7 +5,7 @@
5
5
 
6
6
  module Readorder
7
7
  module Version
8
- MAJOR = 1
8
+ MAJOR = 2
9
9
  MINOR = 0
10
10
  BUILD = 0
11
11
 
@@ -5,18 +5,27 @@ require 'readorder/analyzer'
5
5
  describe Readorder::Analyzer do
6
6
  before( :each ) do
7
7
  s = StringIO.new
8
- fl = Dir.glob("#{Readorder::Paths.spec_path}/*_spec.rb")
9
- s.puts fl.to_a.join("\n")
8
+ fl = Dir.glob("#{Readorder::Paths.spec_path}*_spec.rb")
9
+ s.write( fl.join("\n") )
10
10
  s.rewind
11
+
11
12
  @filelist = Readorder::Filelist.new( s )
12
- @analyzer = Readorder::Analyzer.new( @filelist, false )
13
+ @r = Readorder::Results.new( ":memory:" )
14
+
15
+ @analyzer = Readorder::Analyzer.new( @filelist, @r , false )
16
+ end
17
+
18
+ after( :each ) do
19
+ @r.close
13
20
  end
14
21
 
15
22
  it "collects data about files" do
16
23
  @analyzer.collect_data
17
- @analyzer.good_data.size.should > 0
18
- @analyzer.inode_order.size.should > 0
19
- @analyzer.physical_order.size.should == 0
24
+ @analyzer.results.valid_count.should > 0
25
+ check_count = 0
26
+ @analyzer.results.each_valid { |v| check_count += 1 }
27
+ check_count.should > 0
28
+ check_count.should == @analyzer.results.valid_count
20
29
  end
21
30
 
22
31
  it "logs a summary report" do
@@ -29,12 +38,12 @@ describe Readorder::Analyzer do
29
38
  s = StringIO.new
30
39
  s.puts "/a/nonexistent/file"
31
40
  s.rewind
32
- analyzer = Readorder::Analyzer.new( Readorder::Filelist.new( s ) )
41
+ analyzer = Readorder::Analyzer.new( Readorder::Filelist.new( s ), @r, false )
33
42
  analyzer.collect_data
34
- analyzer.bad_data.size.should > 0
43
+ analyzer.results.error_count.should > 0
35
44
 
36
45
  s2 = StringIO.new
37
- analyzer.dump_bad_data_to( s2 )
46
+ analyzer.dump_errors_to( s2 )
38
47
  s2.rewind
39
48
  s2.gets.should == "error_reason,filename\n"
40
49
  s2.gets.should == "No such file or directory - /a/nonexistent/file,/a/nonexistent/file\n"
@@ -43,9 +52,25 @@ describe Readorder::Analyzer do
43
52
  it "can dump good data to a csv" do
44
53
  @analyzer.collect_data
45
54
  s = StringIO.new
46
- @analyzer.dump_good_data_to( s )
55
+ @analyzer.dump_valid_to( s )
47
56
  s.rewind
48
57
  s.gets.should == "filename,size,inode_number\n"
49
- s.read.split("\n").size.should == @analyzer.good_data.size
58
+ s.read.split("\n").size.should == @analyzer.results.valid_count
59
+ end
60
+
61
+ it "can iterate over inode block numbers" do
62
+ @analyzer.collect_data
63
+ by_order = []
64
+ @analyzer.results.each_valid_by_field( 'original_order' ) do |r|
65
+ by_order << r['filename']
66
+ end
67
+
68
+ by_inode = []
69
+ @analyzer.results.each_valid_by_inode_number do |r|
70
+ by_inode << r['filename']
71
+ end
72
+
73
+ by_order.should_not == by_inode
74
+ by_order.sort.should == by_inode.sort
50
75
  end
51
76
  end
@@ -18,7 +18,7 @@ if pkg_config = Configuration.for_if_exist?("packaging") then
18
18
 
19
19
  desc "Install as a gem"
20
20
  task :install => [:clobber, :package] do
21
- sh "sudo gem install pkg/#{Readorder::GEM_SPEC.full_name}.gem"
21
+ sh "sudo gem install pkg/#{Readorder::GEM_SPEC.full_name}.gem --no-rdoc --no-ri --ignore-dependencies --local"
22
22
  end
23
23
 
24
24
  desc "Uninstall gem"
metadata CHANGED
@@ -1,7 +1,7 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: readorder
3
3
  version: !ruby/object:Gem::Version
4
- version: 1.0.0
4
+ version: 2.0.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - Jeremy Hinegardner
@@ -9,7 +9,7 @@ autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
11
 
12
- date: 2009-06-27 00:00:00 -06:00
12
+ date: 2009-08-24 00:00:00 -06:00
13
13
  default_executable:
14
14
  dependencies:
15
15
  - !ruby/object:Gem::Dependency
@@ -23,14 +23,14 @@ dependencies:
23
23
  version: 0.0.5
24
24
  version:
25
25
  - !ruby/object:Gem::Dependency
26
- name: rbtree
26
+ name: amalgalite
27
27
  type: :runtime
28
28
  version_requirement:
29
29
  version_requirements: !ruby/object:Gem::Requirement
30
30
  requirements:
31
31
  - - ~>
32
32
  - !ruby/object:Gem::Version
33
- version: 0.2.1
33
+ version: 0.11.0
34
34
  version:
35
35
  - !ruby/object:Gem::Dependency
36
36
  name: main
@@ -60,7 +60,7 @@ dependencies:
60
60
  requirements:
61
61
  - - ~>
62
62
  - !ruby/object:Gem::Version
63
- version: 1.0.1
63
+ version: 1.0.4
64
64
  version:
65
65
  - !ruby/object:Gem::Dependency
66
66
  name: rake
@@ -92,6 +92,7 @@ extra_rdoc_files:
92
92
  - lib/readorder/filelist.rb
93
93
  - lib/readorder/log.rb
94
94
  - lib/readorder/paths.rb
95
+ - lib/readorder/results.rb
95
96
  - lib/readorder/runner.rb
96
97
  - lib/readorder/version.rb
97
98
  - lib/readorder.rb
@@ -107,6 +108,7 @@ files:
107
108
  - lib/readorder/filelist.rb
108
109
  - lib/readorder/log.rb
109
110
  - lib/readorder/paths.rb
111
+ - lib/readorder/results.rb
110
112
  - lib/readorder/runner.rb
111
113
  - lib/readorder/version.rb
112
114
  - lib/readorder.rb