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 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
@@ -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
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: []