Beispiel #1
0
 /**
  * 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 SABRE_KATANA_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";
 }
Beispiel #2
0
 public function listen()
 {
     Cursor::setStyle('▋', true);
     do {
         Cursor::colorize('b fg(yellow) bg(blue)');
         echo '◼ datatext > ';
         Cursor::colorize('!b fg(default) bg(default)');
         $line = $this->readline->readLine(' ');
         if ($line === 'fake') {
             $rows = [];
             $size = Window::getSize();
             for ($i = 0; $i < $size['y'] - 4; $i++) {
                 $row = [];
                 for ($j = 0; $j < 10; $j++) {
                     $row[] = $this->faker->name;
                 }
                 $rows[] = $row;
             }
             $table = new Table($rows, ['headers' => ['a', 'b', 'c', 'd', 'e'], 'stickyColumns' => [2]]);
             $navigable = new NavigableTable($table);
             $navigable->render();
         } else {
             echo '< ', $line, "\n";
         }
     } while (false !== $line && 'quit' !== $line);
 }
Beispiel #3
0
 /**
  * Colorize a portion of a text.
  * It is kind of a shortcut of \Hoa\Console\Color.
  *
  * @access  public
  * @param   string  $text                Text.
  * @param   string  $attributesBefore    Style to apply.
  * @param   string  $attributesAfter     Reset style.
  * @return  string
  */
 public static function colorize($text, $attributesBefore, $attributesAfter = 'normal')
 {
     ob_start();
     \Hoa\Console\Cursor::colorize($attributesBefore);
     echo $text;
     \Hoa\Console\Cursor::colorize($attributesAfter);
     $out = ob_get_contents();
     ob_end_clean();
     return $out;
 }
Beispiel #4
0
 public function _bindK()
 {
     if ($this->columnOffset == $this->table->getNumberOfColumns() - 1) {
         Cursor::bip();
     } else {
         $this->columnOffset++;
         $this->renderInternal();
     }
     return Readline::STATE_NO_ECHO;
 }
