u3d 1.2.3 → 1.3.0

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.
Files changed (61) hide show
  1. checksums.yaml +5 -5
  2. data/.circleci/config.yml +33 -10
  3. data/.github/workflows/ci.yml +35 -0
  4. data/.github_changelog_generator +3 -1
  5. data/.gitignore +1 -0
  6. data/.rubocop.yml +15 -3
  7. data/CHANGELOG.md +62 -11
  8. data/Gemfile.lock +147 -87
  9. data/Rakefile +12 -7
  10. data/appveyor.yml +25 -6
  11. data/examples/Example1/Gemfile +4 -2
  12. data/examples/Example1/Gemfile.lock +8 -6
  13. data/examples/Example1/Rakefile +2 -0
  14. data/examples/Example1/fastlane/Fastfile +2 -0
  15. data/examples/Example2/Gemfile +4 -2
  16. data/examples/Example2/Gemfile.lock +12 -7
  17. data/examples/Example2/fastlane/Fastfile +2 -0
  18. data/exe/u3d +3 -1
  19. data/lib/u3d/asset.rb +6 -2
  20. data/lib/u3d/cache.rb +14 -10
  21. data/lib/u3d/commands.rb +14 -9
  22. data/lib/u3d/commands_generator.rb +6 -4
  23. data/lib/u3d/compatibility.rb +2 -0
  24. data/lib/u3d/download_validator.rb +6 -3
  25. data/lib/u3d/downloader.rb +12 -8
  26. data/lib/u3d/failure_reporter.rb +4 -3
  27. data/lib/u3d/hub_modules_parser.rb +24 -7
  28. data/lib/u3d/ini_modules_parser.rb +10 -8
  29. data/lib/u3d/installation.rb +31 -49
  30. data/lib/u3d/installer.rb +44 -33
  31. data/lib/u3d/log_analyzer.rb +31 -27
  32. data/lib/u3d/unity_license.rb +2 -0
  33. data/lib/u3d/unity_module.rb +2 -0
  34. data/lib/u3d/unity_project.rb +4 -1
  35. data/lib/u3d/unity_runner.rb +12 -10
  36. data/lib/u3d/unity_version_definition.rb +3 -0
  37. data/lib/u3d/unity_version_number.rb +8 -2
  38. data/lib/u3d/unity_versions.rb +28 -23
  39. data/lib/u3d/utils.rb +82 -15
  40. data/lib/u3d/version.rb +8 -6
  41. data/lib/u3d.rb +2 -0
  42. data/lib/u3d_core/admin_tools.rb +2 -0
  43. data/lib/u3d_core/command_executor.rb +11 -7
  44. data/lib/u3d_core/command_runner.rb +17 -19
  45. data/lib/u3d_core/core_ext/hash.rb +2 -0
  46. data/lib/u3d_core/core_ext/operating_system_symbol.rb +3 -0
  47. data/lib/u3d_core/core_ext/string.rb +2 -0
  48. data/lib/u3d_core/credentials.rb +9 -7
  49. data/lib/u3d_core/env.rb +3 -0
  50. data/lib/u3d_core/globals.rb +7 -7
  51. data/lib/u3d_core/helper.rb +6 -4
  52. data/lib/u3d_core/ui/disable_colors.rb +2 -0
  53. data/lib/u3d_core/ui/implementations/shell.rb +8 -5
  54. data/lib/u3d_core/ui/interface.rb +3 -0
  55. data/lib/u3d_core/ui/ui.rb +5 -4
  56. data/lib/u3d_core/update_checker/changelog.rb +4 -0
  57. data/lib/u3d_core/update_checker/update_checker.rb +7 -8
  58. data/lib/u3d_core/version.rb +2 -0
  59. data/lib/u3d_core.rb +2 -0
  60. data/u3d.gemspec +19 -9
  61. metadata +101 -30
data/lib/u3d/cache.rb CHANGED
@@ -1,3 +1,5 @@
1
+ # frozen_string_literal: true
2
+
1
3
  ## --- BEGIN LICENSE BLOCK ---
2
4
  # Copyright (c) 2016-present WeWantToKnow AS
3
5
  #
@@ -32,12 +34,12 @@ module U3d
32
34
  using ::CoreExtensions::OperatingSystem
