--- a/lib/Protobuf-PHP/library/DrSlump/Protobuf/Compiler/Cli.php +++ b/lib/Protobuf-PHP/library/DrSlump/Protobuf/Compiler/Cli.php @@ -1,1 +1,238 @@ - +compile($stdin); + exit(0); + } catch(\Exception $e) { + fputs(STDERR, 'ERROR: ' . $e->getMessage()); + fputs(STDERR, $e->getTraceAsString()); + exit(255); + } + } + + public static function runProtoc($pluginExecutable) + { + $result = self::parseArguments(); + + $protocBin = $result->options['protoc']; + + // Check if protoc is available + exec("$protocBin --version", $output, $return); + + if (0 !== $return && 1 !== $return) { + fputs(STDERR, "ERROR: Unable to find the protoc command.". PHP_EOL); + fputs(STDERR, " Please make sure it's installed and available in the path." . PHP_EOL); + exit(1); + } + + if (!preg_match('/[0-9\.]+/', $output[0], $m)) { + fputs(STDERR, "ERROR: Unable to get protoc command version.". PHP_EOL); + fputs(STDERR, " Please make sure it's installed and available in the path." . PHP_EOL); + exit(1); + } + + if (version_compare($m[0], '2.3.0') < 0) { + fputs(STDERR, "ERROR: The protoc command in your system is too old." . PHP_EOL); + fputs(STDERR, " Minimum version required is 2.3.0 but found {$m[0]}." . PHP_EOL); + exit(1); + } + + $cmd[] = $protocBin; + $cmd[] = '--plugin=protoc-gen-php=' . escapeshellarg($pluginExecutable); + + // Include paths + $cmd[] = '--proto_path=' . escapeshellarg(__DIR__ . DIRECTORY_SEPARATOR . 'protos'); + if (!empty($result->options['include'])) { + foreach($result->options['include'] as $include) { + $include = realpath($include); + $cmd[] = '--proto_path=' . escapeshellarg($include); + } + } + + // Convert proto files to absolute paths + $protos = array(); + foreach ($result->args['protos'] as $proto) { + $realpath = realpath($proto); + if (FALSE === $realpath) { + fputs(STDERR, "ERROR: File '$proto' does not exists"); + exit(1); + } + + $protos[] = $realpath; + } + + // Protoc will pass custom arguments to the plugin if they are given + // before a colon character. ie: --php_out="foo=bar:/path/to/plugin" + // We make use of it to pass arguments encoded as an URI query string + + $args = array(); + if ($result->options['comments']) { + $args['comments'] = 1; + // Protos are only needed for comments right now + $args['protos'] = $protos; + } + if ($result->options['verbose']) { + $args['verbose'] = 1; + } + if ($result->options['json']) { + $args['json'] = 1; + } + if ($result->options['skipImported']) { + $args['skip-imported'] = 1; + } + if ($result->options['define']) { + $args['options'] = array(); + foreach($result->options['define'] as $define) { + $parts = explode('=', $define); + $parts = array_filter(array_map('trim', $parts)); + if (count($parts) === 1) { + $parts[1] = 1; + } + $args['options'][$parts[0]] = $parts[1]; + } + } + + $cmd[] = '--php_out=' . + escapeshellarg( + http_build_query($args, '', '&') . + ':' . + $result->options['out'] + ); + + // Add the chosen proto files to generate + foreach ($protos as $proto) { + $cmd[] = escapeshellarg($proto); + } + + $cmdStr = implode(' ', $cmd); + + // Run command with stderr redirected to stdout + passthru($cmdStr . ' 2>&1', $return); + + if ($return !== 0) { + fputs(STDERR, PHP_EOL); + fputs(STDERR, 'ERROR: protoc exited with an error (' . $return . ') when executed with: ' . PHP_EOL); + fputs(STDERR, ' ' . implode(" \\\n ", $cmd) . PHP_EOL); + exit($return); + } + } + + + public static function parseArguments() + { + $main = new \Console_CommandLine(); + + $main->addOption('out', array( + 'short_name' => '-o', + 'long_name' => '--out', + 'action' => 'StoreString', + 'description' => 'destination directory for generated files', + 'default' => './', + )); + + $main->addOption('include', array( + 'short_name' => '-i', + 'long_name' => '--include', + 'action' => 'StoreArray', + 'description' => 'define an include path (can be repeated)', + 'multiple' => true, + )); + + + $main->addOption('json', array( + 'short_name' => '-j', + 'long_name' => '--json', + 'action' => 'StoreTrue', + 'description' => 'turn on ProtoJson Javascript file generation', + )); + + $main->addOption('protoc', array( + 'long_name' => '--protoc', + 'action' => 'StoreString', + 'default' => 'protoc', + 'description' => 'protoc compiler executable path', + )); + + $main->addOption('skipImported', array( + 'long_name' => '--skip-imported', + 'action' => 'StoreTrue', + 'default' => false, + 'description' => 'do not generate imported proto files', + )); + + $main->addOption('comments', array( + 'long_name' => '--comments', + 'action' => 'StoreTrue', + 'description' => 'port .proto comments to generated code', + )); + + $main->addOption('define', array( + 'short_name' => '-D', + 'long_name' => '--define', + 'action' => 'StoreArray', + 'multiple' => true, + 'description' => 'define a generator option (ie: -Dmultifile -Dsuffix=pb.php)', + )); + + $main->addOption('verbose', array( + 'short_name' => '-v', + 'long_name' => '--verbose', + 'action' => 'StoreTrue', + 'description' => 'turn on verbose output', + )); + + + $main->addArgument('protos', array( + 'multiple' => true, + 'description' => 'proto files', + )); + + try { + echo 'Protobuf-PHP ' . Protobuf::VERSION . ' by Ivan -DrSlump- Montes' . PHP_EOL . PHP_EOL; + $result = $main->parse(); + return $result; + } catch (\Exception $e) { + $main->displayError($e->getMessage()); + exit(1); + } + } + +} +