Beispiel #5
0
 /**
  * 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 = Protocol::getInstance();
         $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\Cursor::colorize('foreground(yellow)'), $path, Console\Cursor::colorize('normal'), ' is equivalent to:', "\n";
     }
     $resolved = resolve($path, $exists, $unfold);
     foreach ((array) $resolved as $r) {
         echo $r, "\n";
     }
     return;
 }
Beispiel #6
0
 /**
  * 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("", $no_echo);
         $readline->addMapping("", $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);
 }
Beispiel #7
0
 /**
  * The entry method.
  *
  * @return  int
  */
 public function main()
 {
     $breakBC = false;
     $minimumTag = null;
     $doSteps = ['test' => -1, 'changelog' => -1, 'tag' => -1, 'github' => -1];
     $onlyStep = function ($step) use(&$doSteps) {
         $doSteps[$step] = 1;
         foreach ($doSteps as &$doStep) {
             if (-1 === $doStep) {
                 $doStep = 0;
             }
         }
         return;
     };
     while (false !== ($c = $this->getOption($v))) {
         switch ($c) {
             case '__ambiguous':
                 $this->resolveOptionAmbiguity($v);
                 break;
             case 'c':
                 $onlyStep('changelog');
                 break;
             case 't':
                 $onlyStep('tag');
                 break;
             case 'g':
                 $onlyStep('github');
                 break;
             case 'b':
                 $breakBC = $v;
                 break;
             case 'm':
                 $minimumTag = $v;
                 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);
     }
     date_default_timezone_set('UTC');
     $allTags = $tags = explode("\n", Console\Processus::execute('git --git-dir=' . $repositoryRoot . '/.git ' . 'tag'));
     rsort($tags);
     list($currentMCN) = explode('.', $tags[0], 2);
     if (true === $breakBC) {
         ++$currentMCN;
     }
     $newTag = $currentMCN . '.' . date('y.m.d');
     if (null === $minimumTag) {
         $tags = [$tags[0]];
     } else {
         $toInt = function ($tag) {
             list($x, $y, $m, $d) = explode('.', $tag);
             return $x * 1000000 + $y * 10000 + $m * 100 + $d * 1;
         };
         $_tags = [];
         $_minimumTag = $toInt($minimumTag);
         foreach ($tags as $tag) {
             if ($toInt($tag) >= $_minimumTag) {
                 $_tags[] = $tag;
             }
         }
         $tags = $_tags;
     }
     $changelog = '';
     echo 'We are going to snapshot this library together, by following ', 'these steps:', "\n", '  1. tests must pass,', "\n", '  2. updating the CHANGELOG.md file,', "\n", '  3. commit the CHANGELOG.md file,', "\n", '  4. creating a tag,', "\n", '  5. pushing the tag,', "\n", '  6. creating a release on Github.', "\n";
     $step = function ($stepGroup, $message, $task) use($doSteps) {
         echo "\n\n";
         Console\Cursor::colorize('foreground(black) background(yellow)');
         echo 'Step “', $message, '”.';
         Console\Cursor::colorize('normal');
         echo "\n";
         if (0 === $doSteps[$stepGroup]) {
             $answer = 'no';
         } else {
             $answer = $this->readLine('Would you like to do this one: [yes/no] ');
         }
         if ('yes' === $answer) {
             echo "\n";
             $task();
         } else {
             Console\Cursor::colorize('foreground(red)');
             echo 'Aborted!', "\n";
             Console\Cursor::colorize('normal');
         }
     };
     $step('test', 'tests must pass', function () {
         echo 'Tests must be green. Execute:', "\n", '    $ hoa test:run -d Test', "\n", 'to run the tests.', "\n";
         $this->readLine('Press Enter when it is green (or Ctrl-C to abort).');
     });
     $step('changelog', 'updating the CHANGELOG.md file', function () use($tags, $newTag, $repositoryRoot, &$changelog) {
         array_unshift($tags, 'HEAD');
         $changelog = null;
         for ($i = 0, $max = count($tags) - 1; $i < $max; ++$i) {
             $fromStep = $tags[$i];
             $toStep = $tags[$i + 1];
             $title = $fromStep;
             if ('HEAD' === $fromStep) {
                 $title = $newTag;
             }
             $changelog .= '# ' . $title . "\n\n" . Console\Processus::execute('git --git-dir=' . $repositoryRoot . '/.git ' . 'log ' . '--first-parent ' . '--pretty="format:  * %s (%aN, %aI)" ' . $fromStep . '...' . $toStep, false) . "\n\n";
         }
         $file = new File\ReadWrite($repositoryRoot . DS . 'CHANGELOG.md');
         $file->rewind();
         $temporary = new File\ReadWrite($repositoryRoot . DS . '._hoa.CHANGELOG.md');
         $temporary->truncate(0);
         $temporary->writeAll($changelog);
         $temporary->close();
         echo 'The CHANGELOG is ready.', "\n";
         $this->readLine('Press Enter to check and edit the file (empty the file to abort).');
         Console\Chrome\Editor::open($temporary->getStreamName());
         $temporary->open();
         $changelog = $temporary->readAll();
         if (empty(trim($changelog))) {
             $temporary->delete();
             $temporary->close();
             exit;
         }
         $previous = $file->readAll();
         $file->truncate(0);
         $file->writeAll($changelog . $previous);
         $temporary->delete();
         $temporary->close();
         $file->close();
         return;
     });
     $step('changelog', 'commit the CHANGELOG.md file', function () use($newTag, $repositoryRoot) {
         echo Console\Processus::execute('git --git-dir=' . $repositoryRoot . '/.git ' . 'add ' . '--verbose ' . 'CHANGELOG.md');
         echo Console\Processus::execute('git --git-dir=' . $repositoryRoot . '/.git ' . 'commit ' . '--verbose ' . '--message "Prepare ' . $newTag . '." ' . 'CHANGELOG.md');
         return;
     });
     $step('tag', 'creating a tag', function () use($breakBC, $step, $currentMCN, $repositoryRoot, $tags, $newTag, $allTags) {
         if (true === $breakBC) {
             echo 'A BC break has been introduced, ', 'few more steps are required:', "\n";
             $step('tag', 'update the composer.json file', function () use($currentMCN) {
                 echo 'The `extra.branch-alias.dev-master` value ', 'must be set to `', $currentMCN, '.x-dev`', "\n";
                 $this->readLine('Press Enter to edit the file.');
                 Console\Chrome\Editor::open($repository . DS . 'composer.json');
             });
             $step('tag', 'open issues to update parent dependencies', function () {
                 echo 'Some libraries may depend on this one. ', 'Issues must be opened to update this ', 'dependency.', "\n";
                 $this->readLine('Press Enter when it is done (or Ctrl-C to abort).');
             });
             $step('tag', 'update the README.md file', function () use($currentMCN) {
                 echo 'The installation Section must invite the ', 'user to install the version ', '`~', $currentMCN, '.0`.', "\n";
                 $this->readLine('Press Enter when it is done (or Ctrl-C to abort).');
                 Console\Chrome\Editor::open($repository . DS . 'README.md');
             });
             $step('tag', 'commit the composer.json and README.md files', function () use($currentMCN) {
                 echo Console\Processus::execute('git --git-dir=' . $repositoryRoot . '/.git ' . 'add ' . '--verbose ' . 'composer.json README.md');
                 echo Console\Processus::execute('git --git-dir=' . $repositoryRoot . '/.git ' . 'commit ' . '--verbose ' . '--message "Update because of the BC break." ' . 'composer.json README.md');
             });
         }
         $status = Console\Processus::execute('git --git-dir=' . $repositoryRoot . '/.git ' . 'status ' . '--short');
         if (!empty($status)) {
             Console\Cursor::colorize('foreground(white) background(red)');
             echo 'At least one file is not commited!';
             Console\Cursor::colorize('normal');
             echo "\n", '(tips: use `git stash` if it is not related ', 'to this snapshot)', "\n";
             $this->readLine('Press Enter when everything is clean.');
         }
         echo 'Here is the list of tags:', "\n", '  * ', implode(',' . "\n" . '  * ', $allTags), '.', "\n", 'We are going to create the following tag: ', $newTag, '.', "\n";
         $answer = $this->readLine('Is it correct? [yes/no] ');
         if ('yes' !== $answer) {
             return;
         }
         Console\Processus::execute('git --git-dir=' . $repositoryRoot . '/.git ' . 'tag ' . $newTag);
     });
     $step('tag', 'push the new snapshot', function () use($repositoryRoot) {
         Console\Cursor::colorize('foreground(white) background(red)');
         echo 'This step ', Console\Cursor::colorize('underlined');
         echo 'must not';
         Console\Cursor::colorize('!underlined');
         echo ' be undo!';
         Console\Cursor::colorize('normal');
         echo "\n";
         $i = 5;
         while ($i-- > 0) {
             Console\Cursor::clear('↔');
             echo $i + 1;
             sleep(1);
         }
         $remotes = Console\Processus::execute('git --git-dir=' . $repositoryRoot . '/.git ' . 'remote ' . '--verbose');
         $gotcha = false;
         foreach (explode("\n", $remotes) as $remote) {
             if (0 !== preg_match('/(git@git.hoa-project.net:[^ ]+)/', $remote, $matches)) {
                 $gotcha = true;
                 break;
             }
         }
         if (false === $gotcha) {
             echo 'No remote has been found.';
             return;
         }
         echo "\n", 'To push tag, execute:', "\n", '    $ git push ', $matches[1], "\n", '    $ git push ', $matches[1], ' --tags', "\n";
         $this->readLine('Press Enter when it is done (or Ctrl-C to abort).');
     });
     $step('github', 'create a release on Github', function () use($newTag, $changelog, $repositoryRoot) {
         $temporary = new File\ReadWrite($repositoryRoot . DS . '._hoa.GithubRelease.md');
         $temporary->truncate(0);
         if (!empty($changelog)) {
             $temporary->writeAll($changelog);
         }
         $temporary->close();
         Console\Chrome\Editor::open($temporary->getStreamName());
         $temporary->open();
         $temporary->rewind();
         $body = $temporary->readAll();
         $temporary->delete();
         $composer = json_decode(file_get_contents('composer.json'));
         list(, $libraryName) = explode('/', $composer->name);
         $output = json_encode(['tag_name' => $newTag, 'body' => $body]);
         $username = $this->readLine('Username: '******'Password: '******':' . $password);
         $context = stream_context_create(['http' => ['method' => 'POST', 'header' => 'Host: api.github.com' . CRLF . 'User-Agent: Hoa\\Devtools' . CRLF . 'Accept: application/json' . CRLF . 'Content-Type: application/json' . CRLF . 'Content-Length: ' . strlen($output) . CRLF . 'Authorization: Basic ' . $auth . CRLF, 'content' => $output]]);
         echo file_get_contents('https://api.github.com/repos/hoaproject/' . $libraryName . '/releases', false, $context);
     });
     echo "\n", '🍺 🍺 🍺', "\n";
     return;
 }
 /**
  *
  */
 private function drawField()
 {
     \Hoa\Console\Cursor::clear();
     //\Hoa\Console\Cursor::save();
     //echo PHP_EOL;
     //\Hoa\Console\Cursor::colorize('underlined foreground(yellow) background(#932e2e)');
     echo $this->view->drawField();
     //\Hoa\Console\Cursor::restore();
 }
