require'erb'require'rubygems/dependency_installer'moduleBundlerclassInstaller<Environmentclass<<selfattr_accessor:post_install_messagesend# Begins the installation process for Bundler.# For more information see the #run method on this class.defself.install(root,definition,options={})installer=new(root,definition)installer.run(options)installerend# Runs the install procedures for a specific Gemfile.## Firstly, this method will check to see if Bundler.bundle_path exists # and if not then will create it. This is usually the location of gems# on the system, be it RVM or at a system path.# # Secondly, it checks if Bundler has been configured to be "frozen"# Frozen ensures that the Gemfile and the Gemfile.lock file are matching.# This stops a situation where a developer may update the Gemfile but may not run# `bundle install`, which leads to the Gemfile.lock file not being correctly updated.# If this file is not correctly updated then any other developer running# `bundle install` will potentially not install the correct gems.## Thirdly, Bundler checks if there are any dependencies specified in the Gemfile using # Bundler::Environment#dependencies. If there are no dependencies specified then# Bundler returns a warning message stating so and this method returns.## Fourthly, Bundler checks if the default lockfile (Gemfile.lock) exists, and if so# then proceeds to set up a defintion based on the default gemfile (Gemfile) and the# default lock file (Gemfile.lock). However, this is not the case if the platform is different# to that which is specified in Gemfile.lock, or if there are any missing specs for the gems.## Fifthly, Bundler resolves the dependencies either through a cache of gems or by remote.# This then leads into the gems being installed, along with stubs for their executables,# but only if the --binstubs option has been passed or Bundler.options[:bin] has been set# earlier. # # Sixthly, a new Gemfile.lock is created from the installed gems to ensure that the next time# that a user runs `bundle install` they will receive any updates from this process.# # Finally: TODO add documentation for how the standalone process works.defrun(options)# Create the BUNDLE_PATH directorybeginBundler.bundle_path.mkpathunlessBundler.bundle_path.exist?rescueErrno::EEXISTraisePathError,"Could not install to path `#{Bundler.settings[:path]}` "+"because of an invalid symlink. Remove the symlink so the directory can be created."endifBundler.settings[:frozen]@definition.ensure_equivalent_gemfile_and_lockfile(options[:deployment])endifdependencies.empty?Bundler.ui.warn"The Gemfile specifies no dependencies"lockreturnendifBundler.default_lockfile.exist?&&!options["update"]begintmpdef=Definition.build(Bundler.default_gemfile,Bundler.default_lockfile,nil)local=trueunlesstmpdef.new_platform?||tmpdef.missing_specs.any?rescueBundlerErrorendend# Since we are installing, we can resolve the definition# using remote specsunlesslocaloptions["local"]?@definition.resolve_with_cache!:@definition.resolve_remotely!end# Must install gems in the order that the resolver provides# as dependencies might actually affect the installation of# the gem.Installer.post_install_messages={}specs.eachdo|spec|install_gem_from_spec(spec,options[:standalone])endlockgenerate_standalone(options[:standalone])ifoptions[:standalone]endprivatedefinstall_gem_from_spec(spec,standalone=false)# Download the gem to get the spec, because some specs that are returned# by rubygems.org are broken and wrong.Bundler::Fetcher.fetch(spec)ifspec.source.is_a?(Bundler::Source::Rubygems)# Fetch the build settings, if there are anysettings=Bundler.settings["build.#{spec.name}"]Bundler.rubygems.with_build_args[settings]dospec.source.install(spec)Bundler.ui.debug"from #{spec.loaded_from} "end# newline comes after installing, some gems say "with native extensions"Bundler.ui.info""ifBundler.settings[:bin]standalone?generate_standalone_bundler_executable_stubs(spec):generate_bundler_executable_stubs(spec)endFileUtils.rm_rf(Bundler.tmp)rescueException=>e# install hook failedraiseeife.is_a?(Bundler::InstallHookError)# other failure, likely a native extension build failureBundler.ui.info""Bundler.ui.warn"#{e.class}: #{e.message}"msg="An error occurred while installing #{spec.name} (#{spec.version}),"msg<<" and Bundler cannot continue.\nMake sure that `gem install"msg<<" #{spec.name} -v '#{spec.version}'` succeeds before bundling."Bundler.ui.debuge.backtrace.join("\n")raiseBundler::InstallError,msgenddefgenerate_bundler_executable_stubs(spec)bin_path=Bundler.bin_pathtemplate=File.read(File.expand_path('../templates/Executable',__FILE__))relative_gemfile_path=Bundler.default_gemfile.relative_path_from(bin_path)ruby_command=Thor::Util.ruby_commandspec.executables.eachdo|executable|nextifexecutable=="bundle"File.open"#{bin_path}/#{executable}",'w',0755do|f|f.putsERB.new(template,nil,'-').result(binding)endendenddefgenerate_standalone_bundler_executable_stubs(spec)bin_path=Bundler.bin_pathtemplate=File.read(File.expand_path('../templates/Executable.standalone',__FILE__))ruby_command=Thor::Util.ruby_commandspec.executables.eachdo|executable|nextifexecutable=="bundle"standalone_path=Pathname(Bundler.settings[:path]).expand_path.relative_path_from(bin_path)executable_path=Pathname(spec.full_gem_path).join(spec.bindir,executable).relative_path_from(bin_path)File.open"#{bin_path}/#{executable}",'w',0755do|f|f.putsERB.new(template,nil,'-').result(binding)endendenddefgenerate_standalone(groups)standalone_path=Bundler.settings[:path]bundler_path=File.join(standalone_path,"bundler")FileUtils.mkdir_p(bundler_path)paths=[]ifgroups.empty?specs=Bundler.definition.requested_specselsespecs=Bundler.definition.specs_forgroups.map{|g|g.to_sym}endspecs.eachdo|spec|nextifspec.name=="bundler"spec.require_paths.eachdo|path|full_path=File.join(spec.full_gem_path,path)paths<<Pathname.new(full_path).relative_path_from(Bundler.root.join(bundler_path))endendFile.openFile.join(bundler_path,"setup.rb"),"w"do|file|file.puts"path = File.expand_path('..', __FILE__)"paths.eachdo|path|file.puts%{$:.unshift File.expand_path("\#{path}/#{path}")}endendendendend