Module: Rys::Bundler::Hooks

Defined in:
lib/rys/bundler/hooks.rb

Class Method Summary collapse

Class Method Details

.add_source_definition(dependency, to_definition) ⇒ Object



239
240
241
242
243
244
245
246
247
248
249
# File 'lib/rys/bundler/hooks.rb', line 239

def self.add_source_definition(dependency, to_definition)
  sources = to_definition.send(:sources).send(:source_list_for, dependency.source)

  if sources.include?(dependency.source)
    # Already there
  else
    sources << dependency.source
  end
rescue
  # Bundler could raise an ArgumentError
end

.before_install_all(dependencies) ⇒ Object

Be careful!!! There is a lot of possibilities for gem definition

1. Normal gem
2. Gem on git (download)
3. Gem on git (not-downloaded)
4. Gem on git locally overriden
5. Gem on local disk


83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
# File 'lib/rys/bundler/hooks.rb', line 83

def self.before_install_all(dependencies)
  new_dependencies = []
  resolved_dependencies = []
  resolve_rys_dependencies(dependencies, new_dependencies, resolved_dependencies)

  # Select only missing dependencies so user can
  # rewrite each dependecny in main gems.rb
  new_dependencies = new_dependencies.uniq(&:name)
  new_dependencies.reject! do |dep1|
    dependencies.any? do |dep2|
      dep1.name == dep2.name && !dep2.groups.include?(:__dependencies__)
    end
  end

  # Adding sources from new dependecies
  # Needef for Path or Git
  new_dependencies.each do |dependency|
    next if !dependency.source
    sources = ::Bundler.definition.send(:sources).send(:source_list_for, dependency.source)
    sources << dependency.source
  end

  ::Bundler.ui.info "Added #{new_dependencies.size} new dependencies"

  # Concat them to main Bundler.definition.dependencies
  dependencies.concat(new_dependencies)

  # Save them for Bundler.require (rails config/boot.rb)
  save_new_dependencies(new_dependencies)

  # To ensure main bundler download plugins
  ::Bundler.definition.instance_eval do
    @dependency_changes = true
    # @local_changes = converge_locals
  end
end

.gems_dependencies_rbObject



189
190
191
# File 'lib/rys/bundler/hooks.rb', line 189

def self.gems_dependencies_rb
  ::Bundler.root.join('gems.dependencies.rb')
end

.merge_definition_sources(from_definition, to_definition) ⇒ Object



228
229
230
231
232
233
234
235
236
237
# File 'lib/rys/bundler/hooks.rb', line 228

def self.merge_definition_sources(from_definition, to_definition)
  to_sources = to_definition.send(:sources)

  from_definition.send(:sources).all_sources.map do |source|
    begin
      to_sources.send(:source_list_for, source) << source
    rescue
    end
  end
end

.prepare_dependencies_for_next_round(dependencies, resolved_dependencies) ⇒ Object



193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
# File 'lib/rys/bundler/hooks.rb', line 193

def self.prepare_dependencies_for_next_round(dependencies, resolved_dependencies)
  dependencies = dependencies.dup

  # Prepare dependencies
  dependencies.keep_if do |dependency|
    dependency.groups.include?(:rys) &&
    dependency.source &&
    resolved_dependencies.none?{|rd| rd.name == dependency.name }
  end

  # Sort them to prior local dependencies
  dependencies.sort_by! do |dependency|
    case dependency.source
    # Git should be first because its inherit from Path
    when ::Bundler::Source::Git
      if dependency.source.send(:local?)
        1
      else
        3
      end
    # Local path
    when ::Bundler::Source::Path
      0
    # Rubygems, gemspec, metadata
    else
      2
    end
  end

  # More dependencies can depend on the same dependencies :-)
  dependencies.uniq!(&:name)

  return dependencies
end

.resolve_rys_dependencies(dependencies, new_dependencies, resolved_dependencies) ⇒ Object

Recursively searches for dependencies If there will be same dependencies => first won

Arguments:

dependencies

Array of dependencies which should be resolved

new_dependencies

All dependencies from resolving Array is in-place modified

resolved_dependencies

Already resolved dependencies

For preventing loops


41
42
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
# File 'lib/rys/bundler/hooks.rb', line 41

