📜 ⬆️ ⬇️

Version Control with Bundler

A rake update was recently released from version 0.8.7 to version 0.9.0, which caused a lot of noise in the community and once again revealed the issue of version control. I would like to clarify the situation and again speak out the main points that I already mentioned during the release of Bundler 1.0. First, I will talk about the simple rules of work, and then delve a little into the details.

Simple version control


  1. Add Gemfile.lock to the repository after the bundle made.
  2. After changing the Gemfile, always do the first thing bundle install - this "conservatively" will update Gemfile.lock. Only those gems that you change in the gemfile will change. Everything else will remain as it was.
  3. If a “conservative” update is not possible, the Bundler will prompt you to make a bundle update [somegem] . This command will update only the specified gem and all dependencies necessary for it. The remaining gems will remain intact.
  4. If you need to re-enable all dependencies from scratch, you need to make a bundle update .
  5. When you run executable files, ALWAYS do this through bundle exec [command] . Quote from the documentation: In some cases, launching files without bundle exec may work if this file is part of the heme that is installed on your system and does not load any dependencies that could conflict with your bandl. However, this method is extremely unreliable and is the source of many problems. Even if everything seems to be working, it’s not a fact that it will work tomorrow or on another server. The next section, Executable Files, is about that.
  6. Remember that you can always get your old Gemfile.lock back with the git checkout Gemfile.lock or similar command for other SCMs.


Executable files


When you install a gem, Rubygems creates wrappers for all executable files that come with the gem. When launching the wrapper, it launches Rubygems, which connects the gem itself using a standard activation mechanism. Rubygems will launch the latest gem version installed on the system , even if a different version is specified in Gemfile.lock. In addition, the latest (compatible) versions of all gem dependencies will be activated, even if other versions are indicated in Gemfile.lock.
')
This means that running executables as simple commands simply bypasses the Bundler and all its dependencies. Sometimes this is not a problem, since the developers most likely have just the right versions of all the gems. For a long time, Rake was an excellent example of such a heme with the “correct” version, since the majority of Gemfile.lock were locked to version 0.8.7, which was the last available version and was installed by everyone.

The result was a misconception that running executable files directly is compatible with the Bundler and uses it to resolve dependencies. In case of problems, it was usually recommended to use gems from RVM, since the gemset compiled from Gemfile.lock essentially meant that all the executable environment files worked with the right dependency versions.

Unfortunately, because of this crutch, people continue to ignore the advice from the documentation to always use bundle exec .

There is no reason to believe that when you type rake foo in the console, you run the Bundler sandbox code, because in fact it is not involved and does not start anywhere. The Bundler should be activated at the very beginning of the download and be able to replace the bootloader by slipping the necessary gem versions specified in Gemfile.lock to it. By running executable files directly, you are executing Ruby code before the Bundler could interfere with the dependency connection process. As a result, the code that you are counting on is not connected at all. Once this happens, everything becomes very unpredictable.

bundle install --binstubs


In order to somehow facilitate all these dances with bundle exec , Bundler 1.0 offers a special flag - --binstubs , which creates a bin directory into which the executable files of all the gems used in the application are placed. Thus, running bin/cucumber , for example, is equivalent to the bundle exec cucumber command.

The bin directory creates “portable” wrappers for the launched files, so you can safely add it to the repository.

rails team


The only exception to the above rules is the rails command. Starting with version 3.0, this command first tries to start script/rails from the current directory. And script/rails in turn, first of all launches Bundler
 #This command will automatically be run when you run "rails" with Rails 3 gems installed from the root of your application. APP_PATH = File.expand_path('../../config/application', __FILE__) require File.expand_path('../../config/boot', __FILE__) require 'rails/commands' 


The contents of the boot.rb file boot.rb in turn, is very nontrivial:
 require 'rubygems' # Set up gems listed in the Gemfile. ENV['BUNDLE_GEMFILE'] ||= File.expand_path('../../Gemfile', __FILE__) require 'bundler/setup' if File.exists?(ENV['BUNDLE_GEMFILE']) 


In short, the rails executable file deliberately does everything possible to ensure that the Bundler sandbox startup logic works at the very beginning and uses Kernel#exec to overload the current process if any gems still have time to boot.
This behavior is impossible for most application gems and the question still remains whether it is worth using this hack at all and whether it will be possible that rails can be run even more bundle exec without bundle exec .

Source: https://habr.com/ru/post/120259/


All Articles