Beispiel #9
0
                break;
            }
        }
    }
}
Core::enableErrorHandler();
Core::enableExceptionHandler();
/**
 * Here we go!
 */
try {
    $router = new Router\Cli();
    $router->get('g', '(?:(?<vendor>\\w+)\\s+)?(?<library>\\w+)?(?::(?<command>\\w+))?(?<_tail>.*?)', 'main', 'main', ['vendor' => 'hoa', 'library' => 'core', 'command' => 'welcome']);
    $dispatcher = new Dispatcher\ClassMethod(['synchronous.call' => '(:%variables.vendor:lU:)\\(:%variables.library:lU:)\\Bin\\(:%variables.command:lU:)', 'synchronous.able' => 'main']);
    $dispatcher->setKitName('Hoa\\Console\\Dispatcher\\Kit');
    exit((int) $dispatcher->dispatch($router));
} catch (Core\Exception $e) {
    $message = $e->raise(true);
    $code = 1;
} catch (\Exception $e) {
    $message = $e->getMessage();
    $code = 2;
}
ob_start();
Console\Cursor::colorize('foreground(white) background(red)');
echo $message, "\n";
Console\Cursor::colorize('normal');
$content = ob_get_contents();
ob_end_clean();
file_put_contents('php://stderr', $content);
exit($code);
Beispiel #10
0
 /**
  * Clear the current line/buffer.
  * ctrl+c like behavior, used by Reader
  * @param int|object $code SIGINT = 2 on osx
  */
 public function bindClearLine($code = null)
 {
     $line = $this->reader->getLine();
     $buffer = trim($this->reader->getBuffer());
     // ctrl+c = Cancelling...
     if (!empty($line) && $buffer === '') {
         Cursor::clear('line');
     } else {
         // User is viewing their history, else typed something
         if (empty($this->buf)) {
             $mLines = substr_count($buffer, "\n");
         } else {
             $mLines = substr_count($this->buf, "\n");
         }
         // Redraw the prompt, by erasing the existing buffered lines
         Cursor::move('up', $mLines);
         Cursor::clear('line');
         Cursor::clear('down', $mLines);
         $this->buf = '';
         echo $this->prompter;
     }
     $this->reader->setLine(null);
     $this->reader->setBuffer('');
 }
Beispiel #11
0
 /**
  * The entry method.
  *
  * @return  int
  */
 public function main()
 {
     while (false !== ($c = $this->getOption($v))) {
         switch ($c) {
             case 'h':
             case '?':
                 return $this->usage();
             case '__ambiguous':
                 $this->resolveOptionAmbiguity($v);
                 break;
         }
     }
     Realdom::setDefaultSampler(new Math\Sampler\Random());
     $compiler = Compiler\Llk::load(new File\Read('hoa://Library/Praspel/Grammar.pp'));
     $interpreter = new Praspel\Visitor\Interpreter();
     $dump = new Praspel\Visitor\Compiler();
     $interpreter->visit($compiler->parse('@requires;'));
     $words = [];
     from('Hoathis or Hoa')->foreachImport('Realdom.*', function ($classname) use(&$words) {
         $class = new \ReflectionClass($classname);
         if ($class->isSubclassOf('\\Hoa\\Realdom')) {
             $words[] = $classname::NAME;
         }
         return;
     });
     $readline = new Console\Readline();
     $readline->setAutocompleter(new Console\Readline\Autocompleter\Word($words));
     $expression = '.h';
     do {
         try {
             if ('.' === $expression[0]) {
                 @(list($expression, $tail) = explode(' ', $expression));
             }
             switch ($expression) {
                 case '.h':
                 case '.help':
                     echo 'Usage:', "\n", '    .h[elp]      to print this help;', "\n", '    .c[lear]     to clear the screen;', "\n", '    .v[ariables] to print all variables;', "\n", '    .s[ample]    to sample a value of a variable;', "\n", '    .u[nset]     to unset a variable;', "\n", '    .d[ump]      to dump the tree of the expression;', "\n", '    .q[uit]      to quit.', "\n";
                     break;
                 case '.c':
                 case '.clear':
                     Console\Cursor::clear('↕');
                     break;
                 case '.v':
                 case '.variables':
                     foreach ($interpreter->getClause() as $variable) {
                         echo $variable->getName(), ': ', $variable->getHeld()->toPraspel(), "\n";
                     }
                     break;
                 case '.s':
                 case '.sample':
                     if (null === $tail) {
                         echo 'You must precise a variable name.', "\n";
                         break;
                     }
                     $_clause = $interpreter->getClause();
                     if (!isset($_clause[$tail])) {
                         echo 'Variable ', $tail, ' does not exist.', "\n";
                         break;
                     }
                     $_variable = $_clause[$tail];
                     var_export($_variable->sample());
                     echo "\n";
                     $_variable->reset();
                     break;
                 case '.u':
                 case '.unset':
                     if (null === $tail) {
                         echo 'You must precise a variable name.', "\n";
                         break;
                     }
                     $_clause = $interpreter->getClause();
                     unset($_clause[$tail]);
                     break;
                 case '.d':
                 case '.dump':
                     echo $dump->visit($interpreter->getRoot());
                     break;
                 case '.q':
                 case '.quit':
                     break 2;
                 default:
                     if (null === $expression) {
                         break;
                     }
                     $interpreter->visit($compiler->parse($expression, 'expression'));
                     break;
             }
         } catch (\Exception $e) {
             echo $e->getMessage(), "\n";
         }
         echo "\n";
     } while (false !== ($expression = $readline->readLine('> ')));
     return;
 }
