diff options
Diffstat (limited to 'tools')
| -rw-r--r-- | tools/benchmark.php | 52 | ||||
| -rwxr-xr-x | tools/i18n_compile.php | 44 | ||||
| -rwxr-xr-x | tools/i18n_extract.php | 47 | ||||
| -rw-r--r-- | tools/inc/cli.php | 100 | ||||
| -rw-r--r-- | tools/inc/lib/jsgettext/JSParser.php | 94 | ||||
| -rw-r--r-- | tools/inc/lib/jsgettext/PoeditParser.php | 83 | ||||
| -rw-r--r-- | tools/inc/lib/jsgettext/PoeditString.php | 29 | ||||
| -rw-r--r-- | tools/inc/lib/jsgettext/jsgettext.php | 63 | ||||
| -rw-r--r-- | tools/inc/lib/jsgettext/po2json.php | 42 | ||||
| -rwxr-xr-x | tools/rebuild.php | 105 |
10 files changed, 659 insertions, 0 deletions
diff --git a/tools/benchmark.php b/tools/benchmark.php new file mode 100644 index 00000000..8c97364c --- /dev/null +++ b/tools/benchmark.php @@ -0,0 +1,52 @@ +#!/usr/bin/php +<?php +/* + * benchmark.php - benchmarks thumbnailing methods + * + */ + +require dirname(__FILE__) . '/inc/cli.php'; +require 'inc/image.php'; + +// move back to this directory +chdir(dirname(__FILE__)); + +if(count($argv) != 2) + die("Usage: {$argv[0]} [file]\n"); + +$file = $argv[1]; +$extension = strtolower(substr($file, strrpos($file, '.') + 1)); +$out = tempnam($config['tmp'], 'thumb'); +$count = 300; + +function benchmark($method) { + global $config, $file, $extension, $out, $count; + + $config['thumb_method'] = $method; + + printf("Method: %s\nThumbnailing %d times... ", $method, $count); + + $start = microtime(true); + for($i = 0; $i < $count; $i++) { + $image = new Image($file, $extension); + $thumb = $image->resize( + $config['thumb_ext'] ? $config['thumb_ext'] : $extension, + $config['thumb_width'], + $config['thumb_height'] + ); + + $thumb->to($out); + $thumb->_destroy(); + $image->destroy(); + } + $end = microtime(true); + + printf("Took %.2f seconds (%.2f/second; %.2f ms)\n", $end - $start, $rate = ($count / ($end - $start)), 1000 / $rate); + + unlink($out); +} + +benchmark('gd'); +benchmark('imagick'); +benchmark('convert'); + diff --git a/tools/i18n_compile.php b/tools/i18n_compile.php new file mode 100755 index 00000000..ba193767 --- /dev/null +++ b/tools/i18n_compile.php @@ -0,0 +1,44 @@ +#!/usr/bin/php +<?php + +/* + * i18n_compile.php - compiles the i18n + * + * Options: + * -l [locale], --locale=[locale] + * Compiles [locale] locale. + * + */ + +require dirname(__FILE__) . '/inc/cli.php'; + +// parse command line +$opts = getopt('l:', Array('locale:')); +$options = Array(); + +$options['locale'] = isset($opts['l']) ? $opts['l'] : (isset($opts['locale']) ? $opts['locale'] : false); + +if ($options['locale']) $locales = array($options['locale']); +else die("Error: no locales specified; use -l switch, eg. -l pl_PL\n"); + +foreach ($locales as $loc) { + if (file_exists ($locdir = "inc/locale/".$loc)) { + if (!is_dir ($locdir)) { + continue; + } + } + else { + die("Error: $locdir does not exist\n"); + } + + // Generate tinyboard.po + if (file_exists($locdir."/LC_MESSAGES/tinyboard.po")) $join = "-j"; + else $join = ""; + passthru("cd $locdir/LC_MESSAGES; + msgfmt tinyboard.po -o tinyboard.mo"); + + // Generate javascript.po + passthru("cd tools/inc/lib/jsgettext/; + php po2json.php -i ../../../../$locdir/LC_MESSAGES/javascript.po \ + -o ../../../../$locdir/LC_MESSAGES/javascript.js"); +} diff --git a/tools/i18n_extract.php b/tools/i18n_extract.php new file mode 100755 index 00000000..33650b50 --- /dev/null +++ b/tools/i18n_extract.php @@ -0,0 +1,47 @@ +#!/usr/bin/php +<?php + +/* + * i18n_extract.php - extracts the strings and updates all locales + * + * Options: + * -l [locale], --locale=[locale] + * Updates only [locale] locale. If it does not exist yet, we create a new directory. + * + */ + +require dirname(__FILE__) . '/inc/cli.php'; + +// parse command line +$opts = getopt('l:', Array('locale:')); +$options = Array(); + +$options['locale'] = isset($opts['l']) ? $opts['l'] : (isset($opts['locale']) ? $opts['locale'] : false); + +$locales = glob("inc/locale/*"); +$locales = array_map("basename", $locales); + +if ($options['locale']) $locales = array($options['locale']); + + +foreach ($locales as $loc) { + if (file_exists ($locdir = "inc/locale/".$loc)) { + if (!is_dir ($locdir)) { + continue; + } + } + else { + mkdir($locdir); + mkdir($locdir."/LC_MESSAGES"); + } + + // Generate tinyboard.po + if (file_exists($locdir."/LC_MESSAGES/tinyboard.po")) $join = "-j"; + else $join = ""; + passthru("cd $locdir/LC_MESSAGES; + xgettext -d tinyboard -L php --from-code utf-8 $join -c $(find ../../../../ -name \*.php)"); + + // Generate javascript.po + passthru("cd $locdir/LC_MESSAGES; + xgettext -d javascript -L Python --force-po --from-code utf-8 $join -c $(find ../../../../js/ -name \*.js)"); +} diff --git a/tools/inc/cli.php b/tools/inc/cli.php new file mode 100644 index 00000000..294609cd --- /dev/null +++ b/tools/inc/cli.php @@ -0,0 +1,100 @@ +<?php + +/* + * This script will look for Tinyboard in the following places (in order): + * - $TINYBOARD_PATH environment varaible + * - ./ + * - ./Tinyboard/ + * - ../ + */ + +set_time_limit(0); +$shell_path = getcwd(); + +if(getenv('TINYBOARD_PATH') !== false) + $dir = getenv('TINYBOARD_PATH'); +elseif(file_exists('inc/functions.php')) + $dir = false; +elseif(file_exists('Tinyboard') && is_dir('Tinyboard') && file_exists('Tinyboard/inc/functions.php')) + $dir = 'Tinyboard'; +elseif(file_exists('../inc/functions.php')) + $dir = '..'; +else + die("Could not locate Tinyboard directory!\n"); + +if($dir && !chdir($dir)) + die("Could not change directory to {$dir}\n"); + +if(!getenv('TINYBOARD_PATH')) { + // follow symlink + chdir(realpath('inc') . '/..'); +} + +putenv('TINYBOARD_PATH=' . getcwd()); + +require 'inc/functions.php'; +require 'inc/mod.php'; + +$mod = Array( + 'id' => -1, + 'type' => ADMIN, + 'username' => '?', + 'boards' => Array('*') +); + +function get_httpd_privileges() { + global $config, $shell_path, $argv; + + if(php_sapi_name() != 'cli') + die("get_httpd_privileges(): invoked from HTTP client.\n"); + + echo "Dropping priviledges...\n"; + + if(!is_writable('.')) + die("get_httpd_privileges(): web directory is not writable\n"); + + $filename = '.' . md5(rand()) . '.php'; + $inc_filename = '.' . md5(rand()) . '.php'; + + echo "Copying rebuilder to web directory...\n"; + + // replace "/inc/cli.php" with its new filename + passthru("cat " . escapeshellarg($shell_path . '/' . $_SERVER['PHP_SELF']) . " | sed \"s/'\/inc\/cli\.php'/'\/{$inc_filename}'/\" > {$filename}"); + + $inc_header = "<?php\n"; + + // copy environment + $env = explode("\n", shell_exec('printenv | grep ^TINYBOARD')); + foreach($env as $line) { + if(!empty($line)) + $inc_header .= "putenv('" . addslashes($line) . "');\n"; + } + + // copy command line arguments + $inc_header .= "\$argv = " . var_export($argv, true) . ";\n"; + + // copy this file + file_put_contents($inc_filename, $inc_header . substr($inc = file_get_contents(__FILE__), strpos($inc, "\n"))); + + chmod($filename, 0666); + chmod($inc_filename, 0666); + + if(preg_match('/^https?:\/\//', $config['root'])) { + $url = $config['root'] . $filename; + } elseif($host = getenv('TINYBOARD_HOST')) { + $url = 'http://' . $host . $config['root'] . $filename; + } else { + // assume localhost + $url = 'http://localhost' . $config['root'] . $filename; + } + + echo "Downloading $url\n"; + + passthru('curl -s -N ' . escapeshellarg($url)); + + unlink($filename); + unlink($inc_filename); + + exit(0); +} + diff --git a/tools/inc/lib/jsgettext/JSParser.php b/tools/inc/lib/jsgettext/JSParser.php new file mode 100644 index 00000000..adba59bc --- /dev/null +++ b/tools/inc/lib/jsgettext/JSParser.php @@ -0,0 +1,94 @@ +<?php + +class JSParser { + + protected $content; + protected $keywords; + protected $regs = array(); + protected $regsCounter = 0; + protected $strings = array(); + protected $stringsCounter = 0; + + protected function _extractRegs($match) { + $this->regs[$this->regsCounter] = $match[1]; + $id = "<<reg{$this->regsCounter}>>"; + $this->regsCounter++; + return $id; + } + protected function _extractStrings($match) { + $this->strings[$this->stringsCounter] = $this->importRegExps($match[0]); + $id = "<<s{$this->stringsCounter}>>"; + $this->stringsCounter++; + return $id; + } + protected function importRegExps($input) { + $regs = $this->regs; + return preg_replace_callback("#<<reg(\d+)>>#", function ($match) use($regs) { + return $regs[$match[1]]; + }, $input); + } + + protected function importStrings($input) { + $strings = $this->strings; + return preg_replace_callback("#<<s(\d+)>>#", function ($match) use($strings) { + return $strings[$match[1]]; + }, $input); + } + + public function __construct($file, $keywords = '_') { + $this->content = file_get_contents($file); + $this->keywords = (array)$keywords; + } + + public function parse() { + $output = $this->content; //htmlspecialchars($this->content, ENT_NOQUOTES); + + // extract reg exps + $output = preg_replace_callback( + '# ( / (?: (?>[^/\\\\]++) | \\\\\\\\ | (?<!\\\\)\\\\(?!\\\\) | \\\\/ )+ (?<!\\\\)/ ) [a-z]* \b #ix', + array($this, '_extractRegs'), $output + ); + + // extract strings + $output = preg_replace_callback( + array( + '# " ( (?: (?>[^"\\\\]++) | \\\\\\\\ | (?<!\\\\)\\\\(?!\\\\) | \\\\" )* ) (?<!\\\\)" #ix', + "# ' ( (?: (?>[^'\\\\]++) | \\\\\\\\ | (?<!\\\\)\\\\(?!\\\\) | \\\\' )* ) (?<!\\\\)' #ix" + ), array($this, '_extractStrings'), $output + ); + + // delete line comments + $output = preg_replace("#(//.*?)$#m", '', $output); + + // delete multiline comments + $output = preg_replace('#/\*(.*?)\*/#is', '', $output); + + $strings = $this->strings; + $output = preg_replace_callback("#<<s(\d+)>>#", function($match) use($strings) { + return $strings[$match[1]]; + }, $output); + + $keywords = implode('|', $this->keywords); + + $strings = array(); + + // extract func calls + preg_match_all( + '# (?:'.$keywords.') \(\\ *" ( (?: (?>[^"\\\\]++) | \\\\\\\\ | (?<!\\\\)\\\\(?!\\\\) | \\\\" )* ) (?<!\\\\)"\\ *\) #ix', + $output, $matches, PREG_SET_ORDER + ); + + foreach ($matches as $m) $strings[] = stripslashes($m[1]); + + $matches = array(); + preg_match_all( + "# (?:$keywords) \(\\ *' ( (?: (?>[^'\\\\]++) | \\\\\\\\ | (?<!\\\\)\\\\(?!\\\\) | \\\\' )* ) (?<!\\\\)'\\ *\) #ix", + $output, $matches, PREG_SET_ORDER + ); + + foreach ($matches as $m) $strings[] = stripslashes($m[1]); + + return $strings; + } +} +?> diff --git a/tools/inc/lib/jsgettext/PoeditParser.php b/tools/inc/lib/jsgettext/PoeditParser.php new file mode 100644 index 00000000..eebd816e --- /dev/null +++ b/tools/inc/lib/jsgettext/PoeditParser.php @@ -0,0 +1,83 @@ +<?php + +require_once 'PoeditString.php'; + +class PoeditParser { + + protected $file; + protected $header = ''; + protected $strings = array(); + + protected function _fixQuotes($str) { + return stripslashes($str); + } + + public function __construct($file) { + $this->file = $file; + } + + public function parse() { + $contents = file_get_contents($this->file); + + $parts = preg_split('#(\r\n|\n){2}#', $contents, -1, PREG_SPLIT_NO_EMPTY); + + $this->header = array_shift($parts); + + foreach ($parts as $part) { + + // parse comments + $comments = array(); + preg_match_all('#^\\#: (.*?)$#m', $part, $matches, PREG_SET_ORDER); + foreach ($matches as $m) $comments[] = $m[1]; + + $isFuzzy = preg_match('#^\\#, fuzzy$#im', $part) ? true : false; + + preg_match_all('# ^ (msgid|msgstr)\ " ( (?: (?>[^"\\\\]++) | \\\\\\\\ | (?<!\\\\)\\\\(?!\\\\) | \\\\" )* ) (?<!\\\\)" $ #ixm', $part, $matches2, PREG_SET_ORDER); + + $k = $this->_fixQuotes($matches2[0][2]); + $v = !empty($matches2[1][2]) ? $this->_fixQuotes($matches2[1][2]) : ''; + + $this->strings[$k] = new PoeditString($k, $v, $isFuzzy, $comments); + } + } + + public function merge($strings) { + foreach ((array)$strings as $str) { + if (!in_array($str, array_keys($this->strings))) { + $this->strings[$str] = new PoeditString($str); + } + } + } + + public function getHeader() { + return $this->header; + } + + public function getStrings() { + return $this->strings; + } + + public function getJSON() { + $str = array(); + foreach ($this->strings as $s) { + if ($s->value) $str[$s->key] = $s->value; + } + return json_encode($str); + } + + public function toJSON($outputFilename, $varName = 'l10n') { + $str = "$varName = " . $this->getJSON() . ";"; + return file_put_contents($outputFilename, $str) !== false; + } + + public function save($filename = null) { + $data = $this->header . "\n\n"; + foreach ($this->strings as $str) { + $data .= $str; + } + return file_put_contents($filename ? $filename : $this->file, $data) !== false; + } +} + + +?> diff --git a/tools/inc/lib/jsgettext/PoeditString.php b/tools/inc/lib/jsgettext/PoeditString.php new file mode 100644 index 00000000..3d59d004 --- /dev/null +++ b/tools/inc/lib/jsgettext/PoeditString.php @@ -0,0 +1,29 @@ +<?php + +class PoeditString { + public $key; + public $value; + public $fuzzy; + public $comments; + + function __construct($key, $value = '', $fuzzy = false, $comments = array()) { + $this->key = $key; + $this->value = $value; + $this->fuzzy = $fuzzy; + $this->comments = (array)$comments; + } + + public function __toString() { + $str =''; + foreach ($this->comments as $c) { + $str .= "#: $c\n"; + } + if ($this->fuzzy) $str .= "#, fuzzy\n"; + $str .= 'msgid "'.str_replace('"', '\\"', $this->key).'"' . "\n"; + $str .= 'msgstr "'.str_replace('"', '\\"', $this->value).'"' . "\n"; + $str .= "\n"; + return $str; + } +} + +?>
\ No newline at end of file diff --git a/tools/inc/lib/jsgettext/jsgettext.php b/tools/inc/lib/jsgettext/jsgettext.php new file mode 100644 index 00000000..6c70f0b4 --- /dev/null +++ b/tools/inc/lib/jsgettext/jsgettext.php @@ -0,0 +1,63 @@ +<?php + + require_once 'JSParser.php'; + require_once 'PoeditParser.php'; + + function buildOptions($args) { + $options = array( + 'files' => array(), + '-o' => null, + '-k' => '_' + ); + $len = count($args); + $i = 1; + while ($i < $len) { + if (preg_match('#^-[a-z]$#i', $args[$i])) { + $options[$args[$i]] = isset($args[$i+1]) ? trim($args[$i+1]) : true; + $i += 2; + } + else { + $options['files'][] = $args[$i]; + $i++; + } + } + return $options; + } + + $options = buildOptions($argv); + + if (!file_exists($options['-o'])) { + touch($options['-o']); + } + + if (!is_writable($options['-o'])) { + die("Invalid output file name. Make sure it exists and is writable."); + } + + $inputFiles = $options['files']; + + if (empty($inputFiles)) { + die("You did not provide any input file."); + } + + $poeditParser = new PoeditParser($options['-o']); + $poeditParser->parse(); + + $errors = array(); + + foreach ($inputFiles as $f) { + if (!is_readable($f) || !preg_match('#\.js$#', $f)) { + $errors[] = ("$f is not a valid javascript file."); + continue; + } + $jsparser = new JSParser($f, explode(' ', $options['-k'])); + $jsStrings = $jsparser->parse(); + $poeditParser->merge($jsStrings); + } + + if (!empty($errors)) { + echo "\nThe following errors occured:\n" . implode("\n", $errors) . "\n"; + } + + $poeditParser->save(); +?> diff --git a/tools/inc/lib/jsgettext/po2json.php b/tools/inc/lib/jsgettext/po2json.php new file mode 100644 index 00000000..847b0899 --- /dev/null +++ b/tools/inc/lib/jsgettext/po2json.php @@ -0,0 +1,42 @@ +<?php + + require_once 'PoeditParser.php'; + + function buildOptions($args) { + $options = array( + '-o' => null, + '-i' => null, + '-n' => 'l10n' + ); + $len = count($args); + $i = 0; + while ($i < $len) { + if (preg_match('#^-[a-z]$#i', $args[$i])) { + $options[$args[$i]] = isset($args[$i+1]) ? trim($args[$i+1]) : true; + $i += 2; + } + else { + $options[] = $args[$i]; + $i++; + } + } + return $options; + } + + $options = buildOptions($argv); + + if (!file_exists($options['-i']) || !is_readable($options['-i'])) { + die("Invalid input file. Make sure it exists and is readable."); + } + + $poeditParser = new PoeditParser($options['-i']); + $poeditParser->parse(); + + if ($poeditParser->toJSON($options['-o'], $options['-n'])) { + $strings = count($poeditParser->getStrings()); + echo "Successfully exported " . count($strings) . " strings.\n"; + } + else { + echo "Cannor write to file '{$options['-o']}'.\n"; + } +?> diff --git a/tools/rebuild.php b/tools/rebuild.php new file mode 100755 index 00000000..3b5c0de2 --- /dev/null +++ b/tools/rebuild.php @@ -0,0 +1,105 @@ +#!/usr/bin/php +<?php + +/* + * rebuild.php - rebuilds all static files + * + * Command line arguments: + * -q, --quiet + * Suppress output. + * + * --quick + * Do not rebuild posts. + * + * -b, --board <string> + * Rebuild only the specified board. + * + * -f, --full + * Rebuild replies as well as threads (re-markup). + * + */ + +require dirname(__FILE__) . '/inc/cli.php'; + +if(!is_writable($config['file_script'])) { + get_httpd_privileges(); +} + +$start = microtime(true); + +// parse command line +$opts = getopt('qfb:', Array('board:', 'quick', 'full', 'quiet')); +$options = Array(); + +$options['board'] = isset($opts['board']) ? $opts['board'] : (isset($opts['b']) ? $opts['b'] : false); +$options['quiet'] = isset($opts['q']) || isset($opts['quiet']); +$options['quick'] = isset($opts['quick']); +$options['full'] = isset($opts['full']) || isset($opts['f']); + +if(!$options['quiet']) + echo "== Tinyboard {$config['version']} ==\n"; + +if(!$options['quiet']) + echo "Clearing template cache...\n"; + +load_twig(); +$twig->clearCacheFiles(); + +if(!$options['quiet']) + echo "Regenerating theme files...\n"; +rebuildThemes('all'); + +if(!$options['quiet']) + echo "Generating Javascript file...\n"; +buildJavascript(); + +$main_js = $config['file_script']; + +$boards = listBoards(); + +foreach($boards as &$board) { + if($options['board'] && $board['uri'] != $options['board']) + continue; + + if(!$options['quiet']) + echo "Opening board /{$board['uri']}/...\n"; + openBoard($board['uri']); + + if($config['file_script'] != $main_js) { + // different javascript file + if(!$options['quiet']) + echo "Generating Javascript file...\n"; + buildJavascript(); + } + + + if(!$options['quiet']) + echo "Creating index pages...\n"; + buildIndex(); + + if($options['quick']) + continue; // do no more + + if($options['full']) { + $query = query(sprintf("SELECT `id` FROM `posts_%s`", $board['uri'])) or error(db_error()); + while($post = $query->fetch()) { + if(!$options['quiet']) + echo "Rebuilding #{$post['id']}...\n"; + rebuildPost($post['id']); + } + } + + $query = query(sprintf("SELECT `id` FROM `posts_%s` WHERE `thread` IS NULL", $board['uri'])) or error(db_error()); + while($post = $query->fetch()) { + if(!$options['quiet']) + echo "Rebuilding #{$post['id']}...\n"; + buildThread($post['id']); + } +} + +if(!$options['quiet']) + printf("Complete! Took %g seconds\n", microtime(true) - $start); + +unset($board); +modLog('Rebuilt everything using tools/rebuild.php'); + |
