初始化项目

This commit is contained in:
2016-06-21 17:12:08 +08:00
commit 7ea154d684
903 changed files with 226100 additions and 0 deletions

View File

@@ -0,0 +1,196 @@
<?php
// +----------------------------------------------------------------------
// | ThinkPHP [ WE CAN DO IT JUST THINK ]
// +----------------------------------------------------------------------
// | Copyright (c) 2006~2015 http://thinkphp.cn All rights reserved.
// +----------------------------------------------------------------------
// | Licensed ( http://www.apache.org/licenses/LICENSE-2.0 )
// +----------------------------------------------------------------------
// | Author: yunwuxin <448901948@qq.com>
// +----------------------------------------------------------------------
namespace think\console\output;
use think\console\output\formatter\Style;
use think\console\output\formatter\Stack as StyleStack;
class Formatter
{
private $decorated = false;
private $styles = [];
private $styleStack;
/**
* 转义
* @param string $text
* @return string
*/
public static function escape($text)
{
return preg_replace('/([^\\\\]?)</is', '$1\\<', $text);
}
/**
* 初始化命令行输出格式
*/
public function __construct()
{
$this->setStyle('error', new Style('white', 'red'));
$this->setStyle('info', new Style('green'));
$this->setStyle('comment', new Style('yellow'));
$this->setStyle('question', new Style('black', 'cyan'));
$this->styleStack = new StyleStack();
}
/**
* 设置外观标识
* @param bool $decorated 是否美化文职
*/
public function setDecorated($decorated)
{
$this->decorated = (bool)$decorated;
}
/**
* 获取外观标识
* @return bool
*/
public function isDecorated()
{
return $this->decorated;
}
/**
* 添加一个新样式
* @param string $name 样式名
* @param Style $style 样式实例
*/
public function setStyle($name, Style $style)
{
$this->styles[strtolower($name)] = $style;
}
/**
* 是否有这个样式
* @param string $name
* @return bool
*/
public function hasStyle($name)
{
return isset($this->styles[strtolower($name)]);
}
/**
* 获取样式
* @param string $name
* @return Style
* @throws \InvalidArgumentException
*/
public function getStyle($name)
{
if (!$this->hasStyle($name)) {
throw new \InvalidArgumentException(sprintf('Undefined style: %s', $name));
}
return $this->styles[strtolower($name)];
}
/**
* 使用所给的样式格式化文字
* @param string $message 文字
* @return string
*/
public function format($message)
{
$offset = 0;
$output = '';
$tagRegex = '[a-z][a-z0-9_=;-]*';
preg_match_all("#<(($tagRegex) | /($tagRegex)?)>#isx", $message, $matches, PREG_OFFSET_CAPTURE);
foreach ($matches[0] as $i => $match) {
$pos = $match[1];
$text = $match[0];
if (0 != $pos && '\\' == $message[$pos - 1]) {
continue;
}
$output .= $this->applyCurrentStyle(substr($message, $offset, $pos - $offset));
$offset = $pos + strlen($text);
if ($open = '/' != $text[1]) {
$tag = $matches[1][$i][0];
} else {
$tag = isset($matches[3][$i][0]) ? $matches[3][$i][0] : '';
}
if (!$open && !$tag) {
// </>
$this->styleStack->pop();
} elseif (false === $style = $this->createStyleFromString(strtolower($tag))) {
$output .= $this->applyCurrentStyle($text);
} elseif ($open) {
$this->styleStack->push($style);
} else {
$this->styleStack->pop($style);
}
}
$output .= $this->applyCurrentStyle(substr($message, $offset));
return str_replace('\\<', '<', $output);
}
/**
* @return StyleStack
*/
public function getStyleStack()
{
return $this->styleStack;
}
/**
* 根据字符串创建新的样式实例
* @param string $string
* @return Style|bool
*/
private function createStyleFromString($string)
{
if (isset($this->styles[$string])) {
return $this->styles[$string];
}
if (!preg_match_all('/([^=]+)=([^;]+)(;|$)/', strtolower($string), $matches, PREG_SET_ORDER)) {
return false;
}
$style = new Style();
foreach ($matches as $match) {
array_shift($match);
if ('fg' == $match[0]) {
$style->setForeground($match[1]);
} elseif ('bg' == $match[0]) {
$style->setBackground($match[1]);
} else {
try {
$style->setOption($match[1]);
} catch (\InvalidArgumentException $e) {
return false;
}
}
}
return $style;
}
/**
* 从堆栈应用样式到文字
* @param string $text 文字
* @return string
*/
private function applyCurrentStyle($text)
{
return $this->isDecorated() && strlen($text) > 0 ? $this->styleStack->getCurrent()->apply($text) : $text;
}
}

