Class: Bridgetown::PluginManager

Inherits:
Object
  • Object
show all
Defined in:
bridgetown-core/lib/bridgetown-core/plugin_manager.rb

Constant Summary collapse

NPM_DEPENDENCY_REGEXP =
%r!(.+)@([^@]*)$!

Class Attribute Summary collapse

Instance Attribute Summary collapse

Class Method Summary collapse

Instance Method Summary collapse

Constructor Details

#initialize(site) ⇒ PluginManager

Provides a plugin manager for the site

Parameters:

[View source]

167
168
169
# File 'bridgetown-core/lib/bridgetown-core/plugin_manager.rb', line 167

def initialize(site)
  @site = site
end

Class Attribute Details

.registered_pluginsObject (readonly)

Returns the value of attribute registered_plugins.


16
17
18
# File 'bridgetown-core/lib/bridgetown-core/plugin_manager.rb', line 16

def registered_plugins
  @registered_plugins
end

Instance Attribute Details

#loaders_managerObject (readonly)

Returns the value of attribute loaders_manager.


7
8
9
# File 'bridgetown-core/lib/bridgetown-core/plugin_manager.rb', line 7

def loaders_manager
  @loaders_manager
end

#siteObject (readonly)

Returns the value of attribute site.


7
8
9
# File 'bridgetown-core/lib/bridgetown-core/plugin_manager.rb', line 7

def site
  @site
end

Class Method Details

.add_npm_dependency?(npm_dependency, package_json) ⇒ Boolean

rubocop:enable Metrics/PerceivedComplexity, Metrics/CyclomaticComplexity

Returns:

  • (Boolean)
[View source]

147
148
149
150
151
152
153
154
155
156
157
158
# File 'bridgetown-core/lib/bridgetown-core/plugin_manager.rb', line 147

def self.add_npm_dependency?(npm_dependency, package_json)
  return false if npm_dependency.nil?

  # check matching version number is see if it's already installed
  if package_json["dependencies"]
    current_version = package_json["dependencies"][npm_dependency.first]
    current_version = current_version.delete_prefix("^") if current_version
    package_requires_updating?(current_version, npm_dependency.last)
  else
    true
  end
end

.add_registered_plugin(gem_or_plugin_file) ⇒ Object

[View source]

11
12
13
# File 'bridgetown-core/lib/bridgetown-core/plugin_manager.rb', line 11

def self.add_registered_plugin(gem_or_plugin_file)
  @registered_plugins << gem_or_plugin_file
end

.bundler_specsObject

[View source]

18
19
20
# File 'bridgetown-core/lib/bridgetown-core/plugin_manager.rb', line 18

def bundler_specs
  @bundler_specs ||= Bundler.load.requested_specs
end

.find_npm_dependency(loaded_gem) ⇒ Object

[View source]

136
137
138
139
140
141
142
143
# File 'bridgetown-core/lib/bridgetown-core/plugin_manager.rb', line 136

def self.find_npm_dependency(loaded_gem)
   = loaded_gem.to_spec&.&.dig("npm-add") ||
    loaded_gem.to_spec&.&.dig("yarn-add")
  npm_dependency = &.match(NPM_DEPENDENCY_REGEXP)
  return nil if npm_dependency&.length != 3 || npm_dependency[2] == ""

  npm_dependency[1..2]
end

.install_npm_dependencies(required_gems = bundler_specs, name: nil) ⇒ Bundler::SpecSet

Iterates through loaded gems and finds npm-add gemspec metadata. If that exact package hasn’t been installed, execute npm i

Returns:

  • (Bundler::SpecSet)
[View source]

109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
# File 'bridgetown-core/lib/bridgetown-core/plugin_manager.rb', line 109

def self.install_npm_dependencies(required_gems = bundler_specs, name: nil)
  return required_gems unless File.exist?("package.json")

  package_json = JSON.parse(File.read("package.json"))

  gems_to_search = if name
                     required_gems.select do |loaded_gem|
                       loaded_gem.to_spec&.name == name.to_s
                     end
                   else
                     required_gems
                   end

  # all right, time to install the package
  gems_to_search.each do |loaded_gem|
    npm_dependency = find_npm_dependency(loaded_gem)
    next unless add_npm_dependency?(npm_dependency, package_json)

    next if package_manager.empty?

    cmd = "#{package_manager} #{package_manager_install_command} #{npm_dependency.join("@")}"
    system cmd
  end

  gems_to_search
end

.load_determined_bundler_environmentObject

[View source]

42
43
44
45
46
47
48
49
50
51
52
53
54
# File 'bridgetown-core/lib/bridgetown-core/plugin_manager.rb', line 42

