bootsnap 1.4.5 → 1.16.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (48) hide show
  1. checksums.yaml +4 -4
  2. data/CHANGELOG.md +227 -0
  3. data/LICENSE.txt +1 -1
  4. data/README.md +57 -20
  5. data/exe/bootsnap +5 -0
  6. data/ext/bootsnap/bootsnap.c +301 -155
  7. data/ext/bootsnap/extconf.rb +22 -14
  8. data/lib/bootsnap/bundler.rb +2 -0
  9. data/lib/bootsnap/cli/worker_pool.rb +136 -0
  10. data/lib/bootsnap/cli.rb +281 -0
  11. data/lib/bootsnap/compile_cache/iseq.rb +64 -19
  12. data/lib/bootsnap/compile_cache/json.rb +93 -0
  13. data/lib/bootsnap/compile_cache/yaml.rb +333 -42
  14. data/lib/bootsnap/compile_cache.rb +26 -8
  15. data/lib/bootsnap/explicit_require.rb +5 -3
  16. data/lib/bootsnap/load_path_cache/cache.rb +65 -37
  17. data/lib/bootsnap/load_path_cache/change_observer.rb +19 -3
  18. data/lib/bootsnap/load_path_cache/core_ext/kernel_require.rb +28 -83
  19. data/lib/bootsnap/load_path_cache/core_ext/loaded_features.rb +2 -0
  20. data/lib/bootsnap/load_path_cache/loaded_features_index.rb +63 -29
  21. data/lib/bootsnap/load_path_cache/path.rb +42 -19
  22. data/lib/bootsnap/load_path_cache/path_scanner.rb +60 -29
  23. data/lib/bootsnap/load_path_cache/store.rb +64 -23
  24. data/lib/bootsnap/load_path_cache.rb +31 -38
  25. data/lib/bootsnap/setup.rb +3 -36
  26. data/lib/bootsnap/version.rb +3 -1
  27. data/lib/bootsnap.rb +127 -36
  28. metadata +15 -99
  29. data/.github/CODEOWNERS +0 -2
  30. data/.github/probots.yml +0 -2
  31. data/.gitignore +0 -17
  32. data/.rubocop.yml +0 -20
  33. data/.travis.yml +0 -21
  34. data/CODE_OF_CONDUCT.md +0 -74
  35. data/CONTRIBUTING.md +0 -21
  36. data/Gemfile +0 -8
  37. data/README.jp.md +0 -231
  38. data/Rakefile +0 -12
  39. data/bin/ci +0 -10
  40. data/bin/console +0 -14
  41. data/bin/setup +0 -8
  42. data/bin/test-minimal-support +0 -7
  43. data/bin/testunit +0 -8
  44. data/bootsnap.gemspec +0 -45
  45. data/dev.yml +0 -10
  46. data/lib/bootsnap/load_path_cache/core_ext/active_support.rb +0 -106
  47. data/lib/bootsnap/load_path_cache/realpath_cache.rb +0 -32
  48. data/shipit.rubygems.yml +0 -0