33
35
 
34
36
  # Name of the cache file
35
- DEFAULT_NAME = 'cache.json'.freeze
37
+ DEFAULT_NAME = 'cache.json'
36
38
  # Maximum duration after which the cache is considered outdated
37
39
  # Currently set to 24h
38
40
  CACHE_LIFE = 60 * 60 * 24
39
41
 
40
- GLOBAL_CACHE_URL = 'https://dragonbox.github.io/unities/v1/versions.json'.freeze
42
+ GLOBAL_CACHE_URL = 'https://dragonbox.github.io/unities/v1/versions.json'
41
43
 
42
44
  private
43
45
 
@@ -49,11 +51,13 @@ module U3d
49
51
 
50
52
  def [](key)
51
53
  return nil if @cache[key].nil?
54
+
52
55
  @cache[key]
53
56
  end
54
57
 
55
58
  def initialize(path: nil, force_os: nil, force_refresh: false, offline: false, central_cache: false)
56
59
  raise "Cache: cannot specify both offline and force_refresh" if offline && force_refresh
60
+
57
61
  @path = path || Cache.default_os_path
58
62
  @cache = {}
59
63
  os = force_os || U3dCore::Helper.operating_system
@@ -78,23 +82,23 @@ module U3d
78
82
  def check_for_update(file_path, os)
79
83
  need_update = false
80
84
  data = {}
81
- if !File.file?(file_path)
82
- need_update = true
83
- else
85
+ if File.file?(file_path)
84
86
  begin
85
87
  File.open(file_path, 'r') do |f|
86
88
  data = JSON.parse(f.read)
87
89
  end
88
- rescue JSON::ParserError => json_error
89
- UI.error 'Failed to parse cache.json: ' + json_error.to_s
90
+ rescue JSON::ParserError => e
91
+ UI.error "Failed to parse cache.json: #{e}"
90
92
  need_update = true
91
- rescue SystemCallError => file_error
92
- UI.error 'Failed to open cache.json: ' + file_error.to_s
93
+ rescue SystemCallError => e
94
+ UI.error "Failed to open cache.json: #{e}"
93
95
  need_update = true
94
96
  else
95
97
  need_update = os_data_need_update?(data, os)
96
98
  data[os.id2name] = nil if need_update
97
99
  end
100
+ else
101
+ need_update = true
98
102
  end
99
103
  return need_update, data
100
104
  end
@@ -111,7 +115,7 @@ module U3d
111
115
  update_cache(os) unless central_cache && fetch_central_cache(os)
112
116
 
113
117
  File.delete(file_path) if File.file?(file_path)
114
- File.open(file_path, 'w') { |f| f.write(@cache.to_json) }
118
+ File.write(file_path, @cache.to_json)
115
119
  end
116
120
 
117
121
  # Fetches central versions.json. Ignore it if it is too old
data/lib/u3d/commands.rb CHANGED
@@ -1,3 +1,5 @@
1
+ # frozen_string_literal: true
2
+
1
3
  ## --- BEGIN LICENSE BLOCK ---
2
4
  # Copyright (c) 2016-present WeWantToKnow AS
3
5
  #
@@ -37,7 +39,7 @@ require 'fileutils'
37
39
 
38
40
  module U3d
39
41
  # API for U3d, redirecting calls to class they concern
40
- # rubocop:disable ClassLength
42
+ # rubocop:disable Metrics/ClassLength
41
43
  class Commands
42
44
  using ::CoreExtensions::Extractable
43
45
 
@@ -51,18 +53,18 @@ module U3d
51
53
  return
52
54
  end
53
55
  list.each do |u|
54
- version_format = "Version %-15{version} [%<build_number>s] %<do_not_move>s(%<root_path>s)"
56
+ version_format = "Version %-15<version>s [%<build_number>s] %<do_not_move>s(%<root_path>s)"
55
57
  do_not_move = u.do_not_move? ? '!'.red.bold : ' '
56
58
  h = { version: u.version, build_number: u.build_number, root_path: u.root_path, do_not_move: do_not_move }
57
59
  UI.message version_format % h
58
60
  packages = u.packages
59
61
  next unless options[:packages] && packages && !packages.empty?
