Class: RubyCms::Installer

Inherits:
Object
  • Object
show all
Defined in:
lib/ruby_cms/installer.rb

Overview

Composes the gem/file/routes/nav/migration installers, runs the Rails shell steps, and records the installed modules in the lockfile.

Defined Under Namespace

Classes: Error

Constant Summary collapse

BASE_FRAMEWORK_STEPS =

Framework generators the admin templates depend on (run once, on a fresh install).

[
  "bin/rails generate ruby_ui:install",
  "bin/rails tailwindcss:install",
  "bin/rails action_text:install",
  "bin/rails noticed:install:migrations"
].freeze
AHOY_STEP =
"bin/rails generate ahoy:install"

Instance Method Summary collapse

Constructor Details

#initialize(manifest:, templates_root:, app_root:, shell:, version:) ⇒ Installer

Returns a new instance of Installer.



33
34
35
36
37
38
39
# File 'lib/ruby_cms/installer.rb', line 33

def initialize(manifest:, templates_root:, app_root:, shell:, version:)
  @manifest = manifest
  @templates_root = templates_root
  @app_root = app_root
  @shell = shell
  @version = version
end

Instance Method Details

#add(new_keys:) ⇒ Object

Layer additional modules onto an existing install. Routes/nav are regenerated for the full union; gem + framework scaffolding are NOT re-run.



91
92
93
94
95
96
97
98
99
100
101
# File 'lib/ruby_cms/installer.rb', line 91

def add(new_keys:)
  lock = Lockfile.new(@app_root)
  added_keys = Array(new_keys).map(&:to_sym)
  prior = lock.modules
  union = (prior + added_keys).uniq
  install(selected: union - @manifest.base_modules.map(&:key), framework_setup: false)
  return unless added_keys.include?(:analytics) && !prior.include?(:analytics)

  @shell.run(AHOY_STEP)
  run_critical("bin/rails db:migrate")
end

#install(selected:, framework_setup: true) ⇒ Object

selected: array of optional module keys chosen by the user. framework_setup: run gem + framework scaffolding (true for a fresh install).



43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
# File 'lib/ruby_cms/installer.rb', line 43

def install(selected:, framework_setup: true)
  modules = @manifest.resolve(selected)

  # Gems first: base + module gems on a fresh install; on `--add`, only the newly
  # selected modules' own gems (so e.g. adding passkeys pulls in webauthn).
  gem_setup = GemSetup.new(app_root: @app_root)
  added = gem_setup.ensure_gems!(modules: modules, include_base: framework_setup)
  conflicts_patched = gem_setup.resolve_conflicts!(modules: modules)
  if conflicts_patched
    @shell.ok("bitwarden-sdk-secrets", hint: "set require: false (conflicts with webauthn passkeys)")
  end
  run_critical("bundle install") if added.any? || conflicts_patched

  # Framework scaffolding runs on the still-vanilla app, fresh install only, so the
  # Rails generators don't collide with (and interactively prompt about) gem files.
  if framework_setup
    run_auth_setup
    run_framework_steps(modules)
  end

  # Copy each module's files (overwriting any generator output), one line per module.
  file_installer = FileInstaller.new(templates_root: @templates_root, app_root: @app_root)
  @shell.heading("Installing modules:")
  modules.each do |mod|
    file_installer.install([mod])
    @shell.ok(mod.key.to_s, hint: mod.description)
  end

  AppWiring.new(app_root: @app_root).apply!
  HelperWiring.new(app_root: @app_root).apply!
  ImportmapWiring.new(app_root: @app_root).apply!
  PasskeyWiring.new(app_root: @app_root).apply! if modules.any? {|m| m.key == :passkeys }
  RoutesAssembler.new(templates_root: @templates_root, app_root: @app_root).inject(modules)
  NavAssembler.new(templates_root: @templates_root, app_root: @app_root).write(modules)

  # Migrations last so they are re-stamped to run after the ahoy/action_text tables
  # the framework generators created.
  MigrationInstaller.new(templates_root: @templates_root, app_root: @app_root).install(modules)
  run_rails_steps
  # Rebuild Tailwind AFTER admin views/components exist so their utility classes are
  # compiled — on fresh install AND on `--add` (a new module brings new view classes).
  @shell.run("bin/rails tailwindcss:build")
  Lockfile.new(@app_root).write!(modules: modules.map(&:key), version: @version)
  modules
end