Beispiel #12
0
 /**
  * Tab binding.
  *
  * @access  public
  * @param   \Hoa\Console\Readline  $self    Self.
  * @return  int
  */
 public function _bindTab(Readline $self)
 {
     $autocompleter = $self->getAutocompleter();
     $state = static::STATE_CONTINUE | static::STATE_NO_ECHO;
     if (null === $autocompleter) {
         return $state;
     }
     $current = $self->getLineCurrent();
     $line = $self->getLine();
     if (0 === $current) {
         return $state;
     }
     $matches = preg_match_all('#' . $autocompleter->getWordDefinition() . '#u', $line, $words, PREG_OFFSET_CAPTURE);
     if (0 === $matches) {
         return $state;
     }
     for ($i = 0, $max = count($words[0]); $i < $max && $current > $words[0][$i][1]; ++$i) {
     }
     $word = $words[0][$i - 1];
     if ('' === trim($word[0])) {
         return $state;
     }
     $prefix = mb_substr($word[0], 0, $current - $word[1]);
     $solution = $autocompleter->complete($prefix);
     $length = mb_strlen($prefix);
     if (null === $solution) {
         return $state;
     }
     if (is_array($solution)) {
         $_solution = $solution;
         $count = count($_solution) - 1;
         $cWidth = 0;
         $window = \Hoa\Console\Window::getSize();
         $wWidth = $window['x'];
         $cursor = \Hoa\Console\Cursor::getPosition();
         array_walk($_solution, function (&$value) use(&$cWidth) {
             $handle = mb_strlen($value);
             if ($handle > $cWidth) {
                 $cWidth = $handle;
             }
             return;
         });
         array_walk($_solution, function (&$value) use(&$cWidth) {
             $handle = mb_strlen($value);
             if ($handle >= $cWidth) {
                 return;
             }
             $value .= str_repeat(' ', $cWidth - $handle);
             return;
         });
         $mColumns = (int) floor($wWidth / ($cWidth + 2));
         $mLines = (int) ceil(($count + 1) / $mColumns);
         --$mColumns;
         $i = 0;
         if (0 > $window['y'] - $cursor['y'] - $mLines) {
             \Hoa\Console\Window::scroll('↑', $mLines);
             \Hoa\Console\Cursor::move('↑', $mLines);
         }
         \Hoa\Console\Cursor::save();
         \Hoa\Console\Cursor::hide();
         \Hoa\Console\Cursor::move('↓ LEFT');
         \Hoa\Console\Cursor::clear('↓');
         foreach ($_solution as $j => $s) {
             echo "", $s, "";
             if ($i++ < $mColumns) {
                 echo '  ';
             } else {
                 $i = 0;
                 if (isset($_solution[$j + 1])) {
                     echo "\n";
                 }
             }
         }
         \Hoa\Console\Cursor::restore();
         \Hoa\Console\Cursor::show();
         ++$mColumns;
         $read = array(STDIN);
         $mColumn = -1;
         $mLine = -1;
         $coord = -1;
         $unselect = function () use(&$mColumn, &$mLine, &$coord, &$_solution, &$cWidth) {
             \Hoa\Console\Cursor::save();
             \Hoa\Console\Cursor::hide();
             \Hoa\Console\Cursor::move('↓ LEFT');
             \Hoa\Console\Cursor::move('→', $mColumn * ($cWidth + 2));
             \Hoa\Console\Cursor::move('↓', $mLine);
             echo "" . $_solution[$coord] . "";
             \Hoa\Console\Cursor::restore();
             \Hoa\Console\Cursor::show();
             return;
         };
         $select = function () use(&$mColumn, &$mLine, &$coord, &$_solution, &$cWidth) {
             \Hoa\Console\Cursor::save();
             \Hoa\Console\Cursor::hide();
             \Hoa\Console\Cursor::move('↓ LEFT');
             \Hoa\Console\Cursor::move('→', $mColumn * ($cWidth + 2));
             \Hoa\Console\Cursor::move('↓', $mLine);
             echo "" . $_solution[$coord] . "";
             \Hoa\Console\Cursor::restore();
             \Hoa\Console\Cursor::show();
             return;
         };
         $init = function () use(&$mColumn, &$mLine, &$coord, &$select) {
             $mColumn = 0;
             $mLine = 0;
             $coord = 0;
             $select();
             return;
         };
         while (true) {
             @stream_select($read, $write, $except, 30, 0);
             if (empty($read)) {
                 $read = array(STDIN);
                 continue;
             }
             switch ($char = $self->_read()) {
                 case "":
                     if (-1 === $mColumn && -1 === $mLine) {
                         $init();
                         break;
                     }
                     $unselect();
                     $coord = max(0, $coord - $mColumns);
                     $mLine = (int) floor($coord / $mColumns);
                     $mColumn = $coord % $mColumns;
                     $select();
                     break;
                 case "":
                     if (-1 === $mColumn && -1 === $mLine) {
                         $init();
                         break;
                     }
                     $unselect();
                     $coord = min($count, $coord + $mColumns);
                     $mLine = (int) floor($coord / $mColumns);
                     $mColumn = $coord % $mColumns;
                     $select();
                     break;
                 case "\t":
                 case "":
                     if (-1 === $mColumn && -1 === $mLine) {
                         $init();
                         break;
                     }
                     $unselect();
                     $coord = min($count, $coord + 1);
                     $mLine = (int) floor($coord / $mColumns);
                     $mColumn = $coord % $mColumns;
                     $select();
                     break;
                 case "":
                     if (-1 === $mColumn && -1 === $mLine) {
                         $init();
                         break;
                     }
                     $unselect();
                     $coord = max(0, $coord - 1);
                     $mLine = (int) floor($coord / $mColumns);
                     $mColumn = $coord % $mColumns;
                     $select();
                     break;
                 case "\n":
                     if (-1 !== $mColumn && -1 !== $mLine) {
                         $tail = mb_substr($line, $current);
                         $current -= $length;
                         $self->setLine(mb_substr($line, 0, $current) . $solution[$coord] . $tail);
                         $self->setLineCurrent($current + mb_strlen($solution[$coord]));
                         \Hoa\Console\Cursor::move('←', $length);
                         echo $solution[$coord];
                         \Hoa\Console\Cursor::clear('→');
                         echo $tail;
                         \Hoa\Console\Cursor::move('←', mb_strlen($tail));
                     }
                 default:
                     $mColumn = -1;
                     $mLine = -1;
                     $coord = -1;
                     \Hoa\Console\Cursor::save();
                     \Hoa\Console\Cursor::move('↓ LEFT');
                     \Hoa\Console\Cursor::clear('↓');
                     \Hoa\Console\Cursor::restore();
                     if ("" !== $char && "\n" !== $char) {
                         $self->setBuffer($char);
                         return $self->_readLine($char);
                     }
                     break 2;
             }
         }
         return $state;
     }
     $tail = mb_substr($line, $current);
     $current -= $length;
     $self->setLine(mb_substr($line, 0, $current) . $solution . $tail);
     $self->setLineCurrent($current + mb_strlen($solution));
     \Hoa\Console\Cursor::move('←', $length);
     echo $solution;
     \Hoa\Console\Cursor::clear('→');
     echo $tail;
     \Hoa\Console\Cursor::move('←', mb_strlen($tail));
     return $state;
 }