62
+
60
63
  UI.message 'Packages:'
61
64
  packages.each { |pack| UI.message " - #{pack}" }
62
65
  end
63
66
  end
64
67
 
65
- # rubocop:disable Style/FormatStringToken
66
68
  def console
67
69
  require 'irb'
68
70
  ARGV.clear
@@ -81,7 +83,6 @@ module U3d
81
83
 
82
84
  catch(:IRB_EXIT) { @irb.eval_input }
83
85
  end
84
- # rubocop:enable Style/FormatStringToken
85
86
 
86
87
  def move(args: {}, options: {})
87
88
  long_name = options[:long]
@@ -131,6 +132,7 @@ module U3d
131
132
  v = cache_versions[k]
132
133
  UI.message "Version #{k}: " + v.to_s.cyan.underline
133
134
  next unless show_packages
135
+
134
136
  version_packages = packages[k]
135
137
  UI.message 'Packages:'
136
138
  version_packages.each { |package| UI.message " - #{package.id.capitalize}" }
@@ -166,6 +168,7 @@ module U3d
166
168
  files = Downloader.fetch_modules(definition, packages: packages, download: options[:download])
167
169
 
168
170
  return unless options[:install]
171
+
169
172
  Installer.install_modules(files, definition.version, installation_path: options[:installation_path])
170
173
  end
171
174
 
@@ -222,12 +225,14 @@ module U3d
222
225
  action = args[0]
223
226
  raise "Please specify an action to perform, one of #{credentials_actions.join(',')}" unless action
224
227
  raise "Unknown action '#{action}'. Use one of #{credentials_actions.join(',')}" unless credentials_actions.include? action
225
- if action == 'add'
228
+
229
+ case action
230
+ when 'add'
226
231
  U3dCore::Globals.use_keychain = true
227
232
  # credentials = U3dCore::Credentials.new(user: ENV['USER'])
228
233
  # credentials.login # ask password
229
234
  UI.error 'Invalid credentials' unless U3dCore::CommandExecutor.has_admin_privileges?
230
- elsif action == 'remove'
235
+ when 'remove'
231
236
  U3dCore::Globals.use_keychain = true
232
237
  U3dCore::Credentials.new(user: ENV['USER']).forget_credentials(force: true)
233
238
  else
@@ -269,8 +274,7 @@ module U3d
269
274
  def cache_versions(os, offline: false, force_refresh: false, central_cache: true)
270
275
  cache = Cache.new(force_os: os, offline: offline, force_refresh: force_refresh, central_cache: central_cache)
271
276
  cache_os = cache[os.id2name] || {}
272
- cache_versions = cache_os['versions'] || {}
273
- cache_versions
277
+ cache_os['versions'] || {}
274
278
  end
275
279
 
276
280
  def verify_package_names(packages, definition)
@@ -418,6 +422,7 @@ module U3d
418
422
  package = definition[package_name]
419
423
  return true unless package.depends_on
420
424
  return true if unity.package_installed?(package.depends_on)
425
+
421
426
  installing.map { |other| definition[other] }.any? do |other|
422
427
  other.id == package.depends_on || other.name == package.depends_on
423
428
  end
@@ -430,7 +435,7 @@ module U3d
430
435
  end
431
436
  end
432
437
  end
433
- # rubocop:enable ClassLength
438
+ # rubocop:enable Metrics/ClassLength
434
439
  end
435
440
 
436
441
  class InstallationSetupError < StandardError
@@ -1,3 +1,5 @@
1
+ # frozen_string_literal: true
2
+
1
3
  ## --- BEGIN LICENSE BLOCK ---
2
4
  # Copyright (c) 2016-present WeWantToKnow AS
3
5
  #
@@ -28,12 +30,12 @@ HighLine.track_eof = false
28
30
 
29
31
  module U3d
30
32
  # CLI using commander gem for u3d
31
- # rubocop:disable ClassLength
33
+ # rubocop:disable Metrics/ClassLength
32
34
  class CommandsGenerator
33
35
  include Commander::Methods
34
36
  UI = U3dCore::UI
35
37
 
36
- UNICODE_FILE = File.expand_path('../../assets/utf8.txt', __FILE__)
38
+ UNICODE_FILE = File.expand_path('../assets/utf8.txt', __dir__)
37
39
 
