ocran 1.3.17 → 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.
Files changed (54) hide show
  1. checksums.yaml +4 -4
  2. data/CHANGELOG.txt +306 -272
  3. data/LICENSE.txt +22 -22
  4. data/README.md +549 -531
  5. data/exe/ocran +5 -5
  6. data/ext/extconf.rb +15 -0
  7. data/lib/ocran/build_constants.rb +16 -16
  8. data/lib/ocran/build_facade.rb +17 -17
  9. data/lib/ocran/build_helper.rb +110 -105
  10. data/lib/ocran/command_output.rb +22 -22
  11. data/lib/ocran/dir_builder.rb +162 -0
  12. data/lib/ocran/direction.rb +623 -386
  13. data/lib/ocran/file_path_set.rb +69 -69
  14. data/lib/ocran/gem_spec_queryable.rb +172 -172
  15. data/lib/ocran/host_config_helper.rb +57 -37
  16. data/lib/ocran/inno_setup_script_builder.rb +111 -111
  17. data/lib/ocran/launcher_batch_builder.rb +85 -85
  18. data/lib/ocran/library_detector.rb +61 -61
  19. data/lib/ocran/library_detector_posix.rb +55 -0
  20. data/lib/ocran/option.rb +323 -273
  21. data/lib/ocran/refine_pathname.rb +104 -104
  22. data/lib/ocran/runner.rb +115 -105
  23. data/lib/ocran/runtime_environment.rb +46 -46
  24. data/lib/ocran/stub_builder.rb +298 -224
  25. data/lib/ocran/version.rb +5 -5
  26. data/lib/ocran/windows_command_escaping.rb +15 -15
  27. data/lib/ocran.rb +7 -7
  28. data/share/ocran/lzma.exe +0 -0
  29. data/src/Makefile +75 -0
  30. data/src/edicon.c +161 -0
  31. data/src/error.c +100 -0
  32. data/src/error.h +66 -0
  33. data/src/inst_dir.c +334 -0
  34. data/src/inst_dir.h +157 -0
  35. data/src/lzma/7zTypes.h +529 -0
  36. data/src/lzma/Compiler.h +43 -0
  37. data/src/lzma/LzmaDec.c +1363 -0
  38. data/src/lzma/LzmaDec.h +236 -0
  39. data/src/lzma/Precomp.h +10 -0
  40. data/src/script_info.c +246 -0
  41. data/src/script_info.h +7 -0
  42. data/src/stub.c +133 -0
  43. data/src/stub.manifest +29 -0
  44. data/src/stub.rc +3 -0
  45. data/src/system_utils.c +1002 -0
  46. data/src/system_utils.h +209 -0
  47. data/src/system_utils_posix.c +500 -0
  48. data/src/unpack.c +574 -0
  49. data/src/unpack.h +85 -0
  50. data/src/vit-ruby.ico +0 -0
  51. metadata +55 -22
  52. data/share/ocran/edicon.exe +0 -0
  53. data/share/ocran/stub.exe +0 -0
  54. data/share/ocran/stubw.exe +0 -0
