ocran 1.3.18 → 1.4.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.
- checksums.yaml +4 -4
- data/CHANGELOG.txt +306 -292
- data/LICENSE.txt +22 -22
- data/README.md +549 -533
- data/exe/ocran +5 -5
- data/ext/extconf.rb +15 -0
- data/lib/ocran/build_constants.rb +16 -16
- data/lib/ocran/build_facade.rb +17 -17
- data/lib/ocran/build_helper.rb +110 -105
- data/lib/ocran/command_output.rb +22 -22
- data/lib/ocran/dir_builder.rb +162 -0
- data/lib/ocran/direction.rb +623 -458
- data/lib/ocran/file_path_set.rb +69 -69
- data/lib/ocran/gem_spec_queryable.rb +172 -172
- data/lib/ocran/host_config_helper.rb +57 -44
- data/lib/ocran/inno_setup_script_builder.rb +111 -111
- data/lib/ocran/launcher_batch_builder.rb +85 -85
- data/lib/ocran/library_detector.rb +61 -61
- data/lib/ocran/library_detector_posix.rb +55 -0
- data/lib/ocran/option.rb +323 -273
- data/lib/ocran/refine_pathname.rb +104 -104
- data/lib/ocran/runner.rb +115 -105
- data/lib/ocran/runtime_environment.rb +46 -46
- data/lib/ocran/stub_builder.rb +298 -264
- data/lib/ocran/version.rb +5 -5
- data/lib/ocran/windows_command_escaping.rb +15 -15
- data/lib/ocran.rb +7 -7
- data/share/ocran/lzma.exe +0 -0
- data/src/Makefile +75 -0
- data/src/edicon.c +161 -0
- data/src/error.c +100 -0
- data/src/error.h +66 -0
- data/src/inst_dir.c +334 -0
- data/src/inst_dir.h +157 -0
- data/src/lzma/7zTypes.h +529 -0
- data/src/lzma/Compiler.h +43 -0
- data/src/lzma/LzmaDec.c +1363 -0
- data/src/lzma/LzmaDec.h +236 -0
- data/src/lzma/Precomp.h +10 -0
- data/src/script_info.c +246 -0
- data/src/script_info.h +7 -0
- data/src/stub.c +133 -0
- data/src/stub.manifest +29 -0
- data/src/stub.rc +3 -0
- data/src/system_utils.c +1002 -0
- data/src/system_utils.h +209 -0
- data/src/system_utils_posix.c +500 -0
- data/src/unpack.c +574 -0
- data/src/unpack.h +85 -0
- data/src/vit-ruby.ico +0 -0
- metadata +52 -16
- data/share/ocran/edicon.exe +0 -0
- data/share/ocran/stub.exe +0 -0
- data/share/ocran/stubw.exe +0 -0
|
@@ -1,104 +1,104 @@
|
|
|
1
|
-
# frozen_string_literal: true
|
|
2
|
-
require "pathname"
|
|
3
|
-
|
|
4
|
-
module Ocran
|
|
5
|
-
# The Pathname class in Ruby is modified to handle mixed path separators and
|
|
6
|
-
# to be case-insensitive.
|
|
7
|
-
module RefinePathname
|
|
8
|
-
refine Pathname do
|
|
9
|
-
def normalize_file_separator(s)
|
|
10
|
-
if File::ALT_SEPARATOR
|
|
11
|
-
s.tr(File::ALT_SEPARATOR, File::SEPARATOR)
|
|
12
|
-
else
|
|
13
|
-
s
|
|
14
|
-
end
|
|
15
|
-
end
|
|
16
|
-
private :normalize_file_separator
|
|
17
|
-
|
|
18
|
-
# Compares two paths for equality based on the case sensitivity of the
|
|
19
|
-
# Ruby execution environment's file system.
|
|
20
|
-
# If the file system is case-insensitive, it performs a case-insensitive
|
|
21
|
-
# comparison. Otherwise, it performs a case-sensitive comparison.
|
|
22
|
-
def pathequal(a, b)
|
|
23
|
-
if File::FNM_SYSCASE.nonzero?
|
|
24
|
-
a.casecmp(b) == 0
|
|
25
|
-
else
|
|
26
|
-
a == b
|
|
27
|
-
end
|
|
28
|
-
end
|
|
29
|
-
private :pathequal
|
|
30
|
-
|
|
31
|
-
def to_posix
|
|
32
|
-
normalize_file_separator(to_s)
|
|
33
|
-
end
|
|
34
|
-
|
|
35
|
-
# Checks if two Pathname objects are equal, considering the file system's
|
|
36
|
-
# case sensitivity and path separators. Returns false if the other object is not
|
|
37
|
-
# an Pathname.
|
|
38
|
-
# This method enables the use of the `uniq` method on arrays of Pathname objects.
|
|
39
|
-
def eql?(other)
|
|
40
|
-
return false unless other.is_a?(Pathname)
|
|
41
|
-
|
|
42
|
-
a = normalize_file_separator(to_s)
|
|
43
|
-
b = normalize_file_separator(other.to_s)
|
|
44
|
-
pathequal(a, b)
|
|
45
|
-
end
|
|
46
|
-
|
|
47
|
-
alias == eql?
|
|
48
|
-
alias === eql?
|
|
49
|
-
|
|
50
|
-
# Calculates a normalized hash value for a pathname to ensure consistent
|
|
51
|
-
# hashing across different environments, particularly in Windows.
|
|
52
|
-
# This method first normalizes the path by:
|
|
53
|
-
# 1. Converting the file separator from the platform-specific separator
|
|
54
|
-
# to the common POSIX separator ('/') if necessary.
|
|
55
|
-
# 2. Converting the path to lowercase if the filesystem is case-insensitive.
|
|
56
|
-
# The normalized path string is then hashed, providing a stable hash value
|
|
57
|
-
# that is consistent with the behavior of eql? method, thus maintaining
|
|
58
|
-
# the integrity of hash-based data structures like Hash or Set.
|
|
59
|
-
#
|
|
60
|
-
# @return [Integer] A hash integer based on the normalized path.
|
|
61
|
-
def hash
|
|
62
|
-
path = if File::FNM_SYSCASE.nonzero?
|
|
63
|
-
to_s.downcase
|
|
64
|
-
else
|
|
65
|
-
to_s
|
|
66
|
-
end
|
|
67
|
-
normalize_file_separator(path).hash
|
|
68
|
-
end
|
|
69
|
-
|
|
70
|
-
# Checks if the current path is a sub path of the specified base_directory.
|
|
71
|
-
# Both paths must be either absolute paths or relative paths; otherwise, this
|
|
72
|
-
# method returns false.
|
|
73
|
-
def subpath?(base_directory)
|
|
74
|
-
s = relative_path_from(base_directory).each_filename.first
|
|
75
|
-
s != '.' && s != ".."
|
|
76
|
-
rescue ArgumentError
|
|
77
|
-
false
|
|
78
|
-
end
|
|
79
|
-
|
|
80
|
-
# Appends the given suffix to the filename, preserving the file extension.
|
|
81
|
-
# If the filename has an extension, the suffix is inserted before the extension.
|
|
82
|
-
# If the filename does not have an extension, the suffix is appended to the end.
|
|
83
|
-
# This method handles both directory and file paths correctly.
|
|
84
|
-
#
|
|
85
|
-
# Examples:
|
|
86
|
-
# pathname = Pathname("path.to/foo.tar.gz")
|
|
87
|
-
# pathname.append_to_filename("_bar") # => #<Pathname:path.to/foo_bar.tar.gz>
|
|
88
|
-
#
|
|
89
|
-
# pathname = Pathname("path.to/foo")
|
|
90
|
-
# pathname.append_to_filename("_bar") # => #<Pathname:path.to/foo_bar>
|
|
91
|
-
#
|
|
92
|
-
def append_to_filename(suffix)
|
|
93
|
-
dirname + basename.sub(/(\.?[^.]+)?(\..*)?\z/, "\\1#{suffix}\\2")
|
|
94
|
-
end
|
|
95
|
-
|
|
96
|
-
# Checks if the file's extension matches the expected extension.
|
|
97
|
-
# The comparison is case-insensitive.
|
|
98
|
-
# Example usage: ocran_pathname.extname?(".exe")
|
|
99
|
-
def extname?(expected_ext)
|
|
100
|
-
extname.casecmp(expected_ext) == 0
|
|
101
|
-
end
|
|
102
|
-
end
|
|
103
|
-
end
|
|
104
|
-
end
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
require "pathname"
|
|
3
|
+
|
|
4
|
+
module Ocran
|
|
5
|
+
# The Pathname class in Ruby is modified to handle mixed path separators and
|
|
6
|
+
# to be case-insensitive.
|
|
7
|
+
module RefinePathname
|
|
8
|
+
refine Pathname do
|
|
9
|
+
def normalize_file_separator(s)
|
|
10
|
+
if File::ALT_SEPARATOR
|
|
11
|
+
s.tr(File::ALT_SEPARATOR, File::SEPARATOR)
|
|
12
|
+
else
|
|
13
|
+
s
|
|
14
|
+
end
|
|
15
|
+
end
|
|
16
|
+
private :normalize_file_separator
|
|
17
|
+
|
|
18
|
+
# Compares two paths for equality based on the case sensitivity of the
|
|
19
|
+
# Ruby execution environment's file system.
|
|
20
|
+
# If the file system is case-insensitive, it performs a case-insensitive
|
|
21
|
+
# comparison. Otherwise, it performs a case-sensitive comparison.
|
|
22
|
+
def pathequal(a, b)
|
|
23
|
+
if File::FNM_SYSCASE.nonzero?
|
|
24
|
+
a.casecmp(b) == 0
|
|
25
|
+
else
|
|
26
|
+
a == b
|
|
27
|
+
end
|
|
28
|
+
end
|
|
29
|
+
private :pathequal
|
|
30
|
+
|
|
31
|
+
def to_posix
|
|
32
|
+
normalize_file_separator(to_s)
|
|
33
|
+
end
|
|
34
|
+
|
|
35
|
+
# Checks if two Pathname objects are equal, considering the file system's
|
|
36
|
+
# case sensitivity and path separators. Returns false if the other object is not
|
|
37
|
+
# an Pathname.
|
|
38
|
+
# This method enables the use of the `uniq` method on arrays of Pathname objects.
|
|
39
|
+
def eql?(other)
|
|
40
|
+
return false unless other.is_a?(Pathname)
|
|
41
|
+
|
|
42
|
+
a = normalize_file_separator(to_s)
|
|
43
|
+
b = normalize_file_separator(other.to_s)
|
|
44
|
+
pathequal(a, b)
|
|
45
|
+
end
|
|
46
|
+
|
|
47
|
+
alias == eql?
|
|
48
|
+
alias === eql?
|
|
49
|
+
|
|
50
|
+
# Calculates a normalized hash value for a pathname to ensure consistent
|
|
51
|
+
# hashing across different environments, particularly in Windows.
|
|
52
|
+
# This method first normalizes the path by:
|
|
53
|
+
# 1. Converting the file separator from the platform-specific separator
|
|
54
|
+
# to the common POSIX separator ('/') if necessary.
|
|
55
|
+
# 2. Converting the path to lowercase if the filesystem is case-insensitive.
|
|
56
|
+
# The normalized path string is then hashed, providing a stable hash value
|
|
57
|
+
# that is consistent with the behavior of eql? method, thus maintaining
|
|
58
|
+
# the integrity of hash-based data structures like Hash or Set.
|
|
59
|
+
#
|
|
60
|
+
# @return [Integer] A hash integer based on the normalized path.
|
|
61
|
+
def hash
|
|
62
|
+
path = if File::FNM_SYSCASE.nonzero?
|
|
63
|
+
to_s.downcase
|
|
64
|
+
else
|
|
65
|
+
to_s
|
|
66
|
+
end
|
|
67
|
+
normalize_file_separator(path).hash
|
|
68
|
+
end
|
|
69
|
+
|
|
70
|
+
# Checks if the current path is a sub path of the specified base_directory.
|
|
71
|
+
# Both paths must be either absolute paths or relative paths; otherwise, this
|
|
72
|
+
# method returns false.
|
|
73
|
+
def subpath?(base_directory)
|
|
74
|
+
s = relative_path_from(base_directory).each_filename.first
|
|
75
|
+
s != '.' && s != ".."
|
|
76
|
+
rescue ArgumentError
|
|
77
|
+
false
|
|
78
|
+
end
|
|
79
|
+
|
|
80
|
+
# Appends the given suffix to the filename, preserving the file extension.
|
|
81
|
+
# If the filename has an extension, the suffix is inserted before the extension.
|
|
82
|
+
# If the filename does not have an extension, the suffix is appended to the end.
|
|
83
|
+
# This method handles both directory and file paths correctly.
|
|
84
|
+
#
|
|
85
|
+
# Examples:
|
|
86
|
+
# pathname = Pathname("path.to/foo.tar.gz")
|
|
87
|
+
# pathname.append_to_filename("_bar") # => #<Pathname:path.to/foo_bar.tar.gz>
|
|
88
|
+
#
|
|
89
|
+
# pathname = Pathname("path.to/foo")
|
|
90
|
+
# pathname.append_to_filename("_bar") # => #<Pathname:path.to/foo_bar>
|
|
91
|
+
#
|
|
92
|
+
def append_to_filename(suffix)
|
|
93
|
+
dirname + basename.sub(/(\.?[^.]+)?(\..*)?\z/, "\\1#{suffix}\\2")
|
|
94
|
+
end
|
|
95
|
+
|
|
96
|
+
# Checks if the file's extension matches the expected extension.
|
|
97
|
+
# The comparison is case-insensitive.
|
|
98
|
+
# Example usage: ocran_pathname.extname?(".exe")
|
|
99
|
+
def extname?(expected_ext)
|
|
100
|
+
extname.casecmp(expected_ext) == 0
|
|
101
|
+
end
|
|
102
|
+
end
|
|
103
|
+
end
|
|
104
|
+
end
|
data/lib/ocran/runner.rb
CHANGED
|
@@ -1,105 +1,115 @@
|
|
|
1
|
-
# frozen_string_literal: true
|
|
2
|
-
load File.expand_path("../ocran.rb", __dir__)
|
|
3
|
-
|
|
4
|
-
module Ocran
|
|
5
|
-
class Runner
|
|
6
|
-
load File.expand_path("command_output.rb", __dir__)
|
|
7
|
-
include CommandOutput
|
|
8
|
-
|
|
9
|
-
def fatal_error(statement)
|
|
10
|
-
error statement
|
|
11
|
-
exit false
|
|
12
|
-
end
|
|
13
|
-
|
|
14
|
-
def initialize
|
|
15
|
-
load File.expand_path("runtime_environment.rb", __dir__)
|
|
16
|
-
@pre_env = RuntimeEnvironment.save
|
|
17
|
-
|
|
18
|
-
load File.expand_path("option.rb", __dir__)
|
|
19
|
-
@option = Option.new.tap do |opt|
|
|
20
|
-
opt.parse(ARGV)
|
|
21
|
-
rescue RuntimeError => e
|
|
22
|
-
# Capture RuntimeError during parsing and display an appropriate
|
|
23
|
-
# error message to the user. This error usually occurs from invalid
|
|
24
|
-
# option arguments.
|
|
25
|
-
fatal_error e.message
|
|
26
|
-
else
|
|
27
|
-
# Update ARGV with the parsed command line arguments to pass to
|
|
28
|
-
# the user's script. This ensures the script executes based on
|
|
29
|
-
# the user-specified arguments.
|
|
30
|
-
ARGV.replace(opt.argv)
|
|
31
|
-
end
|
|
32
|
-
|
|
33
|
-
Ocran.option = @option
|
|
34
|
-
|
|
35
|
-
@ignore_modules = ObjectSpace.each_object(Module).to_a
|
|
36
|
-
end
|
|
37
|
-
|
|
38
|
-
def run
|
|
39
|
-
at_exit do
|
|
40
|
-
if $!.nil? or $!.kind_of?(SystemExit)
|
|
41
|
-
build
|
|
42
|
-
exit
|
|
43
|
-
end
|
|
44
|
-
end
|
|
45
|
-
|
|
46
|
-
exit unless @option.run_script?
|
|
47
|
-
say "Loading script to check dependencies"
|
|
48
|
-
$PROGRAM_NAME = @option.script.to_s
|
|
49
|
-
end
|
|
50
|
-
|
|
51
|
-
# Force loading autoloaded constants. Searches through all modules
|
|
52
|
-
# (and hence classes), and checks their constants for autoloaded
|
|
53
|
-
# ones, then attempts to load them.
|
|
54
|
-
def attempt_load_autoload(ignore_modules = [])
|
|
55
|
-
checked_modules = ignore_modules.inject({}) { |h, mod| h[mod] = true; h }
|
|
56
|
-
while ObjectSpace.each_object(Module).count { |mod|
|
|
57
|
-
next if checked_modules.include?(mod)
|
|
58
|
-
mod.constants.each do |const|
|
|
59
|
-
next unless mod.autoload?(const)
|
|
60
|
-
say "Attempting to trigger autoload of #{mod}::#{const}"
|
|
61
|
-
begin
|
|
62
|
-
mod.const_get(const)
|
|
63
|
-
rescue ScriptError, StandardError => e
|
|
64
|
-
# Some autoload constants may throw exceptions beyond the expected
|
|
65
|
-
# errors. This includes issues dependent on the system or execution
|
|
66
|
-
# environment, so it is preferable to ignore exceptions other than
|
|
67
|
-
# critical errors.
|
|
68
|
-
warning "#{mod}::#{const} loading failed: #{e.message}"
|
|
69
|
-
end
|
|
70
|
-
end
|
|
71
|
-
checked_modules[mod] = true
|
|
72
|
-
}.nonzero?
|
|
73
|
-
# Loops until all constants have been checked.
|
|
74
|
-
end
|
|
75
|
-
end
|
|
76
|
-
|
|
77
|
-
def build
|
|
78
|
-
# If the script was run and autoload is enabled, attempt to autoload libraries.
|
|
79
|
-
if @option.force_autoload?
|
|
80
|
-
attempt_load_autoload(@ignore_modules)
|
|
81
|
-
end
|
|
82
|
-
|
|
83
|
-
@post_env = RuntimeEnvironment.save
|
|
84
|
-
# NOTE: From this point, $LOADED_FEATURES has been captured, so it is now
|
|
85
|
-
# safe to call require_relative.
|
|
86
|
-
|
|
87
|
-
ENV.replace(@pre_env.env)
|
|
88
|
-
|
|
89
|
-
# It might be useful to reset the current directory to the point where the
|
|
90
|
-
# command was launched, especially when implementing the builder object.
|
|
91
|
-
Dir.chdir(@pre_env.pwd)
|
|
92
|
-
|
|
93
|
-
require_relative "direction"
|
|
94
|
-
direction = Direction.new(@post_env, @pre_env, @option)
|
|
95
|
-
|
|
96
|
-
if @option.use_inno_setup?
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
load File.expand_path("../ocran.rb", __dir__)
|
|
3
|
+
|
|
4
|
+
module Ocran
|
|
5
|
+
class Runner
|
|
6
|
+
load File.expand_path("command_output.rb", __dir__)
|
|
7
|
+
include CommandOutput
|
|
8
|
+
|
|
9
|
+
def fatal_error(statement)
|
|
10
|
+
error statement
|
|
11
|
+
exit false
|
|
12
|
+
end
|
|
13
|
+
|
|
14
|
+
def initialize
|
|
15
|
+
load File.expand_path("runtime_environment.rb", __dir__)
|
|
16
|
+
@pre_env = RuntimeEnvironment.save
|
|
17
|
+
|
|
18
|
+
load File.expand_path("option.rb", __dir__)
|
|
19
|
+
@option = Option.new.tap do |opt|
|
|
20
|
+
opt.parse(ARGV)
|
|
21
|
+
rescue RuntimeError => e
|
|
22
|
+
# Capture RuntimeError during parsing and display an appropriate
|
|
23
|
+
# error message to the user. This error usually occurs from invalid
|
|
24
|
+
# option arguments.
|
|
25
|
+
fatal_error e.message
|
|
26
|
+
else
|
|
27
|
+
# Update ARGV with the parsed command line arguments to pass to
|
|
28
|
+
# the user's script. This ensures the script executes based on
|
|
29
|
+
# the user-specified arguments.
|
|
30
|
+
ARGV.replace(opt.argv)
|
|
31
|
+
end
|
|
32
|
+
|
|
33
|
+
Ocran.option = @option
|
|
34
|
+
|
|
35
|
+
@ignore_modules = ObjectSpace.each_object(Module).to_a
|
|
36
|
+
end
|
|
37
|
+
|
|
38
|
+
def run
|
|
39
|
+
at_exit do
|
|
40
|
+
if $!.nil? or $!.kind_of?(SystemExit)
|
|
41
|
+
build
|
|
42
|
+
exit
|
|
43
|
+
end
|
|
44
|
+
end
|
|
45
|
+
|
|
46
|
+
exit unless @option.run_script?
|
|
47
|
+
say "Loading script to check dependencies"
|
|
48
|
+
$PROGRAM_NAME = @option.script.to_s
|
|
49
|
+
end
|
|
50
|
+
|
|
51
|
+
# Force loading autoloaded constants. Searches through all modules
|
|
52
|
+
# (and hence classes), and checks their constants for autoloaded
|
|
53
|
+
# ones, then attempts to load them.
|
|
54
|
+
def attempt_load_autoload(ignore_modules = [])
|
|
55
|
+
checked_modules = ignore_modules.inject({}) { |h, mod| h[mod] = true; h }
|
|
56
|
+
while ObjectSpace.each_object(Module).count { |mod|
|
|
57
|
+
next if checked_modules.include?(mod)
|
|
58
|
+
mod.constants.each do |const|
|
|
59
|
+
next unless mod.autoload?(const)
|
|
60
|
+
say "Attempting to trigger autoload of #{mod}::#{const}"
|
|
61
|
+
begin
|
|
62
|
+
mod.const_get(const)
|
|
63
|
+
rescue ScriptError, StandardError => e
|
|
64
|
+
# Some autoload constants may throw exceptions beyond the expected
|
|
65
|
+
# errors. This includes issues dependent on the system or execution
|
|
66
|
+
# environment, so it is preferable to ignore exceptions other than
|
|
67
|
+
# critical errors.
|
|
68
|
+
warning "#{mod}::#{const} loading failed: #{e.message}"
|
|
69
|
+
end
|
|
70
|
+
end
|
|
71
|
+
checked_modules[mod] = true
|
|
72
|
+
}.nonzero?
|
|
73
|
+
# Loops until all constants have been checked.
|
|
74
|
+
end
|
|
75
|
+
end
|
|
76
|
+
|
|
77
|
+
def build
|
|
78
|
+
# If the script was run and autoload is enabled, attempt to autoload libraries.
|
|
79
|
+
if @option.force_autoload?
|
|
80
|
+
attempt_load_autoload(@ignore_modules)
|
|
81
|
+
end
|
|
82
|
+
|
|
83
|
+
@post_env = RuntimeEnvironment.save
|
|
84
|
+
# NOTE: From this point, $LOADED_FEATURES has been captured, so it is now
|
|
85
|
+
# safe to call require_relative.
|
|
86
|
+
|
|
87
|
+
ENV.replace(@pre_env.env)
|
|
88
|
+
|
|
89
|
+
# It might be useful to reset the current directory to the point where the
|
|
90
|
+
# command was launched, especially when implementing the builder object.
|
|
91
|
+
Dir.chdir(@pre_env.pwd)
|
|
92
|
+
|
|
93
|
+
require_relative "direction"
|
|
94
|
+
direction = Direction.new(@post_env, @pre_env, @option)
|
|
95
|
+
|
|
96
|
+
if @option.use_inno_setup?
|
|
97
|
+
if Gem.win_platform?
|
|
98
|
+
direction.build_inno_setup_installer
|
|
99
|
+
else
|
|
100
|
+
raise "Inno Setup is only supported on Windows"
|
|
101
|
+
end
|
|
102
|
+
elsif @option.macosx_bundle
|
|
103
|
+
direction.build_macosx_bundle(@option.macosx_bundle)
|
|
104
|
+
elsif @option.output_dir
|
|
105
|
+
direction.build_output_dir(@option.output_dir)
|
|
106
|
+
elsif @option.output_zip
|
|
107
|
+
direction.build_zip(@option.output_zip)
|
|
108
|
+
else
|
|
109
|
+
direction.build_stab_exe
|
|
110
|
+
end
|
|
111
|
+
rescue RuntimeError => e
|
|
112
|
+
fatal_error e.message
|
|
113
|
+
end
|
|
114
|
+
end
|
|
115
|
+
end
|
|
@@ -1,46 +1,46 @@
|
|
|
1
|
-
# frozen_string_literal: true
|
|
2
|
-
require "pathname"
|
|
3
|
-
|
|
4
|
-
module Ocran
|
|
5
|
-
load File.expand_path("refine_pathname.rb", __dir__) unless defined? RefinePathname
|
|
6
|
-
using RefinePathname
|
|
7
|
-
|
|
8
|
-
class RuntimeEnvironment
|
|
9
|
-
class << self
|
|
10
|
-
alias save new
|
|
11
|
-
end
|
|
12
|
-
|
|
13
|
-
attr_reader :env, :load_path, :loaded_features, :pwd
|
|
14
|
-
|
|
15
|
-
def initialize
|
|
16
|
-
@env = ENV.to_hash.freeze
|
|
17
|
-
@load_path = $LOAD_PATH.dup.freeze
|
|
18
|
-
@loaded_features = $LOADED_FEATURES.dup.freeze
|
|
19
|
-
@pwd = Dir.pwd.freeze
|
|
20
|
-
end
|
|
21
|
-
|
|
22
|
-
# Expands the given path using the working directory stored in this
|
|
23
|
-
# instance as the base. This method resolves relative paths to
|
|
24
|
-
# absolute paths, ensuring they are fully qualified based on the
|
|
25
|
-
# working directory stored within this instance.
|
|
26
|
-
def expand_path(path)
|
|
27
|
-
File.expand_path(path, @pwd)
|
|
28
|
-
end
|
|
29
|
-
|
|
30
|
-
def find_load_path(path)
|
|
31
|
-
path = Pathname.new(path) unless path.is_a?(Pathname)
|
|
32
|
-
|
|
33
|
-
if path.absolute?
|
|
34
|
-
# For an absolute path feature, find the load path that contains the feature
|
|
35
|
-
# and determine the longest matching path (most specific path).
|
|
36
|
-
@load_path.select { |load_path| path.subpath?(expand_path(load_path)) }
|
|
37
|
-
.max_by { |load_path| expand_path(load_path).length }
|
|
38
|
-
else
|
|
39
|
-
# For a relative path feature, find the load path where the expanded feature exists
|
|
40
|
-
# and select the longest load path (most specific path).
|
|
41
|
-
@load_path.select { |load_path| path.expand_path(load_path).exist? }
|
|
42
|
-
.max_by { |load_path| load_path.length }
|
|
43
|
-
end
|
|
44
|
-
end
|
|
45
|
-
end
|
|
46
|
-
end
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
require "pathname"
|
|
3
|
+
|
|
4
|
+
module Ocran
|
|
5
|
+
load File.expand_path("refine_pathname.rb", __dir__) unless defined? RefinePathname
|
|
6
|
+
using RefinePathname
|
|
7
|
+
|
|
8
|
+
class RuntimeEnvironment
|
|
9
|
+
class << self
|
|
10
|
+
alias save new
|
|
11
|
+
end
|
|
12
|
+
|
|
13
|
+
attr_reader :env, :load_path, :loaded_features, :pwd
|
|
14
|
+
|
|
15
|
+
def initialize
|
|
16
|
+
@env = ENV.to_hash.freeze
|
|
17
|
+
@load_path = $LOAD_PATH.dup.freeze
|
|
18
|
+
@loaded_features = $LOADED_FEATURES.dup.freeze
|
|
19
|
+
@pwd = Dir.pwd.freeze
|
|
20
|
+
end
|
|
21
|
+
|
|
22
|
+
# Expands the given path using the working directory stored in this
|
|
23
|
+
# instance as the base. This method resolves relative paths to
|
|
24
|
+
# absolute paths, ensuring they are fully qualified based on the
|
|
25
|
+
# working directory stored within this instance.
|
|
26
|
+
def expand_path(path)
|
|
27
|
+
File.expand_path(path, @pwd)
|
|
28
|
+
end
|
|
29
|
+
|
|
30
|
+
def find_load_path(path)
|
|
31
|
+
path = Pathname.new(path) unless path.is_a?(Pathname)
|
|
32
|
+
|
|
33
|
+
if path.absolute?
|
|
34
|
+
# For an absolute path feature, find the load path that contains the feature
|
|
35
|
+
# and determine the longest matching path (most specific path).
|
|
36
|
+
@load_path.select { |load_path| path.subpath?(expand_path(load_path)) }
|
|
37
|
+
.max_by { |load_path| expand_path(load_path).length }
|
|
38
|
+
else
|
|
39
|
+
# For a relative path feature, find the load path where the expanded feature exists
|
|
40
|
+
# and select the longest load path (most specific path).
|
|
41
|
+
@load_path.select { |load_path| path.expand_path(load_path).exist? }
|
|
42
|
+
.max_by { |load_path| load_path.length }
|
|
43
|
+
end
|
|
44
|
+
end
|
|
45
|
+
end
|
|
46
|
+
end
|