38
40
  def self.start
39
41
  U3dCore::UpdateChecker.start_looking_for_update('u3d')
@@ -97,7 +99,7 @@ Fore more information about how the rules work, see https://github.com/DragonBox
97
99
  c.option '-u', '--unity_version STRING', String, 'Version of Unity to run with. If not specified, it runs with the version of the project (either specified as -projectPath or current)'
98
100
  c.option '-r', '--raw_logs', 'Raw Unity output, not filtered by u3d\'s log prettifier'
99
101
  c.action do |args, options|
100
- UI.user_error! "Run doesn't take arguments. Did you forget '--' or did you mistake your command? (#{args})" if args.count > 0
102
+ UI.user_error! "Run doesn't take arguments. Did you forget '--' or did you mistake your command? (#{args})" if args.count.positive?
101
103
  U3dCore::Globals.log_timestamps = true
102
104
  Commands.run(options: convert_options(options), run_args: run_args)
103
105
  end
@@ -263,5 +265,5 @@ More on that: https://forum.unity3d.com/threads/unity-on-linux-release-notes-and
263
265
  run!
264
266
  end
265
267
  end
266
- # rubocop:enable ClassLength
268
+ # rubocop:enable Metrics/ClassLength
267
269
  end
@@ -1,3 +1,5 @@
1
+ # frozen_string_literal: true
2
+
1
3
  ## --- BEGIN LICENSE BLOCK ---
2
4
  # Copyright (c) 2016-present WeWantToKnow AS
3
5
  #
@@ -1,3 +1,5 @@
1
+ # frozen_string_literal: true
2
+
1
3
  ## --- BEGIN LICENSE BLOCK ---
2
4
  # Copyright (c) 2016-present WeWantToKnow AS
3
5
  #
@@ -51,7 +53,8 @@ module U3d
51
53
 
52
54
  class LinuxValidator < DownloadValidator
53
55
  def validate(package, file, definition)
54
- return size_validation(expected: definition[package].download_size, actual: File.size(file)) if definition[package] && definition[package].download_size
56
+ return size_validation(expected: definition[package].download_size, actual: File.size(file)) if definition[package]&.download_size
57
+
55
58
  UI.important "No file validation available, #{file} is assumed to be correct"
56
59
  true
57
60
  end
@@ -59,7 +62,7 @@ module U3d
59
62
 
60
63
  class MacValidator < DownloadValidator
61
64
  def validate(package, file, definition)
62
- if definition[package].download_size % 1000 && definition[package].checksum.nil?
65
+ if (definition[package].download_size % 1000) && definition[package].checksum.nil?
63
66
  UI.verbose "File '#{definition[package].name}' seems external. Validation skipped"
64
67
  return true
65
68
  end
@@ -71,7 +74,7 @@ module U3d
71
74
  class WindowsValidator < DownloadValidator
72
75
  def validate(package, file, definition)
73
76
  # External packages have no md5 and a false size value
74
- if definition[package].download_size % 1000 && definition[package].checksum.nil?
77
+ if (definition[package].download_size % 1000) && definition[package].checksum.nil?
75
78
  UI.verbose "File '#{definition[package].name}' seems external. Validation skipped"
76
79
  return true
77
80
  end
@@ -1,3 +1,5 @@
1
+ # frozen_string_literal: true
2
+
1
3
  ## --- BEGIN LICENSE BLOCK ---
2
4
  # Copyright (c) 2016-present WeWantToKnow AS
3
5
  #
@@ -27,13 +29,13 @@ module U3d
27
29
  # Take care of downloading files and packages
28
30
  module Downloader
29
31
  # Name of the directory for the package downloading
30
- DOWNLOAD_DIRECTORY = 'Unity_Packages'.freeze
32
+ DOWNLOAD_DIRECTORY = 'Unity_Packages'
31
33
  # Path to the directory for the package downloading
32
- DOWNLOAD_PATH = "#{ENV['HOME']}/Downloads".freeze
34
+ DOWNLOAD_PATH = "#{ENV['HOME']}/Downloads"
33
35
  # Regex to get the name of a localization asset
