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 CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: fd3e0ae69c6ef23c28a6f91e0ea2bef191fb23cb497624c4a6861542f0d55529
4
- data.tar.gz: 74f1b174266c581ab857fd8079bc08345e055c12de0df175a24b84d5cf943c0b
3
+ metadata.gz: d70aff1f7ed368044b414fdca605fa438e0fbfe68c2af436d534a233fc6bff17
4
+ data.tar.gz: e4467d443894344c50a2c3c663e262afd7e54cc806da308ecd16d732bcd2c844
5
5
  SHA512:
6
- metadata.gz: 3e2065dcd3968f5e692db72955f6c898e16c442c47cca55681586fb6c9b07c1ba7ed19c48b402b73b02004f70fb6c25def55d4f9daa4a46b1316ec5a2489e019
7
- data.tar.gz: e56b480e1bd28fe040e0cd7a561f848596a654bb492457c92244902dbc046fe8a5ce8634f49455322ef03587c2762dc4003eb38e2b9c1fea5a7681562572a700
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
- Max: 50
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.7.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.1.10)
17
+ concurrent-ruby (1.2.0)
18
18
  diff-lcs (1.5.0)
19
- faraday (2.7.3)
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.8.0)
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.50.0-x86_64-darwin)
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.1)
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.2)
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.43.0)
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-rspec (2.17.0)
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)
@@ -14,8 +14,10 @@
14
14
  },
15
15
  "collections": {
16
16
  "modinfo": "meta/modinfo",
17
+ "proginfo": "meta/proginfo",
17
18
  "repositories": "meta/repos",
18
- "mods": "mods"
19
+ "mods": "mods",
20
+ "progs": "progs"
19
21
  }
20
22
  },
