/** * Main method. * * @return int */ function main() { $prefix = SABRE_KATANA_PREFIX; $verbose = Console::isDirect(STDOUT); while (false !== ($c = $this->getOption($v))) { switch ($c) { case 'p': echo $prefix, "\n"; return 0; break; case 'v': echo Version::VERSION, "\n"; return 0; break; case 'V': $verbose = !$v; break; case '__ambiguous': $this->resolveOptionAmbiguity($v); break; case 'h': case '?': default: return $this->usage(); break; } } if (false === $verbose) { echo implode("\n", $this->commands); } Console\Cursor::colorize('foreground(yellow)'); echo static::LOGO; Console\Cursor::colorize('normal'); echo "\n\n", 'Just type:', "\n\n", ' $ katana <command> <options>', "\n\n", 'where <command> is:', "\n\n", ' * ', implode(',' . "\n" . ' * ', $this->commands), '.', "\n\n", '<options> always contains -h, -? and --help to get the usage ' . 'of the command.', "\n"; }
/** * The entry method. * * @return int */ public function main() { $exists = true; $unfold = false; $tree = false; $verbose = Console::isDirect(STDOUT); while (false !== ($c = $this->getOption($v))) { switch ($c) { case 'E': $exists = false; break; case 'u': $unfold = true; break; case 't': $tree = true; break; case 'V': $verbose = false; break; case 'h': case '?': return $this->usage(); case '__ambiguous': $this->resolveOptionAmbiguity($v); break; } } $this->parser->listInputs($path); if (null === $path) { return $this->usage(); } if (true === $tree) { $protocol = Core::getProtocol(); $foo = substr($path, 0, 6); if ('hoa://' !== $foo) { return; } $path = substr($path, 6); $current = $protocol; foreach (explode('/', $path) as $component) { if (!isset($current[$component])) { break; } $current = $current[$component]; } echo $current; return; } if (true === $verbose) { echo Console\Chrome\Text::colorize($path, 'foreground(yellow)'), ' is equivalent to:', "\n"; } $resolved = resolve($path, $exists, $unfold); foreach ((array) $resolved as $r) { echo $r, "\n"; } return; }
/** * The entry method. * * @return int */ public function main() { $verbose = Console::isDirect(STDOUT); $print = 'both'; while (false !== ($c = $this->getOption($v))) { switch ($c) { case 'V': $verbose = false; break; case 'l': $print = 'library'; break; case 'v': $print = 'version'; break; case 'h': case '?': return $this->usage(); case '__ambiguous': $this->resolveOptionAmbiguity($v); break; } } $this->parser->listInputs($library); if (empty($library)) { return $this->usage(); } $library = ucfirst(strtolower($library)); $path = 'hoa://Library/' . $library . '/composer.json'; if (true === $verbose) { echo 'Dependency for the library ', $library, ':', "\n"; } if (false === file_exists($path)) { throw new Console\Exception('Not yet computed or the %s library does not exist.', 0, $library); } $json = json_decode(file_get_contents($path), true); if (true === $verbose) { $item = ' • '; $separator = ' => '; } else { $item = ''; $separator = ' '; } foreach ($json['require'] ?: [] as $dependency => $version) { switch ($print) { case 'both': echo $item, $dependency, $separator, $version, "\n"; break; case 'library': echo $item, $dependency, "\n"; break; case 'version': echo $item, $version, "\n"; break; } } return; }
/** * The entry method. * * @access public * @return int */ public function main() { $tput = \Hoa\Console::getTput(); while (false !== ($c = $this->getOption($v))) { switch ($c) { case 't': echo $tput->getTerm(); return; case 'f': echo $tput->getTerminfo(); return; case 'H': echo $tput->has($v) ? 1 : 0; return; case 'c': echo $tput->count($v); return; case 'g': echo $tput->get($v); return; case 'b': $informations = $tput->getInformations(); static::format($informations['booleans']); return; case 'n': $informations = $tput->getInformations(); static::format($informations['numbers']); return; case 's': $informations = $tput->getInformations(); static::format($informations['strings']); return; case '__ambiguous': $this->resolveOptionAmbiguity($v); break; case 'h': case '?': default: return $this->usage(); break; } } return $this->usage(); }
/** * The entry method. * * @return int */ public function main() { $library = null; $verbose = Console::isDirect(STDOUT); while (false !== ($c = $this->getOption($v))) { switch ($c) { case 'l': $library = $this->parser->parseSpecialValue($v); break; case 'V': $verbose = false; break; case 'h': case '?': return $this->usage(); case '__ambiguous': $this->resolveOptionAmbiguity($v); break; } } if (true === $verbose) { echo Console\Chrome\Text::colorize(' _ _' . "\n" . ' | | | | ___ __ _' . "\n" . ' | |_| |/ _ \\ / _` |' . "\n" . ' | _ | (_) | (_| |' . "\n" . ' |_| |_|\\___/ \\__,_|' . "\n", 'foreground(yellow)'), "\n\n", 'Welcome in the command-line interface of Hoa :-).', "\n\n", Console\Chrome\Text::colorize('List of available commands', 'foreground(green)'), "\n\n"; } if (null !== $library) { $library = array_map('mb_strtolower', $library); } $locations = resolve('hoa://Library', true, true); $iterator = new \AppendIterator(); foreach ($locations as $location) { $iterator->append(new \GlobIterator($location . DS . '*' . DS . 'Bin' . DS . '*.php')); } if (WITH_COMPOSER) { $iterator->append(new \GlobIterator(dirname(dirname(dirname(dirname(__DIR__)))) . DS . 'Bin' . DS . '*.php')); } $binaries = []; foreach ($iterator as $entry) { $pathname = $entry->getPathname(); $lib = mb_strtolower(basename(dirname(dirname($pathname)))); $bin = mb_strtolower(mb_substr($entry->getBasename(), 0, -4)); if (null !== $library && false === in_array($lib, $library)) { continue; } if ('core' === $lib && 'hoa' === $bin) { continue; } if (!isset($binaries[$lib])) { $binaries[$lib] = []; } $description = ''; if (true === $verbose) { $lines = file($pathname); // Berk… for ($i = count($lines) - 1; $i >= 0; --$i) { if ('__halt_compiler();' . "\n" === $lines[$i]) { $description = trim(implode('', array_slice($lines, $i + 1))); break; } } unset($lines); } $binaries[$lib][] = ['name' => $bin, 'description' => $description]; } if (true === $verbose) { $out = []; foreach ($binaries as $group => $commands) { $out[] = [mb_convert_case($group, MB_CASE_TITLE)]; foreach ($commands as $binary) { $out[] = [' ' . Console\Chrome\Text::colorize($binary['name'], 'foreground(blue)'), $binary['description']]; } } echo Console\Chrome\Text::columnize($out); } else { $out = null; foreach ($binaries as $group => $commands) { foreach ($commands as $binary) { $out .= $group . ':' . $binary['name'] . "\n"; } } echo $out; } return; }
/** * Main method. * * @return int */ function main() { $verbose = !(Console::isDirect(STDOUT) || !OS_WIN); while (false !== ($c = $this->getOption($v))) { switch ($c) { case '__ambiguous': $this->resolveOptionAmbiguity($v); break; case 'v': $verbose = $v; break; case 'h': case '?': default: return $this->usage(); } } if (true === Installer::isInstalled()) { echo 'The application is already installed.', "\n"; return 1; } $oldTitle = Window::getTitle(); Window::setTitle('Installation of sabre/katana'); $form = ['baseUrl' => '/', 'email' => null, 'password' => null, 'database' => ['driver' => 'sqlite', 'host' => '', 'port' => '', 'name' => '', 'username' => '', 'password' => '']]; $readline = new Console\Readline(); if (true === $verbose) { $windowWidth = Window::getSize()['x']; $labelMaxWidth = 35; $inputMaxWidth = $windowWidth - $labelMaxWidth; $numberOfSteps = 5; $input = function ($default = '') use($inputMaxWidth) { return Text::colorize($default . str_repeat(' ', $inputMaxWidth - mb_strlen($default)), 'foreground(black) background(#cccccc)'); }; $resetInput = function ($default = '') use($input, $labelMaxWidth) { Cursor::move('→', $labelMaxWidth); echo $input($default); Cursor::move('LEFT'); Cursor::move('→', $labelMaxWidth); Cursor::colorize('foreground(black) background(#cccccc)'); }; echo Text::colorize('Installation of sabre/' . "\n" . Welcome::LOGO, 'foreground(yellow)'), "\n\n", static::getBaseURLInfo(), "\n\n", 'Choose the base URL: ', $input('/'), "\n", 'Your administrator login: '******'Choose the administrator password: '******'Choose the administrator email: ', $input(), "\n", 'Choose the database driver: ', '🔘 SQLite ⚪️ MySQL', "\n"; Window::scroll('↑', 10); Cursor::move('↑', 10); Cursor::move('↑', $numberOfSteps); Cursor::move('→', $labelMaxWidth); // Disable arrow up and down. $no_echo = function ($readline) { return $readline::STATE_NO_ECHO; }; $readline->addMapping("[A", $no_echo); $readline->addMapping("[B", $no_echo); $step = function ($index, $label, callable $validator, $errorMessage, $default = '') use($numberOfSteps, &$readline, $resetInput, $labelMaxWidth) { Cursor::colorize('foreground(black) background(#cccccc)'); do { $out = $readline->readLine(); if (empty($out)) { $out = $default; } $valid = $validator($out); if (true !== $valid) { Cursor::move('↑'); $resetInput($default); Cursor::save(); Cursor::move('LEFT'); Cursor::move('↓', $numberOfSteps - $index + 1); list($title, $message) = explode("\n", $errorMessage); Cursor::colorize('foreground(white) background(red)'); echo $title, "\n"; Cursor::colorize('foreground(red) background(normal)'); echo $message; Cursor::restore(); } else { Cursor::save(); Cursor::move('LEFT'); Cursor::move('↓', $numberOfSteps - $index - 1); Cursor::colorize('normal'); Cursor::clear('↓'); Cursor::restore(); } } while (true !== $valid); if ($numberOfSteps !== $index + 1) { Cursor::move('→', $labelMaxWidth); } Cursor::colorize('normal'); return $out; }; $progress = function ($percent, $message) use($windowWidth) { static $margin = 4; $barWidth = $windowWidth - $margin * 2; Cursor::move('LEFT'); Cursor::move('↑', 1); Cursor::clear('↓'); if ($percent <= 0) { $color = '#c74844'; } elseif ($percent <= 25) { $color = '#cb9a3d'; } elseif ($percent <= 50) { $color = '#dcb11e'; } elseif ($percent <= 75) { $color = '#aed633'; } else { $color = '#54b455'; } echo str_repeat(' ', $margin); Cursor::colorize('foreground(' . $color . ') background(' . $color . ')'); echo str_repeat('|', $percent * $barWidth / 100); Cursor::move('LEFT ↓'); Cursor::colorize('background(normal)'); echo str_repeat(' ', $margin) . $message; Cursor::colorize('normal'); sleep(1); }; } else { echo 'Installation of sabre/' . "\n" . Welcome::LOGO, "\n\n", static::getBaseURLInfo(), "\n\n"; $step = function ($index, $label, callable $validator, $errorMessage, $default = '') use(&$readline) { do { echo $label; if (!empty($default)) { echo ' [default: ', $default, ']'; } $out = $readline->readLine(': '); if (empty($out)) { $out = $default; } $valid = $validator($out); if (true !== $valid) { echo $errorMessage, "\n"; } } while (true !== $valid); return $out; }; $progress = function ($percent, $message) { echo $message, "\n"; }; } $form['baseUrl'] = $step(0, 'Choose the base URL', function ($baseUrl) use($verbose) { $valid = Installer::checkBaseUrl($baseUrl); if (true === $valid && true === $verbose) { Cursor::move('↓'); } return $valid; }, 'Base URL must start and end by a slash' . "\n" . 'Check the Section “The base URL” on http://sabre.io/dav/gettingstarted/.', '/'); if (false === $verbose) { echo 'Your administrator login: '******'password'] = $step(1, 'Choose the administrator password', function ($administratorPassword) { return Installer::checkPassword($administratorPassword . $administratorPassword); }, 'Password must not be empty' . "\n" . 'An empty password is not a password anymore!'); $readline = $oldReadline; $form['email'] = $step(2, 'Choose the administrator email', function ($administratorEmail) { return Installer::checkEmail($administratorEmail . $administratorEmail); }, 'Email is invalid' . "\n" . 'The given email seems invalid.'); $databaseDriver =& $form['database']['driver']; if (true === $verbose) { $radioReadline = new Console\Readline\Password(); $radioReadline->addMapping('\\e[D', function () use($labelMaxWidth, &$databaseDriver) { $databaseDriver = 'sqlite'; Cursor::save(); Cursor::move('LEFT'); Cursor::move('→', $labelMaxWidth); Cursor::clear('→'); echo '🔘 SQLite ⚪️ MySQL'; Cursor::restore(); }); $radioReadline->addMapping('\\e[C', function () use($labelMaxWidth, &$databaseDriver) { $databaseDriver = 'mysql'; Cursor::save(); Cursor::move('LEFT'); Cursor::move('→', $labelMaxWidth); Cursor::clear('→'); echo '⚪️ SQLite 🔘 MySQL'; Cursor::restore(); }); Cursor::hide(); $radioReadline->readLine(); Cursor::show(); unset($databaseDriver); if ('mysql' === $form['database']['driver']) { echo 'Choose MySQL host: ', $input(), "\n", 'Choose MySQL port: ', $input('3306'), "\n", 'Choose MySQL username: '******'Choose MySQL password: '******'Choose MySQL database name: ', $input(), "\n"; Window::scroll('↑', 10); Cursor::move('↑', 10); $numberOfSteps = 5; Cursor::move('↑', $numberOfSteps); Cursor::move('→', $labelMaxWidth); Cursor::colorize('foreground(black) background(#cccccc)'); } } else { $form['database']['driver'] = $step(3, 'Choose the database driver (sqlite or mysql)', function ($databaseDriver) { return in_array($databaseDriver, ['sqlite', 'mysql']); }, 'Database driver is invalid' . "\n" . 'Database driver must be `sqlite` or `mysql`', 'sqlite'); } if ('mysql' === $form['database']['driver']) { $form['database']['host'] = $step(0, 'Choose MySQL host', function () { return true; }, ''); $form['database']['port'] = $step(1, 'Choose MySQL port', function ($port) { return false !== filter_var($port, FILTER_VALIDATE_INT); }, 'Port is invalid' . "\n" . 'Port must be an integer.', '3306'); $form['database']['username'] = $step(2, 'Choose MySQL username', function () { return true; }, ''); $oldReadline = $readline; $readline = new Console\Readline\Password(); $form['database']['password'] = $step(3, 'Choose MySQL password', function () { return true; }, ''); $readline = $oldReadline; $form['database']['name'] = $step(3, 'Choose MySQL database name', function () { return true; }, ''); } $readline->readLine("\n" . 'Ready to install? (Enter to continue, Ctrl-C to abort)'); echo "\n\n"; try { $progress(5, 'Create configuration file…'); $configuration = Installer::createConfigurationFile(Server::CONFIGURATION_FILE, ['baseUrl' => $form['baseUrl'], 'database' => $form['database']]); $progress(25, 'Configuration file created 👍!'); $progress(30, 'Create the database…'); $database = Installer::createDatabase($configuration); $progress(50, 'Database created 👍!'); $progress(55, 'Create administrator profile…'); Installer::createAdministratorProfile($configuration, $database, $form['email'], $form['password']); $progress(75, 'Administrator profile created 👍!'); $progress(100, 'sabre/katana is ready!'); } catch (\Exception $e) { $progress(-1, 'An error occured: ' . $e->getMessage()); if (null !== ($previous = $e->getPrevious())) { echo 'Underlying error: ' . $previous->getMessage(); } echo "\n", 'You are probably likely to run: ' . '`make uninstall` before trying again.', "\n"; return 2; } list($dirname) = Uri\split($form['baseUrl']); echo "\n\n", 'The administration interface will be found at this path: ', '<your website>', $dirname, '/admin.php.', "\n"; Window::setTitle($oldTitle); }
/** * The entry method. * * @return int */ public function main() { $verbose = Console::isDirect(STDOUT); $printSnapshot = false; $printDays = false; $printCommits = false; while (false !== ($c = $this->getOption($v))) { switch ($c) { case '__ambiguous': $this->resolveOptionAmbiguity($v); break; case 'V': $verbose = false; break; case 's': $printSnapshot = true; break; case 'd': $printDays = true; break; case 'c': $printCommits = true; break; case 'h': case '?': default: return $this->usage(); } } $this->parser->listInputs($repositoryRoot); if (empty($repositoryRoot)) { return $this->usage(); } if (false === file_exists($repositoryRoot . DS . '.git')) { throw new Console\Exception('%s is not a valid Git repository.', 0, $repositoryRoot); } $tag = Console\Processus::execute('git --git-dir=' . $repositoryRoot . '/.git ' . 'describe --abbrev=0 --tags origin/master'); if (empty($tag)) { throw new Console\Exception('No tag.', 1); } $timeZone = new \DateTimeZone('UTC'); $snapshotDT = \DateTime::createFromFormat('*.y.m.d', $tag, $timeZone); $sixWeeks = new \DateInterval('P6W'); $nextSnapshotDT = clone $snapshotDT; $nextSnapshotDT->add($sixWeeks); $today = new \DateTime('now', $timeZone); $needNewSnapshot = '+' === $nextSnapshotDT->diff($today)->format('%R'); $numberOfDays = 0; $numberOfCommits = 0; $output = 'No snapshot is required.'; if (true === $needNewSnapshot) { $numberOfDays = (int) $nextSnapshotDT->diff($today)->format('%a'); $numberOfCommits = (int) Console\Processus::execute('git --git-dir=' . $repositoryRoot . '/.git ' . 'rev-list ' . $tag . '..origin/master --count'); $needNewSnapshot = 0 < $numberOfCommits; if (true === $needNewSnapshot) { $output = 'A snapshot is required, since ' . $numberOfDays . ' day' . (1 < $numberOfDays ? 's' : '') . ' (tag ' . $tag . ', ' . $numberOfCommits . ' commit' . (1 < $numberOfCommits ? 's' : '') . ' to publish)!'; } } if (true === $printSnapshot || true === $printDays || true === $printCommits) { $columns = []; if (true === $printSnapshot) { $columns[] = $tag; } if (true === $printDays) { $columns[] = $numberOfDays . ' day' . (1 < $numberOfDays ? 's' : ''); } if (true === $printCommits) { $columns[] = $numberOfCommits . ' commit' . (1 < $numberOfCommits ? 's' : ''); } echo implode("\t", $columns), "\n"; } elseif (true === $verbose) { echo $output, "\n"; } return !$needNewSnapshot; }
/** * Scroll whole page. * Directions can be: * • u, up, ↑ : scroll whole page up; * • d, down, ↓ : scroll whole page down. * Directions can be concatenated by a single space. * * @access public * @param string $directions Directions. * @param int $repeat How many times do we scroll? * @reutrn void */ public static function scroll($directions, $repeat = 1) { if (OS_WIN) { return; } if (1 > $repeat) { return; } elseif (1 === $repeat) { $handle = explode(' ', $directions); } else { $handle = explode(' ', $directions, 1); } $tput = \Hoa\Console::getTput(); $count = array('up' => 0, 'down' => 0); foreach ($handle as $direction) { switch ($direction) { case 'u': case 'up': case '↑': ++$count['up']; break; case 'd': case 'down': case '↓': ++$count['down']; break; } } if (0 < $count['up']) { echo str_replace('%p1%d', $count['up'] * $repeat, $tput->get('parm_index')); } if (0 < $count['down']) { echo str_replace('%p1%d', $count['down'] * $repeat, $tput->get('parm_rindex')); } return; }
/** * Read a line from STDIN. * * @access public * @param string $prefix Prefix. * @return string */ public function readLine($prefix = null) { if (feof(STDIN)) { return false; } $direct = \Hoa\Console::isDirect(STDIN); if (false === $direct || OS_WIN) { $out = fgets(STDIN); if (false === $out) { return false; } $out = substr($out, 0, -1); if (true === $direct) { echo $prefix; } else { echo $prefix, $out, "\n"; } return $out; } $this->resetLine(); $this->setPrefix($prefix); $read = array(STDIN); echo $prefix; while (true) { @stream_select($read, $write, $except, 30, 0); if (empty($read)) { $read = array(STDIN); continue; } $char = $this->_read(); $this->_buffer = $char; $return = $this->_readLine($char); if (0 === ($return & self::STATE_NO_ECHO)) { echo $this->_buffer; } if (0 !== ($return & self::STATE_BREAK)) { break; } } return $this->getLine(); }
/** * Make a stupid “bip”. * * @access public * @return void */ public static function bip() { echo \Hoa\Console::getTput()->get('bell'); return; }