def self.resolve_rys_dependencies(dependencies, new_dependencies, resolved_dependencies)
  dependencies = prepare_dependencies_for_next_round(dependencies, resolved_dependencies)

  # Resolving is done in next round
  next_dependencies_to_resolve = []

  dependencies.each do |dependency|
    # To allow resolving
    dependency.source.remote!

    # Ensure gem (downloaded if necessary)
    dependency.source.specs

    # Get dependencies from this file using rys group
    dependencies_rb = dependency.source.path.join('dependencies.rb')

    if dependencies_rb.exist?
      definition = ::Bundler::Dsl.evaluate(dependencies_rb, ::Bundler.default_lockfile, true)
      rys_group_dependencies = definition.dependencies.select{|dep| dep.groups.include?(:rys) }

      new_dependencies.concat(rys_group_dependencies)
      next_dependencies_to_resolve.concat(rys_group_dependencies)
    end

    resolved_dependencies << dependency
    # add_source_definition(dependency, ::Bundler.definition)
  end

  if next_dependencies_to_resolve.size > 0
    resolve_rys_dependencies(next_dependencies_to_resolve, new_dependencies, resolved_dependencies)
  end
end

.rys_gemfile(dsl) ⇒ Object



120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
# File 'lib/rys/bundler/hooks.rb', line 120

def self.rys_gemfile(dsl)
  # Loading dependencies brings some troubles. For example if main
  # app add a gem which already exist as dependencies. There could
  # be conflicts. To avoid some of problems - dependencies are
  # loaded only if there is not a lock file (bundler wasn't
  # launched or user want force install).
  return if !::Bundler.root.join('gems.locked').exist? && !::Bundler.root.join('Gemfile.lock').exist?

  if gems_dependencies_rb.exist?
    # Mark gems as dependencies to be rewritten in a hook
    # Because you dont know if:
    #   - gems are loaded for rails
    #   - running bundle install
    #   - bundle exec
    #   - or something else
    dsl.group(:__dependencies__) do
      dsl.eval_gemfile(gems_dependencies_rb)
    end
  end
end

.rys_load_dummy(dsl, dummy_path = nil) ⇒ Object

Load gems from dummy path Conflicts are ingnored



144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
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
185
186
187
# File 'lib/rys/bundler/hooks.rb', line 144

def self.rys_load_dummy(dsl, dummy_path=nil)
  possible_app_dirs = [
    dummy_path,
    ENV['DUMMY_PATH'],
    ::Bundler.root.join('test/dummy')
  ]

  possible_app_dirs.each do |dir|
    next if !dir
    next if !File.directory?(dir)

    ['Gemfile', 'gems.rb'].each do |gems_rb|
      gems_rb = File.expand_path(File.join(dir, gems_rb))

      if File.exist?(gems_rb)
        dsl.instance_eval do

          # Patch method `gem` to avoid duplicit definition
          # For example you can test rys 'ondra' but its
          # already included in main app gemfile.
          if is_a?(::Bundler::Plugin::DSL)
            # gem methods is not defined here
          else
            singleton_class.class_eval do
              alias_method :original_gem, :gem
            end

            def gem(name, *args)
              if @dependencies.any? {|d| d.name == name }
                ::Bundler.ui.info "Skipping gem '#{name}' because already exist"
              else
                original_gem(name, *args)
              end
            end
          end

          eval_gemfile(gems_rb)
        end

        return
      end
    end
  end
end

.save_new_dependencies(dependencies) ⇒ Object



251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
# File 'lib/rys/bundler/hooks.rb', line 251

def self.save_new_dependencies(dependencies)
  File.open(gems_dependencies_rb, 'w') do |f|
    f.puts %{# This file was generated by Rys::Bundler at #{Time.now}}
    f.puts %{# Dependencies are generated after every `bundle` command}
    f.puts %{# Modify file at your own risk}
    f.puts

    dependencies.each do |dep|
      options = {}

      source = dep.source
      case source
      when ::Bundler::Source::Git
        options[:git] = source.uri
        options[:branch] = source.branch
        options[:ref] = source.ref
      when NilClass
        # Regular gem
      else
        raise "Unknow source '#{source.class}'"
      end

      args = []
      args << dep.name
      args.concat(dep.requirement.as_list)

      options[:groups] = dep.groups
      options[:require] = dep.autorequire if dep.autorequire

      gem_args = args.map{|arg| '"' + arg + '"' }.join(', ')

      f.puts %{if dependencies.none?{|dep| dep.name.to_s == "#{dep.name}" }}
      f.puts %{  gem #{gem_args}, #{options}}
      f.puts %{end}
      f.puts
    end
  end
end