21
23
  "github": {
@@ -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
@@ -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
- modinfos = Firestore.new.list(:modinfo)
14
- puts modinfos
15
- puts "Total: #{modinfos.count}" if verbose > 1
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
- valid_keys = Icarus::Mod::Tools::Modinfo::HASHKEYS + [:updated_at]
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
- sort_field = options[:sort]&.to_sym
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
- filter = !options[:filter].empty?
53
+ if filter
54
+ filter_field = options[:filter].first&.to_sym
55
+ filter_value = options[:filter].last&.to_s
34
56
 
35
- if filter
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
- raise Icarus::Mod::Tools::Error, "Invalid filter option #{options[:filter]}" unless options[:filter].empty? || options[:filter]&.count == 2
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 filter field '#{filter_field}'" unless filter_field && valid_keys.include?(filter_field)
42
- end
62
+ raise Icarus::Mod::Tools::Error, "Invalid sort field '#{sort_field}'" unless valid_keys.include?(sort_field)
43
63
 
44
- raise Icarus::Mod::Tools::Error, "Invalid sort field '#{sort_field}'" unless valid_keys.include?(sort_field)
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
- puts "Sorted by #{sort_field}" if sort_field && verbose > 2
47
- puts "Filtered by #{filter_field} = #{filter_value}" if filter_field && verbose > 2
67
+ items = Firestore.new.list(type)
48
68
 
49
- mods = Firestore.new.list(:mods)
69
+ # Filter by field
70
+ items.select! { |item| item.send(filter_field).downcase =~ /#{filter_value&.downcase}/ } if filter_field
50
71
 
51
- # Filter by field
52
- mods.select! { |mod| mod.send(filter_field).downcase =~ /#{filter_value&.downcase}/ } if filter_field
72
+ if items.empty?
73
+ puts "no entries found" if verbose?
74
+ return
75
+ end
53
76
 
54
- if mods.empty?
55
- puts "no mods found" if verbose?
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
- header_format = "%-<name>50s %-<author>20s %-<version>10s %-<updated_at>20s"
60
- header_format += " %-<id>20s %<description>s" if verbose > 1
61
-
62
- if verbose?
63
- puts format(
64
- header_format,
65
- name: "NAME",
66
- author: "AUTHOR",
67
- version: "VERSION",
68
- updated_at: "LAST UPDATED",
69
- id: "ID",
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
- # Sort by field, optionally subsorting by name
75
- (sort_field == :name ? mods.sort_by(&:name) : mods.sort_by { |mod| [mod.send(sort_field), mod.name] }).each do |mod|
76
- data_format = "%-<name>50s %-<author>20s v%-<version>10s%-<updated_at>20s"
77
- data_format += " %-<id>20s %<description>s" if verbose > 1
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
- puts format(data_format, mod.to_h.merge(id: mod.id, updated_at: mod.updated_at.strftime("%Y-%m-%d %H:%M:%S")))
80
- end
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
- puts "Total: #{mods.count}" if verbose?
83
- rescue Icarus::Mod::Tools::Error => e
84
- puts e.message
85
- exit 1
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
@@ -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
- modinfo_sync = Icarus::Mod::Tools::ModinfoSync.new
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
- puts "Saving to Firestore..." if verbose?
26
- response = modinfo_sync.update(modinfo_array)
27
- puts response ? "Success" : "Failure (may be no changes)" if verbose?
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
- modsync = Icarus::Mod::Tools::ModSync.new
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
- puts "Retrieving modinfo Data..." if verbose?
36
- modinfo_array = modsync.modinfo_array
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
- puts "Retrieving mod Data..." if verbose?
39
- mod_array = modsync.mods
49
+ puts "Retrieving repository Data..." if verbose?
50
+ repositories = sync.repositories
40
51
 
41
- return if options[:check]
52
+ raise Icarus::Mod::Tools::Error, "Unable to find any repositories!" unless repositories.any?
42
53
 
43
- puts "Updating mod Data..." if verbose?
44
- modinfo_array.each do |mod|
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
- puts "Validating modinfo Data for #{mod.uniq_name}..." if verbose > 2
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
- doc_id = modsync.find_mod(mod)
51
- if doc_id
52
- puts "Found existing mod #{mod.name} at #{doc_id}" if verbose > 2
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
- print format("#{verb} %-<name>60s", name: "'#{mod.author || "NoOne"}/#{mod.name || "Unnamed"}'") if verbose > 1
58
- response = modsync.update(mod)
59
- puts format("%<status>10s", status: response ? "Success" : "Failure") if verbose > 1
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
- puts "Created/Updated #{modinfo_array.count} mods" if verbose?
71
+ def sync_list(type)
72
+ sync = (type == :mods ? Icarus::Mod::Tools::ModSync : Icarus::Mod::Tools::ProgSync).new
63
73
 
64
- delete_array = mod_array.filter { |mod| modsync.find_modinfo(mod).nil? }
74
+ puts "Retrieving Info Data..." if verbose?
75
+ info_array = sync.info_array
65
76
 
66
- return unless delete_array.any?
77
+ puts "Retrieving List Data..." if verbose?
78
+ list_array = sync.send(type)
67
79
 
68
- puts "Deleting outdated mods..." if verbose?
69
- delete_array.each do |mod|
70
- print format("Deleting %-<name>60s", name: "'#{mod.author || "NoOne"}/#{mod.name || "Unnamed'"}") if verbose > 1
71
- response = modsync.delete(mod)
72
- puts format("%<status>10s", status: response ? "Success" : "Failure") if verbose > 1
73
- end
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
- puts "Deleted #{delete_array.count} outdated mods" if verbose?
76
- rescue Icarus::Mod::Tools::Error => e
77
- warn e.message
78
- exit 1
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/modinfo_validate"
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
- exit_code = 0
13
- modinfo_validate = Icarus::Mod::Tools::ModinfoValidate.new
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
- puts "Validating Entries..." if verbose?
16
- max_length = modinfo_validate.modinfo_array.map { |modinfo| modinfo.uniq_name.length }.max
20
+ no_commands do
21
+ def validate(type)
22
+ exit_code = 0
23
+ validator = Icarus::Mod::Tools::Validator.new(type)
17
24
 
18
- modinfo_validate.modinfo_array.each do |modinfo|
19
- print Paint[format("%s %-#{max_length}s", "Running validation steps on", modinfo.uniq_name), :cyan, :bright] if verbose > 1
25
+ puts "Validating Entries..." if verbose?
26
+ max_length = validator.array.map { |info| info.uniq_name.length }.max + 1
20
27
 
21
- modinfo.validate
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
- if modinfo.errors.empty? && modinfo.warnings.empty?
24
- puts Paint["SUCCESS", :green, :bright] if verbose > 1
25
- next
26
- end
31
+ info.valid?
27
32
 
28
- if modinfo.errors.any?
29
- exit_code = 1
30
- puts Paint["ERROR", :red, :bright] if verbose? && verbose > 1
31
- warn modinfo.errors.map { |error| Paint[error, :red] }.join("\n")
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
- puts Paint["WARNING", :yellow, :bright] if modinfo.warnings.any? && verbose > 1
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
@@ -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 modinfo_array
22
- @modinfo_array ||= list(:modinfo)
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 find_mod(name:, author:)
30
- mods.find { |mod| mod.name == name && mod.author == author }
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
- @client.doc(collections.modinfo).get[:list]
37
- when :repositories
38
- @client.doc(collections.repositories).get[:list]
39
- when :mods
40
- @client.col(collections.mods).get.map do |doc|
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 update_or_create_mod(payload, merge:)
49
- doc_id = payload.id || find_mod(name: payload.name, author: payload.author)&.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.mods}/#{doc_id}").set(payload.to_h, merge:) if doc_id
65
+ return @client.doc("#{collections.send(type)}/#{doc_id}").set(payload.to_h, merge:) if doc_id
52
66
 
53
- @client.col(collections.mods).add(payload.to_h)
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 = (modinfo_array + [payload]).flatten.uniq
62
- response = @client.doc(collections.modinfo).set({ list: update_array }, merge:) if update_array.any?
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 = update_or_create_mod(payload, merge:)
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.mods}/#{payload.id}").delete
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 modinfo_array
22
- @modinfo_array ||= @firestore.modinfo_array.map do |url|
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 find_mod(modinfo)
34
- @firestore.find_mod(name: modinfo.name, author: modinfo.author)&.id
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 find_modinfo(modinfo)
38
- @modinfo_array.find { |mod| mod.name == modinfo.name }
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
@@ -29,7 +29,7 @@ module Icarus
29
29
  retrieve_from_url(url)
30
30
  end
31
31
 
32
- def modinfo_data(repositories, verbose: false)
32
+ def data(repositories, verbose: false)
33
33
  repositories.map do |repo|
34
34
  print "searching #{repo}..." if verbose
35
35
 
@@ -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
@@ -2,6 +2,6 @@
2
2
 
3
3
  module Icarus
4
4
  module Mod
5
- VERSION = "1.7.1"
5
+ VERSION = "1.8.1"
6
6
  end
7
7
  end
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.7.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-21 00:00:00.000000000 Z
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/modinfo_validate.rb
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