34
- UNITY_LANGUAGE_FILE_REGEX = %r{\/\d+/[0-9\.]+\/([\w-]+)$}
36
+ UNITY_LANGUAGE_FILE_REGEX = %r{/\d+/[0-9.]+/([\w-]+)$}.freeze
35
37
  # Regex to get the name of a package out of its file name
36
- UNITY_MODULE_FILE_REGEX = %r{\/([\w\-_\.\+]+\.(?:pkg|dmg|exe|zip|sh|deb|msi|xz))[^\/]*$}
38
+ UNITY_MODULE_FILE_REGEX = %r{/([\w\-_.+]+\.(?:pkg|dmg|exe|zip|sh|deb|msi|xz))[^/]*$}.freeze
37
39
 
38
40
  class << self
39
41
  def download_directory
@@ -112,15 +114,15 @@ module U3d
112
114
  return
113
115
  else
114
116
  extension = File.extname(path)
115
- new_path = File.join(File.dirname(path), File.basename(path, extension) + '_CORRUPTED' + extension)
117
+ new_path = File.join(File.dirname(path), "#{File.basename(path, extension)}_CORRUPTED#{extension}")
116
118
  UI.important "File present at #{path} is not correct, it has been renamed to #{new_path}"
117
119
  File.rename(path, new_path)
118
120
  end
119
121
  end
120
122
 
121
123
  UI.header "Downloading #{package_info.name} version #{definition.version}"
122
- UI.message 'Downloading from ' + url.to_s.cyan.underline
123
- UI.message 'Download will be found at ' + path
124
+ UI.message "Downloading from #{url.to_s.cyan.underline}"
125
+ UI.message "Download will be found at #{path}"
124
126
  download_package(path, url, size: package_info.download_size)
125
127
 
126
128
  if validator.validate(package, path, definition)
@@ -153,7 +155,7 @@ module U3d
153
155
  Utils.ensure_dir(dir)
154
156
 
155
157
  file_name = if (language_match = UNITY_LANGUAGE_FILE_REGEX.match(final_url))
156
- language_match[1] + '.po' # Unity uses PO (Portable object files) for localization
158
+ "#{language_match[1]}.po" # Unity uses PO (Portable object files) for localization
157
159
  elsif (module_match = UNITY_MODULE_FILE_REGEX.match(final_url))
158
160
  module_match[1]
159
161
  else
@@ -182,8 +184,10 @@ module U3d
182
184
  # for backward compatibility
183
185
  class MacDownloader < StandardPackageDownloader
184
186
  end
187
+
185
188
  class LinuxDownloader < StandardPackageDownloader
186
189
  end
190
+
187
191
  class WindowsDownloader < StandardPackageDownloader
188
192
  end
189
193
  end
@@ -1,3 +1,5 @@
1
+ # frozen_string_literal: true
2
+
1
3
  require 'date'
2
4
  require 'fileutils'
3
5
  require 'json'
@@ -9,6 +11,7 @@ module U3d
9
11
  class << self
10
12
  def report(failure_type: "DEFAULT", failure_message: "", data: {})
11
13
  return unless ENV['U3D_REPORT_FAILURES']
14
+
12
15
  report = {
13
16
  type: failure_type,
14
17
  message: failure_message,
@@ -21,9 +24,7 @@ module U3d
21
24
  "#{failure_type}.#{Date.now.strftime('%Y%m%dT%H%M')}.failure.json"
22
25
  )
23
26
 
24
- File.open(report_file, 'w') do |file|
25
- file.write JSON.pretty_generate(report)
26
- end
27
+ File.write(report_file, JSON.pretty_generate(report))
27
28
  rescue StandardError => e
28
29
  UI.important "Unable to report a #{failure_type} failure. Please use --verbose to get more information about the failure"
29
30
  UI.verbose "Unable to report failure: #{e}"
@@ -1,3 +1,5 @@
1
+ # frozen_string_literal: true
2
+
1
3
  ## --- BEGIN LICENSE BLOCK ---
2
4
  # Copyright (c) 2016-present WeWantToKnow AS
3
5
  #
@@ -28,19 +30,34 @@ require 'u3d_core/helper'
28
30
  module U3d
29
31
  module HubModulesParser
