bin/serve-stub
authorMichael Wallner <mike@php.net>
Fri, 28 Jan 2022 10:11:55 +0000 (11:11 +0100)
committerMichael Wallner <mike@php.net>
Fri, 28 Jan 2022 10:11:55 +0000 (11:11 +0100)
bin/ref2html
bin/serve-stub [new file with mode: 0755]
bin/stub2ref
mdref/Generator.php
mdref/Generator/Scrap.php

index 779a1d0d9048d2bf1df0c9ec120b31086eeef900..27326362932ce8498976c44da8525ac659309d03 100755 (executable)
@@ -18,9 +18,6 @@ if ($argc < 3) {
        fprintf(STDERR, "       Note: the basedir will also be used as <base href>\n");
        exit(1);
 }
-function say($fmt, ...$args) {
-       return fprintf(STDERR, $fmt, ...$args);
-};
 $out = $argv[1];
 if (!is_dir($out) && !mkdir($out, 0775, true)) {
        fprintf(STDERR, "Could not create output directory %s\n", $out);
@@ -63,7 +60,7 @@ $gen = function(Entry $entry) use($fmt, $out, $xfm, $red, &$gen) {
        $dst = $dir . ".html";
        foreach ($xfm as $from => $dest) {
                if (strpos($src, $dest) !== false) {
-                       say("Redirecting from %s to %s\n", $from, $dest);
+                       printf("Redirecting from %s to %s\n", $from, $dest);
                        $red($from, $dest, $src);
                        break;
                }
@@ -76,12 +73,12 @@ $gen = function(Entry $entry) use($fmt, $out, $xfm, $red, &$gen) {
                        $gen($subentry);
                }
        }
-       say("Generating %s from %s\n", $dst, $src);
+       printf("Generating %s from %s\n", $dst, $src);
        $fmt($src, $dst);
 };
 /** @var $repo Repo */
 foreach ($ref as $repo) {
-       say("Entering ref %s\n", $repo->getName());
+       printf("Entering ref %s\n", $repo->getName());
        if (is_file($stub = $repo->getPath($repo->getName().".stub.php"))) {
                copy($stub, $out . "/" . basename($stub));
        }
diff --git a/bin/serve-stub b/bin/serve-stub
new file mode 100755 (executable)
index 0000000..650d67c
--- /dev/null
@@ -0,0 +1,113 @@
+#!/usr/bin/env php
+<?php
+
+namespace mdref;
+
+require_once $_composer_autoload_path ?? __DIR__."/../vendor/autoload.php";
+
+if ($argc < 2) {
+       fprintf(STDERR, "Usage: %s <stub.php> [<ns>]\n", $argv[0]);
+       exit(1);
+}
+
+if (!($stub = realpath($argv[1]))) {
+       $stat = stat($stub);
+       assert(!$stat);
+       exit(2);
+}
+if ($argc > 2) {
+       $namespace = $argv[2];
+} else {
+       $namespace = basename($stub, ".stub.php");
+}
+
+$tmplck = tempnam(sys_get_temp_dir(), "mdref.");
+$tmpdir = $tmplck . ".d";
+mkdir($tmpdir) && chdir($tmpdir) || exit(-1);
+
+$running = true;
+$shutdown = function() use($tmpdir, $tmplck, &$running) {
+       $running = false;
+       chdir(__DIR__) && rm_r($tmpdir, $tmplck);
+};
+register_shutdown_function($shutdown);
+pcntl_signal(SIGINT, $shutdown, false);
+pcntl_signal(SIGTERM, $shutdown, false);
+
+$passthru = fn($cmd) => fn() => printf("%s\n", $cmd) && !passthru("$cmd 2>&1 >/dev/null", $rc) && !$rc;
+$stub2ref = $passthru(
+       sprintf("%s/stub2ref %s %s %s",
+                       __DIR__,
+                       escapeshellarg($namespace),
+                       escapeshellarg($stub),
+                       escapeshellarg($tmpdir)
+       )
+);
+$ref2html = $passthru(
+       sprintf("%s/ref2html . .",
+               __DIR__,
+       )
+);
+$update = fn() => $stub2ref() && $ref2html();
+
+if ($update()) {
+       $ifd = inotify_init();
+       inotify_add_watch($ifd, $stub, IN_MODIFY);
+       stream_set_blocking($ifd, false);
+
+       file_put_contents("router.php", file_get_contents(__FILE__, false, null, __COMPILER_HALT_OFFSET__));
+       $php = popen(sprintf("%s -S localhost:0 -t . router.php 2>&1 | grep --line-buffered -Ev 'Accepted|Closing|GET'", PHP_BINARY), "r");
+       echo fgets($php);
+       stream_set_blocking($php, false);
+
+       while ($running) {
+               $R = [$ifd, $php]; $W = []; $E = [];
+               if (stream_select($R, $W, $E, null)) {
+                       foreach ($R as $r) {
+                               switch ($r) {
+                                       case $php:
+                                               while (($string = fgets($php))) echo $string;
+                                               break;
+                                       case $ifd:
+                                               // cooldown
+                                               usleep(50 * 1000);
+                                               while (inotify_read($ifd));
+                                               $update();
+                                               break;
+                               }
+                       }
+               }
+               pcntl_signal_dispatch();
+       }
+}
+
+function rm_r(string ...$args) {
+       foreach ($args as $del) {
+               if (is_dir($del)) {
+                       rm_r(...array_map(fn($sub) => "$del/$sub", array_slice(scandir($del), 2)));
+                       rmdir($del);
+               } else if (file_exists($del)) {
+                       unlink($del);
+               }
+       }
+}
+
+__HALT_COMPILER();
+<?php
+
+$file = __DIR__ . urldecode($_SERVER["REQUEST_URI"]);
+
+if (is_file($file)) {
+       return false;
+}
+
+if (is_dir($file) && file_exists($file."/index.html")) {
+       readfile($file."/index.html");
+} else {
+       $file = rtrim($file, "/").".html";
+       if (file_exists($file)) {
+               readfile($file);
+       } else {
+               return false;
+       }
+}
index 78c7d1799b64b714399f7df48b2fefc84a9ac8ec..b1753dc9cbda3eaf2287f2b276f0d953844a2ac0 100755 (executable)
@@ -19,9 +19,19 @@ if (!is_dir($destination)) {
        mkdir($destination) || exit -1;
 }
 if (!file_exists("$destination/$namespace.mdref")) {
-       fprintf(STDERR, "Missing $destination/$namespace.mdref; generated default.\n");
+       fprintf(STDERR, "Missing $destination/$namespace.mdref; generating default.\n");
        file_put_contents("$destination/$namespace.mdref", "./%s") || exit -2;
 }
+if (!file_exists("$destination/$namespace.md")) {
+       fprintf(STDERR, "Missing $destination/$namespace.mdref; generating default from README.\n");
+       $readme = dirname($argv[2]) . "/README.md";
+       if (!file_exists($readme))  {
+               fprintf(STDERR, "Missing $readme; creating empty $namespace.md");
+               touch("$destination/$namespace.md");
+       } else {
+               link(realpath($readme), "$destination/$namespace.md");
+       }
+}
 
 $inspector = new Inspector;
 $inspector->inspectNamespace($namespace);
index 8cd96bd96215e0f54e4e61c865ac44a980c2f1a8..ec1a23e8fcb6ad9dc96f8ebc0bb533fca893da6a 100644 (file)
@@ -20,7 +20,7 @@ class Generator {
                        $ns_path = $this->destination . "/" . strtr($ns, "\\", "/");
                        foreach ($funcs as $fn => $rf) {
                                $fn_file = "$ns_path/$fn.md";
-                               fprintf(STDERR, "Generating %s\n", $fn_file);
+                               printf("Generating %s\n", $fn_file);
                                is_dir($ns_path) || mkdir($ns_path, 0770, true);
                                file_put_contents($fn_file, new Func($this, $rf));
                        }
@@ -37,7 +37,7 @@ class Generator {
                        foreach ($cls as $cn => $rc) {
                                $cn_path = "$ns_path/$cn";
                                $cn_file = "$cn_path.md";
-                               fprintf(STDERR, "Generating %s\n", $cn_file);
+                               printf("Generating %s\n", $cn_file);
                                is_dir($ns_path) || mkdir($ns_path, 0770, true);
                                file_put_contents($cn_file, new Cls($this, $rc));
                                $this->generateMethods($rc);
index 30b936be3da07bbcd7155a61e18a81ef83d24b8e..82f81dbbeca7e0c91152397014f41d1ec26d432d 100644 (file)
@@ -19,7 +19,7 @@ class Scrap {
                        $this->createDocBlock();
                }
                if (!$this->doc) {
-                       fprintf(STDERR, ... match (get_class($ref)) {
+                       printf(... match (get_class($ref)) {
                                \ReflectionClass::class => ["Missing docs for class %s\n", $ref->name],
                                \ReflectionMethod::class => ["Missing docs for method %s::%s()\n", $ref->class, $ref->name],
                                \ReflectionProperty::class => ["Missing docs for property %s %s::\$%s\n", $ref->getType(), $ref->class, $ref->name],