u3d 0.9.3 → 0.9.4

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -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