stibium-bundled 0.0.1 → 0.0.6
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- checksums.yaml +4 -4
- data/README.md +129 -0
- data/lib/stibium/bundled.rb +63 -40
- data/lib/stibium/bundled/bundle.rb +101 -13
- data/lib/stibium/bundled/bundle/config.rb +149 -0
- data/lib/stibium/bundled/bundle/config/reader.rb +56 -0
- data/lib/stibium/bundled/bundle/directory.rb +52 -0
- data/lib/stibium/bundled/version.rb +19 -6
- data/lib/stibium/bundled/version.yml +3 -3
- metadata +9 -18
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 3be68fcb9db04232974861f121d822dec6236d7b45a6ed3eec003d1814811e77
|
4
|
+
data.tar.gz: 3962f200a155fe9931eafc6664c3fb1787d6c25378fcd54c45b38b013bf7da5d
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: dc8e6621dabc968957985f69253abae2f02c5909f51c906b8298b1cd4e9ef19ad038a9bab0aa743272f06e59d3baed1bf7155c83ee888762e5ef10e0a5d1a1c4
|
7
|
+
data.tar.gz: '08eb70137990b8174da7d5165c965d45b4c9820d0469ed5601aafecffd1378615aff8f97398e1ac6db75cce28c290cf5d98fa1c6711332ccb75dc715c3d5a7d2'
|
data/README.md
ADDED
@@ -0,0 +1,129 @@
|
|
1
|
+
# ``stibium-bundled`` [][rubygems:stibium-bundled] [](https://codeclimate.com/github/SwagDevOps/stibium-bundled/maintainability)
|
2
|
+
|
3
|
+
This gem is intended to mimic Bundler's behavior and conform to [bundler configuration options][bundler:config].
|
4
|
+
|
5
|
+
``stibium-bundled`` detects ``gems.rb`` and ``gems.locked``
|
6
|
+
(or ``Gemfile`` and ``Gemfile.lock``)
|
7
|
+
and [``bundler/setup``][bundler:setup] (for [standalone][man:install#options] installation).
|
8
|
+
|
9
|
+
``standalone`` makes a bundle that can work __without depending__ on Bundler (or Rubygems) at runtime. Bundler generates
|
10
|
+
a ``bundler/setup.rb`` file to replace Bundler's own setup in the manner required.
|
11
|
+
|
12
|
+
[Configuration settings][bundler:config] are loaded in this order:
|
13
|
+
|
14
|
+
1. Local config (``.bundle/config`` or ``"$BUNDLE_APP_CONFIG/config``)
|
15
|
+
2. Environment variables (``ENV``)
|
16
|
+
3. Global config (``~/.bundle/config``)
|
17
|
+
4. Default config
|
18
|
+
|
19
|
+
## Sample of use
|
20
|
+
|
21
|
+
```ruby
|
22
|
+
# file: lib/awesome_gem.rb
|
23
|
+
|
24
|
+
require 'stibium/bundled'
|
25
|
+
|
26
|
+
module AwesomeGem
|
27
|
+
include(Stibium::Bundled)
|
28
|
+
|
29
|
+
self.bundled_from("#{__dir__}/..", setup: true)
|
30
|
+
end
|
31
|
+
```
|
32
|
+
|
33
|
+
or more concise:
|
34
|
+
|
35
|
+
```ruby
|
36
|
+
# file: lib/awesome_gem.rb
|
37
|
+
|
38
|
+
require 'stibium/bundled'
|
39
|
+
|
40
|
+
module AwesomeGem
|
41
|
+
include(Stibium::Bundled).bundled_from("#{__dir__}/..", setup: true)
|
42
|
+
end
|
43
|
+
```
|
44
|
+
|
45
|
+
or load a gem depending on status:
|
46
|
+
|
47
|
+
```ruby
|
48
|
+
# file: lib/awesome_gem.rb
|
49
|
+
|
50
|
+
require 'stibium/bundled'
|
51
|
+
|
52
|
+
module AwesomeGem
|
53
|
+
include(Stibium::Bundled).bundled_from("#{__dir__}/..", setup: true) do |bundle|
|
54
|
+
if Object.const_defined?(:Gem) and bundle.locked? and bundle.installed?
|
55
|
+
'foo-bar'.tap do |gem_name|
|
56
|
+
unless bundle.specifications.keep_if { |spec| spec.name == gem_name }.empty?
|
57
|
+
require gem_name.gsub('-', '/')
|
58
|
+
end
|
59
|
+
end
|
60
|
+
end
|
61
|
+
end
|
62
|
+
end
|
63
|
+
```
|
64
|
+
|
65
|
+
if ``stibium-bundled`` is not system wide installed, it can be necessary to
|
66
|
+
locate it:
|
67
|
+
|
68
|
+
```ruby
|
69
|
+
# file: lib/awesome_gem.rb
|
70
|
+
|
71
|
+
autoload(:Pathname, 'pathname')
|
72
|
+
autoload(:RbConfig, 'rbconfig')
|
73
|
+
|
74
|
+
module AwesomeGem
|
75
|
+
Pathname.new("#{__dir__}/..").expand_path.yield_self do |basedir|
|
76
|
+
begin
|
77
|
+
require 'stibium/bundled'
|
78
|
+
rescue LoadError
|
79
|
+
[
|
80
|
+
[RUBY_ENGINE, RbConfig::CONFIG.fetch('ruby_version'), 'bundler/gems/*/stibium-bundled.gemspec'],
|
81
|
+
[RUBY_ENGINE, RbConfig::CONFIG.fetch('ruby_version'), 'gems/stibium-bundled-*/lib/'],
|
82
|
+
].map { |parts| basedir.join(*['{**/,}bundle'].concat(parts)) }.yield_self do |patterns|
|
83
|
+
Pathname.glob(patterns).first&.dirname.tap { |gem_dir| require gem_dir.join('lib/stibium/bundled') }
|
84
|
+
end
|
85
|
+
end
|
86
|
+
|
87
|
+
include(::Stibium::Bundled).bundled_from(basedir, setup: true) do |bundle|
|
88
|
+
if bundle.locked? and bundle.installed? and Object.const_defined?(:Gem)
|
89
|
+
require 'fabulous/feature' if bundle.specifications.keep_if { |s| s.name == 'fabulous' }.any?
|
90
|
+
end
|
91
|
+
end
|
92
|
+
end
|
93
|
+
end
|
94
|
+
```
|
95
|
+
|
96
|
+
## Benchmarks
|
97
|
+
|
98
|
+
Using ``Stibium::Bundled`` setup leads to minor overhead compared to direct require for ``bundler/setup``,
|
99
|
+
on the other hand ``Stibium::Bundled`` setup is compatible with standalone's bundler setup without code change.
|
100
|
+
And ``bundle exec`` is known to be [slow][stackoverflow/running-scripts-with-bundle-exec-is-slow].
|
101
|
+
|
102
|
+
Install [hypefine][sharkdp/hyperfine] and run benchmarks:
|
103
|
+
|
104
|
+
```shell
|
105
|
+
rake bench runs=20
|
106
|
+
```
|
107
|
+
|
108
|
+
| Command | Mean [ms] | Min [ms] | Max [ms] | Relative |
|
109
|
+
|:---|---:|---:|---:|---:|
|
110
|
+
| `bundler/setup` | 205.7 ± 7.1 | 200.1 | 232.5 | 1.00 ± 0.05 |
|
111
|
+
| `bundled` | 205.7 ± 6.2 | 196.8 | 222.4 | 1.00 |
|
112
|
+
| `bundle exec` | 559.4 ± 13.0 | 543.2 | 587.8 | 2.72 ± 0.10 |
|
113
|
+
|
114
|
+
## Install
|
115
|
+
|
116
|
+
```sh
|
117
|
+
bundle config set --local clean 'true'
|
118
|
+
bundle config set --local path 'vendor/bundle'
|
119
|
+
bundle install --standalone
|
120
|
+
```
|
121
|
+
|
122
|
+
<!-- hyperlinks -->
|
123
|
+
|
124
|
+
[rubygems:stibium-bundled]: https://rubygems.org/gems/stibium-bundled
|
125
|
+
[bundler:config]: https://bundler.io/v2.2/bundle_config.html
|
126
|
+
[bundler:setup]: https://bundler.io/v1.5/bundler_setup.html
|
127
|
+
[man:install#options]: https://bundler.io/man/bundle-install.1.html#OPTIONS
|
128
|
+
[sharkdp/hyperfine]: https://github.com/sharkdp/hyperfine
|
129
|
+
[stackoverflow/running-scripts-with-bundle-exec-is-slow]: https://stackoverflow.com/questions/13894966/running-scripts-with-bundle-exec-is-slow
|
data/lib/stibium/bundled.rb
CHANGED
@@ -17,72 +17,95 @@ end
|
|
17
17
|
# ```ruby
|
18
18
|
# # file: lib/awesome_gem.rb
|
19
19
|
# module AwesomeGem
|
20
|
-
# Stibium::Bundled
|
20
|
+
# include(Stibium::Bundled)
|
21
21
|
#
|
22
|
-
#
|
23
|
-
# unless bundle.standalone!
|
24
|
-
# require 'bundler/setup' if bundle.locked?
|
25
|
-
# end
|
26
|
-
# end
|
22
|
+
# self.bundled_from("#{__dir__}/..", setup: true)
|
27
23
|
# end
|
28
24
|
# ```
|
29
|
-
#
|
30
|
-
# or:
|
31
|
-
#
|
32
|
-
# ```ruby
|
33
|
-
# # file: lib/awesome_gem.rb
|
34
|
-
# module AwesomeGem
|
35
|
-
# class << self
|
36
|
-
# include(Stibium::Bundled)
|
37
|
-
# end
|
38
|
-
#
|
39
|
-
# self.bundled_from("#{__dir__}/..") do |bundle|
|
40
|
-
# unless bundle.standalone!
|
41
|
-
# require 'bundler/setup' if bundle.locked?
|
42
|
-
# end
|
43
|
-
# end
|
44
|
-
# end
|
45
25
|
module Stibium::Bundled
|
46
26
|
{
|
47
27
|
Bundle: 'bundle',
|
48
28
|
VERSION: 'version',
|
49
29
|
}.each { |k, v| autoload(k, "#{__dir__}/bundled/#{v}") }
|
50
30
|
|
51
|
-
|
52
|
-
|
53
|
-
# @return [Boolean]
|
31
|
+
class << self
|
32
|
+
private
|
54
33
|
|
55
|
-
|
56
|
-
|
34
|
+
# Callback invoked whenever the receiver is included in another module or class.
|
35
|
+
#
|
36
|
+
# @param [Class, Module] othermod
|
37
|
+
#
|
38
|
+
# @see https://ruby-doc.org/core-2.5.3/Module.html#method-i-included
|
39
|
+
def included(othermod)
|
40
|
+
othermod.singleton_class.__send__(:include, self) unless othermod.singleton_class?
|
41
|
+
end
|
42
|
+
end
|
57
43
|
|
58
|
-
#
|
44
|
+
# Denote bundle is locked or standalone.
|
45
|
+
#
|
46
|
+
# @return [Boolean]
|
47
|
+
#
|
48
|
+
# @see .call
|
49
|
+
def bundled?
|
50
|
+
false
|
51
|
+
end
|
52
|
+
|
53
|
+
# @return [Bundle, nil]
|
54
|
+
#
|
55
|
+
# @see .call
|
56
|
+
def bundled
|
57
|
+
nil
|
58
|
+
end
|
59
|
+
|
60
|
+
protected
|
61
|
+
|
62
|
+
# @param basedir [String, Pathname]
|
63
|
+
# @param setup [Boolean, Array<Symbol>]
|
64
|
+
# @param env [Hash{String => String}]
|
65
|
+
# @param ruby_config [Hash{Symbol => Object}]
|
59
66
|
#
|
60
67
|
# @return [Bundle. nil]
|
61
|
-
|
62
|
-
|
63
|
-
|
64
|
-
|
65
|
-
|
68
|
+
#
|
69
|
+
# @see Stibium::Bundled::Bundle#setup
|
70
|
+
def bundled_from(basedir, setup: false, env: ENV.to_h, ruby_config: {})
|
71
|
+
# @type [Stibium::Bundled::Bundle] bundle
|
72
|
+
Stibium::Bundled.call(self, basedir: basedir, env: env, ruby_config: ruby_config).bundled&.tap do |bundle|
|
73
|
+
bundle.__send__(:setup, **{ guards: setup.is_a?(Array) ? setup : nil }.compact) if setup
|
74
|
+
|
75
|
+
yield(bundle) if block_given?
|
76
|
+
end
|
66
77
|
end
|
67
78
|
|
68
79
|
class << self
|
69
80
|
# @param target [Class, Module]
|
70
81
|
# @param basedir [String, Pathname]
|
82
|
+
# @param env [Hash{String => String}]
|
83
|
+
# @param ruby_config [Hash{Symbol => Object}]
|
71
84
|
#
|
72
|
-
# @return [Class, Module]
|
73
|
-
def call(target, basedir:)
|
85
|
+
# @return [Class, Module] given ``Class`` or ``Module``
|
86
|
+
def call(target, basedir:, env: ENV.to_h, ruby_config: nil)
|
74
87
|
target.tap do |t|
|
75
88
|
t.singleton_class.tap do |sc|
|
76
89
|
sc.singleton_class.__send__(:include, self)
|
77
|
-
sc.define_method(:bundled?) { !bundled
|
90
|
+
sc.define_method(:bundled?) { !bundled.nil? }
|
78
91
|
sc.define_method(:bundled) do
|
79
|
-
|
80
|
-
# rubocop:disable Style/TernaryParentheses
|
81
|
-
Bundle.new(basedir).yield_self { |bundle| (bundle.locked? or bundle.standalone?) ? bundle : nil }
|
82
|
-
# rubocop:enable Style/TernaryParentheses
|
92
|
+
Stibium::Bundled.__send__(:bundler).call(basedir, env: env, ruby_config: ruby_config)
|
83
93
|
end
|
84
94
|
end
|
85
95
|
end
|
86
96
|
end
|
97
|
+
|
98
|
+
protected
|
99
|
+
|
100
|
+
# @api private
|
101
|
+
#
|
102
|
+
# @return [Proc]
|
103
|
+
def bundler
|
104
|
+
lambda do |basedir, env:, ruby_config: nil|
|
105
|
+
Bundle.new(basedir, env: env, ruby_config: ruby_config).yield_self do |bundle|
|
106
|
+
bundle.bundled? ? bundle : nil
|
107
|
+
end
|
108
|
+
end
|
109
|
+
end
|
87
110
|
end
|
88
111
|
end
|
@@ -11,19 +11,36 @@ require_relative '../bundled'
|
|
11
11
|
# Describe a bundle.
|
12
12
|
class Stibium::Bundled::Bundle
|
13
13
|
autoload(:Pathname, 'pathname')
|
14
|
+
autoload(:Gem, 'rubygems') # @see .specifications
|
15
|
+
|
16
|
+
{
|
17
|
+
Config: 'config',
|
18
|
+
Directory: 'directory',
|
19
|
+
}.each { |k, v| autoload(k, "#{__dir__}/bundle/#{v}") }
|
14
20
|
|
15
21
|
# @return [Pathname]
|
16
22
|
attr_reader :path
|
17
23
|
|
24
|
+
# @return [Config]
|
25
|
+
attr_reader :config
|
26
|
+
|
27
|
+
# @return [Directory]
|
28
|
+
attr_reader :directory
|
29
|
+
|
18
30
|
# @param path [String, Pathname]
|
31
|
+
# @param env [Hash{String => String}]
|
32
|
+
# @param ruby_config [Hash{Symbol => Object}]
|
19
33
|
#
|
20
34
|
# @raise [Errno::ENOENT]
|
21
35
|
# @raise [ArgumentError] when given ``path`` is not a directory.
|
22
|
-
def initialize(path)
|
36
|
+
def initialize(path, env: ENV.to_h, ruby_config: {})
|
23
37
|
self.tap do
|
24
|
-
@path = Pathname.new(path).realpath.freeze
|
38
|
+
(@path = Pathname.new(path).realpath.freeze).tap do |base_path|
|
39
|
+
raise ArgumentError, 'path is not a directory' unless base_path.directory?
|
40
|
+
end
|
25
41
|
|
26
|
-
|
42
|
+
@config = Config.new(self.path, env: env).freeze
|
43
|
+
@directory = Directory.new(self.bundle_path, ruby_config: ruby_config).freeze
|
27
44
|
end.freeze
|
28
45
|
end
|
29
46
|
|
@@ -38,7 +55,30 @@ class Stibium::Bundled::Bundle
|
|
38
55
|
#
|
39
56
|
# @return [Boolean]
|
40
57
|
def locked?
|
41
|
-
!!gemfiles
|
58
|
+
!!gemfiles&.fetch(1, nil)
|
59
|
+
end
|
60
|
+
|
61
|
+
# Get specifications.
|
62
|
+
#
|
63
|
+
# @see https://docs.ruby-lang.org/en/3.0.0/Gem/Specification.html
|
64
|
+
#
|
65
|
+
# @return [Array<Gem::Specification>]
|
66
|
+
def specifications
|
67
|
+
directory.specifications.map { |file| instance_eval(file.read, file.to_path) }.sort_by(&:name)
|
68
|
+
end
|
69
|
+
|
70
|
+
# Denote install seems to be happened (since specifications are present).
|
71
|
+
#
|
72
|
+
# @return [Boolean]
|
73
|
+
def installed?
|
74
|
+
!directory.specifications.empty?
|
75
|
+
end
|
76
|
+
|
77
|
+
# Denote bundle seems installed by bundler.
|
78
|
+
#
|
79
|
+
# @return [Boolean]
|
80
|
+
def bundled?
|
81
|
+
locked? or standalone?
|
42
82
|
end
|
43
83
|
|
44
84
|
# Get path to gemfile.
|
@@ -47,7 +87,7 @@ class Stibium::Bundled::Bundle
|
|
47
87
|
#
|
48
88
|
# @return [Pathname, nil]
|
49
89
|
def gemfile
|
50
|
-
gemfiles
|
90
|
+
gemfiles&.fetch(0, nil)
|
51
91
|
end
|
52
92
|
|
53
93
|
# Get gemfile files (gemfile + lockfile) or nothing.
|
@@ -67,23 +107,71 @@ class Stibium::Bundled::Bundle
|
|
67
107
|
#
|
68
108
|
# @return [Boolean]
|
69
109
|
def standalone?
|
70
|
-
|
110
|
+
bundler_setup.yield_self { |fp| fp.file? and fp.readable? }
|
71
111
|
end
|
72
112
|
|
73
|
-
|
113
|
+
protected
|
114
|
+
|
115
|
+
# Load standalone setup if present.
|
74
116
|
#
|
75
|
-
# @return [
|
76
|
-
|
117
|
+
# @return [self]
|
118
|
+
#
|
119
|
+
# @raise [Errno::ENOENT, LoadError]
|
120
|
+
def standalone!(&fallback)
|
77
121
|
# noinspection RubyResolve
|
78
|
-
|
122
|
+
require(bundler_setup.realpath)
|
123
|
+
rescue Errno::ENOENT, LoadError => e
|
124
|
+
fallback ? fallback.call(self) : raise(e)
|
125
|
+
ensure
|
126
|
+
self
|
79
127
|
end
|
80
128
|
|
81
|
-
|
129
|
+
# Load standalone setup if present, else fallback to <code>bundler/setup</code>.
|
130
|
+
#
|
131
|
+
# Load Bundler's setup (<code>bundler/setup</code>) when all guards are ``true``,
|
132
|
+
# as a result, default behavior, is to load <code>bundler/setup</code>
|
133
|
+
# only when locked and installed.
|
134
|
+
#
|
135
|
+
# @param guards [Array<Symbol>]
|
136
|
+
#
|
137
|
+
# @return [self]
|
138
|
+
#
|
139
|
+
# @raise [LoadError] when <code>bundle/setup</code> is loaded and bundler is not present.
|
140
|
+
#
|
141
|
+
# @see https://bundler.io/v1.5/bundler_setup.html
|
142
|
+
# @see https://github.com/ruby/ruby/blob/0e40cc9b194a5e46024d32b85a61e651372a65cb/lib/bundler.rb#L139
|
143
|
+
# @see https://github.com/ruby/ruby/blob/0e40cc9b194a5e46024d32b85a61e651372a65cb/lib/bundler/setup.rb
|
144
|
+
# @see https://github.com/ruby/ruby/blob/69ed64949b0c02d4b195809fa104ff23dd100093/lib/bundler.rb#L11
|
145
|
+
# @see https://github.com/ruby/ruby/blob/69ed64949b0c02d4b195809fa104ff23dd100093/lib/bundler/rubygems_integration.rb
|
146
|
+
def setup(guards: [:bundled, :installed])
|
147
|
+
self.tap do
|
148
|
+
unless guards.map { |s| self.public_send('%s?' % s.to_s.gsub(/\?$/, '')) }.include?(false)
|
149
|
+
standalone! { require 'bundler/setup' }
|
150
|
+
end
|
151
|
+
end
|
152
|
+
end
|
153
|
+
|
154
|
+
# @return [Pathname]
|
155
|
+
def bundle_path
|
156
|
+
Pathname.new(config.fetch('BUNDLE_PATH')).yield_self do |bundle_path|
|
157
|
+
(bundle_path.absolute? ? bundle_path : path.join(bundle_path))
|
158
|
+
end
|
159
|
+
end
|
82
160
|
|
161
|
+
# Standalone setup file.
|
162
|
+
#
|
163
|
+
# ``bundle install --standalone[=<list>]`` makes a bundle that can work without depending on
|
164
|
+
# Rubygems or Bundler at runtime.
|
165
|
+
# A space separated list of groups to install has to be specified.
|
166
|
+
# Bundler creates a directory named ``bundle`` and installs the bundle there.
|
167
|
+
# It also generates a ``bundle/bundler/setup.rb`` file to replace Bundler's own setup in the manner required.
|
168
|
+
#
|
83
169
|
# @see #standalone?
|
170
|
+
# @see #standalone!
|
171
|
+
# @see https://bundler.io/v2.2/man/bundle-install.1.html#OPTIONS
|
84
172
|
#
|
85
173
|
# @return [Pathname]
|
86
|
-
def
|
87
|
-
|
174
|
+
def bundler_setup
|
175
|
+
bundle_path.join('bundler/setup.rb')
|
88
176
|
end
|
89
177
|
end
|
@@ -0,0 +1,149 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
# Copyright (C) 2020-2021 Dimitri Arrigoni <dimitri@arrigoni.me>
|
4
|
+
# License GPLv3+: GNU GPL version 3 or later
|
5
|
+
# <http://www.gnu.org/licenses/gpl.html>.
|
6
|
+
# This is free software: you are free to change and redistribute it.
|
7
|
+
# There is NO WARRANTY, to the extent permitted by law.
|
8
|
+
|
9
|
+
require_relative '../bundle'
|
10
|
+
|
11
|
+
# Describe bundler configuration settings.
|
12
|
+
#
|
13
|
+
# Bundler loads configuration settings in this order:
|
14
|
+
#
|
15
|
+
# 1. Local config (``.bundle/config`` or ``$BUNDLE_APP_CONFIG/config``)
|
16
|
+
# 2. Environment variables (``ENV``)
|
17
|
+
# 3. Global config (``~/.bundle/config``)
|
18
|
+
# 4. Bundler default config - PARTIAL support is implemented in ``Config.defaults``
|
19
|
+
#
|
20
|
+
# @note Executing bundle with the ``BUNDLE_IGNORE_CONFIG`` environment set will cause it to ignore all configuration.
|
21
|
+
#
|
22
|
+
# @see https://bundler.io/v2.2/bundle_config.html
|
23
|
+
# @see https://evilmartians.com/chronicles/ruby-on-whales-docker-for-ruby-rails-development
|
24
|
+
# @see .load
|
25
|
+
# @see .read
|
26
|
+
# @see .env
|
27
|
+
# @see .defaults
|
28
|
+
class Stibium::Bundled::Bundle::Config < ::Hash
|
29
|
+
autoload(:Pathname, 'pathname')
|
30
|
+
autoload(:YAML, 'yaml')
|
31
|
+
|
32
|
+
{
|
33
|
+
Reader: 'reader',
|
34
|
+
}.each { |k, v| autoload(k, "#{__dir__}/config/#{v}") }
|
35
|
+
|
36
|
+
# @param basedir [String, Pathname]
|
37
|
+
# @param env [Hash{String => String}]
|
38
|
+
def initialize(basedir, env: ENV.to_h)
|
39
|
+
super().tap do
|
40
|
+
@basedir = Pathname.new(basedir).freeze
|
41
|
+
@env = self.class.__send__(:env, source: env).freeze
|
42
|
+
|
43
|
+
self.class.__send__(:call, self.resolve_file, env: env).each { |k, v| self[k.freeze] = v.freeze }
|
44
|
+
end.freeze
|
45
|
+
end
|
46
|
+
|
47
|
+
# @return [Hash{String => Object}]
|
48
|
+
attr_reader :env
|
49
|
+
|
50
|
+
# @return [Pathname]
|
51
|
+
attr_reader :basedir
|
52
|
+
|
53
|
+
protected
|
54
|
+
|
55
|
+
# Resolve path to local config (depending on ``BUNDLE_APP_CONFIG`` value).
|
56
|
+
#
|
57
|
+
# @return [Pathname]
|
58
|
+
def resolve_file
|
59
|
+
begin
|
60
|
+
'BUNDLE_APP_CONFIG'.yield_self do |k|
|
61
|
+
self.env.fetch(k) { self.class.defaults.fetch(k) }
|
62
|
+
end
|
63
|
+
end.yield_self do |s|
|
64
|
+
Pathname.new(s)
|
65
|
+
end.yield_self do |path|
|
66
|
+
(path.absolute? ? path : basedir.join(path)).join('config')
|
67
|
+
end
|
68
|
+
end
|
69
|
+
|
70
|
+
class << self
|
71
|
+
# Default config values (as seen from an empty environment).
|
72
|
+
#
|
73
|
+
# ```shell
|
74
|
+
# rm -rfv ~/.bundle/config .bundle/config
|
75
|
+
# env -i $(which bundle) install --standalone
|
76
|
+
# cat .bundle/config
|
77
|
+
# ```
|
78
|
+
#
|
79
|
+
# @see Stibium::Bundled::Bundle#bundler_setup
|
80
|
+
def defaults
|
81
|
+
{
|
82
|
+
'BUNDLE_APP_CONFIG' => '.bundle',
|
83
|
+
'BUNDLE_PATH' => 'bundle',
|
84
|
+
}
|
85
|
+
end
|
86
|
+
|
87
|
+
protected
|
88
|
+
|
89
|
+
# Load config.
|
90
|
+
#
|
91
|
+
# @param file [Pathname]
|
92
|
+
# @param env [Hash{String => String}]
|
93
|
+
#
|
94
|
+
# @api private
|
95
|
+
# @see https://bundler.io/v2.2/bundle_config.html
|
96
|
+
#
|
97
|
+
# @return [Hash{String => Object}]
|
98
|
+
def call(file, env: ENV.to_h)
|
99
|
+
# @formatter:off
|
100
|
+
self.defaults # 4. Bundler default config
|
101
|
+
.merge(self.global_config(env: env)) # 3. Global config
|
102
|
+
.merge(self.env(source: env)) # 2. Environmental variables
|
103
|
+
.merge(self.read(file, env: env)) # 1. Local config
|
104
|
+
.sort.map { |k, v| [k.freeze, v.freeze] }.to_h.freeze
|
105
|
+
# @formatter:on
|
106
|
+
end
|
107
|
+
|
108
|
+
# Get global config.
|
109
|
+
#
|
110
|
+
# @api private
|
111
|
+
#
|
112
|
+
# @param env [Hash{String => String}]
|
113
|
+
#
|
114
|
+
# @return [Hash{String => Object}]
|
115
|
+
def global_config(env: ENV.to_h)
|
116
|
+
env['HOME'].yield_self do |home_path|
|
117
|
+
return {} if home_path.nil?
|
118
|
+
|
119
|
+
Pathname.new(home_path).expand_path.join('.bundle/config').yield_self { |file| self.read(file, env: env) }
|
120
|
+
end
|
121
|
+
end
|
122
|
+
|
123
|
+
# Get bundler related environment variables (``/^BUNDLE_.+/``)
|
124
|
+
#
|
125
|
+
# @param source [Hash{String => String}]
|
126
|
+
#
|
127
|
+
# @api private
|
128
|
+
#
|
129
|
+
# @return [Hash{String => Object}]
|
130
|
+
def env(source: ENV.to_h)
|
131
|
+
source.dup.keep_if { |k, _| /^BUNDLE_.+/ =~ k }
|
132
|
+
.transform_keys(&:freeze)
|
133
|
+
.transform_values { |v| (v.is_a?(String) ? YAML.safe_load(v) : v).freeze }
|
134
|
+
.sort.to_h
|
135
|
+
end
|
136
|
+
|
137
|
+
# Read given config file.
|
138
|
+
#
|
139
|
+
# @api private
|
140
|
+
#
|
141
|
+
# @param file [Pathname]
|
142
|
+
# @param env [Hash{String => String}]
|
143
|
+
#
|
144
|
+
# @return [Hash{String => Object}]
|
145
|
+
def read(file, env: ENV.to_h)
|
146
|
+
Reader.new(env: env).read(file)
|
147
|
+
end
|
148
|
+
end
|
149
|
+
end
|
@@ -0,0 +1,56 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
# Copyright (C) 2020-2021 Dimitri Arrigoni <dimitri@arrigoni.me>
|
4
|
+
# License GPLv3+: GNU GPL version 3 or later
|
5
|
+
# <http://www.gnu.org/licenses/gpl.html>.
|
6
|
+
# This is free software: you are free to change and redistribute it.
|
7
|
+
# There is NO WARRANTY, to the extent permitted by law.
|
8
|
+
|
9
|
+
require_relative '../config'
|
10
|
+
|
11
|
+
# Config file reader.
|
12
|
+
class Stibium::Bundled::Bundle::Config::Reader
|
13
|
+
autoload(:YAML, 'yaml')
|
14
|
+
|
15
|
+
# @return [Hash{String => String}]
|
16
|
+
attr_reader :env
|
17
|
+
|
18
|
+
def initialize(env: ENV.to_h)
|
19
|
+
self.tap do
|
20
|
+
@env = env.dup.map { |k, v| [k.freeze, v.freeze] }.to_h.freeze
|
21
|
+
end.freeze
|
22
|
+
end
|
23
|
+
|
24
|
+
# @return [Boolean]
|
25
|
+
def ignore_config?
|
26
|
+
env.key?('BUNDLE_IGNORE_CONFIG')
|
27
|
+
end
|
28
|
+
|
29
|
+
# Read given config file.
|
30
|
+
#
|
31
|
+
# @param file [Pathname]
|
32
|
+
#
|
33
|
+
# @return [Hash{String => Object}]
|
34
|
+
def read(file)
|
35
|
+
scrutinize(file).transform_values { |v| v.is_a?(String) ? YAML.safe_load(v) : v }
|
36
|
+
end
|
37
|
+
|
38
|
+
protected
|
39
|
+
|
40
|
+
# @api private
|
41
|
+
#
|
42
|
+
# @param file [Pathname]
|
43
|
+
#
|
44
|
+
# @raise [RuntimeError]
|
45
|
+
# @return [Hash{String => Object}]
|
46
|
+
def scrutinize(file)
|
47
|
+
return {} if ignore_config?
|
48
|
+
|
49
|
+
return {} unless file.file? and file.readable?
|
50
|
+
|
51
|
+
file.read
|
52
|
+
.yield_self { |content| YAML.safe_load(content) }
|
53
|
+
.yield_self { |result| result.nil? ? {} : result }
|
54
|
+
.tap { |result| raise RuntimeError, "Hash expected, got #{result.class}" unless result.is_a?(Hash) }
|
55
|
+
end
|
56
|
+
end
|
@@ -0,0 +1,52 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
# Copyright (C) 2020-2021 Dimitri Arrigoni <dimitri@arrigoni.me>
|
4
|
+
# License GPLv3+: GNU GPL version 3 or later
|
5
|
+
# <http://www.gnu.org/licenses/gpl.html>.
|
6
|
+
# This is free software: you are free to change and redistribute it.
|
7
|
+
# There is NO WARRANTY, to the extent permitted by law.
|
8
|
+
|
9
|
+
require_relative '../bundle'
|
10
|
+
|
11
|
+
# Describe vendor directory.
|
12
|
+
class Stibium::Bundled::Bundle::Directory
|
13
|
+
autoload(:RbConfig, 'rbconfig')
|
14
|
+
autoload(:Pathname, 'pathname')
|
15
|
+
|
16
|
+
# @return [Pathname]
|
17
|
+
attr_reader :path
|
18
|
+
|
19
|
+
# @param path [String, Pathname]
|
20
|
+
# @param ruby_config [Hash{Symbol => Object}]
|
21
|
+
def initialize(path, ruby_config: {})
|
22
|
+
@path = Pathname.new(path).expand_path.freeze
|
23
|
+
@ruby_config = {
|
24
|
+
engine: RUBY_ENGINE,
|
25
|
+
version: RbConfig::CONFIG['ruby_version'],
|
26
|
+
}.merge(ruby_config.to_h)
|
27
|
+
end
|
28
|
+
|
29
|
+
# @return [String]
|
30
|
+
def to_path
|
31
|
+
path.to_path
|
32
|
+
end
|
33
|
+
|
34
|
+
alias to_s to_path
|
35
|
+
|
36
|
+
# @return [Array<Pathname>]
|
37
|
+
def specifications
|
38
|
+
[
|
39
|
+
[ruby_config.fetch(:engine), ruby_config.fetch(:version), 'specifications', '*.gemspec'],
|
40
|
+
[ruby_config.fetch(:engine), ruby_config.fetch(:version), 'bundler', 'gems', '*/*.gemspec'],
|
41
|
+
].map do |parts|
|
42
|
+
self.path.join(*parts).yield_self do |s|
|
43
|
+
Dir.glob(s).sort.map { |fp| Pathname.new(fp) }.keep_if(&:file?)
|
44
|
+
end
|
45
|
+
end.flatten.sort
|
46
|
+
end
|
47
|
+
|
48
|
+
protected
|
49
|
+
|
50
|
+
# @return [Hash{Symbol => Object}]
|
51
|
+
attr_reader :ruby_config
|
52
|
+
end
|
@@ -7,11 +7,24 @@
|
|
7
7
|
# There is NO WARRANTY, to the extent permitted by law.
|
8
8
|
|
9
9
|
require_relative '../bundled'
|
10
|
-
require 'kamaze/version'
|
11
10
|
|
12
|
-
|
13
|
-
|
14
|
-
|
15
|
-
|
16
|
-
|
11
|
+
Stibium::Bundled.instance_eval do
|
12
|
+
autoload(:YAML, 'yaml')
|
13
|
+
autoload(:Pathname, 'pathname')
|
14
|
+
|
15
|
+
Pathname.new(__dir__).join('version.yml').tap do |file|
|
16
|
+
YAML.safe_load(file.read).yield_self do |v|
|
17
|
+
%w[major minor patch].map { |key| v.fetch(key) }.join('.')
|
18
|
+
end.tap do |version|
|
19
|
+
lambda do
|
20
|
+
require 'kamaze/version'
|
21
|
+
rescue LoadError
|
22
|
+
# :nocov:
|
23
|
+
version
|
24
|
+
# :nocov:
|
25
|
+
else
|
26
|
+
Kamaze::Version.new.freeze
|
27
|
+
end.tap { |func| self.const_set(:VERSION, func.call) }
|
28
|
+
end
|
29
|
+
end
|
17
30
|
end
|
@@ -1,12 +1,12 @@
|
|
1
1
|
---
|
2
2
|
major: 0
|
3
3
|
minor: 0
|
4
|
-
patch:
|
4
|
+
patch: 6
|
5
5
|
authors: ['Dimitri Arrigoni']
|
6
6
|
email: 'dimitri@arrigoni.me'
|
7
|
-
date: '2021-
|
7
|
+
date: '2021-02-22'
|
8
8
|
summary: 'Denote bundle state'
|
9
|
-
description: 'Denote bundle state
|
9
|
+
description: 'Denote bundle state and (optionally) load bundler/setup according to the configuration.'
|
10
10
|
homepage: 'https://github.com/SwagDevOps/stibium-bundled'
|
11
11
|
licenses: ['GPL-3.0']
|
12
12
|
license_header: |
|
metadata
CHANGED
@@ -1,39 +1,30 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: stibium-bundled
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.0.
|
4
|
+
version: 0.0.6
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Dimitri Arrigoni
|
8
8
|
autorequire:
|
9
9
|
bindir: bin
|
10
10
|
cert_chain: []
|
11
|
-
date: 2021-
|
12
|
-
dependencies:
|
13
|
-
|
14
|
-
|
15
|
-
requirement: !ruby/object:Gem::Requirement
|
16
|
-
requirements:
|
17
|
-
- - "~>"
|
18
|
-
- !ruby/object:Gem::Version
|
19
|
-
version: '1.0'
|
20
|
-
type: :runtime
|
21
|
-
prerelease: false
|
22
|
-
version_requirements: !ruby/object:Gem::Requirement
|
23
|
-
requirements:
|
24
|
-
- - "~>"
|
25
|
-
- !ruby/object:Gem::Version
|
26
|
-
version: '1.0'
|
27
|
-
description: Denote bundle state, based on conventions.
|
11
|
+
date: 2021-02-22 00:00:00.000000000 Z
|
12
|
+
dependencies: []
|
13
|
+
description: Denote bundle state and (optionally) load bundler/setup according to
|
14
|
+
the configuration.
|
28
15
|
email: dimitri@arrigoni.me
|
29
16
|
executables: []
|
30
17
|
extensions: []
|
31
18
|
extra_rdoc_files: []
|
32
19
|
files:
|
33
20
|
- ".yardopts"
|
21
|
+
- README.md
|
34
22
|
- lib/stibium-bundled.rb
|
35
23
|
- lib/stibium/bundled.rb
|
36
24
|
- lib/stibium/bundled/bundle.rb
|
25
|
+
- lib/stibium/bundled/bundle/config.rb
|
26
|
+
- lib/stibium/bundled/bundle/config/reader.rb
|
27
|
+
- lib/stibium/bundled/bundle/directory.rb
|
37
28
|
- lib/stibium/bundled/version.rb
|
38
29
|
- lib/stibium/bundled/version.yml
|
39
30
|
homepage: https://github.com/SwagDevOps/stibium-bundled
|