reapack-index 1.0beta4 → 1.0rc2
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 +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|
|