Beispiel #13
0
 /**
  * The entry method.
  *
  * @return  int
  */
 public function main()
 {
     $libraries = [];
     while (false !== ($c = $this->getOption($v))) {
         switch ($c) {
             case 'a':
                 $iterator = new File\Finder();
                 $iterator->in(resolve('hoa://Library/', true, true))->directories()->maxDepth(1);
                 foreach ($iterator as $fileinfo) {
                     $libraryName = $fileinfo->getBasename();
                     $pathname = resolve('hoa://Library/' . $libraryName);
                     $automaticTests = $pathname . DS . 'Test' . DS . 'Praspel' . DS;
                     if (is_dir($automaticTests)) {
                         $libraries[] = $automaticTests;
                     }
                 }
                 if (empty($libraries)) {
                     echo 'Already clean.';
                     return;
                 }
                 break;
             case 'l':
                 foreach ($this->parser->parseSpecialValue($v) as $library) {
                     $libraryName = ucfirst(strtolower($library));
                     $pathname = resolve('hoa://Library/' . $libraryName);
                     $automaticTests = $pathname . DS . 'Test' . DS . 'Praspel' . DS;
                     if (is_dir($automaticTests)) {
                         $libraries[] = $automaticTests;
                     }
                 }
                 if (empty($libraries)) {
                     echo 'Already clean.';
                     return;
                 }
                 break;
             case '__ambiguous':
                 $this->resolveOptionAmbiguity($v);
                 break;
             case 'h':
             case '?':
             default:
                 return $this->usage();
         }
     }
     if (empty($libraries)) {
         return $this->usage();
     }
     foreach ($libraries as $path) {
         $status = 'Clean ' . (40 < strlen($path) ? '…' . substr($path, -39) : $path);
         echo '  ⌛ ', $status;
         $directory = new File\Directory($path);
         if (false === $directory->delete()) {
             echo '  ', Console\Chrome\Text::colorize('✖︎', 'foreground(red)'), ' ', $status, "\n";
         } else {
             Console\Cursor::clear('↔');
             echo '  ', Console\Chrome\Text::colorize('✔︎', 'foreground(green)'), ' ', $status, "\n";
         }
         $directory->close();
     }
     return;
 }
Beispiel #14
0
 /**
  * Main method.
  *
  * @return int
  */
 function main()
 {
     $operation = 0;
     $location = null;
     $updateServer = Updater::DEFAULT_UPDATE_SERVER;
     while (false !== ($c = $this->getOption($v))) {
         switch ($c) {
             case '__ambiguous':
                 $this->resolveOptionAmbiguity($v);
                 break;
             case 'f':
                 $operation = static::OPERATION_FETCH | Updater::FORMAT_PHAR;
                 break;
             case 'z':
                 $operation = static::OPERATION_FETCH | Updater::FORMAT_ZIP;
                 break;
             case 'a':
                 $operation = static::OPERATION_APPLY;
                 $location = $v;
                 break;
             case 's':
                 $updateServer = $v;
                 break;
             case 'h':
             case '?':
             default:
                 return $this->usage();
                 break;
         }
     }
     $updateServer = rtrim($updateServer, '/') . '/';
     if (0 !== (static::OPERATION_FETCH & $operation)) {
         $updatesDotJson = Updater::getUpdateUrl($updateServer);
         $versions = @file_get_contents($updatesDotJson);
         if (empty($versions)) {
             throw new Exception\Console('Oh no! We are not able to check if a new version exists… ' . 'Contact us at http://sabre.io/ ' . '(tried URL %s).', 0, $updatesDotJson);
         }
         $versions = json_decode($versions, true);
         /**
          * Expected format:
          *     {
          *         "1.0.1": {
          *             "phar": "https://…",
          *             "zip" : "https://…"
          *         },
          *         "1.0.0": {
          *             "phar": "https://…",
          *             "zip" : "https://…"
          *         },
          *         …
          *     }
          */
         $versionsToFetch = Updater::filterVersions($versions, Version::VERSION, $operation);
         $windowWidth = Window::getSize()['x'];
         $progress = function ($percent) use($windowWidth) {
             Cursor::clear('↔');
             $message = 'Downloading… ';
             $barWidth = $windowWidth - mb_strlen($message);
             if ($percent <= 0) {
                 $color = '#c74844';
             } elseif ($percent <= 25) {
                 $color = '#cb9a3d';
             } elseif ($percent <= 50) {
                 $color = '#dcb11e';
             } elseif ($percent <= 75) {
                 $color = '#aed633';
             } else {
                 $color = '#54b455';
             }
             echo $message;
             Cursor::colorize('foreground(' . $color . ') background(' . $color . ')');
             echo str_repeat('|', $percent * $barWidth / 100);
             Cursor::colorize('normal');
         };
         foreach ($versionsToFetch as $versionNumber => $versionUrl) {
             list(, $versionUrlBasename) = Uri\split($versionUrl);
             $fileIn = new File\Read($versionUrl, File::MODE_READ, null, true);
             $fileOut = new File\Write(SABRE_KATANA_PREFIX . '/data/share/update/' . $versionUrlBasename);
             echo "\n", 'Fetch version ', $versionNumber, ' from ', $versionUrl, "\n", 'Waiting…', "\n";
             $fileIn->on('connect', function () {
                 Cursor::clear('↔');
                 echo 'Downloading… ';
             });
             $fileIn->on('progress', function (Core\Event\Bucket $bucket) use($progress) {
                 static $previousPercent = 0;
                 $data = $bucket->getData();
                 $current = $data['transferred'];
                 $max = $data['max'];
                 $percent = $current * 100 / $max;
                 $delta = $percent - $previousPercent;
                 if (1 <= $delta) {
                     $previousPercent = $percent;
                     $progress($percent);
                 }
             });
             $fileIn->open();
             $fileOut->writeAll($fileIn->readAll());
             echo "\n", 'Fetched at ', $fileOut->getStreamName(), '.', "\n";
         }
         return 0;
     } elseif (static::OPERATION_APPLY === $operation) {
         if (false === file_exists($location)) {
             throw new Exception\Console('Update %s is not found.', 1, $location);
         }
         $processus = new Console\Processus(Core::getPHPBinary(), [$location, '--extract' => SABRE_KATANA_PREFIX, '--overwrite']);
         $processus->on('input', function () {
             return false;
         });
         $processus->on('output', function (Core\Event\Bucket $bucket) {
             echo $bucket->getData()['line'], "\n";
         });
         $processus->run();
         if (true === $processus->isSuccessful()) {
             echo 'sabre/katana updated!', "\n";
         } else {
             echo 'Something wrong happened!', "\n";
         }
         return $processus->getExitCode();
     } else {
         return $this->usage();
     }
 }
