Module: Bundler::Overrule

Defined in:
lib/bundler/overrule.rb,
lib/bundler/overrule/dsl.rb,
lib/bundler/overrule/rule.rb,
lib/bundler/overrule/errors.rb,
lib/bundler/overrule/command.rb,
lib/bundler/overrule/patcher.rb,
lib/bundler/overrule/version.rb,
lib/bundler/overrule/registry.rb,
lib/bundler/overrule/reporter.rb,
lib/bundler/overrule/dependency_rewriter.rb

Overview

Force, ban, and swap gem versions from your Gemfile.

Nothing here patches Bundler until the first rule is declared: with no rules, resolution is byte-identical to vanilla Bundler (G4).

Defined Under Namespace

Modules: DependencyRewriter, Dsl, Patcher Classes: Ban, BannedDirectDependencyError, Command, DuplicateRuleError, Edge, Error, Force, InvalidRuleError, Registry, Reporter, Rule, Swap, UnsupportedBundlerError

Constant Summary collapse

SUPPORTED_BUNDLER =

Verified against 2.6.x, 2.7.x and 4.0.x. The upper bound is deliberately loose — Patcher also structurally verifies every patch target, which is a better guard than a version number, and refuses to run if one is missing.

An Array, not a comma-joined String: Gem::Requirement.create(">= 2.6, < 5") raises BadRequirementError.

[">= 2.6", "< 5"].freeze
SUPPORTED_BUNDLER_DESCRIPTION =
SUPPORTED_BUNDLER.join(", ").freeze
VERSION =
"0.3.0"

Class Method Summary collapse

Class Method Details

.active?Boolean

Returns:

  • (Boolean)


131
132
133
# File 'lib/bundler/overrule.rb', line 131

def active?
  registry.any?
end

.ban(name, reason: nil) ⇒ Object



54
55
56
# File 'lib/bundler/overrule.rb', line 54

def ban(name, reason: nil)
  register(Ban.new(name, reason: reason))
end

.definition_built?Boolean

Returns:

  • (Boolean)


114
115
116
# File 'lib/bundler/overrule.rb', line 114

def definition_built?
  @definition_built ||= false
end

.finalize!Object

Print the summary and persist the state file. Idempotent — it is reachable from both the plugin hook and the at_exit fallback.



120
121
122
123
124
125
126
127
128
129
# File 'lib/bundler/overrule.rb', line 120

def finalize!
  return if @finalized || registry.empty? || !definition_built?

  @finalized = true
  reporter.print_summary unless suppress_summary?
  reporter.write_state!
rescue StandardError => e
  # Reporting must never be the thing that breaks an install.
  ::Bundler.ui.warn("[bundler-overrule] could not write report: #{e.message}")
end

.force(name, requirement, reason: nil) ⇒ Object



50
51
52
# File 'lib/bundler/overrule.rb', line 50

def force(name, requirement, reason: nil)
  register(Force.new(name, requirement, reason: reason))
end

.note_definition_built!Object



100
101
102
# File 'lib/bundler/overrule.rb', line 100

def note_definition_built!
  @definition_built = true
end

.plugin_prepass?(dsl) ⇒ Boolean

True while Bundler is doing its pre-pass over the Gemfile looking for plugin lines (Bundler::Plugin.gemfile_install). Nothing is resolved in that pass.

Returns:

  • (Boolean)


96
97
98
# File 'lib/bundler/overrule.rb', line 96

def plugin_prepass?(dsl)
  defined?(::Bundler::Plugin::DSL) && dsl.is_a?(::Bundler::Plugin::DSL)
end

.register(rule) ⇒ Object



62
63
64
65
66
# File 'lib/bundler/overrule.rb', line 62

def register(rule)
  rule = registry.add(rule)
  Patcher.apply!
  rule
end

.registryObject



30
31
32
# File 'lib/bundler/overrule.rb', line 30

def registry
  @registry ||= Registry.new
end

.reporterObject



34
35
36
# File 'lib/bundler/overrule.rb', line 34

def reporter
  @reporter ||= Reporter.new(registry)
end

.reset!Object

Test hook.



39
40
41
42
43
44
45
46
47
48
# File 'lib/bundler/overrule.rb', line 39

def reset!
  @registry = nil
  @reporter = nil
  @rules_changed = nil
  @finalized = false
  @definition_built = false
  @suppress_summary = false
  Patcher.reset!
  self
end

.rewrite_gemfile_dependencies!(dependencies) ⇒ Object

Called from the Dsl#to_definition seam with the Gemfile's own dependency array, which we mutate in place.

force has to beat a Gemfile pin (B2) and swap has to substitute a directly declared gem (B13), so both run over the Gemfile's own list through the same rewriter every other edge uses. ban is the exception: banning a gem you directly require is a user error, not something to silently honour (B6).



76
77
78
79
80
81
# File 'lib/bundler/overrule.rb', line 76

def rewrite_gemfile_dependencies!(dependencies)
  return dependencies if registry.empty? || dependencies.nil?

  reject_banned_direct_dependencies!(dependencies)
  dependencies.replace(registry.filter(dependencies, owner: "Gemfile"))
end

.rules_changed?Boolean

Has the rule set changed since the lockfile was last written? Used to defeat Bundler's "lockfile looks current, skip resolution" fast path.

Returns:

  • (Boolean)


85
86
87
88
89
90
91
# File 'lib/bundler/overrule.rb', line 85

def rules_changed?
  return false if registry.empty?
  return @rules_changed unless @rules_changed.nil?

  state = reporter.read_state
  @rules_changed = state.nil? || state["fingerprint"] != registry.fingerprint
end

.suppress_summary!Object

bundle overrule list prints its own report; the install-time "YOU own the consequences" banner on top of it would just be noise.



106
107
108
# File 'lib/bundler/overrule.rb', line 106

def suppress_summary!
  @suppress_summary = true
end

.suppress_summary?Boolean

Returns:

  • (Boolean)


110
111
112
# File 'lib/bundler/overrule.rb', line 110

def suppress_summary?
  @suppress_summary ||= false
end

.swap(name, with:, version: nil, reason: nil) ⇒ Object



58
59
60
# File 'lib/bundler/overrule.rb', line 58

def swap(name, with:, version: nil, reason: nil)
  register(Swap.new(name, with, version: version, reason: reason))
end