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 +4 -4
- data/README.md +5 -3
- data/lib/reapack/index.rb +31 -130
- data/lib/reapack/index/cdetector.rb +33 -19
- data/lib/reapack/index/cli.rb +12 -6
- data/lib/reapack/index/cli/options.rb +7 -1
- data/lib/reapack/index/gem_version.rb +1 -1
- data/lib/reapack/index/git.rb +5 -1
- data/lib/reapack/index/provides.rb +8 -4
- data/lib/reapack/index/scanner.rb +129 -0
- data/lib/reapack/index/source.rb +9 -3
- data/lib/reapack/index/version.rb +1 -1
- data/reapack-index.gemspec +2 -1
- data/setup/reapack-index.nsi +15 -2
- data/test/cli/test_check.rb +25 -19
- data/test/cli/test_scan.rb +59 -1
- data/test/data/index.xml +5 -2
- data/test/index/test_provides.rb +64 -10
- data/test/index/test_scan.rb +24 -84
- data/test/test_cdetector.rb +121 -72
- data/test/test_cli.rb +6 -0
- data/test/test_git.rb +6 -0
- data/test/test_index.rb +89 -57
- data/test/test_provides.rb +21 -10
- data/test/test_scanner.rb +191 -0
- data/test/test_source.rb +37 -8
- data/test/test_version.rb +3 -4
- metadata +21 -6
- data/test/data/noindex.lua +0 -1
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA1:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 5cbcf419229c7231caca844f3b7f9e6800261b24
|
4
|
+
data.tar.gz: e3a8eabd17b759e7125f39276371383263130081
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
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
|
14
|
-
|
15
|
-
|
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
|
data/lib/reapack/index.rb
CHANGED
@@ -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
|
141
|
-
|
142
|
-
|
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
|
-
|
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
|
-
|
152
|
-
|
153
|
-
|
154
|
-
|
155
|
-
|
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[
|
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 =
|
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
|
280
|
-
@
|
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.
|
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
|
317
|
-
|
318
|
-
|
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.
|
399
|
-
|
296
|
+
node.element_children.map {|n| sort n }
|
400
297
|
return if node.name == Package.tag
|
401
|
-
|
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(
|
7
|
-
@
|
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
|
-
@
|
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
|
-
@
|
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.
|
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 [](
|
35
|
-
Selector.new
|
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
|
43
|
-
|
50
|
+
def clear
|
51
|
+
@buckets.clear
|
52
|
+
end
|
44
53
|
|
45
|
-
|
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 =
|
62
|
+
original = sort_platforms(a)[1]
|
53
63
|
msg = "duplicate file '#{original.file}'"
|
54
64
|
else
|
55
|
-
original =
|
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
|
-
|
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(
|
105
|
+
bucket(type.to_sym) << entry
|
93
106
|
}
|
94
107
|
}
|
95
108
|
}
|
96
109
|
end
|
97
110
|
|
98
111
|
private
|
99
|
-
def
|
100
|
-
|
101
|
-
|
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
|
data/lib/reapack/index/cli.rb
CHANGED
@@ -77,10 +77,13 @@ private
|
|
77
77
|
return
|
78
78
|
end
|
79
79
|
|
80
|
-
if @opts[:
|
81
|
-
|
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
|
-
|
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
|
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.
|
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?(
|
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|
|