u3d 0.9.3 → 0.9.4

Sign up to get free protection for your applications and to get access to all the features.
@@ -24,6 +24,7 @@ require 'json'
24
24
 
25
25
  module U3d
26
26
  # Analyzes log by filtering output along a set of rules
27
+ # rubocop:disable ClassLength, PerceivedComplexity, BlockNesting
27
28
  class LogAnalyzer
28
29
  RULES_PATH = File.expand_path('../../../config/log_rules.json', __FILE__)
29
30
  MEMORY_SIZE = 10
@@ -227,4 +228,5 @@ module U3d
227
228
  true
228
229
  end
229
230
  end
231
+ # rubocop:enable ClassLength, PerceivedComplexity, BlockNesting
230
232
  end
@@ -0,0 +1,45 @@
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_core/helper'
24
+
25
+ module U3d
26
+ class UnityProject
27
+ attr_reader :path
28
+
29
+ def initialize(path)
30
+ @path = path
31
+ end
32
+
33
+ def exist?
34
+ Dir.exist?("#{@path}/Assets") && Dir.exist?("#{@path}/ProjectSettings")
35
+ end
36
+
37
+ def editor_version
38
+ require 'yaml'
39
+ yaml = YAML.safe_load(File.read("#{@path}/ProjectSettings/ProjectVersion.txt"))
40
+ version = yaml['m_EditorVersion']
41
+ version.gsub!(/(\d+\.\d+\.\d+)(?:x)?(\w\d+)(?:Linux)?/, '\1\2') if Helper.linux?
42
+ version
43
+ end
44
+ end
45
+ end
@@ -28,16 +28,7 @@ module U3d
28
28
  # Launches Unity with given arguments
29
29
  class Runner
30
30
  def run(installation, args, raw_logs: false)
31
- log_file = find_logFile_in_args(args)
32
-
33
- if log_file # we wouldn't want to do that for the default log file.
34
- File.delete(log_file) if File.file?(log_file) # We only delete real files
35
- else
36
- log_file = installation.default_log_file
37
- end
38
-
39
- Utils.ensure_dir File.dirname(log_file)
40
- FileUtils.touch(log_file) unless File.exist? log_file
31
+ log_file = find_and_prepare_logfile(installation, args)
41
32
 
42
33
  tail_thread = Thread.new do
43
34
  begin
@@ -64,7 +55,7 @@ module U3d
64
55
  else
65
56
  args.map!(&:shellescape)
66
57
  end
67
-
58
+
68
59
  U3dCore::CommandExecutor.execute(command: args, print_all: true)
69
60
  ensure
70
61
  sleep 1
@@ -72,20 +63,38 @@ module U3d
72
63
  end
73
64
  end
74
65
 
75
- def find_logFile_in_args(args)
76
- find_arg_in_args('-logFile', args)
77
- end
66
+ def find_and_prepare_logfile(installation, args)
67
+ log_file = Runner.find_logFile_in_args(args)
68
+
69
+ if log_file # we wouldn't want to do that for the default log file.
70
+ File.delete(log_file) if File.file?(log_file) # We only delete real files
71
+ else
72
+ log_file = installation.default_log_file
73
+ end
78
74
 
79
- def find_projectpath_in_args(args)
80
- find_arg_in_args('-projectpath', args)
75
+ Utils.ensure_dir File.dirname(log_file)
76
+ FileUtils.touch(log_file) unless File.exist? log_file
77
+ log_file
81
78
  end
82
79
 
83
- def find_arg_in_args(arg_to_find, args)
84
- raise 'Only arguments of type array supported right now' unless args.is_a?(Array)
85
- args.each_with_index do |arg, index|
86
- return args[index + 1] if arg == arg_to_find && index < args.count - 1
80
+ class << self
81
+ # rubocop:disable MethodName
82
+ def find_logFile_in_args(args)
83
+ # rubocop:enable MethodName
84
+ find_arg_in_args('-logFile', args)
85
+ end
86
+
87
+ def find_projectpath_in_args(args)
88
+ find_arg_in_args('-projectpath', args)
89
+ end
90
+
91
+ def find_arg_in_args(arg_to_find, args)
92
+ raise 'Only arguments of type array supported right now' unless args.is_a?(Array)
93
+ args.each_with_index do |arg, index|
94
+ return args[index + 1] if arg == arg_to_find && index < args.count - 1
95
+ end
96
+ nil
87
97
  end
