bootsnap 1.4.5 → 1.6.0
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/CHANGELOG.md +46 -0
- data/README.md +17 -3
- data/exe/bootsnap +5 -0
- data/ext/bootsnap/bootsnap.c +183 -65
- data/ext/bootsnap/extconf.rb +1 -0
- data/lib/bootsnap/bundler.rb +1 -0
- data/lib/bootsnap/cli/worker_pool.rb +131 -0
- data/lib/bootsnap/cli.rb +246 -0
- data/lib/bootsnap/compile_cache/iseq.rb +22 -7
- data/lib/bootsnap/compile_cache/yaml.rb +89 -39
- data/lib/bootsnap/compile_cache.rb +3 -2
- data/lib/bootsnap/explicit_require.rb +1 -0
- data/lib/bootsnap/load_path_cache/cache.rb +8 -8
- data/lib/bootsnap/load_path_cache/change_observer.rb +2 -1
- data/lib/bootsnap/load_path_cache/core_ext/active_support.rb +1 -0
- data/lib/bootsnap/load_path_cache/core_ext/kernel_require.rb +18 -5
- data/lib/bootsnap/load_path_cache/core_ext/loaded_features.rb +1 -0
- data/lib/bootsnap/load_path_cache/loaded_features_index.rb +33 -10
- data/lib/bootsnap/load_path_cache/path.rb +3 -2
- data/lib/bootsnap/load_path_cache/path_scanner.rb +39 -26
- data/lib/bootsnap/load_path_cache/realpath_cache.rb +5 -5
- data/lib/bootsnap/load_path_cache/store.rb +6 -5
- data/lib/bootsnap/load_path_cache.rb +1 -1
- data/lib/bootsnap/setup.rb +1 -0
- data/lib/bootsnap/version.rb +2 -1
- data/lib/bootsnap.rb +4 -2
- metadata +15 -28
- data/.github/CODEOWNERS +0 -2
- data/.github/probots.yml +0 -2
- data/.gitignore +0 -17
- data/.rubocop.yml +0 -20
- data/.travis.yml +0 -21
- data/CODE_OF_CONDUCT.md +0 -74
- data/CONTRIBUTING.md +0 -21
- data/Gemfile +0 -8
- data/README.jp.md +0 -231
- data/Rakefile +0 -12
- data/bin/ci +0 -10
- data/bin/console +0 -14
- data/bin/setup +0 -8
- data/bin/test-minimal-support +0 -7
- data/bin/testunit +0 -8
- data/bootsnap.gemspec +0 -45
- data/dev.yml +0 -10
- data/shipit.rubygems.yml +0 -0
    
        checksums.yaml
    CHANGED
    
    | @@ -1,7 +1,7 @@ | |
| 1 1 | 
             
            ---
         | 
| 2 2 | 
             
            SHA256:
         | 
| 3 | 
            -
              metadata.gz:  | 
| 4 | 
            -
              data.tar.gz:  | 
| 3 | 
            +
              metadata.gz: '029d63ba428f470d2cd2ef194d857e20689e7c8e377e2eaaaab83570f366034a'
         | 
| 4 | 
            +
              data.tar.gz: 36a55f9d12dddef6ea3c4739f586c9236d7f4bc677a8b6747dfd7465d46eeca2
         | 
| 5 5 | 
             
            SHA512:
         | 
| 6 | 
            -
              metadata.gz:  | 
| 7 | 
            -
              data.tar.gz:  | 
| 6 | 
            +
              metadata.gz: 131ec17c4e4912f387c18778250e689467ebfcc80e91eb884237307af1a57a3c89d4fb20c772fbc0330123a796d631861a9cf145bd32c54183077bbc97d7fa6f
         | 
| 7 | 
            +
              data.tar.gz: d0c92454c8a5d8b16a25908fd0ae134fc817c5977958bde8424baca2bb6c96e60eb648c9f770bf7c7f58a3dd98871d4e7b0e3a0950c269100fded45ca9fddfa3
         | 
    
        data/CHANGELOG.md
    CHANGED
    
    | @@ -1,3 +1,49 @@ | |
| 1 | 
            +
            # Unreleased
         | 
| 2 | 
            +
             | 
| 3 | 
            +
            # 1.6.0
         | 
| 4 | 
            +
             | 
