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



243
244
245
246
247
248
249
250
251
252
253
# File 'lib/rys/bundler/hooks.rb', line 243

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
119
120
121
122
# File 'lib/rys/bundler/hooks.rb', line 83

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

  # To avoid multiple `git clone` on the same folder
  ::Bundler::ProcessLock.lock do
    resolve_rys_dependencies(dependencies, new_dependencies, resolved_dependencies)
  end

  # 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



193
194
195
# File 'lib/rys/bundler/hooks.rb', line 193

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

.merge_definition_sources(from_definition, to_definition) ⇒ Object



232
233
234
235
236
237
238
239
240
241
# File 'lib/rys/bundler/hooks.rb', line 232

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



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
227
228
229
230
# File 'lib/rys/bundler/hooks.rb', line 197

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



124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
# File 'lib/rys/bundler/hooks.rb', line 124

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



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
188
189
190
191
# File 'lib/rys/bundler/hooks.rb', line 148

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



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
289
290
291
292
# File 'lib/rys/bundler/hooks.rb', line 255

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