88
- nil
89
98
  end
90
99
 
91
100
  private
@@ -0,0 +1,60 @@
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
+
25
+ module U3d
26
+ class UnityVersionDefinition
27
+ attr_accessor :version, :os, :url, :ini
28
+
29
+ def initialize(version, os, cached_versions)
30
+ @version = version
31
+ @os = os
32
+ # Cache is assumed to be correct
33
+ @url = cached_versions ? cached_versions[version] : nil
34
+ begin
35
+ @ini = INIparser.load_ini(version, cached_versions, os: os)
36
+ rescue => e
37
+ UI.error "Could not load INI file for version #{@version} on #{@os}: #{e}"
38
+ @ini = nil
39
+ end
40
+ end
41
+
42
+ def available_packages
43
+ @ini.keys
44
+ end
45
+
46
+ def [](key)
47
+ return nil unless @ini
48
+ @ini[key]
49
+ end
50
+
51
+ def size_in_kb(package)
52
+ return -1 unless @ini[package] && @ini[package]['size']
53
+ @os == :win ? @ini[package]['size'] * 1024 : @ini[package]['size']
54
+ end
55
+
56
+ def self.create_fake(version, size, url)
57
+ INIparser.create_linux_ini(version, size, url)
58
+ end
59
+ end
60
+ end
@@ -20,7 +20,7 @@
20
20
  # SOFTWARE.
21
21
  ## --- END LICENSE BLOCK ---
22
22
 
23
- require 'u3d/iniparser'
23
+ require 'u3d/unity_version_definition'
24
24
  require 'u3d_core/helper'
25
25
  require 'net/http'
26
26
 
@@ -91,7 +91,52 @@ module U3d
91
91
  class << self
92
92
  def list_available
93
93
  UI.message 'Loading Unity releases'
94
- request = nil
94
+
95
+ data = linux_forum_page_content
96
+
97
+ versions = {}
98
+ results = data.scan(LINUX_DOWNLOAD_DATED)
99
+ results.each do |capt|
100
+ save_package_size(capt[1], capt[0])
101
+ versions[capt[1]] = capt[0]
102
+ end
103
+
104
+ response = nil
105
+ results = data.scan(LINUX_DOWNLOAD_RECENT_PAGE)
106
+ results.each do |page|
107
+ response = linux_forum_version_page_content(page[0])
108
+ if response.is_a? Net::HTTPSuccess
109
+ capt = response.body.match(LINUX_DOWNLOAD_RECENT_FILE)
110
+ if capt && capt[1] && capt[2]
111
+ ver = capt[2].delete('x')
112
+ UI.important "Version #{ver} does not match standard Unity versions" unless ver =~ Utils::UNITY_VERSION_REGEX
113
+ save_package_size(ver, capt[1])
114
+ versions[ver] = capt[1]
115
+ else
116
+ UI.error("Could not retrieve a fitting file from #{url}")
117
+ end
118
+ else
119
+ UI.error("Could not access #{url}")
120
+ end
121
+ end
122
+ if versions.count.zero?
123
+ UI.important 'Found no releases'
124
+ else
125
+ UI.success "Found #{versions.count} releases."
126
+ end
127
+ versions
128
+ end
129
+
130
+ def save_package_size(version, url)
131
+ size = Utils.get_url_content_length(url)
132
+ if size
133
+ UnityVersionDefinition.create_fake(version, size, url)
134
+ else
135
+ UI.important "u3d tried to get the size of the installer for version #{version}, but wasn't able to"
136
+ end
137
+ end
138
+
139
+ def linux_forum_page_content
95
140
  response = nil
96
141
  data = ''
97
142
  uri = URI(UNITY_LINUX_DOWNLOADS)
@@ -148,38 +193,15 @@ module U3d
148
193
  else raise "Request failed with status #{response.code}"
149
194
  end
150
195
  end
151
- data.gsub(/[ \t]+/, '').each_line { |l| puts l if /<a href=/ =~ l }
152
- versions = {}
153
- results = data.scan(LINUX_DOWNLOAD_DATED)
154
- results.each do |capt|
155
- versions[capt[1]] = capt[0]
156
- end
196
+ data
197
+ end
157
198
 
