u3d 0.9
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +7 -0
- data/.gitignore +2 -0
- data/.licenses.json +19 -0
- data/.rspec +1 -0
- data/.rubocop.yml +43 -0
- data/Gemfile +5 -0
- data/Gemfile.lock +98 -0
- data/LICENSE +21 -0
- data/LICENSE.fastlane +22 -0
- data/LOG_RULES.md +170 -0
- data/README.md +72 -0
- data/Rakefile +28 -0
- data/TODO.md +15 -0
- data/build.sh +5 -0
- data/config/log_rules.json +230 -0
- data/examples/Example1/.gitignore +19 -0
- data/examples/Example1/Assets/Editor.meta +9 -0
- data/examples/Example1/Assets/Editor/EditorRun.cs +23 -0
- data/examples/Example1/Assets/Editor/EditorRun.cs.meta +12 -0
- data/examples/Example1/Assets/Editor/FileSystemUtil.cs +26 -0
- data/examples/Example1/Assets/Editor/FileSystemUtil.cs.meta +12 -0
- data/examples/Example1/Assets/Scene1.unity +264 -0
- data/examples/Example1/Assets/Scene1.unity.meta +8 -0
- data/examples/Example1/Gemfile +8 -0
- data/examples/Example1/Gemfile.lock +165 -0
- data/examples/Example1/ProjectSettings/AudioManager.asset +16 -0
- data/examples/Example1/ProjectSettings/ClusterInputManager.asset +6 -0
- data/examples/Example1/ProjectSettings/DynamicsManager.asset +18 -0
- data/examples/Example1/ProjectSettings/EditorBuildSettings.asset +7 -0
- data/examples/Example1/ProjectSettings/EditorSettings.asset +14 -0
- data/examples/Example1/ProjectSettings/GraphicsSettings.asset +61 -0
- data/examples/Example1/ProjectSettings/InputManager.asset +295 -0
- data/examples/Example1/ProjectSettings/NavMeshAreas.asset +89 -0
- data/examples/Example1/ProjectSettings/NetworkManager.asset +8 -0
- data/examples/Example1/ProjectSettings/Physics2DSettings.asset +35 -0
- data/examples/Example1/ProjectSettings/ProjectSettings.asset +591 -0
- data/examples/Example1/ProjectSettings/ProjectVersion.txt +1 -0
- data/examples/Example1/ProjectSettings/QualitySettings.asset +180 -0
- data/examples/Example1/ProjectSettings/TagManager.asset +43 -0
- data/examples/Example1/ProjectSettings/TimeManager.asset +9 -0
- data/examples/Example1/ProjectSettings/UnityConnectSettings.asset +32 -0
- data/examples/Example1/README.md +5 -0
- data/examples/Example1/Rakefile +5 -0
- data/examples/Example1/fastlane/Fastfile +4 -0
- data/examples/Example1/fastlane/Pluginfile +1 -0
- data/examples/Example1/run.sh +1 -0
- data/examples/Example2/.gitignore +20 -0
- data/examples/Example2/Assets/Editor.meta +9 -0
- data/examples/Example2/Assets/Editor/EditorRun.cs +33 -0
- data/examples/Example2/Assets/Editor/EditorRun.cs.meta +12 -0
- data/examples/Example2/Assets/Editor/PostprocessBuildPlayer.cs +92 -0
- data/examples/Example2/Assets/Editor/PostprocessBuildPlayer.cs.meta +8 -0
- data/examples/Example2/Assets/Editor/PostprocessBuildPlayer_log.sh +31 -0
- data/examples/Example2/Assets/Editor/PostprocessBuildPlayer_log.sh.meta +8 -0
- data/examples/Example2/Assets/Editor/SimpleBuildSetup.cs +20 -0
- data/examples/Example2/Assets/Editor/SimpleBuildSetup.cs.meta +12 -0
- data/examples/Example2/Assets/Scene.unity +278 -0
- data/examples/Example2/Assets/Scene.unity.meta +8 -0
- data/examples/Example2/Gemfile +8 -0
- data/examples/Example2/Gemfile.lock +165 -0
- data/examples/Example2/ProjectSettings/AudioManager.asset +17 -0
- data/examples/Example2/ProjectSettings/ClusterInputManager.asset +6 -0
- data/examples/Example2/ProjectSettings/DynamicsManager.asset +19 -0
- data/examples/Example2/ProjectSettings/EditorBuildSettings.asset +10 -0
- data/examples/Example2/ProjectSettings/EditorSettings.asset +14 -0
- data/examples/Example2/ProjectSettings/GraphicsSettings.asset +63 -0
- data/examples/Example2/ProjectSettings/InputManager.asset +295 -0
- data/examples/Example2/ProjectSettings/NavMeshAreas.asset +89 -0
- data/examples/Example2/ProjectSettings/NetworkManager.asset +8 -0
- data/examples/Example2/ProjectSettings/Physics2DSettings.asset +36 -0
- data/examples/Example2/ProjectSettings/ProjectSettings.asset +591 -0
- data/examples/Example2/ProjectSettings/ProjectVersion.txt +1 -0
- data/examples/Example2/ProjectSettings/QualitySettings.asset +193 -0
- data/examples/Example2/ProjectSettings/TagManager.asset +43 -0
- data/examples/Example2/ProjectSettings/TimeManager.asset +9 -0
- data/examples/Example2/ProjectSettings/UnityConnectSettings.asset +34 -0
- data/examples/Example2/README.md +10 -0
- data/examples/Example2/fastlane/Fastfile +4 -0
- data/examples/Example2/fastlane/Pluginfile +1 -0
- data/exe/u3d +7 -0
- data/fastlane-plugin-u3d/.gitignore +10 -0
- data/fastlane-plugin-u3d/.licenses.json +9 -0
- data/fastlane-plugin-u3d/.rspec +3 -0
- data/fastlane-plugin-u3d/.rubocop.yml +253 -0
- data/fastlane-plugin-u3d/.travis.yml +4 -0
- data/fastlane-plugin-u3d/Gemfile +6 -0
- data/fastlane-plugin-u3d/LICENSE +21 -0
- data/fastlane-plugin-u3d/README.md +52 -0
- data/fastlane-plugin-u3d/Rakefile +9 -0
- data/fastlane-plugin-u3d/circle.yml +9 -0
- data/fastlane-plugin-u3d/fastlane-plugin-u3d.gemspec +31 -0
- data/fastlane-plugin-u3d/fastlane/Fastfile +3 -0
- data/fastlane-plugin-u3d/fastlane/Pluginfile +1 -0
- data/fastlane-plugin-u3d/lib/fastlane/plugin/u3d.rb +38 -0
- data/fastlane-plugin-u3d/lib/fastlane/plugin/u3d/actions/u3d_action.rb +80 -0
- data/fastlane-plugin-u3d/lib/fastlane/plugin/u3d/helper/u3d_helper.rb +34 -0
- data/fastlane-plugin-u3d/lib/fastlane/plugin/u3d/version.rb +27 -0
- data/fastlane-plugin-u3d/spec/spec_helper.rb +32 -0
- data/lib/u3d.rb +33 -0
- data/lib/u3d/cache.rb +120 -0
- data/lib/u3d/commands.rb +307 -0
- data/lib/u3d/commands_generator.rb +163 -0
- data/lib/u3d/downloader.rb +363 -0
- data/lib/u3d/iniparser.rb +83 -0
- data/lib/u3d/installer.rb +445 -0
- data/lib/u3d/log_analyzer.rb +221 -0
- data/lib/u3d/unity_version_number.rb +71 -0
- data/lib/u3d/unity_versions.rb +207 -0
- data/lib/u3d/utils.rb +121 -0
- data/lib/u3d/version.rb +31 -0
- data/lib/u3d_core.rb +30 -0
- data/lib/u3d_core/command_executor.rb +134 -0
- data/lib/u3d_core/command_runner.rb +93 -0
- data/lib/u3d_core/credentials.rb +116 -0
- data/lib/u3d_core/globals.rb +84 -0
- data/lib/u3d_core/helper.rb +149 -0
- data/lib/u3d_core/ui/disable_colors.rb +40 -0
- data/lib/u3d_core/ui/implementations/shell.rb +157 -0
- data/lib/u3d_core/ui/interface.rb +182 -0
- data/lib/u3d_core/ui/ui.rb +49 -0
- data/local_gem_install.sh +6 -0
- data/scripts/be +14 -0
- data/u3d.gemspec +41 -0
- metadata +388 -0
@@ -0,0 +1,221 @@
|
|
1
|
+
## --- BEGIN LICENSE BLOCK ---
|
2
|
+
# Copyright (c) 2016-present WeWantToKnow AS
|
3
|
+
#
|
4
|
+
# Permission is hereby granted, free of charge, to any person obtaining a copy
|
5
|
+
# of this software and associated documentation files (the "Software"), to deal
|
6
|
+
# in the Software without restriction, including without limitation the rights
|
7
|
+
# to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
8
|
+
# copies of the Software, and to permit persons to whom the Software is
|
9
|
+
# furnished to do so, subject to the following conditions:
|
10
|
+
#
|
11
|
+
# The above copyright notice and this permission notice shall be included in all
|
12
|
+
# copies or substantial portions of the Software.
|
13
|
+
#
|
14
|
+
# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
15
|
+
# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
16
|
+
# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
17
|
+
# AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
18
|
+
# LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
19
|
+
# OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
20
|
+
# SOFTWARE.
|
21
|
+
## --- END LICENSE BLOCK ---
|
22
|
+
|
23
|
+
require 'json'
|
24
|
+
|
25
|
+
module U3d
|
26
|
+
# Analyzes log by filtering output along a set of rules
|
27
|
+
class LogAnalyzer
|
28
|
+
RULES_PATH = File.expand_path('../../../config/log_rules.json', __FILE__)
|
29
|
+
MEMORY_SIZE = 10
|
30
|
+
|
31
|
+
def initialize
|
32
|
+
@lines_memory = Array.new(MEMORY_SIZE)
|
33
|
+
@active_phase = nil
|
34
|
+
@active_rule = nil
|
35
|
+
@context = {}
|
36
|
+
@rule_lines_buffer = []
|
37
|
+
@generic_rules, @phases = load_rules
|
38
|
+
end
|
39
|
+
|
40
|
+
def load_rules
|
41
|
+
data = {}
|
42
|
+
generic_rules = {}
|
43
|
+
phases = {}
|
44
|
+
File.open(RULES_PATH, 'r') do |f|
|
45
|
+
data = JSON.parse(f.read)
|
46
|
+
end
|
47
|
+
if data['GENERAL'] && data['GENERAL']['active']
|
48
|
+
data['GENERAL']['rules'].each do |rn, r|
|
49
|
+
generic_rules[rn] = r if parse_rule(r)
|
50
|
+
end
|
51
|
+
end
|
52
|
+
data.delete('GENERAL')
|
53
|
+
data.each do |name, phase|
|
54
|
+
# Phase parsing
|
55
|
+
next unless phase['active']
|
56
|
+
next if phase['phase_start_pattern'].nil?
|
57
|
+
phase['phase_start_pattern'] = Regexp.new phase['phase_start_pattern']
|
58
|
+
phase['phase_end_pattern'] = Regexp.new phase['phase_end_pattern'] if phase['phase_end_pattern']
|
59
|
+
phase.delete('comment')
|
60
|
+
# Rules parsing
|
61
|
+
temp_rules = {}
|
62
|
+
unless phase['silent'] == true
|
63
|
+
phase['rules'].each do |rn, r|
|
64
|
+
temp_rules[rn] = r if parse_rule(r)
|
65
|
+
end
|
66
|
+
end
|
67
|
+
phase['rules'] = temp_rules
|
68
|
+
phases[name] = phase
|
69
|
+
end
|
70
|
+
return generic_rules, phases
|
71
|
+
end
|
72
|
+
|
73
|
+
def parse_line(line)
|
74
|
+
# Insert new line and remove last stored line
|
75
|
+
@lines_memory.push(line).shift
|
76
|
+
|
77
|
+
# Check if phase is changing
|
78
|
+
@phases.each do |name, phase|
|
79
|
+
next if name == @active_phase
|
80
|
+
next unless line =~ phase['phase_start_pattern']
|
81
|
+
if @active_rule
|
82
|
+
# Active rule should be finished
|
83
|
+
# If it is still active during phase change, it means that something went wrong
|
84
|
+
UI.error("[#{@active_phase}] Could not finish active rule '#{@active_rule}'. Aborting it.")
|
85
|
+
@active_rule = nil
|
86
|
+
end
|
87
|
+
@active_phase = name
|
88
|
+
@context.clear
|
89
|
+
@rule_lines_buffer.clear
|
90
|
+
UI.verbose("--- Beginning #{name} phase ---")
|
91
|
+
break
|
92
|
+
end
|
93
|
+
|
94
|
+
apply_ruleset = lambda do |ruleset, header|
|
95
|
+
# Apply the active rule
|
96
|
+
if @active_rule && ruleset[@active_rule]
|
97
|
+
rule = ruleset[@active_rule]
|
98
|
+
pattern = rule['end_pattern']
|
99
|
+
|
100
|
+
# Is it the end of the rule?
|
101
|
+
if line =~ pattern
|
102
|
+
unless @rule_lines_buffer.empty?
|
103
|
+
@rule_lines_buffer.each do |l|
|
104
|
+
UI.send(rule['type'], "[#{header}] " + l)
|
105
|
+
end
|
106
|
+
end
|
107
|
+
if rule['end_message'] != false
|
108
|
+
if rule['end_message']
|
109
|
+
match = line.match(pattern)
|
110
|
+
params = match.names.map(&:to_sym).zip(match.captures).to_h
|
111
|
+
message = rule['end_message'] % params.merge(@context)
|
112
|
+
else
|
113
|
+
message = line.chomp
|
114
|
+
end
|
115
|
+
message = "[#{header}] " + message
|
116
|
+
UI.send(rule['type'], message)
|
117
|
+
end
|
118
|
+
@active_rule = nil
|
119
|
+
@context.clear
|
120
|
+
@rule_lines_buffer.clear
|
121
|
+
|
122
|
+
# It's not the end of the rules, should the line be stored?
|
123
|
+
elsif rule['store_lines']
|
124
|
+
match = false
|
125
|
+
if rule['ignore_lines']
|
126
|
+
rule['ignore_lines'].each do |pat|
|
127
|
+
if line =~ pat
|
128
|
+
match = true
|
129
|
+
break
|
130
|
+
end
|
131
|
+
end
|
132
|
+
end
|
133
|
+
@rule_lines_buffer << line.chomp unless match
|
134
|
+
end
|
135
|
+
end
|
136
|
+
|
137
|
+
# If there is no active rule, try to apply a new one
|
138
|
+
if @active_rule.nil?
|
139
|
+
ruleset.each do |rn, r|
|
140
|
+
pattern = r['start_pattern']
|
141
|
+
next unless line =~ pattern
|
142
|
+
@active_rule = rn if r['end_pattern']
|
143
|
+
match = line.match(pattern)
|
144
|
+
@context = match.names.map(&:to_sym).zip(match.captures).to_h
|
145
|
+
if r['fetch_line_at_index'] || r['fetch_first_line_not_matching']
|
146
|
+
if r['fetch_line_at_index']
|
147
|
+
fetched_line = @lines_memory.reverse[r['fetch_line_at_index']]
|
148
|
+
else
|
149
|
+
fetched_line = nil
|
150
|
+
@lines_memory.reverse.each do |l|
|
151
|
+
match = false
|
152
|
+
r['fetch_first_line_not_matching'].each do |pat|
|
153
|
+
next unless l =~ pat
|
154
|
+
match = true
|
155
|
+
break
|
156
|
+
end
|
157
|
+
next if match
|
158
|
+
fetched_line = l
|
159
|
+
break
|
160
|
+
end
|
161
|
+
end
|
162
|
+
if fetched_line
|
163
|
+
if r['fetched_line_pattern']
|
164
|
+
match = fetched_line.match(r['fetched_line_pattern'])
|
165
|
+
@context.merge!(match.names.map(&:to_sym).zip(match.captures).to_h)
|
166
|
+
end
|
167
|
+
if r['fetched_line_message'] != false
|
168
|
+
message = if r['fetched_line_message']
|
169
|
+
r['fetched_line_message'] % @context
|
170
|
+
else
|
171
|
+
fetched_line.chomp
|
172
|
+
end
|
173
|
+
message = "[#{header}] " + message
|
174
|
+
UI.send(r['type'], message)
|
175
|
+
end
|
176
|
+
end
|
177
|
+
end
|
178
|
+
if r['start_message'] != false
|
179
|
+
message = if r['start_message']
|
180
|
+
r['start_message'] % @context
|
181
|
+
else
|
182
|
+
line.chomp
|
183
|
+
end
|
184
|
+
message = "[#{header}] " + message
|
185
|
+
UI.send(r['type'], message)
|
186
|
+
end
|
187
|
+
break
|
188
|
+
end
|
189
|
+
end
|
190
|
+
end
|
191
|
+
|
192
|
+
apply_ruleset.call(@phases[@active_phase]['rules'], @active_phase) if @active_phase
|
193
|
+
apply_ruleset.call(@generic_rules, 'GENERAL')
|
194
|
+
end
|
195
|
+
|
196
|
+
private
|
197
|
+
|
198
|
+
def parse_rule(r)
|
199
|
+
return false unless r['active']
|
200
|
+
return false if r['start_pattern'].nil?
|
201
|
+
r['start_pattern'] = Regexp.new r['start_pattern']
|
202
|
+
r['end_pattern'] = Regexp.new r['end_pattern'] if r['end_pattern']
|
203
|
+
if r['fetch_line_at_index']
|
204
|
+
r.delete('fetch_line_at_index') if r['fetch_line_at_index'] >= MEMORY_SIZE
|
205
|
+
r.delete('fetch_line_at_index') if r['fetch_line_at_index'] <= 0
|
206
|
+
elsif r['fetch_first_line_not_matching']
|
207
|
+
r['fetch_first_line_not_matching'].map! { |pat| Regexp.new pat }
|
208
|
+
end
|
209
|
+
if r['fetch_line_at_index'] || r['fetch_first_line_not_matching']
|
210
|
+
r['fetched_line_pattern'] = Regexp.new r['fetched_line_pattern'] if r['fetched_line_pattern']
|
211
|
+
end
|
212
|
+
r['type'] = 'important' if r['type'] == 'warning'
|
213
|
+
if r['type'] && r['type'] != 'error' && r['type'] != 'important' && r['type'] != 'success'
|
214
|
+
r['type'] = 'message'
|
215
|
+
end
|
216
|
+
r['type'] ||= 'message'
|
217
|
+
r['ignore_lines'].map! { |pat| Regexp.new pat } if r['ignore_lines']
|
218
|
+
true
|
219
|
+
end
|
220
|
+
end
|
221
|
+
end
|
@@ -0,0 +1,71 @@
|
|
1
|
+
## --- BEGIN LICENSE BLOCK ---
|
2
|
+
# Copyright (c) 2016-present WeWantToKnow AS
|
3
|
+
#
|
4
|
+
# Permission is hereby granted, free of charge, to any person obtaining a copy
|
5
|
+
# of this software and associated documentation files (the "Software"), to deal
|
6
|
+
# in the Software without restriction, including without limitation the rights
|
7
|
+
# to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
8
|
+
# copies of the Software, and to permit persons to whom the Software is
|
9
|
+
# furnished to do so, subject to the following conditions:
|
10
|
+
#
|
11
|
+
# The above copyright notice and this permission notice shall be included in all
|
12
|
+
# copies or substantial portions of the Software.
|
13
|
+
#
|
14
|
+
# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
15
|
+
# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
16
|
+
# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
17
|
+
# AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
18
|
+
# LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
19
|
+
# OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
20
|
+
# SOFTWARE.
|
21
|
+
## --- END LICENSE BLOCK ---
|
22
|
+
|
23
|
+
require 'u3d/utils'
|
24
|
+
|
25
|
+
module U3d
|
26
|
+
class UnityVersionNumber
|
27
|
+
attr_reader :parts
|
28
|
+
|
29
|
+
def initialize(version)
|
30
|
+
parsed = Utils.parse_unity_version(version)
|
31
|
+
parsed.each_with_index do |val, index|
|
32
|
+
next if val.nil? || (index == 3)
|
33
|
+
parsed[index] = val.to_i
|
34
|
+
end
|
35
|
+
@parts = parsed
|
36
|
+
end
|
37
|
+
|
38
|
+
def to_s
|
39
|
+
"#{parts[0]}.#{parts[1]}.#{parts[2]}#{parts[3]}#{parts[4]}"
|
40
|
+
end
|
41
|
+
end
|
42
|
+
|
43
|
+
class UnityVersionComparator
|
44
|
+
include Comparable
|
45
|
+
|
46
|
+
RELEASE_LETTER_STRENGTH = { a: 1, b: 2, f: 3, p: 4 }.freeze
|
47
|
+
|
48
|
+
attr_reader :version
|
49
|
+
|
50
|
+
def <=>(other)
|
51
|
+
comp = @version.parts[0] <=> other.version.parts[0]
|
52
|
+
return comp if comp.nonzero?
|
53
|
+
comp = @version.parts[1] <=> other.version.parts[1]
|
54
|
+
return comp if comp.nonzero?
|
55
|
+
comp = @version.parts[2] <=> other.version.parts[2]
|
56
|
+
return comp if comp.nonzero?
|
57
|
+
comp = RELEASE_LETTER_STRENGTH[@version.parts[3].to_sym] <=> RELEASE_LETTER_STRENGTH[other.version.parts[3].to_sym]
|
58
|
+
return comp if comp.nonzero?
|
59
|
+
return @version.parts[4] <=> other.version.parts[4]
|
60
|
+
end
|
61
|
+
|
62
|
+
def initialize(version)
|
63
|
+
version = UnityVersionNumber.new(version.to_s)
|
64
|
+
@version = version
|
65
|
+
end
|
66
|
+
|
67
|
+
def inspect
|
68
|
+
@version
|
69
|
+
end
|
70
|
+
end
|
71
|
+
end
|
@@ -0,0 +1,207 @@
|
|
1
|
+
## --- BEGIN LICENSE BLOCK ---
|
2
|
+
# Copyright (c) 2016-present WeWantToKnow AS
|
3
|
+
#
|
4
|
+
# Permission is hereby granted, free of charge, to any person obtaining a copy
|
5
|
+
# of this software and associated documentation files (the "Software"), to deal
|
6
|
+
# in the Software without restriction, including without limitation the rights
|
7
|
+
# to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
8
|
+
# copies of the Software, and to permit persons to whom the Software is
|
9
|
+
# furnished to do so, subject to the following conditions:
|
10
|
+
#
|
11
|
+
# The above copyright notice and this permission notice shall be included in all
|
12
|
+
# copies or substantial portions of the Software.
|
13
|
+
#
|
14
|
+
# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
15
|
+
# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
16
|
+
# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
17
|
+
# AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
18
|
+
# LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
19
|
+
# OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
20
|
+
# SOFTWARE.
|
21
|
+
## --- END LICENSE BLOCK ---
|
22
|
+
|
23
|
+
require 'u3d/iniparser'
|
24
|
+
require 'u3d_core/helper'
|
25
|
+
require 'net/http'
|
26
|
+
|
27
|
+
module U3d
|
28
|
+
# Takes care of fectching versions and version list
|
29
|
+
module UnityVersions
|
30
|
+
#####################################################
|
31
|
+
# @!group URLS: Locations to fetch information from
|
32
|
+
#####################################################
|
33
|
+
# URL for the forum thread listing all the Linux releases
|
34
|
+
UNITY_LINUX_DOWNLOADS = 'https://forum.unity3d.com/threads/unity-on-linux-release-notes-and-known-issues.350256/'.freeze
|
35
|
+
# URL for the main releases for Windows and Macintosh
|
36
|
+
UNITY_DOWNLOADS = 'https://unity3d.com/get-unity/download/archive'.freeze
|
37
|
+
# URL for the patch releases for Windows and Macintosh
|
38
|
+
UNITY_PATCHES = 'https://unity3d.com/unity/qa/patch-releases'.freeze
|
39
|
+
# URL for the beta releases list, they need to be accessed after
|
40
|
+
UNITY_BETAS = 'https://unity3d.com/unity/beta/archive'.freeze
|
41
|
+
# URL for a specific beta, takes into parameter a version string (%s)
|
42
|
+
UNITY_BETA_URL = 'https://unity3d.com/unity/beta/unity%s'.freeze
|
43
|
+
|
44
|
+
#####################################################
|
45
|
+
# @!group REGEX: expressions to interpret data
|
46
|
+
#####################################################
|
47
|
+
# Captures a version and its base url
|
48
|
+
MAC_DOWNLOAD = %r{"(https?://[\w/\.-]+/[0-9a-f]{12}/)MacEditorInstaller/[a-zA-Z0-9/\.]+-(\d+\.\d+\.\d+\w\d+)\.?\w+"}
|
49
|
+
WIN_DOWNLOAD = %r{"(https?://[\w/\.-]+/[0-9a-f]{12}/)Windows..EditorInstaller/[a-zA-Z0-9/\.]+-(\d+\.\d+\.\d+\w\d+)\.?\w+"}
|
50
|
+
LINUX_DOWNLOAD = %r{"(https?://[\w/\._-]+/unity\-editor\-installer\-(\d+\.\d+\.\d+\w\d+).*\.sh)"}
|
51
|
+
# Captures a beta version in html page
|
52
|
+
UNITY_BETAVERSION_REGEX = %r{\/unity\/beta\/unity(\d+\.\d+\.\d+\w\d+)"}
|
53
|
+
UNITY_EXTRA_DOWNLOAD_REGEX = %r{"(https?:\/\/[\w\/.-]+\.unity3d\.com\/(\w+))\/[a-zA-Z\/.-]+\/download.html"}
|
54
|
+
|
55
|
+
class << self
|
56
|
+
def list_available(os: nil)
|
57
|
+
os ||= U3dCore::Helper.operating_system
|
58
|
+
|
59
|
+
case os
|
60
|
+
when :linux
|
61
|
+
return U3d::UnityVersions::LinuxVersions.list_available
|
62
|
+
when :mac
|
63
|
+
return U3d::UnityVersions::MacVersions.list_available
|
64
|
+
when :win
|
65
|
+
return U3d::UnityVersions::WindowsVersions.list_available
|
66
|
+
else
|
67
|
+
raise ArgumentError, "Operating system #{os} not supported"
|
68
|
+
end
|
69
|
+
end
|
70
|
+
|
71
|
+
def fetch_version(url, pattern)
|
72
|
+
hash = {}
|
73
|
+
data = Utils.get_ssl(url)
|
74
|
+
results = data.scan(pattern)
|
75
|
+
results.each { |capt| hash[capt[1]] = capt[0] }
|
76
|
+
return hash
|
77
|
+
end
|
78
|
+
|
79
|
+
def fetch_betas(url, pattern)
|
80
|
+
hash = {}
|
81
|
+
data = Utils.get_ssl(url)
|
82
|
+
results = data.scan(UNITY_BETAVERSION_REGEX).uniq
|
83
|
+
results.each { |beta| hash.merge!(fetch_version(UNITY_BETA_URL % beta[0], pattern)) }
|
84
|
+
hash
|
85
|
+
end
|
86
|
+
end
|
87
|
+
|
88
|
+
class LinuxVersions
|
89
|
+
class << self
|
90
|
+
def list_available
|
91
|
+
UI.message 'Loading Unity releases'
|
92
|
+
request = nil
|
93
|
+
response = nil
|
94
|
+
data = ''
|
95
|
+
uri = URI(UNITY_LINUX_DOWNLOADS)
|
96
|
+
Net::HTTP.start(uri.host, uri.port, use_ssl: true) do |http|
|
97
|
+
request = Net::HTTP::Get.new uri
|
98
|
+
request['Connection'] = 'keep-alive'
|
99
|
+
response = http.request request
|
100
|
+
|
101
|
+
case response
|
102
|
+
when Net::HTTPSuccess then
|
103
|
+
# Successfully retrieved forum content
|
104
|
+
data = response.body
|
105
|
+
when Net::HTTPRedirection then
|
106
|
+
# A session must be opened with the server before accessing forum
|
107
|
+
res = nil
|
108
|
+
cookie_str = ''
|
109
|
+
# Store the name and value of the cookies returned by the server
|
110
|
+
response['set-cookie'].gsub(/\s+/, '').split(',').each do |c|
|
111
|
+
cookie_str << c.split(';', 2)[0] + '; '
|
112
|
+
end
|
113
|
+
cookie_str.chomp!('; ')
|
114
|
+
|
115
|
+
# It should be the Unity register API
|
116
|
+
uri = URI(response['location'])
|
117
|
+
Net::HTTP.start(uri.host, uri.port, use_ssl: true) do |http_api|
|
118
|
+
request = Net::HTTP::Get.new uri
|
119
|
+
request['Connection'] = 'keep-alive'
|
120
|
+
res = http_api.request request
|
121
|
+
end
|
122
|
+
|
123
|
+
raise 'Unexpected result' unless res.is_a? Net::HTTPRedirection
|
124
|
+
# It should be a redirection to the forum to perform authentication
|
125
|
+
uri = URI(res['location'])
|
126
|
+
|
127
|
+
request = Net::HTTP::Get.new uri
|
128
|
+
request['Connection'] = 'keep-alive'
|
129
|
+
request['Cookie'] = cookie_str
|
130
|
+
|
131
|
+
res = http.request request
|
132
|
+
|
133
|
+
raise 'Unable to establish a session with Unity forum' unless res.is_a? Net::HTTPRedirection
|
134
|
+
|
135
|
+
cookie_str << '; ' + res['set-cookie'].gsub(/\s+/, '').split(';', 2)[0]
|
136
|
+
|
137
|
+
uri = URI(res['location'])
|
138
|
+
|
139
|
+
request = Net::HTTP::Get.new uri
|
140
|
+
request['Connection'] = 'keep-alive'
|
141
|
+
request['Cookie'] = cookie_str
|
142
|
+
|
143
|
+
res = http.request request
|
144
|
+
|
145
|
+
data = res.body if res.is_a? Net::HTTPSuccess
|
146
|
+
else raise "Request failed with status #{response.code}"
|
147
|
+
end
|
148
|
+
end
|
149
|
+
data.gsub(/[ \t]+/, '').each_line { |l| puts l if /<a href=/ =~ l }
|
150
|
+
versions = {}
|
151
|
+
results = data.scan(LINUX_DOWNLOAD)
|
152
|
+
results.each do |capt|
|
153
|
+
versions[capt[1]] = capt[0]
|
154
|
+
end
|
155
|
+
if versions.count.zero?
|
156
|
+
UI.important 'Found no releases'
|
157
|
+
else
|
158
|
+
UI.success "Found #{versions.count} releases."
|
159
|
+
end
|
160
|
+
versions
|
161
|
+
end
|
162
|
+
end
|
163
|
+
end
|
164
|
+
|
165
|
+
class MacVersions
|
166
|
+
class << self
|
167
|
+
def list_available
|
168
|
+
versions = {}
|
169
|
+
UI.message 'Loading Unity releases'
|
170
|
+
current = UnityVersions.fetch_version(UNITY_DOWNLOADS, MAC_DOWNLOAD)
|
171
|
+
UI.success "Found #{current.count} releases." if current.count.nonzero?
|
172
|
+
versions = versions.merge(current)
|
173
|
+
UI.message 'Loading Unity patch releases'
|
174
|
+
current = UnityVersions.fetch_version(UNITY_PATCHES, MAC_DOWNLOAD)
|
175
|
+
UI.success "Found #{current.count} patch releases." if current.count.nonzero?
|
176
|
+
versions = versions.merge(current)
|
177
|
+
UI.message 'Loading Unity beta releases'
|
178
|
+
current = UnityVersions.fetch_betas(UNITY_BETAS, MAC_DOWNLOAD)
|
179
|
+
UI.success "Found #{current.count} beta releases." if current.count.nonzero?
|
180
|
+
versions = versions.merge(current)
|
181
|
+
versions
|
182
|
+
end
|
183
|
+
end
|
184
|
+
end
|
185
|
+
|
186
|
+
class WindowsVersions
|
187
|
+
class << self
|
188
|
+
def list_available
|
189
|
+
versions = {}
|
190
|
+
UI.message 'Loading Unity releases'
|
191
|
+
current = UnityVersions.fetch_version(UNITY_DOWNLOADS, WIN_DOWNLOAD)
|
192
|
+
UI.success "Found #{current.count} releases." if current.count.nonzero?
|
193
|
+
versions = versions.merge(current)
|
194
|
+
UI.message 'Loading Unity patch releases'
|
195
|
+
current = UnityVersions.fetch_version(UNITY_PATCHES, WIN_DOWNLOAD)
|
196
|
+
UI.success "Found #{current.count} patch releases." if current.count.nonzero?
|
197
|
+
versions = versions.merge(current)
|
198
|
+
UI.message 'Loading Unity beta releases'
|
199
|
+
current = UnityVersions.fetch_betas(UNITY_BETAS, WIN_DOWNLOAD)
|
200
|
+
UI.success "Found #{current.count} beta releases." if current.count.nonzero?
|
201
|
+
versions = versions.merge(current)
|
202
|
+
versions
|
203
|
+
end
|
204
|
+
end
|
205
|
+
end
|
206
|
+
end
|
207
|
+
end
|