$argv): void { invariant(count($argv) >= 2, 'Need to specify path to www'); self::importHackLib($argv[1]); self::transpileHack(); } protected static function importHackLib(string $www_path): void { self::walkPHPFiles( $www_path.'/flib/thrift/core', array(''), function (string $root, string $path, string $file) { if (strpos($path, '__tests__') !== false) { echo "Skipping $path/$file\n"; return; } $contents = file_get_contents($root.$path.'/'.$file); $contents = preg_replace( '#/\* BEGIN_STRIP \*/.*?/\* END_STRIP \*/#s', '', $contents, ); $contents = preg_replace( '#/\* INSERT (.*?) END_INSERT \*/#s', '\\1', $contents, ); $license = array( '/**', '* Copyright (c) 2006- Facebook', '* Distributed under the Thrift Software License', '*', '* See accompanying file LICENSE or visit the Thrift site at:', '* http://developers.facebook.com/thrift/', '*', '* @package '.str_replace('/', '.',dirname('thrift'.$path.'/'.$file)), '*/', ); $replacement = "\\1\n".implode("\n", $license)."\n"; $contents = preg_replace( '#^(<\?hh(?: +// +[a-z]+)?\n)//.*\n#', $replacement, $contents, ); if (!file_exists(__DIR__.'/src/'.$path)) { mkdir(__DIR__.'/src/'.$path, 0755, true); } file_put_contents(__DIR__.'/src/'.$path.'/'.$file, $contents); echo "Imported $path/$file\n"; } ); } protected static function transpileHack(): void { $transpiler = realpath(__DIR__.'/../../../_bin/hphp/hack/src/h2tp/h2tp'); $source = realpath(__DIR__.'/src'); $dest = realpath(__DIR__.'/../php/src'); system('rm -rf '.$dest); system($transpiler.' '.$source.' '.$dest); file_put_contents($dest.'/Thrift.php', implode("\n", array( 'contains($path.'/'.$file)) { $classes[basename($file, '.php')] = $path.'/'.$file; } $contents = file_get_contents($root.$path.'/'.$file); $header = array( 'contains($path.'/'.$file)) { return; } $contents = file_get_contents($root.$path.'/'.$file); $includes = Vector {}; $skip_includes = ImmMap { 'TProtocol.php' => ImmSet { 'TBinaryProtocolAccelerated', 'TBinaryProtocolUnaccelerated', 'TCompactProtocolAccelerated', 'TCompactProtocolUnaccelerated', }, }; foreach ($classes as $class => $classpath) { if ($file === $class.'.php') { continue; } if ($skip_includes->containsKey($file)) { if ($skip_includes->at($file)->contains($class)) { continue; } } if (preg_match('/'.$class.'[^a-zA-Z]/', $contents)) { $includes[] = $classpath; } } if (!$includes->isEmpty()) { sort($includes); $hacklib = 'require_once ($GLOBALS["HACKLIB_ROOT"]);'; $thrift_root_path = '__DIR__'; $subdirs = substr_count($path, '/'); if ($subdirs > 0) { $thrift_root_path = '__DIR__.\''.str_repeat('/..', $subdirs).'\''; } $thrift_root = implode("\n", array( 'if (!isset($GLOBALS[\'THRIFT_ROOT\'])) {', ' $GLOBALS[\'THRIFT_ROOT\'] = '.$thrift_root_path.';', '}', )); $replacement = "$hacklib\n$thrift_root\n".implode("\n", $includes->map(function ($path): string { return 'require_once $GLOBALS[\'THRIFT_ROOT\'].\''.$path.'\';'; })); $contents = str_replace( $hacklib, $replacement, $contents, ); file_put_contents($root.$path.'/'.$file, $contents); echo "Added includes to $path/$file\n"; } } ); } protected static function walkPHPFiles( string $root, array $paths, (function (string, string, string): void) $cb, ): void { for ($i = 0; $i < count($paths); $i++) { $path = $paths[$i]; $full_path = $root.$path; $files = scandir($full_path); foreach ($files as $file) { if ($file === '.' || $file === '..') { continue; } if (is_dir($full_path.'/'.$file)) { $paths[] = $path.'/'.$file; } if (!preg_match('/\.php$/', $file)) { continue; } $cb($root, $path, $file); } } } } ImportThriftLibFromWWW::run($argv);