158
- results = data.scan(LINUX_DOWNLOAD_RECENT_PAGE)
159
- results.each do |page|
160
- url = page[0]
161
- uri = URI(url)
162
- Net::HTTP.start(uri.host, uri.port) do |http|
163
- request = Net::HTTP::Get.new uri
164
- response = http.request request
165
- end
166
- if response.kind_of? Net::HTTPSuccess
167
- capt = response.body.match(LINUX_DOWNLOAD_RECENT_FILE)
168
- if capt && capt[1] && capt[2]
169
- versions[capt[2].delete('x')] = capt[1]
170
- else
171
- UI.error("Could not retrieve a fitting file from #{url}")
172
- end
173
- else
174
- UI.error("Could not access #{url}")
175
- end
176
- end
177
- if versions.count.zero?
178
- UI.important 'Found no releases'
179
- else
180
- UI.success "Found #{versions.count} releases."
199
+ def linux_forum_version_page_content(url)
200
+ uri = URI(url)
201
+ Net::HTTP.start(uri.host, uri.port) do |http|
202
+ request = Net::HTTP::Get.new uri
203
+ return http.request request
181
204
  end
182
- versions
183
205
  end
184
206
  end
185
207
  end
@@ -58,6 +58,16 @@ module U3d
58
58
  end
59
59
  end
60
60
 
61
+ def get_url_content_length(url)
62
+ uri = URI(url)
63
+ size = nil
64
+ Net::HTTP.start(uri.host, uri.port) do |http|
65
+ response = http.request_head url
66
+ size = Integer(response['Content-Length'])
67
+ end
68
+ size
69
+ end
70
+
61
71
  def hashfile(file_path, blocksize: 65_536)
62
72
  require 'digest'
63
73
  raise ArgumentError, 'Not a file' unless File.file?(file_path)
@@ -21,7 +21,7 @@
21
21
  ## --- END LICENSE BLOCK ---
22
22
 
23
23
  module U3d
24
- VERSION = '0.9.3'.freeze
24
+ VERSION = '0.9.4'.freeze
25
25
  DESCRIPTION = 'Provides numerous tools for installing, managing and running the Unity3D game engine from command line.'.freeze
26
26
  UNITY_VERSIONS_NOTE = "Unity3d uses the following version formatting: 0.0.0x0. The \'x\' can takes different values:\n"\
27
27
  "\t. 'f' are the main release candidates for Unity3d\n"\
@@ -61,23 +61,19 @@ module U3dCore
61
61
  print_all = true if U3dCore::Globals.verbose?
62
62
  prefix ||= {}
63
63
 
64
- output = []
65
64
  command = command.join(' ') if command.is_a?(Array)
66
65
  UI.command(command) if print_command
67
66
 
68
67
  # this is only used to show the "Loading text"...
69
68
  UI.command_output(loading) if print_all && loading
70
69
 
71
- if admin
72
- cred = U3dCore::Credentials.new(user: ENV['USER'])
73
- if Helper.windows?
74
- raise CredentialsError, "The command \'#{command}\' must be run in administrative shell" unless has_admin_privileges?
75
- else
76
- command = "sudo -k && echo #{cred.password.shellescape} | sudo -S bash -c \"#{command}\""
77
- end
78
- UI.verbose 'Admin privileges granted for command execution'
79
- end
70
+ command = grant_admin_privileges(command) if admin
80
71
 
72
+ execute_command(command: command, print_all: print_all, error: error, prefix: prefix)
73
+ end
74
+
75
+ def execute_command(command: nil, print_all: nil, error: nil, prefix: nil)
76
+ output = []
81
77
  begin
82
78
  status = U3dCore::Runner.run(command) do |stdin, _stdout, _pid|
83
79
  stdin.each do |l|
@@ -109,7 +105,9 @@ module U3dCore
109
105
  return output.join("\n")
110
106
  end
111
107
 
108
+ # rubocop:disable PredicateName
112
109
  def has_admin_privileges?
110
+ # rubocop:enable PredicateName
113
111
  if Helper.windows?
114
112
  begin
115
113
  result = system('reg query HKU\\S-1-5-19', out: File::NULL, err: File::NULL)
