tebako-release 0.2.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 +7 -0
- data/LICENSE.md +24 -0
- data/README.md +66 -0
- data/exe/tebako-release +37 -0
- data/lib/tebako_release/adapter.rb +59 -0
- data/lib/tebako_release/bundler.rb +89 -0
- data/lib/tebako_release/config.rb +49 -0
- data/lib/tebako_release/error.rb +11 -0
- data/lib/tebako_release/platform.rb +76 -0
- data/lib/tebako_release/signer.rb +381 -0
- data/lib/tebako_release/uploader.rb +1636 -0
- data/lib/tebako_release/version.rb +9 -0
- data/lib/tebako_release.rb +41 -0
- metadata +72 -0
checksums.yaml
ADDED
|
@@ -0,0 +1,7 @@
|
|
|
1
|
+
---
|
|
2
|
+
SHA256:
|
|
3
|
+
metadata.gz: cd3ef0747dda2fc3ea4d7fcd7f35fe9aeba66cec808604ff7933ba3f644e0191
|
|
4
|
+
data.tar.gz: 24374660ac6c58c5b0d226b67224d84b1f18f3f0f415c666657a6b9aeeebe015
|
|
5
|
+
SHA512:
|
|
6
|
+
metadata.gz: 15a427891a21fb83094aa5f6dd1970a5efe45cb9431b8ab62ad2e7b6faea108c26d7ca66b2743c332c8f4600b3072fa131f0b5002496c90448a5f60da7671305
|
|
7
|
+
data.tar.gz: 23ecefb7508b57e6d9c907e867b8825b54b0915a084a04ff7cf88d1c81f42a1c469b01cd4a6fc1ade5faddfa2a250860e94306c69738c37e8d58d4c33fdd0981
|
data/LICENSE.md
ADDED
|
@@ -0,0 +1,24 @@
|
|
|
1
|
+
Copyright (c) 2026 [Ribose Inc](https://www.ribose.com).
|
|
2
|
+
All rights reserved.
|
|
3
|
+
This file is a part of tamatebako
|
|
4
|
+
|
|
5
|
+
Redistribution and use in source and binary forms, with or without
|
|
6
|
+
modification, are permitted provided that the following conditions
|
|
7
|
+
are met:
|
|
8
|
+
1. Redistributions of source code must retain the above copyright
|
|
9
|
+
notice, this list of conditions and the following disclaimer.
|
|
10
|
+
2. Redistributions in binary form must reproduce the above copyright
|
|
11
|
+
notice, this list of conditions and the following disclaimer in the
|
|
12
|
+
documentation and/or other materials provided with the distribution.
|
|
13
|
+
|
|
14
|
+
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
|
|
15
|
+
``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
|
|
16
|
+
TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
|
|
17
|
+
PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDERS OR CONTRIBUTORS
|
|
18
|
+
BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
|
|
19
|
+
CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
|
|
20
|
+
SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
|
|
21
|
+
INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
|
|
22
|
+
CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
|
|
23
|
+
ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF
|
|
24
|
+
THE POSSIBILITY OF SUCH DAMAGE.
|
data/README.md
ADDED
|
@@ -0,0 +1,66 @@
|
|
|
1
|
+
# tebako-release-tooling
|
|
2
|
+
|
|
3
|
+
The tebako factories' release machinery — the **single owner** of the per-leg
|
|
4
|
+
publish uploader and the no-fold OpenPGP release signer that every runtime
|
|
5
|
+
factory (ruby, python, openjdk, …) consumes. Ecosystem invariant 10: the
|
|
6
|
+
machinery exists exactly once; factories declare their identity and policy
|
|
7
|
+
through a small adapter file and pin this gem — they never carry copies.
|
|
8
|
+
|
|
9
|
+
## What ships here
|
|
10
|
+
|
|
11
|
+
- **`TebakoRelease::Uploader`** (`tebako-release upload`) — the spec 13 §2a
|
|
12
|
+
de-rendezvoused publish: each build leg uploads only the write-once names
|
|
13
|
+
it owns (payloads byte-immutable per name, per-asset `.sha256` sidecars,
|
|
14
|
+
per-package `.manifest.json` shards), with the convergence, rate-limit
|
|
15
|
+
ride-out, and settled-ledger machinery earned against the named incidents
|
|
16
|
+
of the v0.16.x line.
|
|
17
|
+
- **`TebakoRelease::Signer`** (`tebako-release sign`) — spec 09 §5's no-fold
|
|
18
|
+
signing: every served name gets its own detached `.asc`, provenance-checked
|
|
19
|
+
against the release listing's digest, with the young-release-object
|
|
20
|
+
served-bytes convergence.
|
|
21
|
+
- **`TebakoRelease::Bundler`** — spec 36's deterministic bundle builder:
|
|
22
|
+
one `<stem>.tar.gz` per leg (exe + env image + support DLLs + a closing
|
|
23
|
+
in-bundle SHA256SUMS; fixed member order, mtime=0 — identical inputs
|
|
24
|
+
yield identical bytes). A factory opts into the bundle-era publish shape
|
|
25
|
+
through its adapter (`bundle_publish? → true`); the per-file shape stays
|
|
26
|
+
the default for pre-bundle lines.
|
|
27
|
+
- **`TebakoRelease::Platform`** — the release-side platform vocabulary
|
|
28
|
+
(the `(os, arch) → host_id` table; mirrors `tpkg::Platform`, drift fails
|
|
29
|
+
loudly in factory CI).
|
|
30
|
+
|
|
31
|
+
## Consuming factory contract
|
|
32
|
+
|
|
33
|
+
A factory adds the gem, pinned through its `contract.yml` SSOT:
|
|
34
|
+
|
|
35
|
+
```ruby
|
|
36
|
+
# Gemfile
|
|
37
|
+
gem "tebako-release",
|
|
38
|
+
git: "https://github.com/tamatebako/tebako-release-tooling.git",
|
|
39
|
+
tag: YAML.load_file("contract.yml").fetch("release_tooling")
|
|
40
|
+
```
|
|
41
|
+
|
|
42
|
+
and declares itself once in `scripts/release_adapter.rb`:
|
|
43
|
+
|
|
44
|
+
```ruby
|
|
45
|
+
TebakoRelease.configure(
|
|
46
|
+
repo: "tamatebako/tebako-runtime-ruby", # whose releases this run manages
|
|
47
|
+
language: "ruby", # EXPECTED_RUBY_MATRIX, ruby_version key
|
|
48
|
+
title_prefix: "Tebako runtime packages",
|
|
49
|
+
contract_yml: File.expand_path("../contract.yml", __dir__),
|
|
50
|
+
adapter: RubyReleaseAdapter.new # capable_pair? / capabilities / dll_install_name
|
|
51
|
+
)
|
|
52
|
+
```
|
|
53
|
+
|
|
54
|
+
CI then calls `bundle exec tebako-release upload` (publish legs) and
|
|
55
|
+
`bundle exec tebako-release sign` (sign legs). Sign-only consumers can skip
|
|
56
|
+
the adapter and set `TEBAKO_RELEASE_REPO` instead.
|
|
57
|
+
|
|
58
|
+
## force_rebuild, the release-object rule
|
|
59
|
+
|
|
60
|
+
Payload assets are byte-immutable per name — the uploader **never** deletes a
|
|
61
|
+
published payload asset to replace it (delete → re-upload of the same name is
|
|
62
|
+
the 422 wedge; tebako-runtime-ruby#189). A forced republication recreates the
|
|
63
|
+
**release object** once, coordinator-side, before any leg fans out
|
|
64
|
+
(`gh release delete <tag> --cleanup-tag false` … the first leg's
|
|
65
|
+
race-safe create re-makes it), turning every leg's publish into pure creates.
|
|
66
|
+
Operator-run re-uploads follow the same rule by hand.
|
data/exe/tebako-release
ADDED
|
@@ -0,0 +1,37 @@
|
|
|
1
|
+
#!/usr/bin/env ruby
|
|
2
|
+
# frozen_string_literal: true
|
|
3
|
+
|
|
4
|
+
# Copyright (c) 2026 [Ribose Inc](https://www.ribose.com).
|
|
5
|
+
# All rights reserved.
|
|
6
|
+
# This file is a part of tamatebako
|
|
7
|
+
|
|
8
|
+
# CI log truth: stdout to a pipe is block-buffered, and the runner stamps
|
|
9
|
+
# each line at FLUSH time — in the 2026-08-20 wedge incident's log, lines
|
|
10
|
+
# written minutes apart (sleeps included) appeared 2 ms apart. Flush every
|
|
11
|
+
# line so the log's timestamps are the writes' real times.
|
|
12
|
+
$stdout.sync = true
|
|
13
|
+
|
|
14
|
+
require "tebako_release"
|
|
15
|
+
|
|
16
|
+
command = ARGV.shift
|
|
17
|
+
|
|
18
|
+
# The consuming factory's adapter file declares TebakoRelease.configure(...)
|
|
19
|
+
# — repo, language, version grammar, and the policy callbacks. Sign-only
|
|
20
|
+
# invocations may run adapter-less on TEBAKO_RELEASE_REPO alone.
|
|
21
|
+
adapter = ENV.fetch("TEBAKO_RELEASE_ADAPTER", "scripts/release_adapter.rb")
|
|
22
|
+
require File.expand_path(adapter) if File.file?(adapter)
|
|
23
|
+
|
|
24
|
+
case command
|
|
25
|
+
when "upload"
|
|
26
|
+
TebakoRelease::Uploader.new.run
|
|
27
|
+
when "sign"
|
|
28
|
+
begin
|
|
29
|
+
TebakoRelease::Signer.new.sign_release
|
|
30
|
+
rescue TebakoRelease::Signer::SigningGateError, TebakoRelease::Error, KeyError => e
|
|
31
|
+
warn e.message
|
|
32
|
+
exit 1
|
|
33
|
+
end
|
|
34
|
+
else
|
|
35
|
+
warn "usage: tebako-release <upload|sign>"
|
|
36
|
+
exit 64
|
|
37
|
+
end
|
|
@@ -0,0 +1,59 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
# Copyright (c) 2026 [Ribose Inc](https://www.ribose.com).
|
|
4
|
+
# All rights reserved.
|
|
5
|
+
# This file is a part of tamatebako
|
|
6
|
+
|
|
7
|
+
module TebakoRelease
|
|
8
|
+
# The factory-policy surface — the one seam through which a consuming
|
|
9
|
+
# factory's own vocabulary reaches the release machinery. Factories
|
|
10
|
+
# subclass this (or pass any object responding to the same methods) in
|
|
11
|
+
# their adapter file; the defaults describe a runtime with no
|
|
12
|
+
# capability gates, no capabilities display metadata, no DLL facet,
|
|
13
|
+
# plain string version matrix rows, and a semver version grammar.
|
|
14
|
+
class Adapter
|
|
15
|
+
# (os id, arch id, runtime version) → false when the factory never
|
|
16
|
+
# builds that combination (the audit must never expect it). Default:
|
|
17
|
+
# every pair is capable.
|
|
18
|
+
def capable_pair?(_os, _arch, _version)
|
|
19
|
+
true
|
|
20
|
+
end
|
|
21
|
+
|
|
22
|
+
# The additive capabilities line of a manifest entry: display metadata
|
|
23
|
+
# owned by the factory that compiled the runtime — never a selector
|
|
24
|
+
# axis. Default: none.
|
|
25
|
+
def capabilities(version:, platform_id:)
|
|
26
|
+
_ = version
|
|
27
|
+
_ = platform_id
|
|
28
|
+
[]
|
|
29
|
+
end
|
|
30
|
+
|
|
31
|
+
# The PE name the store materializes next to a windows exe so its
|
|
32
|
+
# imports resolve (nil → the runtime ships no DLL facet).
|
|
33
|
+
def dll_install_name(_version, _host_id)
|
|
34
|
+
nil
|
|
35
|
+
end
|
|
36
|
+
|
|
37
|
+
# The prepare job's version matrix rows → version strings. Default:
|
|
38
|
+
# rows ARE the version strings; factories whose rows carry extra keys
|
|
39
|
+
# (a src_sha256 cache key) override.
|
|
40
|
+
def expected_versions(rows)
|
|
41
|
+
rows.map { |row| row.is_a?(Hash) ? row.fetch("version") : row }
|
|
42
|
+
end
|
|
43
|
+
|
|
44
|
+
# The version capture of the package-name grammar, as a regex SOURCE
|
|
45
|
+
# (the consuming factory's version-line model owns it).
|
|
46
|
+
def version_grammar_source
|
|
47
|
+
"\\d+\\.\\d+\\.\\d+"
|
|
48
|
+
end
|
|
49
|
+
|
|
50
|
+
# Spec 36's publish shape: when true, each leg publishes ONE bundle
|
|
51
|
+
# (<stem>.tar.gz — exe + env image + DLLs + in-bundle SHA256SUMS) plus
|
|
52
|
+
# its sidecar and shard, instead of the per-file asset enumeration.
|
|
53
|
+
# Default off: a factory opts in deliberately, with the bundle-era
|
|
54
|
+
# resolver shipped downstream (spec 36 §4's compat window).
|
|
55
|
+
def bundle_publish?
|
|
56
|
+
false
|
|
57
|
+
end
|
|
58
|
+
end
|
|
59
|
+
end
|
|
@@ -0,0 +1,89 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
# Copyright (c) 2026 [Ribose Inc](https://www.ribose.com).
|
|
4
|
+
# All rights reserved.
|
|
5
|
+
# This file is a part of tamatebako
|
|
6
|
+
|
|
7
|
+
require "digest"
|
|
8
|
+
require "rubygems/package"
|
|
9
|
+
require "zlib"
|
|
10
|
+
|
|
11
|
+
module TebakoRelease
|
|
12
|
+
# Spec 36 §2 — the deterministic tar.gz runtime bundle: ONE distribution
|
|
13
|
+
# artifact per (version × triplet) leg carrying the interpreter exe, the
|
|
14
|
+
# env image, and any windows support DLLs, closed by an in-bundle
|
|
15
|
+
# SHA256SUMS. The bundle is the publish unit on bundle-era lines: the
|
|
16
|
+
# per-file asset enumeration (exe + image + per-asset sidecars, each
|
|
17
|
+
# signed) costs ~10–14 release assets per leg; the bundle costs 3–5.
|
|
18
|
+
#
|
|
19
|
+
# Determinism is a publish-economy property, not a promise to consumers:
|
|
20
|
+
# identical inputs must yield identical bytes so a re-run's digest-match
|
|
21
|
+
# skip stays cheap (fixed member order, mtime=0 everywhere, no gzip
|
|
22
|
+
# original-name field).
|
|
23
|
+
class Bundler
|
|
24
|
+
BUNDLE_SUFFIX = ".tar.gz"
|
|
25
|
+
SUMS_NAME = "SHA256SUMS"
|
|
26
|
+
|
|
27
|
+
# Member modes as the store materializes them (spec 05 §3): the exe is
|
|
28
|
+
# 0755, the env image 0444, support DLLs plain read-only data.
|
|
29
|
+
EXE_MODE = 0o755
|
|
30
|
+
IMAGE_MODE = 0o444
|
|
31
|
+
DLL_MODE = 0o444
|
|
32
|
+
|
|
33
|
+
def self.bundle_name_for(stem)
|
|
34
|
+
"#{stem}#{BUNDLE_SUFFIX}"
|
|
35
|
+
end
|
|
36
|
+
|
|
37
|
+
# Build <dir>/<stem>.tar.gz from the leg's staged members.
|
|
38
|
+
# members: exe Pathname (required), image Pathname (required — a
|
|
39
|
+
# bundle without its env image is not a runtime), dlls (zero or
|
|
40
|
+
# more). Returns the bundle Pathname.
|
|
41
|
+
def build(dir, stem, exe:, image:, dlls: [])
|
|
42
|
+
members = [[exe, EXE_MODE], [image, IMAGE_MODE]] + dlls.sort_by { |d| d.basename.to_s }.map { |d| [d, DLL_MODE] }
|
|
43
|
+
members.map(&:first).each { |path| validate_member!(path) }
|
|
44
|
+
bundle = Pathname.new(dir).join(self.class.bundle_name_for(stem))
|
|
45
|
+
write_bundle(bundle, members, sums_content(members))
|
|
46
|
+
bundle
|
|
47
|
+
end
|
|
48
|
+
|
|
49
|
+
private
|
|
50
|
+
|
|
51
|
+
# SHA256SUMS, coreutils shape ("<sha> <file>\n" per member), in member
|
|
52
|
+
# order — the bundle's last member, pinning every other (spec 36 §2).
|
|
53
|
+
def sums_content(members)
|
|
54
|
+
lines = members.map { |path, _| "#{Digest::SHA256.file(path).hexdigest} #{path.basename}" }
|
|
55
|
+
"#{lines.join("\n")}\n"
|
|
56
|
+
end
|
|
57
|
+
|
|
58
|
+
# Deterministic bytes (spec 36 §2): fixed member order, mtime=0 in the
|
|
59
|
+
# gzip header and every tar header — identical inputs yield identical
|
|
60
|
+
# bytes, so a re-run's digest-match skip stays cheap.
|
|
61
|
+
def write_bundle(bundle, members, sums)
|
|
62
|
+
File.open(bundle, "wb") do |io|
|
|
63
|
+
gz = Zlib::GzipWriter.new(io)
|
|
64
|
+
gz.mtime = 0
|
|
65
|
+
Gem::Package::TarWriter.new(gz) do |tar|
|
|
66
|
+
members.each { |path, mode| add_member(tar, path.basename.to_s, mode, path) }
|
|
67
|
+
tar.add_file_simple(SUMS_NAME, 0o444, sums.bytesize) { |io_member| io_member.write(sums) }
|
|
68
|
+
end
|
|
69
|
+
gz.close
|
|
70
|
+
end
|
|
71
|
+
end
|
|
72
|
+
|
|
73
|
+
def add_member(tar, name, mode, path)
|
|
74
|
+
tar.add_file_simple(name, mode, path.size) do |io_member|
|
|
75
|
+
File.open(path, "rb") { |f| IO.copy_stream(f, io_member) }
|
|
76
|
+
end
|
|
77
|
+
end
|
|
78
|
+
|
|
79
|
+
# The §2 member grammar: a plain staged regular file — never a
|
|
80
|
+
# symlink, directory, or device (members are written under their bare
|
|
81
|
+
# basenames, so no path traversal is possible by construction; what
|
|
82
|
+
# remains to assert is the kind).
|
|
83
|
+
def validate_member!(path)
|
|
84
|
+
return if path.file? && !path.symlink?
|
|
85
|
+
|
|
86
|
+
raise Error, "bundle member #{path} is not a plain staged file (spec 36 §2's member grammar)"
|
|
87
|
+
end
|
|
88
|
+
end
|
|
89
|
+
end
|
|
@@ -0,0 +1,49 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
# Copyright (c) 2026 [Ribose Inc](https://www.ribose.com).
|
|
4
|
+
# All rights reserved.
|
|
5
|
+
# This file is a part of tamatebako
|
|
6
|
+
|
|
7
|
+
module TebakoRelease
|
|
8
|
+
# The consuming factory's identity: which repo's releases this run
|
|
9
|
+
# manages, the language whose version strings ride the package-name
|
|
10
|
+
# grammar, the release title prefix, the contract.yml path (the release
|
|
11
|
+
# pipeline's SSOT for the bootstrap<->runtime contract version), and the
|
|
12
|
+
# policy adapter. `repo` is the one value a sign-only consumer must
|
|
13
|
+
# declare; everything else has an upload-side default.
|
|
14
|
+
class Config
|
|
15
|
+
DEFAULT_TOOL_REPO = "tamatebako/tebako"
|
|
16
|
+
|
|
17
|
+
attr_reader :repo, :language, :title_prefix, :contract_yml, :adapter, :tool_repo
|
|
18
|
+
|
|
19
|
+
def initialize(repo:, language: nil, title_prefix: nil, contract_yml: "contract.yml", # rubocop:disable Metrics/ParameterLists
|
|
20
|
+
adapter: Adapter.new, tool_repo: DEFAULT_TOOL_REPO)
|
|
21
|
+
@repo = repo
|
|
22
|
+
@language = language
|
|
23
|
+
@title_prefix = title_prefix || "Tebako runtime packages"
|
|
24
|
+
@contract_yml = contract_yml
|
|
25
|
+
@adapter = adapter
|
|
26
|
+
@tool_repo = tool_repo
|
|
27
|
+
end
|
|
28
|
+
|
|
29
|
+
# The minimal env-only declaration: the sign path's one repo value.
|
|
30
|
+
def self.from_env(env = ENV)
|
|
31
|
+
new(repo: env.fetch("TEBAKO_RELEASE_REPO") do
|
|
32
|
+
raise Error, "TEBAKO_RELEASE_REPO is not set and no release adapter was configured — " \
|
|
33
|
+
"the release machinery never guesses which repo it publishes to"
|
|
34
|
+
end)
|
|
35
|
+
end
|
|
36
|
+
|
|
37
|
+
# The manifest entry's version key for this runtime's language
|
|
38
|
+
# (ruby_version / python_version / …).
|
|
39
|
+
def version_key
|
|
40
|
+
:"#{language}_version"
|
|
41
|
+
end
|
|
42
|
+
|
|
43
|
+
# The env var carrying this leg's expected version matrix
|
|
44
|
+
# (EXPECTED_RUBY_MATRIX / EXPECTED_PYTHON_MATRIX / …).
|
|
45
|
+
def version_matrix_env
|
|
46
|
+
"EXPECTED_#{language.upcase}_MATRIX"
|
|
47
|
+
end
|
|
48
|
+
end
|
|
49
|
+
end
|
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
# Copyright (c) 2026 [Ribose Inc](https://www.ribose.com).
|
|
4
|
+
# All rights reserved.
|
|
5
|
+
# This file is a part of tamatebako
|
|
6
|
+
|
|
7
|
+
module TebakoRelease
|
|
8
|
+
# Named error for every release-machinery failure (spec 00: named errors,
|
|
9
|
+
# never silent fallbacks).
|
|
10
|
+
class Error < StandardError; end
|
|
11
|
+
end
|
|
@@ -0,0 +1,76 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
# Copyright (c) 2026 [Ribose Inc](https://www.ribose.com).
|
|
4
|
+
# All rights reserved.
|
|
5
|
+
# This file is a part of tamatebako
|
|
6
|
+
|
|
7
|
+
require "rbconfig"
|
|
8
|
+
|
|
9
|
+
module TebakoRelease
|
|
10
|
+
# The release-side platform vocabulary: (os id, arch id) ↔ the release
|
|
11
|
+
# platform id used in runtime package names. Owned by tpkg::Platform
|
|
12
|
+
# (tamatebako/tebako, docs/spec/03 §3); NOT derivable by formula
|
|
13
|
+
# ("windows-ucrt64" carries no arch segment). windows/arm64 follows the
|
|
14
|
+
# product's RESERVED release-asset name ("windows-ucrt-arm64" — the
|
|
15
|
+
# aarch64-windows-ucrt triplet, which tpkg parses but rejects in payload
|
|
16
|
+
# manifests until the platform ships). This is the release tooling's
|
|
17
|
+
# mirror of that table; drift fails loudly in the factories' CI parity
|
|
18
|
+
# checks.
|
|
19
|
+
class Platform
|
|
20
|
+
HOST_IDS = {
|
|
21
|
+
%w[windows x86_64] => "windows-ucrt64",
|
|
22
|
+
%w[windows arm64] => "windows-ucrt-arm64",
|
|
23
|
+
%w[macos arm64] => "macos-arm64",
|
|
24
|
+
%w[macos x86_64] => "macos-x86_64",
|
|
25
|
+
%w[linux-gnu x86_64] => "linux-gnu-x86_64",
|
|
26
|
+
%w[linux-gnu arm64] => "linux-gnu-arm64",
|
|
27
|
+
%w[linux-musl x86_64] => "linux-musl-x86_64",
|
|
28
|
+
%w[linux-musl arm64] => "linux-musl-arm64"
|
|
29
|
+
}.freeze
|
|
30
|
+
|
|
31
|
+
# The lookup for callers with no detected host (the release pipeline's
|
|
32
|
+
# expected-asset model); the instance path shares the named failure.
|
|
33
|
+
def self.host_id_for(os_id, arch_id)
|
|
34
|
+
HOST_IDS.fetch([os_id, arch_id]) { raise Error, "no release platform id for #{os_id}/#{arch_id}" }
|
|
35
|
+
end
|
|
36
|
+
|
|
37
|
+
def initialize(ostype = RUBY_PLATFORM, arch = RbConfig::CONFIG["host_cpu"])
|
|
38
|
+
@ostype = ostype
|
|
39
|
+
@arch = arch
|
|
40
|
+
end
|
|
41
|
+
|
|
42
|
+
attr_reader :ostype
|
|
43
|
+
|
|
44
|
+
# Platform id as used by runtime package names (e.g. "macos-arm64",
|
|
45
|
+
# "windows-ucrt64").
|
|
46
|
+
def host_id
|
|
47
|
+
self.class.host_id_for(host_os_id, host_arch_id)
|
|
48
|
+
end
|
|
49
|
+
|
|
50
|
+
def exe_suffix
|
|
51
|
+
@ostype =~ /msys|mingw|cygwin/ ? ".exe" : ""
|
|
52
|
+
end
|
|
53
|
+
|
|
54
|
+
private
|
|
55
|
+
|
|
56
|
+
def host_os_id
|
|
57
|
+
case @ostype
|
|
58
|
+
when /msys|mingw|cygwin/ then "windows"
|
|
59
|
+
when /darwin/ then "macos"
|
|
60
|
+
when /linux-musl/ then "linux-musl"
|
|
61
|
+
when /linux/ then "linux-gnu"
|
|
62
|
+
else
|
|
63
|
+
raise Error, "no release os id for #{@ostype}"
|
|
64
|
+
end
|
|
65
|
+
end
|
|
66
|
+
|
|
67
|
+
def host_arch_id
|
|
68
|
+
case @arch
|
|
69
|
+
when /^(x86_64|amd64|x64)$/ then "x86_64"
|
|
70
|
+
when /^(aarch64|arm64)$/ then "arm64"
|
|
71
|
+
else
|
|
72
|
+
raise Error, "no release arch id for #{@arch}"
|
|
73
|
+
end
|
|
74
|
+
end
|
|
75
|
+
end
|
|
76
|
+
end
|