reapack-index 1.0beta4 → 1.0rc2

Sign up to get free protection for your applications and to get access to all the features.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA1:
3
- metadata.gz: b08f343ff91fe1f1f543b9ac82de72f698404ce8
4
- data.tar.gz: 3b4f0c39955b88ba41f3bdf0759d7531d57e32ca
3
+ metadata.gz: 5cbcf419229c7231caca844f3b7f9e6800261b24
4
+ data.tar.gz: e3a8eabd17b759e7125f39276371383263130081
5
5
  SHA512:
6
- metadata.gz: 545316c4c749f62d19f68b1f3cb82f447a5d8b0b7d9aaaaba815258ee86424e8f6c0e06cfa2c9ef8876b4eb52074f5a5ac193a954070602d859d2c078a4803cc
7
- data.tar.gz: b0f6a34ed77612b71fe28a62cea6f0b6b0a7375506e8a2ecfc9ac90496172b2c30228a8212a064ae8c78e9d26103155ff493fab5d749b14ae4e04f2e4e17c5b7
6
+ metadata.gz: 7e04598f176942c766ade75dc7ec901793d3a58383e9e4e648d364f869d3798bdbc7b5239574ccc71b247bd115500c1c6c434de41353adc2611cbda46ed2bbf8
7
+ data.tar.gz: 42ebb6abbc5043e80b858d01ec64b94ec8c550e0a11a0c1daa964f3a7823b83a4282ef476d2c1e738b2242e781912d7cfe48bdcbba48bb943becb4bc3382a2f0
data/README.md CHANGED
@@ -10,9 +10,10 @@ Subproject: [https://github.com/cfillion/metaheader](https://github.com/cfillion
10
10
 
11
11
  ### Installation
12
12
 
13
- Ruby 2 need to be installed on your computer and ready to be used from a command
14
- prompt. Run the following command from a command prompt (cmd.exe, Terminal.app,
15
- XTerm) to install reapack-index on your computer:
13
+ Ruby v2.3 or newer must be installed on your computer in order to install
14
+ and use this software.
15
+ Run the following command from a command prompt (eg. cmd.exe, Terminal.app,
16
+ XTerm) to install reapack-index:
16
17
 
17
18
  ```
18
19
  gem install reapack-index
@@ -28,6 +29,7 @@ reapack-index [options] [path-to-your-repository]
28
29
  Modes:
29
30
  -c, --check Test every package including uncommited changes and exit
30
31
  -s, --scan [COMMIT] Scan new commits (default) or specific commits
32
+ --rebuild Clear the index and rescan the whole git history
31
33
  Indexer options:
32
34
  -a, --[no-]amend Reindex existing versions
33
35
  -i, --ignore PATH Don't check or index any file starting with PATH
@@ -12,6 +12,7 @@ require 'pandoc-ruby'
12
12
  require 'pathname'
13
13
  require 'rugged'
14
14
  require 'shellwords'
15
+ require 'stable_sort'
15
16
  require 'time'
16
17
 
17
18
  require 'reapack/index/cdetector'
@@ -23,6 +24,7 @@ require 'reapack/index/named_node'
23
24
  require 'reapack/index/package'
24
25
  require 'reapack/index/parsers'
25
26
  require 'reapack/index/provides'
27
+ require 'reapack/index/scanner'
26
28
  require 'reapack/index/source'
27
29
  require 'reapack/index/version'
28
30
 
@@ -36,31 +38,10 @@ class ReaPack::Index
36
38
  data: %w{data},
37
39
  }.freeze
38
40
 
39
- WITH_MAIN = [:script, :effect].freeze
40
-
41
- PROVIDES_VALIDATOR = proc {|value|
42
- begin
43
- Provides.parse_each(value).to_a and nil
44
- rescue Error => e
45
- e.message
46
- end
47
- }
48
-
49
- HEADER_RULES = {
50
- # package-wide tags
51
- :version => [
52
- MetaHeader::REQUIRED, MetaHeader::VALUE, MetaHeader::SINGLELINE, /\d/],
53
-
54
- # version-specific tags
55
- :author => [MetaHeader::VALUE, MetaHeader::SINGLELINE],
56
- :changelog => [MetaHeader::VALUE],
57
- :provides => [MetaHeader::VALUE, PROVIDES_VALIDATOR]
58
- }.freeze
59
-
60
41
  FS_ROOT = File.expand_path('/').freeze
61
42
 
62
- attr_reader :path, :url_template
63
- attr_accessor :amend, :files, :time
43
+ attr_reader :path, :url_template, :cdetector
44
+ attr_accessor :amend, :commit, :files, :time
64
45
 
65
46
  class << self
66
47
  def is_type?(input)
@@ -125,11 +106,6 @@ class ReaPack::Index
125
106
  type = self.class.type_of path
126
107
  return unless type
127
108
 
128
- # variables to restore if an error occur
129
- backups = Hash[[:@doc, :@cdetector].map {|var|
130
- [var, instance_variable_get(var).clone]
131
- }]
132
-
133
109
  mh = MetaHeader.new contents
134
110
 
135
111
  if mh[:noindex]
@@ -137,42 +113,21 @@ class ReaPack::Index
137
113
  return
138
114
  end
139
115
 
140
- if errors = mh.validate(HEADER_RULES)
141
- raise Error, errors.join("\n")
142
- end
116
+ # variables to restore if an error occur
117
+ backups = Hash[[:@doc, :@cdetector].map {|var|
118
+ [var, instance_variable_get(var).clone]
119
+ }]
143
120
 
144
121
  cat, pkg = package_for path
122
+ pkg.type = type
145
123
 
146
- cselector = @cdetector[pkg.type = type, path]
147
-
148
- pkg.version mh[:version] do |ver|
149
- next unless ver.is_new? || @amend
124
+ scanner = Scanner.new cat, pkg, mh, self
150
125
 
151
- # store the version name for make_url
152
- @currentVersion = ver.name
153
-
154
- ver.author = mh[:author]
155
- ver.time = @time if @time && ver.is_new?
156
- ver.changelog = mh[:changelog]
157
-
158
- ver.replace_sources do
159
- cselector.clear
160
- sources = parse_provides mh[:provides], pkg
161
-
162
- if WITH_MAIN.include?(type) && sources.none? {|src| src.file.nil? }
163
- # add the package itself as a source
164
- src = Source.new make_url(path)
165
- sources.unshift src
166
-
167
- cselector.push src.platform, path
168
- end
169
-
170
- sources.each {|src| ver.add_source src }
171
- end
172
- end
173
-
174
- if cons = cselector.resolve
175
- raise Error, cons.first
126
+ begin
127
+ scanner.run
128
+ rescue Error
129
+ backups.each {|var, value| instance_variable_set var, value }
130
+ raise
176
131
  end
177
132
 
178
133
  log_change 'new category', 'new categories' if cat.is_new?
@@ -190,16 +145,13 @@ class ReaPack::Index
190
145
  }
191
146
 
192
147
  bump_commit
193
- rescue Error
194
- backups.each {|var, value| instance_variable_set var, value }
195
- raise
196
148
  end
197
-
149
+
198
150
  def remove(path)
199
151
  cat, pkg = package_for path, false
200
152
  return unless pkg
201
153
 
202
- @cdetector[pkg.type, path].clear
154
+ @cdetector[path].clear
203
155
 
204
156
  pkg.remove
205
157
  cat.remove if cat.empty?
@@ -253,7 +205,7 @@ class ReaPack::Index
253
205
  raise Addressable::URI::InvalidURIError
254
206
  end
255
207
 
256
- @url_template = uri.to_s.freeze
208
+ @url_template = tpl
257
209
  rescue Addressable::URI::InvalidURIError
258
210
  raise Error, "invalid template '#{tpl}'"
259
211
  end
@@ -276,17 +228,15 @@ class ReaPack::Index
276
228
  log_change 'modified metadata' if oldName != newName
277
229
  end
278
230
 
279
- def commit
280
- @commit ||= @doc.root[:commit]
231
+ def last_commit
232
+ @doc.root[:commit]
281
233
  end
282
234
 
283
- attr_writer :commit
284
-
285
235
  def write(path)
286
236
  sort @doc.root
287
237
 
288
238
  FileUtils.mkdir_p File.dirname(path)
289
- File.write path, @doc.to_xml
239
+ File.binwrite path, @doc.to_xml
290
240
  end
291
241
 
292
242
  def write!
@@ -313,21 +263,9 @@ class ReaPack::Index
313
263
  list.join ', '
314
264
  end
315
265
 
316
- def make_url(path, template = nil)
317
- unless template
318
- unless @url_template
319
- raise Error, 'unable to generate download links: empty url template'
320
- end
321
-
322
- unless @files.include? path
323
- raise Error, "file not found '#{path}'"
324
- end
325
- end
326
-
327
- (template || @url_template)
328
- .sub('$path', path)
329
- .sub('$commit', commit || 'master')
330
- .sub('$version', @currentVersion.to_s)
266
+ def clear
267
+ Category.find_all(@doc.root).each {|cat| cat.remove }
268
+ @cdetector.clear
331
269
  end
332
270
 
333
271
  def self.expand(filepath, basedir)
@@ -354,56 +292,19 @@ private
354
292
  [cat, pkg]
355
293
  end
356
294
 
357
- def parse_provides(provides, pkg)
358
- pathdir = Pathname.new pkg.category
359
-
360
- Provides.parse_each(provides).map {|line|
361
- line.file_pattern = pkg.name if line.file_pattern == '.'
362
-
363
- expanded = self.class.expand line.file_pattern, pkg.category
364
- cselector = @cdetector[line.type || pkg.type, pkg.path]
365
-
366
- if expanded == pkg.path
367
- # always resolve path even when an url template is set
368
- files = [expanded]
369
- elsif line.url_template.nil?
370
- files = @files.select {|f| File.fnmatch expanded, f, File::FNM_PATHNAME }
371
- raise Error, "file not found '#{line.file_pattern}'" if files.empty?
372
- else
373
- # use the relative path for external urls
374
- files = [line.file_pattern]
375
- end
376
-
377
- files.map {|file|
378
- src = Source.new make_url(file, line.url_template)
379
- src.platform = line.platform
380
- src.type = line.type
381
-
382
- cselector.push src.platform, line.url_template ? expanded : file
383
-
384
- if file != pkg.path
385
- if line.url_template
386
- src.file = file
387
- else
388
- src.file = Pathname.new(file).relative_path_from(pathdir).to_s
389
- end
390
- end
391
-
392
- src
393
- }
394
- }.flatten
395
- end
396
-
397
295
  def sort(node)
398
- node.children.each {|n| sort n }
399
-
296
+ node.element_children.map {|n| sort n }
400
297
  return if node.name == Package.tag
401
- sorted = node.children.sort_by{|n| n[:name].to_s }.sort_by {|n| n.name }
298
+
299
+ sorted = node.element_children
300
+ .stable_sort_by {|n| n[:name].to_s.downcase }
301
+ .stable_sort_by {|n| n.name.downcase }
302
+
402
303
  sorted.each {|n| node << n }
403
304
  end
404
305
 
405
306
  def bump_commit
406
- sha1 = commit()
307
+ sha1 = @commit || last_commit
407
308
 
408
309
  if sha1.nil?
409
310
  @doc.root.remove_attribute 'commit'
@@ -3,21 +3,26 @@ class ReaPack::Index
3
3
  Entry = Struct.new :key, :platform, :file
4
4
 
5
5
  class Selector
6
- def initialize(bucket, key, cdetector)
7
- @bucket, @key, @cdetector = bucket, key, cdetector
8
- @entries = @cdetector.bucket bucket
6
+ def initialize(key, cdetector)
7
+ @key, @cdetector = key, cdetector
9
8
  end
10
9
 
11
- def push(platform, file)
12
- @entries << Entry.new(@key, platform, file).freeze
10
+ def push(bucket, platform, file)
11
+ @cdetector.bucket(bucket) << Entry.new(@key, platform, file).freeze
13
12
  end
14
13
 
15
14
  def clear
16
- @entries.reject! {|e| e.key == @key }
15
+ @cdetector.buckets.each_value do |b|
16
+ b.reject! {|e| e.key == @key }
17
+ end
17
18
  end
18
19
 
19
20
  def resolve
20
- @cdetector.resolve @bucket, @key
21
+ errors = @cdetector.buckets.map do |b, _|
22
+ @cdetector.resolve b, @key
23
+ end.compact.flatten
24
+
25
+ errors unless errors.empty?
21
26
  end
22
27
  end
23
28
 
@@ -31,28 +36,33 @@ class ReaPack::Index
31
36
  Hash[@buckets.map {|k, v| [k, v.clone] }]
32
37
  end
33
38
 
34
- def [](bucket, key)
35
- Selector.new bucket, key, self
39
+ def [](key)
40
+ Selector.new key, self
36
41
  end
37
42
 
43
+ attr_reader :buckets
44
+
38
45
  def bucket(name)
46
+ raise ArgumentError, 'bucket name is not a symbol' unless name.is_a? Symbol
39
47
  @buckets[name] ||= []
40
48
  end
41
49
 
42
- def resolve(bucket, key = nil)
43
- return unless bucket = @buckets[bucket]
50
+ def clear
51
+ @buckets.clear
52
+ end
44
53
 
45
- dups = bucket.group_by {|e| e.file }.values.select {|a| a.size > 1 }
54
+ def resolve(bname, key = nil)
55
+ dups = bucket(bname).group_by {|e| e.file }.values.select {|a| a.size > 1 }
46
56
 
47
57
  errors = dups.map {|a|
48
58
  packages = a.map {|e| e.key }.uniq
49
59
  next if key && !packages.include?(key)
50
60
 
51
61
  if packages.size == 1 || !key
52
- original = sort(a)[1]
62
+ original = sort_platforms(a)[1]
53
63
  msg = "duplicate file '#{original.file}'"
54
64
  else
55
- original = sort(a.select {|e| e.key != key }).first
65
+ original = sort_platforms(a.select {|e| e.key != key }).first
56
66
  msg = "'#{original.file}' conflicts with '#{original.key}'"
57
67
  end
58
68
 
@@ -61,6 +71,7 @@ class ReaPack::Index
61
71
  if platforms.size > 1
62
72
  # check platform inheritance
63
73
  platforms.any? {|p|
74
+ break true unless Source::PLATFORMS[p]
64
75
  loop do
65
76
  p = Source::PLATFORMS[p] or break false
66
77
  break true if platforms.include? p
@@ -81,7 +92,9 @@ class ReaPack::Index
81
92
  pkgroot = File.join(cat.name, pkg.name)
82
93
 
83
94
  pkg.versions.last&.children(Source::TAG)&.each {|src|
84
- entry = Entry.new pkgroot, src[:platform].to_sym
95
+ type = src[:type] || pkg.type
96
+ platform = src[:platform] || :all
97
+ entry = Entry.new pkgroot, platform.to_sym
85
98
 
86
99
  if src[:file]
87
100
  entry.file = ReaPack::Index.expand(src[:file], cat.name)
@@ -89,16 +102,17 @@ class ReaPack::Index
89
102
  entry.file = pkgroot
90
103
  end
91
104
 
92
- bucket(pkg.type) << entry
105
+ bucket(type.to_sym) << entry
93
106
  }
94
107
  }
95
108
  }
96
109
  end
97
110
 
98
111
  private
99
- def sort(set)
100
- sorted = set.sort_by {|e| levels[e.platform] }
101
- sorted.sort_by! {|e| Source::PLATFORMS.keys.index e.platform }
112
+ def sort_platforms(set)
113
+ set.group_by {|e| levels[e.platform] || 0 }.sort
114
+ .map {|_, a| a.sort_by {|e| Source::PLATFORMS.keys.index(e.platform) || 0 } }
115
+ .flatten
102
116
  end
103
117
 
104
118
  def levels
@@ -77,10 +77,13 @@ private
77
77
  return
78
78
  end
79
79
 
80
- if @opts[:scan].empty?
81
- commits = @git.commits_since @index.commit.to_s
80
+ commits = if @opts[:rebuild]
81
+ @index.clear
82
+ @git.commits
83
+ elsif @opts[:scan].empty?
84
+ @git.commits_since @index.last_commit
82
85
  else
83
- commits = @opts[:scan].map {|hash|
86
+ @opts[:scan].map {|hash|
84
87
  @git.get_commit hash or begin
85
88
  $stderr.puts '--scan: bad revision: %s' % @opts[:scan]
86
89
  @exit = false
@@ -105,7 +108,9 @@ private
105
108
  @index.time = commit.time
106
109
  @index.files = commit.filelist
107
110
 
108
- commit.each_diff {|diff| process_diff diff }
111
+ commit.each_diff
112
+ .sort_by {|diff| diff.status == :deleted ? 0 : 1 }
113
+ .each {|diff| process_diff diff }
109
114
  ensure
110
115
  bump_progress
111
116
  end
@@ -190,18 +195,19 @@ private
190
195
  def do_check
191
196
  check_name
192
197
 
193
- @index.amend = true # enable checks for released versions as well
198
+ @index.clear
194
199
  failures = []
195
200
 
196
201
  pkgs = Hash[Dir.glob("#{Regexp.quote(@git.path)}/**/*").sort.map {|abs|
197
202
  rel = @git.relative_path abs
198
203
  @index.files << rel
199
204
 
200
- next if !File.file?(abs) || ignored?(abs) || !ReaPack::Index.is_package?(abs)
205
+ next if !File.file?(abs) || ignored?(abs) || !ReaPack::Index.is_package?(rel)
201
206
 
202
207
  [abs, rel]
203
208
  }.compact]
204
209
 
210
+ # reiterate over the pkg list after registering every file
205
211
  pkgs.each_pair {|abs, rel|
206
212
  begin
207
213
  @index.scan rel, File.read(abs)
@@ -9,6 +9,7 @@ class ReaPack::Index::CLI
9
9
  DEFAULTS = {
10
10
  check: false,
11
11
  scan: [],
12
+ rebuild: false,
12
13
  verbose: false,
13
14
  warnings: true,
14
15
  progress: true,
@@ -53,7 +54,7 @@ class ReaPack::Index::CLI
53
54
  end
54
55
 
55
56
  op.on '-s', '--scan [COMMIT]', 'Scan new commits (default) or specific commits' do |commit|
56
- opts[:check] = false
57
+ opts[:check] = opts[:rebuild] = false
57
58
  opts[:scan] ||= []
58
59
 
59
60
  if commit
@@ -63,6 +64,11 @@ class ReaPack::Index::CLI
63
64
  end
64
65
  end
65
66
 
67
+ op.on '--rebuild', 'Clear the index and rescan the whole git history' do
68
+ opts[:check] = false
69
+ opts[:rebuild] = true
70
+ end
71
+
66
72
  op.separator 'Indexer options:'
67
73
 
68
74
  op.on '-a', '--[no-]amend', 'Reindex existing versions' do |bool|