data/exe/ocran CHANGED
@@ -1,5 +1,5 @@
1
- #!/usr/bin/env ruby
2
- # encoding: UTF-8
3
-
4
- load File.expand_path("../lib/ocran/runner.rb", __dir__)
5
- load Ocran::Runner.new.run
1
+ #!/usr/bin/env ruby
2
+ # encoding: UTF-8
3
+
4
+ load File.expand_path("../lib/ocran/runner.rb", __dir__)
5
+ load Ocran::Runner.new.run
data/ext/extconf.rb ADDED
@@ -0,0 +1,15 @@
1
+ gem_root = File.expand_path('..', __dir__)
2
+ src_dir = File.join(gem_root, 'src')
3
+ stub_dir = File.join(gem_root, 'share', 'ocran')
4
+
5
+ if Gem.win_platform?
6
+ system('ridk', 'exec', 'make', '-C', src_dir, 'install') ||
7
+ system('make', '-C', src_dir, 'install') ||
8
+ abort('Build failed')
9
+ else
10
+ system('make', '-C', src_dir, 'install') || abort('Build failed')
11
+ File.chmod(0755, File.join(stub_dir, 'stub'))
12
+ end
13
+
14
+ # Satisfy RubyGems' expectation that extconf.rb produces a Makefile
15
+ File.write('Makefile', "all:\ninstall:\nclean:\n")
@@ -1,16 +1,16 @@
1
- # frozen_string_literal: true
2
-
3
- module Ocran
4
- module BuildConstants
5
- # Alias for the temporary directory where files are extracted.
6
- EXTRACT_ROOT = Pathname.new("|")
7
- # Directory for source files in temporary directory.
8
- SRCDIR = Pathname.new("src")
9
- # Directory for Ruby binaries in temporary directory.
10
- BINDIR = Pathname.new("bin")
11
- # Directory for gem files in temporary directory.
12
- GEMDIR = Pathname.new("gems")
13
- # Directory for Ruby library in temporary directory.
14
- LIBDIR = Pathname.new("lib")
15
- end
16
- end
1
+ # frozen_string_literal: true
2
+
3
+ module Ocran
4
+ module BuildConstants
5
+ # Alias for the temporary directory where files are extracted.
6
+ EXTRACT_ROOT = Pathname.new("|")
7
+ # Directory for source files in temporary directory.
8
+ SRCDIR = Pathname.new("src")
9
+ # Directory for Ruby binaries in temporary directory.
10
+ BINDIR = Pathname.new("bin")
11
+ # Directory for gem files in temporary directory.
12
+ GEMDIR = Pathname.new("gems")
13
+ # Directory for Ruby library in temporary directory.
14
+ LIBDIR = Pathname.new("lib")
15
+ end
16
+ end
@@ -1,17 +1,17 @@
1
- # frozen_string_literal: true
2
-
3
- module Ocran
4
- class BuildFacade
5
- def initialize(filer, launcher)
6
- @filer, @launcher = filer, launcher
7
- end
8
-
9
- def mkdir(...) = @filer.__send__(__method__, ...)
10
-
11
- def cp(...) = @filer.__send__(__method__, ...)
12
-
13
- def export(...) = @launcher.__send__(__method__, ...)
14
-
15
- def exec(...) = @launcher.__send__(__method__, ...)
16
- end
17
- end
1
+ # frozen_string_literal: true
2
+
3
+ module Ocran
4
+ class BuildFacade
5
+ def initialize(filer, launcher)
6
+ @filer, @launcher = filer, launcher
7
+ end
8
+
9
+ def mkdir(...) = @filer.__send__(__method__, ...)
10
+
11
+ def cp(...) = @filer.__send__(__method__, ...)
12
+
13
+ def export(...) = @launcher.__send__(__method__, ...)
14
+
15
+ def exec(...) = @launcher.__send__(__method__, ...)
16
+ end
17
+ end
@@ -1,105 +1,110 @@
1
- # frozen_string_literal: true
2
- require "pathname"
3
- require_relative "refine_pathname"
4
- require_relative "command_output"
5
- require_relative "build_constants"
6
-
7
- module Ocran
8
- module BuildHelper
9
- using RefinePathname
10
-
11
- include BuildConstants, CommandOutput
12
-
13
- EMPTY_SOURCE = File.expand_path("empty_source", __dir__).freeze
14
-
15
- def mkdir(target)
16
- verbose "mkdir #{target}"
17
- super
18
- end
19
-
20
- def cp(source, target)
21
- verbose "cp #{source} #{target}"
22
- super
23
- end
24
-
25
- def exec(image, script, *argv)
26
- args = argv.map { |s| replace_placeholder(s) }.join(" ")
27
- verbose "exec #{image} #{script} #{args}"
28
- super
29
- end
30
-
31
- def export(name, value)
32
- verbose "export #{name}=#{replace_placeholder(value)}"
33
- super
34
- end
35
-
36
- def replace_placeholder(s)
37
- s.to_s.gsub(EXTRACT_ROOT.to_s, "<tempdir>")
38
- end
39
- private :replace_placeholder
40
-
41
- def copy_to_bin(source, target)
42
- cp(source, BINDIR / target)
43
- end
44
-
45
- def copy_to_gem(source, target)
46
- cp(source, GEMDIR / target)
47
- end
48
-
49
- def copy_to_lib(source, target)
50
- cp(source, LIBDIR / target)
51
- end
52
-
53
- def duplicate_to_exec_prefix(source)
54
- cp(source, Pathname(source).relative_path_from(HostConfigHelper.exec_prefix))
55
- end
56
-
57
- def duplicate_to_gem_home(source, gem_path)
58
- copy_to_gem(source, Pathname(source).relative_path_from(gem_path))
59
- end
60
-
61
- def resolve_source_path(source, root_prefix)
62
- source = Pathname(source)
63
-
64
- if source.subpath?(HostConfigHelper.exec_prefix)
65
- source.relative_path_from(HostConfigHelper.exec_prefix)
66
- elsif source.subpath?(root_prefix)
67
- SRCDIR / source.relative_path_from(root_prefix)
68
- else
69
- SRCDIR / source.basename
70
- end
71
- end
72
-
73
- # Sets an environment variable with a joined path value.
74
- # This method processes an array of path strings or Pathname objects, accepts
75
- # absolute paths as is, and appends a placeholder to relative paths to convert
76
- # them into absolute paths. The converted paths are then joined into a single
77
- # string using the system's path separator.
78
- #
79
- # @param name [String] the name of the environment variable to set.
80
- # @param paths [Array<String, Pathname>] an array of path arguments which can
81
- # be either absolute or relative.
82
- #
83
- # Example:
84
- # set_env_path("RUBYLIB", "lib", "ext", "vendor/lib")
85
- # # This sets RUBYLIB to a string such as "C:/ProjectRoot/lib;C:/ProjectRoot/ext;C:/ProjectRoot/vendor/lib"
86
- # # assuming each path is correctly converted to an absolute path through a placeholder.
87
- #
88
- def set_env_path(name, *paths)
89
- value = paths.map { |path|
90
- if File.absolute_path?(path)
91
- path
92
- else
93
- File.join(EXTRACT_ROOT, path)
94
- end
95
- }.join(File::PATH_SEPARATOR)
96
-
97
- export(name, value)
98
- end
99
-
100
- def touch(target)
101
- verbose "touch #{target}"
102
- cp(EMPTY_SOURCE, target)
103
- end
104
- end
105
- end
1
+ # frozen_string_literal: true
2
+ require "pathname"
3
+ require_relative "refine_pathname"
4
+ require_relative "command_output"
5
+ require_relative "build_constants"
6
+
7
+ module Ocran
8
+ module BuildHelper
9
+ using RefinePathname
10
+
11
+ include BuildConstants, CommandOutput
12
+
13
+ EMPTY_SOURCE = File.expand_path("empty_source", __dir__).freeze
14
+
15
+ def mkdir(target)
16
+ verbose "mkdir #{target}"
17
+ super
18
+ end
19
+
20
+ def cp(source, target)
21
+ verbose "cp #{source} #{target}"
22
+ super
23
+ end
24
+
25
+ def exec(image, script, *argv)
26
+ args = argv.map { |s| replace_placeholder(s) }.join(" ")
27
+ verbose "exec #{image} #{script} #{args}"
28
+ super
29
+ end
30
+
31
+ def export(name, value)
32
+ verbose "export #{name}=#{replace_placeholder(value)}"
33
+ super
34
+ end
35
+
36
+ def replace_placeholder(s)
37
+ s.to_s.gsub(EXTRACT_ROOT.to_s, "<tempdir>")
38
+ end
39
+ private :replace_placeholder
40
+
41
+ def copy_to_bin(source, target)
42
+ cp(source, BINDIR / target)
43
+ end
44
+
45
+ def symlink_in_bin(target, link_name)
46
+ verbose "symlink #{BINDIR / link_name} -> #{target}"
47
+ symlink(BINDIR / link_name, target.to_s)
48
+ end
49
+
50
+ def copy_to_gem(source, target)
51
+ cp(source, GEMDIR / target)
52
+ end
53
+
54
+ def copy_to_lib(source, target)
55
+ cp(source, LIBDIR / target)
56
+ end
57
+
58
+ def duplicate_to_exec_prefix(source)
59
+ cp(source, Pathname(source).relative_path_from(HostConfigHelper.exec_prefix))
60
+ end
61
+
62
+ def duplicate_to_gem_home(source, gem_path)
63
+ copy_to_gem(source, Pathname(source).relative_path_from(gem_path))
64
+ end
65
+
66
+ def resolve_source_path(source, root_prefix)
67
+ source = Pathname(source)
68
+
69
+ if source.subpath?(HostConfigHelper.exec_prefix)
70
+ source.relative_path_from(HostConfigHelper.exec_prefix)
71
+ elsif source.subpath?(root_prefix)
72
+ SRCDIR / source.relative_path_from(root_prefix)
73
+ else
74
+ SRCDIR / source.basename
75
+ end
76
+ end
77
+
78
+ # Sets an environment variable with a joined path value.
79
+ # This method processes an array of path strings or Pathname objects, accepts
80
+ # absolute paths as is, and appends a placeholder to relative paths to convert
81
+ # them into absolute paths. The converted paths are then joined into a single
82
+ # string using the system's path separator.
83
+ #
84
+ # @param name [String] the name of the environment variable to set.
85
+ # @param paths [Array<String, Pathname>] an array of path arguments which can
86
+ # be either absolute or relative.
87
+ #
88
+ # Example:
89
+ # set_env_path("RUBYLIB", "lib", "ext", "vendor/lib")
90
+ # # This sets RUBYLIB to a string such as "C:/ProjectRoot/lib;C:/ProjectRoot/ext;C:/ProjectRoot/vendor/lib"
91
+ # # assuming each path is correctly converted to an absolute path through a placeholder.
92
+ #
93
+ def set_env_path(name, *paths)
94
+ value = paths.map { |path|
95
+ if File.absolute_path?(path)
96
+ path
97
+ else
98
+ File.join(EXTRACT_ROOT, path)
99
+ end
100
+ }.join(File::PATH_SEPARATOR)
101
+
102
+ export(name, value)
103
+ end
104
+
105
+ def touch(target)
106
+ verbose "touch #{target}"
107
+ cp(EMPTY_SOURCE, target)
108
+ end
109
+ end
110
+ end
@@ -1,22 +1,22 @@
1
- # frozen_string_literal: true
2
- load File.expand_path("../ocran.rb", __dir__)
3
-
4
- module Ocran
5
- module CommandOutput
6
- def say(s)
7
- puts "=== #{s}" unless Ocran.option&.quiet?
8
- end
9
-
10
- def verbose(s)
11
- puts s if Ocran.option&.verbose?
12
- end
13
-
14
- def warning(s)
15
- STDERR.puts "WARNING: #{s}" if Ocran.option&.warning?
16
- end
17
-
18
- def error(s)
19
- STDERR.puts "ERROR: #{s}"
20
- end
21
- end
22
- end
1
+ # frozen_string_literal: true
2
+ load File.expand_path("../ocran.rb", __dir__)
3
+
4
+ module Ocran
5
+ module CommandOutput
6
+ def say(s)
7
+ puts "=== #{s}" unless Ocran.option&.quiet?
8
+ end
9
+
10
+ def verbose(s)
11
+ puts s if Ocran.option&.verbose?
12
+ end
13
+
14
+ def warning(s)
15
+ STDERR.puts "WARNING: #{s}" if Ocran.option&.warning?
16
+ end
17
+
18
+ def error(s)
19
+ STDERR.puts "ERROR: #{s}"
20
+ end
21
+ end
22
+ end
@@ -0,0 +1,162 @@
1
+ # frozen_string_literal: true
2
+ require "pathname"
3
+ require "fileutils"
4
+ require_relative "build_constants"
5
+
6
+ module Ocran
7
+ # Builder that outputs all files to a plain directory instead of a self-extracting
8
+ # executable. A launch script (`.sh` on POSIX, `.bat` on Windows) is written at
9
+ # the root of the directory so the packaged app can be started directly.
10
+ class DirBuilder
11
+ include BuildConstants
12
+
13
+ WINDOWS = Gem.win_platform?
14
+
15
+ attr_reader :data_size
16
+
17
+ def initialize(path)
18
+ @path = Pathname(path)
19
+ @path.mkpath
20
+ @env = {}
21
+ @exec_args = nil
22
+ @symlinks = []
23
+ @data_size = 0
24
+
25
+ yield(self) if block_given?
26
+
27
+ finalize
28
+ end
29
+
30
+ def mkdir(target)
31
+ (@path / target).mkpath
32
+ end
33
+
34
+ def cp(source, target)
35
+ dest = @path / target
36
+ dest.dirname.mkpath
37
+ src = source.to_s
38
+ FileUtils.cp(src, dest.to_s)
39
+ @data_size += File.size(src)
40
+ end
41
+
42
+ def symlink(link_path, target)
43
+ @symlinks << [link_path.to_s, target.to_s]
44
+ end
45
+
46
+ def export(name, value)
47
+ @env[name.to_s] = value.to_s
48
+ end
49
+
50
+ def exec(image, script, *argv)
51
+ raise "Script is already set" if @exec_args
52
+ @exec_args = [image.to_s, script.to_s, argv.map(&:to_s)]
53
+ end
54
+
55
+ # Create a zip archive from a source directory.
56
+ # Uses the `zip` command on POSIX and PowerShell on Windows.
57
+ def self.create_zip(zip_path, source_dir)
58
+ zip_path = File.expand_path(zip_path.to_s)
59
+ if Gem.win_platform?
60
+ system("powershell", "-NoProfile", "-Command",
61
+ "Compress-Archive -Path '#{source_dir}\\*' -DestinationPath '#{zip_path}'",
62
+ exception: true)
63
+ else
64
+ Dir.chdir(source_dir) do
65
+ system("zip", "-r", zip_path, ".", exception: true)
66
+ end
67
+ end
68
+ end
69
+
70
+ private
71
+
72
+ def finalize
73
+ unless WINDOWS
74
+ @symlinks.each do |link_path, target|
75
+ dest = @path / link_path
76
+ dest.dirname.mkpath
77
+ File.symlink(target, dest) unless dest.exist?
78
+ end
79
+ end
80
+
81
+ write_launch_script
82
+ end
83
+
84
+ # Replace the EXTRACT_ROOT placeholder ("|") in a value string with
85
+ # the runtime directory variable.
86
+ def replace_root(value, root_var)
87
+ value.gsub("#{EXTRACT_ROOT}/", "#{root_var}/")
88
+ end
89
+
90
+ def script_basename
91
+ @exec_args ? Pathname(@exec_args[1]).basename.sub_ext("").to_s : "run"
92
+ end
93
+
94
+ def write_launch_script
95
+ WINDOWS ? write_batch_script : write_shell_script
96
+ end
97
+
98
+ def write_shell_script
99
+ script_path = @path / "#{script_basename}.sh"
100
+
101
+ lines = [
102
+ "#!/bin/sh",
103
+ 'SCRIPT_DIR="$(cd "$(dirname "$0")" && pwd)"',
104
+ ]
105
+
106
+ @env.each do |name, value|
107
+ replaced = replace_root(value, "$SCRIPT_DIR")
108
+ lines << "export #{name}=\"#{replaced}\""
109
+ end
110
+
111
+ if @exec_args
112
+ image, script, argv = @exec_args
113
+ image_r = replace_root(image, "$SCRIPT_DIR")
114
+ script_r = replace_root(script, "$SCRIPT_DIR")
115
+
116
+ # Prepend SCRIPT_DIR to relative paths
117
+ image_r = "$SCRIPT_DIR/#{image_r}" unless image_r.start_with?("/", "$SCRIPT_DIR")
118
+ script_r = "$SCRIPT_DIR/#{script_r}" unless script_r.start_with?("/", "$SCRIPT_DIR")
119
+
120
+ args = argv.map { |a| "\"#{replace_root(a, "$SCRIPT_DIR")}\"" }.join(" ")
121
+ exec_line = "exec \"#{image_r}\" \"#{script_r}\""
122
+ exec_line += " #{args}" unless args.empty?
123
+ exec_line += ' "$@"'
124
+ lines << exec_line
125
+ end
126
+
127
+ File.write(script_path, lines.join("\n") + "\n")
128
+ File.chmod(0755, script_path)
129
+ end
130
+
131
+ def write_batch_script
132
+ script_path = @path / "#{script_basename}.bat"
133
+
134
+ lines = [
135
+ "@echo off",
136
+ "set SCRIPT_DIR=%~dp0",
137
+ ]
138
+
139
+ @env.each do |name, value|
140
+ replaced = replace_root(value, "%SCRIPT_DIR%").tr("/", "\\")
141
+ lines << "set #{name}=#{replaced}"
142
+ end
143
+
144
+ if @exec_args
145
+ image, script, argv = @exec_args
146
+ image_r = replace_root(image, "%SCRIPT_DIR%").tr("/", "\\")
147
+ script_r = replace_root(script, "%SCRIPT_DIR%").tr("/", "\\")
148
+
149
+ image_r = "%SCRIPT_DIR%#{image_r}" unless image_r.include?("%SCRIPT_DIR%") || File.absolute_path?(image_r)
150
+ script_r = "%SCRIPT_DIR%#{script_r}" unless script_r.include?("%SCRIPT_DIR%") || File.absolute_path?(script_r)
151
+
152
+ args = argv.map { |a| replace_root(a, "%SCRIPT_DIR%") }.join(" ")
153
+ exec_line = "\"#{image_r}\" \"#{script_r}\""
154
+ exec_line += " #{args}" unless args.empty?
155
+ exec_line += " %*"
156
+ lines << exec_line
157
+ end
158
+
159
+ File.write(script_path, lines.join("\r\n") + "\r\n")
160
+ end
161
+ end
162
+ end