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.
- checksums.yaml +4 -4
- data/FEATURES.md +4 -0
- data/README.md +142 -198
- data/VERSION +1 -1
- data/lib/scint/cache/layout.rb +66 -5
- data/lib/scint/cache/manifest.rb +120 -0
- data/lib/scint/cache/prewarm.rb +445 -33
- data/lib/scint/cache/validity.rb +134 -0
- data/lib/scint/cli/cache.rb +34 -6
- data/lib/scint/cli/exec.rb +1 -1
- data/lib/scint/cli/install.rb +611 -292
- data/lib/scint/fs.rb +175 -28
- data/lib/scint/gem/package.rb +6 -2
- data/lib/scint/gemfile/parser.rb +13 -6
- data/lib/scint/index/client.rb +13 -2
- data/lib/scint/installer/extension_builder.rb +63 -43
- data/lib/scint/installer/linker.rb +43 -2
- data/lib/scint/installer/planner.rb +24 -28
- data/lib/scint/installer/preparer.rb +167 -37
- data/lib/scint/installer/promoter.rb +97 -0
- data/lib/scint/linker.sh +137 -0
- data/lib/scint/spec_utils.rb +79 -0
- data/lib/scint.rb +12 -4
- metadata +5 -1
|
@@ -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
|
data/lib/scint/cli/cache.rb
CHANGED
|
@@ -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
|
-
|
|
184
|
-
|
|
185
|
-
|
|
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
|
|
data/lib/scint/cli/exec.rb
CHANGED
|
@@ -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 =
|
|
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
|