| 5 | 
            +
            * Fix a Ruby 2.7/3.0 issue with `YAML.load_file` keyword arguments. (#342)
         | 
| 6 | 
            +
            * `bootsnap precompile` CLI use multiple processes to complete faster. (#341)
         | 
| 7 | 
            +
            * `bootsnap precompile` CLI also precompile YAML files. (#340)
         | 
| 8 | 
            +
            * Changed the load path cache directory from `$BOOTSNAP_CACHE_DIR/bootsnap-load-path-cache` to `$BOOTSNAP_CACHE_DIR/bootsnap/load-path-cache` for ease of use. (#334)
         | 
| 9 | 
            +
            * Changed the compile cache directory from `$BOOTSNAP_CACHE_DIR/bootsnap-compile-cache` to `$BOOTSNAP_CACHE_DIR/bootsnap/compile-cache` for ease of use. (#334)
         | 
| 10 | 
            +
             | 
| 11 | 
            +
            # 1.5.1
         | 
| 12 | 
            +
             | 
| 13 | 
            +
            * Workaround a Ruby bug in InstructionSequence.compile_file. (#332)
         | 
| 14 | 
            +
             | 
| 15 | 
            +
            # 1.5.0
         | 
| 16 | 
            +
             | 
| 17 | 
            +
            * Add a command line to statically precompile the ISeq cache. (#326)
         | 
| 18 | 
            +
             | 
| 19 | 
            +
            # 1.4.9
         | 
| 20 | 
            +
             | 
| 21 | 
            +
            * [Windows support](https://github.com/Shopify/bootsnap/pull/319)
         | 
| 22 | 
            +
            * [Fix potential crash](https://github.com/Shopify/bootsnap/pull/322)
         | 
| 23 | 
            +
             | 
| 24 | 
            +
            # 1.4.8
         | 
| 25 | 
            +
             | 
| 26 | 
            +
            * [Prevent FallbackScan from polluting exception cause](https://github.com/Shopify/bootsnap/pull/314)
         | 
| 27 | 
            +
             | 
| 28 | 
            +
            # 1.4.7
         | 
| 29 | 
            +
             | 
| 30 | 
            +
            * Various performance enhancements
         | 
| 31 | 
            +
            * Fix race condition in heavy concurrent load scenarios that would cause bootsnap to raise
         | 
| 32 | 
            +
             | 
| 33 | 
            +
            # 1.4.6
         | 
| 34 | 
            +
             | 
| 35 | 
            +
            * Fix bug that was erroneously considering that files containing `.` in the names were being
         | 
| 36 | 
            +
              required if a different file with the same name was already being required
         | 
| 37 | 
            +
             | 
| 38 | 
            +
              Example:
         | 
| 39 | 
            +
              
         | 
| 40 | 
            +
                  require 'foo'
         | 
| 41 | 
            +
                  require 'foo.en'
         | 
| 42 | 
            +
             | 
| 43 | 
            +
              Before bootsnap was considering `foo.en` to be the same file as `foo`
         | 
| 44 | 
            +
             | 
| 45 | 
            +
            * Use glibc as part of the ruby_platform cache key
         | 
| 46 | 
            +
             | 
| 1 47 | 
             
            # 1.4.5
         | 
| 2 48 |  | 
| 3 49 | 
             
            * MRI 2.7 support
         | 
    
        data/README.md
    CHANGED
    
    | @@ -1,4 +1,4 @@ | |
| 1 | 
            -
            # Bootsnap [](https://github.com/Shopify/bootsnap/actions)
         | 
| 2 2 |  | 
| 3 3 | 
             
            Bootsnap is a library that plugs into Ruby, with optional support for `ActiveSupport` and `YAML`,
         | 
| 4 4 | 
             
            to optimize and cache expensive computations. See [How Does This Work](#how-does-this-work).
         | 
| @@ -29,7 +29,8 @@ If you are using Rails, add this to `config/boot.rb` immediately after `require | |
| 29 29 | 
             
            require 'bootsnap/setup'
         | 
| 30 30 | 
             
            ```
         | 
| 31 31 |  | 
| 32 | 
            -
            Note that bootsnap writes to `tmp/cache | 
| 32 | 
            +
            Note that bootsnap writes to `tmp/cache` (or the path specified by `ENV['BOOTSNAP_CACHE_DIR']`), 
         | 
| 33 | 
            +
            and that directory *must* be writable. Rails will fail to
         | 
| 33 34 | 
             
            boot if it is not. If this is unacceptable (e.g. you are running in a read-only container and
         | 
| 34 35 | 
             
            unwilling to mount in a writable tmpdir), you should remove this line or wrap it in a conditional.
         | 
| 35 36 |  | 
| @@ -214,7 +215,7 @@ Bootsnap writes a cache file containing a 64 byte header followed by the cache c | |
| 214 215 | 
             
            is a cache key including several fields:
         | 
| 215 216 |  | 
| 216 217 | 
             
            * `version`, hardcoded in bootsnap. Essentially a schema version;
         | 
| 217 | 
            -
            * ` | 
| 218 | 
            +
            * `ruby_platform`, A hash of `RUBY_PLATFORM` (e.g. x86_64-linux-gnu) variable and glibc version (on Linux) or OS version (`uname -v` on BSD, macOS)
         | 
| 218 219 | 
             
            * `compile_option`, which changes with `RubyVM::InstructionSequence.compile_option` does;
         | 
| 219 220 | 
             
            * `ruby_revision`, the version of Ruby this was compiled with;
         | 
| 220 221 | 
             
            * `size`, the size of the source file;
         | 
| @@ -294,6 +295,19 @@ open    /c/nope.bundle -> -1 | |
| 294 295 | 
             
            # (nothing!)
         | 
| 295 296 | 
             
            ```
         | 
| 296 297 |  | 
| 298 | 
            +
            ## Precompilation
         | 
| 299 | 
            +
             | 
| 300 | 
            +
            In development environments the bootsnap compilation cache is generated on the fly when source files are loaded.
         | 
| 301 | 
            +
            But in production environments, such as docker images, you might need to precompile the cache.
         | 
| 302 | 
            +
             | 
| 303 | 
            +
            To do so you can use the `bootsnap precompile` command.
         | 
| 304 | 
            +
             | 
| 305 | 
            +
            Example:
         | 
| 306 | 
            +
             | 
| 307 | 
            +
            ```bash
         | 
| 308 | 
            +
            $ bundle exec bootsnap precompile --gemfile app/ lib/
         | 
| 309 | 
            +
            ```
         | 
| 310 | 
            +
             | 
| 297 311 | 
             
            ## When not to use Bootsnap
         | 
| 298 312 |  | 
| 299 313 | 
             
            *Alternative engines*: Bootsnap is pretty reliant on MRI features, and parts are disabled entirely on alternative ruby
         | 
    
        data/exe/bootsnap
    ADDED
    
    
    
        data/ext/bootsnap/bootsnap.c
    CHANGED
    
    | @@ -21,6 +21,9 @@ | |
| 21 21 | 
             
            #ifndef _WIN32
         | 
| 22 22 | 
             
            #include <sys/utsname.h>
         | 
| 23 23 | 
             
            #endif
         | 
| 24 | 
            +
            #ifdef __GLIBC__
         | 
| 25 | 
            +
            #include <gnu/libc-version.h>
         | 
| 26 | 
            +
            #endif
         | 
| 24 27 |  | 
| 25 28 | 
             
            /* 1000 is an arbitrary limit; FNV64 plus some slashes brings the cap down to
         | 
| 26 29 | 
             
             * 981 for the cache dir */
         | 
| @@ -29,6 +32,8 @@ | |
| 29 32 |  | 
| 30 33 | 
             
            #define KEY_SIZE 64
         | 
| 31 34 |  | 
| 35 | 
            +
            #define MAX_CREATE_TEMPFILE_ATTEMPT 3
         | 
| 36 | 
            +
             | 
| 32 37 | 
             
            /*
         | 
| 33 38 | 
             
             * An instance of this key is written as the first 64 bytes of each cache file.
         | 
| 34 39 | 
             
             * The mtime and size members track whether the file contents have changed, and
         | 
| @@ -65,7 +70,7 @@ struct bs_cache_key { | |
| 65 70 | 
             
            STATIC_ASSERT(sizeof(struct bs_cache_key) == KEY_SIZE);
         | 
| 66 71 |  | 
| 67 72 | 
             
            /* Effectively a schema version. Bumping invalidates all previous caches */
         | 
| 68 | 
            -
            static const uint32_t current_version =  | 
| 73 | 
            +
            static const uint32_t current_version = 3;
         | 
| 69 74 |  | 
| 70 75 | 
             
            /* hash of e.g. "x86_64-darwin17", invalidating when ruby is recompiled on a
         | 
| 71 76 | 
             
             * new OS ABI, etc. */
         | 
| @@ -86,16 +91,18 @@ static ID uncompilable; | |
| 86 91 |  | 
| 87 92 | 
             
            /* Functions exposed as module functions on Bootsnap::CompileCache::Native */
         | 
| 88 93 | 
             
            static VALUE bs_compile_option_crc32_set(VALUE self, VALUE crc32_v);
         | 
| 89 | 
            -
            static VALUE bs_rb_fetch(VALUE self, VALUE cachedir_v, VALUE path_v, VALUE handler);
         | 
| 94 | 
            +
            static VALUE bs_rb_fetch(VALUE self, VALUE cachedir_v, VALUE path_v, VALUE handler, VALUE args);
         | 
| 95 | 
            +
            static VALUE bs_rb_precompile(VALUE self, VALUE cachedir_v, VALUE path_v, VALUE handler);
         | 
| 90 96 |  | 
| 91 97 | 
             
            /* Helpers */
         | 
| 92 98 | 
             
            static uint64_t fnv1a_64(const char *str);
         | 
| 93 | 
            -
            static void bs_cache_path(const char * cachedir, const char * path, char  | 
| 99 | 
            +
            static void bs_cache_path(const char * cachedir, const char * path, char (* cache_path)[MAX_CACHEPATH_SIZE]);
         | 
| 94 100 | 
             
            static int bs_read_key(int fd, struct bs_cache_key * key);
         | 
| 95 101 | 
             
            static int cache_key_equal(struct bs_cache_key * k1, struct bs_cache_key * k2);
         | 
| 96 | 
            -
            static VALUE bs_fetch(char * path, VALUE path_v, char * cache_path, VALUE handler);
         | 
| 97 | 
            -
            static  | 
| 98 | 
            -
            static int  | 
| 102 | 
            +
            static VALUE bs_fetch(char * path, VALUE path_v, char * cache_path, VALUE handler, VALUE args);
         | 
| 103 | 
            +
            static VALUE bs_precompile(char * path, VALUE path_v, char * cache_path, VALUE handler);
         | 
| 104 | 
            +
            static int open_current_file(char * path, struct bs_cache_key * key, const char ** errno_provenance);
         | 
| 105 | 
            +
            static int fetch_cached_data(int fd, ssize_t data_size, VALUE handler, VALUE args, VALUE * output_data, int * exception_tag, const char ** errno_provenance);
         | 
| 99 106 | 
             
            static uint32_t get_ruby_revision(void);
         | 
| 100 107 | 
             
            static uint32_t get_ruby_platform(void);
         | 
| 101 108 |  | 
| @@ -103,12 +110,12 @@ static uint32_t get_ruby_platform(void); | |
| 103 110 | 
             
             * Helper functions to call ruby methods on handler object without crashing on
         | 
| 104 111 | 
             
             * exception.
         | 
| 105 112 | 
             
             */
         | 
| 106 | 
            -
            static int bs_storage_to_output(VALUE handler, VALUE storage_data, VALUE * output_data);
         | 
| 113 | 
            +
            static int bs_storage_to_output(VALUE handler, VALUE args, VALUE storage_data, VALUE * output_data);
         | 
| 107 114 | 
             
            static VALUE prot_storage_to_output(VALUE arg);
         | 
| 108 115 | 
             
            static VALUE prot_input_to_output(VALUE arg);
         | 
| 109 | 
            -
            static void bs_input_to_output(VALUE handler, VALUE input_data, VALUE * output_data, int * exception_tag);
         | 
| 116 | 
            +
            static void bs_input_to_output(VALUE handler, VALUE args, VALUE input_data, VALUE * output_data, int * exception_tag);
         | 
| 110 117 | 
             
            static VALUE prot_input_to_storage(VALUE arg);
         | 
| 111 | 
            -
            static int bs_input_to_storage(VALUE handler, VALUE input_data, VALUE pathval, VALUE * storage_data);
         | 
| 118 | 
            +
            static int bs_input_to_storage(VALUE handler, VALUE args, VALUE input_data, VALUE pathval, VALUE * storage_data);
         | 
| 112 119 | 
             
            struct s2o_data;
         | 
| 113 120 | 
             
            struct i2o_data;
         | 
| 114 121 | 
             
            struct i2s_data;
         | 
| @@ -143,7 +150,8 @@ Init_bootsnap(void) | |
| 143 150 | 
             
              uncompilable = rb_intern("__bootsnap_uncompilable__");
         | 
| 144 151 |  | 
| 145 152 | 
             
              rb_define_module_function(rb_mBootsnap_CompileCache_Native, "coverage_running?", bs_rb_coverage_running, 0);
         | 
| 146 | 
            -
              rb_define_module_function(rb_mBootsnap_CompileCache_Native, "fetch", bs_rb_fetch,  | 
| 153 | 
            +
              rb_define_module_function(rb_mBootsnap_CompileCache_Native, "fetch", bs_rb_fetch, 4);
         | 
| 154 | 
            +
              rb_define_module_function(rb_mBootsnap_CompileCache_Native, "precompile", bs_rb_precompile, 3);
         | 
| 147 155 | 
             
              rb_define_module_function(rb_mBootsnap_CompileCache_Native, "compile_option_crc32=", bs_compile_option_crc32_set, 1);
         | 
| 148 156 |  | 
| 149 157 | 
             
              current_umask = umask(0777);
         | 
| @@ -236,6 +244,9 @@ get_ruby_platform(void) | |
| 236 244 |  | 
| 237 245 | 
             
            #ifdef _WIN32
         | 
| 238 246 | 
             
              return (uint32_t)(hash >> 32) ^ (uint32_t)GetVersion();
         | 
| 247 | 
            +
            #elif defined(__GLIBC__)
         | 
| 248 | 
            +
              hash = fnv1a_64_iter(hash, gnu_get_libc_version());
         | 
| 249 | 
            +
              return (uint32_t)(hash >> 32);
         | 
| 239 250 | 
             
            #else
         | 
| 240 251 | 
             
              struct utsname utsname;
         | 
| 241 252 |  | 
| @@ -256,10 +267,9 @@ get_ruby_platform(void) | |
| 256 267 | 
             
             * The path will look something like: <cachedir>/12/34567890abcdef
         | 
| 257 268 | 
             
             */
         | 
| 258 269 | 
             
            static void
         | 
| 259 | 
            -
            bs_cache_path(const char * cachedir, const char * path, char  | 
| 270 | 
            +
            bs_cache_path(const char * cachedir, const char * path, char (* cache_path)[MAX_CACHEPATH_SIZE])
         | 
| 260 271 | 
             
            {
         | 
| 261 272 | 
             
              uint64_t hash = fnv1a_64(path);
         | 
| 262 | 
            -
             | 
| 263 273 | 
             
              uint8_t first_byte = (hash >> (64 - 8));
         | 
| 264 274 | 
             
              uint64_t remainder = hash & 0x00ffffffffffffff;
         | 
| 265 275 |  | 
| @@ -293,7 +303,7 @@ cache_key_equal(struct bs_cache_key * k1, struct bs_cache_key * k2) | |
| 293 303 | 
             
             * conversions on the ruby VALUE arguments before passing them along.
         | 
| 294 304 | 
             
             */
         | 
| 295 305 | 
             
            static VALUE
         | 
| 296 | 
            -
            bs_rb_fetch(VALUE self, VALUE cachedir_v, VALUE path_v, VALUE handler)
         | 
| 306 | 
            +
            bs_rb_fetch(VALUE self, VALUE cachedir_v, VALUE path_v, VALUE handler, VALUE args)
         | 
| 297 307 | 
             
            {
         | 
| 298 308 | 
             
              FilePathValue(path_v);
         | 
| 299 309 |  | 
| @@ -308,27 +318,51 @@ bs_rb_fetch(VALUE self, VALUE cachedir_v, VALUE path_v, VALUE handler) | |
| 308 318 | 
             
              char * path     = RSTRING_PTR(path_v);
         | 
| 309 319 | 
             
              char cache_path[MAX_CACHEPATH_SIZE];
         | 
| 310 320 |  | 
| 311 | 
            -
               | 
| 312 | 
            -
             | 
| 313 | 
            -
                bs_cache_path(cachedir, path, &tmp);
         | 
| 314 | 
            -
              }
         | 
| 321 | 
            +
              /* generate cache path to cache_path */
         | 
| 322 | 
            +
              bs_cache_path(cachedir, path, &cache_path);
         | 
| 315 323 |  | 
| 316 | 
            -
              return bs_fetch(path, path_v, cache_path, handler);
         | 
| 324 | 
            +
              return bs_fetch(path, path_v, cache_path, handler, args);
         | 
| 317 325 | 
             
            }
         | 
| 318 326 |  | 
| 327 | 
            +
            /*
         | 
| 328 | 
            +
             * Entrypoint for Bootsnap::CompileCache::Native.precompile.
         | 
| 329 | 
            +
             * Similar to fetch, but it only generate the cache if missing
         | 
| 330 | 
            +
             * and doesn't return the content.
         | 
| 331 | 
            +
             */
         | 
| 332 | 
            +
            static VALUE
         | 
| 333 | 
            +
            bs_rb_precompile(VALUE self, VALUE cachedir_v, VALUE path_v, VALUE handler)
         | 
| 334 | 
            +
            {
         | 
| 335 | 
            +
              FilePathValue(path_v);
         | 
| 336 | 
            +
             | 
| 337 | 
            +
              Check_Type(cachedir_v, T_STRING);
         | 
| 338 | 
            +
              Check_Type(path_v, T_STRING);
         | 
| 339 | 
            +
             | 
| 340 | 
            +
              if (RSTRING_LEN(cachedir_v) > MAX_CACHEDIR_SIZE) {
         | 
| 341 | 
            +
                rb_raise(rb_eArgError, "cachedir too long");
         | 
| 342 | 
            +
              }
         | 
| 343 | 
            +
             | 
| 344 | 
            +
              char * cachedir = RSTRING_PTR(cachedir_v);
         | 
| 345 | 
            +
              char * path     = RSTRING_PTR(path_v);
         | 
| 346 | 
            +
              char cache_path[MAX_CACHEPATH_SIZE];
         | 
| 347 | 
            +
             | 
| 348 | 
            +
              /* generate cache path to cache_path */
         | 
| 349 | 
            +
              bs_cache_path(cachedir, path, &cache_path);
         | 
| 350 | 
            +
             | 
| 351 | 
            +
              return bs_precompile(path, path_v, cache_path, handler);
         | 
| 352 | 
            +
            }
         | 
| 319 353 | 
             
            /*
         | 
| 320 354 | 
             
             * Open the file we want to load/cache and generate a cache key for it if it
         | 
| 321 355 | 
             
             * was loaded.
         | 
| 322 356 | 
             
             */
         | 
| 323 357 | 
             
            static int
         | 
| 324 | 
            -
            open_current_file(char * path, struct bs_cache_key * key, char ** errno_provenance)
         | 
| 358 | 
            +
            open_current_file(char * path, struct bs_cache_key * key, const char ** errno_provenance)
         | 
| 325 359 | 
             
            {
         | 
| 326 360 | 
             
              struct stat statbuf;
         | 
| 327 361 | 
             
              int fd;
         | 
| 328 362 |  | 
| 329 363 | 
             
              fd = open(path, O_RDONLY);
         | 
| 330 364 | 
             
              if (fd < 0) {
         | 
| 331 | 
            -
                *errno_provenance =  | 
| 365 | 
            +
                *errno_provenance = "bs_fetch:open_current_file:open";
         | 
| 332 366 | 
             
                return fd;
         | 
| 333 367 | 
             
              }
         | 
| 334 368 | 
             
              #ifdef _WIN32
         | 
| @@ -336,7 +370,7 @@ open_current_file(char * path, struct bs_cache_key * key, char ** errno_provenan | |
| 336 370 | 
             
              #endif
         | 
| 337 371 |  | 
| 338 372 | 
             
              if (fstat(fd, &statbuf) < 0) {
         | 
| 339 | 
            -
                *errno_provenance =  | 
| 373 | 
            +
                *errno_provenance = "bs_fetch:open_current_file:fstat";
         | 
| 340 374 | 
             
                close(fd);
         | 
| 341 375 | 
             
                return -1;
         | 
| 342 376 | 
             
              }
         | 
| @@ -382,13 +416,13 @@ bs_read_key(int fd, struct bs_cache_key * key) | |
| 382 416 | 
             
             *   - ERROR_WITH_ERRNO (-1, errno is set)
         | 
| 383 417 | 
             
             */
         | 
| 384 418 | 
             
            static int
         | 
| 385 | 
            -
            open_cache_file(const char * path, struct bs_cache_key * key, char ** errno_provenance)
         | 
| 419 | 
            +
            open_cache_file(const char * path, struct bs_cache_key * key, const char ** errno_provenance)
         | 
| 386 420 | 
             
            {
         | 
| 387 421 | 
             
              int fd, res;
         | 
| 388 422 |  | 
| 389 423 | 
             
              fd = open(path, O_RDONLY);
         | 
| 390 424 | 
             
              if (fd < 0) {
         | 
| 391 | 
            -
                *errno_provenance =  | 
| 425 | 
            +
                *errno_provenance = "bs_fetch:open_cache_file:open";
         | 
| 392 426 | 
             
                if (errno == ENOENT) return CACHE_MISSING_OR_INVALID;
         | 
| 393 427 | 
             
                return ERROR_WITH_ERRNO;
         | 
| 394 428 | 
             
              }
         | 
| @@ -398,7 +432,7 @@ open_cache_file(const char * path, struct bs_cache_key * key, char ** errno_prov | |
| 398 432 |  | 
| 399 433 | 
             
              res = bs_read_key(fd, key);
         | 
| 400 434 | 
             
              if (res < 0) {
         | 
| 401 | 
            -
                *errno_provenance =  | 
| 435 | 
            +
                *errno_provenance = "bs_fetch:open_cache_file:read";
         | 
| 402 436 | 
             
                close(fd);
         | 
| 403 437 | 
             
                return res;
         | 
| 404 438 | 
             
              }
         | 
| @@ -422,7 +456,7 @@ open_cache_file(const char * path, struct bs_cache_key * key, char ** errno_prov | |
| 422 456 | 
             
             * or exception, will be the final data returnable to the user.
         | 
| 423 457 | 
             
             */
         | 
| 424 458 | 
             
            static int
         | 
| 425 | 
            -
            fetch_cached_data(int fd, ssize_t data_size, VALUE handler, VALUE * output_data, int * exception_tag, char ** errno_provenance)
         | 
| 459 | 
            +
            fetch_cached_data(int fd, ssize_t data_size, VALUE handler, VALUE args, VALUE * output_data, int * exception_tag, const char ** errno_provenance)
         | 
| 426 460 | 
             
            {
         | 
| 427 461 | 
             
              char * data = NULL;
         | 
| 428 462 | 
             
              ssize_t nread;
         | 
| @@ -431,7 +465,7 @@ fetch_cached_data(int fd, ssize_t data_size, VALUE handler, VALUE * output_data, | |
| 431 465 | 
             
              VALUE storage_data;
         | 
| 432 466 |  | 
| 433 467 | 
             
              if (data_size > 100000000000) {
         | 
| 434 | 
            -
                *errno_provenance =  | 
| 468 | 
            +
                *errno_provenance = "bs_fetch:fetch_cached_data:datasize";
         | 
| 435 469 | 
             
                errno = EINVAL; /* because wtf? */
         | 
| 436 470 | 
             
                ret = -1;
         | 
| 437 471 | 
             
                goto done;
         | 
| @@ -439,7 +473,7 @@ fetch_cached_data(int fd, ssize_t data_size, VALUE handler, VALUE * output_data, | |
| 439 473 | 
             
              data = ALLOC_N(char, data_size);
         | 
| 440 474 | 
             
              nread = read(fd, data, data_size);
         | 
| 441 475 | 
             
              if (nread < 0) {
         | 
| 442 | 
            -
                *errno_provenance =  | 
| 476 | 
            +
                *errno_provenance = "bs_fetch:fetch_cached_data:read";
         | 
| 443 477 | 
             
                ret = -1;
         | 
| 444 478 | 
             
                goto done;
         | 
| 445 479 | 
             
              }
         | 
| @@ -448,9 +482,9 @@ fetch_cached_data(int fd, ssize_t data_size, VALUE handler, VALUE * output_data, | |
| 448 482 | 
             
                goto done;
         | 
| 449 483 | 
             
              }
         | 
| 450 484 |  | 
| 451 | 
            -
              storage_data =  | 
| 485 | 
            +
              storage_data = rb_str_new(data, data_size);
         | 
| 452 486 |  | 
| 453 | 
            -
              *exception_tag = bs_storage_to_output(handler, storage_data, output_data);
         | 
| 487 | 
            +
              *exception_tag = bs_storage_to_output(handler, args, storage_data, output_data);
         | 
| 454 488 | 
             
              ret = 0;
         | 
| 455 489 | 
             
            done:
         | 
| 456 490 | 
             
              if (data != NULL) xfree(data);
         | 
| @@ -491,29 +525,36 @@ mkpath(char * file_path, mode_t mode) | |
| 491 525 | 
             
             * path.
         | 
| 492 526 | 
             
             */
         | 
| 493 527 | 
             
            static int
         | 
| 494 | 
            -
            atomic_write_cache_file(char * path, struct bs_cache_key * key, VALUE data, char ** errno_provenance)
         | 
| 528 | 
            +
            atomic_write_cache_file(char * path, struct bs_cache_key * key, VALUE data, const char ** errno_provenance)
         | 
| 495 529 | 
             
            {
         | 
| 496 530 | 
             
              char template[MAX_CACHEPATH_SIZE + 20];
         | 
| 497 531 | 
             
              char * tmp_path;
         | 
| 498 | 
            -
              int fd, ret;
         | 
| 532 | 
            +
              int fd, ret, attempt;
         | 
| 499 533 | 
             
              ssize_t nwrite;
         | 
| 500 534 |  | 
| 501 | 
            -
               | 
| 502 | 
            -
             | 
| 535 | 
            +
              for (attempt = 0; attempt < MAX_CREATE_TEMPFILE_ATTEMPT; ++attempt) {
         | 
| 536 | 
            +
                tmp_path = strncpy(template, path, MAX_CACHEPATH_SIZE);
         | 
| 537 | 
            +
                strcat(tmp_path, ".tmp.XXXXXX");
         | 
| 503 538 |  | 
| 504 | 
            -
             | 
| 505 | 
            -
             | 
| 506 | 
            -
             | 
| 507 | 
            -
             | 
| 508 | 
            -
             | 
| 509 | 
            -
                   | 
| 510 | 
            -
                }
         | 
| 511 | 
            -
                fd = open(tmp_path, O_WRONLY | O_CREAT, 0664);
         | 
| 512 | 
            -
                if (fd < 0) {
         | 
| 513 | 
            -
                  *errno_provenance = (char *)"bs_fetch:atomic_write_cache_file:open";
         | 
| 539 | 
            +
                // mkstemp modifies the template to be the actual created path
         | 
| 540 | 
            +
                fd = mkstemp(tmp_path);
         | 
| 541 | 
            +
                if (fd > 0) break;
         | 
| 542 | 
            +
             | 
| 543 | 
            +
                if (attempt == 0 && mkpath(tmp_path, 0775) < 0) {
         | 
| 544 | 
            +
                  *errno_provenance = "bs_fetch:atomic_write_cache_file:mkpath";
         | 
| 514 545 | 
             
                  return -1;
         | 
| 515 546 | 
             
                }
         | 
| 516 547 | 
             
              }
         | 
| 548 | 
            +
              if (fd < 0) {
         | 
| 549 | 
            +
                *errno_provenance = "bs_fetch:atomic_write_cache_file:mkstemp";
         | 
| 550 | 
            +
                return -1;
         | 
| 551 | 
            +
              }
         | 
| 552 | 
            +
             | 
| 553 | 
            +
              if (chmod(tmp_path, 0644) < 0) {
         | 
| 554 | 
            +
                *errno_provenance = "bs_fetch:atomic_write_cache_file:chmod";
         | 
| 555 | 
            +
                return -1;
         | 
| 556 | 
            +
              }
         | 
| 557 | 
            +
             | 
| 517 558 | 
             
              #ifdef _WIN32
         | 
| 518 559 | 
             
              setmode(fd, O_BINARY);
         | 
| 519 560 | 
             
              #endif
         | 
| @@ -521,11 +562,11 @@ atomic_write_cache_file(char * path, struct bs_cache_key * key, VALUE data, char | |
| 521 562 | 
             
              key->data_size = RSTRING_LEN(data);
         | 
| 522 563 | 
             
              nwrite = write(fd, key, KEY_SIZE);
         | 
| 523 564 | 
             
              if (nwrite < 0) {
         | 
| 524 | 
            -
                *errno_provenance =  | 
| 565 | 
            +
                *errno_provenance = "bs_fetch:atomic_write_cache_file:write";
         | 
| 525 566 | 
             
                return -1;
         | 
| 526 567 | 
             
              }
         | 
| 527 568 | 
             
              if (nwrite != KEY_SIZE) {
         | 
| 528 | 
            -
                *errno_provenance =  | 
| 569 | 
            +
                *errno_provenance = "bs_fetch:atomic_write_cache_file:keysize";
         | 
| 529 570 | 
             
                errno = EIO; /* Lies but whatever */
         | 
| 530 571 | 
             
                return -1;
         | 
| 531 572 | 
             
              }
         | 
| @@ -533,7 +574,7 @@ atomic_write_cache_file(char * path, struct bs_cache_key * key, VALUE data, char | |
| 533 574 | 
             
              nwrite = write(fd, RSTRING_PTR(data), RSTRING_LEN(data));
         | 
| 534 575 | 
             
              if (nwrite < 0) return -1;
         | 
| 535 576 | 
             
              if (nwrite != RSTRING_LEN(data)) {
         | 
| 536 | 
            -
                *errno_provenance =  | 
| 577 | 
            +
                *errno_provenance = "bs_fetch:atomic_write_cache_file:writelength";
         | 
| 537 578 | 
             
                errno = EIO; /* Lies but whatever */
         | 
| 538 579 | 
             
                return -1;
         | 
| 539 580 | 
             
              }
         | 
| @@ -541,12 +582,12 @@ atomic_write_cache_file(char * path, struct bs_cache_key * key, VALUE data, char | |
| 541 582 | 
             
              close(fd);
         | 
| 542 583 | 
             
              ret = rename(tmp_path, path);
         | 
| 543 584 | 
             
              if (ret < 0) {
         | 
| 544 | 
            -
                *errno_provenance =  | 
| 585 | 
            +
                *errno_provenance = "bs_fetch:atomic_write_cache_file:rename";
         | 
| 545 586 | 
             
                return -1;
         | 
| 546 587 | 
             
              }
         | 
| 547 588 | 
             
              ret = chmod(path, 0664 & ~current_umask);
         | 
| 548 589 | 
             
              if (ret < 0) {
         | 
| 549 | 
            -
                *errno_provenance =  | 
| 590 | 
            +
                *errno_provenance = "bs_fetch:atomic_write_cache_file:chmod";
         | 
| 550 591 | 
             
              }
         | 
| 551 592 | 
             
              return ret;
         | 
| 552 593 | 
             
            }
         | 
| @@ -555,13 +596,13 @@ atomic_write_cache_file(char * path, struct bs_cache_key * key, VALUE data, char | |
| 555 596 | 
             
            /* Read contents from an fd, whose contents are asserted to be +size+ bytes
         | 
| 556 597 | 
             
             * long, into a buffer */
         | 
| 557 598 | 
             
            static ssize_t
         | 
| 558 | 
            -
            bs_read_contents(int fd, size_t size, char ** contents, char ** errno_provenance)
         | 
| 599 | 
            +
            bs_read_contents(int fd, size_t size, char ** contents, const char ** errno_provenance)
         | 
| 559 600 | 
             
            {
         | 
| 560 601 | 
             
              ssize_t nread;
         | 
| 561 602 | 
             
              *contents = ALLOC_N(char, size);
         | 
| 562 603 | 
             
              nread = read(fd, *contents, size);
         | 
| 563 604 | 
             
              if (nread < 0) {
         | 
| 564 | 
            -
                *errno_provenance =  | 
| 605 | 
            +
                *errno_provenance = "bs_fetch:bs_read_contents:read";
         | 
| 565 606 | 
             
              }
         | 
| 566 607 | 
             
              return nread;
         | 
| 567 608 | 
             
            }
         | 
| @@ -611,13 +652,13 @@ bs_read_contents(int fd, size_t size, char ** contents, char ** errno_provenance | |
| 611 652 | 
             
             *   - Return storage_to_output(storage_data)
         | 
| 612 653 | 
             
             */
         | 
| 613 654 | 
             
            static VALUE
         | 
| 614 | 
            -
            bs_fetch(char * path, VALUE path_v, char * cache_path, VALUE handler)
         | 
| 655 | 
            +
            bs_fetch(char * path, VALUE path_v, char * cache_path, VALUE handler, VALUE args)
         | 
| 615 656 | 
             
            {
         | 
| 616 657 | 
             
              struct bs_cache_key cached_key, current_key;
         | 
| 617 658 | 
             
              char * contents = NULL;
         | 
| 618 659 | 
             
              int cache_fd = -1, current_fd = -1;
         | 
| 619 660 | 
             
              int res, valid_cache = 0, exception_tag = 0;
         | 
| 620 | 
            -
              char * errno_provenance = NULL;
         | 
| 661 | 
            +
              const char * errno_provenance = NULL;
         | 
| 621 662 |  | 
| 622 663 | 
             
              VALUE input_data;   /* data read from source file, e.g. YAML or ruby source */
         | 
| 623 664 | 
             
              VALUE storage_data; /* compiled data, e.g. msgpack / binary iseq */
         | 
| @@ -644,7 +685,7 @@ bs_fetch(char * path, VALUE path_v, char * cache_path, VALUE handler) | |
| 644 685 | 
             
              if (valid_cache) {
         | 
| 645 686 | 
             
                /* Fetch the cache data and return it if we're able to load it successfully */
         | 
| 646 687 | 
             
                res = fetch_cached_data(
         | 
| 647 | 
            -
                  cache_fd, (ssize_t)cached_key.data_size, handler,
         | 
| 688 | 
            +
                  cache_fd, (ssize_t)cached_key.data_size, handler, args,
         | 
| 648 689 | 
             
                  &output_data, &exception_tag, &errno_provenance
         | 
| 649 690 | 
             
                );
         | 
| 650 691 | 
             
                if (exception_tag != 0)                   goto raise;
         | 
| @@ -658,15 +699,15 @@ bs_fetch(char * path, VALUE path_v, char * cache_path, VALUE handler) | |
| 658 699 |  | 
| 659 700 | 
             
              /* Read the contents of the source file into a buffer */
         | 
| 660 701 | 
             
              if (bs_read_contents(current_fd, current_key.size, &contents, &errno_provenance) < 0) goto fail_errno;
         | 
| 661 | 
            -
              input_data =  | 
| 702 | 
            +
              input_data = rb_str_new(contents, current_key.size);
         | 
| 662 703 |  | 
| 663 704 | 
             
              /* Try to compile the input_data using input_to_storage(input_data) */
         | 
| 664 | 
            -
              exception_tag = bs_input_to_storage(handler, input_data, path_v, &storage_data);
         | 
| 705 | 
            +
              exception_tag = bs_input_to_storage(handler, args, input_data, path_v, &storage_data);
         | 
| 665 706 | 
             
              if (exception_tag != 0) goto raise;
         | 
| 666 707 | 
             
              /* If input_to_storage raised Bootsnap::CompileCache::Uncompilable, don't try
         | 
| 667 708 | 
             
               * to cache anything; just return input_to_output(input_data) */
         | 
| 668 709 | 
             
              if (storage_data == uncompilable) {
         | 
| 669 | 
            -
                bs_input_to_output(handler, input_data, &output_data, &exception_tag);
         | 
| 710 | 
            +
                bs_input_to_output(handler, args, input_data, &output_data, &exception_tag);
         | 
| 670 711 | 
             
                if (exception_tag != 0) goto raise;
         | 
| 671 712 | 
             
                goto succeed;
         | 
| 672 713 | 
             
              }
         | 
| @@ -678,17 +719,17 @@ bs_fetch(char * path, VALUE path_v, char * cache_path, VALUE handler) | |
| 678 719 | 
             
              if (res < 0) goto fail_errno;
         | 
| 679 720 |  | 
| 680 721 | 
             
              /* Having written the cache, now convert storage_data to output_data */
         | 
| 681 | 
            -
              exception_tag = bs_storage_to_output(handler, storage_data, &output_data);
         | 
| 722 | 
            +
              exception_tag = bs_storage_to_output(handler, args, storage_data, &output_data);
         | 
| 682 723 | 
             
              if (exception_tag != 0) goto raise;
         | 
| 683 724 |  | 
| 684 725 | 
             
              /* If output_data is nil, delete the cache entry and generate the output
         | 
| 685 726 | 
             
               * using input_to_output */
         | 
| 686 727 | 
             
              if (NIL_P(output_data)) {
         | 
| 687 728 | 
             
                if (unlink(cache_path) < 0) {
         | 
| 688 | 
            -
                  errno_provenance =  | 
| 729 | 
            +
                  errno_provenance = "bs_fetch:unlink";
         | 
| 689 730 | 
             
                  goto fail_errno;
         | 
| 690 731 | 
             
                }
         | 
| 691 | 
            -
                bs_input_to_output(handler, input_data, &output_data, &exception_tag);
         | 
| 732 | 
            +
                bs_input_to_output(handler, args, input_data, &output_data, &exception_tag);
         | 
| 692 733 | 
             
                if (exception_tag != 0) goto raise;
         | 
| 693 734 | 
             
              }
         | 
| 694 735 |  | 
| @@ -719,6 +760,79 @@ invalid_type_storage_data: | |
| 719 760 | 
             
            #undef CLEANUP
         | 
| 720 761 | 
             
            }
         | 
| 721 762 |  | 
| 763 | 
            +
            static VALUE
         | 
| 764 | 
            +
            bs_precompile(char * path, VALUE path_v, char * cache_path, VALUE handler)
         | 
| 765 | 
            +
            {
         | 
| 766 | 
            +
              struct bs_cache_key cached_key, current_key;
         | 
| 767 | 
            +
              char * contents = NULL;
         | 
| 768 | 
            +
              int cache_fd = -1, current_fd = -1;
         | 
| 769 | 
            +
              int res, valid_cache = 0, exception_tag = 0;
         | 
| 770 | 
            +
              const char * errno_provenance = NULL;
         | 
| 771 | 
            +
             | 
| 772 | 
            +
              VALUE input_data;   /* data read from source file, e.g. YAML or ruby source */
         | 
| 773 | 
            +
              VALUE storage_data; /* compiled data, e.g. msgpack / binary iseq */
         | 
| 774 | 
            +
             | 
| 775 | 
            +
              /* Open the source file and generate a cache key for it */
         | 
| 776 | 
            +
              current_fd = open_current_file(path, ¤t_key, &errno_provenance);
         | 
| 777 | 
            +
              if (current_fd < 0) goto fail;
         | 
| 778 | 
            +
             | 
| 779 | 
            +
              /* Open the cache key if it exists, and read its cache key in */
         | 
| 780 | 
            +
              cache_fd = open_cache_file(cache_path, &cached_key, &errno_provenance);
         | 
| 781 | 
            +
              if (cache_fd == CACHE_MISSING_OR_INVALID) {
         | 
| 782 | 
            +
                /* This is ok: valid_cache remains false, we re-populate it. */
         | 
| 783 | 
            +
              } else if (cache_fd < 0) {
         | 
| 784 | 
            +
                goto fail;
         | 
| 785 | 
            +
              } else {
         | 
| 786 | 
            +
                /* True if the cache existed and no invalidating changes have occurred since
         | 
| 787 | 
            +
                 * it was generated. */
         | 
| 788 | 
            +
                valid_cache = cache_key_equal(¤t_key, &cached_key);
         | 
| 789 | 
            +
              }
         | 
| 790 | 
            +
             | 
| 791 | 
            +
              if (valid_cache) {
         | 
| 792 | 
            +
                goto succeed;
         | 
| 793 | 
            +
              }
         | 
| 794 | 
            +
             | 
| 795 | 
            +
              close(cache_fd);
         | 
| 796 | 
            +
              cache_fd = -1;
         | 
| 797 | 
            +
              /* Cache is stale, invalid, or missing. Regenerate and write it out. */
         | 
| 798 | 
            +
             | 
| 799 | 
            +
              /* Read the contents of the source file into a buffer */
         | 
| 800 | 
            +
              if (bs_read_contents(current_fd, current_key.size, &contents, &errno_provenance) < 0) goto fail;
         | 
| 801 | 
            +
              input_data = rb_str_new(contents, current_key.size);
         | 
| 802 | 
            +
             | 
| 803 | 
            +
              /* Try to compile the input_data using input_to_storage(input_data) */
         | 
| 804 | 
            +
              exception_tag = bs_input_to_storage(handler, Qnil, input_data, path_v, &storage_data);
         | 
| 805 | 
            +
              if (exception_tag != 0) goto fail;
         | 
| 806 | 
            +
             | 
| 807 | 
            +
              /* If input_to_storage raised Bootsnap::CompileCache::Uncompilable, don't try
         | 
| 808 | 
            +
               * to cache anything; just return false */
         | 
| 809 | 
            +
              if (storage_data == uncompilable) {
         | 
| 810 | 
            +
                goto fail;
         | 
| 811 | 
            +
              }
         | 
| 812 | 
            +
              /* If storage_data isn't a string, we can't cache it */
         | 
| 813 | 
            +
              if (!RB_TYPE_P(storage_data, T_STRING)) goto fail;
         | 
| 814 | 
            +
             | 
| 815 | 
            +
              /* Write the cache key and storage_data to the cache directory */
         | 
| 816 | 
            +
              res = atomic_write_cache_file(cache_path, ¤t_key, storage_data, &errno_provenance);
         | 
| 817 | 
            +
              if (res < 0) goto fail;
         | 
| 818 | 
            +
             | 
| 819 | 
            +
              goto succeed;
         | 
| 820 | 
            +
             | 
| 821 | 
            +
            #define CLEANUP \
         | 
| 822 | 
            +
              if (contents != NULL) xfree(contents);   \
         | 
| 823 | 
            +
              if (current_fd >= 0)  close(current_fd); \
         | 
| 824 | 
            +
              if (cache_fd >= 0)    close(cache_fd);
         | 
| 825 | 
            +
             | 
| 826 | 
            +
            succeed:
         | 
| 827 | 
            +
              CLEANUP;
         | 
| 828 | 
            +
              return Qtrue;
         | 
| 829 | 
            +
            fail:
         | 
| 830 | 
            +
              CLEANUP;
         | 
| 831 | 
            +
              return Qfalse;
         | 
| 832 | 
            +
            #undef CLEANUP
         | 
| 833 | 
            +
            }
         | 
| 834 | 
            +
             | 
| 835 | 
            +
             | 
| 722 836 | 
             
            /*****************************************************************************/
         | 
| 723 837 | 
             
            /********************* Handler Wrappers **************************************/
         | 
| 724 838 | 
             
            /*****************************************************************************
         | 
| @@ -738,11 +852,13 @@ invalid_type_storage_data: | |
| 738 852 |  | 
| 739 853 | 
             
            struct s2o_data {
         | 
| 740 854 | 
             
              VALUE handler;
         | 
| 855 | 
            +
              VALUE args;
         | 
| 741 856 | 
             
              VALUE storage_data;
         | 
| 742 857 | 
             
            };
         | 
| 743 858 |  | 
| 744 859 | 
             
            struct i2o_data {
         | 
| 745 860 | 
             
              VALUE handler;
         | 
| 861 | 
            +
              VALUE args;
         | 
| 746 862 | 
             
              VALUE input_data;
         | 
| 747 863 | 
             
            };
         | 
| 748 864 |  | 
| @@ -756,15 +872,16 @@ static VALUE | |
| 756 872 | 
             
            prot_storage_to_output(VALUE arg)
         | 
| 757 873 | 
             
            {
         | 
| 758 874 | 
             
              struct s2o_data * data = (struct s2o_data *)arg;
         | 
| 759 | 
            -
              return rb_funcall(data->handler, rb_intern("storage_to_output"),  | 
| 875 | 
            +
              return rb_funcall(data->handler, rb_intern("storage_to_output"), 2, data->storage_data, data->args);
         | 
| 760 876 | 
             
            }
         | 
| 761 877 |  | 
| 762 878 | 
             
            static int
         | 
| 763 | 
            -
            bs_storage_to_output(VALUE handler, VALUE storage_data, VALUE * output_data)
         | 
| 879 | 
            +
            bs_storage_to_output(VALUE handler, VALUE args, VALUE storage_data, VALUE * output_data)
         | 
| 764 880 | 
             
            {
         | 
| 765 881 | 
             
              int state;
         | 
| 766 882 | 
             
              struct s2o_data s2o_data = {
         | 
| 767 883 | 
             
                .handler      = handler,
         | 
| 884 | 
            +
                .args         = args,
         | 
| 768 885 | 
             
                .storage_data = storage_data,
         | 
| 769 886 | 
             
              };
         | 
| 770 887 | 
             
              *output_data = rb_protect(prot_storage_to_output, (VALUE)&s2o_data, &state);
         | 
| @@ -772,10 +889,11 @@ bs_storage_to_output(VALUE handler, VALUE storage_data, VALUE * output_data) | |
| 772 889 | 
             
            }
         | 
| 773 890 |  | 
| 774 891 | 
             
            static void
         | 
| 775 | 
            -
            bs_input_to_output(VALUE handler, VALUE input_data, VALUE * output_data, int * exception_tag)
         | 
| 892 | 
            +
            bs_input_to_output(VALUE handler, VALUE args, VALUE input_data, VALUE * output_data, int * exception_tag)
         | 
| 776 893 | 
             
            {
         | 
| 777 894 | 
             
              struct i2o_data i2o_data = {
         | 
| 778 895 | 
             
                .handler    = handler,
         | 
| 896 | 
            +
                .args       = args,
         | 
| 779 897 | 
             
                .input_data = input_data,
         | 
| 780 898 | 
             
              };
         | 
| 781 899 | 
             
              *output_data = rb_protect(prot_input_to_output, (VALUE)&i2o_data, exception_tag);
         | 
| @@ -785,7 +903,7 @@ static VALUE | |
| 785 903 | 
             
            prot_input_to_output(VALUE arg)
         | 
| 786 904 | 
             
            {
         | 
| 787 905 | 
             
              struct i2o_data * data = (struct i2o_data *)arg;
         | 
| 788 | 
            -
              return rb_funcall(data->handler, rb_intern("input_to_output"),  | 
| 906 | 
            +
              return rb_funcall(data->handler, rb_intern("input_to_output"), 2, data->input_data, data->args);
         | 
| 789 907 | 
             
            }
         | 
| 790 908 |  | 
| 791 909 | 
             
            static VALUE
         | 
| @@ -796,7 +914,7 @@ try_input_to_storage(VALUE arg) | |
| 796 914 | 
             
            }
         | 
| 797 915 |  | 
| 798 916 | 
             
            static VALUE
         | 
| 799 | 
            -
            rescue_input_to_storage(VALUE arg)
         | 
| 917 | 
            +
            rescue_input_to_storage(VALUE arg, VALUE e)
         | 
| 800 918 | 
             
            {
         | 
| 801 919 | 
             
              return uncompilable;
         | 
| 802 920 | 
             
            }
         | 
| @@ -812,7 +930,7 @@ prot_input_to_storage(VALUE arg) | |
| 812 930 | 
             
            }
         | 
| 813 931 |  | 
| 814 932 | 
             
            static int
         | 
| 815 | 
            -
            bs_input_to_storage(VALUE handler, VALUE input_data, VALUE pathval, VALUE * storage_data)
         | 
| 933 | 
            +
            bs_input_to_storage(VALUE handler, VALUE args, VALUE input_data, VALUE pathval, VALUE * storage_data)
         | 
| 816 934 | 
             
            {
         | 
| 817 935 | 
             
              int state;
         | 
| 818 936 | 
             
              struct i2s_data i2s_data = {
         | 
    
        data/ext/bootsnap/extconf.rb
    CHANGED
    
    
    
        data/lib/bootsnap/bundler.rb
    CHANGED