ocran 1.4.6 → 1.5.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.
Files changed (49) hide show
  1. checksums.yaml +4 -4
  2. data/CHANGELOG.txt +68 -0
  3. data/README.md +295 -10
  4. data/ext/extconf.rb +5 -1
  5. data/lib/ocran/aot_toolchain.rb +154 -0
  6. data/lib/ocran/command_output.rb +8 -1
  7. data/lib/ocran/compatibility_scan.rb +414 -0
  8. data/lib/ocran/cosmo_toolchain.rb +29 -7
  9. data/lib/ocran/dir_builder.rb +88 -38
  10. data/lib/ocran/direction.rb +190 -30
  11. data/lib/ocran/ed_resource.rb +113 -0
  12. data/lib/ocran/ed_resource_builder.rb +199 -0
  13. data/lib/ocran/file_path_set.rb +9 -5
  14. data/lib/ocran/gem_spec_queryable.rb +7 -3
  15. data/lib/ocran/host_config_helper.rb +11 -1
  16. data/lib/ocran/inno_setup_script_builder.rb +24 -14
  17. data/lib/ocran/launcher_batch_builder.rb +8 -11
  18. data/lib/ocran/npm_package.rb +106 -0
  19. data/lib/ocran/option.rb +425 -35
  20. data/lib/ocran/pe_imports.rb +96 -0
  21. data/lib/ocran/pe_resources.rb +226 -0
  22. data/lib/ocran/refine_pathname.rb +29 -32
  23. data/lib/ocran/roundhouse_builder.rb +316 -0
  24. data/lib/ocran/runner.rb +43 -11
  25. data/lib/ocran/runtime_sdk.rb +252 -0
  26. data/lib/ocran/spinel_builder.rb +183 -0
  27. data/lib/ocran/spinel_compatibility.rb +149 -0
  28. data/lib/ocran/static_runtime/boot.rb +443 -0
  29. data/lib/ocran/static_runtime/build_static_ext.rb +86 -0
  30. data/lib/ocran/static_runtime_builder.rb +814 -0
  31. data/lib/ocran/stub_builder.rb +70 -25
  32. data/lib/ocran/version.rb +1 -1
  33. data/lib/ocran/wasm_builder.rb +570 -0
  34. data/lib/ocran/wasm_compatibility.rb +198 -0
  35. data/lib/ocran/windows_command_escaping.rb +21 -0
  36. data/lib/ocran/zip_payload_builder.rb +18 -9
  37. data/lib/ocran/zip_writer.rb +48 -9
  38. data/src/Makefile +18 -2
  39. data/src/Makefile.mswin +65 -0
  40. data/src/inst_dir.c +34 -6
  41. data/src/path_utils.c +144 -0
  42. data/src/script_info.c +5 -0
  43. data/src/stub.c +77 -19
  44. data/src/stub.rc +1 -1
  45. data/src/system_utils.c +276 -155
  46. data/src/system_utils.h +46 -3
  47. data/src/system_utils_posix.c +243 -148
  48. data/src/unpack.c +9 -0
  49. metadata +22 -4
@@ -2,12 +2,14 @@
2
2
  #include <mach-o/dyld.h>
3
3
  #endif
4
4
  #ifdef __COSMOPOLITAN__
5
- #include <cosmo.h> /* GetProgramExecutableName() */
5
+ #include <cosmo.h> /* GetProgramExecutableName(), IsWindows() */
6
6
  #endif
7
7
  #include <unistd.h>
8
8
  #include <fcntl.h>
9
+ #include <termios.h>
9
10
  #include <sys/stat.h>
10
11
  #include <sys/mman.h>
12
+ #include <sys/resource.h>
11
13
  #include <sys/wait.h>
12
14
  #include <sys/types.h>
13
15
  #include <dirent.h>
@@ -27,121 +29,6 @@ struct MemoryMap {
27
29
  size_t size;
28
30
  };
29
31
 