@@ -120,8 +118,8 @@ module U3dCore
120
118
  credentials = U3dCore::Credentials.new(user: ENV['USER'])
121
119
  begin
122
120
  result = system("sudo -k && echo #{credentials.password.shellescape} | sudo -S /usr/bin/whoami",
123
- out: File::NULL,
124
- err: File::NULL)
121
+ out: File::NULL,
122
+ err: File::NULL)
125
123
  rescue
126
124
  result = false
127
125
  end
@@ -130,6 +128,19 @@ module U3dCore
130
128
  # returns false if result is nil (command execution fail)
131
129
  return (result ? true : false)
132
130
  end
131
+
132
+ def grant_admin_privileges(command)
133
+ cred = U3dCore::Credentials.new(user: ENV['USER'])
134
+ if Helper.windows?
135
+ raise CredentialsError, "The command \'#{command}\' must be run in administrative shell" unless has_admin_privileges?
136
+ else
137
+ command = "sudo -k && echo #{cred.password.shellescape} | sudo -S bash -c \"#{command}\""
138
+ end
139
+ UI.verbose 'Admin privileges granted for command execution'
140
+ command
141
+ end
133
142
  end
143
+
144
+ private_class_method :execute_command
134
145
  end
135
146
  end
@@ -21,6 +21,8 @@
21
21
  # SOFTWARE.
22
22
  ## --- END LICENSE BLOCK ---
23
23
 
24
+ require 'English'
25
+
24
26
  module U3dCore
25
27
  # this module is meant to be private to this lib
26
28
  module Runner
@@ -60,17 +62,21 @@ module U3dCore
60
62
  yield r, w, p
61
63
  # if the process has closed, ruby might raise an exception if we try
62
64
  # to do I/O on a closed stream. This behavior is platform specific
65
+ # rubocop:disable HandleExceptions
63
66
  rescue Errno::EIO
67
+ # rubocop:enable HandleExceptions
64
68
  ensure
65
69
  begin
66
70
  Process.wait p
67
71
  # The process might have exited.
68
72
  # This behavior is also ruby version dependent.
73
+ # rubocop:disable HandleExceptions
69
74
  rescue Errno::ECHILD, PTY::ChildExited
70
75
  end
76
+ # rubocop:enable HandleExceptions
71
77
  end
72
78
  end
73
- $?.exitstatus
79
+ $CHILD_STATUS.exitstatus
74
80
  end
75
81
  end
76
82
 
@@ -105,8 +105,8 @@ module U3dCore
105
105
  UI.message 'Deleting credentials from the keychain'
106
106
  Security::InternetPassword.delete(server: MAC_U3D_SERVER)
107
107
  end
108
- else
109
- UI.verbose 'Keychain may store invalid credentials for u3d' if Helper.mac?
108
+ elsif Helper.mac?
109
+ UI.verbose 'Keychain may store invalid credentials for u3d'
110
110
  end
111
111
  end
112
112
  end
@@ -33,7 +33,7 @@ module U3dCore
33
33
  attr_writer :verbose, :log_timestamps, :use_keychain, :do_not_login
34
34
 
35
35
  def attributes
36
- @attributes ||= ((methods - public_instance_methods).grep(/=$/) - [:<=, :>=]).map do |s|
36
+ @attributes ||= ((methods - public_instance_methods).grep(/=$/) - %i[<= >=]).map do |s|
37
37
  a = s.to_s
38
38
  a[0..(a.length - 2)] # remove the '='
39
39
  end
@@ -69,7 +69,8 @@ module U3dCore
69
69
  end
70
70
  end
71
71
 
72
- def respond_to?(method_sym, include_private = false)
72
+ def respond_to_missing?(method_sym, include_private = false)
73
+ # rubocop:disable GuardClause
73
74
  if method_sym.to_s =~ /^with_(.*)$/
74
75
  return attributes.include? Regexp.last_match(1)
75
76
  elsif method_sym.to_s =~ /^(.*)\?$/
@@ -77,6 +78,7 @@ module U3dCore
77
78
  else
78
79
  super
79
80
  end
81
+ # rubocop:enable GuardClause
80
82
  end
81
83
  end
82
84
  private_class_method :is?, :with, :attributes