Module: Bundler::Plugin::API::Source
- Defined in:
- lib/bundler/plugin/api/source.rb
Overview
This class provides the base to build source plugins All the method here are required to build a source plugin (except ‘uri_hash`, `gem_install_dir`; they are helpers).
Defaults for methods, where ever possible are provided which is expected to work. But, all source plugins have to override ‘fetch_gemspec_files` and `install`. Defaults are also not provided for `remote!`, `cache!` and `unlock!`.
The defaults shall work for most situations but nevertheless they can be (preferably should be) overridden as per the plugins’ needs safely (as long as they behave as expected). On overriding ‘initialize` you should call super first.
If required plugin should override ‘hash`, `==` and `eql?` methods to be able to match objects representing same sources, but may be created in different situation (like form gemfile and lockfile). The default ones checks only for class and uri, but elaborate source plugins may need more comparisons (e.g. git checking on branch or tag).
Instance Attribute Summary collapse
-
#checksum_store ⇒ Object
readonly
Returns the value of attribute checksum_store.
-
#dependency_names ⇒ Array<String>
Names of dependencies that the source should try to resolve.
-
#name ⇒ String
readonly
Name that can be used to uniquely identify a source.
-
#options ⇒ String
readonly
Options passed during initialization (either from lockfile or Gemfile).
-
#uri ⇒ String
readonly
The remote specified with ‘source` block in Gemfile.
Instance Method Summary collapse
-
#==(other) ⇒ Object
(also: #eql?)
This shall check if two source object represent the same source.
-
#add_dependency_names(names) ⇒ Object
Used by definition.
-
#app_cache_dirname ⇒ Object
Name of directory where plugin the is expected to cache the gems when #cache is called.
-
#app_cache_path(custom_path = nil) ⇒ Object
The full path where the plugin should cache the gem so that it can be installed latter.
-
#cache(spec, custom_path = nil) ⇒ Object
This method is called while caching to save copy of the gems that the source can resolve to path provided by ‘app_cache_app`so that they can be reinstalled from the cache without querying the remote (i.e. an alternative to remote).
-
#cached! ⇒ Object
Set internal representation to fetch the gems/specs from app cache.
-
#can_lock?(spec) ⇒ Boolean
NOTE: Do not override if you don’t know what you are doing.
-
#double_check_for ⇒ Object
This API on source might not be stable, and for now we expect plugins to download all specs in ‘#specs`, so we implement the method for compatibility purposes and leave it undocumented (and don’t support) overriding it).
-
#fetch_gemspec_files ⇒ Array<String>
This is used by the default ‘spec` method to constructs the Specification objects for the gems and versions that can be installed by this source plugin.
-
#gem_install_dir ⇒ Object
NOTE: Do not override if you don’t know what you are doing.
-
#hash ⇒ Object
When overriding ‘hash` please preserve the behaviour as mentioned in docstring for `==` method, i.e.
-
#include?(other) ⇒ Boolean
NOTE: Do not override if you don’t know what you are doing.
- #initialize(opts) ⇒ Object
-
#install(spec, opts) ⇒ String
Install the gem specified by the spec at appropriate path.
-
#install_path ⇒ Object
A default installation path to install a single gem.
-
#installed? ⇒ Boolean
A helper method, not necessary if not used internally.
-
#local! ⇒ Object
Set internal representation to fetch the gems/specs locally.
-
#options_to_lock ⇒ Hash
Options to be saved in the lockfile so that the source plugin is able to check out same version of gem later.
-
#post_install(spec, disable_exts = false) ⇒ Object
It builds extensions, generates bins and installs them for the spec provided.
-
#remote! ⇒ Object
Set internal representation to fetch the gems/specs from remote.
-
#root ⇒ Object
It is used to obtain the full_gem_path.
-
#spec_names ⇒ Object
Used by definition.
-
#specs ⇒ Bundler::Index
Parses the gemspec files to find the specs for the gems that can be satisfied by the source.
-
#to_lock ⇒ Object
Generates the content to be entered into the lockfile.
- #to_s ⇒ Object (also: #identifier)
-
#unlock! ⇒ Object
This is called to update the spec and installation.
-
#unmet_deps ⇒ Object
Used by definition.
- #uri_hash ⇒ Object
Instance Attribute Details
#checksum_store ⇒ Object (readonly)
Returns the value of attribute checksum_store.
42 43 44 |
# File 'lib/bundler/plugin/api/source.rb', line 42 def checksum_store @checksum_store end |
#dependency_names ⇒ Array<String>
Returns Names of dependencies that the source should try to resolve. It is not necessary to use this list internally. This is present to be compatible with ‘Definition` and is used by rubygems source.
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 73 74 75 76 77 78 79 80 81 82 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 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 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 188 189 190 191 192 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 227 228 229 230 231 232 233 234 235 236 237 238 239 240 241 242 243 244 245 246 247 248 249 250 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 289 290 291 292 293 294 295 296 297 298 299 300 301 302 303 304 305 306 307 308 309 310 311 312 313 314 315 316 317 318 |
# File 'lib/bundler/plugin/api/source.rb', line 41 module Source attr_reader :uri, :options, :name, :checksum_store attr_accessor :dependency_names def initialize(opts) @options = opts @dependency_names = [] @uri = opts["uri"] @type = opts["type"] @name = opts["name"] || "#{@type} at #{@uri}" @checksum_store = Checksum::Store.new end # This is used by the default `spec` method to constructs the # Specification objects for the gems and versions that can be installed # by this source plugin. # # Note: If the spec method is overridden, this function is not necessary # # @return [Array<String>] paths of the gemspec files for gems that can # be installed def fetch_gemspec_files [] end # Options to be saved in the lockfile so that the source plugin is able # to check out same version of gem later. # # There options are passed when the source plugin is created from the # lock file. # # @return [Hash] def {} end # Install the gem specified by the spec at appropriate path. # `install_path` provides a sufficient default, if the source can only # satisfy one gem, but is not binding. # # @return [String] post installation message (if any) def install(spec, opts) raise MalformattedPlugin, "Source plugins need to override the install method." end # It builds extensions, generates bins and installs them for the spec # provided. # # It depends on `spec.loaded_from` to get full_gem_path. The source # plugins should set that. # # It should be called in `install` after the plugin is done placing the # gem at correct install location. # # It also runs Gem hooks `pre_install`, `post_build` and `post_install` # # Note: Do not override if you don't know what you are doing. def post_install(spec, disable_exts = false) opts = { env_shebang: false, disable_extensions: disable_exts } installer = Bundler::Source::Path::Installer.new(spec, opts) installer.post_install end # A default installation path to install a single gem. If the source # servers multiple gems, it's not of much use and the source should one # of its own. def install_path @install_path ||= begin base_name = File.basename(Gem::URI.parse(uri).normalize.path) gem_install_dir.join("#{base_name}-#{uri_hash[0..11]}") end end # Parses the gemspec files to find the specs for the gems that can be # satisfied by the source. # # Few important points to keep in mind: # - If the gems are not installed then it shall return specs for all # the gems it can satisfy # - If gem is installed (that is to be detected by the plugin itself) # then it shall return at least the specs that are installed. # - The `loaded_from` for each of the specs shall be correct (it is # used to find the load path) # # @return [Bundler::Index] index containing the specs def specs files = fetch_gemspec_files Bundler::Index.build do |index| files.each do |file| next unless spec = Bundler.load_gemspec(file) Bundler.rubygems.set_installed_by_version(spec) spec.source = self Bundler.rubygems.validate(spec) index << spec end end end # Set internal representation to fetch the gems/specs locally. # # When this is called, the source should try to fetch the specs and # install from the local system. def local! end # Set internal representation to fetch the gems/specs from remote. # # When this is called, the source should try to fetch the specs and # install from remote path. def remote! end # Set internal representation to fetch the gems/specs from app cache. # # When this is called, the source should try to fetch the specs and # install from the path provided by `app_cache_path`. def cached! end # This is called to update the spec and installation. # # If the source plugin is loaded from lockfile or otherwise, it shall # refresh the cache/specs (e.g. git sources can make a fresh clone). def unlock! end # Name of directory where plugin the is expected to cache the gems when # #cache is called. # # Also this name is matched against the directories in cache for pruning # # This is used by `app_cache_path` def app_cache_dirname base_name = File.basename(Gem::URI.parse(uri).normalize.path) "#{base_name}-#{uri_hash}" end # This method is called while caching to save copy of the gems that the # source can resolve to path provided by `app_cache_app`so that they can # be reinstalled from the cache without querying the remote (i.e. an # alternative to remote) # # This is stored with the app and source plugins should try to provide # specs and install only from this cache when `cached!` is called. # # This cache is different from the internal caching that can be done # at sub paths of `cache_path` (from API). This can be though as caching # by bundler. def cache(spec, custom_path = nil) new_cache_path = app_cache_path(custom_path) FileUtils.rm_rf(new_cache_path) FileUtils.cp_r(install_path, new_cache_path) FileUtils.touch(app_cache_path.join(".bundlecache")) end # This shall check if two source object represent the same source. # # The comparison shall take place only on the attribute that can be # inferred from the options passed from Gemfile and not on attributes # that are used to pin down the gem to specific version (e.g. Git # sources should compare on branch and tag but not on commit hash) # # The sources objects are constructed from Gemfile as well as from # lockfile. To converge the sources, it is necessary that they match. # # The same applies for `eql?` and `hash` def ==(other) other.is_a?(self.class) && uri == other.uri end # When overriding `eql?` please preserve the behaviour as mentioned in # docstring for `==` method. alias_method :eql?, :== # When overriding `hash` please preserve the behaviour as mentioned in # docstring for `==` method, i.e. two methods equal by above comparison # should have same hash. def hash [self.class, uri].hash end # A helper method, not necessary if not used internally. def installed? File.directory?(install_path) end # The full path where the plugin should cache the gem so that it can be # installed latter. # # Note: Do not override if you don't know what you are doing. def app_cache_path(custom_path = nil) @app_cache_path ||= Bundler.app_cache(custom_path).join(app_cache_dirname) end # Used by definition. # # Note: Do not override if you don't know what you are doing. def unmet_deps specs.unmet_dependency_names end # Used by definition. # # Note: Do not override if you don't know what you are doing. def spec_names specs.spec_names end # Used by definition. # # Note: Do not override if you don't know what you are doing. def add_dependency_names(names) @dependencies |= Array(names) end # NOTE: Do not override if you don't know what you are doing. def can_lock?(spec) spec.source == self end # Generates the content to be entered into the lockfile. # Saves type and remote and also calls to `options_to_lock`. # # Plugin should use `options_to_lock` to save information in lockfile # and not override this. # # Note: Do not override if you don't know what you are doing. def to_lock out = String.new("#{LockfileParser::PLUGIN}\n") out << " remote: #{@uri}\n" out << " type: #{@type}\n" .each do |opt, value| out << " #{opt}: #{value}\n" end out << " specs:\n" end def to_s "plugin source for #{@type} with uri #{@uri}" end alias_method :identifier, :to_s # NOTE: Do not override if you don't know what you are doing. def include?(other) other == self end def uri_hash SharedHelpers.digest(:SHA1).hexdigest(uri) end # NOTE: Do not override if you don't know what you are doing. def gem_install_dir Bundler.install_path end # It is used to obtain the full_gem_path. # # spec's loaded_from path is expanded against this to get full_gem_path # # Note: Do not override if you don't know what you are doing. def root Bundler.root end # @private # This API on source might not be stable, and for now we expect plugins # to download all specs in `#specs`, so we implement the method for # compatibility purposes and leave it undocumented (and don't support) # overriding it) def double_check_for(*); end end |
#name ⇒ String (readonly)
Returns name that can be used to uniquely identify a source.
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 73 74 75 76 77 78 79 80 81 82 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 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 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 188 189 190 191 192 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 227 228 229 230 231 232 233 234 235 236 237 238 239 240 241 242 243 244 245 246 247 248 249 250 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 289 290 291 292 293 294 295 296 297 298 299 300 301 302 303 304 305 306 307 308 309 310 311 312 313 314 315 316 317 318 |
# File 'lib/bundler/plugin/api/source.rb', line 41 module Source attr_reader :uri, :options, :name, :checksum_store attr_accessor :dependency_names def initialize(opts) @options = opts @dependency_names = [] @uri = opts["uri"] @type = opts["type"] @name = opts["name"] || "#{@type} at #{@uri}" @checksum_store = Checksum::Store.new end # This is used by the default `spec` method to constructs the # Specification objects for the gems and versions that can be installed # by this source plugin. # # Note: If the spec method is overridden, this function is not necessary # # @return [Array<String>] paths of the gemspec files for gems that can # be installed def fetch_gemspec_files [] end # Options to be saved in the lockfile so that the source plugin is able # to check out same version of gem later. # # There options are passed when the source plugin is created from the # lock file. # # @return [Hash] def {} end # Install the gem specified by the spec at appropriate path. # `install_path` provides a sufficient default, if the source can only # satisfy one gem, but is not binding. # # @return [String] post installation message (if any) def install(spec, opts) raise MalformattedPlugin, "Source plugins need to override the install method." end # It builds extensions, generates bins and installs them for the spec # provided. # # It depends on `spec.loaded_from` to get full_gem_path. The source # plugins should set that. # # It should be called in `install` after the plugin is done placing the # gem at correct install location. # # It also runs Gem hooks `pre_install`, `post_build` and `post_install` # # Note: Do not override if you don't know what you are doing. def post_install(spec, disable_exts = false) opts = { env_shebang: false, disable_extensions: disable_exts } installer = Bundler::Source::Path::Installer.new(spec, opts) installer.post_install end # A default installation path to install a single gem. If the source # servers multiple gems, it's not of much use and the source should one # of its own. def install_path @install_path ||= begin base_name = File.basename(Gem::URI.parse(uri).normalize.path) gem_install_dir.join("#{base_name}-#{uri_hash[0..11]}") end end # Parses the gemspec files to find the specs for the gems that can be # satisfied by the source. # # Few important points to keep in mind: # - If the gems are not installed then it shall return specs for all # the gems it can satisfy # - If gem is installed (that is to be detected by the plugin itself) # then it shall return at least the specs that are installed. # - The `loaded_from` for each of the specs shall be correct (it is # used to find the load path) # # @return [Bundler::Index] index containing the specs def specs files = fetch_gemspec_files Bundler::Index.build do |index| files.each do |file| next unless spec = Bundler.load_gemspec(file) Bundler.rubygems.set_installed_by_version(spec) spec.source = self Bundler.rubygems.validate(spec) index << spec end end end # Set internal representation to fetch the gems/specs locally. # # When this is called, the source should try to fetch the specs and # install from the local system. def local! end # Set internal representation to fetch the gems/specs from remote. # # When this is called, the source should try to fetch the specs and # install from remote path. def remote! end # Set internal representation to fetch the gems/specs from app cache. # # When this is called, the source should try to fetch the specs and # install from the path provided by `app_cache_path`. def cached! end # This is called to update the spec and installation. # # If the source plugin is loaded from lockfile or otherwise, it shall # refresh the cache/specs (e.g. git sources can make a fresh clone). def unlock! end # Name of directory where plugin the is expected to cache the gems when # #cache is called. # # Also this name is matched against the directories in cache for pruning # # This is used by `app_cache_path` def app_cache_dirname base_name = File.basename(Gem::URI.parse(uri).normalize.path) "#{base_name}-#{uri_hash}" end # This method is called while caching to save copy of the gems that the # source can resolve to path provided by `app_cache_app`so that they can # be reinstalled from the cache without querying the remote (i.e. an # alternative to remote) # # This is stored with the app and source plugins should try to provide # specs and install only from this cache when `cached!` is called. # # This cache is different from the internal caching that can be done # at sub paths of `cache_path` (from API). This can be though as caching # by bundler. def cache(spec, custom_path = nil) new_cache_path = app_cache_path(custom_path) FileUtils.rm_rf(new_cache_path) FileUtils.cp_r(install_path, new_cache_path) FileUtils.touch(app_cache_path.join(".bundlecache")) end # This shall check if two source object represent the same source. # # The comparison shall take place only on the attribute that can be # inferred from the options passed from Gemfile and not on attributes # that are used to pin down the gem to specific version (e.g. Git # sources should compare on branch and tag but not on commit hash) # # The sources objects are constructed from Gemfile as well as from # lockfile. To converge the sources, it is necessary that they match. # # The same applies for `eql?` and `hash` def ==(other) other.is_a?(self.class) && uri == other.uri end # When overriding `eql?` please preserve the behaviour as mentioned in # docstring for `==` method. alias_method :eql?, :== # When overriding `hash` please preserve the behaviour as mentioned in # docstring for `==` method, i.e. two methods equal by above comparison # should have same hash. def hash [self.class, uri].hash end # A helper method, not necessary if not used internally. def installed? File.directory?(install_path) end # The full path where the plugin should cache the gem so that it can be # installed latter. # # Note: Do not override if you don't know what you are doing. def app_cache_path(custom_path = nil) @app_cache_path ||= Bundler.app_cache(custom_path).join(app_cache_dirname) end # Used by definition. # # Note: Do not override if you don't know what you are doing. def unmet_deps specs.unmet_dependency_names end # Used by definition. # # Note: Do not override if you don't know what you are doing. def spec_names specs.spec_names end # Used by definition. # # Note: Do not override if you don't know what you are doing. def add_dependency_names(names) @dependencies |= Array(names) end # NOTE: Do not override if you don't know what you are doing. def can_lock?(spec) spec.source == self end # Generates the content to be entered into the lockfile. # Saves type and remote and also calls to `options_to_lock`. # # Plugin should use `options_to_lock` to save information in lockfile # and not override this. # # Note: Do not override if you don't know what you are doing. def to_lock out = String.new("#{LockfileParser::PLUGIN}\n") out << " remote: #{@uri}\n" out << " type: #{@type}\n" .each do |opt, value| out << " #{opt}: #{value}\n" end out << " specs:\n" end def to_s "plugin source for #{@type} with uri #{@uri}" end alias_method :identifier, :to_s # NOTE: Do not override if you don't know what you are doing. def include?(other) other == self end def uri_hash SharedHelpers.digest(:SHA1).hexdigest(uri) end # NOTE: Do not override if you don't know what you are doing. def gem_install_dir Bundler.install_path end # It is used to obtain the full_gem_path. # # spec's loaded_from path is expanded against this to get full_gem_path # # Note: Do not override if you don't know what you are doing. def root Bundler.root end # @private # This API on source might not be stable, and for now we expect plugins # to download all specs in `#specs`, so we implement the method for # compatibility purposes and leave it undocumented (and don't support) # overriding it) def double_check_for(*); end end |
#options ⇒ String (readonly)
Returns options passed during initialization (either from lockfile or Gemfile).
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 73 74 75 76 77 78 79 80 81 82 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 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 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 188 189 190 191 192 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 227 228 229 230 231 232 233 234 235 236 237 238 239 240 241 242 243 244 245 246 247 248 249 250 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 289 290 291 292 293 294 295 296 297 298 299 300 301 302 303 304 305 306 307 308 309 310 311 312 313 314 315 316 317 318 |
# File 'lib/bundler/plugin/api/source.rb', line 41 module Source attr_reader :uri, :options, :name, :checksum_store attr_accessor :dependency_names def initialize(opts) @options = opts @dependency_names = [] @uri = opts["uri"] @type = opts["type"] @name = opts["name"] || "#{@type} at #{@uri}" @checksum_store = Checksum::Store.new end # This is used by the default `spec` method to constructs the # Specification objects for the gems and versions that can be installed # by this source plugin. # # Note: If the spec method is overridden, this function is not necessary # # @return [Array<String>] paths of the gemspec files for gems that can # be installed def fetch_gemspec_files [] end # Options to be saved in the lockfile so that the source plugin is able # to check out same version of gem later. # # There options are passed when the source plugin is created from the # lock file. # # @return [Hash] def {} end # Install the gem specified by the spec at appropriate path. # `install_path` provides a sufficient default, if the source can only # satisfy one gem, but is not binding. # # @return [String] post installation message (if any) def install(spec, opts) raise MalformattedPlugin, "Source plugins need to override the install method." end # It builds extensions, generates bins and installs them for the spec # provided. # # It depends on `spec.loaded_from` to get full_gem_path. The source # plugins should set that. # # It should be called in `install` after the plugin is done placing the # gem at correct install location. # # It also runs Gem hooks `pre_install`, `post_build` and `post_install` # # Note: Do not override if you don't know what you are doing. def post_install(spec, disable_exts = false) opts = { env_shebang: false, disable_extensions: disable_exts } installer = Bundler::Source::Path::Installer.new(spec, opts) installer.post_install end # A default installation path to install a single gem. If the source # servers multiple gems, it's not of much use and the source should one # of its own. def install_path @install_path ||= begin base_name = File.basename(Gem::URI.parse(uri).normalize.path) gem_install_dir.join("#{base_name}-#{uri_hash[0..11]}") end end # Parses the gemspec files to find the specs for the gems that can be # satisfied by the source. # # Few important points to keep in mind: # - If the gems are not installed then it shall return specs for all # the gems it can satisfy # - If gem is installed (that is to be detected by the plugin itself) # then it shall return at least the specs that are installed. # - The `loaded_from` for each of the specs shall be correct (it is # used to find the load path) # # @return [Bundler::Index] index containing the specs def specs files = fetch_gemspec_files Bundler::Index.build do |index| files.each do |file| next unless spec = Bundler.load_gemspec(file) Bundler.rubygems.set_installed_by_version(spec) spec.source = self Bundler.rubygems.validate(spec) index << spec end end end # Set internal representation to fetch the gems/specs locally. # # When this is called, the source should try to fetch the specs and # install from the local system. def local! end # Set internal representation to fetch the gems/specs from remote. # # When this is called, the source should try to fetch the specs and # install from remote path. def remote! end # Set internal representation to fetch the gems/specs from app cache. # # When this is called, the source should try to fetch the specs and # install from the path provided by `app_cache_path`. def cached! end # This is called to update the spec and installation. # # If the source plugin is loaded from lockfile or otherwise, it shall # refresh the cache/specs (e.g. git sources can make a fresh clone). def unlock! end # Name of directory where plugin the is expected to cache the gems when # #cache is called. # # Also this name is matched against the directories in cache for pruning # # This is used by `app_cache_path` def app_cache_dirname base_name = File.basename(Gem::URI.parse(uri).normalize.path) "#{base_name}-#{uri_hash}" end # This method is called while caching to save copy of the gems that the # source can resolve to path provided by `app_cache_app`so that they can # be reinstalled from the cache without querying the remote (i.e. an # alternative to remote) # # This is stored with the app and source plugins should try to provide # specs and install only from this cache when `cached!` is called. # # This cache is different from the internal caching that can be done # at sub paths of `cache_path` (from API). This can be though as caching # by bundler. def cache(spec, custom_path = nil) new_cache_path = app_cache_path(custom_path) FileUtils.rm_rf(new_cache_path) FileUtils.cp_r(install_path, new_cache_path) FileUtils.touch(app_cache_path.join(".bundlecache")) end # This shall check if two source object represent the same source. # # The comparison shall take place only on the attribute that can be # inferred from the options passed from Gemfile and not on attributes # that are used to pin down the gem to specific version (e.g. Git # sources should compare on branch and tag but not on commit hash) # # The sources objects are constructed from Gemfile as well as from # lockfile. To converge the sources, it is necessary that they match. # # The same applies for `eql?` and `hash` def ==(other) other.is_a?(self.class) && uri == other.uri end # When overriding `eql?` please preserve the behaviour as mentioned in # docstring for `==` method. alias_method :eql?, :== # When overriding `hash` please preserve the behaviour as mentioned in # docstring for `==` method, i.e. two methods equal by above comparison # should have same hash. def hash [self.class, uri].hash end # A helper method, not necessary if not used internally. def installed? File.directory?(install_path) end # The full path where the plugin should cache the gem so that it can be # installed latter. # # Note: Do not override if you don't know what you are doing. def app_cache_path(custom_path = nil) @app_cache_path ||= Bundler.app_cache(custom_path).join(app_cache_dirname) end # Used by definition. # # Note: Do not override if you don't know what you are doing. def unmet_deps specs.unmet_dependency_names end # Used by definition. # # Note: Do not override if you don't know what you are doing. def spec_names specs.spec_names end # Used by definition. # # Note: Do not override if you don't know what you are doing. def add_dependency_names(names) @dependencies |= Array(names) end # NOTE: Do not override if you don't know what you are doing. def can_lock?(spec) spec.source == self end # Generates the content to be entered into the lockfile. # Saves type and remote and also calls to `options_to_lock`. # # Plugin should use `options_to_lock` to save information in lockfile # and not override this. # # Note: Do not override if you don't know what you are doing. def to_lock out = String.new("#{LockfileParser::PLUGIN}\n") out << " remote: #{@uri}\n" out << " type: #{@type}\n" .each do |opt, value| out << " #{opt}: #{value}\n" end out << " specs:\n" end def to_s "plugin source for #{@type} with uri #{@uri}" end alias_method :identifier, :to_s # NOTE: Do not override if you don't know what you are doing. def include?(other) other == self end def uri_hash SharedHelpers.digest(:SHA1).hexdigest(uri) end # NOTE: Do not override if you don't know what you are doing. def gem_install_dir Bundler.install_path end # It is used to obtain the full_gem_path. # # spec's loaded_from path is expanded against this to get full_gem_path # # Note: Do not override if you don't know what you are doing. def root Bundler.root end # @private # This API on source might not be stable, and for now we expect plugins # to download all specs in `#specs`, so we implement the method for # compatibility purposes and leave it undocumented (and don't support) # overriding it) def double_check_for(*); end end |
#uri ⇒ String (readonly)
Returns the remote specified with ‘source` block in Gemfile.
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 73 74 75 76 77 78 79 80 81 82 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 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 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 188 189 190 191 192 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 227 228 229 230 231 232 233 234 235 236 237 238 239 240 241 242 243 244 245 246 247 248 249 250 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 289 290 291 292 293 294 295 296 297 298 299 300 301 302 303 304 305 306 307 308 309 310 311 312 313 314 315 316 317 318 |
# File 'lib/bundler/plugin/api/source.rb', line 41 module Source attr_reader :uri, :options, :name, :checksum_store attr_accessor :dependency_names def initialize(opts) @options = opts @dependency_names = [] @uri = opts["uri"] @type = opts["type"] @name = opts["name"] || "#{@type} at #{@uri}" @checksum_store = Checksum::Store.new end # This is used by the default `spec` method to constructs the # Specification objects for the gems and versions that can be installed # by this source plugin. # # Note: If the spec method is overridden, this function is not necessary # # @return [Array<String>] paths of the gemspec files for gems that can # be installed def fetch_gemspec_files [] end # Options to be saved in the lockfile so that the source plugin is able # to check out same version of gem later. # # There options are passed when the source plugin is created from the # lock file. # # @return [Hash] def {} end # Install the gem specified by the spec at appropriate path. # `install_path` provides a sufficient default, if the source can only # satisfy one gem, but is not binding. # # @return [String] post installation message (if any) def install(spec, opts) raise MalformattedPlugin, "Source plugins need to override the install method." end # It builds extensions, generates bins and installs them for the spec # provided. # # It depends on `spec.loaded_from` to get full_gem_path. The source # plugins should set that. # # It should be called in `install` after the plugin is done placing the # gem at correct install location. # # It also runs Gem hooks `pre_install`, `post_build` and `post_install` # # Note: Do not override if you don't know what you are doing. def post_install(spec, disable_exts = false) opts = { env_shebang: false, disable_extensions: disable_exts } installer = Bundler::Source::Path::Installer.new(spec, opts) installer.post_install end # A default installation path to install a single gem. If the source # servers multiple gems, it's not of much use and the source should one # of its own. def install_path @install_path ||= begin base_name = File.basename(Gem::URI.parse(uri).normalize.path) gem_install_dir.join("#{base_name}-#{uri_hash[0..11]}") end end # Parses the gemspec files to find the specs for the gems that can be # satisfied by the source. # # Few important points to keep in mind: # - If the gems are not installed then it shall return specs for all # the gems it can satisfy # - If gem is installed (that is to be detected by the plugin itself) # then it shall return at least the specs that are installed. # - The `loaded_from` for each of the specs shall be correct (it is # used to find the load path) # # @return [Bundler::Index] index containing the specs def specs files = fetch_gemspec_files Bundler::Index.build do |index| files.each do |file| next unless spec = Bundler.load_gemspec(file) Bundler.rubygems.set_installed_by_version(spec) spec.source = self Bundler.rubygems.validate(spec) index << spec end end end # Set internal representation to fetch the gems/specs locally. # # When this is called, the source should try to fetch the specs and # install from the local system. def local! end # Set internal representation to fetch the gems/specs from remote. # # When this is called, the source should try to fetch the specs and # install from remote path. def remote! end # Set internal representation to fetch the gems/specs from app cache. # # When this is called, the source should try to fetch the specs and # install from the path provided by `app_cache_path`. def cached! end # This is called to update the spec and installation. # # If the source plugin is loaded from lockfile or otherwise, it shall # refresh the cache/specs (e.g. git sources can make a fresh clone). def unlock! end # Name of directory where plugin the is expected to cache the gems when # #cache is called. # # Also this name is matched against the directories in cache for pruning # # This is used by `app_cache_path` def app_cache_dirname base_name = File.basename(Gem::URI.parse(uri).normalize.path) "#{base_name}-#{uri_hash}" end # This method is called while caching to save copy of the gems that the # source can resolve to path provided by `app_cache_app`so that they can # be reinstalled from the cache without querying the remote (i.e. an # alternative to remote) # # This is stored with the app and source plugins should try to provide # specs and install only from this cache when `cached!` is called. # # This cache is different from the internal caching that can be done # at sub paths of `cache_path` (from API). This can be though as caching # by bundler. def cache(spec, custom_path = nil) new_cache_path = app_cache_path(custom_path) FileUtils.rm_rf(new_cache_path) FileUtils.cp_r(install_path, new_cache_path) FileUtils.touch(app_cache_path.join(".bundlecache")) end # This shall check if two source object represent the same source. # # The comparison shall take place only on the attribute that can be # inferred from the options passed from Gemfile and not on attributes # that are used to pin down the gem to specific version (e.g. Git # sources should compare on branch and tag but not on commit hash) # # The sources objects are constructed from Gemfile as well as from # lockfile. To converge the sources, it is necessary that they match. # # The same applies for `eql?` and `hash` def ==(other) other.is_a?(self.class) && uri == other.uri end # When overriding `eql?` please preserve the behaviour as mentioned in # docstring for `==` method. alias_method :eql?, :== # When overriding `hash` please preserve the behaviour as mentioned in # docstring for `==` method, i.e. two methods equal by above comparison # should have same hash. def hash [self.class, uri].hash end # A helper method, not necessary if not used internally. def installed? File.directory?(install_path) end # The full path where the plugin should cache the gem so that it can be # installed latter. # # Note: Do not override if you don't know what you are doing. def app_cache_path(custom_path = nil) @app_cache_path ||= Bundler.app_cache(custom_path).join(app_cache_dirname) end # Used by definition. # # Note: Do not override if you don't know what you are doing. def unmet_deps specs.unmet_dependency_names end # Used by definition. # # Note: Do not override if you don't know what you are doing. def spec_names specs.spec_names end # Used by definition. # # Note: Do not override if you don't know what you are doing. def add_dependency_names(names) @dependencies |= Array(names) end # NOTE: Do not override if you don't know what you are doing. def can_lock?(spec) spec.source == self end # Generates the content to be entered into the lockfile. # Saves type and remote and also calls to `options_to_lock`. # # Plugin should use `options_to_lock` to save information in lockfile # and not override this. # # Note: Do not override if you don't know what you are doing. def to_lock out = String.new("#{LockfileParser::PLUGIN}\n") out << " remote: #{@uri}\n" out << " type: #{@type}\n" .each do |opt, value| out << " #{opt}: #{value}\n" end out << " specs:\n" end def to_s "plugin source for #{@type} with uri #{@uri}" end alias_method :identifier, :to_s # NOTE: Do not override if you don't know what you are doing. def include?(other) other == self end def uri_hash SharedHelpers.digest(:SHA1).hexdigest(uri) end # NOTE: Do not override if you don't know what you are doing. def gem_install_dir Bundler.install_path end # It is used to obtain the full_gem_path. # # spec's loaded_from path is expanded against this to get full_gem_path # # Note: Do not override if you don't know what you are doing. def root Bundler.root end # @private # This API on source might not be stable, and for now we expect plugins # to download all specs in `#specs`, so we implement the method for # compatibility purposes and leave it undocumented (and don't support) # overriding it) def double_check_for(*); end end |
Instance Method Details
#==(other) ⇒ Object Also known as: eql?
This shall check if two source object represent the same source.
The comparison shall take place only on the attribute that can be inferred from the options passed from Gemfile and not on attributes that are used to pin down the gem to specific version (e.g. Git sources should compare on branch and tag but not on commit hash)
The sources objects are constructed from Gemfile as well as from lockfile. To converge the sources, it is necessary that they match.
The same applies for ‘eql?` and `hash`
213 214 215 |
# File 'lib/bundler/plugin/api/source.rb', line 213 def ==(other) other.is_a?(self.class) && uri == other.uri end |
#add_dependency_names(names) ⇒ Object
Used by definition.
Note: Do not override if you don’t know what you are doing.
258 259 260 |
# File 'lib/bundler/plugin/api/source.rb', line 258 def add_dependency_names(names) @dependencies |= Array(names) end |
#app_cache_dirname ⇒ Object
Name of directory where plugin the is expected to cache the gems when #cache is called.
Also this name is matched against the directories in cache for pruning
This is used by ‘app_cache_path`
178 179 180 181 |
# File 'lib/bundler/plugin/api/source.rb', line 178 def app_cache_dirname base_name = File.basename(Gem::URI.parse(uri).normalize.path) "#{base_name}-#{uri_hash}" end |
#app_cache_path(custom_path = nil) ⇒ Object
The full path where the plugin should cache the gem so that it can be installed latter.
Note: Do not override if you don’t know what you are doing.
237 238 239 |
# File 'lib/bundler/plugin/api/source.rb', line 237 def app_cache_path(custom_path = nil) @app_cache_path ||= Bundler.app_cache(custom_path).join(app_cache_dirname) end |
#cache(spec, custom_path = nil) ⇒ Object
This method is called while caching to save copy of the gems that the source can resolve to path provided by ‘app_cache_app`so that they can be reinstalled from the cache without querying the remote (i.e. an alternative to remote)
This is stored with the app and source plugins should try to provide specs and install only from this cache when ‘cached!` is called.
This cache is different from the internal caching that can be done at sub paths of ‘cache_path` (from API). This can be though as caching by bundler.
194 195 196 197 198 199 200 |
# File 'lib/bundler/plugin/api/source.rb', line 194 def cache(spec, custom_path = nil) new_cache_path = app_cache_path(custom_path) FileUtils.rm_rf(new_cache_path) FileUtils.cp_r(install_path, new_cache_path) FileUtils.touch(app_cache_path.join(".bundlecache")) end |
#cached! ⇒ Object
Set internal representation to fetch the gems/specs from app cache.
When this is called, the source should try to fetch the specs and install from the path provided by ‘app_cache_path`.
162 163 |
# File 'lib/bundler/plugin/api/source.rb', line 162 def cached! end |
#can_lock?(spec) ⇒ Boolean
NOTE: Do not override if you don’t know what you are doing.
263 264 265 |
# File 'lib/bundler/plugin/api/source.rb', line 263 def can_lock?(spec) spec.source == self end |
#double_check_for ⇒ Object
This API on source might not be stable, and for now we expect plugins to download all specs in ‘#specs`, so we implement the method for compatibility purposes and leave it undocumented (and don’t support) overriding it)
317 |
# File 'lib/bundler/plugin/api/source.rb', line 317 def double_check_for(*); end |
#fetch_gemspec_files ⇒ Array<String>
This is used by the default ‘spec` method to constructs the Specification objects for the gems and versions that can be installed by this source plugin.
Note: If the spec method is overridden, this function is not necessary
62 63 64 |
# File 'lib/bundler/plugin/api/source.rb', line 62 def fetch_gemspec_files [] end |
#gem_install_dir ⇒ Object
NOTE: Do not override if you don’t know what you are doing.
299 300 301 |
# File 'lib/bundler/plugin/api/source.rb', line 299 def gem_install_dir Bundler.install_path end |
#hash ⇒ Object
When overriding ‘hash` please preserve the behaviour as mentioned in docstring for `==` method, i.e. two methods equal by above comparison should have same hash.
224 225 226 |
# File 'lib/bundler/plugin/api/source.rb', line 224 def hash [self.class, uri].hash end |
#include?(other) ⇒ Boolean
NOTE: Do not override if you don’t know what you are doing.
290 291 292 |
# File 'lib/bundler/plugin/api/source.rb', line 290 def include?(other) other == self end |
#initialize(opts) ⇒ Object
45 46 47 48 49 50 51 52 |
# File 'lib/bundler/plugin/api/source.rb', line 45 def initialize(opts) @options = opts @dependency_names = [] @uri = opts["uri"] @type = opts["type"] @name = opts["name"] || "#{@type} at #{@uri}" @checksum_store = Checksum::Store.new end |
#install(spec, opts) ⇒ String
Install the gem specified by the spec at appropriate path. ‘install_path` provides a sufficient default, if the source can only satisfy one gem, but is not binding.
82 83 84 |
# File 'lib/bundler/plugin/api/source.rb', line 82 def install(spec, opts) raise MalformattedPlugin, "Source plugins need to override the install method." end |
#install_path ⇒ Object
A default installation path to install a single gem. If the source servers multiple gems, it’s not of much use and the source should one of its own.
107 108 109 110 111 112 113 114 |
# File 'lib/bundler/plugin/api/source.rb', line 107 def install_path @install_path ||= begin base_name = File.basename(Gem::URI.parse(uri).normalize.path) gem_install_dir.join("#{base_name}-#{uri_hash[0..11]}") end end |
#installed? ⇒ Boolean
A helper method, not necessary if not used internally.
229 230 231 |
# File 'lib/bundler/plugin/api/source.rb', line 229 def installed? File.directory?(install_path) end |
#local! ⇒ Object
Set internal representation to fetch the gems/specs locally.
When this is called, the source should try to fetch the specs and install from the local system.
148 149 |
# File 'lib/bundler/plugin/api/source.rb', line 148 def local! end |
#options_to_lock ⇒ Hash
Options to be saved in the lockfile so that the source plugin is able to check out same version of gem later.
There options are passed when the source plugin is created from the lock file.
73 74 75 |
# File 'lib/bundler/plugin/api/source.rb', line 73 def {} end |
#post_install(spec, disable_exts = false) ⇒ Object
It builds extensions, generates bins and installs them for the spec provided.
It depends on ‘spec.loaded_from` to get full_gem_path. The source plugins should set that.
It should be called in ‘install` after the plugin is done placing the gem at correct install location.
It also runs Gem hooks ‘pre_install`, `post_build` and `post_install`
Note: Do not override if you don’t know what you are doing.
98 99 100 101 102 |
# File 'lib/bundler/plugin/api/source.rb', line 98 def post_install(spec, disable_exts = false) opts = { env_shebang: false, disable_extensions: disable_exts } installer = Bundler::Source::Path::Installer.new(spec, opts) installer.post_install end |
#remote! ⇒ Object
Set internal representation to fetch the gems/specs from remote.
When this is called, the source should try to fetch the specs and install from remote path.
155 156 |
# File 'lib/bundler/plugin/api/source.rb', line 155 def remote! end |
#root ⇒ Object
It is used to obtain the full_gem_path.
spec’s loaded_from path is expanded against this to get full_gem_path
Note: Do not override if you don’t know what you are doing.
308 309 310 |
# File 'lib/bundler/plugin/api/source.rb', line 308 def root Bundler.root end |
#spec_names ⇒ Object
Used by definition.
Note: Do not override if you don’t know what you are doing.
251 252 253 |
# File 'lib/bundler/plugin/api/source.rb', line 251 def spec_names specs.spec_names end |
#specs ⇒ Bundler::Index
Parses the gemspec files to find the specs for the gems that can be satisfied by the source.
Few important points to keep in mind:
- If the gems are not installed then it shall return specs for all
the gems it can satisfy
- If gem is installed (that is to be detected by the plugin itself)
then it shall return at least the specs that are installed.
- The `loaded_from` for each of the specs shall be correct (it is
used to find the load path)
128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 |
# File 'lib/bundler/plugin/api/source.rb', line 128 def specs files = fetch_gemspec_files Bundler::Index.build do |index| files.each do |file| next unless spec = Bundler.load_gemspec(file) Bundler.rubygems.set_installed_by_version(spec) spec.source = self Bundler.rubygems.validate(spec) index << spec end end end |
#to_lock ⇒ Object
Generates the content to be entered into the lockfile. Saves type and remote and also calls to ‘options_to_lock`.
Plugin should use ‘options_to_lock` to save information in lockfile and not override this.
Note: Do not override if you don’t know what you are doing.
274 275 276 277 278 279 280 281 282 |
# File 'lib/bundler/plugin/api/source.rb', line 274 def to_lock out = String.new("#{LockfileParser::PLUGIN}\n") out << " remote: #{@uri}\n" out << " type: #{@type}\n" .each do |opt, value| out << " #{opt}: #{value}\n" end out << " specs:\n" end |
#to_s ⇒ Object Also known as: identifier
284 285 286 |
# File 'lib/bundler/plugin/api/source.rb', line 284 def to_s "plugin source for #{@type} with uri #{@uri}" end |
#unlock! ⇒ Object
This is called to update the spec and installation.
If the source plugin is loaded from lockfile or otherwise, it shall refresh the cache/specs (e.g. git sources can make a fresh clone).
169 170 |
# File 'lib/bundler/plugin/api/source.rb', line 169 def unlock! end |
#unmet_deps ⇒ Object
Used by definition.
Note: Do not override if you don’t know what you are doing.
244 245 246 |
# File 'lib/bundler/plugin/api/source.rb', line 244 def unmet_deps specs.unmet_dependency_names end |
#uri_hash ⇒ Object
294 295 296 |
# File 'lib/bundler/plugin/api/source.rb', line 294 def uri_hash SharedHelpers.digest(:SHA1).hexdigest(uri) end |