data/.gitignore DELETED
@@ -1,17 +0,0 @@
1
- /.bundle/
2
- /.yardoc
3
- /Gemfile.lock
4
- /_yardoc/
5
- /coverage/
6
- /doc/
7
- /pkg/
8
- /spec/reports/
9
- /tmp/
10
- *.bundle
11
- *.so
12
- *.o
13
- *.a
14
- *.gem
15
- *.db
16
- mkmf.log
17
- .rubocop-*
data/.rubocop.yml DELETED
@@ -1,20 +0,0 @@
1
- inherit_from:
2
- - http://shopify.github.io/ruby-style-guide/rubocop.yml
3
-
4
- AllCops:
5
- Exclude:
6
- - 'vendor/**/*'
7
- - 'tmp/**/*'
8
- TargetRubyVersion: '2.2'
9
-
10
- # This doesn't take into account retrying from an exception
11
- Lint/HandleExceptions:
12
- Enabled: false
13
-
14
- # allow String.new to create mutable strings
15
- Style/EmptyLiteral:
16
- Enabled: false
17
-
18
- # allow the use of globals which makes sense in a CLI app like this
19
- Style/GlobalVars:
20
- Enabled: false
data/.travis.yml DELETED
@@ -1,21 +0,0 @@
1
- language: ruby
2
- sudo: false
3
-
4
- os:
5
- - linux
6
- - osx
7
-
8
- rvm:
9
- - ruby-2.4
10
- - ruby-2.5
11
- - ruby-head
12
-
13
- matrix:
14
- allow_failures:
15
- - rvm: ruby-head
16
- include:
17
- - rvm: jruby
18
- os: linux
19
- env: MINIMAL_SUPPORT=1
20
-
21
- script: bin/ci
data/CODE_OF_CONDUCT.md DELETED
@@ -1,74 +0,0 @@
1
- # Contributor Covenant Code of Conduct
2
-
3
- ## Our Pledge
4
-
5
- In the interest of fostering an open and welcoming environment, we as
6
- contributors and maintainers pledge to making participation in our project and
7
- our community a harassment-free experience for everyone, regardless of age, body
8
- size, disability, ethnicity, gender identity and expression, level of experience,
9
- nationality, personal appearance, race, religion, or sexual identity and
10
- orientation.
11
-
12
- ## Our Standards
13
-
14
- Examples of behavior that contributes to creating a positive environment
15
- include:
16
-
17
- * Using welcoming and inclusive language
18
- * Being respectful of differing viewpoints and experiences
19
- * Gracefully accepting constructive criticism
20
- * Focusing on what is best for the community
21
- * Showing empathy towards other community members
22
-
23
- Examples of unacceptable behavior by participants include:
24
-
25
- * The use of sexualized language or imagery and unwelcome sexual attention or
26
- advances
27
- * Trolling, insulting/derogatory comments, and personal or political attacks
28
- * Public or private harassment
29
- * Publishing others' private information, such as a physical or electronic
30
- address, without explicit permission
31
- * Other conduct which could reasonably be considered inappropriate in a
32
- professional setting
33
-
34
- ## Our Responsibilities
35
-
36
- Project maintainers are responsible for clarifying the standards of acceptable
37
- behavior and are expected to take appropriate and fair corrective action in
38
- response to any instances of unacceptable behavior.
39
-
40
- Project maintainers have the right and responsibility to remove, edit, or
41
- reject comments, commits, code, wiki edits, issues, and other contributions
42
- that are not aligned to this Code of Conduct, or to ban temporarily or
43
- permanently any contributor for other behaviors that they deem inappropriate,
44
- threatening, offensive, or harmful.
45
-
46
- ## Scope
47
-
48
- This Code of Conduct applies both within project spaces and in public spaces
49
- when an individual is representing the project or its community. Examples of
50
- representing a project or community include using an official project e-mail
51
- address, posting via an official social media account, or acting as an appointed
52
- representative at an online or offline event. Representation of a project may be
53
- further defined and clarified by project maintainers.
54
-
55
- ## Enforcement
56
-
57
- Instances of abusive, harassing, or otherwise unacceptable behavior may be
58
- reported by contacting the project team at burke@libbey.me. All
59
- complaints will be reviewed and investigated and will result in a response that
60
- is deemed necessary and appropriate to the circumstances. The project team is
61
- obligated to maintain confidentiality with regard to the reporter of an incident.
62
- Further details of specific enforcement policies may be posted separately.
63
-
64
- Project maintainers who do not follow or enforce the Code of Conduct in good
65
- faith may face temporary or permanent repercussions as determined by other
66
- members of the project's leadership.
67
-
68
- ## Attribution
69
-
70
- This Code of Conduct is adapted from the [Contributor Covenant][homepage], version 1.4,
71
- available at [http://contributor-covenant.org/version/1/4][version]
72
-
73
- [homepage]: http://contributor-covenant.org
74
- [version]: http://contributor-covenant.org/version/1/4/
data/CONTRIBUTING.md DELETED
@@ -1,21 +0,0 @@
1
- # Contributing to Bootsnap
2
-
3
- We love receiving pull requests!
4
-
5
- ## Standards
6
-
7
- * PR should explain what the feature does, and why the change exists.
8
- * PR should include any carrier specific documentation explaining how it works.
9
- * Code _must_ be tested, including both unit and remote tests where applicable.
10
- * Be consistent. Write clean code that follows [Ruby community standards](https://github.com/bbatsov/ruby-style-guide).
11
- * Code should be generic and reusable.
12
-
13
- If you're stuck, ask questions!
14
-
15
- ## How to contribute
16
-
17
- 1. Fork it ( https://github.com/Shopify/bootsnap/fork )
18
- 2. Create your feature branch (`git checkout -b my-new-feature`)
19
- 3. Commit your changes (`git commit -am 'Add some feature'`)
20
- 4. Push to the branch (`git push origin my-new-feature`)
21
- 5. Create a new Pull Request
data/Gemfile DELETED
@@ -1,8 +0,0 @@
1
- source 'https://rubygems.org'
2
-
3
- # Specify your gem's dependencies in bootsnap.gemspec
4
- gemspec
5
-
6
- group :development do
7
- gem 'rubocop'
8
- end
data/README.jp.md DELETED
@@ -1,231 +0,0 @@
1
- # Bootsnap [![Build Status](https://travis-ci.org/Shopify/bootsnap.svg?branch=master)](https://travis-ci.org/Shopify/bootsnap)
2
-
3
- Bootsnap は RubyVM におけるバイトコード生成やファイルルックアップ等の時間のかかる処理を最適化するためのライブラリです。ActiveSupport や YAML もサポートしています。[内部動作](#内部動作)もご覧ください。
4
-
5
- 注意書き: このライブラリは英語話者によって管理されています。この README は日本語ですが、日本語でのサポートはしておらず、リクエストにお答えすることもできません。バイリンガルの方がサポートをサポートしてくださる場合はお知らせください!:)
6
-
7
- ### パフォーマンス
8
-
9
- * [Discourse](https://github.com/discourse/discourse) では、約6秒から3秒まで、約50%の起動時間短縮が確認されています。
10
- * 小さなアプリケーションでも、50%の改善(3.6秒から1.8秒)が確認されています。
11
- * 非常に巨大でモノリシックなアプリである Shopify のプラットフォームでは、約25秒から6.5秒へと約75%短縮されました。
12
-
13
- ## 使用方法
14
-
15
- この gem は macOS と Linux で作動します。まずは、`bootsnap` を `Gemfile` に追加します:
16
-
17
- ```ruby
18
- gem 'bootsnap', require: false
19
- ```
20
-
21
- Rails を使用している場合は、以下のコードを、`config/boot.rb` 内にある `require 'bundler/setup'` の直後に追加してください。
22
-
23
- ```ruby
24
- require 'bootsnap/setup'
25
- ```
26
-
27
- 単に `gem 'bootsnap', require: 'bootsnap/setup'` と指定することも技術的には可能ですが、最大限のパフォーマンス改善を得るためには Bootsnap をできるだけ早く読み込むことが重要です。
28
-
29
- この require の仕組みは[こちら](https://github.com/Shopify/bootsnap/blob/master/lib/bootsnap/setup.rb)で確認できます。
30
-
31
- Rails を使用していない場合、または、より多くの設定を変更したい場合は、以下のコードを `require 'bundler/setup'` の直後に追加してください(早く読み込まれるほど、より多くのものを最適化することができます)。
32
-
33
- ```ruby
34
- require 'bootsnap'
35
- env = ENV['RAILS_ENV'] || "development"
36
- Bootsnap.setup(
37
-  cache_dir:           'tmp/cache',         # キャッシュファイルを保存する path
38
-  development_mode:     env == 'development', # 現在の作業環境、例えば RACK_ENV, RAILS_ENV など。
39
- load_path_cache: true, # キャッシュで LOAD_PATH を最適化する。
40
-  autoload_paths_cache: true,                 # キャッシュで ActiveSupport による autoload を行う。
41
-  disable_trace:       true,                 # (アルファ) `RubyVM::InstructionSequence.compile_option = { trace_instruction: false }`をセットする。
42
-  compile_cache_iseq:   true,                 # ISeq キャッシュをコンパイルする
43
-  compile_cache_yaml:   true                 # YAML キャッシュをコンパイルする
44
- )
45
- ```
46
-
47
- **ヒント**: `require 'bootsnap'` を `BootLib::Require.from_gem('bootsnap', 'bootsnap')` で、 [こちらのトリック](https://github.com/Shopify/bootsnap/wiki/Bootlib::Require)を使って置き換えることができます。こうすると、巨大な`$LOAD_PATH`がある場合でも、起動時間を最短化するのに役立ちます。
48
-
49
- 注意: Bootsnap と [Spring](https://github.com/rails/spring) は別領域の問題を扱うツールです。Bootsnap は個々のソースファイルの読み込みを高速化します。一方で、Spring は起動されたRailsプロセスのコピーを保持して次回の起動時に起動プロセスの一部を完全にスキップします。2つのツールはうまく連携しており、どちらも新しく生成された Rails アプリケーションにデフォルトで含まれています。
50
-
51
- ### 環境
52
- Bootsnapのすべての機能はセットアップ時の設定に従って開発、テスト、プロダクション、および他のすべての環境で有効化されます。Shopify では、この gem を問題なくすべての環境で安全に使用しています。
53
-
54
- 特定の環境で機能を無効にする場合は、必要に応じて適切な ENV 変数または設定を考慮して設定を変更することをおすすめします。
55
-
56
- ## 内部動作
57
-
58
- Bootsnap は、処理に時間のかかるメソッドの結果をキャッシュすることで最適化しています。これは、大きく分けて2つのカテゴリに分けられます。
59
-
60
- * [Path Pre-Scanning](#path-pre-scanning)
61
- * `Kernel#require` と `Kernel#load` を `$LOAD_PATH` フルスキャンを行わないように変更します。
62
- * `ActiveSupport::Dependencies.{autoloadable_module?,load_missing_constant,depend_on}` を `ActiveSupport::Dependencies.autoload_paths` のフルスキャンを行わないようにオーバーライドします。
63
- * [Compilation caching](#compilation-caching)
64
- * Ruby バイトコードのコンパイル結果をキャッシュするためのメソッド `RubyVM::InstructionSequence.load_iseq` が実装されています。
65
- * `YAML.load_file` を YAML オブジェクトのロード結果を MessagePack でキャッシュするように変更します。 MessagePack でサポートされていないタイプが使われている場合は Marshal が使われます。
66
-
67
- ### Path Pre-Scanning
68
-
69
- _(このライブラリは [bootscale](https://github.com/byroot/bootscale) という別のライブラリを元に開発されました)_
70
-
71
- Bootsnap の初期化時、あるいはパス(例えば、`$LOAD_PATH`)の変更時に、`Bootsnap::LoadPathCache` がキャッシュから必要なエントリーのリストを読み込みます。または、必要に応じてフルスキャンを実行し結果をキャッシュします。
72
- その後、たとえば `require 'foo'` を評価する場合, Ruby は `$LOAD_PATH` `['x', 'y', ...]` のすべてのエントリーを繰り返し評価することで `x/foo.rb`, `y/foo.rb` などを探索します。これに対して Bootsnap は、キャッシュされた require 可能なファイルと `$LOAD_PATH` を見ることで、Rubyが最終的に選択するであろうパスで置き換えます。
73
-
74
- この動作によって生成された syscall を見ると、最終的な結果は以前なら次のようになります。
75
-
76
- ```
77
- open x/foo.rb # (fail)
78
- # (imagine this with 500 $LOAD_PATH entries instead of two)
79
- open y/foo.rb # (success)
80
- close y/foo.rb
81
- open y/foo.rb
82
- ...
83
- ```
84
-
85
- これが、次のようになります:
86
-
87
- ```
88
- open y/foo.rb
89
- ...
90
- ```
91
-
92
- `autoload_paths_cache` オプションが `Bootsnap.setup` に与えられている場合、`ActiveSupport::Dependencies.autoload_paths` をトラバースする方法にはまったく同じ最適化が使用されます。
93
-
94
- `*_path_cache` を機能させるオーバーライドを図にすると、次のようになります。
95
-
96
- ![Bootsnapの説明図](https://cloud.githubusercontent.com/assets/3074765/24532120/eed94e64-158b-11e7-9137-438d759b2ac8.png)
97
-
98
- Bootsnap は、 `$LOAD_PATH` エントリを安定エントリと不安定エントリの2つのカテゴリに分類します。不安定エントリはアプリケーションが起動するたびにスキャンされ、そのキャッシュは30秒間だけ有効になります。安定エントリーに期限切れはありません。コンテンツがスキャンされると、決して変更されないものとみなされます。
99
-
100
- 安定していると考えられる唯一のディレクトリは、Rubyのインストールプレフィックス (`RbConfig::CONFIG['prefix']`, または `/usr/local/ruby` や `~/.rubies/x.y.z`)下にあるものと、`Gem.path` (たとえば `~/.gem/ruby/x.y.z`) や `Bundler.bundle_path` 下にあるものです。他のすべては不安定エントリと分類されます。
101
-
102
- [`Bootsnap::LoadPathCache::Cache`](https://github.com/Shopify/bootsnap/blob/master/lib/bootsnap/load_path_cache/cache.rb) に加えて次の図では、エントリの解決がどのように機能するかを理解するのに役立つかもしれません。経路探索は以下のようになります。
103
-
104
- ![パス探索の仕組み](https://cloud.githubusercontent.com/assets/3074765/25388270/670b5652-299b-11e7-87fb-975647f68981.png)
105
-
106
- また、`LoadError` のスキャンがどれほど重いかに注意を払うことも大切です。もし Ruby が `require 'something'` を評価し、そのファイルが `$LOAD_PATH` にない場合は、それを知るために `2 * $LOAD_PATH.length` のファイルシステムアスセスが必要になります。Bootsnap は、ファイルシステムにまったく触れずに `LoadError` を投げ、この結果をキャッシュします。
107
-
108
- ## Compilation Caching
109
-
110
- *(このコンセプトのより分かりやすい解説は [yomikomu](https://github.com/ko1/yomikomu) をお読み下さい。)*
111
-
112
- Ruby には複雑な文法が実装されており、構文解析は簡単なオペレーションではありません。1.9以降、Ruby は Ruby ソースを内部のバイトコードに変換した後、Ruby VM によって実行してきました。2.3.0 以降、[RubyはAPIを公開し](https://ruby-doc.org/core-2.3.0/RubyVM/InstructionSequence.html)、そのバイトコードをキャッシュすることができるようになりました。これにより、同じファイルが複数ロードされた時の、比較的時間のかかる部分をバイパスすることができます。
113
-
114
- また、アプリケーションの起動時に YAML ドキュメントの読み込みに多くの時間を費やしていることを発見しました。そして、 MessagePack と Marshal は deserialization にあたって YAML よりもはるかに高速であるということに気付きました。そこで、YAML ドキュメントを、Ruby バイトコードと同じコンパイルキャッシングの最適化を施すことで、高速化しています。Ruby の "バイトコード" フォーマットに相当するものは MessagePack ドキュメント (あるいは、MessagePack をサポートしていないタイプの YAML ドキュメントの場合は、Marshal stream)になります。
115
-
116
- これらのコンパイル結果は、入力ファイル(FNV1a-64)のフルパスのハッシュを取って生成されたファイル名で、キャッシュディレクトリに保存されます。
117
-
118
- Bootsnap 無しでは、ファイルを `require` するために生成された syscall の順序は次のようになっていました:
119
-
120
- ```
121
- open /c/foo.rb -> m
122
- fstat64 m
123
- close m
124
- open /c/foo.rb -> o
125
- fstat64 o
126
- fstat64 o
127
- read o
128
- read o
129
- ...
130
- close o
131
- ```
132
-
133
- しかし Bootsnap では、次のようになります:
134
-
135
- ```
136
- open /c/foo.rb -> n
137
- fstat64 n
138
- close n
139
- open /c/foo.rb -> n
140
- fstat64 n
141
- open (cache) -> m
142
- read m
143
- read m
144
- close m
145
- close n
146
- ```
147
-
148
- これは一見劣化していると思われるかもしれませんが、性能に大きな違いがあります。
149
-
150
- *(両方のリストの最初の3つの syscalls -- `open`, `fstat64`, `close` -- は本質的に有用ではありません。[このRubyパッチ](https://bugs.ruby-lang.org/issues/13378)は、Boosnap と組み合わせることによって、それらを最適化しています)*
151
-
152
- Bootsnap は、64バイトのヘッダーとそれに続くキャッシュの内容を含んだキャッシュファイルを書き込みます。ヘッダーは、次のいくつかのフィールドで構成されるキャッシュキーです。
153
-
154
- - `version`、Bootsnapにハードコードされる基本的なスキーマのバージョン
155
- - `os_version`、(macOS, BSDの) 現在のカーネルバージョンか 、(Linuxの) glibc のバージョンのハッシュ
156
- - `compile_option`、`RubyVM::InstructionSequence.compile_option` の返り値
157
- - `ruby_revision`、コンパイルされたRubyのバージョン
158
- - `size`、ソースファイルのサイズ
159
- - `mtime`、コンパイル時のソースファイルの最終変更タイムスタンプ
160
- - `data_size`、バッファに読み込む必要のあるヘッダーに続くバイト数。
161
-
162
- キーが有効な場合、キャッシュがファイルからロードされます。そうでない場合、キャッシュは再生成され、現在のキャッシュを破棄します。
163
-
164
- # 最終的なキャッシュ結果
165
-
166
- 次のファイル構造があるとします。
167
-
168
- ```
169
- /
170
- ├── a
171
- ├── b
172
- └── c
173
- └── foo.rb
174
- ```
175
-
176
- そして、このような `$LOAD_PATH` があるとします。
177
-
178
- ```
179
- ["/a", "/b", "/c"]
180
- ```
181
-
182
- Bootsnap なしで `require 'foo'` を呼び出すと、Ruby は次の順序で syscalls を生成します:
183
-
184
- ```
185
- open /a/foo.rb -> -1
186
- open /b/foo.rb -> -1
187
- open /c/foo.rb -> n
188
- close n
189
- open /c/foo.rb -> m
190
- fstat64 m
191
- close m
192
- open /c/foo.rb -> o
193
- fstat64 o
194
- fstat64 o
195
- read o
196
- read o
197
- ...
198
- close o
199
- ```
200
-
201
- しかし Bootsnap では、次のようになります:
202
-
203
- ```
204
- open /c/foo.rb -> n
205
- fstat64 n
206
- close n
207
- open /c/foo.rb -> n
208
- fstat64 n
209
- open (cache) -> m
210
- read m
211
- read m
212
- close m
213
- close n
214
- ```
215
-
216
- Bootsnap なしで `require 'nope'` を呼び出すと、次のようになります:
217
-
218
- ```
219
- open /a/nope.rb -> -1
220
- open /b/nope.rb -> -1
221
- open /c/nope.rb -> -1
222
- open /a/nope.bundle -> -1
223
- open /b/nope.bundle -> -1
224
- open /c/nope.bundle -> -1
225
- ```
226
-
227
- ...そして、Bootsnap で `require 'nope'` を呼び出すと、次のようになります...
228
-
229
- ```
230
- # (nothing!)
231
- ```
data/Rakefile DELETED
@@ -1,12 +0,0 @@
1
- require('rake/extensiontask')
2
- require('bundler/gem_tasks')
3
-
4
- gemspec = Gem::Specification.load('bootsnap.gemspec')
5
- Rake::ExtensionTask.new do |ext|
6
- ext.name = 'bootsnap'
7
- ext.ext_dir = 'ext/bootsnap'
8
- ext.lib_dir = 'lib/bootsnap'
9
- ext.gem_spec = gemspec
10
- end
11
-
12
- task(default: :compile)
data/bin/ci DELETED
@@ -1,10 +0,0 @@
1
- #!/bin/bash
2
-
3
- set -euxo pipefail
4
-
5
- if [[ "${MINIMAL_SUPPORT-0}" -eq 1 ]]; then
6
- exec bin/test-minimal-support
7
- else
8
- rake
9
- exec bin/testunit
10
- fi
data/bin/console DELETED
@@ -1,14 +0,0 @@
1
- #!/usr/bin/env ruby
2
-
3
- require("bundler/setup")
4
- require("bootsnap")
5
-
6
- # You can add fixtures and/or initialization code here to make experimenting
7
- # with your gem easier. You can also use a different console, if you like.
8
-
9
- # (If you use this, don't forget to add pry to your Gemfile!)
10
- # require "pry"
11
- # Pry.start
12
-
13
- require("irb")
14
- IRB.start(__FILE__)
data/bin/setup DELETED
@@ -1,8 +0,0 @@
1
- #!/usr/bin/env bash
2
- set -euo pipefail
3
- IFS=$'\n\t'
4
- set -vx
5
-
6
- bundle install
7
-
8
- # Do any other automated setup that you need to do here
@@ -1,7 +0,0 @@
1
- #!/bin/bash
2
-
3
- set -euxo pipefail
4
-
5
- cd test/minimal_support
6
- bundle
7
- BOOTSNAP_CACHE_DIR=/tmp bundle exec ruby -w -I ../../lib bootsnap_setup.rb
data/bin/testunit DELETED
@@ -1,8 +0,0 @@
1
- #!/bin/bash
2
-
3
- if [[ $# -eq 0 ]]; then
4
- exec ruby -I"test" -w -e 'Dir.glob("./test/**/*_test.rb").each { |f| require f }' -- "$@"
5
- else
6
- path=$1
7
- exec ruby -I"test" -w -e "require '${path#test/}'" -- "$@"
8
- fi
data/bootsnap.gemspec DELETED
@@ -1,45 +0,0 @@
1
- # coding: utf-8
2
- lib = File.expand_path('../lib', __FILE__)
3
- $LOAD_PATH.unshift(lib) unless $LOAD_PATH.include?(lib)
4
- require('bootsnap/version')
5
-
6
- Gem::Specification.new do |spec|
7
- spec.name = "bootsnap"
8
- spec.version = Bootsnap::VERSION
9
- spec.authors = ["Burke Libbey"]
10
- spec.email = ["burke.libbey@shopify.com"]
11
-
12
- spec.license = "MIT"
13
-
14
- spec.summary = "Boot large ruby/rails apps faster"
15
- spec.description = spec.summary
16
- spec.homepage = "https://github.com/Shopify/bootsnap"
17
-
18
- spec.metadata = {
19
- 'bug_tracker_uri' => 'https://github.com/Shopify/bootsnap/issues',
20
- 'changelog_uri' => 'https://github.com/Shopify/bootsnap/blob/master/CHANGELOG.md',
21
- 'source_code_uri' => 'https://github.com/Shopify/bootsnap',
22
- }
23
-
24
- spec.files = %x(git ls-files -z).split("\x0").reject do |f|
25
- f.match(%r{^(test|spec|features)/})
26
- end
27
- spec.require_paths = %w(lib)
28
-
29
- spec.required_ruby_version = '>= 2.0.0'
30
-
31
- if RUBY_PLATFORM =~ /java/
32
- spec.platform = 'java'
33
- else
34
- spec.platform = Gem::Platform::RUBY
35
- spec.extensions = ['ext/bootsnap/extconf.rb']
36
- end
37
-
38
- spec.add_development_dependency("bundler")
39
- spec.add_development_dependency('rake', '~> 10.0')
40
- spec.add_development_dependency('rake-compiler', '~> 0')
41
- spec.add_development_dependency("minitest", "~> 5.0")
42
- spec.add_development_dependency("mocha", "~> 1.2")
43
-
44
- spec.add_runtime_dependency("msgpack", "~> 1.0")
45
- end
data/dev.yml DELETED
@@ -1,10 +0,0 @@
1
- env:
2
- BOOTSNAP_PEDANTIC: '1'
3
-
4
- up:
5
- - ruby: 2.6.0
6
- - bundler
7
- commands:
8
- build: rake compile
9
- test: 'rake compile && exec bin/testunit'
10
- style: 'exec rubocop -D'
@@ -1,106 +0,0 @@
1
- module Bootsnap
2
- module LoadPathCache
3
- module CoreExt
4
- module ActiveSupport
5
- def self.without_bootsnap_cache
6
- prev = Thread.current[:without_bootsnap_cache] || false
7
- Thread.current[:without_bootsnap_cache] = true
8
- yield
9
- ensure
10
- Thread.current[:without_bootsnap_cache] = prev
11
- end
12
-
13
- def self.allow_bootsnap_retry(allowed)
14
- prev = Thread.current[:without_bootsnap_retry] || false
15
- Thread.current[:without_bootsnap_retry] = !allowed
16
- yield
17
- ensure
18
- Thread.current[:without_bootsnap_retry] = prev
19
- end
20
-
21
- module ClassMethods
22
- def autoload_paths=(o)
23
- super
24
- Bootsnap::LoadPathCache.autoload_paths_cache.reinitialize(o)
25
- end
26
-
27
- def search_for_file(path)
28
- return super if Thread.current[:without_bootsnap_cache]
29
- begin
30
- Bootsnap::LoadPathCache.autoload_paths_cache.find(path)
31
- rescue Bootsnap::LoadPathCache::ReturnFalse
32
- nil # doesn't really apply here
33
- rescue Bootsnap::LoadPathCache::FallbackScan
34
- nil # doesn't really apply here
35
- end
36
- end
37
-
38
- def autoloadable_module?(path_suffix)
39
- Bootsnap::LoadPathCache.autoload_paths_cache.load_dir(path_suffix)
40
- end
41
-
42
- def remove_constant(const)
43
- CoreExt::ActiveSupport.without_bootsnap_cache { super }
44
- end
45
-
46
- def require_or_load(*)
47
- CoreExt::ActiveSupport.allow_bootsnap_retry(true) do
48
- super
49
- end
50
- end
51
-
52
- # If we can't find a constant using the patched implementation of
53
- # search_for_file, try again with the default implementation.
54
- #
55
- # These methods call search_for_file, and we want to modify its
56
- # behaviour. The gymnastics here are a bit awkward, but it prevents
57
- # 200+ lines of monkeypatches.
58
- def load_missing_constant(from_mod, const_name)
59
- CoreExt::ActiveSupport.allow_bootsnap_retry(false) do
60
- super
61
- end
62
- rescue NameError => e
63
- raise(e) if e.instance_variable_defined?(Bootsnap::LoadPathCache::ERROR_TAG_IVAR)
64
- e.instance_variable_set(Bootsnap::LoadPathCache::ERROR_TAG_IVAR, true)
65
-
66
- # This function can end up called recursively, we only want to
67
- # retry at the top-level.
68
- raise(e) if Thread.current[:without_bootsnap_retry]
69
- # If we already had cache disabled, there's no use retrying
70
- raise(e) if Thread.current[:without_bootsnap_cache]
71
- # NoMethodError is a NameError, but we only want to handle actual
72
- # NameError instances.
73
- raise(e) unless e.class == NameError
74
- # We can only confidently handle cases when *this* constant fails
75
- # to load, not other constants referred to by it.
76
- raise(e) unless e.name == const_name
77
- # If the constant was actually loaded, something else went wrong?
78
- raise(e) if from_mod.const_defined?(const_name)
79
- CoreExt::ActiveSupport.without_bootsnap_cache { super }
80
- end
81
-
82
- # Signature has changed a few times over the years; easiest to not
83
- # reiterate it with version polymorphism here...
84
- def depend_on(*)
85
- super
86
- rescue LoadError => e
87
- raise(e) if e.instance_variable_defined?(Bootsnap::LoadPathCache::ERROR_TAG_IVAR)
88
- e.instance_variable_set(Bootsnap::LoadPathCache::ERROR_TAG_IVAR, true)
89
-
90
- # If we already had cache disabled, there's no use retrying
91
- raise(e) if Thread.current[:without_bootsnap_cache]
92
- CoreExt::ActiveSupport.without_bootsnap_cache { super }
93
- end
94
- end
95
- end
96
- end
97
- end
98
- end
99
-
100
- module ActiveSupport
101
- module Dependencies
102
- class << self
103
- prepend(Bootsnap::LoadPathCache::CoreExt::ActiveSupport::ClassMethods)
104
- end
105
- end
106
- end
@@ -1,32 +0,0 @@
1
- # frozen_string_literal: true
2
-
3
- module Bootsnap
4
- module LoadPathCache
5
- class RealpathCache
6
- def initialize
7
- @cache = Hash.new { |h, k| h[k] = realpath(*k) }
8
- end
9
-
10
- def call(*key)
11
- @cache[key]
12
- end
13
-
14
- private
15
-
16
- def realpath(caller_location, path)
17
- base = File.dirname(caller_location)
18
- file = find_file(File.expand_path(path, base))
19
- dir = File.dirname(file)
20
- File.join(dir, File.basename(file))
21
- end
22
-
23
- def find_file(name)
24
- ['', *CACHED_EXTENSIONS].each do |ext|
25
- filename = "#{name}#{ext}"
26
- return File.realpath(filename) if File.exist?(filename)
27
- end
28
- name
29
- end
30
- end
31
- end
32
- end
data/shipit.rubygems.yml DELETED
File without changes