View File

@@ -0,0 +1,108 @@
<?php
// +----------------------------------------------------------------------
// | ThinkPHP [ WE CAN DO IT JUST THINK ]
// +----------------------------------------------------------------------
// | Copyright (c) 2006~2015 http://thinkphp.cn All rights reserved.
// +----------------------------------------------------------------------
// | Licensed ( http://www.apache.org/licenses/LICENSE-2.0 )
// +----------------------------------------------------------------------
// | Author: yunwuxin <448901948@qq.com>
// +----------------------------------------------------------------------
namespace think\console\output;
use think\console\Output;
class Nothing extends Output
{
/** @noinspection PhpMissingParentConstructorInspection */
public function __construct()
{
}
/**
* {@inheritdoc}
*/
public function setFormatter(Formatter $formatter)
{
// do nothing
}
/**
* {@inheritdoc}
*/
public function getFormatter()
{
// to comply with the interface we must return a OutputFormatterInterface
return new Formatter();
}
/**
* {@inheritdoc}
*/
public function setDecorated($decorated)
{
// do nothing
}
/**
* {@inheritdoc}
*/
public function isDecorated()
{
return false;
}
/**
* {@inheritdoc}
*/
public function setVerbosity($level)
{
// do nothing
}
/**
* {@inheritdoc}
*/
public function getVerbosity()
{
return self::VERBOSITY_QUIET;
}
public function isQuiet()
{
return true;
}
public function isVerbose()
{
return false;
}
public function isVeryVerbose()
{
return false;
}
public function isDebug()
{
return false;
}
/**
* {@inheritdoc}
*/
public function writeln($messages, $options = self::OUTPUT_NORMAL)
{
// do nothing
}
/**
* {@inheritdoc}
*/
public function write($messages, $newline = false, $options = self::OUTPUT_NORMAL)
{
// do nothing
}
}

View File

@@ -0,0 +1,189 @@
<?php
// +----------------------------------------------------------------------
// | ThinkPHP [ WE CAN DO IT JUST THINK ]
// +----------------------------------------------------------------------
// | Copyright (c) 2006~2015 http://thinkphp.cn All rights reserved.
// +----------------------------------------------------------------------
// | Licensed ( http://www.apache.org/licenses/LICENSE-2.0 )
// +----------------------------------------------------------------------
// | Author: yunwuxin <448901948@qq.com>
// +----------------------------------------------------------------------
namespace think\console\output;
class Stream
{
const VERBOSITY_QUIET = 0;
const VERBOSITY_NORMAL = 1;
const VERBOSITY_VERBOSE = 2;
const VERBOSITY_VERY_VERBOSE = 3;
const VERBOSITY_DEBUG = 4;
const OUTPUT_NORMAL = 0;
const OUTPUT_RAW = 1;
const OUTPUT_PLAIN = 2;
private $verbosity = self::VERBOSITY_NORMAL;
private $formatter;
private $stream;
/**
* 构造方法
*/
public function __construct($stream, Formatter $formatter = null)
{
if (!is_resource($stream) || 'stream' !== get_resource_type($stream)) {
throw new \InvalidArgumentException('The StreamOutput class needs a stream as its first argument.');
}
$this->stream = $stream;
$decorated = $this->hasColorSupport();
$this->formatter = $formatter ?: new Formatter();
$this->formatter->setDecorated($decorated);
}
/**
* {@inheritdoc}
*/
public function setFormatter(Formatter $formatter)
{
$this->formatter = $formatter;
}
/**
* {@inheritdoc}
*/
public function getFormatter()
{
return $this->formatter;
}
/**
* {@inheritdoc}
*/
public function setDecorated($decorated)
{
$this->formatter->setDecorated($decorated);
}
/**
* {@inheritdoc}
*/
public function isDecorated()
{
return $this->formatter->isDecorated();
}
/**
* {@inheritdoc}
*/
public function setVerbosity($level)
{
$this->verbosity = (int)$level;
}
/**
* {@inheritdoc}
*/
public function getVerbosity()
{
return $this->verbosity;
}
public function isQuiet()
{
return self::VERBOSITY_QUIET === $this->verbosity;
}
public function isVerbose()
{
return self::VERBOSITY_VERBOSE <= $this->verbosity;
}
public function isVeryVerbose()
{
return self::VERBOSITY_VERY_VERBOSE <= $this->verbosity;
}
public function isDebug()
{
return self::VERBOSITY_DEBUG <= $this->verbosity;
}
/**
* {@inheritdoc}
*/
public function writeln($messages, $type = self::OUTPUT_NORMAL)
{
$this->write($messages, true, $type);
}
/**
* {@inheritdoc}
*/
public function write($messages, $newline = false, $type = self::OUTPUT_NORMAL)
{
if (self::VERBOSITY_QUIET === $this->verbosity) {
return;
}
$messages = (array)$messages;
foreach ($messages as $message) {
switch ($type) {
case self::OUTPUT_NORMAL:
$message = $this->formatter->format($message);
break;
case self::OUTPUT_RAW:
break;
case self::OUTPUT_PLAIN:
$message = strip_tags($this->formatter->format($message));
break;
default:
throw new \InvalidArgumentException(sprintf('Unknown output type given (%s)', $type));
}
$this->doWrite($message, $newline);
}
}
/**
* 将消息写入到输出。
* @param string $message 消息
* @param bool $newline 是否另起一行
*/
protected function doWrite($message, $newline)
{
if (false === @fwrite($this->stream, $message . ($newline ? PHP_EOL : ''))) {
throw new \RuntimeException('Unable to write output.');
}
fflush($this->stream);
}
/**
* @return resource
*/
public function getStream()
{
return $this->stream;
}
/**
* 是否支持着色
* @return bool
*/
protected function hasColorSupport()
{
if (DIRECTORY_SEPARATOR == '\\') {
return false !== getenv('ANSICON') || 'ON' === getenv('ConEmuANSI');
}
return function_exists('posix_isatty') && @posix_isatty($this->stream);
}
}

