kompo 0.3.1 → 0.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 CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: 62d037ca6d6e6732787913525793259a1f7fc873ef236d878f311f7f7a006027
4
- data.tar.gz: 85a8518c2f667948993610c8c371f5965f23a9c5e3966c56528effd1d83f83c1
3
+ metadata.gz: 77c057a8598fe8c02319c0635d2bf80cca3578f2606f676adae992dcf34afa68
4
+ data.tar.gz: 68dfc19d5b9484b5fabe79cd18f8f8bb11368fb0f788a7adc38a44d94aa7aa21
5
5
  SHA512:
6
- metadata.gz: 39f7e8db6050dc96a268717d9f8e95bd46a1e25a2d9f39062565fd4d61975440d5810eec072011361c4ba6d68189ce271326f9b43adbae5ea06ce9f022a85a0f
7
- data.tar.gz: 4dde801ca0ca7df82a0221a2e79a3a9ce835a201108010355262d2c77aad55bff5b2d21f119746560cbb71275a8b07ca2db87f1c7da44200c022dbe911510124
6
+ metadata.gz: c1da9b9c3b8f2903977b3ab503822a52586e3cded7af5c96651a3e423efa3e324e99fd82462fcbeba23a9bda06b80a90fe66239be62230b5f39cb6001387ee09
7
+ data.tar.gz: 63f90fcac1d59773595e696378573e8a1bfbb1cea9581145b729bc7e842dc479a982f0589acdf2f1823b8a21448df4fd8a3c434868e0ba8c281d47d13daed164
data/CHANGELOG.md CHANGED
@@ -7,6 +7,31 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
7
7
 
8
8
  ## [Unreleased]
9
9
 