30
- /* ===== Cross-platform path utilities (from system_utils.c) ===== */
31
-
32
- bool IsCleanRelativePath(const char *path)
33
- {
34
- if (!path || !*path) {
35
- return false;
36
- }
37
-
38
- #ifdef _WIN32
39
- /* Forbid Windows drive specification (e.g. "C:\") */
40
- if (((path[0] >= 'A' && path[0] <= 'Z') || (path[0] >= 'a' && path[0] <= 'z'))
41
- && path[1] == ':'
42
- && is_path_separator(path[2])) {
43
- return false;
44
- }
45
- #endif
46
-
47
- /* Forbid absolute path (leading '/' or '\') */
48
- if (is_path_separator(*path)) {
49
- return false;
50
- }
51
-
52
- /* Validate each path segment */
53
- const char *p = path;
54
- while (*p) {
55
- const char *start = p;
56
-
57
- /* Advance until next separator or end-of-string */
58
- while (*p && !is_path_separator(*p)) {
59
- p++;
60
- }
61
-
62
- size_t len = p - start;
63
-
64
- /* Reject empty, "." or ".." segments */
65
- if (len == 0
66
- || (len == 1 && start[0] == '.')
67
- || (len == 2 && start[0] == '.' && start[1] == '.')) {
68
- return false;
69
- }
70
-
71
- /* Skip over the separator */
72
- if (*p) {
73
- p++;
74
- }
75
- }
76
-
77
- return true;
78
- }
79
-
80
- char *JoinPath(const char *p1, const char *p2)
81
- {
82
- if (p1 == NULL || *p1 == '\0') {
83
- APP_ERROR("p1 is null or empty");
84
- return NULL;
85
- }
86
-
87
- if (p2 == NULL || *p2 == '\0') {
88
- APP_ERROR("p2 is null or empty");
89
- return NULL;
90
- }
91
-
92
- size_t p1_len = strlen(p1);
93
- if (is_path_separator(p1[p1_len - 1])) { p1_len--; }
94
-
95
- size_t p2_len = strlen(p2);
96
- const char *p2_start = p2;
97
- if (is_path_separator(*p2_start)) { p2_start++; p2_len--; }
98
-
99
- size_t joined_len = p1_len + 1 + p2_len;
100
- char *joined_path = calloc(1, joined_len + 1);
101
- if (!joined_path) {
102
- APP_ERROR("Failed to allocate buffer for join path");
103
- return NULL;
104
- }
105
- memcpy(joined_path, p1, p1_len);
106
- joined_path[p1_len] = PATH_SEPARATOR;
107
- memcpy(joined_path + p1_len + 1, p2_start, p2_len);
108
- joined_path[joined_len] = '\0';
109
-
110
- return joined_path;
111
- }
112
-
113
- char *GetParentPath(const char *path)
114
- {
115
- if (!path) {
116
- APP_ERROR("path is NULL");
117
- return NULL;
118
- }
119
-
120
- size_t len = strlen(path);
121
- size_t i = len;
122
-
123
- /* Skip any trailing separators */
124
- while (i > 0 && is_path_separator(path[i])) {
125
- i--;
126
- }
127
-
128
- /* Skip the last segment's characters */
129
- while (i > 0 && !is_path_separator(path[i])) {
130
- i--;
131
- }
132
-
133
- /* i==0 ⇒ empty parent */
134
-
135
- char *out = malloc(i + 1);
136
- if (!out) {
137
- APP_ERROR("Memory allocation failed for parent path");
138
- return NULL;
139
- }
140
- memcpy(out, path, i);
141
- out[i] = '\0';
142
- return out;
143
- }
144
-
145
32
  /* ===== Memory-mapped file I/O ===== */
146
33
 