Beispiel #15
0
 /**
  * The entry method.
  *
  * @return  int
  */
 public function main()
 {
     $dryRun = false;
     $classes = [];
     while (false !== ($c = $this->getOption($v))) {
         switch ($c) {
             case 'n':
                 foreach ($this->parser->parseSpecialValue($v) as $namespace) {
                     $namespace = trim(str_replace('.', '\\', $namespace), '\\');
                     if (false === ($pos = strpos($namespace, '\\'))) {
                         throw new Console\Exception('Namespace %s is too short.', 0, $namespace);
                     }
                     $tail = substr($namespace, strpos($namespace, '\\') + 1);
                     $root = resolve('hoa://Library/' . str_replace('\\', '/', $tail));
                     $classes = array_merge($classes, static::findClasses($root, $namespace));
                 }
                 break;
             case 'c':
                 foreach ($this->parser->parseSpecialValue($v) as $class) {
                     $classes[] = $class;
                 }
                 break;
             case 'd':
                 $dryRun = $v;
                 break;
             case '__ambiguous':
                 $this->resolveOptionAmbiguity($v);
                 break;
             case 'h':
             case '?':
             default:
                 return $this->usage();
         }
     }
     if (empty($classes)) {
         return $this->usage();
     }
     foreach ($classes as $i => $class) {
         $classes[$i] = str_replace('.', '\\', $class);
     }
     $generator = new \Atoum\PraspelExtension\Praspel\Generator();
     $generator->setTestNamespacer(function ($namespace) {
         $parts = explode('\\', $namespace);
         return implode('\\', array_slice($parts, 0, 2)) . '\\Test\\Praspel\\Unit' . (isset($parts[2]) ? '\\' . implode('\\', array_slice($parts, 2)) : '');
     });
     $phpBinary = Core::getPHPBinary() ?: Console\Processus::localte('php');
     $envVariable = '__HOA_ATOUM_PRASPEL_EXTENSION_' . md5(Core::uuid());
     $reflection = null;
     $buffer = null;
     $reflectionner = new Console\Processus($phpBinary);
     $reflectionner->on('input', function (Core\Event\Bucket $bucket) use($envVariable) {
         $bucket->getSource()->writeAll('<?php' . "\n" . 'require_once \'' . dirname(__DIR__) . DS . '.bootstrap.atoum.php\';' . "\n" . '$class = getenv(\'' . $envVariable . '\');' . "\n" . 'if (class_exists(\'\\mageekguy\\atoum\\scripts\\runner\', false)) {' . "\n" . '    \\atoum\\scripts\\runner::disableAutorun();' . "\n" . '}' . "\n" . '$reflection = new \\Atoum\\PraspelExtension\\Praspel\\Reflection\\RClass($class);' . "\n" . 'echo serialize($reflection), "\\n";');
         return false;
     });
     $reflectionner->on('output', function (Core\Event\Bucket $bucket) use(&$buffer) {
         $data = $bucket->getData();
         $buffer .= $data['line'] . "\n";
         return;
     });
     $reflectionner->on('stop', function () use(&$buffer, &$reflection) {
         $handle = @unserialize($buffer);
         if (false === $handle) {
             echo $buffer, "\n";
             return;
         }
         $reflection = $handle;
         return;
     });
     foreach ($classes as $class) {
         $status = $class . ' (in ';
         echo '  ⌛ ', $status;
         putenv($envVariable . '=' . $class);
         $buffer = null;
         $reflection = null;
         $reflectionner->run();
         $output = $generator->generate($reflection);
         $parts = explode('\\', $class);
         $paths = resolve('hoa://Library/' . $parts[1] . '/' . 'Test/Praspel/Unit/' . implode('/', array_slice($parts, 2)) . '.php', false, true);
         $max = 0;
         $thePath = 0;
         foreach ($paths as $path) {
             $length = Ustring\Search::lcp($reflection->getFilename(), $path);
             if ($length > $max) {
                 $thePath = $path;
             }
         }
         $statusTail = (40 < strlen($thePath) ? '…' . substr($thePath, -39) : $thePath) . ')';
         echo $statusTail;
         $status .= $statusTail;
         if (false === $reflection->isInstantiable()) {
             Console\Cursor::clear('↔');
             echo '  ⚡️ ', $status, '; not instantiable.', "\n";
             continue;
         }
         $dirname = dirname($thePath);
         if (false === is_dir($dirname)) {
             if (false === $dryRun) {
                 mkdir($dirname, 0755, true);
             } else {
                 echo "\n", static::info('Creating directory: ' . $dirname . '.');
             }
         }
         if (false === $dryRun) {
             file_put_contents($thePath, $output);
         } else {
             echo "\n", static::info('Content of the ' . $thePath . ':'), "\n";
             Console\Cursor::colorize('foreground(yellow)');
             echo '    ┏', "\n", '    ┃  ', str_replace("\n", "\n" . '    ┃  ', trim($output)), "\n", '    ┗', "\n";
             Console\Cursor::colorize('foreground(normal)');
         }
         Console\Cursor::clear('↔');
         echo '  ', Console\Chrome\Text::colorize('✔︎', 'foreground(green)'), ' ', $status, "\n";
     }
     return;
 }