30
32
  class << self
31
- HUB_MODULES_NAME = '%<version>s-%<os>s-modules.json'.freeze
33
+ HUB_MODULES_NAME = '%<version>s-%<os>s-modules.json'
32
34
 
33
35
  def load_modules(version, os: U3dCore::Helper.operating_system, offline: false)
34
36
  path = modules_path(version, os)
35
37
 
36
- unless File.file?(path) && File.size(path) > 0
37
- return [] if offline # Should not raise, not all versions have hub modules
38
- versions = download_modules(os: os)
38
+ # force download if no hub file present
39
+ download_modules(os: os) if !File.file?(path) && File.size(path).positive? && !offline
40
+
41
+ unless File.file?(path) && File.size(path).positive?
42
+ UI.verbose "No modules registered for UnityHub for version #{version}"
43
+ # cached_versions.keys.map{|s| UnityVersionNumber.new(s)}
44
+ # searching for closest version
45
+ files = Dir.glob("#{default_modules_path}/*-#{os}-modules.json")
46
+
47
+ vn = UnityVersionNumber.new(version)
48
+
49
+ versions_and_paths = files.map do |p|
50
+ v = File.basename(p).split('-')[0]
51
+ [UnityVersionNumber.new(v), p]
52
+ end
53
+ # filtered by version major.minor.patch (same major & minor and patch higher or equal)
54
+ versions_and_paths = versions_and_paths.select { |a| a[0].parts[0] == vn.parts[0] && a[0].parts[1] == vn.parts[1] && a[0].parts[2] >= vn.parts[2] }
39
55
 
40
- unless versions.include? version
41
- UI.verbose "No modules registered for UnityHub for version #{version}"
56
+ if versions_and_paths.empty?
57
+ UI.info "No closest version from UnityHub found for version #{version}"
42
58
  return []
43
59
  end
60
+ path = versions_and_paths.first[1]
44
61
  end
45
62
 
46
63
  return JSON.parse(File.read(path))
@@ -81,7 +98,7 @@ module U3d
81
98
  path = modules_path(build['version'], os)
82
99
  Utils.ensure_dir(File.dirname(path))
83
100
 
84
- File.open(path, 'w') { |file| file.write build['modules'].to_json }
101
+ File.write(path, build['modules'].to_json)
85
102
  end
86
103
  end
87
104
  end
@@ -1,3 +1,5 @@
1
+ # frozen_string_literal: true
2
+
1
3
  ## --- BEGIN LICENSE BLOCK ---
2
4
  # Copyright (c) 2016-present WeWantToKnow AS
3
5
  #
@@ -30,7 +32,7 @@ module U3d
30
32
  #####################################################
31
33
  # @!group INI parameters to load and save ini files
32
34
  #####################################################
33
- INI_NAME = 'unity-%<version>s-%<os>s.ini'.freeze
35
+ INI_NAME = 'unity-%<version>s-%<os>s.ini'
34
36
 
35
37
  class << self
36
38
  def load_ini(version, cached_versions, os: U3dCore::Helper.operating_system, offline: false)
@@ -42,8 +44,9 @@ module U3d
42
44
  ini_name = format(INI_NAME, version: version, os: os)
43
45
  Utils.ensure_dir(default_ini_path)
44
46
  ini_path = File.expand_path(ini_name, default_ini_path)
45
- unless File.file?(ini_path) && File.size(ini_path) > 0
47
+ unless File.file?(ini_path) && File.size(ini_path).positive?
46
48
  raise "INI file does not exist at #{ini_path}" if offline
49
+
47
50
  download_ini(version, cached_versions, os, ini_name, ini_path)
48
51
  end
49
52
  begin
@@ -58,7 +61,8 @@ module U3d
58
61
  ini_name = format(INI_NAME, version: version, os: 'linux')
59
62
  Utils.ensure_dir(default_ini_path)
60
63
  ini_path = File.expand_path(ini_name, default_ini_path)