147
34
  MemoryMap *CreateMemoryMap(const char *path) {
@@ -248,6 +135,9 @@ bool CreateDirectoriesRecursively(const char *dir) {
248
135
  return true;
249
136
  }
250
137
 
138
+ /* Keeps going after a failure so that as much as possible gets deleted, and
139
+ returns false if anything could not be. Failures are only reported in
140
+ debug mode: the application has run, and there is nobody to act on them. */
251
141
  bool DeleteRecursively(const char *path) {
252
142
  if (!path || !*path) {
253
143
  return false;
@@ -255,23 +145,31 @@ bool DeleteRecursively(const char *path) {
255
145
 
256
146
  struct stat st;
257
147
  if (lstat(path, &st) < 0) {
258
- FATAL("DeleteRecursively: stat(\"%s\") failed: %s", path, strerror(errno));
148
+ APP_ERROR("DeleteRecursively: lstat(\"%s\") failed: %s", path, strerror(errno));
259
149
  return false;
260
150
  }
261
151
 
262
152
  if (!S_ISDIR(st.st_mode)) {
263
- /* It's a file, just delete it */
153
+ /* A file or a symlink (which is not followed): just delete it */
264
154
  if (unlink(path) < 0) {
265
- FATAL("DeleteRecursively: unlink(\"%s\") failed: %s", path, strerror(errno));
155
+ APP_ERROR("DeleteRecursively: unlink(\"%s\") failed: %s", path, strerror(errno));
266
156
  return false;
267
157
  }
268
158
  return true;
269
159
  }
270
160
 
161
+ /* Listing a directory and deleting its entries takes read, write and
162
+ search permission, which the application may have removed (e.g. a
163
+ read-only copy of a Go module cache). The directory is the user's
164
+ own, so give them back. */
165
+ if ((st.st_mode & S_IRWXU) != S_IRWXU) {
166
+ chmod(path, (st.st_mode & 07777) | S_IRWXU);
167
+ }
168
+
271
169
  /* It's a directory, delete contents recursively */
272
170
  DIR *dir = opendir(path);
273
171
  if (!dir) {
274
- FATAL("DeleteRecursively: opendir(\"%s\") failed: %s", path, strerror(errno));
172
+ APP_ERROR("DeleteRecursively: opendir(\"%s\") failed: %s", path, strerror(errno));
275
173
  return false;
276
174
  }
277
175
 
@@ -285,13 +183,11 @@ bool DeleteRecursively(const char *path) {
285
183
  char *child_path = JoinPath(path, entry->d_name);
286
184
  if (!child_path) {
287
185
  success = false;
288
- break;
186
+ continue;
289
187
  }
290
188
 
291
189
  if (!DeleteRecursively(child_path)) {
292
- free(child_path);
293
190
  success = false;
294
- break;
295
191
  }
296
192
  free(child_path);
297
193
  }
@@ -300,7 +196,7 @@ bool DeleteRecursively(const char *path) {
300
196
 
301
197
  if (success) {
302
198
  if (rmdir(path) < 0) {
303
- FATAL("DeleteRecursively: rmdir(\"%s\") failed: %s", path, strerror(errno));
199
+ APP_ERROR("DeleteRecursively: rmdir(\"%s\") failed: %s", path, strerror(errno));
304
200
  return false;
305
201
  }
306
202
  }
@@ -338,8 +234,13 @@ bool ExportFile(const char *path, const void *buffer, size_t buffer_size) {
338
234
  free(parent);
339
235
  }
340
236
 
341
- /* Create/overwrite the file */
342
- int fd = open(path, O_WRONLY | O_CREAT | O_TRUNC, 0777);
237
+ /* Create/overwrite the file, but never write through a symlink that
238
+ happens to sit at its path (the file would land at the link's
239
+ target). O_EXCL would be stricter still, but on a case-insensitive
240
+ file system (the macOS default) it would turn two packed names that
241
+ differ only in case, which merely overwrite each other today, into a
242
+ failed start. */
243
+ int fd = open(path, O_WRONLY | O_CREAT | O_TRUNC | O_NOFOLLOW, 0777);
343
244
  if (fd < 0) {
344
245
  FATAL("ExportFile: open(\"%s\") failed: %s", path, strerror(errno));
345
246
  return false;
@@ -449,28 +350,191 @@ char *GetTempDirectoryPath(void) {
449
350
 
450
351
  /* ===== Process and signal handling ===== */
451
352
 
452
- bool InitializeSignalHandling(void) {
453
- /* On POSIX systems, the parent process ignores SIGINT and SIGTERM during
454
- initialization and cleanup. The child process will reset these to
455
- SIG_DFL before execv-ing the target application. */
353
+ /*
354
+ * Termination signals the stub handles while it runs. The handler records
355
+ * the signal and passes it on to the child, so that `kill`, `docker stop`
356
+ * or a service manager stopping the stub stop the application, and the
357
+ * stub lives on to delete the extraction directory. Signals that were
358
+ * ignored when the stub started (e.g. SIGHUP under nohup) stay ignored,
359
+ * and the child inherits that.
360
+ */
361
+ static const int TerminationSignals[] = { SIGINT, SIGTERM, SIGHUP, SIGQUIT };
362
+ #define TERMINATION_SIGNAL_COUNT \
363
+ (sizeof(TerminationSignals) / sizeof(TerminationSignals[0]))
364
+
365
+ /* Which of TerminationSignals were ignored at startup. */
366
+ static bool SignalIgnoredAtStartup[TERMINATION_SIGNAL_COUNT];
367
+
368
+ /* Child to forward termination signals to; 0 while there is none. */
369
+ static volatile sig_atomic_t ChildPid = 0;
370
+
371
+ /* Last termination signal the stub received itself. */
372
+ static volatile sig_atomic_t ReceivedSignal = 0;
373
+
374
+ /* Signal the stub dies of once cleanup is done: the one that killed the
375
+ child, or one received before the child was started. */
376
+ static int TerminatingSignal = 0;
377
+
378
+ /* Whether a signal was sent by a process (kill(2), sigqueue(3)) rather than
379
+ generated by the kernel. Signals the kernel raises for a terminal (Ctrl+C,
380
+ Ctrl+\, hangup) go to the whole foreground process group, the child
381
+ included, which must not get them twice. */
382
+ #ifdef __APPLE__
383
+ /* Whether this process is in the foreground process group of its
384
+ controlling terminal, the only place a terminal-generated signal can
385
+ reach it. Everything here is async-signal-safe. */
386
+ static bool in_foreground_process_group(void)
387
+ {
388
+ int fd = open("/dev/tty", O_RDONLY | O_NOCTTY | O_CLOEXEC);
389
+ if (fd < 0) {
390
+ return false;
391
+ }
392
+ pid_t foreground = tcgetpgrp(fd);
393
+ close(fd);
394
+ return foreground > 0 && foreground == getpgrp();
395
+ }
396
+ #endif
397
+
398
+ static bool is_sent_by_process(const siginfo_t *info)
399
+ {
400
+ if (!info) {
401
+ return true;
402
+ }
403
+ if (info->si_code == SI_USER) {
404
+ return true;
405
+ }
406
+ #ifdef __APPLE__
407
+ /* XNU never reports SI_USER: every caught signal arrives with si_code 0
408
+ and si_pid naming the process in whose context it was raised, for
409
+ kill(2) and for the terminal driver alike (bsd/kern/kern_sig.c), so
410
+ siginfo cannot tell them apart. A terminal signal only reaches the
411
+ foreground process group of the controlling terminal; a stub running
412
+ anywhere else - no terminal, a background job, a service, a CI runner
413
+ - can only have been signaled by a process. */
414
+ if (info->si_code == 0) {
415
+ return !in_foreground_process_group();
416
+ }
417
+ #endif
418
+ #ifdef SI_QUEUE
419
+ if (info->si_code == SI_QUEUE) {
420
+ return true;
421
+ }
422
+ #endif
423
+ #ifdef SI_TKILL
424
+ if (info->si_code == SI_TKILL) {
425
+ return true;
426
+ }
427
+ #endif
428
+ return false;
429
+ }
430
+
431
+ static void termination_signal_handler(int sig, siginfo_t *info, void *context)
432
+ {
433
+ (void)context;
434
+ int saved_errno = errno;
456
435
 
436
+ ReceivedSignal = sig;
437
+ pid_t child = (pid_t)ChildPid;
438
+ if (child > 0 && is_sent_by_process(info)) {
439
+ kill(child, sig);
440
+ }
441
+
442
+ errno = saved_errno;
443
+ }
444
+
445
+ bool InitializeSignalHandling(void) {
457
446
  struct sigaction sa;
458
447
  memset(&sa, 0, sizeof(sa));
459
- sa.sa_handler = SIG_IGN;
460
-
461
- if (sigaction(SIGINT, &sa, NULL) < 0) {
462
- FATAL("InitializeSignalHandling: sigaction(SIGINT) failed: %s", strerror(errno));
463
- return false;
448
+ sa.sa_sigaction = termination_signal_handler;
449
+ sa.sa_flags = SA_SIGINFO | SA_RESTART;
450
+ sigemptyset(&sa.sa_mask);
451
+ for (size_t i = 0; i < TERMINATION_SIGNAL_COUNT; i++) {
452
+ sigaddset(&sa.sa_mask, TerminationSignals[i]);
464
453
  }
465
454
 
466
- if (sigaction(SIGTERM, &sa, NULL) < 0) {
467
- FATAL("InitializeSignalHandling: sigaction(SIGTERM) failed: %s", strerror(errno));
468
- return false;
455
+ for (size_t i = 0; i < TERMINATION_SIGNAL_COUNT; i++) {
456
+ int sig = TerminationSignals[i];
457
+ struct sigaction old;
458
+
459
+ if (sigaction(sig, NULL, &old) < 0) {
460
+ FATAL("InitializeSignalHandling: sigaction(%d) failed: %s", sig, strerror(errno));
461
+ return false;
462
+ }
463
+ if (!(old.sa_flags & SA_SIGINFO) && old.sa_handler == SIG_IGN) {
464
+ SignalIgnoredAtStartup[i] = true;
465
+ continue;
466
+ }
467
+ if (sigaction(sig, &sa, NULL) < 0) {
468
+ FATAL("InitializeSignalHandling: sigaction(%d) failed: %s", sig, strerror(errno));
469
+ return false;
470
+ }
469
471
  }
470
472
 
471
473
  return true;
472
474
  }
473
475
 
476
+ static void (*CleanupRoutine)(void) = NULL;
477
+ static bool CleanupDone = false;
478
+
479
+ void SetCleanupRoutine(void (*routine)(void))
480
+ {
481
+ CleanupRoutine = routine;
482
+ }
483
+
484
+ /* Only ever called from the main thread here: signal handlers merely
485
+ forward, and the main thread outlives the child to clean up. */
486
+ void RunCleanupRoutine(void)
487
+ {
488
+ if (CleanupDone) {
489
+ return;
490
+ }
491
+ CleanupDone = true;
492
+ if (CleanupRoutine) {
493
+ CleanupRoutine();
494
+ }
495
+ }
496
+
497
+ void ReraiseChildSignal(void)
498
+ {
499
+ int sig = TerminatingSignal;
500
+ if (sig == 0) {
501
+ return;
502
+ }
503
+
504
+ #ifdef __COSMOPOLITAN__
505
+ /* A native Windows parent cannot see a signal death; it gets the
506
+ 128 + signal exit code instead (see the end of main()). */
507
+ if (IsWindows()) {
508
+ return;
509
+ }
510
+ #endif
511
+
512
+ DEBUG("Terminating with signal %d like the application", sig);
513
+ fflush(NULL);
514
+
515
+ /* The application dumped core already if it was going to. */
516
+ struct rlimit no_core = { 0, 0 };
517
+ setrlimit(RLIMIT_CORE, &no_core);
518
+
519
+ struct sigaction sa;
520
+ memset(&sa, 0, sizeof(sa));
521
+ sa.sa_handler = SIG_DFL;
522
+ sigemptyset(&sa.sa_mask);
523
+ sigaction(sig, &sa, NULL);
524
+
525
+ sigset_t set;
526
+ sigemptyset(&set);
527
+ sigaddset(&set, sig);
528
+ sigprocmask(SIG_UNBLOCK, &set, NULL);
529
+
530
+ raise(sig);
531
+
532
+ /* Still alive: e.g. PID 1 of a container, for which the kernel drops
533
+ signals whose action is the default. The caller exits with
534
+ 128 + signal instead. */
535
+ DEBUG("Signal %d did not terminate the stub", sig);
536
+ }
537
+
474
538
  bool SetEnvVar(const char *name, const char *value) {
475
539
  if (!name) {
476
540
  FATAL("SetEnvVar: name is NULL");
@@ -499,31 +563,60 @@ bool CreateAndWaitForProcess(const char *app_name, char *argv[], int *exit_code)
499
563
  return false;
500
564
  }
501
565
 
566
+ /* Hold termination signals until ChildPid is set, so that none arriving
567
+ around fork() gets lost. */
568
+ sigset_t term_set, orig_mask;
569
+ sigemptyset(&term_set);
570
+ for (size_t i = 0; i < TERMINATION_SIGNAL_COUNT; i++) {
571
+ sigaddset(&term_set, TerminationSignals[i]);
572
+ }
573
+ sigprocmask(SIG_BLOCK, &term_set, &orig_mask);
574
+
575
+ /* Asked to terminate during extraction: do not start the application. */
576
+ if (ReceivedSignal) {
577
+ TerminatingSignal = ReceivedSignal;
578
+ *exit_code = 128 + TerminatingSignal;
579
+ DEBUG("Received signal %d before the application started", TerminatingSignal);
580
+ sigprocmask(SIG_SETMASK, &orig_mask, NULL);
581
+ return true;
582
+ }
583
+
502
584
  pid_t pid = fork();
503
585
  if (pid < 0) {
504
586
  FATAL("CreateAndWaitForProcess: fork() failed: %s", strerror(errno));
587
+ sigprocmask(SIG_SETMASK, &orig_mask, NULL);
505
588
  return false;
506
589
  }
507
590
 
508
591
  if (pid == 0) {
509
- /* Child process */
510
-
511
- /* Reset signal handlers to default before exec */
512
- signal(SIGINT, SIG_DFL);
513
- signal(SIGTERM, SIG_DFL);
592
+ /* Child process: restore the signal handling the stub was started
593
+ with, then execute the target application. */
594
+ for (size_t i = 0; i < TERMINATION_SIGNAL_COUNT; i++) {
595
+ signal(TerminationSignals[i],
596
+ SignalIgnoredAtStartup[i] ? SIG_IGN : SIG_DFL);
597
+ }
598
+ sigprocmask(SIG_SETMASK, &orig_mask, NULL);
514
599
 
515
- /* Execute the target application */
516
600
  execv(app_name, argv);
517
601
 
518
- /* If we get here, execv failed */
602
+ /* If we get here, execv failed. _exit, not exit: atexit handlers
603
+ and stdio buffers belong to the parent. */
519
604
  FATAL("CreateAndWaitForProcess: execv(\"%s\") failed: %s", app_name, strerror(errno));
520
- exit(127);
605
+ _exit(127);
521
606
  }
522
607
 
523
608
  /* Parent process */
609
+ ChildPid = pid;
610
+ sigprocmask(SIG_SETMASK, &orig_mask, NULL);
524
611
 
525
612
  int wstatus;
526
- if (waitpid(pid, &wstatus, 0) < 0) {
613
+ pid_t waited;
614
+ do {
615
+ waited = waitpid(pid, &wstatus, 0);
616
+ } while (waited < 0 && errno == EINTR);
617
+ ChildPid = 0;
618
+
619
+ if (waited < 0) {
527
620
  FATAL("CreateAndWaitForProcess: waitpid failed: %s", strerror(errno));
528
621
  return false;
529
622
  }
@@ -531,7 +624,9 @@ bool CreateAndWaitForProcess(const char *app_name, char *argv[], int *exit_code)
531
624
  if (WIFEXITED(wstatus)) {
532
625
  *exit_code = WEXITSTATUS(wstatus);
533
626
  } else if (WIFSIGNALED(wstatus)) {
534
- *exit_code = 128 + WTERMSIG(wstatus);
627
+ TerminatingSignal = WTERMSIG(wstatus);
628
+ *exit_code = 128 + TerminatingSignal;
629
+ DEBUG("The application was terminated by signal %d", TerminatingSignal);
535
630
  } else {
536
631
  *exit_code = 1;
537
632
  }
data/src/unpack.c CHANGED
@@ -224,6 +224,15 @@ static bool decompress_lzma(void *dest, unsigned long long dest_size,
224
224
  APP_ERROR("LZMA decompression error: %d, status: %d", res, status);
225
225
  return false;
226
226
  }
227
+
228
+ /* The end mark can come before the buffer is full: the rest of it would
229
+ then be parsed as opcodes although it holds nothing but whatever
230
+ malloc left there. */
231
+ if ((unsigned long long)decompressed_size != dest_size) {
232
+ APP_ERROR("LZMA decompressed size mismatch: header says %llu bytes, got %llu",
233
+ dest_size, (unsigned long long)decompressed_size);
234
+ return false;
235
+ }
227
236
  return true;
228
237
  }
229
238
 
metadata CHANGED
@@ -1,7 +1,7 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: ocran
3
3
  version: !ruby/object:Gem::Version
4
- version: 1.4.6
4
+ version: 1.5.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - Andi Idogawa
@@ -30,10 +30,10 @@ description: 'OCRAN (One-Click Ruby Application Next) packages Ruby applications
30
30
  gems, and native libraries into a self-contained artifact that runs without Ruby
31
31
  installed on the target machine: a self-extracting executable (default), a directory
32
32
  (--output-dir), a zip archive (--output-zip), or a macOS .app bundle (--macosx-bundle).
33
- Fork of OCRA maintained for Ruby 3.2+; migrating code should replace OCRA_EXECUTABLE
33
+ Fork of OCRA maintained for Ruby 3.3+; migrating code should replace OCRA_EXECUTABLE
34
34
  with OCRAN_EXECUTABLE.'
35
35
  email:
36
- - andi@idogawa.com
36
+ - web@idogawa.com
37
37
  executables:
38
38
  - ocran
39
39
  extensions:
@@ -46,14 +46,18 @@ files:
46
46
  - exe/ocran
47
47
  - ext/extconf.rb
48
48
  - lib/ocran.rb
49
+ - lib/ocran/aot_toolchain.rb
49
50
  - lib/ocran/build_constants.rb
50
51
  - lib/ocran/build_facade.rb
51
52
  - lib/ocran/build_helper.rb
52
53
  - lib/ocran/command_output.rb
54
+ - lib/ocran/compatibility_scan.rb
53
55
  - lib/ocran/cosmo_toolchain.rb
54
56
  - lib/ocran/dir_builder.rb
55
57
  - lib/ocran/direction.rb
56
58
  - lib/ocran/ed_icon.rb
59
+ - lib/ocran/ed_resource.rb
60
+ - lib/ocran/ed_resource_builder.rb
57
61
  - lib/ocran/empty_source
58
62
  - lib/ocran/file_path_set.rb
59
63
  - lib/ocran/gem_spec_queryable.rb
@@ -63,18 +67,31 @@ files:
63
67
  - lib/ocran/launcher_event_recorder.rb
64
68
  - lib/ocran/library_detector.rb
65
69
  - lib/ocran/library_detector_posix.rb
70
+ - lib/ocran/npm_package.rb
66
71
  - lib/ocran/option.rb
72
+ - lib/ocran/pe_imports.rb
73
+ - lib/ocran/pe_resources.rb
67
74
  - lib/ocran/refine_pathname.rb
75
+ - lib/ocran/roundhouse_builder.rb
68
76
  - lib/ocran/rubyopt_processor.rb
69
77
  - lib/ocran/runner.rb
70
78
  - lib/ocran/runtime_environment.rb
79
+ - lib/ocran/runtime_sdk.rb
80
+ - lib/ocran/spinel_builder.rb
81
+ - lib/ocran/spinel_compatibility.rb
82
+ - lib/ocran/static_runtime/boot.rb
83
+ - lib/ocran/static_runtime/build_static_ext.rb
84
+ - lib/ocran/static_runtime_builder.rb
71
85
  - lib/ocran/stub_builder.rb
72
86
  - lib/ocran/version.rb
87
+ - lib/ocran/wasm_builder.rb
88
+ - lib/ocran/wasm_compatibility.rb
73
89
  - lib/ocran/windows_command_escaping.rb
74
90
  - lib/ocran/zip_payload_builder.rb
75
91
  - lib/ocran/zip_writer.rb
76
92
  - share/ocran/lzma.exe
77
93
  - src/Makefile
94
+ - src/Makefile.mswin
78
95
  - src/error.c
79
96
  - src/error.h
80
97
  - src/inst_dir.c
@@ -84,6 +101,7 @@ files:
84
101
  - src/lzma/LzmaDec.c
85
102
  - src/lzma/LzmaDec.h
86
103
  - src/lzma/Precomp.h
104
+ - src/path_utils.c
87
105
  - src/script_info.c
88
106
  - src/script_info.h
89
107
  - src/stub.c
@@ -109,7 +127,7 @@ required_ruby_version: !ruby/object:Gem::Requirement
109
127
  requirements:
110
128
  - - ">="
111
129
  - !ruby/object:Gem::Version
112
- version: 3.2.0
130
+ version: 3.3.0
113
131
  required_rubygems_version: !ruby/object:Gem::Requirement
114
132
  requirements:
115
133
  - - ">="