Beispiel #16
0
 /**
  * The entry method.
  *
  * @return  int
  */
 public function main()
 {
     $directories = [];
     $clean = false;
     $lang = 'En';
     while (false !== ($c = $this->getOption($v))) {
         switch ($c) {
             case 'd':
                 foreach ($this->parser->parseSpecialValue($v) as $directory) {
                     $directory = realpath($directory);
                     if (false === is_dir($directory)) {
                         throw new Console\Exception('Directory %s does not exist.', 0, $directory);
                     }
                     $directories[] = $directory;
                 }
                 break;
             case 'c':
                 $clean = true;
                 break;
             case 'l':
                 $lang = ucfirst(strtolower($v));
                 break;
             case '__ambiguous':
                 $this->resolveOptionAmbiguity($v);
                 break;
             case 'h':
             case '?':
             default:
                 return $this->usage();
         }
     }
     $workspace = resolve('hoa://Library/Devtools/Resource/Documentation') . DS . 'HackBook.output';
     if (true === $clean) {
         if (true === is_dir($workspace)) {
             $directory = new File\Directory($workspace);
             $directory->delete();
             unset($directory);
         }
         return;
     }
     clearstatcache(true);
     $workspace .= DS . $lang;
     if (false === is_dir($workspace)) {
         File\Directory::create($workspace);
     }
     Console\Cursor::colorize('foreground(yellow)');
     echo 'Selected language: ', $lang, '.', "\n\n";
     Console\Cursor::colorize('normal');
     require_once 'hoa://Library/Devtools/Resource/Documentation/Router.php';
     // $router is defined.
     $finder = new File\Finder();
     foreach ($directories as $location) {
         $_location = $location . DS . 'Documentation' . DS . $lang;
         if (false === is_dir($_location)) {
             throw new Console\Exception('Directory %s does not contain documentation.', 1, $location);
         }
         $finder->in($_location);
     }
     foreach (resolve('hoa://Library', true, true) as $location) {
         $libraryFinder = new File\Finder();
         $libraryFinder->in($location)->directories()->maxDepth(1);
         foreach ($libraryFinder as $_location) {
             $_location = $_location->getPathName() . DS . 'Documentation' . DS . $lang;
             if (true === is_dir($_location)) {
                 $finder->in($_location);
             }
         }
     }
     $vendors = [];
     foreach ($finder as $entry) {
         $path = dirname(dirname($entry->getPath()));
         $vendor = ucfirst(strtolower(basename(dirname($path))));
         $library = ucfirst(strtolower(basename($path)));
         if (!isset($vendors[$vendor])) {
             $vendors[$vendor] = [];
         }
         $vendors[$vendor][$library] = ['library' => $library, 'vendor' => $vendor, 'fullname' => $vendor . '\\' . $library];
     }
     foreach ($vendors as $vendor => &$libraries) {
         $libraries = array_values($libraries);
     }
     $layout = new File\Read('hoa://Library/Devtools/Resource/Documentation/Layout.xyl');
     $xyl = new Xyl($layout, new File\Write($workspace . '/index.html'), new Xyl\Interpreter\Html(), $router);
     $xyl->setTheme('');
     $data = $xyl->getData();
     foreach ($vendors as $vendor => $libraries) {
         $data->vendors->vendor = ['name' => $vendor, 'library' => $libraries];
     }
     $xyl->addOverlay('hoa://Library/Devtools/Resource/Documentation/Index.xyl');
     $xyl->render();
     echo 'Generate', "\t";
     Console\Cursor::colorize('foreground(green)');
     echo 'index.html';
     Console\Cursor::colorize('normal');
     echo '.', "\n";
     $xyl = null;
     foreach ($vendors as $vendor => $libraries) {
         File\Directory::create($workspace . dirname($router->unroute('full', ['vendor' => $libraries[0]['vendor'], 'chapter' => $libraries[0]['library']])));
         foreach ($libraries as $library) {
             $in = 'hoa://Library/' . $library['library'] . '/Documentation/' . $lang . '/Index.xyl';
             $out = $workspace . $router->unroute('full', ['vendor' => $library['vendor'], 'chapter' => $library['library']]);
             if (true === file_exists($out) && filemtime($in) <= filemtime($out)) {
                 echo 'Skip', "\t\t";
                 Console\Cursor::colorize('foreground(green)');
                 echo $library['fullname'];
                 Console\Cursor::colorize('normal');
                 echo '.', "\n";
                 continue;
             }
             $out = new File\Write($out);
             $out->truncate(0);
             if (null === $xyl) {
                 $xyl = new Xyl($layout, $out, new Xyl\Interpreter\Html(), $router);
                 $xyl->setTheme('');
                 $xyl->addOverlay('hoa://Library/Devtools/Resource/Documentation/Chapter.xyl');
             } else {
                 $xyl->setOutputStream(new File\Write($out));
             }
             $xyl->addOverlay($in);
             $xyl->getData()->name[0] = $library['fullname'];
             $xyl->getData()->library[0] = $library['library'];
             try {
                 $xyl->render();
             } catch (\Exception $e) {
                 echo $e->getMessage(), "\n";
             }
             $xyl->removeOverlay($in);
             echo 'Generate', "\t";
             Console\Cursor::colorize('foreground(green)');
             echo $library['fullname'];
             Console\Cursor::colorize('normal');
             echo '.', "\n";
         }
     }
     echo "\n", 'Open file://', $workspace, '/index.html', '.', "\n";
     return;
 }