View File

@@ -0,0 +1,116 @@
<?php
// +----------------------------------------------------------------------
// | ThinkPHP [ WE CAN DO IT JUST THINK ]
// +----------------------------------------------------------------------
// | Copyright (c) 2006~2015 http://thinkphp.cn All rights reserved.
// +----------------------------------------------------------------------
// | Licensed ( http://www.apache.org/licenses/LICENSE-2.0 )
// +----------------------------------------------------------------------
// | Author: yunwuxin <448901948@qq.com>
// +----------------------------------------------------------------------
namespace think\console\output\formatter;
class Stack
{
/**
* @var Style[]
*/
private $styles;
/**
* @var Style
*/
private $emptyStyle;
/**
* 构造方法
* @param Style|null $emptyStyle
*/
public function __construct(Style $emptyStyle = null)
{
$this->emptyStyle = $emptyStyle ?: new Style();
$this->reset();
}
/**
* 重置堆栈
*/
public function reset()
{
$this->styles = [];
}
/**
* 推一个样式进入堆栈
* @param Style $style
*/
public function push(Style $style)
{
$this->styles[] = $style;
}
/**
* 从堆栈中弹出一个样式
* @param Style|null $style
* @return Style
* @throws \InvalidArgumentException
*/
public function pop(Style $style = null)
{
if (empty($this->styles)) {
return $this->emptyStyle;
}
if (null === $style) {
return array_pop($this->styles);
}
/**
* @var int $index
* @var Style $stackedStyle
*/
foreach (array_reverse($this->styles, true) as $index => $stackedStyle) {
if ($style->apply('') === $stackedStyle->apply('')) {
$this->styles = array_slice($this->styles, 0, $index);
return $stackedStyle;
}
}
throw new \InvalidArgumentException('Incorrectly nested style tag found.');
}
/**
* 计算堆栈的当前样式。
* @return Style
*/
public function getCurrent()
{
if (empty($this->styles)) {
return $this->emptyStyle;
}
return $this->styles[count($this->styles) - 1];
}
/**
* @param Style $emptyStyle
* @return Stack
*/
public function setEmptyStyle(Style $emptyStyle)
{
$this->emptyStyle = $emptyStyle;
return $this;
}
/**
* @return Style
*/
public function getEmptyStyle()
{
return $this->emptyStyle;
}
}

View File

