Initial commit
This commit is contained in:
commit
eee44b2ada
9 changed files with 3901 additions and 0 deletions
93
.gitignore
vendored
Normal file
93
.gitignore
vendored
Normal file
|
|
@ -0,0 +1,93 @@
|
||||||
|
|
||||||
|
# Created by https://www.gitignore.io/api/vim,macos,linux,windows,composer,phpcodesniffer
|
||||||
|
|
||||||
|
### Composer ###
|
||||||
|
*.phar
|
||||||
|
/vendor/
|
||||||
|
|
||||||
|
# Commit your application's lock file http://getcomposer.org/doc/01-basic-usage.md#composer-lock-the-lock-file
|
||||||
|
# You may choose to ignore a library lock file http://getcomposer.org/doc/02-libraries.md#lock-file
|
||||||
|
# composer.lock
|
||||||
|
|
||||||
|
### Linux ###
|
||||||
|
*~
|
||||||
|
|
||||||
|
# temporary files which can be created if a process still has a handle open of a deleted file
|
||||||
|
.fuse_hidden*
|
||||||
|
|
||||||
|
# KDE directory preferences
|
||||||
|
.directory
|
||||||
|
|
||||||
|
# Linux trash folder which might appear on any partition or disk
|
||||||
|
.Trash-*
|
||||||
|
|
||||||
|
# .nfs files are created when an open file is removed but is still being accessed
|
||||||
|
.nfs*
|
||||||
|
|
||||||
|
### macOS ###
|
||||||
|
*.DS_Store
|
||||||
|
.AppleDouble
|
||||||
|
.LSOverride
|
||||||
|
|
||||||
|
# Icon must end with two \r
|
||||||
|
Icon
|
||||||
|
|
||||||
|
# Thumbnails
|
||||||
|
._*
|
||||||
|
|
||||||
|
# Files that might appear in the root of a volume
|
||||||
|
.DocumentRevisions-V100
|
||||||
|
.fseventsd
|
||||||
|
.Spotlight-V100
|
||||||
|
.TemporaryItems
|
||||||
|
.Trashes
|
||||||
|
.VolumeIcon.icns
|
||||||
|
.com.apple.timemachine.donotpresent
|
||||||
|
|
||||||
|
# Directories potentially created on remote AFP share
|
||||||
|
.AppleDB
|
||||||
|
.AppleDesktop
|
||||||
|
Network Trash Folder
|
||||||
|
Temporary Items
|
||||||
|
.apdisk
|
||||||
|
|
||||||
|
### PHPCodeSniffer ###
|
||||||
|
# CodeSniffer
|
||||||
|
|
||||||
|
/vendor/*
|
||||||
|
/wpcs/*
|
||||||
|
|
||||||
|
### Vim ###
|
||||||
|
# swap
|
||||||
|
.sw[a-p]
|
||||||
|
.*.sw[a-p]
|
||||||
|
# session
|
||||||
|
Session.vim
|
||||||
|
# temporary
|
||||||
|
.netrwhist
|
||||||
|
# auto-generated tag files
|
||||||
|
tags
|
||||||
|
|
||||||
|
### Windows ###
|
||||||
|
# Windows thumbnail cache files
|
||||||
|
Thumbs.db
|
||||||
|
ehthumbs.db
|
||||||
|
ehthumbs_vista.db
|
||||||
|
|
||||||
|
# Folder config file
|
||||||
|
Desktop.ini
|
||||||
|
|
||||||
|
# Recycle Bin used on file shares
|
||||||
|
$RECYCLE.BIN/
|
||||||
|
|
||||||
|
# Windows Installer files
|
||||||
|
*.cab
|
||||||
|
*.msi
|
||||||
|
*.msm
|
||||||
|
*.msp
|
||||||
|
|
||||||
|
# Windows shortcuts
|
||||||
|
*.lnk
|
||||||
|
|
||||||
|
|
||||||
|
# End of https://www.gitignore.io/api/vim,macos,linux,windows,composer,phpcodesniffer
|
||||||
20
RoboFile.php
Normal file
20
RoboFile.php
Normal file
|
|
@ -0,0 +1,20 @@
|
||||||
|
<?php
|
||||||
|
/**
|
||||||
|
* This is project's console commands configuration for Robo task runner.
|
||||||
|
*
|
||||||
|
* @see http://robo.li/
|
||||||
|
*/
|
||||||
|
class RoboFile extends \Robo\Tasks
|
||||||
|
{
|
||||||
|
// define public methods as commands
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @command my-project:command-one
|
||||||
|
*/
|
||||||
|
function hello()
|
||||||
|
{
|
||||||
|
$this->io()->title("Build all site assets");
|
||||||
|
$this->taskExec('ls')->run();
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
14
bin/bootstrap.php
Normal file
14
bin/bootstrap.php
Normal file
|
|
@ -0,0 +1,14 @@
|
||||||
|
<?php
|
||||||
|
|
||||||
|
set_time_limit(0);
|
||||||
|
|
||||||
|
$autoLoaders = [
|
||||||
|
__DIR__.'/../vendor/autoload.php',
|
||||||
|
__DIR__.'/../../../autoload.php'
|
||||||
|
];
|
||||||
|
|
||||||
|
foreach ($autoLoaders as $loader) {
|
||||||
|
if (is_file($loader)) {
|
||||||
|
include_once $loader;
|
||||||
|
}
|
||||||
|
}
|
||||||
10
bin/build-phar
Executable file
10
bin/build-phar
Executable file
|
|
@ -0,0 +1,10 @@
|
||||||
|
#!/usr/bin/env php
|
||||||
|
<?php
|
||||||
|
|
||||||
|
require __DIR__.'/bootstrap.php';
|
||||||
|
|
||||||
|
use pgrep\Compiler;
|
||||||
|
|
||||||
|
$compiler = new Compiler;
|
||||||
|
$compiler->compile();
|
||||||
|
|
||||||
15
bin/pgrep
Executable file
15
bin/pgrep
Executable file
|
|
@ -0,0 +1,15 @@
|
||||||
|
#!/usr/bin/env php
|
||||||
|
<?php
|
||||||
|
|
||||||
|
require __DIR__.'/bootstrap.php';
|
||||||
|
|
||||||
|
use pgrep\DefaultCommand;
|
||||||
|
use Symfony\Component\Console\Application;
|
||||||
|
|
||||||
|
$application = new Application('echo', '1.0.0');
|
||||||
|
$command = new DefaultCommand();
|
||||||
|
|
||||||
|
$application->add($command);
|
||||||
|
|
||||||
|
$application->setDefaultCommand($command->getName(), true);
|
||||||
|
$application->run();
|
||||||
32
composer.json
Normal file
32
composer.json
Normal file
|
|
@ -0,0 +1,32 @@
|
||||||
|
{
|
||||||
|
"name": "adeattwood/pgrep",
|
||||||
|
"require": {
|
||||||
|
"php": ">=7.0 <8.0",
|
||||||
|
"symfony/console": "^3.2",
|
||||||
|
"symfony/finder": "^3.4",
|
||||||
|
"consolidation/robo": "^1.2"
|
||||||
|
},
|
||||||
|
"require-dev": {
|
||||||
|
"codeception/codeception": "^2.2",
|
||||||
|
"codeception/specify": "^0.4.6",
|
||||||
|
"codeception/verify": "^0.3.3",
|
||||||
|
"squizlabs/php_codesniffer": "^2.8",
|
||||||
|
"symfony/var-dumper": "^3.2"
|
||||||
|
},
|
||||||
|
"authors": [
|
||||||
|
{
|
||||||
|
"name": "Ade Attwood",
|
||||||
|
"email": "code@adeattwood.co.uk",
|
||||||
|
"homepage": "http://adeattwood.co.uk",
|
||||||
|
"role": "Developer"
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"autoload": {
|
||||||
|
"psr-4": {
|
||||||
|
"pgrep\\": "src/"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"bin": [
|
||||||
|
"bin/pgrep"
|
||||||
|
]
|
||||||
|
}
|
||||||
3412
composer.lock
generated
Normal file
3412
composer.lock
generated
Normal file
File diff suppressed because it is too large
Load diff
132
src/Compiler.php
Normal file
132
src/Compiler.php
Normal file
|
|
@ -0,0 +1,132 @@
|
||||||
|
<?php
|
||||||
|
|
||||||
|
namespace pgrep;
|
||||||
|
|
||||||
|
use Symfony\Component\Finder\Finder;
|
||||||
|
|
||||||
|
class Compiler
|
||||||
|
{
|
||||||
|
public $name = 'pgrep.phar';
|
||||||
|
|
||||||
|
private $version;
|
||||||
|
private $branchAliasVersion = '';
|
||||||
|
private $versionDate;
|
||||||
|
|
||||||
|
private $basePath;
|
||||||
|
|
||||||
|
public function __construct()
|
||||||
|
{
|
||||||
|
$this->basePath = dirname(__DIR__).'/';
|
||||||
|
}
|
||||||
|
|
||||||
|
public function getFinder()
|
||||||
|
{
|
||||||
|
$finder = new Finder();
|
||||||
|
|
||||||
|
$finder->files()
|
||||||
|
->ignoreVCS(true)
|
||||||
|
->name('*.php')
|
||||||
|
->notName('Compiler.php')
|
||||||
|
->exclude('Tests')
|
||||||
|
->exclude('tests')
|
||||||
|
->exclude('docs')
|
||||||
|
->in($this->basePath.'src')
|
||||||
|
->in($this->basePath.'bin')
|
||||||
|
->in($this->basePath.'vendor/symfony')
|
||||||
|
->in($this->basePath.'vendor/composer');
|
||||||
|
|
||||||
|
return $finder;
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
public function getFiles()
|
||||||
|
{
|
||||||
|
return [
|
||||||
|
$this->basePath.'bin/pgrep',
|
||||||
|
$this->basePath.'vendor/autoload.php'
|
||||||
|
];
|
||||||
|
}
|
||||||
|
|
||||||
|
public function compile()
|
||||||
|
{
|
||||||
|
echo "Starting\n";
|
||||||
|
|
||||||
|
$phar = new \Phar($this->name, 0, $this->name);
|
||||||
|
$phar->setSignatureAlgorithm(\Phar::SHA1);
|
||||||
|
$phar->startBuffering();
|
||||||
|
|
||||||
|
foreach ($this->getFinder() as $file) {
|
||||||
|
$this->addFile($phar, $file);
|
||||||
|
}
|
||||||
|
|
||||||
|
foreach ($this->getFiles() as $file) {
|
||||||
|
$this->addFile($phar, $file);
|
||||||
|
}
|
||||||
|
|
||||||
|
$phar->setStub(<<<EOL
|
||||||
|
#!/usr/bin/env php
|
||||||
|
<?php
|
||||||
|
Phar::mapPhar();
|
||||||
|
require 'phar://{$this->name}/bin/pgrep';
|
||||||
|
__HALT_COMPILER();
|
||||||
|
EOL
|
||||||
|
);
|
||||||
|
|
||||||
|
|
||||||
|
$phar->stopBuffering();
|
||||||
|
}
|
||||||
|
|
||||||
|
public function addFile($phar, $file)
|
||||||
|
{
|
||||||
|
if (is_string($file)) {
|
||||||
|
$file = new \SplFileInfo($file);
|
||||||
|
}
|
||||||
|
|
||||||
|
$path = str_replace($this->basePath, '', $file->getRealPath());
|
||||||
|
|
||||||
|
echo "Adding {$path}\n";
|
||||||
|
|
||||||
|
$content = file_get_contents($file->getRealPath());
|
||||||
|
$content = preg_replace('{^#!/usr/bin/env php\s*}', '', $content);
|
||||||
|
$content = $this->stripWhitespace($content);
|
||||||
|
|
||||||
|
$phar->addFromString($path, $content);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Removes whitespace from a PHP source string while preserving line numbers.
|
||||||
|
*
|
||||||
|
* @param string $source A PHP string
|
||||||
|
*
|
||||||
|
* @return string The PHP string with the whitespace removed
|
||||||
|
*/
|
||||||
|
public function stripWhitespace($source)
|
||||||
|
{
|
||||||
|
if (!function_exists('token_get_all')) {
|
||||||
|
return $source;
|
||||||
|
}
|
||||||
|
|
||||||
|
$output = '';
|
||||||
|
|
||||||
|
foreach (token_get_all($source) as $token) {
|
||||||
|
if (is_string($token)) {
|
||||||
|
$output .= $token;
|
||||||
|
} elseif (in_array($token[0], array(T_COMMENT, T_DOC_COMMENT))) {
|
||||||
|
$output .= str_repeat("\n", substr_count($token[1], "\n"));
|
||||||
|
} elseif (T_WHITESPACE === $token[0]) {
|
||||||
|
// reduce wide spaces
|
||||||
|
$whitespace = preg_replace('{[ \t]+}', ' ', $token[1]);
|
||||||
|
// normalize newlines to \n
|
||||||
|
$whitespace = preg_replace('{(?:\r\n|\r|\n)}', "\n", $whitespace);
|
||||||
|
// trim leading spaces
|
||||||
|
$whitespace = preg_replace('{\n +}', "\n", $whitespace);
|
||||||
|
$output .= $whitespace;
|
||||||
|
} else {
|
||||||
|
$output .= $token[1];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return $output;
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
173
src/DefaultCommand.php
Normal file
173
src/DefaultCommand.php
Normal file
|
|
@ -0,0 +1,173 @@
|
||||||
|
<?php
|
||||||
|
|
||||||
|
namespace pgrep;
|
||||||
|
|
||||||
|
use Symfony\Component\Console\Input\InputArgument;
|
||||||
|
use Symfony\Component\Console\Input\InputInterface;
|
||||||
|
use Symfony\Component\Console\Input\InputOption;
|
||||||
|
use Symfony\Component\Console\Output\OutputInterface;
|
||||||
|
use Symfony\Component\Finder\Finder;
|
||||||
|
use Exception;
|
||||||
|
|
||||||
|
class DefaultCommand extends \Symfony\Component\Console\Command\Command
|
||||||
|
{
|
||||||
|
|
||||||
|
public $count = 0;
|
||||||
|
|
||||||
|
public $outputTemplate = '{file}:{lineNumber} {line}';
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Sets the name, help, options and arguments for the command
|
||||||
|
*
|
||||||
|
* @return void
|
||||||
|
*/
|
||||||
|
protected function configure()
|
||||||
|
{
|
||||||
|
$options = [
|
||||||
|
[
|
||||||
|
'case-insensitive',
|
||||||
|
'i',
|
||||||
|
InputOption::VALUE_NONE,
|
||||||
|
'Case insensitive regex'
|
||||||
|
],
|
||||||
|
[
|
||||||
|
'count',
|
||||||
|
null,
|
||||||
|
InputOption::VALUE_NONE,
|
||||||
|
'Only print the total number of matches found'
|
||||||
|
],
|
||||||
|
[
|
||||||
|
'in',
|
||||||
|
null,
|
||||||
|
InputOption::VALUE_OPTIONAL | InputOption::VALUE_IS_ARRAY,
|
||||||
|
'Directory to find files in',
|
||||||
|
[getcwd()]
|
||||||
|
],
|
||||||
|
[
|
||||||
|
'size',
|
||||||
|
null,
|
||||||
|
InputOption::VALUE_OPTIONAL,
|
||||||
|
'A size range of files to look into'
|
||||||
|
],
|
||||||
|
[
|
||||||
|
'date',
|
||||||
|
null,
|
||||||
|
InputOption::VALUE_OPTIONAL,
|
||||||
|
'Date range to search in files. The date must be something that strtotime()'
|
||||||
|
],
|
||||||
|
[
|
||||||
|
'depth',
|
||||||
|
null,
|
||||||
|
InputOption::VALUE_OPTIONAL,
|
||||||
|
'The depth of directors to dive into'
|
||||||
|
],
|
||||||
|
];
|
||||||
|
|
||||||
|
$this->setName('pgrep')
|
||||||
|
->setDescription('Grep with php regex')
|
||||||
|
->addArgument('pattern', InputArgument::REQUIRED, 'The pattern to look for')
|
||||||
|
->setHelp('Search for php regex in files');
|
||||||
|
|
||||||
|
foreach ($options as $option) {
|
||||||
|
call_user_func_array([$this, 'addOption'], $option);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Runs the command
|
||||||
|
*
|
||||||
|
* @param InputInterface $input The interface implemented the symfony input class
|
||||||
|
* @param OutputInterface $output The interface implemented the symfony output class
|
||||||
|
*
|
||||||
|
* @return void
|
||||||
|
*/
|
||||||
|
protected function execute(InputInterface $input, OutputInterface $output)
|
||||||
|
{
|
||||||
|
$inputStream = $input->getStream() ?: STDIN;
|
||||||
|
stream_set_blocking($inputStream, 0);
|
||||||
|
$pipedInput = stream_get_contents($inputStream);
|
||||||
|
|
||||||
|
$pattern = '/'.$input->getArgument('pattern').'/';
|
||||||
|
|
||||||
|
if ($input->getOption('case-insensitive') === true) {
|
||||||
|
$pattern .= 'i';
|
||||||
|
}
|
||||||
|
|
||||||
|
if ($pipedInput !== '') {
|
||||||
|
$this->outputTemplate = '{line}';
|
||||||
|
$out = $this->grepContents($pattern, $pipedInput);
|
||||||
|
|
||||||
|
if (!$input->getOption('count')) {
|
||||||
|
$output->writeln($out);
|
||||||
|
} else {
|
||||||
|
$output->writeln($this->count);
|
||||||
|
}
|
||||||
|
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
foreach ($this->buildFinder($input) as $file) {
|
||||||
|
try {
|
||||||
|
$contents = $file->getContents();
|
||||||
|
} catch (Exception $e) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
$out = $this->grepContents($pattern, $contents, $file);
|
||||||
|
|
||||||
|
if (!$input->getOption('count')) {
|
||||||
|
$output->writeln($out);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if ($input->getOption('count')) {
|
||||||
|
$output->writeln($this->count);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public function grepContents($pattern, $contents, $file = null)
|
||||||
|
{
|
||||||
|
$lines = explode("\n", $contents);
|
||||||
|
|
||||||
|
preg_match_all($pattern, $contents, $matches, PREG_OFFSET_CAPTURE);
|
||||||
|
|
||||||
|
foreach (current($matches) as $match) {
|
||||||
|
$this->count++;
|
||||||
|
|
||||||
|
$lineIndex = substr_count(mb_substr($contents, 0, $match[1]), PHP_EOL);
|
||||||
|
$line = preg_replace($pattern, '<fg=green;options=bold>$0</>', $lines[$lineIndex]);
|
||||||
|
|
||||||
|
return strtr($this->outputTemplate, [
|
||||||
|
'{matchValue}' => $match[0],
|
||||||
|
'{file}' => $file ? $file->getPathName() : '',
|
||||||
|
'{fileRelative}' => $file ? $file->getRelativePathname() : '',
|
||||||
|
'{line}' => $line,
|
||||||
|
'{lineNumber}' => $lineIndex + 1,
|
||||||
|
]);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public function buildFinder($input)
|
||||||
|
{
|
||||||
|
$finder = new Finder();
|
||||||
|
$finder->ignoreUnreadableDirs()->files();
|
||||||
|
|
||||||
|
foreach ($input->getOption('in') as $dir) {
|
||||||
|
$finder->in($dir);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (($size = $input->getOption('size')) !== null) {
|
||||||
|
$finder->size($size);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (($date = $input->getOption('date')) !== null) {
|
||||||
|
$finder->date($date);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (($depth = $input->getOption('depth')) !== null) {
|
||||||
|
$finder->depth($depth);
|
||||||
|
}
|
||||||
|
|
||||||
|
return $finder;
|
||||||
|
}
|
||||||
|
}
|
||||||
Loading…
Reference in a new issue