scint 0.7.0 → 0.8.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.
@@ -0,0 +1,134 @@
1
+ # frozen_string_literal: true
2
+
3
+ require "json"
4
+ require_relative "../platform"
5
+ require_relative "../installer/extension_builder"
6
+
7
+ module Scint
8
+ module Cache
9
+ class Telemetry
10
+ def initialize
11
+ @counts = Hash.new(0)
12
+ @mutex = Thread::Mutex.new
13
+ end
14
+
15
+ def increment(key, by = 1)
16
+ @mutex.synchronize do
17
+ @counts[key] += by
18
+ end
19
+ end
20
+
21
+ def counts
22
+ @mutex.synchronize { @counts.dup }
23
+ end
24
+
25
+ def warn_if_needed(cache_root:, io: $stderr)
26
+ snapshot = counts
27
+ return if snapshot.empty?
28
+
29
+ header = "Warning: legacy cache fallback used in #{cache_root}"
30
+ io.puts "#{YELLOW}#{header}#{RESET}"
31
+ snapshot.sort.each do |key, value|
32
+ io.puts " #{key}=#{value}"
33
+ end
34
+ end
35
+ end
36
+
37
+ module Validity
38
+ module_function
39
+
40
+ SUPPORTED_MANIFEST_VERSION = 1
41
+
42
+ def cached_valid?(spec, layout, abi_key: Platform.abi_key, telemetry: nil)
43
+ cached_dir = layout.cached_path(spec, abi_key)
44
+ spec_path = layout.cached_spec_path(spec, abi_key)
45
+ manifest_path = layout.cached_manifest_path(spec, abi_key)
46
+
47
+ return false unless Dir.exist?(cached_dir)
48
+ return false unless File.exist?(spec_path)
49
+
50
+ manifest = read_manifest(manifest_path, telemetry: telemetry)
51
+ if manifest
52
+ return false unless manifest_matches?(manifest, spec, abi_key, layout)
53
+ else
54
+ return false unless legacy_spec_loadable?(spec_path)
55
+ end
56
+
57
+ true
58
+ end
59
+
60
+ def source_path_for(spec, layout, abi_key: Platform.abi_key, telemetry: nil, allow_legacy: false)
61
+ cached_dir = layout.cached_path(spec, abi_key)
62
+ return cached_dir if cached_valid?(spec, layout, abi_key: abi_key, telemetry: telemetry)
63
+
64
+ return nil unless allow_legacy
65
+
66
+ legacy = layout.extracted_path(spec)
67
+ return nil unless legacy_extracted_valid?(spec, legacy, layout)
68
+
69
+ telemetry&.increment("cache.legacy.extracted")
70
+ legacy
71
+ end
72
+
73
+ def legacy_extracted_valid?(spec, extracted_dir, layout)
74
+ return false unless Dir.exist?(extracted_dir)
75
+
76
+ legacy_spec_path = layout.spec_cache_path(spec)
77
+ return true if File.exist?(legacy_spec_path)
78
+
79
+ return true if Dir.glob(File.join(extracted_dir, "*.gemspec")).any?
80
+
81
+ true
82
+ rescue StandardError
83
+ false
84
+ end
85
+
86
+ def read_manifest(path, telemetry: nil)
87
+ unless File.exist?(path)
88
+ telemetry&.increment("cache.manifest.missing")
89
+ return nil
90
+ end
91
+
92
+ raw = File.read(path)
93
+ raw.force_encoding("UTF-8") unless raw.encoding == Encoding::UTF_8
94
+ data = JSON.parse(raw)
95
+ return nil unless data.is_a?(Hash)
96
+
97
+ version = data["version"]
98
+ return data if version == SUPPORTED_MANIFEST_VERSION
99
+
100
+ telemetry&.increment("cache.manifest.unsupported")
101
+ nil
102
+ rescue StandardError
103
+ telemetry&.increment("cache.manifest.unsupported")
104
+ nil
105
+ end
106
+
107
+ def manifest_matches?(manifest, spec, abi_key, layout)
108
+ manifest["full_name"] == layout.full_name(spec) && manifest["abi"] == abi_key
109
+ rescue StandardError
110
+ false
111
+ end
112
+
113
+ def legacy_spec_loadable?(path)
114
+ Marshal.load(File.binread(path))
115
+ true
116
+ rescue StandardError
117
+ false
118
+ end
119
+
120
+ def extensions_required?(spec, cached_dir)
121
+ Installer::ExtensionBuilder.needs_build?(spec, cached_dir)
122
+ rescue StandardError
123
+ false
124
+ end
125
+
126
+ def extension_build_complete?(spec, layout, abi_key)
127
+ marker = File.join(layout.cached_path(spec, abi_key), Installer::ExtensionBuilder::BUILD_MARKER)
128
+ File.exist?(marker)
129
+ rescue StandardError
130
+ false
131
+ end
132
+ end
133
+ end
134
+ end
@@ -176,17 +176,45 @@ module Scint
176
176
 
177
177
  def clear_packages(packages)
178
178
  removed = 0
179
- %w[inbound extracted ext].each do |subdir|
180
- subdir_path = File.join(cache_root, subdir)
181
- next unless Dir.exist?(subdir_path)
182
179
 
183
- Dir.children(subdir_path).each do |entry|
184
- if packages.any? { |pkg| entry.start_with?(pkg) }
185
- FileUtils.rm_rf(File.join(subdir_path, entry))
180
+ packages.each do |pkg|
181
+ # inbound gems
182
+ Dir.glob(File.join(cache_root, "inbound", "gems", "#{pkg}-*.gem")).each do |path|
183
+ FileUtils.rm_rf(path)
184
+ removed += 1
185
+ end
186
+
187
+ # assembling + cached (per-ABI)
188
+ %w[assembling cached].each do |subdir|
189
+ Dir.glob(File.join(cache_root, subdir, "*", "#{pkg}-*")) do |path|
190
+ FileUtils.rm_rf(path)
191
+ removed += 1
192
+ end
193
+ Dir.glob(File.join(cache_root, subdir, "*", "#{pkg}-*.spec.marshal")) do |path|
194
+ FileUtils.rm_rf(path)
195
+ removed += 1
196
+ end
197
+ Dir.glob(File.join(cache_root, subdir, "*", "#{pkg}-*.manifest")) do |path|
198
+ FileUtils.rm_rf(path)
186
199
  removed += 1
187
200
  end
188
201
  end
202
+
203
+ # legacy directories (extracted/ext)
204
+ Dir.glob(File.join(cache_root, "extracted", "#{pkg}-*")) do |path|
205
+ FileUtils.rm_rf(path)
206
+ removed += 1
207
+ end
208
+ Dir.glob(File.join(cache_root, "extracted", "#{pkg}-*.spec.marshal")) do |path|
209
+ FileUtils.rm_rf(path)
210
+ removed += 1
211
+ end
212
+ Dir.glob(File.join(cache_root, "ext", "*", "#{pkg}-*")) do |path|
213
+ FileUtils.rm_rf(path)
214
+ removed += 1
215
+ end
189
216
  end
217
+
190
218
  removed
191
219
  end
192
220
 
@@ -118,7 +118,7 @@ module Scint
118
118
  def read_require_paths(spec_file)
119
119
  return ["lib"] unless File.exist?(spec_file)
120
120
 
121
- gemspec = Gem::Specification.load(spec_file)
121
+ gemspec = SpecUtils.load_gemspec(spec_file)
122
122
  paths = Array(gemspec&.require_paths).reject(&:empty?)
123
123
  paths.empty? ? ["lib"] : paths
124
124
  rescue StandardError