Script 'mail_helper' called by obssrc
Hello community,

here is the log from the commit of package rubygem-bootsnap for 
openSUSE:Factory checked in at 2024-06-24 20:54:50
++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Comparing /work/SRC/openSUSE:Factory/rubygem-bootsnap (Old)
 and      /work/SRC/openSUSE:Factory/.rubygem-bootsnap.new.18349 (New)
++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++

Package is "rubygem-bootsnap"

Mon Jun 24 20:54:50 2024 rev:24 rq:1182765 version:1.18.3

Changes:
--------
--- /work/SRC/openSUSE:Factory/rubygem-bootsnap/rubygem-bootsnap.changes        
2024-02-26 19:49:43.651315299 +0100
+++ 
/work/SRC/openSUSE:Factory/.rubygem-bootsnap.new.18349/rubygem-bootsnap.changes 
    2024-06-24 20:56:25.715156968 +0200
@@ -1,0 +2,29 @@
+Fri Jun 21 09:33:29 UTC 2024 - Dan Čermák <dan.cer...@posteo.net>
+
+- # 1.18.3
+
+* Fix the cache corruption issue in the revalidation feature. See #474.
+  The cache revalidation feature remains opt-in for now, until it is more 
battle tested.
+
+# 1.18.2
+
+* Disable stale cache entries revalidation by default as it seems to cause 
cache corruption issues. See #471 and #474.
+  Will be re-enabled in a future version once the root cause is identified.
+* Fix a potential compilation issue on some systems. See #470.
+
+# 1.18.1
+
+* Handle `EPERM` errors when opening files with `O_NOATIME`.
+
+# 1.18.0
+
+* `Bootsnap.instrumentation` now receive `:hit` events.
+* Add `Bootsnap.log_stats!` to print hit rate statistics on process exit. Can 
also be enabled with `BOOTSNAP_STATS=1`.
+* Revalidate stale cache entries by digesting the source content.
+  This should significantly improve performance in environments where `mtime` 
isn't preserved (e.g. CI systems doing a git clone, etc).
+  See #468.
+* Open source files and cache entries with `O_NOATIME` when available to 
reduce disk accesses. See #469.
+* `bootsnap precompile --gemfile` now look for `.rb` files in the whole gem 
and not just the `lib/` directory. See #466.
+
+
+-------------------------------------------------------------------

Old:
----
  bootsnap-1.17.1.gem

New:
----
  bootsnap-1.18.3.gem

++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++

Other differences:
------------------
++++++ rubygem-bootsnap.spec ++++++
--- /var/tmp/diff_new_pack.jiQa2n/_old  2024-06-24 20:56:27.179210526 +0200
+++ /var/tmp/diff_new_pack.jiQa2n/_new  2024-06-24 20:56:27.195211111 +0200
@@ -24,7 +24,7 @@
 #
 
 Name:           rubygem-bootsnap
-Version:        1.17.1
+Version:        1.18.3
 Release:        0
 %define mod_name bootsnap
 %define mod_full_name %{mod_name}-%{version}

++++++ bootsnap-1.17.1.gem -> bootsnap-1.18.3.gem ++++++
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/CHANGELOG.md new/CHANGELOG.md
--- old/CHANGELOG.md    2024-01-12 12:03:46.000000000 +0100
+++ new/CHANGELOG.md    2024-01-31 15:42:25.000000000 +0100
@@ -1,5 +1,30 @@
 # Unreleased
 