@@ -0,0 +1,189 @@
<?php
// +----------------------------------------------------------------------
// | ThinkPHP [ WE CAN DO IT JUST THINK ]
// +----------------------------------------------------------------------
// | Copyright (c) 2006~2015 http://thinkphp.cn All rights reserved.
// +----------------------------------------------------------------------
// | Licensed ( http://www.apache.org/licenses/LICENSE-2.0 )
// +----------------------------------------------------------------------
// | Author: yunwuxin <448901948@qq.com>
// +----------------------------------------------------------------------
namespace think\console\output\formatter;
class Style
{
private static $availableForegroundColors = [
'black' => ['set' => 30, 'unset' => 39],
'red' => ['set' => 31, 'unset' => 39],
'green' => ['set' => 32, 'unset' => 39],
'yellow' => ['set' => 33, 'unset' => 39],
'blue' => ['set' => 34, 'unset' => 39],
'magenta' => ['set' => 35, 'unset' => 39],
'cyan' => ['set' => 36, 'unset' => 39],
'white' => ['set' => 37, 'unset' => 39],
];
private static $availableBackgroundColors = [
'black' => ['set' => 40, 'unset' => 49],
'red' => ['set' => 41, 'unset' => 49],
'green' => ['set' => 42, 'unset' => 49],
'yellow' => ['set' => 43, 'unset' => 49],
'blue' => ['set' => 44, 'unset' => 49],
'magenta' => ['set' => 45, 'unset' => 49],
'cyan' => ['set' => 46, 'unset' => 49],
'white' => ['set' => 47, 'unset' => 49],
];
private static $availableOptions = [
'bold' => ['set' => 1, 'unset' => 22],
'underscore' => ['set' => 4, 'unset' => 24],
'blink' => ['set' => 5, 'unset' => 25],
'reverse' => ['set' => 7, 'unset' => 27],
'conceal' => ['set' => 8, 'unset' => 28],
];
private $foreground;
private $background;
private $options = [];
/**
* 初始化输出的样式
* @param string|null $foreground 字体颜色
* @param string|null $background 背景色
* @param array $options 格式
* @api
*/
public function __construct($foreground = null, $background = null, array $options = [])
{
if (null !== $foreground) {
$this->setForeground($foreground);
}
if (null !== $background) {
$this->setBackground($background);
}
if (count($options)) {
$this->setOptions($options);
}
}
/**
* 设置字体颜色
* @param string|null $color 颜色名
* @throws \InvalidArgumentException
* @api
*/
public function setForeground($color = null)
{
if (null === $color) {
$this->foreground = null;
return;
}
if (!isset(static::$availableForegroundColors[$color])) {
throw new \InvalidArgumentException(sprintf('Invalid foreground color specified: "%s". Expected one of (%s)', $color, implode(', ', array_keys(static::$availableForegroundColors))));
}
$this->foreground = static::$availableForegroundColors[$color];
}
/**
* 设置背景色
* @param string|null $color 颜色名
* @throws \InvalidArgumentException
* @api
*/
public function setBackground($color = null)
{
if (null === $color) {
$this->background = null;
return;
}
if (!isset(static::$availableBackgroundColors[$color])) {
throw new \InvalidArgumentException(sprintf('Invalid background color specified: "%s". Expected one of (%s)', $color, implode(', ', array_keys(static::$availableBackgroundColors))));
}
$this->background = static::$availableBackgroundColors[$color];
}
/**
* 设置字体格式
* @param string $option 格式名
* @throws \InvalidArgumentException When the option name isn't defined
* @api
*/
public function setOption($option)
{
if (!isset(static::$availableOptions[$option])) {
throw new \InvalidArgumentException(sprintf('Invalid option specified: "%s". Expected one of (%s)', $option, implode(', ', array_keys(static::$availableOptions))));
}
if (!in_array(static::$availableOptions[$option], $this->options)) {
$this->options[] = static::$availableOptions[$option];
}
}
/**
* 重置字体格式
* @param string $option 格式名
* @throws \InvalidArgumentException
*/
public function unsetOption($option)
{
if (!isset(static::$availableOptions[$option])) {
throw new \InvalidArgumentException(sprintf('Invalid option specified: "%s". Expected one of (%s)', $option, implode(', ', array_keys(static::$availableOptions))));
}
$pos = array_search(static::$availableOptions[$option], $this->options);
if (false !== $pos) {
unset($this->options[$pos]);
}
}
/**
* 批量设置字体格式
* @param array $options
*/
public function setOptions(array $options)
{
$this->options = [];
foreach ($options as $option) {
$this->setOption($option);
}
}
/**
* 应用样式到文字
* @param string $text 文字
* @return string
*/
public function apply($text)
{
$setCodes = [];
$unsetCodes = [];
if (null !== $this->foreground) {
$setCodes[] = $this->foreground['set'];
$unsetCodes[] = $this->foreground['unset'];
}
if (null !== $this->background) {
$setCodes[] = $this->background['set'];
$unsetCodes[] = $this->background['unset'];
}
if (count($this->options)) {
foreach ($this->options as $option) {
$setCodes[] = $option['set'];
$unsetCodes[] = $option['unset'];
}
}
if (0 === count($setCodes)) {
return $text;
}
return sprintf("\033[%sm%s\033[%sm", implode(';', $setCodes), $text, implode(';', $unsetCodes));
}
}