Module: Bundler::Spinel::Scaffold

Defined in:
lib/bundler/spinel/engine_installer.rb

Overview

Scaffolds a minimal Spinel project so onboarding is ‘bundle install && spinel-compat init && bin/build` (spinelgems#9, stretch). Writes a Gemfile with the engine marker + a framework gem, a hello entrypoint, and a bin/build that provisions the engine, vendors deps, and compiles.

Class Method Summary collapse

Class Method Details

.app_rbObject



212
213
214
215
216
217
218
219
220
# File 'lib/bundler/spinel/engine_installer.rb', line 212

def app_rb
  <<~RUBY
    require "tep"

    get "/" do
      "hello from a Spinel-compiled Tep app\\n"
    end
  RUBY
end

.build_shObject



222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
# File 'lib/bundler/spinel/engine_installer.rb', line 222

def build_sh
  <<~SH
    #!/usr/bin/env bash
    # From a fresh checkout to a native binary. The Gemfile's `engine: spinel`
    # marker makes `bundle install` refuse to run under CRuby, so we resolve
    # with `bundle lock` and place deps with `spinel-compat vendor` instead.
    set -e
    command -v tep >/dev/null 2>&1 || gem install tep   # the tep build CLI (a compile-time tool)
    [ -f Gemfile.lock ] || bundle lock                  # resolve deps (NOT `bundle install`)
    spinel-compat install-engine                        # fetch+build the pinned engine (cached)
    export SPINEL="${SPINEL:-$HOME/.cache/spinel/current/spinel}"  # tell tep where the engine is
    spinel-compat vendor                                # place deps where Spinel follows them
    tep build app.rb -o app                             # compile -> ./app
    echo "built ./app — run it with: ./app -p 4567"
  SH
end

.gemfileObject



195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
# File 'lib/bundler/spinel/engine_installer.rb', line 195

def gemfile
  <<~RUBY
    source "https://rubygems.org"

    # Spinel is the engine: code here is compiled ahead-of-time to a native
    # binary, not run on CRuby. `engine_version` is advisory and must be a
    # version literal (bundler parses it as a Gem requirement); the actual
    # engine revision install-engine builds is pinned in ./SPINEL_PIN.
    ruby "3.3.0", engine: "spinel", engine_version: "0.0.0"

    # The web framework — Sinatra-style, compiles via Spinel. >= 0.11.1 builds
    # its C helpers on demand (needed for `gem install tep` without `make`).
    # (For an unreleased sibling instead: gem "tep", git: "https://github.com/OriPekelman/tep.git")
    gem "tep", ">= 0.11.1"
  RUBY
end

.gitignoreObject



239
240
241
242
243
244
245
246
# File 'lib/bundler/spinel/engine_installer.rb', line 239

def gitignore
  <<~TXT
    /app
    /vendor
    *.o
    *.bin
  TXT
end

.init(dir, out: $stdout, rev: nil) ⇒ Object



160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
# File 'lib/bundler/spinel/engine_installer.rb', line 160

def init(dir, out: $stdout, rev: nil)
  FileUtils.mkdir_p(dir)
  engine_rev = rev || EngineInstaller::DEFAULT_REV
  write(out, File.join(dir, "Gemfile"), gemfile)
  # The engine revision is a git SHA — NOT a valid `engine_version:` (bundler
  # parses that as a Gem version requirement and `bundle lock` errors on a
  # SHA). So the rev lives in a SPINEL_PIN file, which `install-engine`
  # reads; the Gemfile keeps a version-literal advisory marker.
  write(out, File.join(dir, "SPINEL_PIN"), "#{engine_rev}\n")
  write(out, File.join(dir, "app.rb"), app_rb)
  bin = File.join(dir, "bin", "build")
  FileUtils.mkdir_p(File.dirname(bin))
  write(out, bin, build_sh)
  File.chmod(0o755, bin)
  write(out, File.join(dir, ".gitignore"), gitignore)
  out.puts ""
  out.puts "Scaffolded a Spinel + Tep project in #{dir}/"
  out.puts "Next:"
  out.puts "  cd #{dir}" unless File.expand_path(dir) == Dir.pwd
  out.puts "  ./bin/build           # ensures tep, resolves + vendors deps, provisions Spinel, compiles"
  out.puts "  ./app -p 4567         # run the native binary"
  out.puts ""
  out.puts "(The `engine: spinel` Gemfile marker makes `bundle install` refuse to run"
  out.puts " under CRuby by design — bin/build uses `bundle lock` + `spinel-compat vendor`.)"
end

.write(out, path, body) ⇒ Object



186
187
188
189
190
191
192
193
# File 'lib/bundler/spinel/engine_installer.rb', line 186

def write(out, path, body)
  if File.exist?(path)
    out.puts "  skip (exists): #{path}"
  else
    File.write(path, body)
    out.puts "  create: #{path}"
  end
end