+# 1.18.3
+
+* Fix the cache corruption issue in the revalidation feature. See #474.
+  The cache revalidation feature remains opt-in for now, until it is more 
battle tested.
+
+# 1.18.2
+
+* Disable stale cache entries revalidation by default as it seems to cause 
cache corruption issues. See #471 and #474.
+  Will be re-enabled in a future version once the root cause is identified.
+* Fix a potential compilation issue on some systems. See #470.
+
+# 1.18.1
+
+* Handle `EPERM` errors when opening files with `O_NOATIME`.
+
+# 1.18.0
+
+* `Bootsnap.instrumentation` now receive `:hit` events.
+* Add `Bootsnap.log_stats!` to print hit rate statistics on process exit. Can 
also be enabled with `BOOTSNAP_STATS=1`.
+* Revalidate stale cache entries by digesting the source content.
+  This should significantly improve performance in environments where `mtime` 
isn't preserved (e.g. CI systems doing a git clone, etc).
+  See #468.
+* Open source files and cache entries with `O_NOATIME` when available to 
reduce disk accesses. See #469.
+* `bootsnap precompile --gemfile` now look for `.rb` files in the whole gem 
and not just the `lib/` directory. See #466.
+
 # 1.17.1
 
 * Fix a compatibility issue with the `prism` library that ships with Ruby 3.3. 
See #463.
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/README.md new/README.md
--- old/README.md       2024-01-12 12:03:46.000000000 +0100
+++ new/README.md       2024-01-31 15:42:25.000000000 +0100
@@ -81,6 +81,7 @@
 - `DISABLE_BOOTSNAP_COMPILE_CACHE` allows to disable ISeq and YAML caches.
 - `BOOTSNAP_READONLY` configure bootsnap to not update the cache on miss or 
stale entries.
 - `BOOTSNAP_LOG` configure bootsnap to log all caches misses to STDERR.
+- `BOOTSNAP_STATS` log hit rate statistics on exit. Can't be used if 
`BOOTSNAP_LOG` is enabled.
 - `BOOTSNAP_IGNORE_DIRECTORIES` a comma separated list of directories that 
shouldn't be scanned.
   Useful when you have large directories of non-ruby files inside `$LOAD_PATH`.
   It defaults to ignore any directory named `node_modules`.