def self.load_determined_bundler_environment
  boot_file = File.join("config", "boot.rb")

  if File.file?(boot_file)
    # We'll let config/boot.rb take care of Bundler setup
    require File.expand_path(boot_file)
  elsif File.file?(File.join("config", "initializers.rb"))
    # We'll just make sure the default and environmental gems are available.
    # Note: the default Bundler config will set up all gem groups,
    #   see: https://bundler.io/guides/groups.html
    Bundler.setup(:default, Bridgetown.env)
  end
end

.package_managerObject

[View source]

83
84
85
86
87
88
89
90
91
92
93
# File 'bridgetown-core/lib/bridgetown-core/plugin_manager.rb', line 83

def self.package_manager
  @package_manager ||= if File.exist?("yarn.lock")
                         "yarn"
                       elsif File.exist?("pnpm-lock.yaml")
                         "pnpm"
                       elsif File.exist?("package.json")
                         "npm"
                       else
                         ""
                       end
end

.package_manager_install_commandObject

[View source]

95
96
97
# File 'bridgetown-core/lib/bridgetown-core/plugin_manager.rb', line 95

def self.package_manager_install_command
  package_manager == "npm" ? "install" : "add"
end

.package_manager_uninstall_commandObject

[View source]

99
100
101
# File 'bridgetown-core/lib/bridgetown-core/plugin_manager.rb', line 99

def self.package_manager_uninstall_command
  package_manager == "npm" ? "uninstall" : "remove"
end

.package_requires_updating?(current_version, dep_version) ⇒ Boolean

Returns:

  • (Boolean)
[View source]

160
161
162
# File 'bridgetown-core/lib/bridgetown-core/plugin_manager.rb', line 160

def self.package_requires_updating?(current_version, dep_version)
  current_version.nil? || (current_version != dep_version && !current_version.include?("/"))
end

.require_gem(name) ⇒ Object

[View source]

66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
# File 'bridgetown-core/lib/bridgetown-core/plugin_manager.rb', line 66

def self.require_gem(name)
  Bridgetown::Utils::RequireGems.require_with_graceful_fail(name)
  plugins = Bridgetown::PluginManager.install_npm_dependencies(name:)

  plugin_to_register = if plugins.length == 1
                         plugins.first
                       else
                         bundler_specs.find do |loaded_gem|
                           loaded_gem.to_spec&.name == name.to_s
                         end
                       end
  add_registered_plugin plugin_to_register

  Bridgetown.logger.debug("PluginManager:",
                          "Registered #{plugin_to_register.name}")
end

.require_plugin_featuresObject

[View source]

56
57
58
59
60
61
62
63
64
# File 'bridgetown-core/lib/bridgetown-core/plugin_manager.rb', line 56

def self.require_plugin_features
  bundler_specs.select do |loaded_gem|
    loaded_gem.to_spec.["bridgetown_features"] == "true"
  end.each do |plugin_gem|
    Bridgetown::Utils::RequireGems.require_with_graceful_fail(
      "bridgetown/features/#{plugin_gem.name}"
    )
  end
end

.setup_bundlerObject Also known as: require_from_bundler

[View source]

23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
# File 'bridgetown-core/lib/bridgetown-core/plugin_manager.rb', line 23

def self.setup_bundler
  if !ENV["BRIDGETOWN_NO_BUNDLER_REQUIRE"] &&
      (Bundler::SharedHelpers.in_bundle? || Bridgetown.env.test?)
    require "bundler"

    require_relative "utils/initializers"
    load_determined_bundler_environment
    require_plugin_features

    ENV["BRIDGETOWN_NO_BUNDLER_REQUIRE"] = "true"
    true
  else
    false
  end
end

Instance Method Details

#plugins_pathArray<String>

Expands the path(s) of the plugins_dir config value

Returns:

  • (Array<String>)

    one or more plugin search paths

[View source]

195
196
197
198
199
200
201
# File 'bridgetown-core/lib/bridgetown-core/plugin_manager.rb', line 195

def plugins_path
  if site.config["plugins_dir"].eql? Bridgetown::Configuration::DEFAULTS["plugins_dir"]
    [site.in_root_dir(site.config["plugins_dir"])]
  else
    Array(site.config["plugins_dir"]).map { |d| File.expand_path(d) }
  end
end

#require_plugin_filesvoid

This method returns an undefined value.

Finds and registers plugins in the local folder(s)

[View source]

174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
# File 'bridgetown-core/lib/bridgetown-core/plugin_manager.rb', line 174

def require_plugin_files
  plugins_path.each do |plugin_search_path|
    plugin_files = Utils.safe_glob(plugin_search_path, File.join("**", "*.rb"))

    # Require "site_builder.rb" first if present so subclasses can all
    # inherit from SiteBuilder without needing explicit require statements
    sorted_plugin_files = plugin_files.select do |path|
      path.include?("site_builder.rb")
    end + plugin_files.reject do |path|
      path.include?("site_builder.rb")
    end

    sorted_plugin_files.each do |plugin_file|
      self.class.add_registered_plugin plugin_file
    end
  end
end