ruar 0.0.2

Sign up to get free protection for your applications and to get access to all the features.
checksums.yaml ADDED
@@ -0,0 +1,7 @@
1
+ ---
2
+ SHA256:
3
+ metadata.gz: 2ad6f68a61d0accd3eb5e970934fcbbf30e299c3caafb1ec69ebfc9f9a3b76bf
4
+ data.tar.gz: 9a9f620ce167c3c5b0f1ab163b0d40f4261652005b83f8f2757098b600ee5b6a
5
+ SHA512:
6
+ metadata.gz: d5508e42916f61c9aeb2c47d90a956401139baac154d7a6776b600434da114aecdf156b860621c4117755a8dbf1f6ad45ee2cff5a601254b278b7d9804fe0065
7
+ data.tar.gz: 790039c7c05c5da8c09a22bc349926c3c10476e7b37090ac2e2c213cd91bbd512aae7c596900ab89e1afcfad98d06cfe89671d0ebf39fe534d9444221f6f9cd0
data/LICENSE ADDED
@@ -0,0 +1,201 @@
1
+ Apache License
2
+ Version 2.0, January 2004
3
+ http://www.apache.org/licenses/
4
+
5
+ TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION
6
+
7
+ 1. Definitions.
8
+
9
+ "License" shall mean the terms and conditions for use, reproduction,
10
+ and distribution as defined by Sections 1 through 9 of this document.
11
+
12
+ "Licensor" shall mean the copyright owner or entity authorized by
13
+ the copyright owner that is granting the License.
14
+
15
+ "Legal Entity" shall mean the union of the acting entity and all
16
+ other entities that control, are controlled by, or are under common
17
+ control with that entity. For the purposes of this definition,
18
+ "control" means (i) the power, direct or indirect, to cause the
19
+ direction or management of such entity, whether by contract or
20
+ otherwise, or (ii) ownership of fifty percent (50%) or more of the
21
+ outstanding shares, or (iii) beneficial ownership of such entity.
22
+
23
+ "You" (or "Your") shall mean an individual or Legal Entity
24
+ exercising permissions granted by this License.
25
+
26
+ "Source" form shall mean the preferred form for making modifications,
27
+ including but not limited to software source code, documentation
28
+ source, and configuration files.
29
+
30
+ "Object" form shall mean any form resulting from mechanical
31
+ transformation or translation of a Source form, including but
32
+ not limited to compiled object code, generated documentation,
33
+ and conversions to other media types.
34
+
35
+ "Work" shall mean the work of authorship, whether in Source or
36
+ Object form, made available under the License, as indicated by a
37
+ copyright notice that is included in or attached to the work
38
+ (an example is provided in the Appendix below).
39
+
40
+ "Derivative Works" shall mean any work, whether in Source or Object
41
+ form, that is based on (or derived from) the Work and for which the
42
+ editorial revisions, annotations, elaborations, or other modifications
43
+ represent, as a whole, an original work of authorship. For the purposes
44
+ of this License, Derivative Works shall not include works that remain
45
+ separable from, or merely link (or bind by name) to the interfaces of,
46
+ the Work and Derivative Works thereof.
47
+
48
+ "Contribution" shall mean any work of authorship, including
49
+ the original version of the Work and any modifications or additions
50
+ to that Work or Derivative Works thereof, that is intentionally
51
+ submitted to Licensor for inclusion in the Work by the copyright owner
52
+ or by an individual or Legal Entity authorized to submit on behalf of
53
+ the copyright owner. For the purposes of this definition, "submitted"
54
+ means any form of electronic, verbal, or written communication sent
55
+ to the Licensor or its representatives, including but not limited to
56
+ communication on electronic mailing lists, source code control systems,
57
+ and issue tracking systems that are managed by, or on behalf of, the
58
+ Licensor for the purpose of discussing and improving the Work, but
59
+ excluding communication that is conspicuously marked or otherwise
60
+ designated in writing by the copyright owner as "Not a Contribution."
61
+
62
+ "Contributor" shall mean Licensor and any individual or Legal Entity
63
+ on behalf of whom a Contribution has been received by Licensor and
64
+ subsequently incorporated within the Work.
65
+
66
+ 2. Grant of Copyright License. Subject to the terms and conditions of
67
+ this License, each Contributor hereby grants to You a perpetual,
68
+ worldwide, non-exclusive, no-charge, royalty-free, irrevocable
69
+ copyright license to reproduce, prepare Derivative Works of,
70
+ publicly display, publicly perform, sublicense, and distribute the
71
+ Work and such Derivative Works in Source or Object form.
72
+
73
+ 3. Grant of Patent License. Subject to the terms and conditions of
74
+ this License, each Contributor hereby grants to You a perpetual,
75
+ worldwide, non-exclusive, no-charge, royalty-free, irrevocable
76
+ (except as stated in this section) patent license to make, have made,
77
+ use, offer to sell, sell, import, and otherwise transfer the Work,
78
+ where such license applies only to those patent claims licensable
79
+ by such Contributor that are necessarily infringed by their
80
+ Contribution(s) alone or by combination of their Contribution(s)
81
+ with the Work to which such Contribution(s) was submitted. If You
82
+ institute patent litigation against any entity (including a
83
+ cross-claim or counterclaim in a lawsuit) alleging that the Work
84
+ or a Contribution incorporated within the Work constitutes direct
85
+ or contributory patent infringement, then any patent licenses
86
+ granted to You under this License for that Work shall terminate
87
+ as of the date such litigation is filed.
88
+
89
+ 4. Redistribution. You may reproduce and distribute copies of the
90
+ Work or Derivative Works thereof in any medium, with or without
91
+ modifications, and in Source or Object form, provided that You
92
+ meet the following conditions:
93
+
94
+ (a) You must give any other recipients of the Work or
95
+ Derivative Works a copy of this License; and
96
+
97
+ (b) You must cause any modified files to carry prominent notices
98
+ stating that You changed the files; and
99
+
100
+ (c) You must retain, in the Source form of any Derivative Works
101
+ that You distribute, all copyright, patent, trademark, and
102
+ attribution notices from the Source form of the Work,
103
+ excluding those notices that do not pertain to any part of
104
+ the Derivative Works; and
105
+
106
+ (d) If the Work includes a "NOTICE" text file as part of its
107
+ distribution, then any Derivative Works that You distribute must
108
+ include a readable copy of the attribution notices contained
109
+ within such NOTICE file, excluding those notices that do not
110
+ pertain to any part of the Derivative Works, in at least one
111
+ of the following places: within a NOTICE text file distributed
112
+ as part of the Derivative Works; within the Source form or
113
+ documentation, if provided along with the Derivative Works; or,
114
+ within a display generated by the Derivative Works, if and
115
+ wherever such third-party notices normally appear. The contents
116
+ of the NOTICE file are for informational purposes only and
117
+ do not modify the License. You may add Your own attribution
118
+ notices within Derivative Works that You distribute, alongside
119
+ or as an addendum to the NOTICE text from the Work, provided
120
+ that such additional attribution notices cannot be construed
121
+ as modifying the License.
122
+
123
+ You may add Your own copyright statement to Your modifications and
124
+ may provide additional or different license terms and conditions
125
+ for use, reproduction, or distribution of Your modifications, or
126
+ for any such Derivative Works as a whole, provided Your use,
127
+ reproduction, and distribution of the Work otherwise complies with
128
+ the conditions stated in this License.
129
+
130
+ 5. Submission of Contributions. Unless You explicitly state otherwise,
131
+ any Contribution intentionally submitted for inclusion in the Work
132
+ by You to the Licensor shall be under the terms and conditions of
133
+ this License, without any additional terms or conditions.
134
+ Notwithstanding the above, nothing herein shall supersede or modify
135
+ the terms of any separate license agreement you may have executed
136
+ with Licensor regarding such Contributions.
137
+
138
+ 6. Trademarks. This License does not grant permission to use the trade
139
+ names, trademarks, service marks, or product names of the Licensor,
140
+ except as required for reasonable and customary use in describing the
141
+ origin of the Work and reproducing the content of the NOTICE file.
142
+
143
+ 7. Disclaimer of Warranty. Unless required by applicable law or
144
+ agreed to in writing, Licensor provides the Work (and each
145
+ Contributor provides its Contributions) on an "AS IS" BASIS,
146
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
147
+ implied, including, without limitation, any warranties or conditions
148
+ of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A
149
+ PARTICULAR PURPOSE. You are solely responsible for determining the
150
+ appropriateness of using or redistributing the Work and assume any
151
+ risks associated with Your exercise of permissions under this License.
152
+
153
+ 8. Limitation of Liability. In no event and under no legal theory,
154
+ whether in tort (including negligence), contract, or otherwise,
155
+ unless required by applicable law (such as deliberate and grossly
156
+ negligent acts) or agreed to in writing, shall any Contributor be
157
+ liable to You for damages, including any direct, indirect, special,
158
+ incidental, or consequential damages of any character arising as a
159
+ result of this License or out of the use or inability to use the
160
+ Work (including but not limited to damages for loss of goodwill,
161
+ work stoppage, computer failure or malfunction, or any and all
162
+ other commercial damages or losses), even if such Contributor
163
+ has been advised of the possibility of such damages.
164
+
165
+ 9. Accepting Warranty or Additional Liability. While redistributing
166
+ the Work or Derivative Works thereof, You may choose to offer,
167
+ and charge a fee for, acceptance of support, warranty, indemnity,
168
+ or other liability obligations and/or rights consistent with this
169
+ License. However, in accepting such obligations, You may act only
170
+ on Your own behalf and on Your sole responsibility, not on behalf
171
+ of any other Contributor, and only if You agree to indemnify,
172
+ defend, and hold each Contributor harmless for any liability
173
+ incurred by, or claims asserted against, such Contributor by reason
174
+ of your accepting any such warranty or additional liability.
175
+
176
+ END OF TERMS AND CONDITIONS
177
+
178
+ APPENDIX: How to apply the Apache License to your work.
179
+
180
+ To apply the Apache License to your work, attach the following
181
+ boilerplate notice, with the fields enclosed by brackets "[]"
182
+ replaced with your own identifying information. (Don't include
183
+ the brackets!) The text should be enclosed in the appropriate
184
+ comment syntax for the file format. We also recommend that a
185
+ file or class name and description of purpose be included on the
186
+ same "printed page" as the copyright notice for easier
187
+ identification within third-party archives.
188
+
189
+ Copyright [yyyy] [name of copyright owner]
190
+
191
+ Licensed under the Apache License, Version 2.0 (the "License");
192
+ you may not use this file except in compliance with the License.
193
+ You may obtain a copy of the License at
194
+
195
+ http://www.apache.org/licenses/LICENSE-2.0
196
+
197
+ Unless required by applicable law or agreed to in writing, software
198
+ distributed under the License is distributed on an "AS IS" BASIS,
199
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
200
+ See the License for the specific language governing permissions and
201
+ limitations under the License.
data/README.md ADDED
@@ -0,0 +1,101 @@
1
+ # ruar
2
+
3
+ Tar-like Archive for RIEN
4
+
5
+ [![CI Tests](https://github.com/DarkKowalski/ruar/workflows/CI%20Tests/badge.svg)](https://github.com/DarkKowalski/ruar/actions?query=workflow%3A%22CI+Tests%22)
6
+ [![Build](https://github.com/DarkKowalski/ruar/workflows/Build/badge.svg)](https://github.com/DarkKowalski/ruar/actions?query=workflow%3ABuild)
7
+
8
+ ## Usage
9
+
10
+ ```ruby
11
+ require 'ruar'
12
+ require 'tmpdir'
13
+
14
+ # Serialize it
15
+ # file /tmp/plain.ruar => data
16
+ archive = File.join(Dir.tmpdir, 'plain.ruar')
17
+ Ruar::Serialize.plain('./test/sample', archive)
18
+
19
+ # Setup
20
+ Ruar.setup(
21
+ archive: archive
22
+ ).activate
23
+
24
+ # Require from /tmp/plain.ruar
25
+ require 'dir/file'
26
+
27
+ # require 'your_file', from: [:both, :ruar, :local]
28
+ # require_relative 'your_file', from: [:both, :ruar, :local]
29
+ # load 'your_file', from: [:both, :ruar, :local]
30
+ #
31
+ # Notice: Currently we don't support autoload from ruar
32
+
33
+ # Here you go
34
+ ```
35
+
36
+ ## Format
37
+
38
+ ```
39
+ +--------+-------+--------+-----+--------+
40
+ | Header | Index | File 0 | ... | File x |
41
+ +--------+-------+--------+-----+--------+
42
+ ```
43
+
44
+ ### Header
45
+
46
+ ```
47
+ +-------------------------------------------------------------+
48
+ | Header |
49
+ +-------------------------------+-----------------------------+
50
+ | major_version: uint32_t | minor_version: uint32_t |
51
+ +-------------------------------+-----------------------------+
52
+ | patch_version: uint32_t | platform: uint32_t |
53
+ +-------------------------------+-----------------------------+
54
+ | encryption_flags: uint32_t | compression_flags: uint32_t |
55
+ +-------------------------------+-----------------------------+
56
+ | index_start(octet): uint32_t | index_size(octet): unit32_t |
57
+ +-------------------------------+-----------------------------+
58
+ | index_checksum: uint32_t | header_checksum: uint32_t |
59
+ +-------------------------------+-----------------------------+
60
+ | padding: |
61
+ | 24 octets |
62
+ +-------------------------------+-----------------------------+
63
+ ```
64
+
65
+ ### Index
66
+
67
+ ```json
68
+ {
69
+ "files": {
70
+ "tmp": {
71
+ "files": {}
72
+ },
73
+ "usr" : {
74
+ "files": {
75
+ "bin": {
76
+ "files": {
77
+ "ls": {
78
+ "offset": "0",
79
+ "size": 100,
80
+ "executable": true
81
+ },
82
+ "cd": {
83
+ "offset": "100",
84
+ "size": 100,
85
+ "executable": true
86
+ }
87
+ }
88
+ }
89
+ }
90
+ },
91
+ "etc": {
92
+ "files": {
93
+ "hosts": {
94
+ "offset": "200",
95
+ "size": 32
96
+ }
97
+ }
98
+ }
99
+ }
100
+ }
101
+ ```
@@ -0,0 +1,9 @@
1
+ # frozen_string_literal: true
2
+
3
+ require 'mkmf'
4
+ $CFLAGS << ' -O3 '
5
+ $CFLAGS << ' -std=c99'
6
+
7
+ return unless have_library('z') && have_header('zlib.h') && have_func('crc32', 'zlib.h')
8
+
9
+ create_makefile('ruar/ruar')
data/ext/ruar/ruar.c ADDED
@@ -0,0 +1,337 @@
1
+ #include "ruar.h"
2
+
3
+ #include <ctype.h>
4
+ #include <ruby.h>
5
+ #include <stdint.h>
6
+ #include <stdio.h>
7
+ #include <stdlib.h>
8
+ #include <string.h>
9
+ #include <zlib.h>
10
+
11
+ #define HEADER_SIZE 64 /* Bytes */
12
+
13
+ /* Notice: O(n) */
14
+ #define INDEX_SIZE(i) ((uint32_t)(strlen((i)) + 1)) /* Bytes */
15
+
16
+ #define READ_SRC_BUFFER_SIZE 0x8000 /* Bytes */
17
+
18
+ struct ruar_header
19
+ {
20
+ uint32_t major_version;
21
+ uint32_t minor_version;
22
+ uint32_t patch_version;
23
+ uint32_t platform;
24
+ uint32_t encryption_flags;
25
+ uint32_t compression_flags;
26
+ uint32_t index_start;
27
+ uint32_t index_size;
28
+ uint32_t index_checksum;
29
+ uint32_t header_checksum;
30
+ uint8_t pad[24];
31
+ } __attribute__((packed));
32
+
33
+ /*
34
+ * If the struct padding isn't correct to pad the key to 64 bytes,
35
+ * refuse to compile.
36
+ */
37
+ #define STATIC_ASSERT(X) STATIC_ASSERT2(X, __LINE__)
38
+ #define STATIC_ASSERT2(X, L) STATIC_ASSERT3(X, L)
39
+ #define STATIC_ASSERT3(X, L) STATIC_ASSERT_MSG(X, at_line_##L)
40
+ #define STATIC_ASSERT_MSG(COND, MSG) typedef char static_assertion_##MSG[(!!(COND)) * 2 - 1]
41
+ STATIC_ASSERT(sizeof(struct ruar_header) == HEADER_SIZE);
42
+
43
+ /* Constants */
44
+ static const uint32_t current_major_version = 0;
45
+ static const uint32_t current_minor_version = 0;
46
+ static const uint32_t current_patch_version = 1;
47
+
48
+ /* System info */
49
+ #ifdef __linux__
50
+ static uint32_t current_platform = 1;
51
+ #elif __APPLE__
52
+ static uint32_t current_platform = 2;
53
+ #elif BSD
54
+ static uint32_t current_platform = 3;
55
+ #elif __CYGWIN__
56
+ static uint32_t current_platform = 4;
57
+ #elif __WIN32
58
+ static uint32_t current_platform = 5;
59
+ #else
60
+ static uint32_t current_platform = 0;
61
+ #endif
62
+
63
+ /* Ruar::Serialize::Native */
64
+ static VALUE rb_mRuar;
65
+ static VALUE rb_mRuar_Serialize;
66
+ static VALUE rb_mRuar_Serialize_Native;
67
+
68
+ /* Functions exposed as module functions on Ruar::Serialize::Native */
69
+ static VALUE ruar_serialize_rb_plain_header(VALUE self, VALUE dstfile, VALUE index);
70
+ static VALUE ruar_serialize_rb_append_file(VALUE self, VALUE dstfile, VALUE srcfile);
71
+
72
+ /* Ruar::Access::Native */
73
+ static VALUE rb_kRuar_Access;
74
+ static VALUE rb_mRuar_Access_Native;
75
+
76
+ /* Functions exposed as instance method on Ruar::Access::Native */
77
+ static VALUE ruar_access_rb_header(VALUE self, VALUE archive);
78
+ static VALUE ruar_access_rb_index(VALUE self, VALUE archive);
79
+ static VALUE ruar_access_rb_file(VALUE self, VALUE archive, VALUE offset, VALUE size);
80
+
81
+ /* Ruar::Const::Native */
82
+ static VALUE rb_mRuar_Const;
83
+ static VALUE rb_mRuar_Const_Native;
84
+
85
+ /* Functions exposed as module functions on Ruar::Const::Native */
86
+ static VALUE ruar_const_rb_header_size(VALUE self);
87
+
88
+ /* Helpers*/
89
+ static uint32_t ruar_crc32_generate(const unsigned char *bytes, const int len);
90
+ static VALUE ruar_rb_header_hash(const struct ruar_header *header);
91
+
92
+ void Init_ruar(void)
93
+ {
94
+ rb_mRuar = rb_define_module("Ruar");
95
+
96
+ rb_mRuar_Serialize = rb_define_module_under(rb_mRuar, "Serialize");
97
+ rb_mRuar_Serialize_Native = rb_define_module_under(rb_mRuar_Serialize, "Native");
98
+ rb_define_module_function(rb_mRuar_Serialize_Native, "plain_header", ruar_serialize_rb_plain_header, 2);
99
+ rb_define_module_function(rb_mRuar_Serialize_Native, "append_file", ruar_serialize_rb_append_file, 2);
100
+
101
+ rb_kRuar_Access = rb_define_class_under(rb_mRuar, "Access", rb_cObject);
102
+ rb_mRuar_Access_Native = rb_define_module_under(rb_kRuar_Access, "Native");
103
+ rb_define_module_function(rb_mRuar_Access_Native, "header", ruar_access_rb_header, 1);
104
+ rb_define_module_function(rb_mRuar_Access_Native, "index", ruar_access_rb_index, 1);
105
+ rb_define_module_function(rb_mRuar_Access_Native, "file", ruar_access_rb_file, 3);
106
+
107
+ rb_mRuar_Const = rb_define_module_under(rb_mRuar, "Const");
108
+ rb_mRuar_Const_Native = rb_define_module_under(rb_mRuar_Const, "Native");
109
+ rb_define_module_function(rb_mRuar_Const_Native, "header_size", ruar_const_rb_header_size, 0);
110
+ }
111
+
112
+ static VALUE ruar_const_rb_header_size(VALUE self)
113
+ {
114
+ return INT2NUM(HEADER_SIZE);
115
+ }
116
+
117
+ static uint32_t ruar_crc32_generate(const unsigned char *bytes, const int len)
118
+ {
119
+ return crc32(0, bytes, len) & 0xffffffff;
120
+ }
121
+
122
+ static VALUE ruar_rb_header_hash(const struct ruar_header *header)
123
+ {
124
+ VALUE rb_header = rb_hash_new();
125
+
126
+ rb_hash_aset(rb_header, rb_utf8_str_new_cstr("major_version"), INT2NUM(header->major_version));
127
+ rb_hash_aset(rb_header, rb_utf8_str_new_cstr("minor_version"), INT2NUM(header->minor_version));
128
+ rb_hash_aset(rb_header, rb_utf8_str_new_cstr("patch_version"), INT2NUM(header->patch_version));
129
+ rb_hash_aset(rb_header, rb_utf8_str_new_cstr("platform"), INT2NUM(header->platform));
130
+ rb_hash_aset(rb_header, rb_utf8_str_new_cstr("compression_flags"), INT2NUM(header->compression_flags));
131
+ rb_hash_aset(rb_header, rb_utf8_str_new_cstr("encrypthon_flags"), INT2NUM(header->encryption_flags));
132
+ rb_hash_aset(rb_header, rb_utf8_str_new_cstr("index_start"), INT2NUM(header->index_start));
133
+ rb_hash_aset(rb_header, rb_utf8_str_new_cstr("index_size"), INT2NUM(header->index_size));
134
+ rb_hash_aset(rb_header, rb_utf8_str_new_cstr("index_checksum"), INT2NUM(header->index_checksum));
135
+ rb_hash_aset(rb_header, rb_utf8_str_new_cstr("header_checksum"), INT2NUM(header->header_checksum));
136
+
137
+ return rb_header;
138
+ }
139
+
140
+ static VALUE ruar_serialize_rb_plain_header(VALUE self, VALUE dstfile, VALUE index)
141
+ {
142
+ /* Call into ruby to generate the index */
143
+ char *index_cstring = rb_string_value_cstr(&index);
144
+ uint32_t index_size = INDEX_SIZE(index_cstring);
145
+
146
+ /* Fill out a header */
147
+ struct ruar_header header = {
148
+ .major_version = current_major_version,
149
+ .minor_version = current_minor_version,
150
+ .patch_version = current_patch_version,
151
+ .platform = current_platform,
152
+ .encryption_flags = 0,
153
+ .compression_flags = 0,
154
+ .index_start = HEADER_SIZE,
155
+ .index_size = index_size,
156
+ .index_checksum = ruar_crc32_generate((unsigned char *)index_cstring, index_size),
157
+ .header_checksum = 0};
158
+ header.header_checksum = ruar_crc32_generate((unsigned char *)&header, HEADER_SIZE);
159
+
160
+ /* Write header */
161
+ char *dstfile_cstring = rb_string_value_cstr(&dstfile);
162
+ FILE *outfile = fopen(dstfile_cstring, "wb");
163
+ if (outfile == NULL)
164
+ {
165
+ fprintf(stderr, "\nFailed to open file! %s\n", dstfile_cstring);
166
+ return Qnil;
167
+ }
168
+
169
+ fwrite(&header, HEADER_SIZE, 1, outfile);
170
+ fwrite(index_cstring, index_size, 1, outfile);
171
+ fclose(outfile);
172
+
173
+ /* Get Ruby Hash */
174
+ return ruar_rb_header_hash(&header);
175
+ }
176
+
177
+ /* FIXME: maybe we need an atomic way to do this */
178
+ static VALUE ruar_serialize_rb_append_file(VALUE self, VALUE dstfile, VALUE srcfile)
179
+ {
180
+ /* Open archive file to write */
181
+ char *dstfile_cstring = rb_string_value_cstr(&dstfile);
182
+ FILE *outfile = fopen(dstfile_cstring, "ab");
183
+ if (outfile == NULL)
184
+ {
185
+ fprintf(stderr, "\nFailed to open file! %s\n", dstfile_cstring);
186
+ return Qnil;
187
+ }
188
+
189
+ /* Open source file to read */
190
+ char *srcfile_cstring = rb_string_value_cstr(&srcfile);
191
+ FILE *sourcefile = fopen(srcfile_cstring, "rb");
192
+ if (sourcefile == NULL)
193
+ {
194
+ fprintf(stderr, "\nFailed to open file! %s\n", dstfile_cstring);
195
+ fclose(outfile);
196
+ return Qnil;
197
+ }
198
+
199
+ /* Append source to archive */
200
+ uint8_t buf[READ_SRC_BUFFER_SIZE];
201
+ size_t size = 0;
202
+ while ((size = fread(buf, 1, READ_SRC_BUFFER_SIZE, sourcefile)))
203
+ {
204
+ // fprintf(stdout, "Write %d bytes, from %s to %s\n", size, srcfile_cstring, dstfile_cstring);
205
+ fwrite(buf, 1, size, outfile);
206
+ }
207
+
208
+ /* Clean up */
209
+ fclose(sourcefile);
210
+ fclose(outfile);
211
+
212
+ /* Ruby Hash */
213
+ return srcfile;
214
+ }
215
+
216
+ static VALUE ruar_access_rb_header(VALUE self, VALUE archive)
217
+ {
218
+ char *archive_cstring = rb_string_value_cstr(&archive);
219
+ FILE *fp = fopen(archive_cstring, "rb");
220
+ if (fp == NULL)
221
+ {
222
+ fprintf(stderr, "\nFailed to open file! %s\n", archive_cstring);
223
+ return Qnil;
224
+ }
225
+ uint8_t buf[HEADER_SIZE];
226
+ fread(buf, HEADER_SIZE, 1, fp);
227
+ fclose(fp);
228
+
229
+ struct ruar_header *header = (struct ruar_header *)buf;
230
+
231
+ /* Validate */
232
+ uint32_t header_checksum = header->header_checksum; /* Extract first*/
233
+ header->header_checksum = 0; /* Clear these bits */
234
+ uint32_t re_checksum = ruar_crc32_generate(buf, HEADER_SIZE); /* Re-compute it */
235
+ header->header_checksum = header_checksum; /* Put it back */
236
+ if (re_checksum != header_checksum)
237
+ {
238
+ fprintf(stderr, "\nUnmatched checksum, provided: %x, expected: %x \n", re_checksum, header_checksum);
239
+ return Qnil;
240
+ }
241
+
242
+ /* Ruby Hash */
243
+ return ruar_rb_header_hash(header);
244
+ }
245
+
246
+ static VALUE ruar_access_rb_index(VALUE self, VALUE archive)
247
+ {
248
+ /* Read the header first */
249
+ char *archive_cstring = rb_string_value_cstr(&archive);
250
+ FILE *fp = fopen(archive_cstring, "rb");
251
+ if (fp == NULL)
252
+ {
253
+ fprintf(stderr, "\nFailed to open file! %s\n", archive_cstring);
254
+ return Qnil;
255
+ }
256
+
257
+ uint8_t header_buf[HEADER_SIZE];
258
+ fread(header_buf, HEADER_SIZE, 1, fp);
259
+
260
+ /* Extract index info from the header */
261
+ struct ruar_header *header = (struct ruar_header *)header_buf;
262
+ uint32_t index_start = header->index_start;
263
+ uint32_t index_size = header->index_size;
264
+ uint32_t index_checksum = header->index_checksum;
265
+
266
+ /* Prepare buffer and load the index into memory
267
+ * When we serialized the index into archive, the trailing '\0'
268
+ * has already been added and counted in index_size
269
+ */
270
+ uint8_t *index_buf = (uint8_t *)malloc(sizeof(uint8_t) * index_size);
271
+ if (index_buf == NULL)
272
+ {
273
+ fprintf(stderr, "\nFailed to allocate memory for index buffer!\n");
274
+ fclose(fp);
275
+ return Qnil;
276
+ }
277
+ fseek(fp, index_start, SEEK_SET);
278
+ fread(index_buf, index_size, 1, fp);
279
+ fclose(fp);
280
+
281
+ /* Validate */
282
+ uint32_t re_checksum = ruar_crc32_generate(index_buf, index_size);
283
+ if (re_checksum != index_checksum)
284
+ {
285
+ free(index_buf);
286
+ fprintf(stderr, "\nUnmatched checksum, provided: %x, expected: %x \n", re_checksum, index_checksum);
287
+ return Qnil;
288
+ }
289
+
290
+ /* Get Ruby String */
291
+ VALUE index = rb_utf8_str_new_cstr((char *)index_buf);
292
+ free(index_buf);
293
+
294
+ /* Ruby String */
295
+ return index;
296
+ }
297
+
298
+ /* Offset here is absolute offset from the beginning of the archive,
299
+ * and it's calculated in Ruby code
300
+ */
301
+ static VALUE ruar_access_rb_file(VALUE self, VALUE archive, VALUE offset, VALUE size)
302
+ {
303
+ char *archive_cstring = rb_string_value_cstr(&archive);
304
+ FILE *fp = fopen(archive_cstring, "rb");
305
+ if (fp == NULL)
306
+ {
307
+ fprintf(stderr, "\nFailed to open file! %s\n", archive_cstring);
308
+ return Qnil;
309
+ }
310
+
311
+ size_t size_cint = NUM2SIZET(size);
312
+
313
+
314
+ /* Ruby C API will convert this C-style String to a Ruby String Object
315
+ * Thus one extra byte for the trialing '\0'
316
+ */
317
+ uint8_t *file_buf = (uint8_t *)malloc(sizeof(uint8_t) * size_cint + 1);
318
+ if (file_buf == NULL)
319
+ {
320
+ fprintf(stderr, "\nFailed to allocate memory for file buffer!\n");
321
+ fclose(fp);
322
+ return Qnil;
323
+ }
324
+
325
+ size_t offset_cint = NUM2SIZET(offset);
326
+ fseek(fp, offset_cint, SEEK_SET);
327
+ fread(file_buf, 1, size_cint, fp);
328
+ fclose(fp);
329
+
330
+ /* Trailing '\0' for the C-style string */
331
+ file_buf[size_cint] = '\0';
332
+ VALUE file = rb_utf8_str_new_cstr((char *)file_buf);
333
+ free(file_buf);
334
+
335
+ /* Ruby String */
336
+ return file;
337
+ }
data/ext/ruar/ruar.h ADDED
@@ -0,0 +1,4 @@
1
+ #ifndef RUAR_H
2
+ #define RUAR_H
3
+ /* Doesn't expose anything */
4
+ #endif /* RUAR_H */
data/lib/ruar.rb ADDED
@@ -0,0 +1,19 @@
1
+ # frozen_string_literal: true
2
+
3
+ require 'json'
4
+ require 'tmpdir'
5
+ require 'pathname'
6
+ require 'binding_of_caller'
7
+
8
+ require_relative 'ruar/version'
9
+ require_relative 'ruar/ruar'
10
+ require_relative 'ruar/error'
11
+
12
+ require_relative 'ruar/index'
13
+ require_relative 'ruar/serialize'
14
+ require_relative 'ruar/access'
15
+ require_relative 'ruar/entrypoint'
16
+
17
+ require_relative 'ruar/setup'
18
+
19
+ require_relative 'ruar/core_ext/string_colorize'
@@ -0,0 +1,93 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Ruar
4
+ class Access
5
+ attr_reader :archive, :header, :index
6
+
7
+ def self.make_not_exist_error(path)
8
+ Ruar::Error::FileNotFound.new(path)
9
+ end
10
+
11
+ def self.make_failed_to_eval_error(path)
12
+ Ruar::Error::FailedToEval.new(path)
13
+ end
14
+
15
+ def self.warn_autoload(name_error)
16
+ location = name_error.backtrace_locations.first
17
+ message = <<~MSG
18
+ #{location}
19
+ Kernel.autoload and Module.autoload are not supported by ruar,
20
+ if you are using them, try `require` instead
21
+ MSG
22
+ warn message.yellow
23
+ end
24
+
25
+ def initialize(archive)
26
+ @archive = archive
27
+ rebuild
28
+ end
29
+
30
+ def lookup(path)
31
+ paths = Ruar::Access.clean_path(path)
32
+ filename = paths.pop
33
+
34
+ pwd = @index['files']
35
+
36
+ begin
37
+ paths.each { |dir| pwd = pwd[dir]['files'] }
38
+ rescue StandardError
39
+ raise Ruar::Access.make_not_exist_error(path)
40
+ end
41
+
42
+ raise Ruar::Access.make_not_exist_error(path) if pwd[filename].nil?
43
+
44
+ offset = pwd[filename]['offset'] + @file_start
45
+ size = pwd[filename]['size']
46
+ executable = pwd[filename]['executable']
47
+
48
+ [offset, size, executable]
49
+ end
50
+
51
+ def read(path)
52
+ offset, size, _executable = lookup(path)
53
+ Ruar::Access::Native.file(@archive, offset.to_i, size.to_i)
54
+ end
55
+
56
+ def eval(path, eval_bind = TOPLEVEL_BINDING)
57
+ pseudo_filename = File.join(Ruar.path_prefix.to_s, Ruar::Access.abs_path(path))
58
+ pseudo_lineno = 1
59
+ file = read(path)
60
+ # FIXME: need to test
61
+ begin
62
+ Kernel.eval(file, eval_bind, pseudo_filename, pseudo_lineno)
63
+ rescue NameError => e # FIXME: to warn autoload pitfall
64
+ begin
65
+ Ruar::Access.warn_autoload(e)
66
+ raise
67
+ rescue StandardError
68
+ raise Ruar::Access.make_failed_to_eval_error(path)
69
+ end
70
+ end
71
+ end
72
+
73
+ def self.abs_path(path)
74
+ Pathname.new(path).cleanpath.to_s
75
+ end
76
+
77
+ # Array
78
+ def self.clean_path(path)
79
+ cleaned = Ruar::Access.abs_path(path).split(File::SEPARATOR)
80
+ cleaned.delete('')
81
+
82
+ cleaned
83
+ end
84
+
85
+ private
86
+
87
+ def rebuild
88
+ @header = Ruar::Access::Native.header(@archive)
89
+ @index = JSON.parse(Ruar::Access::Native.index(@archive))
90
+ @file_start = @header['index_start'] + @header['index_size']
91
+ end
92
+ end
93
+ end
@@ -0,0 +1,118 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Ruar
4
+ class Access
5
+ module CoreExt
6
+ def self.make_load_error(path)
7
+ err = LoadError.new(+"cannot load such file -- #{path}")
8
+ err.define_singleton_method(:path) { path }
9
+ err
10
+ end
11
+
12
+ # Generate pseudo $LOADED_FEATURES entry
13
+ def self.pseudo_lf_entry(path)
14
+ prefix = Ruar.path_prefix
15
+ # TODO: support .so here
16
+ if File.extname(path) == '.rb'
17
+ File.join(prefix, path)
18
+ else
19
+ File.join(prefix, "#{path}.rb")
20
+ end
21
+ end
22
+ end
23
+ end
24
+ end
25
+
26
+ module Kernel
27
+ module_function
28
+
29
+ def ruar_eval_wrap(path, eval_bind = TOPLEVEL_BINDING)
30
+ Ruar.eval(path, eval_bind)
31
+ yield
32
+ true
33
+ rescue Ruar::Error::FileNotFound
34
+ # Try again with .rb extension
35
+ begin
36
+ # For rubocop:
37
+ Ruar.eval("#{path}.rb", eval_bind) # Ruar.eval(path.rb, eval_bind)
38
+ yield
39
+ true
40
+ rescue Ruar::Error::BaseError
41
+ raise Ruar::Access::CoreExt.make_load_error(path)
42
+ end
43
+ rescue Ruar::Error::BaseError
44
+ raise Ruar::Access::CoreExt.make_load_error(path)
45
+ end
46
+
47
+ alias require_without_ruar require
48
+
49
+ def require_with_ruar(path, eval_bind = TOPLEVEL_BINDING)
50
+ # puts "path = #{path}, location = #{eval_bind.source_location}"
51
+ pseudo_entry = Ruar::Access::CoreExt.pseudo_lf_entry(path)
52
+ return false if $LOADED_FEATURES.include?(pseudo_entry) # Already been required
53
+
54
+ ruar_eval_wrap(path, eval_bind) do
55
+ $LOADED_FEATURES << pseudo_entry
56
+ end
57
+ end
58
+
59
+ def require(path, from: :both)
60
+ case from
61
+ when :both
62
+ begin
63
+ require_with_ruar(path)
64
+ rescue LoadError
65
+ require_without_ruar(path)
66
+ end
67
+ when :ruar
68
+ require_with_ruar(path)
69
+ when :local
70
+ require_without_ruar(path)
71
+ else
72
+ raise Ruar::Access::CoreExt.make_load_error(path)
73
+ end
74
+ end
75
+
76
+ alias require_relative_without_ruar require_relative
77
+
78
+ # TODO: need to test
79
+ def require_relative(path, from: :both)
80
+ caller_path = caller_locations.first.path.to_s
81
+ caller_dir = Pathname.new(caller_path).dirname.to_s
82
+ prefix = Ruar.path_prefix.to_s
83
+
84
+ # Ruar Internal File
85
+ caller_dir = caller_dir.delete_prefix(prefix).prepend(File::SEPARATOR) if caller_dir.start_with?(prefix)
86
+
87
+ resolved_path = File.expand_path(path, caller_dir)
88
+ require(resolved_path, from: from)
89
+ end
90
+
91
+ alias load_without_ruar load
92
+
93
+ def load_with_ruar(path, eval_bind = TOPLEVEL_BINDING)
94
+ ruar_eval_wrap(path, eval_bind) do
95
+ # Do nothing, just read and eval
96
+ end
97
+ end
98
+
99
+ def load(path, from: :both)
100
+ case from
101
+ when :both
102
+ begin
103
+ load_with_ruar(path)
104
+ rescue LoadError
105
+ load_without_ruar(path)
106
+ end
107
+ when :ruar
108
+ load_with_ruar(path)
109
+ when :local
110
+ load_without_ruar(path)
111
+ else
112
+ raise Ruar::Access::CoreExt.make_load_error(path)
113
+ end
114
+ end
115
+
116
+ # TODO: deliberately test autoload
117
+ # FIXME: not support autoload
118
+ end
@@ -0,0 +1,23 @@
1
+ # frozen_string_literal: true
2
+
3
+ class String
4
+ def colorize(color_code)
5
+ "\e[#{color_code}m#{self}\e[0m"
6
+ end
7
+
8
+ def red
9
+ colorize(31)
10
+ end
11
+
12
+ def green
13
+ colorize(32)
14
+ end
15
+
16
+ def yellow
17
+ colorize(33)
18
+ end
19
+
20
+ def blue
21
+ colorize(34)
22
+ end
23
+ end
@@ -0,0 +1,20 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Ruar
4
+ class EntryPoint
5
+ def initialize(archive: nil, entry: nil)
6
+ @archive = archive
7
+ @entry = entry
8
+ end
9
+
10
+ def activate
11
+ @access = Ruar::Access.new(@archive)
12
+ # First eval this file if option[:entry] is set
13
+ @access.eval(@entry) unless @entry.nil?
14
+ end
15
+
16
+ def eval(path, eval_bind = TOPLEVEL_BINDING)
17
+ @access.eval(path, eval_bind)
18
+ end
19
+ end
20
+ end
data/lib/ruar/error.rb ADDED
@@ -0,0 +1,26 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Ruar
4
+ module Error
5
+ class BaseError < RuntimeError
6
+ end
7
+
8
+ class FileNotFound < BaseError
9
+ attr_reader :path
10
+
11
+ def initialize(path)
12
+ @path = path
13
+ super(+"file does not exist in ruar -- #{path}")
14
+ end
15
+ end
16
+
17
+ class FailedToEval < BaseError
18
+ attr_reader :path
19
+
20
+ def initialize(path)
21
+ @path = path
22
+ super(+"ruar failed to eval -- #{path}")
23
+ end
24
+ end
25
+ end
26
+ end
data/lib/ruar/index.rb ADDED
@@ -0,0 +1,64 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Ruar
4
+ class Index
5
+ attr_reader :dir, :index, :source_info
6
+
7
+ def initialize(dir = '.')
8
+ @dir = dir
9
+ generate(dir)
10
+ end
11
+
12
+ def json_index
13
+ @index.to_json
14
+ end
15
+
16
+ private
17
+
18
+ # Generate json format index
19
+ def generate(dir)
20
+ @index, @source_info = scan(dir, 0)
21
+ end
22
+
23
+ # FIXME: don't recurse
24
+ # TODO: support compression and encryption
25
+ # Recursively scan the directory
26
+ def scan(dir, offset)
27
+ Dir.chdir(dir) do
28
+ index = { 'files' => {} }
29
+ source_info = [] # { realpath, size, offset }
30
+ entities = Dir['**']
31
+ return [index, source_info, offset] if entities.empty?
32
+
33
+ files = entities.select { |f| File.file?(f) }
34
+ files.each do |f|
35
+ size = File.size(f)
36
+
37
+ index['files'][f] = {
38
+ 'size' => size,
39
+ 'offset' => offset,
40
+ 'executable' => File.executable?(f)
41
+ }
42
+
43
+ source_info.push({
44
+ 'realpath' => File.realpath(f),
45
+ 'size' => size,
46
+ 'offset' => offset
47
+ })
48
+
49
+ offset += size
50
+ end
51
+
52
+ dirs = entities.select { |d| File.directory?(d) }
53
+ dirs.each do |d|
54
+ # Notice: need to accumulate offset here
55
+ sub_index, sub_source_info, offset = scan(d, offset)
56
+ index['files'][d] = sub_index
57
+ source_info.concat(sub_source_info)
58
+ end
59
+
60
+ [index, source_info, offset]
61
+ end
62
+ end
63
+ end
64
+ end
data/lib/ruar/ruar.so ADDED
Binary file
@@ -0,0 +1,13 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Ruar
4
+ module Serialize
5
+ def self.plain(srcdir, dstfile)
6
+ index = Ruar::Index.new(srcdir)
7
+ Ruar::Serialize::Native.plain_header(dstfile, index.json_index)
8
+ index.source_info.each do |src|
9
+ Ruar::Serialize::Native.append_file(dstfile, src['realpath'])
10
+ end
11
+ end
12
+ end
13
+ end
data/lib/ruar/setup.rb ADDED
@@ -0,0 +1,41 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Ruar
4
+ module Setup
5
+ def self.included(base)
6
+ base.extend ClassMethods
7
+ end
8
+
9
+ module ClassMethods
10
+ def setup(archive: nil, entry: nil)
11
+ @entrypoint ||= Ruar::EntryPoint.new(archive: archive, entry: entry)
12
+ @path_prefix ||= Pathname.new('/_from/_ruar/_internal')
13
+
14
+ self
15
+ end
16
+
17
+ def path_prefix
18
+ @path_prefix
19
+ end
20
+
21
+ def activate
22
+ return if @activated
23
+
24
+ @activated = true
25
+
26
+ require_relative 'core_ext/kernel_require'
27
+ @entrypoint.activate
28
+
29
+ puts 'Ruar Activated!'.green
30
+ end
31
+
32
+ def eval(path, bind = TOPLEVEL_BINDING)
33
+ @entrypoint.eval(path, bind)
34
+ end
35
+ end
36
+ end
37
+ end
38
+
39
+ module Ruar
40
+ include Ruar::Setup
41
+ end
@@ -0,0 +1,5 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Ruar
4
+ VERSION = '0.0.2'
5
+ end
metadata ADDED
@@ -0,0 +1,173 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: ruar
3
+ version: !ruby/object:Gem::Version
4
+ version: 0.0.2
5
+ platform: ruby
6
+ authors:
7
+ - Kowalski Dark
8
+ autorequire:
9
+ bindir: bin
10
+ cert_chain: []
11
+ date: 2021-02-20 00:00:00.000000000 Z
12
+ dependencies:
13
+ - !ruby/object:Gem::Dependency
14
+ name: binding_of_caller
15
+ requirement: !ruby/object:Gem::Requirement
16
+ requirements:
17
+ - - "~>"
18
+ - !ruby/object:Gem::Version
19
+ version: 1.0.0
20
+ type: :development
21
+ prerelease: false
22
+ version_requirements: !ruby/object:Gem::Requirement
23
+ requirements:
24
+ - - "~>"
25
+ - !ruby/object:Gem::Version
26
+ version: 1.0.0
27
+ - !ruby/object:Gem::Dependency
28
+ name: minitest
29
+ requirement: !ruby/object:Gem::Requirement
30
+ requirements:
31
+ - - "~>"
32
+ - !ruby/object:Gem::Version
33
+ version: 5.14.3
34
+ type: :development
35
+ prerelease: false
36
+ version_requirements: !ruby/object:Gem::Requirement
37
+ requirements:
38
+ - - "~>"
39
+ - !ruby/object:Gem::Version
40
+ version: 5.14.3
41
+ - !ruby/object:Gem::Dependency
42
+ name: minitest-reporters
43
+ requirement: !ruby/object:Gem::Requirement
44
+ requirements:
45
+ - - "~>"
46
+ - !ruby/object:Gem::Version
47
+ version: 1.4.3
48
+ type: :development
49
+ prerelease: false
50
+ version_requirements: !ruby/object:Gem::Requirement
51
+ requirements:
52
+ - - "~>"
53
+ - !ruby/object:Gem::Version
54
+ version: 1.4.3
55
+ - !ruby/object:Gem::Dependency
56
+ name: rake
57
+ requirement: !ruby/object:Gem::Requirement
58
+ requirements:
59
+ - - "~>"
60
+ - !ruby/object:Gem::Version
61
+ version: 13.0.3
62
+ type: :development
63
+ prerelease: false
64
+ version_requirements: !ruby/object:Gem::Requirement
65
+ requirements:
66
+ - - "~>"
67
+ - !ruby/object:Gem::Version
68
+ version: 13.0.3
69
+ - !ruby/object:Gem::Dependency
70
+ name: rake-compiler
71
+ requirement: !ruby/object:Gem::Requirement
72
+ requirements:
73
+ - - "~>"
74
+ - !ruby/object:Gem::Version
75
+ version: 1.1.1
76
+ type: :development
77
+ prerelease: false
78
+ version_requirements: !ruby/object:Gem::Requirement
79
+ requirements:
80
+ - - "~>"
81
+ - !ruby/object:Gem::Version
82
+ version: 1.1.1
83
+ - !ruby/object:Gem::Dependency
84
+ name: rubocop
85
+ requirement: !ruby/object:Gem::Requirement
86
+ requirements:
87
+ - - "~>"
88
+ - !ruby/object:Gem::Version
89
+ version: 1.9.0
90
+ type: :development
91
+ prerelease: false
92
+ version_requirements: !ruby/object:Gem::Requirement
93
+ requirements:
94
+ - - "~>"
95
+ - !ruby/object:Gem::Version
96
+ version: 1.9.0
97
+ - !ruby/object:Gem::Dependency
98
+ name: rubocop-minitest
99
+ requirement: !ruby/object:Gem::Requirement
100
+ requirements:
101
+ - - "~>"
102
+ - !ruby/object:Gem::Version
103
+ version: 0.10.3
104
+ type: :development
105
+ prerelease: false
106
+ version_requirements: !ruby/object:Gem::Requirement
107
+ requirements:
108
+ - - "~>"
109
+ - !ruby/object:Gem::Version
110
+ version: 0.10.3
111
+ - !ruby/object:Gem::Dependency
112
+ name: rubocop-rake
113
+ requirement: !ruby/object:Gem::Requirement
114
+ requirements:
115
+ - - "~>"
116
+ - !ruby/object:Gem::Version
117
+ version: 0.5.1
118
+ type: :development
119
+ prerelease: false
120
+ version_requirements: !ruby/object:Gem::Requirement
121
+ requirements:
122
+ - - "~>"
123
+ - !ruby/object:Gem::Version
124
+ version: 0.5.1
125
+ description: Pack your Ruby code for distribution
126
+ email:
127
+ - darkkowalski2012@gmail.com
128
+ executables: []
129
+ extensions:
130
+ - ext/ruar/extconf.rb
131
+ extra_rdoc_files: []
132
+ files:
133
+ - LICENSE
134
+ - README.md
135
+ - ext/ruar/extconf.rb
136
+ - ext/ruar/ruar.c
137
+ - ext/ruar/ruar.h
138
+ - lib/ruar.rb
139
+ - lib/ruar/access.rb
140
+ - lib/ruar/core_ext/kernel_require.rb
141
+ - lib/ruar/core_ext/string_colorize.rb
142
+ - lib/ruar/entrypoint.rb
143
+ - lib/ruar/error.rb
144
+ - lib/ruar/index.rb
145
+ - lib/ruar/ruar.so
146
+ - lib/ruar/serialize.rb
147
+ - lib/ruar/setup.rb
148
+ - lib/ruar/version.rb
149
+ homepage: https://github.com/darkkowalski/ruar
150
+ licenses:
151
+ - Apache-2.0
152
+ metadata:
153
+ bug_tracker_uri: https://github.com/darkkowalski/ruar/issues
154
+ post_install_message:
155
+ rdoc_options: []
156
+ require_paths:
157
+ - lib
158
+ required_ruby_version: !ruby/object:Gem::Requirement
159
+ requirements:
160
+ - - ">="
161
+ - !ruby/object:Gem::Version
162
+ version: 3.0.0
163
+ required_rubygems_version: !ruby/object:Gem::Requirement
164
+ requirements:
165
+ - - ">="
166
+ - !ruby/object:Gem::Version
167
+ version: '0'
168
+ requirements: []
169
+ rubygems_version: 3.2.3
170
+ signing_key:
171
+ specification_version: 4
172
+ summary: Tar-like Archive for RIEN
173
+ test_files: []