@@ -99,8 +100,8 @@
 Bootsnap.instrumentation = ->(event, path) { puts "#{event} #{path}" }
 ```
 
-`event` is either `:miss` or `:stale`. You can also call `Bootsnap.log!` as a 
shortcut to
-log all events to STDERR.
+`event` is either `:hit`, `:miss`, `:stale` or `:revalidated`.
+You can also call `Bootsnap.log!` as a shortcut to log all events to STDERR.
 
 To turn instrumentation back off you can set it to nil:
 
Binary files old/checksums.yaml.gz and new/checksums.yaml.gz differ
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/ext/bootsnap/bootsnap.c new/ext/bootsnap/bootsnap.c
--- old/ext/bootsnap/bootsnap.c 2024-01-12 12:03:46.000000000 +0100
+++ new/ext/bootsnap/bootsnap.c 2024-01-31 15:42:25.000000000 +0100
@@ -18,8 +18,19 @@
 #include <sys/types.h>
 #include <errno.h>
 #include <fcntl.h>
+#include <unistd.h>
 #include <sys/stat.h>
 
+#ifdef __APPLE__
+  // The symbol is present, however not in the headers
+  // See: https://github.com/Shopify/bootsnap/issues/470
+  extern int fdatasync(int);
+#endif
+
+#ifndef O_NOATIME
+#define O_NOATIME 0
+#endif
+
 /* 1000 is an arbitrary limit; FNV64 plus some slashes brings the cap down to
  * 981 for the cache dir */
 #define MAX_CACHEPATH_SIZE 1000
@@ -30,7 +41,7 @@
 #define MAX_CREATE_TEMPFILE_ATTEMPT 3
 
 #ifndef RB_UNLIKELY
-  #define RB_UNLIKELY(x) (x)
+#define RB_UNLIKELY(x) (x)
 #endif
 
 /*
@@ -54,8 +65,10 @@
   uint32_t ruby_revision;
   uint64_t size;
   uint64_t mtime;
-  uint64_t data_size; /* not used for equality */
-  uint8_t  pad[24];
+  uint64_t data_size; //
+  uint64_t digest;
+  uint8_t digest_set;
+  uint8_t pad[15];
 } __attribute__((packed));
 
 /*
@@ -69,7 +82,7 @@
 STATIC_ASSERT(sizeof(struct bs_cache_key) == KEY_SIZE);
 
 /* Effectively a schema version. Bumping invalidates all previous caches */
-static const uint32_t current_version = 4;
+static const uint32_t current_version = 5;
 
 /* hash of e.g. "x86_64-darwin17", invalidating when ruby is recompiled on a
  * new OS ABI, etc. */
@@ -87,25 +100,36 @@
 static VALUE rb_mBootsnap_CompileCache_Native;
 static VALUE rb_cBootsnap_CompileCache_UNCOMPILABLE;
 static ID instrumentation_method;
-static VALUE sym_miss;
-static VALUE sym_stale;
+static VALUE sym_hit, sym_miss, sym_stale, sym_revalidated;
 static bool instrumentation_enabled = false;
 static bool readonly = false;
+static bool revalidation = false;
+static bool perm_issue = false;
 
 /* Functions exposed as module functions on Bootsnap::CompileCache::Native */
 static VALUE bs_instrumentation_enabled_set(VALUE self, VALUE enabled);
 static VALUE bs_readonly_set(VALUE self, VALUE enabled);
+static VALUE bs_revalidation_set(VALUE self, VALUE enabled);
 static VALUE bs_compile_option_crc32_set(VALUE self, VALUE crc32_v);
 static VALUE bs_rb_fetch(VALUE self, VALUE cachedir_v, VALUE path_v, VALUE 
handler, VALUE args);
 static VALUE bs_rb_precompile(VALUE self, VALUE cachedir_v, VALUE path_v, 
VALUE handler);
 
 /* Helpers */
+enum cache_status {
+  miss,
+  hit,
+  stale,
+};
 static void bs_cache_path(const char * cachedir, const VALUE path, char (* 
cache_path)[MAX_CACHEPATH_SIZE]);
 static int bs_read_key(int fd, struct bs_cache_key * key);
-static int cache_key_equal(struct bs_cache_key * k1, struct bs_cache_key * k2);
+static enum cache_status cache_key_equal_fast_path(struct bs_cache_key * k1, 
struct bs_cache_key * k2);
+static int cache_key_equal_slow_path(struct bs_cache_key * current_key, struct 
bs_cache_key * cached_key, const VALUE input_data);
+static int update_cache_key(struct bs_cache_key *current_key, struct 
bs_cache_key *old_key, int cache_fd, const char ** errno_provenance);
+
+static void bs_cache_key_digest(struct bs_cache_key * key, const VALUE 
input_data);
 static VALUE bs_fetch(char * path, VALUE path_v, char * cache_path, VALUE 
handler, VALUE args);
 static VALUE bs_precompile(char * path, VALUE path_v, char * cache_path, VALUE 
handler);
-static int open_current_file(char * path, struct bs_cache_key * key, const 
char ** errno_provenance);
+static int open_current_file(const char * path, struct bs_cache_key * key, 
const char ** errno_provenance);
 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);
 static uint32_t get_ruby_revision(void);
 static uint32_t get_ruby_platform(void);
@@ -161,14 +185,14 @@
 
   instrumentation_method = rb_intern("_instrument");
 
+  sym_hit = ID2SYM(rb_intern("hit"));
   sym_miss = ID2SYM(rb_intern("miss"));
-  rb_global_variable(&sym_miss);
-
   sym_stale = ID2SYM(rb_intern("stale"));
-  rb_global_variable(&sym_stale);
+  sym_revalidated = ID2SYM(rb_intern("revalidated"));
 
   rb_define_module_function(rb_mBootsnap, "instrumentation_enabled=", 
bs_instrumentation_enabled_set, 1);
   rb_define_module_function(rb_mBootsnap_CompileCache_Native, "readonly=", 
bs_readonly_set, 1);
+  rb_define_module_function(rb_mBootsnap_CompileCache_Native, "revalidation=", 
bs_revalidation_set, 1);
   rb_define_module_function(rb_mBootsnap_CompileCache_Native, 
"coverage_running?", bs_rb_coverage_running, 0);
   rb_define_module_function(rb_mBootsnap_CompileCache_Native, "fetch", 
bs_rb_fetch, 4);
   rb_define_module_function(rb_mBootsnap_CompileCache_Native, "precompile", 
bs_rb_precompile, 3);
@@ -185,6 +209,14 @@
   return enabled;
 }
 
+static inline void
+bs_instrumentation(VALUE event, VALUE path)
+{
+    if (RB_UNLIKELY(instrumentation_enabled)) {
+       rb_funcall(rb_mBootsnap, instrumentation_method, 2, event, path);
+    }
+}
+
 static VALUE
 bs_readonly_set(VALUE self, VALUE enabled)
 {
@@ -192,6 +224,13 @@
   return enabled;
 }
 
+static VALUE
+bs_revalidation_set(VALUE self, VALUE enabled)
+{
+  revalidation = RTEST(enabled);
+  return enabled;
+}
+
 /*
  * Bootsnap's ruby code registers a hook that notifies us via this function
  * when compile_option changes. These changes invalidate all existing caches.
@@ -290,17 +329,59 @@
  * The data_size member is not compared, as it serves more of a "header"
  * function.
  */
-static int
-cache_key_equal(struct bs_cache_key * k1, struct bs_cache_key * k2)
+static enum cache_status cache_key_equal_fast_path(struct bs_cache_key *k1,
+                                     struct bs_cache_key *k2) {
+  if (k1->version == k2->version &&
+          k1->ruby_platform == k2->ruby_platform &&
+          k1->compile_option == k2->compile_option &&
+          k1->ruby_revision == k2->ruby_revision && k1->size == k2->size) {
+      if (k1->mtime == k2->mtime) {
+        return hit;
+      }
+      if (revalidation) {
+        return stale;
+      }
+  }
+  return miss;
+}
+
+static int cache_key_equal_slow_path(struct bs_cache_key *current_key,
+                                     struct bs_cache_key *cached_key,
+                                     const VALUE input_data)
+{
+  bs_cache_key_digest(current_key, input_data);
+  return current_key->digest == cached_key->digest;
+}
+
+static int update_cache_key(struct bs_cache_key *current_key, struct 
bs_cache_key *old_key, int cache_fd, const char ** errno_provenance)
 {
-  return (
-    k1->version        == k2->version        &&
-    k1->ruby_platform  == k2->ruby_platform  &&
-    k1->compile_option == k2->compile_option &&
-    k1->ruby_revision  == k2->ruby_revision  &&
-    k1->size           == k2->size           &&
-    k1->mtime          == k2->mtime
-  );
+  old_key->mtime = current_key->mtime;
+  lseek(cache_fd, 0, SEEK_SET);
+  ssize_t nwrite = write(cache_fd, old_key, KEY_SIZE);
+  if (nwrite < 0) {
+      *errno_provenance = "update_cache_key:write";
+      return -1;
+  }
+
+#ifdef HAVE_FDATASYNC
+  if (fdatasync(cache_fd) < 0) {
+      *errno_provenance = "update_cache_key:fdatasync";
+      return -1;
+  }
+#endif
+
+  return 0;
+}
+
+/*
+ * Fills the cache key digest.
+ */
+static void bs_cache_key_digest(struct bs_cache_key *key,
+                                const VALUE input_data) {
+  if (key->digest_set)
+    return;
+  key->digest = fnv1a_64(input_data);
+  key->digest_set = 1;
 }
 
 /*
@@ -356,17 +437,34 @@
 
   return bs_precompile(path, path_v, cache_path, handler);
 }
+
+static int bs_open_noatime(const char *path, int flags) {
+  int fd = 1;
+  if (!perm_issue) {
+    fd = open(path, flags | O_NOATIME);
+    if (fd < 0 && errno == EPERM) {
+      errno = 0;
+      perm_issue = true;
+    }
+  }
+
+  if (perm_issue) {
+    fd = open(path, flags);
+  }
+  return fd;
+}
+
 /*
  * Open the file we want to load/cache and generate a cache key for it if it
  * was loaded.
  */
 static int
-open_current_file(char * path, struct bs_cache_key * key, const char ** 
errno_provenance)
+open_current_file(const char * path, struct bs_cache_key * key, const char ** 
errno_provenance)
 {
   struct stat statbuf;
   int fd;
 
-  fd = open(path, O_RDONLY);
+  fd = bs_open_noatime(path, O_RDONLY);
   if (fd < 0) {
     *errno_provenance = "bs_fetch:open_current_file:open";
     return fd;
@@ -389,6 +487,7 @@
   key->ruby_revision  = current_ruby_revision;
   key->size           = (uint64_t)statbuf.st_size;
   key->mtime          = (uint64_t)statbuf.st_mtime;
+  key->digest_set     = false;
 
   return fd;
 }
@@ -432,7 +531,12 @@
 {
   int fd, res;
 
-  fd = open(path, O_RDONLY);
+  if (readonly || !revalidation) {
+    fd = bs_open_noatime(path, O_RDONLY);
+  } else {
+    fd = bs_open_noatime(path, O_RDWR);
+  }
+
   if (fd < 0) {
     *errno_provenance = "bs_fetch:open_cache_file:open";
     return CACHE_MISS;
@@ -677,7 +781,8 @@
   int res, valid_cache = 0, exception_tag = 0;
   const char * errno_provenance = NULL;
 
-  VALUE input_data;   /* data read from source file, e.g. YAML or ruby source 
*/
+  VALUE status = Qfalse;
+  VALUE input_data = Qfalse;   /* data read from source file, e.g. YAML or 
ruby source */
   VALUE storage_data; /* compiled data, e.g. msgpack / binary iseq */
   VALUE output_data;  /* return data, e.g. ruby hash or loaded iseq */
 
@@ -695,20 +800,44 @@
   cache_fd = open_cache_file(cache_path, &cached_key, &errno_provenance);
   if (cache_fd == CACHE_MISS || cache_fd == CACHE_STALE) {
     /* This is ok: valid_cache remains false, we re-populate it. */
-    if (RB_UNLIKELY(instrumentation_enabled)) {
-      rb_funcall(rb_mBootsnap, instrumentation_method, 2, cache_fd == 
CACHE_MISS ? sym_miss : sym_stale, path_v);
-    }
+    bs_instrumentation(cache_fd == CACHE_MISS ? sym_miss : sym_stale, path_v);
   } else if (cache_fd < 0) {
     exception_message = rb_str_new_cstr(cache_path);
     goto fail_errno;
   } else {
     /* True if the cache existed and no invalidating changes have occurred 
since
      * it was generated. */
-    valid_cache = cache_key_equal(&current_key, &cached_key);
-    if (RB_UNLIKELY(instrumentation_enabled)) {
-      if (!valid_cache) {
-        rb_funcall(rb_mBootsnap, instrumentation_method, 2, sym_stale, path_v);
+
+    switch(cache_key_equal_fast_path(&current_key, &cached_key)) {
+    case hit:
+      status = sym_hit;
+      valid_cache = true;
+      break;
+    case miss:
+      valid_cache = false;
+      break;
+    case stale:
+      valid_cache = false;
+      if ((input_data = bs_read_contents(current_fd, current_key.size,
+                                     &errno_provenance)) == Qfalse) {
+        exception_message = path_v;
+        goto fail_errno;
+      }
+      valid_cache = cache_key_equal_slow_path(&current_key, &cached_key, 
input_data);
+      if (valid_cache) {
+        if (!readonly) {
+          if (update_cache_key(&current_key, &cached_key, cache_fd, 
&errno_provenance)) {
+              exception_message = path_v;
+              goto fail_errno;
+          }
+        }
+        status = sym_revalidated;
       }
+      break;
+    };
+
+    if (!valid_cache) {
+      status = sym_stale;
     }
   }
 
@@ -722,7 +851,7 @@
     else if (res == CACHE_UNCOMPILABLE) {
       /* If fetch_cached_data returned `Uncompilable` we fallback to 
`input_to_output`
         This happens if we have say, an unsafe YAML cache, but try to load it 
in safe mode */
-      if ((input_data = bs_read_contents(current_fd, current_key.size, 
&errno_provenance)) == Qfalse){
+      if (input_data == Qfalse && (input_data = bs_read_contents(current_fd, 
current_key.size, &errno_provenance)) == Qfalse) {
         exception_message = path_v;
         goto fail_errno;
       }
@@ -741,7 +870,7 @@
   /* Cache is stale, invalid, or missing. Regenerate and write it out. */
 
   /* Read the contents of the source file into a buffer */
-  if ((input_data = bs_read_contents(current_fd, current_key.size, 
&errno_provenance)) == Qfalse){
+  if (input_data == Qfalse && (input_data = bs_read_contents(current_fd, 
current_key.size, &errno_provenance)) == Qfalse) {
     exception_message = path_v;
     goto fail_errno;
   }
@@ -763,6 +892,7 @@
    * We do however ignore any failures to persist the cache, as it's better
    * to move along, than to interrupt the process.
    */
+  bs_cache_key_digest(&current_key, input_data);
   atomic_write_cache_file(cache_path, &current_key, storage_data, 
&errno_provenance);
 
   /* Having written the cache, now convert storage_data to output_data */
@@ -792,6 +922,7 @@
   goto succeed; /* output_data is now the correct return. */
 
 #define CLEANUP \
+  if (status != Qfalse) bs_instrumentation(status, path_v); \
   if (current_fd >= 0)  close(current_fd); \
   if (cache_fd >= 0)    close(cache_fd);
 
@@ -800,6 +931,12 @@
   return output_data;
 fail_errno:
   CLEANUP;
+  if (errno_provenance) {
+    exception_message = rb_str_concat(
+      rb_str_new_cstr(errno_provenance),
+      rb_str_concat(rb_str_new_cstr(": "), exception_message)
+    );
+  }
   exception = rb_syserr_new_str(errno, exception_message);
   rb_exc_raise(exception);
   __builtin_unreachable();
@@ -818,13 +955,16 @@
 static VALUE
 bs_precompile(char * path, VALUE path_v, char * cache_path, VALUE handler)
 {
+  if (readonly) {
+    return Qfalse;
+  }
+
   struct bs_cache_key cached_key, current_key;
-  char * contents = NULL;
   int cache_fd = -1, current_fd = -1;
   int res, valid_cache = 0, exception_tag = 0;
   const char * errno_provenance = NULL;
 
-  VALUE input_data;   /* data read from source file, e.g. YAML or ruby source 
*/
+  VALUE input_data = Qfalse;   /* data read from source file, e.g. YAML or 
ruby source */
   VALUE storage_data; /* compiled data, e.g. msgpack / binary iseq */
 
   /* Open the source file and generate a cache key for it */
@@ -840,7 +980,26 @@
   } else {
     /* True if the cache existed and no invalidating changes have occurred 
since
      * it was generated. */
-    valid_cache = cache_key_equal(&current_key, &cached_key);
+    switch(cache_key_equal_fast_path(&current_key, &cached_key)) {
+    case hit:
+      valid_cache = true;
+      break;
+    case miss:
+      valid_cache = false;
+      break;
+    case stale:
+      valid_cache = false;
+      if ((input_data = bs_read_contents(current_fd, current_key.size, 
&errno_provenance)) == Qfalse) {
+        goto fail;
+      }
+      valid_cache = cache_key_equal_slow_path(&current_key, &cached_key, 
input_data);
+       if (valid_cache) {
+         if (update_cache_key(&current_key, &cached_key, cache_fd, 
&errno_provenance)) {
+             goto fail;
+         }
+      }
+      break;
+    };
   }
 
   if (valid_cache) {
@@ -867,6 +1026,7 @@
   if (!RB_TYPE_P(storage_data, T_STRING)) goto fail;
 
   /* Write the cache key and storage_data to the cache directory */
+  bs_cache_key_digest(&current_key, input_data);
   res = atomic_write_cache_file(cache_path, &current_key, storage_data, 
&errno_provenance);
   if (res < 0) goto fail;
 
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/ext/bootsnap/extconf.rb new/ext/bootsnap/extconf.rb
--- old/ext/bootsnap/extconf.rb 2024-01-12 12:03:46.000000000 +0100
+++ new/ext/bootsnap/extconf.rb 2024-01-31 15:42:25.000000000 +0100
@@ -3,21 +3,28 @@
 require "mkmf"
 
 if %w[ruby truffleruby].include?(RUBY_ENGINE)
-  $CFLAGS << " -O3 "
-  $CFLAGS << " -std=c99"
+  have_func "fdatasync", "unistd.h"
+
+  unless RUBY_PLATFORM.match?(/mswin|mingw|cygwin/)
+    append_cppflags ["-D_GNU_SOURCE"] # Needed of O_NOATIME
+  end
+
+  append_cflags ["-O3", "-std=c99"]
 
   # ruby.h has some -Wpedantic fails in some cases
   # (e.g. https://github.com/Shopify/bootsnap/issues/15)
   unless ["0", "", nil].include?(ENV["BOOTSNAP_PEDANTIC"])
-    $CFLAGS << " -Wall"
-    $CFLAGS << " -Werror"
-    $CFLAGS << " -Wextra"
-    $CFLAGS << " -Wpedantic"
-
-    $CFLAGS << " -Wno-unused-parameter" # VALUE self has to be there but we 
don't care what it is.
-    $CFLAGS << " -Wno-keyword-macro" # hiding return
-    $CFLAGS << " -Wno-gcc-compat" # ruby.h 2.6.0 on macos 10.14, dunno
-    $CFLAGS << " -Wno-compound-token-split-by-macro"
+    append_cflags([
+      "-Wall",
+      "-Werror",
+      "-Wextra",
+      "-Wpedantic",
+
+      "-Wno-unused-parameter", # VALUE self has to be there but we don't care 
what it is.
+      "-Wno-keyword-macro", # hiding return
+      "-Wno-gcc-compat", # ruby.h 2.6.0 on macos 10.14, dunno
+      "-Wno-compound-token-split-by-macro",
+    ])
   end
 
   create_makefile("bootsnap/bootsnap")
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/lib/bootsnap/cli.rb new/lib/bootsnap/cli.rb
--- old/lib/bootsnap/cli.rb     2024-01-12 12:03:46.000000000 +0100
+++ new/lib/bootsnap/cli.rb     2024-01-31 15:42:25.000000000 +0100
@@ -60,14 +60,16 @@
         precompile_json_files(main_sources)
 
         if compile_gemfile
-          # Some gems embed their tests, they're very unlikely to be loaded, 
so not worth precompiling.
-          gem_exclude = Regexp.union([exclude, "/spec/", "/test/"].compact)
-          precompile_ruby_files($LOAD_PATH.map { |d| File.expand_path(d) }, 
exclude: gem_exclude)
-
           # Gems that include JSON or YAML files usually don't put them in 
`lib/`.
           # So we look at the gem root.
+          # Similarly, gems that include Rails engines generally file Ruby 
files in `app/`.
+          # However some gems embed their tests, they're very unlikely to be 
loaded, so not worth precompiling.
+          gem_exclude = Regexp.union([exclude, "/spec/", "/test/", 
"/features/"].compact)
+
           gem_pattern = 
%r{^#{Regexp.escape(Bundler.bundle_path.to_s)}/?(?:bundler/)?gems/[^/]+}
-          gem_paths = $LOAD_PATH.map { |p| p[gem_pattern] }.compact.uniq
+          gem_paths = $LOAD_PATH.map { |p| p[gem_pattern] || p }.uniq
+
+          precompile_ruby_files(gem_paths, exclude: gem_exclude)
           precompile_yaml_files(gem_paths, exclude: gem_exclude)
           precompile_json_files(gem_paths, exclude: gem_exclude)
         end
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/lib/bootsnap/compile_cache.rb 
new/lib/bootsnap/compile_cache.rb
--- old/lib/bootsnap/compile_cache.rb   2024-01-12 12:03:46.000000000 +0100
+++ new/lib/bootsnap/compile_cache.rb   2024-01-31 15:42:25.000000000 +0100
@@ -9,7 +9,7 @@
 
     Error = Class.new(StandardError)
 
-    def self.setup(cache_dir:, iseq:, yaml:, json:, readonly: false)
+    def self.setup(cache_dir:, iseq:, yaml:, json:, readonly: false, 
revalidation: false)
       if iseq
         if supported?
           require_relative "compile_cache/iseq"
@@ -39,6 +39,7 @@
 
       if supported? && defined?(Bootsnap::CompileCache::Native)
         Bootsnap::CompileCache::Native.readonly = readonly
+        Bootsnap::CompileCache::Native.revalidation = revalidation
       end
     end
 
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/lib/bootsnap/version.rb new/lib/bootsnap/version.rb
--- old/lib/bootsnap/version.rb 2024-01-12 12:03:46.000000000 +0100
+++ new/lib/bootsnap/version.rb 2024-01-31 15:42:25.000000000 +0100
@@ -1,5 +1,5 @@
 # frozen_string_literal: true
 
 module Bootsnap
-  VERSION = "1.17.1"
+  VERSION = "1.18.3"
 end
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/lib/bootsnap.rb new/lib/bootsnap.rb
--- old/lib/bootsnap.rb 2024-01-12 12:03:46.000000000 +0100
+++ new/lib/bootsnap.rb 2024-01-31 15:42:25.000000000 +0100
@@ -11,6 +11,16 @@
   class << self
     attr_reader :logger
 
+    def log_stats!
+      stats = {hit: 0, revalidated: 0, miss: 0, stale: 0}
+      self.instrumentation = ->(event, _path) { stats[event] += 1 }
+      Kernel.at_exit do
+        stats.each do |event, count|
+          $stderr.puts "bootsnap #{event}: #{count}"
+        end
+      end
+    end
+
     def log!
       self.logger = $stderr.method(:puts)
     end
@@ -18,9 +28,9 @@
     def logger=(logger)
       @logger = logger
       self.instrumentation = if logger.respond_to?(:debug)
-        ->(event, path) { @logger.debug("[Bootsnap] #{event} #{path}") }
+        ->(event, path) { @logger.debug("[Bootsnap] #{event} #{path}") unless 
event == :hit }
       else
-        ->(event, path) { @logger.call("[Bootsnap] #{event} #{path}") }
+        ->(event, path) { @logger.call("[Bootsnap] #{event} #{path}") unless 
event == :hit }
       end
     end
 
@@ -41,6 +51,7 @@
       load_path_cache: true,
       ignore_directories: nil,
       readonly: false,
+      revalidation: false,
       compile_cache_iseq: true,
       compile_cache_yaml: true,
       compile_cache_json: true
@@ -60,6 +71,7 @@
         yaml: compile_cache_yaml,
         json: compile_cache_json,
         readonly: readonly,
+        revalidation: revalidation,
       )
     end
 
@@ -110,6 +122,8 @@
 
         if ENV["BOOTSNAP_LOG"]
           log!
+        elsif ENV["BOOTSNAP_STATS"]
+          log_stats!
         end
       end
     end
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/metadata new/metadata
--- old/metadata        2024-01-12 12:03:46.000000000 +0100
+++ new/metadata        2024-01-31 15:42:25.000000000 +0100
@@ -1,14 +1,14 @@
 --- !ruby/object:Gem::Specification
 name: bootsnap
 version: !ruby/object:Gem::Version
-  version: 1.17.1
+  version: 1.18.3
 platform: ruby
 authors:
 - Burke Libbey
 autorequire: 
 bindir: exe
 cert_chain: []
-date: 2024-01-12 00:00:00.000000000 Z
+date: 2024-01-31 00:00:00.000000000 Z
 dependencies:
 - !ruby/object:Gem::Dependency
   name: msgpack
@@ -83,7 +83,7 @@
     - !ruby/object:Gem::Version
       version: '0'
 requirements: []
-rubygems_version: 3.5.4
+rubygems_version: 3.5.5
 signing_key: 
 specification_version: 4
 summary: Boot large ruby/rails apps faster

Reply via email to