10
+ ## [0.4.0] - 2025-01-26
11
+
12
+ ### Added
13
+ - `--dry-run` option to show compile command without executing [#17](https://github.com/ahogappa/kompo/pull/17)
14
+ - `--no-gemfile` option to skip Gemfile processing [#13](https://github.com/ahogappa/kompo/pull/13)
15
+ - `.kompoignore` files support for ignoring specific files in VFS [#20](https://github.com/ahogappa/kompo/pull/20)
16
+ - Duplicate file detection in VFS embedding [#15](https://github.com/ahogappa/kompo/pull/15)
17
+ - standardrb lint check to CI [#14](https://github.com/ahogappa/kompo/pull/14)
18
+
19
+ ### Changed
20
+ - Set default progress mode to simple [#16](https://github.com/ahogappa/kompo/pull/16)
21
+ - Bump kompo-vfs minimum version to 0.5.1 [#23](https://github.com/ahogappa/kompo/pull/23)
22
+ - Use Taski.message instead of puts for dry-run output [#21](https://github.com/ahogappa/kompo/pull/21)
23
+ - Remove redundant compile command label from dry-run output [#22](https://github.com/ahogappa/kompo/pull/22)
24
+ - Update README to match actual implementation
25
+
26
+ ### Fixed
27
+ - Extract LIBS from Makefiles including bundled gems [#19](https://github.com/ahogappa/kompo/pull/19)
28
+ - Support bundled gems native extensions for Ruby 4.0+ [#12](https://github.com/ahogappa/kompo/pull/12)
29
+
30
+ ## [0.3.2] - 2025-01-25
31
+
32
+ ### Fixed
33
+ - Embed gemspec files in VFS for runtime Bundler support [#10](https://github.com/ahogappa/kompo/pull/10)
34
+
10
35
  ## [0.3.1] - 2025-01-25
11
36
 
12
37
  ### Fixed
data/Gemfile CHANGED
@@ -1,16 +1,16 @@
1
1
  # frozen_string_literal: true
2
2
 
3
- source 'https://rubygems.org'
3
+ source "https://rubygems.org"
4
4
 
5
5
  # Specify your gem's dependencies in kompo.gemspec
6
6
  gemspec
7
7
 
8
- gem 'rake', '~> 13.0'
9
- gem 'taski', '~> 0.8.0'
8
+ gem "rake", "~> 13.0"
9
+ gem "taski", "~> 0.8.0"
10
10
 
11
11
  group :development, :test do
12
- gem 'debug'
13
- gem 'minitest'
14
- gem 'simplecov', require: false
15
- gem 'standard'
12
+ gem "debug"
13
+ gem "minitest"
14
+ gem "simplecov", require: false
15
+ gem "standard"
16
16
  end
data/Gemfile.lock CHANGED
@@ -1,7 +1,7 @@
1
1
  PATH
2
2
  remote: .
3
3
  specs:
4
- kompo (0.3.1)
4
+ kompo (0.4.0)
5
5
  async
6
6
  mini_portile2
7
7
  pathspec
@@ -103,7 +103,7 @@ GEM
103
103
  lint_roller (~> 1.1)
104
104
  rubocop-performance (~> 1.26.0)
105
105
  stringio (3.2.0)
106
- taski (0.8.0)
106
+ taski (0.8.3)
107
107
  prism (~> 1.4)
108
108
  tsort
109
109
  traces (0.18.2)
data/README.md CHANGED
@@ -33,21 +33,36 @@ $ gem install kompo
33
33
 
34
34
  ## Usage
35
35
 
36
- ### prerequisites
37
- Install [kompo-vfs](https://github.com/ahogappa/kompo-vfs).
36
+ ### Prerequisites
37
+
38
+ Kompo requires [kompo-vfs](https://github.com/ahogappa/kompo-vfs).
39
+
40
+ #### macOS (Homebrew required)
41
+
42
+ On macOS, [Homebrew](https://brew.sh) is required to install kompo-vfs:
38
43
 
39
- #### Homebrew
40
44
  ```sh
41
45
  $ brew tap ahogappa/kompo-vfs https://github.com/ahogappa/kompo-vfs.git
42
46
  $ brew install ahogappa/kompo-vfs/kompo-vfs
43
47
  ```
44
48
 
45
- ### Building
46
- To build komp-vfs, you need to have cargo installation.
49
+ #### Linux
50
+
51
+ On Linux, kompo-vfs is automatically built from source. You need to have Cargo (Rust) installed:
52
+
53
+ ```sh
54
+ $ curl --proto '=https' --tlsv1.2 -sSf https://sh.rustup.rs | sh
55
+ ```
56
+
57
+ #### For Development
58
+
59
+ If you want to use a local build of kompo-vfs, build it manually and use the `--local-vfs-path` option:
60
+
47
61
  ```sh
48
62
  $ git clone https://github.com/ahogappa/kompo-vfs.git
49
63
  $ cd kompo-vfs
50
64
  $ cargo build --release
65
+ $ kompo --local-vfs-path=/path/to/kompo-vfs ...
51
66
  ```
52
67
 
53
68
  ## Options
@@ -62,10 +77,13 @@ Options:
62
77
  --ruby-source=PATH Path to Ruby source tarball or directory
63
78
  --no-cache Build Ruby from source, ignoring cache
64
79
  --no-stdlib Exclude Ruby standard library from binary
80
+ --no-gemfile Skip Gemfile processing (no bundle install)
65
81
  --local-vfs-path=PATH Path to local kompo-vfs for development
66
82
  --clean[=VERSION] Clean cache (current version by default, or specify VERSION, or "all")
83
+ --dry-run Show final compile command without executing it
67
84
  -t, --tree Show task dependency tree and exit
68
- -h, --help Show help message
85
+ -v, --version Show version
86
+ -h, --help Show this help message
69
87
 
70
88
  Files:
71
89
  Additional files and directories to include in the binary
@@ -81,9 +99,12 @@ Files:
81
99
  | `--ruby-source` | Use a local Ruby source instead of downloading. Useful for custom Ruby builds. |
82
100
  | `--no-cache` | Force a fresh Ruby build, ignoring any cached version. |
83
101
  | `--no-stdlib` | Reduce binary size by excluding Ruby standard library. Only use if your app doesn't need stdlib. |
102
+ | `--no-gemfile` | Skip Gemfile processing and bundle install. Useful when your project doesn't use Bundler. |
84
103
  | `--local-vfs-path` | Use a local kompo-vfs build instead of Homebrew installation. Useful for development. |
85
104
  | `--clean` | Remove cached Ruby builds. Use `--clean=all` to remove all versions. |
105
+ | `--dry-run` | Show the final compile command without executing it. Useful for debugging build issues. |
86
106
  | `-t, --tree` | Display the task dependency graph and exit without building. |
107
+ | `-v, --version` | Display the kompo version and exit. |
87
108
 
88
109
  ### Examples
89
110
 
@@ -137,14 +158,18 @@ node_modules/ # Ignore node_modules
137
158
  - Patterns are matched against paths relative to the project root
138
159
  - Comments and empty lines are ignored
139
160
 
140
- ## examples
161
+ ## Samples
162
+
163
+ Sample applications demonstrating various use cases are available in the [samples](./samples) directory:
141
164
 
142
- * hello
143
- * simple hello world script.
144
- * sinatra_and_sqlite
145
- * simple sinatra app with sqlite3.
146
- * rails
147
- * simple Rails 7.1 application.
165
+ * [hello](./samples/hello)
166
+ * Simple hello world script.
167
+ * [native_gems](./samples/native_gems)
168
+ * Demonstrates native extension gems (nokogiri, sqlite3, and msgpack).
169
+ * [sinatra_and_sqlite](./samples/sinatra_and_sqlite)
170
+ * Simple Sinatra app with SQLite3.
171
+ * [rails](./samples/rails/sample)
172
+ * Simple Rails application.
148
173
 
149
174
  ## Development
150
175
 
data/Rakefile CHANGED
@@ -1,14 +1,14 @@
1
1
  # frozen_string_literal: true
2
2
 
3
- require 'bundler/gem_tasks'
4
- require 'rake/testtask'
3
+ require "bundler/gem_tasks"
4
+ require "rake/testtask"
5
5
 
6
6
  Rake::TestTask.new(:test) do |t|
7
- t.libs << 'test'
8
- t.libs << 'lib'
9
- t.test_files = FileList['test/**/*_test.rb']
7
+ t.libs << "test"
8
+ t.libs << "lib"
9
+ t.test_files = FileList["test/**/*_test.rb"]
10
10
  end
11
11
 
12
- require 'standard/rake'
12
+ require "standard/rake"
13
13
 
14
14
  task default: %i[test standard]
data/exe/kompo CHANGED
@@ -1,45 +1,47 @@
1
1
  #!/usr/bin/env ruby
2
2
  # frozen_string_literal: true
3
3
 
4
- require 'optparse'
5
- require_relative '../lib/kompo'
4
+ require "optparse"
5
+ require_relative "../lib/kompo"
6
6
 
7
7
  args = {}
8
8
  opt = OptionParser.new do |o|
9
- o.banner = 'Usage: kompo [options] [files...]'
10
- o.separator ''
11
- o.separator 'Options:'
9
+ o.banner = "Usage: kompo [options] [files...]"
10
+ o.separator ""
11
+ o.separator "Options:"
12
12
 
13
- o.on('-e', '--entrypoint=FILE', 'Entry point file (default: main.rb)') { |v| args[:entrypoint] = v }
14
- o.on('-o', '--output=DIR', 'Output directory for the binary') { |v| args[:output_dir] = File.expand_path(v) }
15
- o.on('--ruby-version=VERSION', "Ruby version to use (default: #{RUBY_VERSION})") { |v| args[:ruby_version] = v }
16
- o.on('--ruby-source=PATH', 'Path to Ruby source tarball or directory') do |v|
13
+ o.on("-e", "--entrypoint=FILE", "Entry point file (default: main.rb)") { |v| args[:entrypoint] = v }
14
+ o.on("-o", "--output=DIR", "Output directory for the binary") { |v| args[:output_dir] = File.expand_path(v) }
15
+ o.on("--ruby-version=VERSION", "Ruby version to use (default: #{RUBY_VERSION})") { |v| args[:ruby_version] = v }
16
+ o.on("--ruby-source=PATH", "Path to Ruby source tarball or directory") do |v|
17
17
  args[:ruby_source_path] = File.expand_path(v)
18
18
  end
19
- o.on('--no-cache', 'Build Ruby from source, ignoring cache') { |_v| args[:no_cache] = true }
20
- o.on('--no-stdlib', 'Exclude Ruby standard library from binary') { |_v| args[:no_stdlib] = true }
21
- o.on('--local-vfs-path=PATH', 'Path to local kompo-vfs for development') do |v|
19
+ o.on("--no-cache", "Build Ruby from source, ignoring cache") { |_v| args[:no_cache] = true }
20
+ o.on("--no-stdlib", "Exclude Ruby standard library from binary") { |_v| args[:no_stdlib] = true }
21
+ o.on("--no-gemfile", "Skip Gemfile processing (no bundle install)") { |_v| args[:no_gemfile] = true }
22
+ o.on("--local-vfs-path=PATH", "Path to local kompo-vfs for development") do |v|
22
23
  args[:local_kompo_vfs_path] = File.expand_path(v)
23
24
  end
24
- o.on('--clean[=VERSION]', 'Clean cache (current Ruby version by default, or specify VERSION, or "all")') do |v|
25
+ o.on("--clean[=VERSION]", 'Clean cache (current Ruby version by default, or specify VERSION, or "all")') do |v|
25
26
  args[:clean_cache] = v.nil? ? RUBY_VERSION : v
26
27
  end
27
- o.on('-t', '--tree', 'Show task dependency tree and exit') do
28
+ o.on("--dry-run", "Show final compile command without executing it") { |_v| args[:dry_run] = true }
29
+ o.on("-t", "--tree", "Show task dependency tree and exit") do
28
30
  puts Kompo::Packing.tree
29
31
  exit(0)
30
32
  end
31
- o.on('-v', '--version', 'Show version') do
33
+ o.on("-v", "--version", "Show version") do
32
34
  puts "kompo #{Kompo::VERSION}"
33
35
  exit(0)
34
36
  end
35
- o.on('-h', '--help', 'Show this help message') do
37
+ o.on("-h", "--help", "Show this help message") do
36
38
  puts o
37
39
  exit(0)
38
40
  end
39
41
 
40
- o.separator ''
41
- o.separator 'Files:'
42
- o.separator ' Additional files and directories to include in the binary'
42
+ o.separator ""
43
+ o.separator "Files:"
44
+ o.separator " Additional files and directories to include in the binary"
43
45
  end
44
46
  opt.parse!(ARGV)
45
47
  args[:files] = ARGV
data/lib/kompo/cache.rb CHANGED
@@ -1,19 +1,19 @@
1
1
  # frozen_string_literal: true
2
2
 
3
- require 'fileutils'
3
+ require "fileutils"
4
4
 
5
5
  module Kompo
6
6
  # Clean the cache for specified Ruby version
7
7
  # @param version [String] Ruby version to clean, or "all" to clean all caches
8
8
  def self.clean_cache(version)
9
- kompo_cache = File.expand_path('~/.kompo/cache')
9
+ kompo_cache = File.expand_path("~/.kompo/cache")
10
10
 
11
11
  unless Dir.exist?(kompo_cache)
12
12
  puts "Cache directory does not exist: #{kompo_cache}"
13
13
  return
14
14
  end
15
15
 
16
- if version == 'all'
16
+ if version == "all"
17
17
  clean_all_caches(kompo_cache)
18
18
  else
19
19
  clean_version_cache(kompo_cache, version)
@@ -22,7 +22,7 @@ module Kompo
22
22
 
23
23
  # Clean all caches in the cache directory
24
24
  def self.clean_all_caches(kompo_cache)
25
- entries = Dir.glob(File.join(kompo_cache, '*'))
25
+ entries = Dir.glob(File.join(kompo_cache, "*"))
26
26
  if entries.empty?
27
27
  puts "No caches found in #{kompo_cache}"
28
28
  return
@@ -33,7 +33,7 @@ module Kompo
33
33
  puts "Removed: #{entry}"
34
34
  end
35
35
 
36
- puts 'All caches cleaned successfully'
36
+ puts "All caches cleaned successfully"
37
37
  end
38
38
  private_class_method :clean_all_caches
39
39
 
@@ -52,8 +52,8 @@ module Kompo
52
52
  real_version_cache = File.realpath(version_cache_dir)
53
53
 
54
54
  unless real_version_cache.start_with?(real_kompo_cache + File::SEPARATOR) ||
55
- real_version_cache == real_kompo_cache
56
- puts 'Error: Invalid cache path detected (possible path traversal)'
55
+ real_version_cache == real_kompo_cache
56
+ puts "Error: Invalid cache path detected (possible path traversal)"
57
57
  return
58
58
  end
59
59
 
@@ -1,12 +1,12 @@
1
1
  # frozen_string_literal: true
2
2
 
3
- require 'pathspec'
3
+ require "pathspec"
4
4
 
5
5
  module Kompo
6
6
  # Handler for .kompoignore file
7
7
  # Uses pathspec gem for gitignore-compatible pattern matching
8
8
  class KompoIgnore
9
- FILENAME = '.kompoignore'
9
+ FILENAME = ".kompoignore"
10
10
 
11
11
  def initialize(project_dir)
12
12
  @project_dir = project_dir
@@ -43,18 +43,40 @@ module Kompo
43
43
  def build_extension(ext, work_dir)
44
44
  dir_name = ext[:dir_name]
45
45
  gem_ext_name = ext[:gem_ext_name]
46
- ext_type = ext[:is_rust] ? "Rust" : "C"
47
46
 
48
- group("Building #{gem_ext_name} (#{ext_type})") do
49
- if ext[:is_rust]
50
- build_rust_extension(dir_name, ext[:cargo_toml], gem_ext_name, work_dir)
51
- else
52
- build_c_extension(dir_name, gem_ext_name, work_dir)
47
+ if ext[:is_prebuilt]
48
+ # Pre-built bundled gems only need registration for ruby_init_ext()
49
+ group("Registering #{gem_ext_name} (pre-built bundled gem)") do
50
+ register_prebuilt_extension(dir_name, gem_ext_name)
51
+ puts "Registered: #{gem_ext_name}"
53
52
  end
53
+ else
54
+ ext_type = ext[:is_rust] ? "Rust" : "C"
55
+ group("Building #{gem_ext_name} (#{ext_type})") do
56
+ if ext[:is_rust]
57
+ build_rust_extension(dir_name, ext[:cargo_toml], gem_ext_name, work_dir)
58
+ else
59
+ build_c_extension(dir_name, gem_ext_name, work_dir)
60
+ end
61
+
62
+ register_extension(dir_name, gem_ext_name)
63
+ puts "Built: #{gem_ext_name}"
64
+ end
65
+ end
66
+ end
67
+
68
+ # Register pre-built bundled gem extension for ruby_init_ext()
69
+ # These extensions are already compiled during Ruby build
70
+ def register_prebuilt_extension(dir_name, gem_ext_name)
71
+ makefile_path = File.join(dir_name, "Makefile")
54
72
 
55
- register_extension(dir_name, gem_ext_name)
56
- puts "Built: #{gem_ext_name}"
73
+ unless File.exist?(makefile_path)
74
+ raise "Cannot register pre-built extension #{gem_ext_name}: Makefile not found in #{dir_name}"
57
75
  end
76
+
77
+ makefile_content = File.read(makefile_path)
78
+ prefix, target_name = parse_makefile_metadata(makefile_content, gem_ext_name)
79
+ add_extension_entry(prefix, target_name)
58
80
  end
59
81
 
60
82
  def register_extension(dir_name, gem_ext_name)
@@ -63,8 +85,7 @@ module Kompo
63
85
  if File.exist?(makefile_path)
64
86
  # C extension: parse Makefile
65
87
  makefile_content = File.read(makefile_path)
66
- prefix = makefile_content.scan(/target_prefix = (.*)/).flatten.first&.delete_prefix("/") || ""
67
- target_name = makefile_content.scan(/TARGET_NAME = (.*)/).flatten.first || gem_ext_name
88
+ prefix, target_name = parse_makefile_metadata(makefile_content, gem_ext_name)
68
89
  else
69
90
  # Rust extension: parse Cargo.toml
70
91
  cargo_toml_path = File.join(dir_name, "Cargo.toml")
@@ -82,9 +103,7 @@ module Kompo
82
103
  end
83
104
  end
84
105
 
85
- # Path for ruby_init_ext must match require path (without file extension)
86
- ext_path = File.join(prefix, target_name).delete_prefix("/")
87
- @exts << [ext_path, "Init_#{target_name}"]
106
+ add_extension_entry(prefix, target_name)
88
107
  end
89
108
 
90
109
  # Parse Cargo.toml to extract target name
@@ -118,6 +137,21 @@ module Kompo
118
137
  lib_name || package_name
119
138
  end
120
139
 
140
+ # Parse Makefile to extract target_prefix and TARGET_NAME
141
+ # Returns [prefix, target_name] where prefix is empty string if not specified
142
+ def parse_makefile_metadata(makefile_content, fallback_name)
143
+ prefix = makefile_content.scan(/target_prefix = (.*)/).flatten.first&.delete_prefix("/") || ""
144
+ target_name = makefile_content.scan(/TARGET_NAME = (.*)/).flatten.first || fallback_name
145
+ [prefix, target_name]
146
+ end
147
+
148
+ # Add extension entry to @exts for ruby_init_ext()
149
+ # ext_path must match the require path (without file extension)
150
+ def add_extension_entry(prefix, target_name)
151
+ ext_path = File.join(prefix, target_name).delete_prefix("/")
152
+ @exts << [ext_path, "Init_#{target_name}"]
153
+ end
154
+
121
155
  def build_rust_extension(dir_name, cargo_toml, gem_ext_name, work_dir)
122
156
  cargo = CargoPath.path
123
157
 
@@ -162,8 +196,7 @@ module Kompo
162
196
 
163
197
  # Get full extension path (prefix/target_name) for proper directory structure
164
198
  # This ensures erb/escape and cgi/escape are stored in different directories
165
- prefix = makefile_content.scan(/target_prefix = (.*)/).flatten.first&.delete_prefix("/") || ""
166
- target_name = makefile_content.scan(/TARGET_NAME = (.*)/).flatten.first || gem_ext_name
199
+ prefix, target_name = parse_makefile_metadata(makefile_content, gem_ext_name)
167
200
  ext_path = File.join(prefix, target_name).delete_prefix("/")
168
201
  dest_ext_dir = File.join(work_dir, "ext", ext_path)
169
202
 
@@ -1,9 +1,9 @@
1
1
  # frozen_string_literal: true
2
2
 
3
- require 'fileutils'
4
- require 'digest'
5
- require 'json'
6
- require 'bundler'
3
+ require "fileutils"
4
+ require "digest"
5
+ require "json"
6
+ require "bundler"
7
7
 
8
8
  module Kompo
9
9
  # Shared helpers for bundle cache operations
@@ -19,7 +19,7 @@ module Kompo
19
19
 
20
20
  def compute_gemfile_lock_hash
21
21
  work_dir = WorkDir.path
22
- gemfile_lock_path = File.join(work_dir, 'Gemfile.lock')
22
+ gemfile_lock_path = File.join(work_dir, "Gemfile.lock")
23
23
  return nil unless File.exist?(gemfile_lock_path)
24
24
 
25
25
  content = File.read(gemfile_lock_path)
@@ -53,10 +53,10 @@ module Kompo
53
53
  work_dir = WorkDir.path
54
54
  ruby_major_minor = InstallRuby.ruby_major_minor
55
55
 
56
- @bundle_ruby_dir = File.join(work_dir, 'bundle', 'ruby', "#{ruby_major_minor}.0")
57
- @bundler_config_path = File.join(work_dir, '.bundle', 'config')
56
+ @bundle_ruby_dir = File.join(work_dir, "bundle", "ruby", "#{ruby_major_minor}.0")
57
+ @bundler_config_path = File.join(work_dir, ".bundle", "config")
58
58
 
59
- kompo_cache = Taski.args.fetch(:kompo_cache, File.expand_path('~/.kompo/cache'))
59
+ kompo_cache = Taski.args.fetch(:kompo_cache, File.expand_path("~/.kompo/cache"))
60
60
  ruby_version = InstallRuby.ruby_version
61
61
  version_cache_dir = File.join(kompo_cache, ruby_version)
62
62
 
@@ -65,19 +65,19 @@ module Kompo
65
65
 
66
66
  cache_dir = File.join(version_cache_dir, bundle_cache_name)
67
67
 
68
- group('Restoring bundle from cache') do
68
+ group("Restoring bundle from cache") do
69
69
  # Clean up existing files in case work_dir is reused
70
- FileUtils.rm_rf(File.join(work_dir, 'bundle')) if Dir.exist?(File.join(work_dir, 'bundle'))
71
- FileUtils.rm_rf(File.join(work_dir, '.bundle')) if Dir.exist?(File.join(work_dir, '.bundle'))
70
+ FileUtils.rm_rf(File.join(work_dir, "bundle")) if Dir.exist?(File.join(work_dir, "bundle"))
71
+ FileUtils.rm_rf(File.join(work_dir, ".bundle")) if Dir.exist?(File.join(work_dir, ".bundle"))
72
72
 
73
73
  # Copy from cache
74
- FileUtils.cp_r(File.join(cache_dir, 'bundle'), File.join(work_dir, 'bundle'))
75
- FileUtils.cp_r(File.join(cache_dir, '.bundle'), File.join(work_dir, '.bundle'))
74
+ FileUtils.cp_r(File.join(cache_dir, "bundle"), File.join(work_dir, "bundle"))
75
+ FileUtils.cp_r(File.join(cache_dir, ".bundle"), File.join(work_dir, ".bundle"))
76
76
 
77
77
  puts "Restored from: #{cache_dir}"
78
78
  end
79
79
 
80
- puts 'Bundle restored from cache'
80
+ puts "Bundle restored from cache"
81
81
  end
82
82
 
83
83
  def clean
@@ -89,7 +89,7 @@ module Kompo
89
89
 
90
90
  FileUtils.rm_rf(path) if File.exist?(path)
91
91
  end
92
- puts 'Cleaned up bundle installation'
92
+ puts "Cleaned up bundle installation"
93
93
  end
94
94
  end
95
95
 
@@ -102,33 +102,33 @@ module Kompo
102
102
  bundler = InstallRuby.bundler_path
103
103
  ruby_major_minor = InstallRuby.ruby_major_minor
104
104
 
105
- @bundle_ruby_dir = File.join(work_dir, 'bundle', 'ruby', "#{ruby_major_minor}.0")
106
- @bundler_config_path = File.join(work_dir, '.bundle', 'config')
105
+ @bundle_ruby_dir = File.join(work_dir, "bundle", "ruby", "#{ruby_major_minor}.0")
106
+ @bundler_config_path = File.join(work_dir, ".bundle", "config")
107
107
 
108
- puts 'Running bundle install --path bundle...'
109
- gemfile_path = File.join(work_dir, 'Gemfile')
108
+ puts "Running bundle install --path bundle..."
109
+ gemfile_path = File.join(work_dir, "Gemfile")
110
110
 
111
111
  # Clear Bundler environment and specify Gemfile path explicitly
112
112
  Bundler.with_unbundled_env do
113
113
  ruby = InstallRuby.ruby_path
114
- env = { 'BUNDLE_GEMFILE' => gemfile_path }
114
+ env = {"BUNDLE_GEMFILE" => gemfile_path}
115
115
 
116
116
  # Suppress clang 18+ warning that causes mkmf try_cppflags to fail
117
117
  # This flag is clang-specific and not recognized by GCC
118
118
  if clang_compiler?
119
- env['CFLAGS'] = '-Wno-default-const-init-field-unsafe'
120
- env['CPPFLAGS'] = '-Wno-default-const-init-field-unsafe'
119
+ env["CFLAGS"] = "-Wno-default-const-init-field-unsafe"
120
+ env["CPPFLAGS"] = "-Wno-default-const-init-field-unsafe"
121
121
  end
122
122
 
123
123
  # Set BUNDLE_PATH to "bundle" - standard Bundler reads .bundle/config
124
124
  # and finds gems in {BUNDLE_PATH}/ruby/X.X.X/gems/
125
125
  # Use ruby to execute bundler to avoid shebang issues
126
- system({ 'BUNDLE_GEMFILE' => gemfile_path }, ruby, bundler, 'config', 'set', '--local', 'path',
127
- 'bundle') or raise 'Failed to set bundle path'
128
- system(env, ruby, bundler, 'install') or raise 'Failed to run bundle install'
126
+ system({"BUNDLE_GEMFILE" => gemfile_path}, ruby, bundler, "config", "set", "--local", "path",
127
+ "bundle") or raise "Failed to set bundle path"
128
+ system(env, ruby, bundler, "install") or raise "Failed to run bundle install"
129
129
  end
130
130
 
131
- puts 'Bundle installed successfully'
131
+ puts "Bundle installed successfully"
132
132
 
133
133
  # Save to cache
134
134
  save_to_cache(work_dir)
@@ -143,18 +143,18 @@ module Kompo
143
143
 
144
144
  FileUtils.rm_rf(path) if File.exist?(path)
145
145
  end
146
- puts 'Cleaned up bundle installation'
146
+ puts "Cleaned up bundle installation"
147
147
  end
148
148
 
149
149
  private
150
150
 
151
151
  def clang_compiler?
152
152
  output = `cc --version 2>&1`
153
- output.include?('clang')
153
+ output.include?("clang")
154
154
  rescue Errno::ENOENT => e
155
155
  warn "cc command not found: #{e.message}"
156
156
  false
157
- rescue StandardError => e
157
+ rescue => e
158
158
  warn "Error checking compiler: #{e.message}"
159
159
  false
160
160
  end
@@ -163,27 +163,27 @@ module Kompo
163
163
  bundle_cache_name = compute_bundle_cache_name
164
164
  return unless bundle_cache_name
165
165
 
166
- kompo_cache = Taski.args.fetch(:kompo_cache, File.expand_path('~/.kompo/cache'))
166
+ kompo_cache = Taski.args.fetch(:kompo_cache, File.expand_path("~/.kompo/cache"))
167
167
  ruby_version = InstallRuby.ruby_version
168
168
  version_cache_dir = File.join(kompo_cache, ruby_version)
169
169
  cache_dir = File.join(version_cache_dir, bundle_cache_name)
170
170
 
171
- group('Saving bundle to cache') do
171
+ group("Saving bundle to cache") do
172
172
  # Remove old cache if exists
173
173
  FileUtils.rm_rf(cache_dir) if Dir.exist?(cache_dir)
174
174
  FileUtils.mkdir_p(cache_dir)
175
175
 
176
176
  # Copy to cache
177
- FileUtils.cp_r(File.join(work_dir, 'bundle'), File.join(cache_dir, 'bundle'))
178
- FileUtils.cp_r(File.join(work_dir, '.bundle'), File.join(cache_dir, '.bundle'))
177
+ FileUtils.cp_r(File.join(work_dir, "bundle"), File.join(cache_dir, "bundle"))
178
+ FileUtils.cp_r(File.join(work_dir, ".bundle"), File.join(cache_dir, ".bundle"))
179
179
 
180
180
  # Save metadata
181
181
  metadata = {
182
- 'ruby_version' => ruby_version,
183
- 'gemfile_lock_hash' => compute_gemfile_lock_hash,
184
- 'created_at' => Time.now.iso8601
182
+ "ruby_version" => ruby_version,
183
+ "gemfile_lock_hash" => compute_gemfile_lock_hash,
184
+ "created_at" => Time.now.iso8601
185
185
  }
186
- File.write(File.join(cache_dir, 'metadata.json'), JSON.pretty_generate(metadata))
186
+ File.write(File.join(cache_dir, "metadata.json"), JSON.pretty_generate(metadata))
187
187
 
188
188
  puts "Saved to: #{cache_dir}"
189
189
  end
@@ -193,7 +193,7 @@ module Kompo
193
193
  # Skip bundle install when no Gemfile
194
194
  class Skip < Taski::Task
195
195
  def run
196
- puts 'No Gemfile, skipping bundle install'
196
+ puts "No Gemfile, skipping bundle install"
197
197
  @bundle_ruby_dir = nil
198
198
  @bundler_config_path = nil
199
199
  end
@@ -209,14 +209,14 @@ module Kompo
209
209
  bundle_cache_name = compute_bundle_cache_name
210
210
  return false unless bundle_cache_name
211
211
 
212
- kompo_cache = Taski.args.fetch(:kompo_cache, File.expand_path('~/.kompo/cache'))
212
+ kompo_cache = Taski.args.fetch(:kompo_cache, File.expand_path("~/.kompo/cache"))
213
213
  ruby_version = InstallRuby.ruby_version
214
214
  version_cache_dir = File.join(kompo_cache, ruby_version)
215
215
  cache_dir = File.join(version_cache_dir, bundle_cache_name)
216
216
 
217
- cache_bundle_dir = File.join(cache_dir, 'bundle')
218
- cache_bundle_config = File.join(cache_dir, '.bundle')
219
- cache_metadata = File.join(cache_dir, 'metadata.json')
217
+ cache_bundle_dir = File.join(cache_dir, "bundle")
218
+ cache_bundle_config = File.join(cache_dir, ".bundle")
219
+ cache_metadata = File.join(cache_dir, "metadata.json")
220
220
 
221
221
  Dir.exist?(cache_bundle_dir) && Dir.exist?(cache_bundle_config) && File.exist?(cache_metadata)
222
222
  end