Icarus-Mod-Tools 1.7.1 → 1.8.1
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/.rubocop.yml +10 -1
- data/Gemfile.lock +16 -9
- data/imtconfig.sample.json +3 -1
- data/lib/icarus/mod/cli/add.rb +8 -0
- data/lib/icarus/mod/cli/list.rb +65 -46
- data/lib/icarus/mod/cli/sync.rb +96 -46
- data/lib/icarus/mod/cli/validate.rb +32 -21
- data/lib/icarus/mod/firestore.rb +45 -25
- data/lib/icarus/mod/tools/baseinfo.rb +104 -0
- data/lib/icarus/mod/tools/mod_sync.rb +6 -6
- data/lib/icarus/mod/tools/modinfo.rb +3 -84
- data/lib/icarus/mod/tools/modinfo_sync.rb +1 -1
- data/lib/icarus/mod/tools/prog_sync.rb +51 -0
- data/lib/icarus/mod/tools/proginfo.rb +24 -0
- data/lib/icarus/mod/tools/proginfo_sync.rb +56 -0
- data/lib/icarus/mod/tools/validator.rb +23 -0
- data/lib/icarus/mod/version.rb +1 -1
- metadata +7 -3
- data/lib/icarus/mod/tools/modinfo_validate.rb +0 -16
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: d70aff1f7ed368044b414fdca605fa438e0fbfe68c2af436d534a233fc6bff17
|
4
|
+
data.tar.gz: e4467d443894344c50a2c3c663e262afd7e54cc806da308ecd16d732bcd2c844
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 26c83360237ab149e6738e60966df113f8ede55460f85b0b2de29dd690cea238cdfda8af0ffc70f288ca58765b535d18b2cfcb21e0619b0a8226bfe099e7fecc
|
7
|
+
data.tar.gz: 278435526ede69d45383920bee07fc3fc094924d022ed55c54141d00e9b53ef003d7688fb26bc4f251e3b13705b743013875583d553ca8c22198a7daeb590238
|
data/.rubocop.yml
CHANGED
@@ -38,8 +38,17 @@ Metrics/AbcSize:
|
|
38
38
|
Exclude:
|
39
39
|
- lib/icarus/mod/cli/*.rb # Thor command files
|
40
40
|
|
41
|
+
Metrics/BlockLength:
|
42
|
+
Enabled: false
|
43
|
+
|
44
|
+
Metrics/ClassLength:
|
45
|
+
Enabled: false
|
46
|
+
|
41
47
|
Metrics/MethodLength:
|
42
|
-
|
48
|
+
Enabled: false
|
49
|
+
|
50
|
+
Naming/BlockForwarding:
|
51
|
+
EnforcedStyle: explicit
|
43
52
|
|
44
53
|
RSpec/MultipleMemoizedHelpers:
|
45
54
|
Enabled: false
|
data/Gemfile.lock
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
PATH
|
2
2
|
remote: .
|
3
3
|
specs:
|
4
|
-
Icarus-Mod-Tools (1.
|
4
|
+
Icarus-Mod-Tools (1.8.1)
|
5
5
|
google-cloud-firestore (~> 2.7)
|
6
6
|
octokit (~> 6.0)
|
7
7
|
paint (~> 2.3)
|
@@ -14,9 +14,9 @@ GEM
|
|
14
14
|
public_suffix (>= 2.0.2, < 6.0)
|
15
15
|
ast (2.4.2)
|
16
16
|
coderay (1.1.3)
|
17
|
-
concurrent-ruby (1.
|
17
|
+
concurrent-ruby (1.2.0)
|
18
18
|
diff-lcs (1.5.0)
|
19
|
-
faraday (2.7.
|
19
|
+
faraday (2.7.4)
|
20
20
|
faraday-net_http (>= 2.0, < 3.1)
|
21
21
|
ruby2_keywords (>= 0.0.4)
|
22
22
|
faraday-net_http (3.0.2)
|
@@ -38,7 +38,7 @@ GEM
|
|
38
38
|
google-cloud-env (1.6.0)
|
39
39
|
faraday (>= 0.17.3, < 3.0)
|
40
40
|
google-cloud-errors (1.3.0)
|
41
|
-
google-cloud-firestore (2.
|
41
|
+
google-cloud-firestore (2.9.0)
|
42
42
|
concurrent-ruby (~> 1.0)
|
43
43
|
google-cloud-core (~> 1.5)
|
44
44
|
google-cloud-firestore-v1 (~> 0.0)
|
@@ -51,6 +51,7 @@ GEM
|
|
51
51
|
gapic-common (>= 0.16.0, < 2.a)
|
52
52
|
google-cloud-errors (~> 1.0)
|
53
53
|
google-protobuf (3.21.12-x86_64-darwin)
|
54
|
+
google-protobuf (3.21.12-x86_64-linux)
|
54
55
|
googleapis-common-protos (1.4.0)
|
55
56
|
google-protobuf (~> 3.14)
|
56
57
|
googleapis-common-protos-types (~> 1.2)
|
@@ -64,7 +65,10 @@ GEM
|
|
64
65
|
multi_json (~> 1.11)
|
65
66
|
os (>= 0.9, < 2.0)
|
66
67
|
signet (>= 0.16, < 2.a)
|
67
|
-
grpc (1.
|
68
|
+
grpc (1.51.0-x86_64-darwin)
|
69
|
+
google-protobuf (~> 3.21)
|
70
|
+
googleapis-common-protos-types (~> 1.0)
|
71
|
+
grpc (1.51.0-x86_64-linux)
|
68
72
|
google-protobuf (~> 3.21)
|
69
73
|
googleapis-common-protos-types (~> 1.0)
|
70
74
|
guard (2.18.0)
|
@@ -112,7 +116,7 @@ GEM
|
|
112
116
|
rb-inotify (0.10.1)
|
113
117
|
ffi (~> 1.0)
|
114
118
|
rbtree (0.4.6)
|
115
|
-
regexp_parser (2.6.
|
119
|
+
regexp_parser (2.6.2)
|
116
120
|
rexml (3.2.5)
|
117
121
|
rspec (3.12.0)
|
118
122
|
rspec-core (~> 3.12.0)
|
@@ -123,11 +127,11 @@ GEM
|
|
123
127
|
rspec-expectations (3.12.2)
|
124
128
|
diff-lcs (>= 1.2.0, < 2.0)
|
125
129
|
rspec-support (~> 3.12.0)
|
126
|
-
rspec-mocks (3.12.
|
130
|
+
rspec-mocks (3.12.3)
|
127
131
|
diff-lcs (>= 1.2.0, < 2.0)
|
128
132
|
rspec-support (~> 3.12.0)
|
129
133
|
rspec-support (3.12.0)
|
130
|
-
rubocop (1.
|
134
|
+
rubocop (1.44.1)
|
131
135
|
json (~> 2.3)
|
132
136
|
parallel (~> 1.10)
|
133
137
|
parser (>= 3.2.0.0)
|
@@ -139,8 +143,11 @@ GEM
|
|
139
143
|
unicode-display_width (>= 2.4.0, < 3.0)
|
140
144
|
rubocop-ast (1.24.1)
|
141
145
|
parser (>= 3.1.1.0)
|
142
|
-
rubocop-
|
146
|
+
rubocop-capybara (2.17.0)
|
147
|
+
rubocop (~> 1.41)
|
148
|
+
rubocop-rspec (2.18.1)
|
143
149
|
rubocop (~> 1.33)
|
150
|
+
rubocop-capybara (~> 2.17)
|
144
151
|
ruby-progressbar (1.11.0)
|
145
152
|
ruby2_keywords (0.0.5)
|
146
153
|
sawyer (0.9.2)
|
data/imtconfig.sample.json
CHANGED
data/lib/icarus/mod/cli/add.rb
CHANGED
@@ -15,6 +15,14 @@ module Icarus
|
|
15
15
|
puts firestore.update(:modinfo, payload, merge: true) ? "Success" : "Failure"
|
16
16
|
end
|
17
17
|
|
18
|
+
desc "proginfo", "Adds an entry to 'meta/proginfo/list'"
|
19
|
+
def proginfo(item)
|
20
|
+
firestore = Firestore.new
|
21
|
+
payload = [firestore.list(:proginfo), item].flatten.compact
|
22
|
+
|
23
|
+
puts firestore.update(:proginfo, payload, merge: true) ? "Success" : "Failure"
|
24
|
+
end
|
25
|
+
|
18
26
|
desc "repos", "Adds an entry to 'meta/repos/list'"
|
19
27
|
def repos(item)
|
20
28
|
firestore = Firestore.new
|
data/lib/icarus/mod/cli/list.rb
CHANGED
@@ -10,9 +10,16 @@ module Icarus
|
|
10
10
|
class List < SubcommandBase
|
11
11
|
desc "modinfo", "Displays data from 'meta/modinfo/list'"
|
12
12
|
def modinfo
|
13
|
-
|
14
|
-
puts
|
15
|
-
puts "Total: #{
|
13
|
+
modinfo_array = Firestore.new.list(:modinfo)
|
14
|
+
puts modinfo_array
|
15
|
+
puts "Total: #{modinfo_array.count}" if verbose > 1
|
16
|
+
end
|
17
|
+
|
18
|
+
desc "proginfo", "Displays data from 'meta/proginfo/list'"
|
19
|
+
def proginfo
|
20
|
+
proginfo_array = Firestore.new.list(:proginfo)
|
21
|
+
puts proginfo_array
|
22
|
+
puts "Total: #{proginfo_array.count}" if verbose > 1
|
16
23
|
end
|
17
24
|
|
18
25
|
desc "repos", "Displays data from 'meta/repos/list'"
|
@@ -26,63 +33,75 @@ module Icarus
|
|
26
33
|
method_option :sort, type: :string, default: "name", desc: "Sort by field (name, author, etc.)"
|
27
34
|
method_option :filter, type: :array, default: [], desc: "Filter by field (name, author, etc.)"
|
28
35
|
def mods
|
29
|
-
|
36
|
+
list_for_type(:mods)
|
37
|
+
end
|
38
|
+
|
39
|
+
desc "progs", "Displays data from 'progs'"
|
40
|
+
method_option :sort, type: :string, default: "name", desc: "Sort by field (name, author, etc.)"
|
41
|
+
method_option :filter, type: :array, default: [], desc: "Filter by field (name, author, etc.)"
|
42
|
+
def progs
|
43
|
+
list_for_type(:progs)
|
44
|
+
end
|
30
45
|
|
31
|
-
|
46
|
+
no_commands do
|
47
|
+
def list_for_type(type)
|
48
|
+
klass = type == :mods ? Icarus::Mod::Tools::Modinfo : Icarus::Mod::Tools::Proginfo
|
49
|
+
valid_keys = klass::HASHKEYS + [:updated_at]
|
50
|
+
sort_field = options[:sort]&.to_sym
|
51
|
+
filter = !options[:filter].empty?
|
32
52
|
|
33
|
-
|
53
|
+
if filter
|
54
|
+
filter_field = options[:filter].first&.to_sym
|
55
|
+
filter_value = options[:filter].last&.to_s
|
34
56
|
|
35
|
-
|
36
|
-
filter_field = options[:filter].first&.to_sym
|
37
|
-
filter_value = options[:filter].last&.to_s
|
57
|
+
raise Icarus::Mod::Tools::Error, "Invalid filter option #{options[:filter]}" unless options[:filter].empty? || options[:filter]&.count == 2
|
38
58
|
|
39
|
-
|
59
|
+
raise Icarus::Mod::Tools::Error, "Invalid filter field '#{filter_field}'" unless filter_field && valid_keys.include?(filter_field)
|
60
|
+
end
|
40
61
|
|
41
|
-
raise Icarus::Mod::Tools::Error, "Invalid
|
42
|
-
end
|
62
|
+
raise Icarus::Mod::Tools::Error, "Invalid sort field '#{sort_field}'" unless valid_keys.include?(sort_field)
|
43
63
|
|
44
|
-
|
64
|
+
puts "Sorted by #{sort_field}" if sort_field && verbose > 2
|
65
|
+
puts "Filtered by #{filter_field} = #{filter_value}" if filter_field && verbose > 2
|
45
66
|
|
46
|
-
|
47
|
-
puts "Filtered by #{filter_field} = #{filter_value}" if filter_field && verbose > 2
|
67
|
+
items = Firestore.new.list(type)
|
48
68
|
|
49
|
-
|
69
|
+
# Filter by field
|
70
|
+
items.select! { |item| item.send(filter_field).downcase =~ /#{filter_value&.downcase}/ } if filter_field
|
50
71
|
|
51
|
-
|
52
|
-
|
72
|
+
if items.empty?
|
73
|
+
puts "no entries found" if verbose?
|
74
|
+
return
|
75
|
+
end
|
53
76
|
|
54
|
-
|
55
|
-
|
56
|
-
return
|
57
|
-
end
|
77
|
+
header_format = "%-<name>50s %-<author>20s %-<version>10s %-<updated_at>20s"
|
78
|
+
header_format += " %-<id>20s %<description>s" if verbose > 1
|
58
79
|
|
59
|
-
|
60
|
-
|
61
|
-
|
62
|
-
|
63
|
-
|
64
|
-
|
65
|
-
|
66
|
-
|
67
|
-
|
68
|
-
|
69
|
-
|
70
|
-
description: "DESCRIPTION"
|
71
|
-
)
|
72
|
-
end
|
80
|
+
if verbose?
|
81
|
+
puts format(
|
82
|
+
header_format,
|
83
|
+
name: "NAME",
|
84
|
+
author: "AUTHOR",
|
85
|
+
version: "VERSION",
|
86
|
+
updated_at: "LAST UPDATED",
|
87
|
+
id: "ID",
|
88
|
+
description: "DESCRIPTION"
|
89
|
+
)
|
90
|
+
end
|
73
91
|
|
74
|
-
|
75
|
-
|
76
|
-
|
77
|
-
|
92
|
+
# Sort by field, optionally subsorting by name
|
93
|
+
(sort_field == :name ? items.sort_by(&:name) : items.sort_by { |item| [item.send(sort_field), item.name] }).each do |item|
|
94
|
+
data_format = "%-<name>50s %-<author>20s v%-<version>10s%-<updated_at>20s"
|
95
|
+
data_format += " %-<id>20s %<description>s" if verbose > 1
|
78
96
|
|
79
|
-
|
80
|
-
|
97
|
+
puts format(data_format, item.to_h.merge(id: item.id, updated_at: item.updated_at.strftime("%Y-%m-%d %H:%M:%S")))
|
98
|
+
end
|
81
99
|
|
82
|
-
|
83
|
-
|
84
|
-
|
85
|
-
|
100
|
+
puts "Total: #{items.count}" if verbose?
|
101
|
+
rescue Icarus::Mod::Tools::Error => e
|
102
|
+
puts e.message
|
103
|
+
exit 1
|
104
|
+
end
|
86
105
|
end
|
87
106
|
end
|
88
107
|
end
|
data/lib/icarus/mod/cli/sync.rb
CHANGED
@@ -1,81 +1,131 @@
|
|
1
1
|
# frozen_string_literal: true
|
2
2
|
|
3
3
|
require "tools/modinfo_sync"
|
4
|
+
require "tools/proginfo_sync"
|
4
5
|
require "tools/mod_sync"
|
6
|
+
require "tools/prog_sync"
|
5
7
|
|
6
8
|
module Icarus
|
7
9
|
module Mod
|
8
10
|
module CLI
|
9
11
|
# Sync CLI command definitions
|
10
12
|
class Sync < SubcommandBase
|
13
|
+
class_option :dry_run, type: :boolean, default: false, desc: "Dry run (no changes will be made)"
|
14
|
+
|
15
|
+
desc "all", "Run all sync jobs"
|
16
|
+
def all
|
17
|
+
invoke :proginfo
|
18
|
+
invoke :progs
|
19
|
+
invoke :modinfo
|
20
|
+
invoke :mods
|
21
|
+
end
|
22
|
+
|
11
23
|
desc "modinfo", "Reads from 'meta/repos/list' and Syncs any modinfo files we find (github only for now)"
|
12
24
|
def modinfo
|
13
|
-
|
14
|
-
|
15
|
-
puts "Retrieving repository Data..." if verbose?
|
16
|
-
repositories = modinfo_sync.repositories
|
17
|
-
|
18
|
-
raise Icarus::Mod::Tools::Error, "Unable to find any repositories!" unless repositories.any?
|
19
|
-
|
20
|
-
puts "Retrieving modinfo Array..." if verbose?
|
21
|
-
modinfo_array = modinfo_sync.modinfo_data(repositories, verbose: verbose > 1)&.map(&:download_url)&.compact
|
22
|
-
|
23
|
-
raise Icarus::Mod::Tools::Error, "Unable to find any modinfo.json files!" unless modinfo_array&.any?
|
25
|
+
sync_info(:modinfo)
|
26
|
+
end
|
24
27
|
|
25
|
-
|
26
|
-
|
27
|
-
|
28
|
+
desc "proginfo", "Reads from 'meta/repos/list' and Syncs any proginfo files we find (github only for now)"
|
29
|
+
def proginfo
|
30
|
+
sync_info(:proginfo)
|
28
31
|
end
|
29
32
|
|
30
33
|
desc "mods", "Reads from 'meta/modinfo/list' and updates the 'mods' database accordingly"
|
31
34
|
method_option :check, type: :boolean, default: false, desc: "Validate modinfo without applying changes"
|
32
35
|
def mods
|
33
|
-
|
36
|
+
sync_list(:mods)
|
37
|
+
end
|
38
|
+
|
39
|
+
desc "progs", "Reads from 'meta/proginfo/list' and updates the 'progs' database accordingly"
|
40
|
+
method_option :check, type: :boolean, default: false, desc: "Validate proginfo without applying changes"
|
41
|
+
def progs
|
42
|
+
sync_list(:progs)
|
43
|
+
end
|
34
44
|
|
35
|
-
|
36
|
-
|
45
|
+
no_commands do
|
46
|
+
def sync_info(type)
|
47
|
+
sync = (type == :modinfo ? Icarus::Mod::Tools::ModinfoSync : Icarus::Mod::Tools::ProginfoSync).new
|
37
48
|
|
38
|
-
|
39
|
-
|
49
|
+
puts "Retrieving repository Data..." if verbose?
|
50
|
+
repositories = sync.repositories
|
40
51
|
|
41
|
-
|
52
|
+
raise Icarus::Mod::Tools::Error, "Unable to find any repositories!" unless repositories.any?
|
42
53
|
|
43
|
-
|
44
|
-
|
45
|
-
verb = "Creating"
|
54
|
+
puts "Retrieving Info Array..." if verbose?
|
55
|
+
info_array = sync.data(repositories, verbose: verbose > 1)&.map(&:download_url)&.compact
|
46
56
|
|
47
|
-
|
48
|
-
warn "Skipping mod #{mod.uniq_name} due to validation errors" && next unless mod.validate
|
57
|
+
raise Icarus::Mod::Tools::Error, "no .json files found for #{type}" unless info_array&.any?
|
49
58
|
|
50
|
-
|
51
|
-
|
52
|
-
|
53
|
-
mod.id = doc_id
|
54
|
-
verb = "Updating"
|
59
|
+
if options[:dry_run]
|
60
|
+
puts "Dry run; no changes will be made"
|
61
|
+
return
|
55
62
|
end
|
56
63
|
|
57
|
-
|
58
|
-
response =
|
59
|
-
puts
|
64
|
+
puts "Saving to Firestore..." if verbose?
|
65
|
+
response = sync.update(info_array)
|
66
|
+
puts response ? "Success" : "Failure (may be no changes)" if verbose?
|
67
|
+
rescue Icarus::Mod::Tools::Error => e
|
68
|
+
warn e.message
|
60
69
|
end
|
61
70
|
|
62
|
-
|
71
|
+
def sync_list(type)
|
72
|
+
sync = (type == :mods ? Icarus::Mod::Tools::ModSync : Icarus::Mod::Tools::ProgSync).new
|
63
73
|
|
64
|
-
|
74
|
+
puts "Retrieving Info Data..." if verbose?
|
75
|
+
info_array = sync.info_array
|
65
76
|
|
66
|
-
|
77
|
+
puts "Retrieving List Data..." if verbose?
|
78
|
+
list_array = sync.send(type)
|
67
79
|
|
68
|
-
|
69
|
-
|
70
|
-
|
71
|
-
|
72
|
-
|
73
|
-
|
80
|
+
return if options[:check]
|
81
|
+
|
82
|
+
puts "Updating List Data..." if verbose?
|
83
|
+
info_array.each do |list|
|
84
|
+
verb = "Creating"
|
85
|
+
|
86
|
+
puts "Validating Info Data for #{list.uniq_name}..." if verbose > 2
|
87
|
+
warn "Skipping List #{list.uniq_name} due to validation errors" && next unless list.valid?
|
74
88
|
|
75
|
-
|
76
|
-
|
77
|
-
|
78
|
-
|
89
|
+
doc_id = sync.find(list)
|
90
|
+
if doc_id
|
91
|
+
puts "Found existing list #{list.name} at #{doc_id}" if verbose > 2
|
92
|
+
list.id = doc_id
|
93
|
+
verb = "Updating"
|
94
|
+
end
|
95
|
+
|
96
|
+
print format("#{verb} %-<name>60s", name: "'#{list.author || "NoOne"}/#{list.name || "Unnamed"}'") if verbose > 1
|
97
|
+
|
98
|
+
if options[:dry_run]
|
99
|
+
puts "Dry run; no changes will be made" if verbose > 1
|
100
|
+
next
|
101
|
+
end
|
102
|
+
|
103
|
+
response = sync.update(list)
|
104
|
+
puts format("%<status>10s", status: response ? "Success" : "Failure") if verbose > 1
|
105
|
+
end
|
106
|
+
|
107
|
+
if options[:dry_run]
|
108
|
+
puts "Dry run; no changes will be made" if verbose?
|
109
|
+
return
|
110
|
+
end
|
111
|
+
|
112
|
+
puts "Created/Updated #{info_array.count} Items" if verbose?
|
113
|
+
|
114
|
+
delete_array = list_array.filter { |list| sync.find_info(list).nil? }
|
115
|
+
|
116
|
+
return unless delete_array.any?
|
117
|
+
|
118
|
+
puts "Deleting outdated items..." if verbose?
|
119
|
+
delete_array.each do |list|
|
120
|
+
print format("Deleting %-<name>60s", name: "'#{list.author || "NoOne"}/#{list.name || "Unnamed'"}") if verbose > 1
|
121
|
+
response = sync.delete(list)
|
122
|
+
puts format("%<status>10s", status: response ? "Success" : "Failure") if verbose > 1
|
123
|
+
end
|
124
|
+
|
125
|
+
puts "Deleted #{delete_array.count} outdated items" if verbose?
|
126
|
+
rescue Icarus::Mod::Tools::Error => e
|
127
|
+
warn e.message
|
128
|
+
end
|
79
129
|
end
|
80
130
|
end
|
81
131
|
end
|
@@ -1,6 +1,6 @@
|
|
1
1
|
# frozen_string_literal: true
|
2
2
|
|
3
|
-
require "tools/
|
3
|
+
require "tools/validator"
|
4
4
|
|
5
5
|
module Icarus
|
6
6
|
module Mod
|
@@ -9,35 +9,46 @@ module Icarus
|
|
9
9
|
class Validate < SubcommandBase
|
10
10
|
desc "modinfo", "Reads modinfo data from 'meta/modinfo/list' and Validates syntax of modfiles"
|
11
11
|
def modinfo
|
12
|
-
|
13
|
-
|
12
|
+
validate(:modinfo)
|
13
|
+
end
|
14
|
+
|
15
|
+
desc "proginfo", "Reads proginfo data from 'meta/proginfo/list' and Validates syntax of progfiles"
|
16
|
+
def proginfo
|
17
|
+
validate(:proginfo)
|
18
|
+
end
|
14
19
|
|
15
|
-
|
16
|
-
|
20
|
+
no_commands do
|
21
|
+
def validate(type)
|
22
|
+
exit_code = 0
|
23
|
+
validator = Icarus::Mod::Tools::Validator.new(type)
|
17
24
|
|
18
|
-
|
19
|
-
|
25
|
+
puts "Validating Entries..." if verbose?
|
26
|
+
max_length = validator.array.map { |info| info.uniq_name.length }.max + 1
|
20
27
|
|
21
|
-
|
28
|
+
validator.array.each do |info|
|
29
|
+
print Paint[format("%s %-#{max_length}s", "Running validation steps on", info.uniq_name), :cyan, :bright] if verbose > 1
|
22
30
|
|
23
|
-
|
24
|
-
puts Paint["SUCCESS", :green, :bright] if verbose > 1
|
25
|
-
next
|
26
|
-
end
|
31
|
+
info.valid?
|
27
32
|
|
28
|
-
|
29
|
-
|
30
|
-
|
31
|
-
|
33
|
+
unless info.errors? || info.warnings?
|
34
|
+
puts Paint["SUCCESS", :green, :bright] if verbose > 1
|
35
|
+
next
|
36
|
+
end
|
37
|
+
|
38
|
+
if info.errors?
|
39
|
+
exit_code = 1
|
40
|
+
puts Paint["ERROR", :red, :bright] if verbose? && verbose > 1
|
41
|
+
puts info.errors.map { |error| Paint["#{error} in #{info.uniq_name}", :red] }.join("\n")
|
42
|
+
puts "\n" if verbose > 1
|
43
|
+
end
|
44
|
+
|
45
|
+
puts Paint["WARNING", :yellow, :bright] if info.warnings.any? && verbose > 1
|
46
|
+
puts info.warnings.map { |warning| Paint["#{warning} in #{info.uniq_name}", :yellow] }.join("\n")
|
32
47
|
puts "\n" if verbose > 1
|
33
48
|
end
|
34
49
|
|
35
|
-
|
36
|
-
puts modinfo.warnings.map { |warning| Paint["#{warning} in #{modinfo.uniq_name}", :yellow] }.join("\n")
|
37
|
-
puts "\n" if verbose > 1
|
50
|
+
exit exit_code
|
38
51
|
end
|
39
|
-
|
40
|
-
exit exit_code
|
41
52
|
end
|
42
53
|
end
|
43
54
|
end
|
data/lib/icarus/mod/firestore.rb
CHANGED
@@ -2,6 +2,7 @@
|
|
2
2
|
|
3
3
|
require "google/cloud/firestore"
|
4
4
|
require "tools/modinfo"
|
5
|
+
require "tools/proginfo"
|
5
6
|
|
6
7
|
module Icarus
|
7
8
|
module Mod
|
@@ -18,52 +19,65 @@ module Icarus
|
|
18
19
|
@repos ||= list(:repositories)
|
19
20
|
end
|
20
21
|
|
21
|
-
def
|
22
|
-
@
|
22
|
+
def modinfo_list
|
23
|
+
@modinfo_list ||= list(:modinfo)
|
24
|
+
end
|
25
|
+
|
26
|
+
def proginfo_list
|
27
|
+
@proginfo_list ||= list(:proginfo)
|
23
28
|
end
|
24
29
|
|
25
30
|
def mods
|
26
31
|
@mods ||= list(:mods)
|
27
32
|
end
|
28
33
|
|
29
|
-
def
|
30
|
-
|
34
|
+
def progs
|
35
|
+
@progs ||= list(:progs)
|
36
|
+
end
|
37
|
+
|
38
|
+
def find_by_type(type:, name:, author:)
|
39
|
+
list(type).find { |obj| obj.name == name && obj.author == author }
|
40
|
+
end
|
41
|
+
|
42
|
+
def get_list(type)
|
43
|
+
raise "Invalid type: #{type} - unknown collection" unless collections.respond_to?(type)
|
44
|
+
|
45
|
+
@client.doc(collections.send(type)).get[:list]
|
31
46
|
end
|
32
47
|
|
33
48
|
def list(type)
|
34
|
-
case type
|
35
|
-
when :modinfo
|
36
|
-
|
37
|
-
when :
|
38
|
-
@client.
|
39
|
-
|
40
|
-
|
41
|
-
Icarus::Mod::Tools::Modinfo.new(doc.data, id: doc.document_id, created: doc.create_time, updated: doc.update_time)
|
49
|
+
case type.to_sym
|
50
|
+
when :modinfo, :proginfo, :repositories
|
51
|
+
get_list(type)
|
52
|
+
when :mods, :progs
|
53
|
+
@client.col(collections.send(type)).get.map do |doc|
|
54
|
+
klass = type == :mods ? Icarus::Mod::Tools::Modinfo : Icarus::Mod::Tools::Proginfo
|
55
|
+
klass.new(doc.data, id: doc.document_id, created: doc.create_time, updated: doc.update_time)
|
42
56
|
end
|
43
57
|
else
|
44
58
|
raise "Invalid type: #{type}"
|
45
59
|
end
|
46
60
|
end
|
47
61
|
|
48
|
-
def
|
49
|
-
doc_id = payload.id ||
|
62
|
+
def update_or_create(type, payload, merge:)
|
63
|
+
doc_id = payload.id || find_by_type(type:, name: payload.name, author: payload.author)&.id
|
50
64
|
|
51
|
-
return @client.doc("#{collections.
|
65
|
+
return @client.doc("#{collections.send(type)}/#{doc_id}").set(payload.to_h, merge:) if doc_id
|
52
66
|
|
53
|
-
@client.col(collections.
|
67
|
+
@client.col(collections.send(type)).add(payload.to_h)
|
54
68
|
end
|
55
69
|
|
56
70
|
def update(type, payload, merge: false)
|
57
71
|
raise "You must specify a payload to update" if payload&.empty? || payload.nil?
|
58
72
|
|
59
|
-
case type
|
60
|
-
when :modinfo
|
61
|
-
update_array = (
|
62
|
-
response = @client.doc(collections.
|
73
|
+
case type.to_sym
|
74
|
+
when :modinfo, :proginfo
|
75
|
+
update_array = (send("#{type}_list") + [payload]).flatten.uniq
|
76
|
+
response = @client.doc(collections.send(type)).set({ list: update_array }, merge:) if update_array.any?
|
63
77
|
when :repositories
|
64
78
|
response = @client.doc(collections.repositories).set({ list: payload }, merge:)
|
65
|
-
when :mod
|
66
|
-
response =
|
79
|
+
when :mod, :prog
|
80
|
+
response = update_or_create(pluralize(type), payload, merge:)
|
67
81
|
else
|
68
82
|
raise "Invalid type: #{type}"
|
69
83
|
end
|
@@ -72,15 +86,21 @@ module Icarus
|
|
72
86
|
end
|
73
87
|
|
74
88
|
def delete(type, payload)
|
75
|
-
case type
|
76
|
-
when :mod
|
77
|
-
response = @client.doc("#{collections.
|
89
|
+
case type.to_sym
|
90
|
+
when :mod, :prog
|
91
|
+
response = @client.doc("#{collections.send(pluralize(type))}/#{payload.id}").delete
|
78
92
|
else
|
79
93
|
raise "Invalid type: #{type}"
|
80
94
|
end
|
81
95
|
|
82
96
|
response.is_a?(Google::Cloud::Firestore::CommitResponse::WriteResult)
|
83
97
|
end
|
98
|
+
|
99
|
+
private
|
100
|
+
|
101
|
+
def pluralize(type)
|
102
|
+
type.to_s.end_with?("s") ? type.to_s : "#{type}s"
|
103
|
+
end
|
84
104
|
end
|
85
105
|
end
|
86
106
|
end
|
@@ -0,0 +1,104 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module Icarus
|
4
|
+
module Mod
|
5
|
+
module Tools
|
6
|
+
# Base class for Modinfo and Proginfo
|
7
|
+
class Baseinfo
|
8
|
+
attr_reader :data, :id, :created_at, :updated_at
|
9
|
+
|
10
|
+
HASHKEYS = %i[name author version compatibility description fileType fileURL imageURL readmeURL].freeze
|
11
|
+
|
12
|
+
def initialize(data, id: nil, created: nil, updated: nil)
|
13
|
+
@id = id
|
14
|
+
@created_at = created
|
15
|
+
@updated_at = updated
|
16
|
+
@errors = []
|
17
|
+
@warnings = []
|
18
|
+
|
19
|
+
read(data)
|
20
|
+
end
|
21
|
+
|
22
|
+
def read(data)
|
23
|
+
@data = data.is_a?(String) ? JSON.parse(data, symbolize_names: true) : data
|
24
|
+
end
|
25
|
+
|
26
|
+
def errors
|
27
|
+
@errors.compact.uniq
|
28
|
+
end
|
29
|
+
|
30
|
+
def errors?
|
31
|
+
@errors.compact.any?
|
32
|
+
end
|
33
|
+
|
34
|
+
def warnings
|
35
|
+
@warnings.compact.uniq
|
36
|
+
end
|
37
|
+
|
38
|
+
def warnings?
|
39
|
+
@warnings.compact.any?
|
40
|
+
end
|
41
|
+
|
42
|
+
def uniq_name
|
43
|
+
"#{author.strip}/#{name.strip}"
|
44
|
+
end
|
45
|
+
|
46
|
+
def to_json(*args)
|
47
|
+
JSON.generate(@data, *args)
|
48
|
+
end
|
49
|
+
|
50
|
+
def to_h
|
51
|
+
HASHKEYS.each_with_object({}) { |key, hash| hash[key] = @data[key] }
|
52
|
+
end
|
53
|
+
|
54
|
+
def valid?
|
55
|
+
@warnings << "Version should be a version string" unless validate_version(version)
|
56
|
+
|
57
|
+
%w[name author description].each do |key|
|
58
|
+
@errors << "#{key.capitalize} cannot be blank" unless validate_string(@data[key.to_sym])
|
59
|
+
end
|
60
|
+
|
61
|
+
@errors << "Invalid fileType: #{fileType || "blank"}" unless validate_filetype(fileType)
|
62
|
+
|
63
|
+
%w[fileURL imageURL readmeURL].each do |key|
|
64
|
+
@errors << "Invalid URL #{key.capitalize}: #{@data[key.to_sym] || "blank"}" unless validate_url(@data[key.to_sym])
|
65
|
+
end
|
66
|
+
|
67
|
+
!errors?
|
68
|
+
end
|
69
|
+
|
70
|
+
def method_missing(method_name, *_args, &_block)
|
71
|
+
@data[method_name.to_sym]&.strip
|
72
|
+
end
|
73
|
+
|
74
|
+
def respond_to_missing?(method_name, include_private = false)
|
75
|
+
HASHKEYS.include?(method_name.to_sym) || super
|
76
|
+
end
|
77
|
+
|
78
|
+
private
|
79
|
+
|
80
|
+
def filetype_pattern
|
81
|
+
/(zip|pak|exmodz?)/i
|
82
|
+
end
|
83
|
+
|
84
|
+
def validate_url(url)
|
85
|
+
return true if url.nil? || url.empty?
|
86
|
+
|
87
|
+
url =~ URI::DEFAULT_PARSER.make_regexp
|
88
|
+
end
|
89
|
+
|
90
|
+
def validate_filetype(filetype)
|
91
|
+
filetype.match?(filetype_pattern)
|
92
|
+
end
|
93
|
+
|
94
|
+
def validate_string(string)
|
95
|
+
!(string.nil? || string.empty?)
|
96
|
+
end
|
97
|
+
|
98
|
+
def validate_version(version)
|
99
|
+
version =~ /\d+\.\d+[.\d+]?/
|
100
|
+
end
|
101
|
+
end
|
102
|
+
end
|
103
|
+
end
|
104
|
+
end
|
@@ -18,8 +18,8 @@ module Icarus
|
|
18
18
|
@firestore.mods
|
19
19
|
end
|
20
20
|
|
21
|
-
def
|
22
|
-
@
|
21
|
+
def info_array
|
22
|
+
@info_array ||= @firestore.modinfo_list.map do |url|
|
23
23
|
retrieve_from_url(url)[:mods].map { |mod| Modinfo.new(mod) if mod[:name] =~ /[a-z0-9]+/i }
|
24
24
|
rescue Icarus::Mod::Tools::RequestFailed
|
25
25
|
warn "Skipped; Failed to retrieve #{url}"
|
@@ -30,12 +30,12 @@ module Icarus
|
|
30
30
|
end.flatten.compact
|
31
31
|
end
|
32
32
|
|
33
|
-
def
|
34
|
-
@firestore.
|
33
|
+
def find(modinfo)
|
34
|
+
@firestore.find_by_type(type: "mods", name: modinfo.name, author: modinfo.author)&.id
|
35
35
|
end
|
36
36
|
|
37
|
-
def
|
38
|
-
@
|
37
|
+
def find_info(modinfo)
|
38
|
+
@info_array.find { |mod| mod.name == modinfo.name }
|
39
39
|
end
|
40
40
|
|
41
41
|
def update(modinfo)
|
@@ -1,100 +1,19 @@
|
|
1
1
|
# frozen_string_literal: true
|
2
2
|
|
3
|
+
require "tools/baseinfo"
|
4
|
+
|
3
5
|
module Icarus
|
4
6
|
module Mod
|
5
7
|
module Tools
|
6
8
|
# Sync methods
|
7
|
-
class Modinfo
|
8
|
-
attr_reader :data, :errors, :id, :created_at, :updated_at, :warnings
|
9
|
-
|
9
|
+
class Modinfo < Baseinfo
|
10
10
|
HASHKEYS = %i[name author version compatibility description long_description fileType fileURL imageURL readmeURL].freeze
|
11
11
|
|
12
|
-
def initialize(data, id: nil, created: nil, updated: nil)
|
13
|
-
@id = id
|
14
|
-
@created_at = created
|
15
|
-
@updated_at = updated
|
16
|
-
@errors = []
|
17
|
-
@warnings = []
|
18
|
-
|
19
|
-
read(data)
|
20
|
-
end
|
21
|
-
|
22
|
-
def read(data)
|
23
|
-
@data = data.is_a?(String) ? JSON.parse(data, symbolize_names: true) : data
|
24
|
-
end
|
25
|
-
|
26
|
-
def uniq_name
|
27
|
-
"#{author}/#{name}"
|
28
|
-
end
|
29
|
-
|
30
12
|
# rubocop:disable Naming/MethodName
|
31
13
|
def fileType
|
32
14
|
@data[:fileType] || "pak"
|
33
15
|
end
|
34
16
|
# rubocop:enable Naming/MethodName
|
35
|
-
|
36
|
-
def to_json(*args)
|
37
|
-
JSON.generate(@data, *args)
|
38
|
-
end
|
39
|
-
|
40
|
-
def to_h
|
41
|
-
{
|
42
|
-
name:,
|
43
|
-
author:,
|
44
|
-
version:,
|
45
|
-
compatibility:,
|
46
|
-
description:,
|
47
|
-
long_description:,
|
48
|
-
fileType:,
|
49
|
-
fileURL:,
|
50
|
-
imageURL:,
|
51
|
-
readmeURL:
|
52
|
-
}
|
53
|
-
end
|
54
|
-
|
55
|
-
def validate
|
56
|
-
@warnings << "Version should be a version string" unless validate_version(version)
|
57
|
-
|
58
|
-
%w[name author description].each do |key|
|
59
|
-
@errors << "#{key.capitalize} cannot be blank" unless validate_string(@data[key.to_sym])
|
60
|
-
end
|
61
|
-
|
62
|
-
@errors << "Invalid fileType: #{fileType || "blank"}" unless validate_filetype(fileType)
|
63
|
-
|
64
|
-
%w[fileURL imageURL readmeURL].each do |key|
|
65
|
-
@errors << "Invalid URL #{key.capitalize}: #{@data[key.to_sym] || "blank"}" unless validate_url(@data[key.to_sym])
|
66
|
-
end
|
67
|
-
|
68
|
-
@errors.empty?
|
69
|
-
end
|
70
|
-
|
71
|
-
def method_missing(method_name, *_args, &)
|
72
|
-
@data[method_name.to_sym]&.strip
|
73
|
-
end
|
74
|
-
|
75
|
-
def respond_to_missing?(method_name, include_private = false)
|
76
|
-
HASHKEYS.include?(method_name.to_sym) || super
|
77
|
-
end
|
78
|
-
|
79
|
-
private
|
80
|
-
|
81
|
-
def validate_url(url)
|
82
|
-
return true if url.nil? || url.empty?
|
83
|
-
|
84
|
-
url =~ URI::DEFAULT_PARSER.make_regexp
|
85
|
-
end
|
86
|
-
|
87
|
-
def validate_filetype(filetype)
|
88
|
-
%w[pak zip exmod].include?(filetype.downcase)
|
89
|
-
end
|
90
|
-
|
91
|
-
def validate_string(string)
|
92
|
-
!(string.nil? || string.empty?)
|
93
|
-
end
|
94
|
-
|
95
|
-
def validate_version(version)
|
96
|
-
version =~ /\d+\.\d+[.\d+]?/
|
97
|
-
end
|
98
17
|
end
|
99
18
|
end
|
100
19
|
end
|
@@ -0,0 +1,51 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
require "firestore"
|
4
|
+
require "tools/sync_helpers"
|
5
|
+
|
6
|
+
module Icarus
|
7
|
+
module Mod
|
8
|
+
module Tools
|
9
|
+
# Sync methods
|
10
|
+
class ProgSync
|
11
|
+
include SyncHelpers
|
12
|
+
|
13
|
+
def initialize
|
14
|
+
@firestore = Firestore.new
|
15
|
+
end
|
16
|
+
|
17
|
+
def progs
|
18
|
+
@firestore.progs
|
19
|
+
end
|
20
|
+
|
21
|
+
def info_array
|
22
|
+
@info_array ||= @firestore.proginfo_list.map do |url|
|
23
|
+
retrieve_from_url(url)[:programs].map { |prog| Proginfo.new(prog) if prog[:name] =~ /[a-z0-9]+/i }
|
24
|
+
rescue Icarus::Mod::Tools::RequestFailed
|
25
|
+
warn "Skipped; Failed to retrieve #{url}"
|
26
|
+
next
|
27
|
+
rescue JSON::ParserError => e
|
28
|
+
warn "Skipped; Invalid JSON: #{e.full_message}"
|
29
|
+
next
|
30
|
+
end.flatten.compact
|
31
|
+
end
|
32
|
+
|
33
|
+
def find(proginfo)
|
34
|
+
@firestore.find_by_type(type: "progs", name: proginfo.name, author: proginfo.author)&.id
|
35
|
+
end
|
36
|
+
|
37
|
+
def find_info(proginfo)
|
38
|
+
@info_array.find { |prog| prog.name == proginfo.name }
|
39
|
+
end
|
40
|
+
|
41
|
+
def update(proginfo)
|
42
|
+
@firestore.update(:prog, proginfo, merge: false)
|
43
|
+
end
|
44
|
+
|
45
|
+
def delete(proginfo)
|
46
|
+
@firestore.delete(:prog, proginfo)
|
47
|
+
end
|
48
|
+
end
|
49
|
+
end
|
50
|
+
end
|
51
|
+
end
|
@@ -0,0 +1,24 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
require "tools/baseinfo"
|
4
|
+
|
5
|
+
module Icarus
|
6
|
+
module Mod
|
7
|
+
module Tools
|
8
|
+
# Sync methods
|
9
|
+
class Proginfo < Baseinfo
|
10
|
+
# rubocop:disable Naming/MethodName
|
11
|
+
def fileType
|
12
|
+
@data[:fileType] || "zip"
|
13
|
+
end
|
14
|
+
# rubocop:enable Naming/MethodName
|
15
|
+
|
16
|
+
private
|
17
|
+
|
18
|
+
def filetype_pattern
|
19
|
+
/(zip|exe)/i
|
20
|
+
end
|
21
|
+
end
|
22
|
+
end
|
23
|
+
end
|
24
|
+
end
|
@@ -0,0 +1,56 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
require "firestore"
|
4
|
+
require "github"
|
5
|
+
require "tools/sync_helpers"
|
6
|
+
|
7
|
+
module Icarus
|
8
|
+
module Mod
|
9
|
+
module Tools
|
10
|
+
# Sync methods
|
11
|
+
class ProginfoSync
|
12
|
+
include SyncHelpers
|
13
|
+
|
14
|
+
def initialize
|
15
|
+
@firestore = Firestore.new
|
16
|
+
@github = Github.new
|
17
|
+
@repositories = []
|
18
|
+
end
|
19
|
+
|
20
|
+
def repositories
|
21
|
+
@firestore.repos
|
22
|
+
end
|
23
|
+
|
24
|
+
def update(proginfo_array)
|
25
|
+
@firestore.update(:proginfo, proginfo_array)
|
26
|
+
end
|
27
|
+
|
28
|
+
def proginfo(url)
|
29
|
+
retrieve_from_url(url)
|
30
|
+
end
|
31
|
+
|
32
|
+
def data(repositories, verbose: false)
|
33
|
+
repositories.map do |repo|
|
34
|
+
print "searching #{repo}..." if verbose
|
35
|
+
|
36
|
+
case repo
|
37
|
+
when /github/
|
38
|
+
@github.repository = repo
|
39
|
+
proginfo_url = @github.find("proginfo.json")
|
40
|
+
|
41
|
+
unless proginfo_url
|
42
|
+
puts "Skipped...no proginfo.json" if verbose
|
43
|
+
next
|
44
|
+
end
|
45
|
+
|
46
|
+
puts "Found!" if verbose
|
47
|
+
proginfo_url
|
48
|
+
else
|
49
|
+
puts "Skipped...repository type not supported yet" if verbose
|
50
|
+
end
|
51
|
+
end.compact
|
52
|
+
end
|
53
|
+
end
|
54
|
+
end
|
55
|
+
end
|
56
|
+
end
|
@@ -0,0 +1,23 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module Icarus
|
4
|
+
module Mod
|
5
|
+
module Tools
|
6
|
+
# Validate Methods
|
7
|
+
class Validator
|
8
|
+
attr_reader :array
|
9
|
+
|
10
|
+
def initialize(type)
|
11
|
+
@array = case type
|
12
|
+
when :modinfo
|
13
|
+
ModSync.new.info_array
|
14
|
+
when :proginfo
|
15
|
+
ProgSync.new.info_array
|
16
|
+
else
|
17
|
+
raise ArgumentError, "Invalid type: #{type}"
|
18
|
+
end
|
19
|
+
end
|
20
|
+
end
|
21
|
+
end
|
22
|
+
end
|
23
|
+
end
|
data/lib/icarus/mod/version.rb
CHANGED
metadata
CHANGED
@@ -1,14 +1,14 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: Icarus-Mod-Tools
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 1.
|
4
|
+
version: 1.8.1
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Donovan Young
|
8
8
|
autorequire:
|
9
9
|
bindir: exe
|
10
10
|
cert_chain: []
|
11
|
-
date: 2023-01-
|
11
|
+
date: 2023-01-27 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: google-cloud-firestore
|
@@ -97,11 +97,15 @@ files:
|
|
97
97
|
- lib/icarus/mod/firestore.rb
|
98
98
|
- lib/icarus/mod/github.rb
|
99
99
|
- lib/icarus/mod/tools.rb
|
100
|
+
- lib/icarus/mod/tools/baseinfo.rb
|
100
101
|
- lib/icarus/mod/tools/mod_sync.rb
|
101
102
|
- lib/icarus/mod/tools/modinfo.rb
|
102
103
|
- lib/icarus/mod/tools/modinfo_sync.rb
|
103
|
-
- lib/icarus/mod/tools/
|
104
|
+
- lib/icarus/mod/tools/prog_sync.rb
|
105
|
+
- lib/icarus/mod/tools/proginfo.rb
|
106
|
+
- lib/icarus/mod/tools/proginfo_sync.rb
|
104
107
|
- lib/icarus/mod/tools/sync_helpers.rb
|
108
|
+
- lib/icarus/mod/tools/validator.rb
|
105
109
|
- lib/icarus/mod/version.rb
|
106
110
|
- sig/database/sync/sync.rbs
|
107
111
|
homepage: https://github.com/DonovanMods/icarus-mod-tools
|
@@ -1,16 +0,0 @@
|
|
1
|
-
# frozen_string_literal: true
|
2
|
-
|
3
|
-
module Icarus
|
4
|
-
module Mod
|
5
|
-
module Tools
|
6
|
-
# Validate Methods
|
7
|
-
class ModinfoValidate
|
8
|
-
attr_reader :modinfo_array
|
9
|
-
|
10
|
-
def initialize
|
11
|
-
@modinfo_array = ModSync.new.modinfo_array
|
12
|
-
end
|
13
|
-
end
|
14
|
-
end
|
15
|
-
end
|
16
|
-
end
|