u3d 1.2.3 → 1.3.0

Sign up to get free protection for your applications and to get access to all the features.
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