Beispiel #17
0
 /**
  * Tab binding.
  *
  * @access  public
  * @param   Readline  $self    Self.
  * @return  int
  */
 public function _bindTab(Readline $self)
 {
     $autocompleter = $self->getAutocompleter();
     $state = static::STATE_CONTINUE | static::STATE_NO_ECHO;
     if (null === $autocompleter) {
         return $state;
     }
     $current = $self->getLineCurrent();
     $line = $self->getLine();
     // we need at least 1 char to work with
     // and if it's the start of a line, we'll echo it.
     if (0 === $current || trim($line) === '') {
         $this->appendLine("\t");
         $this->_buffer .= "\t";
         return static::STATE_CONTINUE;
     }
     $matches = preg_match_all('#' . $autocompleter->getWordDefinition() . '#u', $line, $words, PREG_OFFSET_CAPTURE);
     if (0 === $matches) {
         return $state;
     }
     for ($i = 0, $max = count($words[1]); $i < $max && $current > $words[1][$i][1]; ++$i) {
     }
     $word = $words[1][$i - 1];
     if ('' === trim($word[0])) {
         return $state;
     }
     $prefix = mb_substr($word[0], 0, $current - $word[1]);
     //Debug::log('prefix', compact('line','current','words','word','prefix'));
     $solution = $autocompleter->complete($prefix);
     #Debug::log('solution', $solution);
     if (null === $solution || empty($solution)) {
         return $state;
     }
     if (preg_match('/[\\S]+([\\W]+)([\\S]*)/', $prefix, $m, PREG_OFFSET_CAPTURE)) {
         #Debug::log('matchPrefix', compact('prefix', 'm'));
         $suffixLength = mb_strlen($m[2][0]);
         $prefix = mb_substr($prefix, -$suffixLength);
         $tail = mb_substr($line, $current);
         $head = mb_substr($line, 0, $current - $suffixLength);
         $line = $head . $tail;
         $current -= $suffixLength;
         $length = $suffixLength;
     } else {
         $length = mb_strlen($prefix);
         $tail = mb_substr($line, $current);
         $head = mb_substr($line, 0, $current - $length);
         $line = $head . $tail;
         $current -= $length;
     }
     #Debug::log('completionSetup', compact('prefix','line','current','head','tail','length'));
     if (is_array($solution)) {
         if (count($solution) === 1) {
             $line = $head . $solution[0] . $tail;
             $self->setLine($line);
             $self->setLineCurrent($current + mb_strlen($solution[0]));
             $self->setBuffer($line);
             Cursor::move('left', $length);
             echo $solution[0];
             Cursor::clear('right');
             echo $tail;
             Cursor::move('left', mb_strlen($tail));
             #Debug::log('completion', array(
             #  'line'    =>$self->getLine(),
             #  'current' =>$self->getLineCurrent(),
             #  'buffer'  =>$self->getBuffer(),
             #));
             return $state;
         }
         $_solution = $solution;
         $window = Window::getSize();
         $cursor = Cursor::getPosition();
         $wWidth = $window['x'];
         while (1) {
             $count = count($_solution) - 1;
             $cWidth = 0;
             array_walk($_solution, function ($value) use(&$cWidth) {
                 $handle = mb_strlen($value);
                 if ($handle > $cWidth) {
                     $cWidth = $handle;
                 }
             });
             array_walk($_solution, function (&$value) use($cWidth) {
                 $handle = mb_strlen($value);
                 if ($handle < $cWidth) {
                     $value .= str_repeat(' ', $cWidth - $handle);
                 }
             });
             $mColumns = (int) floor($wWidth / ($cWidth + 2));
             $mLines = (int) ceil(($count + 1) / $mColumns);
             --$mColumns;
             if ($mLines >= $window['y']) {
                 $toRemove = ($mLines - $window['y']) * $mColumns + 1;
                 for ($i = 0; $i < $toRemove; $i++) {
                     array_pop($_solution);
                 }
             } else {
                 break;
             }
         }
         $pos = Cursor::getPosition();
         if ($window['y'] - $cursor['y'] - $mLines < 0) {
             echo str_repeat("\n", $mLines + 1);
             Cursor::move('up', $mLines + 1);
             Cursor::clear('LEFT');
             echo $this->getPrefix() . $this->getLine() . "\n";
             Cursor::move('up LEFT');
             Cursor::move('right', $pos['x'] - 1);
         }
         Cursor::save();
         Cursor::hide();
         Cursor::move('down LEFT');
         Cursor::clear('down');
         $i = 0;
         foreach ($_solution as $j => $s) {
             echo "", $s, "";
             if ($i++ < $mColumns) {
                 echo '  ';
             } else {
                 $i = 0;
                 if (isset($_solution[$j + 1])) {
                     echo "\n";
                 }
             }
         }
         Cursor::restore();
         Cursor::show();
         ++$mColumns;
         $read = array(STDIN);
         $mColumn = -1;
         $mLine = -1;
         $coord = -1;
         $unselect = function () use(&$mColumn, &$mLine, &$coord, &$_solution, &$cWidth) {
             Cursor::save();
             Cursor::hide();
             Cursor::move('down LEFT');
             Cursor::move('right', $mColumn * ($cWidth + 2));
             Cursor::move('down', $mLine);
             echo "" . $_solution[$coord] . "";
             Cursor::restore();
             Cursor::show();
         };
         $select = function () use(&$mColumn, &$mLine, &$coord, &$_solution, &$cWidth) {
             Cursor::save();
             Cursor::hide();
             Cursor::move('down LEFT');
             Cursor::move('right', $mColumn * ($cWidth + 2));
             Cursor::move('down', $mLine);
             echo "" . $_solution[$coord] . "";
             Cursor::restore();
             Cursor::show();
         };
         $init = function () use(&$mColumn, &$mLine, &$coord, &$select) {
             $mColumn = 0;
             $mLine = 0;
             $coord = 0;
             $select();
         };
         while (true) {
             @stream_select($read, $write, $except, 30, 0);
             if (empty($read)) {
                 $read = array(STDIN);
                 continue;
             }
             switch ($char = $self->_read()) {
                 case "":
                     if (-1 === $mColumn && -1 === $mLine) {
                         $init();
                         break;
                     }
                     $unselect();
                     $coord = max(0, $coord - $mColumns);
                     $mLine = (int) floor($coord / $mColumns);
                     $mColumn = $coord % $mColumns;
                     $select();
                     break;
                 case "":
                     if (-1 === $mColumn && -1 === $mLine) {
                         $init();
                         break;
                     }
                     $unselect();
                     $coord = min($count, $coord + $mColumns);
                     $mLine = (int) floor($coord / $mColumns);
                     $mColumn = $coord % $mColumns;
                     $select();
                     break;
                 case "\t":
                 case "":
                     if (-1 === $mColumn && -1 === $mLine) {
                         $init();
                         break;
                     }
                     $unselect();
                     $coord = min($count, $coord + 1);
                     $mLine = (int) floor($coord / $mColumns);
                     $mColumn = $coord % $mColumns;
                     $select();
                     break;
                 case "":
                     if (-1 === $mColumn && -1 === $mLine) {
                         $init();
                         break;
                     }
                     $unselect();
                     $coord = max(0, $coord - 1);
                     $mLine = (int) floor($coord / $mColumns);
                     $mColumn = $coord % $mColumns;
                     $select();
                     break;
                 case "\n":
                     if (-1 !== $mColumn && -1 !== $mLine) {
                         $self->setLine($head . $solution[$coord] . $tail);
                         $self->setLineCurrent($current + mb_strlen($solution[$coord]));
                         Cursor::move('left', $length);
                         echo $solution[$coord];
                         Cursor::clear('right');
                         echo $tail;
                         Cursor::move('left', mb_strlen($tail));
                     }
                 default:
                     $mColumn = -1;
                     $mLine = -1;
                     $coord = -1;
                     Cursor::save();
                     Cursor::move('down LEFT');
                     Cursor::clear('down');
                     Cursor::restore();
                     if ("" !== $char && "\n" !== $char) {
                         $self->setBuffer($char);
                         return $self->_readLine($char);
                     }
                     break 2;
             }
         }
         return $state;
     }
 }