--- a/lib/Protobuf-PHP/library/DrSlump/Protobuf/Compiler.php +++ b/lib/Protobuf-PHP/library/DrSlump/Protobuf/Compiler.php @@ -1,1 +1,212 @@ - +verbose = $verbose; + $this->comments = new Compiler\CommentsParser(); + } + + public function stderr($str) + { + $str = str_replace("\n", PHP_EOL, $str); + fputs(STDERR, $str . PHP_EOL); + } + + public function notice($str) + { + if ($this->verbose) { + $this->stderr('NOTICE: ' . $str); + } + } + + public function warning($str) + { + $this->stderr('WARNING: ' . $str); + } + + protected function error($str) + { + $this->stderr('ERROR: ' . $str); + } + + public function getPackages() + { + return $this->packages; + } + + public function hasPackage($package) + { + return isset($this->packages[$package]); + } + + public function getPackage($package) + { + return $this->packages[$package]; + } + + public function setPackage($package, $namespace) + { + $this->packages[$package] = $namespace; + } + + public function getOption($option, $type = 'string') + { + $value = isset($this->options[$option]) + ? $this->options[$option] + : null; + + switch ($type) { + case 'bool': + return filter_var($value, FILTER_VALIDATE_BOOLEAN); + default: + return $value; + } + } + + public function camelize($name) + { + return preg_replace_callback( + '/_([a-z])/i', + function($m){ return strtoupper($m[1]); }, + $name + ); + } + + public function compile($data) + { + // Parse the request + $req = new \google\protobuf\compiler\CodeGeneratorRequest($data); + + // Set default generator class + $generator = __CLASS__ . '\PhpGenerator'; + + // Reset comments parser + $this->comments->reset(); + $parseComments = false; + + // Get plugin arguments + if ($req->hasParameter()) { + parse_str($req->getParameter(), $args); + foreach ($args as $arg=>$val) { + switch($arg){ + case 'verbose': + $this->verbose = filter_var($val, FILTER_VALIDATE_BOOLEAN, FILTER_NULL_ON_FAILURE); + break; + case 'json': + $this->notice("Using ProtoJson generator"); + $generator = __CLASS__ . '\JsonGenerator'; + break; + case 'comments': + $parseComments = filter_var($val, FILTER_VALIDATE_BOOLEAN); + break; + case 'protos': + $this->protos = $val; + break; + case 'skip-imported': + $this->skipImported = filter_var($val, FILTER_VALIDATE_BOOLEAN); + break; + case 'options': + $this->options = $val; + break; + default: + $this->warning('Skipping unknown option ' . $arg); + } + } + } + + // Parse comments if we're told to do so + if ($parseComments) { + if (empty($this->protos)) { + throw new \RuntimeException('Unable to port comments if .proto files are not passed as argument'); + } + foreach ($this->protos as $fname) { + $src = file_get_contents($fname); + if (FALSE === $src) { + throw new \RuntimeException('Unable to parse file ' . $fname . ' for comments'); + } + $this->comments->parse($src); + } + } + + /** @var $generator \DrSlump\Protobuf\Compiler\AbstractGenerator */ + $generator = new $generator($this); + + // Setup response object + $resp = new \google\protobuf\compiler\CodeGeneratorResponse(); + + // First iterate over all the protos to get a map of namespaces + $this->packages = array(); + foreach($req->getProtoFileList() as $proto) { + $package = $proto->getPackage(); + $namespace = $generator->getNamespace($proto); + if (isset($this->packages[$package]) && $namespace !== $this->packages[$package]) { + $this->warning("Package $package was already mapped to {$this->packages[$package]} but has now been overridden to $namespace"); + } + $this->packages[$package] = $namespace; + $this->notice("Mapping $package to $namespace"); + } + + // Get the list of files to generate + $files = $req->getFileToGenerate(); + + // Run each file + foreach ($req->getProtoFileList() as $file) { + // Only compile those given to generate, not the imported ones + if ($this->skipImported && !in_array($file->getName(), $files)) { + $this->notice('Skipping generation of imported file "' . $file->getName() . '"'); + continue; + } + + $sources = $generator->generate($file); + foreach ($sources as $source) { + $this->notice('Generating "' . $source->getName() . '"'); + $resp->addFile($source); + } + } + + // Finally serialize the response object + return $resp->serialize(); + } + + public function getComment($ident, $prefix = '') + { + if (!$this->comments->hasComment($ident)) { + return null; + } + + $comment = $this->comments->getComment($ident); + if (0 < strlen($prefix)) { + $comment = $prefix . str_replace("\n", "\n$prefix", $comment); + } + + return $comment; + } +} + +