buildonce 0.1.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/README.md +18 -0
- data/lib/buildonce.rb +119 -0
- data/lib/once/native.rb +71 -0
- data/prebuilds/darwin-arm64/libonce.dylib +0 -0
- metadata +57 -0
checksums.yaml
ADDED
|
@@ -0,0 +1,7 @@
|
|
|
1
|
+
---
|
|
2
|
+
SHA256:
|
|
3
|
+
metadata.gz: 10b4f7f6a4fad6b16798b07d81b82d29734ed7815a9404d15296098b8aa00500
|
|
4
|
+
data.tar.gz: a68fb31adae628d07f8032dd04f2f29aa2bbcabdd4e20edd5fb819936540b2b7
|
|
5
|
+
SHA512:
|
|
6
|
+
metadata.gz: 2a88cbca813751e8b465ab009d5467a9f3175e8216323a45cacdd643e578a6a57d6b38a2bd8f77bd24211c48522881fc0ebbb879fc3076588c46d37dfe98f3f9
|
|
7
|
+
data.tar.gz: 3119508b9426c066cf5e109433e4e79fcd9e40bb9ae20e1255f2eed83913266c89aa9899c5f5640b673aedf10952083d477949c4872ada851bb1c64790c567f5
|
data/README.md
ADDED
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
# Once Ruby SDK
|
|
2
|
+
|
|
3
|
+
`buildonce` exposes Once primitives to Ruby. It loads the same
|
|
4
|
+
native Once library used by the other SDKs and does not expose script
|
|
5
|
+
execution.
|
|
6
|
+
|
|
7
|
+
```ruby
|
|
8
|
+
require "buildonce"
|
|
9
|
+
|
|
10
|
+
cache = Once::Cache.new
|
|
11
|
+
digest = cache.put_blob("hello")
|
|
12
|
+
bytes = cache.get_blob(digest)
|
|
13
|
+
|
|
14
|
+
raise unless bytes == "hello"
|
|
15
|
+
```
|
|
16
|
+
|
|
17
|
+
The gem looks for a bundled native library under `prebuilds/`. Set
|
|
18
|
+
`ONCE_LIBRARY_PATH` to load a custom `libonce` build.
|
data/lib/buildonce.rb
ADDED
|
@@ -0,0 +1,119 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
require "json"
|
|
4
|
+
require "once/native"
|
|
5
|
+
|
|
6
|
+
module Once
|
|
7
|
+
class Error < StandardError; end
|
|
8
|
+
|
|
9
|
+
ActionResult = Struct.new(:exit_code, :stdout, :stderr, :outputs, keyword_init: true) do
|
|
10
|
+
def to_h
|
|
11
|
+
{
|
|
12
|
+
exit_code: exit_code,
|
|
13
|
+
stdout: stdout,
|
|
14
|
+
stderr: stderr,
|
|
15
|
+
outputs: outputs || {},
|
|
16
|
+
}
|
|
17
|
+
end
|
|
18
|
+
end
|
|
19
|
+
|
|
20
|
+
CacheStats = Struct.new(:blob_count, :blob_bytes, :action_count, :action_bytes, keyword_init: true)
|
|
21
|
+
|
|
22
|
+
class Cache
|
|
23
|
+
def version
|
|
24
|
+
pointer = Native.once_version
|
|
25
|
+
return "" if pointer.null?
|
|
26
|
+
|
|
27
|
+
pointer.read_string
|
|
28
|
+
ensure
|
|
29
|
+
Native.once_string_free(pointer) if pointer && !pointer.null?
|
|
30
|
+
end
|
|
31
|
+
|
|
32
|
+
def digest(bytes)
|
|
33
|
+
buffer = bytes.to_s.b
|
|
34
|
+
pointer = buffer.empty? ? FFI::Pointer::NULL : FFI::MemoryPointer.from_string(buffer)
|
|
35
|
+
decode_response(Native.once_digest_bytes(pointer, buffer.bytesize))
|
|
36
|
+
end
|
|
37
|
+
|
|
38
|
+
def put_blob(bytes)
|
|
39
|
+
buffer = bytes.to_s.b
|
|
40
|
+
decode_request(:once_cache_put_blob_json, bytes: buffer.bytes)
|
|
41
|
+
end
|
|
42
|
+
|
|
43
|
+
def get_blob(digest)
|
|
44
|
+
response = decode_request(:once_cache_get_blob_json, digest: digest)
|
|
45
|
+
response.fetch("bytes").pack("C*")
|
|
46
|
+
end
|
|
47
|
+
|
|
48
|
+
def has_blob?(digest)
|
|
49
|
+
decode_request(:once_cache_has_blob_json, digest: digest)
|
|
50
|
+
end
|
|
51
|
+
|
|
52
|
+
def put_action_result(result, action_digest:)
|
|
53
|
+
decode_request(
|
|
54
|
+
:once_cache_put_action_result_json,
|
|
55
|
+
action_digest: action_digest,
|
|
56
|
+
result: normalize_action_result(result),
|
|
57
|
+
)
|
|
58
|
+
end
|
|
59
|
+
|
|
60
|
+
def get_action_result(action_digest)
|
|
61
|
+
response = decode_request(:once_cache_get_action_result_json, action_digest: action_digest)
|
|
62
|
+
response && action_result_from_native(response)
|
|
63
|
+
end
|
|
64
|
+
|
|
65
|
+
def forget_action(action_digest)
|
|
66
|
+
decode_request(:once_cache_forget_action_json, action_digest: action_digest)
|
|
67
|
+
end
|
|
68
|
+
|
|
69
|
+
def stats
|
|
70
|
+
response = decode_request(:once_cache_stats_json, {})
|
|
71
|
+
CacheStats.new(
|
|
72
|
+
blob_count: response.fetch("blob_count"),
|
|
73
|
+
blob_bytes: response.fetch("blob_bytes"),
|
|
74
|
+
action_count: response.fetch("action_count"),
|
|
75
|
+
action_bytes: response.fetch("action_bytes"),
|
|
76
|
+
)
|
|
77
|
+
end
|
|
78
|
+
|
|
79
|
+
private
|
|
80
|
+
|
|
81
|
+
def decode_request(function, request)
|
|
82
|
+
decode_response(Native.public_send(function, JSON.generate(request)))
|
|
83
|
+
end
|
|
84
|
+
|
|
85
|
+
def decode_response(pointer)
|
|
86
|
+
raise Error, "native Once function returned null" if pointer.null?
|
|
87
|
+
|
|
88
|
+
response = JSON.parse(pointer.read_string)
|
|
89
|
+
return response.fetch("value") if response.fetch("status") == "ok"
|
|
90
|
+
|
|
91
|
+
raise Error, response.fetch("message")
|
|
92
|
+
ensure
|
|
93
|
+
Native.once_string_free(pointer) if pointer && !pointer.null?
|
|
94
|
+
end
|
|
95
|
+
|
|
96
|
+
def normalize_action_result(result)
|
|
97
|
+
result = result.to_h if result.respond_to?(:to_h)
|
|
98
|
+
{
|
|
99
|
+
exit_code: result.fetch(:exit_code) { result.fetch("exit_code") },
|
|
100
|
+
stdout: result[:stdout] || result["stdout"],
|
|
101
|
+
stderr: result[:stderr] || result["stderr"],
|
|
102
|
+
outputs: result[:outputs] || result["outputs"] || {},
|
|
103
|
+
}
|
|
104
|
+
end
|
|
105
|
+
|
|
106
|
+
def action_result_from_native(result)
|
|
107
|
+
ActionResult.new(
|
|
108
|
+
exit_code: result.fetch("exit_code"),
|
|
109
|
+
stdout: result["stdout"],
|
|
110
|
+
stderr: result["stderr"],
|
|
111
|
+
outputs: result.fetch("outputs", {}),
|
|
112
|
+
)
|
|
113
|
+
end
|
|
114
|
+
end
|
|
115
|
+
|
|
116
|
+
def self.digest(bytes)
|
|
117
|
+
Cache.new.digest(bytes)
|
|
118
|
+
end
|
|
119
|
+
end
|
data/lib/once/native.rb
ADDED
|
@@ -0,0 +1,71 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
require "ffi"
|
|
4
|
+
require "rbconfig"
|
|
5
|
+
|
|
6
|
+
module Once
|
|
7
|
+
module Native
|
|
8
|
+
extend FFI::Library
|
|
9
|
+
|
|
10
|
+
def self.library_path
|
|
11
|
+
return ENV.fetch("ONCE_LIBRARY_PATH") if ENV["ONCE_LIBRARY_PATH"]
|
|
12
|
+
|
|
13
|
+
candidate = File.expand_path(
|
|
14
|
+
File.join("..", "..", "prebuilds", platform_key, library_name),
|
|
15
|
+
__dir__,
|
|
16
|
+
)
|
|
17
|
+
return candidate if File.file?(candidate)
|
|
18
|
+
|
|
19
|
+
raise LoadError,
|
|
20
|
+
"missing native Once library for #{platform_key}; set ONCE_LIBRARY_PATH or install a gem that includes this platform"
|
|
21
|
+
end
|
|
22
|
+
|
|
23
|
+
def self.platform_key
|
|
24
|
+
host = RbConfig::CONFIG.fetch("host_os")
|
|
25
|
+
arch = RbConfig::CONFIG.fetch("host_cpu")
|
|
26
|
+
os = case host
|
|
27
|
+
when /darwin/
|
|
28
|
+
"darwin"
|
|
29
|
+
when /mswin|mingw|cygwin/
|
|
30
|
+
"win32"
|
|
31
|
+
when /linux/
|
|
32
|
+
"linux"
|
|
33
|
+
else
|
|
34
|
+
host
|
|
35
|
+
end
|
|
36
|
+
cpu = case arch
|
|
37
|
+
when /arm64|aarch64/
|
|
38
|
+
"arm64"
|
|
39
|
+
when /x86_64|amd64/
|
|
40
|
+
"x64"
|
|
41
|
+
else
|
|
42
|
+
arch
|
|
43
|
+
end
|
|
44
|
+
"#{os}-#{cpu}"
|
|
45
|
+
end
|
|
46
|
+
|
|
47
|
+
def self.library_name
|
|
48
|
+
case platform_key
|
|
49
|
+
when /^darwin-/
|
|
50
|
+
"libonce.dylib"
|
|
51
|
+
when /^win32-/
|
|
52
|
+
"once.dll"
|
|
53
|
+
else
|
|
54
|
+
"libonce.so"
|
|
55
|
+
end
|
|
56
|
+
end
|
|
57
|
+
|
|
58
|
+
ffi_lib library_path
|
|
59
|
+
|
|
60
|
+
attach_function :once_version, [], :pointer
|
|
61
|
+
attach_function :once_string_free, [:pointer], :void
|
|
62
|
+
attach_function :once_digest_bytes, %i[pointer size_t], :pointer
|
|
63
|
+
attach_function :once_cache_put_blob_json, [:string], :pointer
|
|
64
|
+
attach_function :once_cache_get_blob_json, [:string], :pointer
|
|
65
|
+
attach_function :once_cache_has_blob_json, [:string], :pointer
|
|
66
|
+
attach_function :once_cache_put_action_result_json, [:string], :pointer
|
|
67
|
+
attach_function :once_cache_get_action_result_json, [:string], :pointer
|
|
68
|
+
attach_function :once_cache_forget_action_json, [:string], :pointer
|
|
69
|
+
attach_function :once_cache_stats_json, [:string], :pointer
|
|
70
|
+
end
|
|
71
|
+
end
|
|
Binary file
|
metadata
ADDED
|
@@ -0,0 +1,57 @@
|
|
|
1
|
+
--- !ruby/object:Gem::Specification
|
|
2
|
+
name: buildonce
|
|
3
|
+
version: !ruby/object:Gem::Version
|
|
4
|
+
version: 0.1.0
|
|
5
|
+
platform: ruby
|
|
6
|
+
authors:
|
|
7
|
+
- Tuist GmbH
|
|
8
|
+
bindir: bin
|
|
9
|
+
cert_chain: []
|
|
10
|
+
date: 1980-01-02 00:00:00.000000000 Z
|
|
11
|
+
dependencies:
|
|
12
|
+
- !ruby/object:Gem::Dependency
|
|
13
|
+
name: ffi
|
|
14
|
+
requirement: !ruby/object:Gem::Requirement
|
|
15
|
+
requirements:
|
|
16
|
+
- - "~>"
|
|
17
|
+
- !ruby/object:Gem::Version
|
|
18
|
+
version: '1.16'
|
|
19
|
+
type: :runtime
|
|
20
|
+
prerelease: false
|
|
21
|
+
version_requirements: !ruby/object:Gem::Requirement
|
|
22
|
+
requirements:
|
|
23
|
+
- - "~>"
|
|
24
|
+
- !ruby/object:Gem::Version
|
|
25
|
+
version: '1.16'
|
|
26
|
+
description: Embeds Once primitives in Ruby through the native Once library.
|
|
27
|
+
executables: []
|
|
28
|
+
extensions: []
|
|
29
|
+
extra_rdoc_files: []
|
|
30
|
+
files:
|
|
31
|
+
- README.md
|
|
32
|
+
- lib/buildonce.rb
|
|
33
|
+
- lib/once/native.rb
|
|
34
|
+
- prebuilds/darwin-arm64/libonce.dylib
|
|
35
|
+
homepage: https://github.com/tuist/once
|
|
36
|
+
licenses:
|
|
37
|
+
- MIT
|
|
38
|
+
metadata:
|
|
39
|
+
source_code_uri: https://github.com/tuist/once
|
|
40
|
+
rdoc_options: []
|
|
41
|
+
require_paths:
|
|
42
|
+
- lib
|
|
43
|
+
required_ruby_version: !ruby/object:Gem::Requirement
|
|
44
|
+
requirements:
|
|
45
|
+
- - ">="
|
|
46
|
+
- !ruby/object:Gem::Version
|
|
47
|
+
version: '3.1'
|
|
48
|
+
required_rubygems_version: !ruby/object:Gem::Requirement
|
|
49
|
+
requirements:
|
|
50
|
+
- - ">="
|
|
51
|
+
- !ruby/object:Gem::Version
|
|
52
|
+
version: '0'
|
|
53
|
+
requirements: []
|
|
54
|
+
rubygems_version: 4.0.10
|
|
55
|
+
specification_version: 4
|
|
56
|
+
summary: Ruby SDK for Once
|
|
57
|
+
test_files: []
|