61
- return if File.file?(ini_path) && File.size(ini_path) > 0
64
+ return if File.file?(ini_path) && File.size(ini_path).positive?
65
+
62
66
  data = %([Unity]
63
67
  ; -- NOTE --
64
68
  ; This is not an official Unity file
@@ -90,16 +94,14 @@ url=#{url}
90
94
  UI.verbose("Searching for ini file at #{uri}")
91
95
 
92
96
  data = Net::HTTP.get(uri)
93
- data.tr!("\"", '')
94
- data.gsub!(/Note:.+\n/, '')
97
+ data = data.tr("\"", '')
98
+ data = data.gsub(/Note:.+\n/, '')
95
99
 
96
100
  write_ini_file(ini_path, data)
97
101
  end
98
102
 
99
103
  def write_ini_file(ini_path, data)
100
- File.open(ini_path, 'wb') do |f|
101
- f.write(data)
102
- end
104
+ File.binwrite(ini_path, data)
103
105
  end
104
106
 
105
107
  def default_ini_path
@@ -1,3 +1,5 @@
1
+ # frozen_string_literal: true
2
+
1
3
  ## --- BEGIN LICENSE BLOCK ---
2
4
  # Copyright (c) 2016-present WeWantToKnow AS
3
5
  #
@@ -25,9 +27,12 @@ require 'u3d_core/admin_tools'
25
27
  require 'fileutils'
26
28
 
27
29
  module U3d
28
- UNITY_DIR_CHECK = /Unity_\d+\.\d+\.\d+[a-z]\d+/
29
- UNITY_DIR_CHECK_LINUX = /unity-editor-\d+\.\d+\.\d+[a-z]\d+\z/
30
- U3D_DO_NOT_MOVE = ".u3d_do_not_move".freeze
30
+ UNITY_DIR_CHECK = /Unity_\d+\.\d+\.\d+[a-z]\d+/.freeze
31
+ UNITY_DIR_CHECK_LINUX = /unity-editor-\d+\.\d+\.\d+[a-z]\d+\z/.freeze
32
+ # Linux unity_builtin_extra seek position for version
33
+ UNITY_VERSION_LINUX_POS_LE_2019 = 20
34
+ UNITY_VERSION_LINUX_POS_GT_2019 = 48
35
+ U3D_DO_NOT_MOVE = ".u3d_do_not_move"
31
36
 
32
37
  class Installation
33
38
  attr_accessor :root_path
@@ -114,6 +119,7 @@ module U3d
114
119
  require 'rexml/document'
115
120
  UI.verbose("reading #{config_path}")
116
121
  raise "File not found at #{config_path}" unless File.exist? config_path
122
+
117
123
  doc = REXML::Document.new(File.read(config_path))
118
124
  REXML::XPath.first(doc, node_name).value
119
125
  end
@@ -142,10 +148,19 @@ module U3d
142
148
  class InstallationUtils
143
149
  def self.read_version_from_unity_builtin_extra(file)
144
150
  File.open(file, "rb") do |f|
145
- f.seek(20)
151
+ # Check if it is version lower or equal to 2019
152
+ seek_pos = UNITY_VERSION_LINUX_POS_LE_2019
153
+ f.seek(seek_pos)
154
+ z = f.read(1)
155
+ if z == "\x00"
156
+ # Version is greater than 2019
157
+ seek_pos = UNITY_VERSION_LINUX_POS_GT_2019
158
+ end
159
+ f.seek(seek_pos)
146
160
  s = ""
147
161
  while (c = f.read(1))
148
162
  break if c == "\x00"
163
+
149
164
  s += c
150
165
  end
151
166
  s
@@ -175,6 +190,7 @@ module U3d
175
190
  def path
176
191
  UI.deprecated("path is deprecated. Use root_path instead")
177
192
  return @path if @path
193
+
178
194
  "#{@root_path}/Unity.app"
179
195
  end
180
196
 
@@ -217,13 +233,14 @@ module U3d
217
233
  begin
218
234
  fpath = "#{root_path}/Unity.app/Contents/Info.plist"
219
235
  raise "#{fpath} doesn't exist" unless File.exist? fpath
236
+
220
237
  Plist.parse_xml(fpath)
221
238
  end
222
239
  end
223
240
  end
224
241
 
225
242
  class LinuxInstallationHelper
226
- STRINGS_FULL_VERSION_MATCHER = /^[0-9\.abfp]+_[0-9a-f]{12}/
243
+ STRINGS_FULL_VERSION_MATCHER = /^[0-9.abfp]+_[0-9a-f]{12}/.freeze
227
244
 
228
245
  def find_build_number(root)
229
246
  known_rev_locations.each do |p|
@@ -236,10 +253,10 @@ module U3d
236
253
  private
237
254
 
238
255
  def strings(path)
239
- if `which strings` != ''
240
- binutils_strings(path)
241
- else
256
+ if `which strings` == ''
242
257
  Utils.strings(path).to_a
258
+ else
259
+ binutils_strings(path)
243
260
  end
244
261
  end
245
262
 
@@ -258,8 +275,9 @@ module U3d
258
275
 
259
276
  def find_build_number_in(path = nil)
260
277
  return nil unless File.exist? path
278
+
261
279
  str = strings(path)
262
- lines = str.select { |l| l =~ STRINGS_FULL_VERSION_MATCHER }
280
+ lines = str.grep(STRINGS_FULL_VERSION_MATCHER)
263
281
  lines.empty? ? nil : lines[0].split('_')[1]
264
282
  end
265
283
  end
@@ -347,44 +365,7 @@ module U3d
347
365
  private
348
366
 
349
367
  def unity_version_info
350
- @uvf ||= string_file_info('Unity Version', @exe_path)
351
- end
352
-
353
- def string_file_info(info, path)
354
- require "Win32API"
355
- get_file_version_info_size = Win32API.new('version.dll', 'GetFileVersionInfoSize', 'PP', 'L')
356
- get_file_version_info = Win32API.new('version.dll', 'GetFileVersionInfo', 'PIIP', 'I')
357
- ver_query_value = Win32API.new('version.dll', 'VerQueryValue', 'PPPP', 'I')
358
- rtl_move_memory = Win32API.new('kernel32.dll', 'RtlMoveMemory', 'PLL', 'I')
359
-
360
- file = path.tr("/", "\\")
361
-
362
- buf = [0].pack('L')
363
- version_size = get_file_version_info_size.call(file + "\0", buf)
364
- raise Exception if version_size.zero? # TODO: use GetLastError
365
-
366
- version_info = 0.chr * version_size
367
- version_ok = get_file_version_info.call(file, 0, version_size, version_info)
368
- raise Exception if version_ok.zero? # TODO: use GetLastError
369
-
370
- # hardcoding lang codepage
371
- struct_path = "\\StringFileInfo\\040904b0\\#{info}"
372
-
373
- addr = [0].pack('L')
374
- size = [0].pack('L')
375
- query_ok = ver_query_value.call(version_info, struct_path + "\0", addr, size)
376
- raise Exception if query_ok.zero?
377
-
378
- raddr = addr.unpack('L')[0]
379
- rsize = size.unpack('L')[0]
380
-
381
- info = Array.new(rsize, 0).pack('L*')
382
- rtl_move_memory.call(info, raddr, info.length)
383
- info.strip
384
- rescue StandardError => e
385
- UI.verbose("Failure to find '#{info}' under '#{path}': #{e}")
386
- UI.verbose(e.backtrace)
387
- nil
368
+ @unity_version_info ||= U3d::Utils.windows_fileversion('Unity Version', @exe_path)
388
369
  end
389
370
  end
390
371
 
@@ -396,6 +377,7 @@ module U3d
396
377
  path = "#{root_path}/Editor/Data/"
397
378
  package = IvyPlaybackEngineUtils.list_module_configs(path).first
398
379
  raise "Couldn't find a module under #{path}" unless package
380
+
399
381
  IvyPlaybackEngineUtils.unity_version(package)
400
382
  end
401
383
 
@@ -410,8 +392,8 @@ module U3d
410
392
  log_dir = File.expand_path('Unity/Editor/', loc_appdata)
411
393
  UI.important "Log directory (#{log_dir}) does not exist" unless Dir.exist? log_dir
412
394
  @logfile = File.expand_path('Editor.log', log_dir)
413
- rescue RuntimeError => ex
414
- UI.error "Unable to retrieve the editor logfile: #{ex}"
395
+ rescue RuntimeError => e
396
+ UI.error "Unable to retrieve the editor logfile: #{e}"
415
397
  end
416
398
  end
417
399
  @logfile