├── .semver ├── .gitignore ├── .php_cs ├── .phpspec_cs ├── skeleton ├── git_hooks │ ├── post-merge │ └── pre-commit ├── phpcs │ └── Standards │ │ ├── php │ │ └── ruleset.xml │ │ └── Sniffs │ │ └── Functions │ │ └── ForbiddenFunctionsSniff.php ├── php_cs_fixer │ └── php_cs ├── projects.json └── editor │ └── SublimeText3 │ └── Packages │ └── User │ ├── phpcs.sublime-settings │ ├── SublimeGit.sublime-settings │ ├── Preferences.sublime-settings │ ├── Package Control.sublime-settings │ └── SublimeLinter.sublime-settings ├── .formatter.yml ├── .editorconfig ├── src ├── Vagrant │ ├── CheckVirtualMachineStatusTrait.php │ ├── Configuration │ │ └── SshConfiguration.php │ └── Exec.php ├── Process │ ├── PhpCsFixerAwareTrait.php │ ├── CommandExistTrait.php │ ├── ExecAwareTrait.php │ ├── PhpCsFixer.php │ └── Exec.php ├── Project │ ├── Repository │ │ ├── ProjectConfigurationRepositoryAwareTrait.php │ │ └── ProjectConfigurationRepository.php │ └── ProjectConfigurationFactory.php ├── Symfony │ └── RemoteConsoleExecAwareTrait.php ├── Command │ ├── VirtualMachine │ │ ├── BaseCommand.php │ │ ├── BlackfireRestartCommand.php │ │ ├── SshCommand.php │ │ ├── EnablePhpExtensionCommand.php │ │ ├── DisablePhpExtensionCommand.php │ │ ├── SyncRemoteToLocalCommand.php │ │ └── BlackfireInstallCommand.php │ ├── Project │ │ ├── GitLogCommand.php │ │ ├── ShowLocalDirectoryCommand.php │ │ ├── ListCommand.php │ │ ├── AskProjectNameTrait.php │ │ ├── LintAllCommand.php │ │ ├── PhpDocCommand.php │ │ ├── LintPhpCommand.php │ │ ├── PhpCsCommand.php │ │ ├── SymfonyAssetsBuildCommand.php │ │ ├── GitStatusCommand.php │ │ ├── ConfigShowCommand.php │ │ ├── SshCommand.php │ │ ├── LintYamlCommand.php │ │ ├── LintTwigCommand.php │ │ ├── GitGuiCommand.php │ │ ├── BaseBuildCommand.php │ │ ├── InstallDependenciesAndAssetsCommand.php │ │ ├── GitSummaryCommand.php │ │ ├── PhpMetricsCommand.php │ │ ├── BaseSymfonyCommand.php │ │ ├── BaseGitCommand.php │ │ ├── TestAllCommand.php │ │ ├── SymfonyConsoleCommand.php │ │ ├── GitHooksInstallCommand.php │ │ ├── GitOpenCommand.php │ │ ├── TestIntegrationCommand.php │ │ └── GitCloneCommand.php │ ├── Vagrant │ │ ├── StatusCommand.php │ │ ├── StopCommand.php │ │ ├── ProvisionCommand.php │ │ ├── RestartCommand.php │ │ ├── SshCommand.php │ │ ├── SshAddPrivateKeyCommand.php │ │ ├── UpgradeCommand.php │ │ ├── BaseCommand.php │ │ └── StartCommand.php │ ├── Core │ │ ├── VersionCommand.php │ │ ├── CacheClearCommand.php │ │ ├── SelfUpdateCommand.php │ │ └── AutocompleteCommand.php │ └── Composer │ │ └── ComposerCommand.php ├── Ssh │ └── SshExecAwareTrait.php ├── Console │ ├── Helper │ │ ├── DescriptorHelper.php │ │ └── ReadlineHelper.php │ ├── Formatter │ │ └── OutputFormatter.php │ └── Readline │ │ └── Autocompleter │ │ └── Fuzzy.php ├── Filesystem │ ├── RemoteFilesystemAwareTrait.php │ └── LocalFilesystemAwareTrait.php ├── Phar │ └── Manifest.php ├── Jarvis.php ├── DependencyInjection │ └── Compiler │ │ ├── CommandCompilerPass.php │ │ └── HelperCompilerPass.php ├── Ustring │ └── Search.php └── Composer │ └── GraphComposer.php ├── LICENSE ├── Makefile ├── config └── services │ ├── command.editor.xml │ ├── command.project.config.xml │ ├── command.vm.blackfire.xml │ ├── command.project.editor.xml │ ├── command.core.xml │ ├── command.project.build.xml │ ├── command.vm.php_tools.xml │ ├── command.project.lint.xml │ ├── command.project.cs.xml │ ├── command.project.test.xml │ ├── command.vagrant.xml │ └── command.project.xml ├── box.json ├── composer.json └── bin └── bump-version.sh /.semver: -------------------------------------------------------------------------------- 1 | --- 2 | :major: 0 3 | :minor: 0 4 | :patch: 0 5 | :special: '' 6 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | .* 2 | *.orig 3 | /jarvis.phar 4 | /var/* 5 | /vendor 6 | /build 7 | *.phar 8 | -------------------------------------------------------------------------------- /.php_cs: -------------------------------------------------------------------------------- 1 | in('src'); 4 | 5 | return Symfony\CS\Config\Config::create() 6 | ->level(Symfony\CS\FixerInterface::PSR2_LEVEL) 7 | ->finder($finder) 8 | ; 9 | -------------------------------------------------------------------------------- /.phpspec_cs: -------------------------------------------------------------------------------- 1 | files() 5 | ->name('*Spec.php') 6 | ->in(__DIR__.'/src') 7 | ; 8 | 9 | return Symfony\CS\Config\Config::create()->finder($finder); 10 | -------------------------------------------------------------------------------- /skeleton/git_hooks/post-merge: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | 3 | FILES=$(git diff --name-only HEAD^) 4 | 5 | for FILE in $FILES 6 | do 7 | if [ $FILE = "composer.lock" ]; then 8 | echo "Le fichier composer.lock a changé." 9 | echo "Mise à jour des dépendances:" 10 | {{jarvis_command_name}} project:composer:install --project-name={{project_name}} 11 | fi 12 | done 13 | -------------------------------------------------------------------------------- /.formatter.yml: -------------------------------------------------------------------------------- 1 | use-sort: 2 | group: 3 | - _main 4 | - Jarvis 5 | group-type: each 6 | sort-type: alph 7 | sort-direction: asc 8 | 9 | header: | 10 | /* 11 | * This file is part of the Jarvis package 12 | * 13 | * Copyright (c) 2015 Tony Dubreil 14 | * 15 | * For the full copyright and license information, please view the LICENSE 16 | * file that was distributed with this source code. 17 | * 18 | * Feel free to edit as you please, and have fun. 19 | * 20 | * @author Tony Dubreil 21 | */ 22 | -------------------------------------------------------------------------------- /skeleton/phpcs/Standards/php/ruleset.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | */build/* 5 | */vendor/* 6 | */spec/* 7 | */web/* 8 | */Tests/ServiceTest.php 9 | 10 | 11 | 12 | 13 | 14 | -------------------------------------------------------------------------------- /.editorconfig: -------------------------------------------------------------------------------- 1 | # EditorConfig is awesome: http://EditorConfig.org 2 | # Helps developers maintain consistent coding styles between different editors - Sublime Text plugin 3 | # https://github.com/sindresorhus/editorconfig-sublime#readme 4 | 5 | # top-most EditorConfig file 6 | root = true 7 | 8 | # Unix-style newlines with a newline ending every file 9 | [*] 10 | charset = utf-8 11 | # Unix-style newlines 12 | end_of_line = LF 13 | # Space indentation 14 | indent_style = space 15 | # Whitespace chars 16 | trim_trailing_whitespace = true 17 | insert_final_newline = true 18 | 19 | [*.php] 20 | indent_size = 4 21 | 22 | [*.json] 23 | indent_size = 2 24 | 25 | [*.yml] 26 | indent_size = 4 27 | 28 | [*.feature] 29 | indent_size = 4 30 | 31 | [Makefile] 32 | indent_style = tab 33 | -------------------------------------------------------------------------------- /src/Vagrant/CheckVirtualMachineStatusTrait.php: -------------------------------------------------------------------------------- 1 | 14 | */ 15 | 16 | namespace Jarvis\Vagrant; 17 | 18 | trait CheckVirtualMachineStatusTrait 19 | { 20 | public function isVirtualMachineRunning($name) 21 | { 22 | $result = $this->getVagrantExec()->run(sprintf( 23 | 'status %s', 24 | $name 25 | )); 26 | 27 | return strpos($result, 'running') !== false; 28 | } 29 | } 30 | -------------------------------------------------------------------------------- /skeleton/phpcs/Standards/Sniffs/Functions/ForbiddenFunctionsSniff.php: -------------------------------------------------------------------------------- 1 | phpCsFixer) { 17 | throw new \RuntimeException('Php CS fixer service is not injected'); 18 | } 19 | return $this->phpCsFixer; 20 | } 21 | 22 | /** 23 | * Sets the value of phpCsFixer. 24 | * 25 | * @param mixed $phpCsFixer the php cs fixer 26 | * 27 | * @return self 28 | */ 29 | public function setPhpCsFixer($phpCsFixer) 30 | { 31 | $this->phpCsFixer = $phpCsFixer; 32 | 33 | return $this; 34 | } 35 | } 36 | -------------------------------------------------------------------------------- /skeleton/php_cs_fixer/php_cs: -------------------------------------------------------------------------------- 1 | in(__DIR__) 7 | ; 8 | 9 | return PhpCsFixer\Config::create() 10 | ->setRules(array( 11 | '@PSR2' => true, 12 | )) 13 | ->setFinder($finder) 14 | ; 15 | } elseif (class_exists('Symfony\CS\Finder\DefaultFinder')) { // PHP-CS-Fixer 1.x 16 | $finder = Symfony\CS\Finder\DefaultFinder::create() 17 | ->in(__DIR__) 18 | ; 19 | 20 | return Symfony\CS\Config\Config::create() 21 | ->level(Symfony\CS\FixerInterface::PSR2_LEVEL) 22 | ->fixers(['-psr0']) // don't lowercase namespace (use "namespace App\.." instead of "namespace app\..") to be compatible with Laravel 5 23 | ->finder($finder) 24 | ; 25 | } 26 | -------------------------------------------------------------------------------- /skeleton/projects.json: -------------------------------------------------------------------------------- 1 | { 2 | "projects": { 3 | "symfony-standard": { 4 | "git_repository_url": "https://github.com/symfony/symfony-standard.git", 5 | "git_target_branch": "develop", 6 | "local_webapp_dir": "%local_projects_root_dir%/%project_name%", 7 | "remote_webapp_dir": "%remote_projects_root_dir%/%project_name%", 8 | "local_git_repository_dir": "%local_projects_root_dir%/symfony-standard", 9 | "remote_git_repository_dir": "%remote_vendor_root_dir%", 10 | "remote_vendor_dir": "/home/vagrant/projects/%project_name%/vendor", 11 | "local_vendor_dir": "%local_vendor_root_dir%/%project_name%", 12 | "remote_symfony_console_path": "%remote_vendor_root_dir%/app/console", 13 | "remote_phpunit_configuration_xml_path": "%remote_vendor_root_dir%/app/phpunit.xml.dist" 14 | } 15 | } 16 | } 17 | -------------------------------------------------------------------------------- /src/Project/Repository/ProjectConfigurationRepositoryAwareTrait.php: -------------------------------------------------------------------------------- 1 | projectConfigurationRepository = $repository; 20 | } 21 | /** 22 | * @return string 23 | */ 24 | protected function getProjectConfigurationRepository() 25 | { 26 | if (null === $this->projectConfigurationRepository) { 27 | throw new \RuntimeException('The project configuration repository service does not injected.'); 28 | } 29 | 30 | return $this->projectConfigurationRepository; 31 | } 32 | } 33 | -------------------------------------------------------------------------------- /skeleton/editor/SublimeText3/Packages/User/phpcs.sublime-settings: -------------------------------------------------------------------------------- 1 | { 2 | "show_debug": true, 3 | "extensions_to_execute": [ 4 | "php" 5 | ], 6 | "extensions_to_blacklist": [ 7 | 8 | ], 9 | "phpcs_execute_on_save": false, 10 | "phpcs_show_errors_on_save": false, 11 | "phpcs_show_gutter_marks": false, 12 | "phpcs_outline_for_errors": false, 13 | "phpcs_show_errors_in_status": false, 14 | "phpcs_show_quick_panel": false, 15 | "phpcs_php_prefix_path": "", 16 | "phpcs_commands_to_php_prefix": [], 17 | "phpcs_sniffer_run": false, 18 | "phpcs_command_on_save": false, 19 | "php_cs_fixer_on_save": true, 20 | "php_cs_fixer_show_quick_panel": true, 21 | "php_cs_fixer_executable_path": "php-cs-fixer", 22 | "php_cs_fixer_additional_args": { 23 | "--level": "symfony" 24 | }, 25 | "phpmd_run": false, 26 | "scheck_run": false, 27 | "phpcs_php_path": "/usr/local/php5/bin/php", 28 | "phpcs_executable_path": "phpcs", 29 | "phpmd_executable_path": "phpmd" 30 | } 31 | -------------------------------------------------------------------------------- /src/Symfony/RemoteConsoleExecAwareTrait.php: -------------------------------------------------------------------------------- 1 | symfonyRemoteConsoleExec = $symfonyRemoteConsoleExec; 24 | 25 | return $this; 26 | } 27 | 28 | /** 29 | * Gets the value of symfonyRemoteConsoleExec. 30 | * 31 | * @return SymfonyRemoteConsoleExec 32 | */ 33 | protected function getSymfonyRemoteConsoleExec() 34 | { 35 | return $this->symfonyRemoteConsoleExec; 36 | } 37 | } 38 | -------------------------------------------------------------------------------- /src/Command/VirtualMachine/BaseCommand.php: -------------------------------------------------------------------------------- 1 | 14 | */ 15 | 16 | namespace Jarvis\Command\VirtualMachine; 17 | 18 | use Symfony\Component\Console\Command\Command; 19 | 20 | class BaseCommand extends Command 21 | { 22 | use \Jarvis\Ssh\SshExecAwareTrait; 23 | 24 | /** 25 | * @var bool 26 | */ 27 | private $enabled = false; 28 | 29 | /** 30 | * @param bool $bool 31 | */ 32 | public function setEnabled($bool) 33 | { 34 | $this->enabled = $bool; 35 | 36 | return $this; 37 | } 38 | 39 | /** 40 | * {@inheritdoc} 41 | */ 42 | public function isEnabled() 43 | { 44 | return $this->enabled; 45 | } 46 | } 47 | -------------------------------------------------------------------------------- /src/Process/CommandExistTrait.php: -------------------------------------------------------------------------------- 1 | 14 | */ 15 | 16 | namespace Jarvis\Process; 17 | 18 | trait CommandExistTrait 19 | { 20 | /** 21 | * Check if command exist. 22 | * 23 | * @param string $commandLine 24 | * 25 | * @return bool 26 | */ 27 | protected function commandExist($commandLine, $cwd = null) 28 | { 29 | $previousCwd = null; 30 | if (null !== $cwd) { 31 | $previousCwd = getcwd(); 32 | chdir($cwd); 33 | } 34 | 35 | $returnVal = shell_exec('which '.$commandLine); 36 | 37 | $previousCwd && chdir($previousCwd); 38 | 39 | return null === $returnVal ? false : true; 40 | } 41 | } 42 | -------------------------------------------------------------------------------- /src/Command/Project/GitLogCommand.php: -------------------------------------------------------------------------------- 1 | 14 | */ 15 | 16 | namespace Jarvis\Command\Project; 17 | 18 | use Symfony\Component\Console\Output\OutputInterface; 19 | use Jarvis\Project\ProjectConfiguration; 20 | 21 | class GitLogCommand extends BaseGitCommand 22 | { 23 | /** 24 | * @{inheritdoc} 25 | */ 26 | protected function executeCommandByProject($projectName, ProjectConfiguration $projectConfig, OutputInterface $output) 27 | { 28 | $this->gitCommand = 'log --graph --pretty=tformat:\'%Cred%h%Creset -%C(cyan)%d %Creset%s %Cgreen(%an %cr)%Creset\' --abbrev-commit --date=relative'; 29 | 30 | parent::executeCommandByProject($projectName, $projectConfig, $output); 31 | } 32 | } 33 | -------------------------------------------------------------------------------- /src/Command/Vagrant/StatusCommand.php: -------------------------------------------------------------------------------- 1 | 14 | */ 15 | 16 | namespace Jarvis\Command\Vagrant; 17 | 18 | use Symfony\Component\Console\Input\InputInterface; 19 | use Symfony\Component\Console\Output\OutputInterface; 20 | 21 | class StatusCommand extends BaseCommand 22 | { 23 | /** 24 | * {@inheritdoc} 25 | */ 26 | protected function configure() 27 | { 28 | $this->setName('vagrant:status'); 29 | $this->setDescription('Outputs status of the vagrant machine'); 30 | } 31 | 32 | /** 33 | * {@inheritdoc} 34 | */ 35 | protected function execute(InputInterface $input, OutputInterface $output) 36 | { 37 | $this->getVagrantExec()->exec('status'); 38 | } 39 | } 40 | -------------------------------------------------------------------------------- /skeleton/editor/SublimeText3/Packages/User/SublimeGit.sublime-settings: -------------------------------------------------------------------------------- 1 | { 2 | "log_level": "WARNING", 3 | "encoding": "utf-8", 4 | "fallback_encodings": [ 5 | "cp1252", 6 | "iso-8859-1", 7 | "iso-8859-2", 8 | "cp1250" 9 | ], 10 | "git_show_status_help": true, 11 | "git_update_status_on_focus": true, 12 | "git_status_untracked_files": "auto", 13 | "git_status_open_files_transient": true, 14 | "git_status_bar": "fancy", 15 | "git_commit_verbose": true, 16 | "git_commit_pedantic": false, 17 | "git_merge_flags": [ 18 | 19 | ], 20 | "git_blame_warn_multiple_tabs": true, 21 | "git_executables": { 22 | "git": [ 23 | "git" 24 | ], 25 | "git_flow": [ 26 | "git-flow" 27 | ], 28 | "legit": [ 29 | "legit" 30 | ], 31 | "gitk": [ 32 | "gitk" 33 | ] 34 | }, 35 | "git_help_fancy_list": true, 36 | "git_help_html_path": null, 37 | "git_extensions": { 38 | "git_flow": true, 39 | "legit": false 40 | } 41 | } 42 | -------------------------------------------------------------------------------- /src/Ssh/SshExecAwareTrait.php: -------------------------------------------------------------------------------- 1 | 14 | */ 15 | 16 | namespace Jarvis\Ssh; 17 | 18 | use Jarvis\Ssh\Exec as SshExec; 19 | 20 | trait SshExecAwareTrait 21 | { 22 | /** 23 | * @var SshExec 24 | */ 25 | private $sshExec; 26 | 27 | /** 28 | * Gets the value of sshExec. 29 | * 30 | * @return SshExec 31 | */ 32 | public function getSshExec() 33 | { 34 | return $this->sshExec; 35 | } 36 | 37 | /** 38 | * Sets the value of sshExec. 39 | * 40 | * @param SshExec $sshExec the ssh exec 41 | * 42 | * @return self 43 | */ 44 | public function setSshExec(SshExec $sshExec) 45 | { 46 | $this->sshExec = $sshExec; 47 | 48 | return $this; 49 | } 50 | } 51 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | Copyright (c) 2015 Tony Dubreil 2 | 3 | Permission is hereby granted, free of charge, to any person obtaining a copy 4 | of this software and associated documentation files (the "Software"), to deal 5 | in the Software without restriction, including without limitation the rights 6 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 7 | copies of the Software, and to permit persons to whom the Software is furnished 8 | to do so, subject to the following conditions: 9 | 10 | The above copyright notice and this permission notice shall be included in all 11 | copies or substantial portions of the Software. 12 | 13 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 14 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 15 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 16 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 17 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 18 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 19 | THE SOFTWARE. 20 | -------------------------------------------------------------------------------- /src/Command/Core/VersionCommand.php: -------------------------------------------------------------------------------- 1 | setName('core:version') 18 | ->setDescription('Display current version') 19 | ->setHelp(<<%command.name% command displays current version: 21 | 22 | php %command.full_name% 23 | EOF 24 | ) 25 | ; 26 | } 27 | 28 | /** 29 | * {@inheritdoc} 30 | */ 31 | protected function execute(InputInterface $input, OutputInterface $output) 32 | { 33 | $output->writeln(sprintf( 34 | 'Running %s version %s', 35 | $this->getApplication()->getName(), 36 | $this->getApplication()->getVersion() 37 | )); 38 | } 39 | } 40 | -------------------------------------------------------------------------------- /src/Process/ExecAwareTrait.php: -------------------------------------------------------------------------------- 1 | 14 | */ 15 | 16 | namespace Jarvis\Process; 17 | 18 | trait ExecAwareTrait 19 | { 20 | /** 21 | * @var Exec 22 | */ 23 | private $exec; 24 | 25 | /** 26 | * Gets the value of exec. 27 | * 28 | * @return Exec 29 | */ 30 | public function getExec() 31 | { 32 | if (null === $this->exec) { 33 | throw new \LogicException('The service "exec" is not initialize'); 34 | } 35 | return $this->exec; 36 | } 37 | 38 | /** 39 | * Sets the value of exec. 40 | * 41 | * @param Exec $exec the exec 42 | * 43 | * @return self 44 | */ 45 | public function setExec(Exec $exec) 46 | { 47 | $this->exec = $exec; 48 | 49 | return $this; 50 | } 51 | } 52 | -------------------------------------------------------------------------------- /Makefile: -------------------------------------------------------------------------------- 1 | install: 2 | @ echo '[curl] Getting Composer, the PHP dependency manager' 3 | @ which composer || curl -sS https://getcomposer.org/installer | php -- --install-dir=/usr/local/bin 4 | @ echo '[composer] Downloading the dependencies' 5 | @ composer install --no-dev --optimize-autoloader 6 | 7 | install-php-tools: 8 | @ composer global require "mmoreram/php-formatter" 9 | @ composer global require "friendsofphp/php-cs-fixer" 10 | @ composer global require "halleck45/phpmetrics" 11 | 12 | # Build phar 13 | build-phar: 14 | @ box build 15 | 16 | cs-fix: 17 | @ php-formatter formatter:use:sort src 18 | @ php-cs-fixer fix 19 | 20 | metrics: 21 | @ phpmetrics --level=0 --report-html=build/metrics.html src/ && (which open && open build/metrics.html) || (which xdg-open && xdg-open build/metrics.html) 22 | 23 | # Publish new release. Usage: 24 | # make tag VERSION=(major|minor|patch) 25 | # You need to install https://github.com/flazz/semver/ before with command sudo gem install semver 26 | # Source: http://blog.lepine.pro/semver-git-tags/ 27 | tag: 28 | @ semver inc $(VERSION) 29 | @ echo "New release: `semver tag`" 30 | 31 | # Tag git with last release 32 | git_tag: 33 | @ sh bin/releaser 34 | -------------------------------------------------------------------------------- /config/services/command.editor.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 6 | 7 | 8 | false 9 | 10 | 11 | 12 | 13 | 17 | editor:config:install 18 | 19 | 20 | %editor_skeleton_dir% 21 | 22 | 23 | 24 | 25 | 26 | 27 | 28 | %command.editor.enabled% 29 | 30 | 31 | 32 | 33 | 34 | 35 | -------------------------------------------------------------------------------- /box.json: -------------------------------------------------------------------------------- 1 | { 2 | "alias": "box.phar", 3 | "chmod": "0755", 4 | "compactors": [ 5 | "Herrera\\Box\\Compactor\\Json", 6 | "Herrera\\Box\\Compactor\\Php" 7 | ], 8 | "compression": "GZ", 9 | 10 | "directories": ["config", "skeleton", "src"], 11 | "files": [ 12 | "LICENSE" 13 | ], 14 | "finder": [ 15 | { 16 | "name": "jarvis", 17 | "in": "bin" 18 | }, 19 | { 20 | "name": "*.*", 21 | "exclude": [ 22 | ".gitignore", 23 | ".md", 24 | "File", 25 | "mikey179", 26 | "Net", 27 | "phpunit", 28 | "phpunit-test-case", 29 | "Tester", 30 | "Tests", 31 | "tests" 32 | ], 33 | "in": "vendor" 34 | } 35 | ], 36 | "git-commit": "git-commit", 37 | "git-version": "git-version", 38 | "main": "bin/jarvis", 39 | "output": "build/jarvis.phar", 40 | "replacements": { 41 | "manifest_url": "http://pagesjaunes.github.io/jarvis/manifest.json" 42 | }, 43 | "stub": true, 44 | "web": false 45 | } 46 | -------------------------------------------------------------------------------- /src/Console/Helper/DescriptorHelper.php: -------------------------------------------------------------------------------- 1 | 24 | * 25 | * @internal 26 | */ 27 | class DescriptorHelper extends BaseDescriptorHelper 28 | { 29 | /** 30 | * Constructor. 31 | */ 32 | public function __construct() 33 | { 34 | $this 35 | ->register('txt', new TextDescriptor()) 36 | ->register('xml', new XmlDescriptor()) 37 | ->register('json', new JsonDescriptor()) 38 | ->register('md', new MarkdownDescriptor()) 39 | ; 40 | } 41 | } 42 | -------------------------------------------------------------------------------- /src/Command/Project/ShowLocalDirectoryCommand.php: -------------------------------------------------------------------------------- 1 | setDescription('Show local git repository directory real path'); 21 | 22 | parent::configure(); 23 | } 24 | 25 | /** 26 | * {@inheritdoc} 27 | */ 28 | protected function getProjectNamesToExclude() 29 | { 30 | return []; 31 | } 32 | 33 | /** 34 | * {@inheritdoc} 35 | */ 36 | protected function executeCommandByProject($projectName, ProjectConfiguration $projectConfig, OutputInterface $output) 37 | { 38 | $accessor = PropertyAccess::createPropertyAccessor(); 39 | 40 | $output->write($accessor->getValue($projectConfig, 'local_git_repository_dir')); 41 | } 42 | } 43 | -------------------------------------------------------------------------------- /src/Filesystem/RemoteFilesystemAwareTrait.php: -------------------------------------------------------------------------------- 1 | 14 | */ 15 | 16 | namespace Jarvis\Filesystem; 17 | 18 | use Jarvis\Filesystem\RemoteFilesystem; 19 | 20 | trait RemoteFilesystemAwareTrait 21 | { 22 | /** 23 | * @var RemoteFilesystem 24 | */ 25 | private $remoteFilesystem; 26 | 27 | /** 28 | * Sets the value of remoteFilesystem. 29 | * 30 | * @param RemoteFilesystem $remoteFilesystem the remote filesystem 31 | * 32 | * @return self 33 | */ 34 | public function setRemoteFilesystem(RemoteFilesystem $remoteFilesystem) 35 | { 36 | $this->remoteFilesystem = $remoteFilesystem; 37 | 38 | return $this; 39 | } 40 | 41 | /** 42 | * Gets the value of remoteFilesystem. 43 | * 44 | * @return RemoteFilesystem 45 | */ 46 | public function getRemoteFilesystem() 47 | { 48 | return $this->remoteFilesystem; 49 | } 50 | } 51 | -------------------------------------------------------------------------------- /src/Filesystem/LocalFilesystemAwareTrait.php: -------------------------------------------------------------------------------- 1 | 14 | */ 15 | 16 | namespace Jarvis\Filesystem; 17 | 18 | use Symfony\Component\Filesystem\Filesystem; 19 | 20 | trait LocalFilesystemAwareTrait 21 | { 22 | /** 23 | * @var Filesystem 24 | */ 25 | private $filesystem; 26 | 27 | /** 28 | * Sets the value of filesystem. 29 | * 30 | * @param Filesystem $filesystem the remote filesystem 31 | * 32 | * @return self 33 | */ 34 | public function setLocalFilesystem(Filesystem $filesystem) 35 | { 36 | $this->filesystem = $filesystem; 37 | 38 | return $this; 39 | } 40 | 41 | /** 42 | * Gets the value of filesystem. 43 | * 44 | * @return Filesystem 45 | */ 46 | public function getLocalFilesystem() 47 | { 48 | if (null === $this->filesystem) { 49 | throw new \RuntimeException('The local filesystem service is not injected'); 50 | } 51 | 52 | return $this->filesystem; 53 | } 54 | } 55 | -------------------------------------------------------------------------------- /src/Command/VirtualMachine/BlackfireRestartCommand.php: -------------------------------------------------------------------------------- 1 | 14 | */ 15 | 16 | namespace Jarvis\Command\VirtualMachine; 17 | 18 | use Symfony\Component\Console\Input\InputInterface; 19 | use Symfony\Component\Console\Output\OutputInterface; 20 | 21 | class BlackfireRestartCommand extends BaseCommand 22 | { 23 | /** 24 | * {@inheritdoc} 25 | */ 26 | protected function configure() 27 | { 28 | $this->setDescription('Installing Blackfire'); 29 | } 30 | 31 | /** 32 | * {@inheritdoc} 33 | */ 34 | protected function execute(InputInterface $input, OutputInterface $output) 35 | { 36 | if ($this->getSshExec()->getLastReturnStatus() == 0) { 37 | $this->getSshExec()->run('sudo /etc/init.d/blackfire-agent restart', $output); 38 | } 39 | if ($this->getSshExec()->getLastReturnStatus() == 0) { 40 | $this->getApplication()->executeCommand('vm:service:php-fpm:restart', [], $output); 41 | } 42 | 43 | return $this->getSshExec()->getLastReturnStatus(); 44 | } 45 | } 46 | -------------------------------------------------------------------------------- /config/services/command.project.config.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 6 | 7 | 8 | 9 | 13 | project:config:add 14 | 15 | 16 | %command.project.enabled% 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | 31 | project:config:show 32 | 33 | 34 | %command.project.enabled% 35 | 36 | 37 | 38 | 39 | 40 | 41 | -------------------------------------------------------------------------------- /src/Command/VirtualMachine/SshCommand.php: -------------------------------------------------------------------------------- 1 | 14 | */ 15 | 16 | namespace Jarvis\Command\VirtualMachine; 17 | 18 | use Symfony\Component\Console\Input\InputArgument; 19 | use Symfony\Component\Console\Input\InputInterface; 20 | use Symfony\Component\Console\Input\InputOption; 21 | use Symfony\Component\Console\Output\OutputInterface; 22 | 23 | class SshCommand extends BaseCommand 24 | { 25 | /** 26 | * {@inheritdoc} 27 | */ 28 | protected function configure() 29 | { 30 | $this->setName('vm:ssh'); 31 | $this->setDescription('Connects to machine via SSH'); 32 | 33 | $this->addArgument('remote_command', InputArgument::OPTIONAL, 'Execute an SSH command directly'); 34 | 35 | $this->addOption('name', null, InputOption::VALUE_REQUIRED, 'Vagrant virtual machine name', 'default'); 36 | } 37 | 38 | /** 39 | * {@inheritdoc} 40 | */ 41 | protected function execute(InputInterface $input, OutputInterface $output) 42 | { 43 | $this->getSshExec()->passthru($input->getArgument('remote_command')); 44 | } 45 | } 46 | -------------------------------------------------------------------------------- /src/Command/Vagrant/StopCommand.php: -------------------------------------------------------------------------------- 1 | 14 | */ 15 | 16 | namespace Jarvis\Command\Vagrant; 17 | 18 | use Symfony\Component\Console\Input\InputInterface; 19 | use Symfony\Component\Console\Input\InputOption; 20 | use Symfony\Component\Console\Output\OutputInterface; 21 | 22 | class StopCommand extends BaseCommand 23 | { 24 | /** 25 | * {@inheritdoc} 26 | */ 27 | protected function configure() 28 | { 29 | $this->setName('vagrant:stop'); 30 | $this->setDescription('Stops the virtual machine'); 31 | 32 | $this->addOption('name', null, InputOption::VALUE_REQUIRED, 'Vagrant virtual machine name', 'default'); 33 | } 34 | 35 | /** 36 | * {@inheritdoc} 37 | */ 38 | protected function execute(InputInterface $input, OutputInterface $output) 39 | { 40 | if (! $this->isVirtualMachineRunning($input->getOption('name'))) { 41 | $output->writeln('The virtual machine already stopped'); 42 | 43 | return; 44 | } 45 | 46 | $this->getVagrantExec()->exec('halt'); 47 | } 48 | } 49 | -------------------------------------------------------------------------------- /src/Phar/Manifest.php: -------------------------------------------------------------------------------- 1 | 14 | */ 15 | 16 | namespace Jarvis\Phar; 17 | 18 | use Herrera\Phar\Update\Manifest as BaseManifest; 19 | use Herrera\Version\Version; 20 | 21 | class Manifest extends BaseManifest 22 | { 23 | /** 24 | * @param string $url 25 | * 26 | * @return boolean 27 | * 28 | * @throws \RuntimeException 29 | */ 30 | public static function download($url, $debug = false) 31 | { 32 | $client = new \GuzzleHttp\Client(['debug' => $debug]); 33 | 34 | $response = $client->request('GET', $url); 35 | 36 | $json = (string) $response->getBody(); 37 | 38 | return self::load($json); 39 | } 40 | 41 | /** 42 | * @param Version $version 43 | * 44 | * @return null|Update 45 | */ 46 | public function find(Version $version) 47 | { 48 | $version = (string) $version; 49 | 50 | foreach ($this->getUpdates() as $update) { 51 | if ($version == (string) $update->getVersion()) { 52 | return $update; 53 | } 54 | } 55 | 56 | return; 57 | } 58 | } 59 | -------------------------------------------------------------------------------- /src/Project/ProjectConfigurationFactory.php: -------------------------------------------------------------------------------- 1 | localProjectsRootDir = $localProjectsRootDir; 40 | $this->remoteProjectsRootDir = $remoteProjectsRootDir; 41 | $this->localVendorRootDir = $localVendorRootDir; 42 | $this->localCdnRootDir = $localCdnRootDir; 43 | $this->remoteVendorRootDir = $remoteVendorRootDir; 44 | } 45 | 46 | public function create(array $data) 47 | { 48 | return new ProjectConfiguration( 49 | $data, 50 | $this->localProjectsRootDir, 51 | $this->remoteProjectsRootDir, 52 | $this->localVendorRootDir, 53 | $this->localCdnRootDir, 54 | $this->remoteVendorRootDir 55 | ); 56 | } 57 | } 58 | -------------------------------------------------------------------------------- /skeleton/editor/SublimeText3/Packages/User/Preferences.sublime-settings: -------------------------------------------------------------------------------- 1 | { 2 | "color_scheme": "Packages/User/Solarized (dark) (SL).tmTheme", 3 | "default_encoding": "UTF-8", 4 | "default_line_ending": "unix", 5 | "detect_indentation": true, 6 | "draw_white_space": "all", 7 | "ensure_newline_at_eof_on_save": false, 8 | "fallback_encoding": "UTF-8", 9 | "file_exclude_patterns": 10 | [ 11 | ".DS_Store", 12 | "Desktop.ini", 13 | "*.pyc", 14 | "._*", 15 | "Thumbs.db", 16 | ".Spotlight-V100", 17 | ".Trashes" 18 | ], 19 | "folder_exclude_patterns": 20 | [ 21 | ".sass-cache", 22 | ".svn", 23 | ".git", 24 | ".hg", 25 | "CVS", 26 | "node_modules" 27 | ], 28 | "font_face": null, 29 | "font_size": 14, 30 | "highlight_modified_tabs": true, 31 | "hot_exit": false, 32 | "ignored_packages": 33 | [ 34 | "INI", 35 | "SyncedSideBar", 36 | "Vintage" 37 | ], 38 | "line_padding_bottom": 6, 39 | "match_brackets": true, 40 | "match_brackets_angle": true, 41 | "remember_open_files": false, 42 | "rulers": 43 | [ 44 | 80 45 | ], 46 | "show_encoding": true, 47 | "show_line_endings": true, 48 | "tab_size": 4, 49 | "translate_tabs_to_spaces": true, 50 | "trim_automatic_white_space": true, 51 | "trim_trailing_white_space_on_save": true, 52 | "use_tab_stops": true, 53 | "word_wrap": true 54 | } 55 | -------------------------------------------------------------------------------- /src/Command/Vagrant/ProvisionCommand.php: -------------------------------------------------------------------------------- 1 | 14 | */ 15 | 16 | namespace Jarvis\Command\Vagrant; 17 | 18 | use Symfony\Component\Console\Input\InputInterface; 19 | use Symfony\Component\Console\Input\InputOption; 20 | use Symfony\Component\Console\Output\OutputInterface; 21 | 22 | class ProvisionCommand extends BaseCommand 23 | { 24 | /** 25 | * {@inheritdoc} 26 | */ 27 | protected function configure() 28 | { 29 | $this->setName('vagrant:provision'); 30 | $this->setDescription('Provisions the vagrant machine'); 31 | 32 | $this->addOption('provider', null, InputOption::VALUE_REQUIRED, 'Vagrant provider', 'virtualbox'); 33 | } 34 | 35 | /** 36 | * {@inheritdoc} 37 | */ 38 | protected function execute(InputInterface $input, OutputInterface $output) 39 | { 40 | $this->getVagrantExec()->run('destroy', $output); 41 | 42 | $options = []; 43 | if (null !== $input->getOption('provider')) { 44 | $options['provider'] = $input->getOption('provider'); 45 | } 46 | $this->getApplication()->executeCommand('vagrant:start', $options, $output); 47 | } 48 | } 49 | -------------------------------------------------------------------------------- /src/Jarvis.php: -------------------------------------------------------------------------------- 1 | 14 | */ 15 | 16 | namespace Jarvis; 17 | 18 | use Symfony\Component\DependencyInjection\Container; 19 | 20 | class Jarvis 21 | { 22 | /** 23 | * The service container. 24 | * 25 | * @var Container 26 | */ 27 | private $container; 28 | 29 | /** 30 | * Constructor. 31 | * 32 | * @param Container $container The service container. 33 | */ 34 | public function __construct(Container $container) 35 | { 36 | $this->container = $container; 37 | } 38 | 39 | /** 40 | * Returns the service container. 41 | * 42 | * @return Container The service container. 43 | */ 44 | public function getContainer() 45 | { 46 | return $this->container; 47 | } 48 | 49 | /** 50 | * Runs the console application in the service container. 51 | * 52 | * @return integer The command exit status. 53 | */ 54 | public function run() 55 | { 56 | return $this->container->get('console.application')->run( 57 | $this->container->get('console.input'), 58 | $this->container->get('console.output') 59 | ); 60 | } 61 | } 62 | -------------------------------------------------------------------------------- /src/Command/Project/ListCommand.php: -------------------------------------------------------------------------------- 1 | 14 | */ 15 | 16 | namespace Jarvis\Command\Project; 17 | 18 | use Symfony\Component\Console\Command\Command; 19 | use Symfony\Component\Console\Input\InputInterface; 20 | use Symfony\Component\Console\Output\OutputInterface; 21 | use Jarvis\Project\Repository\ProjectConfigurationRepositoryAwareTrait; 22 | 23 | /** 24 | * ListCommand displays the list of all available projects for the application. 25 | */ 26 | class ListCommand extends Command 27 | { 28 | use ProjectConfigurationRepositoryAwareTrait; 29 | 30 | /** 31 | * {@inheritdoc} 32 | */ 33 | protected function configure() 34 | { 35 | $this->setDescription('Lists projects'); 36 | } 37 | 38 | /** 39 | * {@inheritdoc} 40 | */ 41 | protected function execute(InputInterface $input, OutputInterface $output) 42 | { 43 | $output->writeln(''); 44 | 45 | $output->writeln('Available projects:'); 46 | 47 | foreach ($this->getProjectConfigurationRepository()->getProjectNames() as $name) { 48 | $output->writeln('- '.$name.''); 49 | } 50 | $output->writeln(''); 51 | } 52 | } 53 | -------------------------------------------------------------------------------- /src/Project/Repository/ProjectConfigurationRepository.php: -------------------------------------------------------------------------------- 1 | 14 | */ 15 | 16 | namespace Jarvis\Project\Repository; 17 | 18 | use Jarvis\Project\ProjectConfiguration; 19 | 20 | interface ProjectConfigurationRepository 21 | { 22 | /** 23 | * @return integer 24 | */ 25 | public function count(); 26 | 27 | /** 28 | * @param string $projectName 29 | * 30 | * @return boolean 31 | */ 32 | public function has($projectName); 33 | 34 | /** 35 | * @param string $projectName 36 | * 37 | * @return null|ProjectConfiguration 38 | */ 39 | public function find($projectName); 40 | 41 | /** 42 | * @return []|ProjectConfiguration[] 43 | */ 44 | public function findAll(); 45 | 46 | /** 47 | * @param array $data 48 | */ 49 | public function add(array $data); 50 | 51 | /** 52 | * @param array $data 53 | */ 54 | public function remove(ProjectConfiguration $configuration); 55 | 56 | /** 57 | * @return array 58 | */ 59 | public function getProjectNames(); 60 | 61 | /** 62 | * @return array 63 | */ 64 | public function getProjectAlreadyInstalledNames(); 65 | } 66 | -------------------------------------------------------------------------------- /src/Command/Project/AskProjectNameTrait.php: -------------------------------------------------------------------------------- 1 | 14 | */ 15 | 16 | namespace Jarvis\Command\Project; 17 | 18 | use Hoa\Console\Readline\Readline; 19 | use Symfony\Component\Console\Output\OutputInterface; 20 | use Jarvis\Console\Helper\ReadlineHelper; 21 | use Jarvis\Console\Readline\Autocompleter\Fuzzy as FuzzyAutocompleter; 22 | use Jarvis\Ustring\Search; 23 | 24 | trait AskProjectNameTrait 25 | { 26 | protected function askProjectName(OutputInterface $output, array $choices) 27 | { 28 | $dialog = $this->getHelperSet()->get('dialog'); 29 | 30 | $readline = new Readline(); 31 | $helper = new ReadlineHelper($readline); 32 | 33 | $default = null; 34 | $keyAsValues = false; 35 | $multi = false; 36 | $autocompleter = new FuzzyAutocompleter([], new Search); 37 | 38 | $name = $helper->select( 39 | $output, 40 | 'Select a value > ', 41 | $choices, 42 | $default, 43 | $keyAsValues, 44 | $multi, 45 | $autocompleter 46 | ); 47 | 48 | $output->writeln('You have just selected: '.$name.''); 49 | 50 | return $name; 51 | } 52 | } 53 | -------------------------------------------------------------------------------- /src/Console/Formatter/OutputFormatter.php: -------------------------------------------------------------------------------- 1 | 14 | */ 15 | 16 | namespace Jarvis\Console\Formatter; 17 | 18 | use Monolog\Formatter\LineFormatter; 19 | use Monolog\Logger; 20 | 21 | /** 22 | * Formats the output with adequate colors. 23 | * 24 | * @author Loïc Chardonnet 25 | */ 26 | class OutputFormatter extends LineFormatter 27 | { 28 | const SIMPLE_FORMAT = "%start_tag%%message%%end_tag%\n"; 29 | 30 | /** 31 | * {@inheritdoc} 32 | */ 33 | public function format(array $record) 34 | { 35 | if ($record['level'] >= Logger::ERROR) { 36 | $record['start_tag'] = ''; 37 | $record['end_tag'] = ''; 38 | } elseif ($record['level'] >= Logger::WARNING) { 39 | $record['start_tag'] = ''; 40 | $record['end_tag'] = ''; 41 | } elseif ($record['level'] >= Logger::INFO) { 42 | $record['start_tag'] = ''; 43 | $record['end_tag'] = ''; 44 | } else { 45 | $record['start_tag'] = ''; 46 | $record['end_tag'] = ''; 47 | } 48 | 49 | return parent::format($record); 50 | } 51 | } 52 | -------------------------------------------------------------------------------- /src/Command/Vagrant/RestartCommand.php: -------------------------------------------------------------------------------- 1 | 14 | */ 15 | 16 | namespace Jarvis\Command\Vagrant; 17 | 18 | use Symfony\Component\Console\Input\InputInterface; 19 | use Symfony\Component\Console\Input\InputOption; 20 | use Symfony\Component\Console\Output\OutputInterface; 21 | 22 | class RestartCommand extends BaseCommand 23 | { 24 | /** 25 | * {@inheritdoc} 26 | */ 27 | protected function configure() 28 | { 29 | $this->setName('vagrant:restart'); 30 | $this->setDescription('Restarts vagrant machine, loads new Vagrantfile configuration'); 31 | 32 | $this->addOption('provider', null, InputOption::VALUE_REQUIRED, 'Vagrant provider', 'virtualbox'); 33 | $this->addOption('name', null, InputOption::VALUE_REQUIRED, 'Vagrant virtual machine name', 'default'); 34 | } 35 | 36 | /** 37 | * {@inheritdoc} 38 | */ 39 | protected function execute(InputInterface $input, OutputInterface $output) 40 | { 41 | $this->getApplication()->executeCommand('vagrant:stop', [], $output); 42 | 43 | $this->getApplication()->executeCommand('vagrant:start', [ 44 | '--provider' => $input->getOption('provider'), 45 | ], $output); 46 | } 47 | } 48 | -------------------------------------------------------------------------------- /config/services/command.vm.blackfire.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 6 | 7 | 8 | false 9 | 10 | 11 | 12 | 16 | 17 | 18 | 19 | 20 | 21 | %command.vm.blackfire.enabled% 22 | 23 | 24 | 25 | 26 | 27 | 32 | vm:blackfire:install 33 | 34 | 35 | 36 | 41 | vm:blackfire:restart 42 | 43 | 44 | 45 | 46 | 47 | -------------------------------------------------------------------------------- /src/Command/Vagrant/SshCommand.php: -------------------------------------------------------------------------------- 1 | 14 | */ 15 | 16 | namespace Jarvis\Command\Vagrant; 17 | 18 | use Symfony\Component\Console\Input\InputArgument; 19 | use Symfony\Component\Console\Input\InputInterface; 20 | use Symfony\Component\Console\Input\InputOption; 21 | use Symfony\Component\Console\Output\OutputInterface; 22 | 23 | class SshCommand extends BaseCommand 24 | { 25 | /** 26 | * {@inheritdoc} 27 | */ 28 | protected function configure() 29 | { 30 | $this->setName('vagrant:ssh'); 31 | $this->setDescription('Connects to machine via SSH'); 32 | 33 | $this->addArgument('remote_command', InputArgument::OPTIONAL, 'Execute an SSH command directly'); 34 | 35 | $this->addOption('name', null, InputOption::VALUE_REQUIRED, 'Vagrant virtual machine name', 'default'); 36 | } 37 | 38 | /** 39 | * {@inheritdoc} 40 | */ 41 | protected function execute(InputInterface $input, OutputInterface $output) 42 | { 43 | if (false === $this->isVirtualMachineRunning($input->getOption('name'))) { 44 | $output->writeln('The virtual machine is stopped'); 45 | 46 | return; 47 | } 48 | 49 | $this->getVagrantExec()->ssh($input->getArgument('remote_command')); 50 | } 51 | } 52 | -------------------------------------------------------------------------------- /skeleton/editor/SublimeText3/Packages/User/Package Control.sublime-settings: -------------------------------------------------------------------------------- 1 | { 2 | "in_process_packages": 3 | [], 4 | "installed_packages": 5 | [ 6 | "ApacheConf.tmLanguage", 7 | "BracketHighlighter", 8 | "Case Conversion", 9 | "Cucumber", 10 | "DocBlockr", 11 | "Dockerfile Syntax Highlighting", 12 | "EditorConfig", 13 | "Emmet", 14 | "Gherkin (Cucumber) Formatter", 15 | "Git Config", 16 | "GitGutter", 17 | "Indent XML", 18 | "INI", 19 | "Javascript Beautify", 20 | "Logs Colorize", 21 | "Markdown Preview", 22 | "nginx", 23 | "Package Control", 24 | "Path Tools", 25 | "PHP Getters and Setters", 26 | "PHP-Twig", 27 | "Phpcs", 28 | "PhpNamespace", 29 | "PhpSpec Snippets", 30 | "PHPUnit Completions", 31 | "plist", 32 | "Pretty JSON", 33 | "Sass", 34 | "SassBeautify", 35 | "SideBarEnhancements", 36 | "Solarized Color Scheme", 37 | "SqlBeautifier", 38 | "SublimeCodeIntel", 39 | "SublimeGit", 40 | "SublimeLinter", 41 | "SublimeLinter-annotations", 42 | "SublimeLinter-contrib-scss-lint", 43 | "SublimeLinter-jshint", 44 | "SublimeLinter-json", 45 | "SublimeLinter-php", 46 | "SublimeLinter-phpcs", 47 | "SublimeLinter-phpmd", 48 | "SublimeLinter-pyyaml", 49 | "SublimeLinter-xmllint", 50 | "SyncedSideBar", 51 | "TrailingSpaces", 52 | "Varnish VCL", 53 | "Xdebug Client", 54 | "Zen Tabs" 55 | ] 56 | } 57 | -------------------------------------------------------------------------------- /config/services/command.project.editor.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 6 | 7 | 8 | false 9 | 10 | 11 | 12 | 13 | 17 | project:editor:open 18 | 19 | 20 | %editor_config_dir% 21 | 22 | 23 | 24 | 25 | 26 | 27 | 28 | %editor_project_external_folders_config% 29 | 30 | 31 | 32 | 33 | 34 | 35 | 36 | 37 | 38 | 39 | 40 | %command.project.editor.enabled% 41 | 42 | 43 | 44 | 45 | 46 | 47 | 48 | -------------------------------------------------------------------------------- /src/Command/Project/LintAllCommand.php: -------------------------------------------------------------------------------- 1 | 14 | */ 15 | 16 | namespace Jarvis\Command\Project; 17 | 18 | use Symfony\Component\Console\Output\OutputInterface; 19 | use Jarvis\Project\ProjectConfiguration; 20 | 21 | class LintAllCommand extends BaseCommand 22 | { 23 | /** 24 | * @{inheritdoc} 25 | */ 26 | protected function configure() 27 | { 28 | $this->setDescription('Lints a template and outputs encountered errors'); 29 | 30 | parent::configure(); 31 | } 32 | 33 | /** 34 | * @{inheritdoc} 35 | */ 36 | protected function executeCommandByProject($projectName, ProjectConfiguration $projectConfig, OutputInterface $output) 37 | { 38 | $this->getApplication()->executeCommand('project:lint:php', [ 39 | '--project-name' => $projectName 40 | ], $output); 41 | 42 | $this->getApplication()->executeCommand('project:lint:twig', [ 43 | '--project-name' => $projectName 44 | ], $output); 45 | 46 | $this->getApplication()->executeCommand('project:lint:yaml', [ 47 | '--project-name' => $projectName 48 | ], $output); 49 | 50 | // $this->getApplication()->executeCommand('project:lint:scss', [ 51 | // '--project-name' => $projectName 52 | // ], $output); 53 | } 54 | } 55 | -------------------------------------------------------------------------------- /composer.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "pagesjaunes/jarvis-ci", 3 | "description": "Vagrant, VirtualBox, Symfony Application managed PHP development stack: Nginx, PHP-FPM, Varnish.", 4 | "keywords": ["symfony", "console", "bootstraper", "installer", "php"], 5 | "license": "MIT", 6 | "authors": [ 7 | { 8 | "name": "Tony Dubreil", 9 | "email": "tonydubreil@gmail.com", 10 | "role": "Developer" 11 | } 12 | ], 13 | "autoload": { 14 | "psr-4": { 15 | "Jarvis\\": "src/" 16 | } 17 | }, 18 | "require": { 19 | "php": ">=5.4.0", 20 | "symfony/debug": "~2.7", 21 | "symfony/config": "~2.7", 22 | "symfony/yaml": "~2.7", 23 | "symfony/console": "~2.7", 24 | "symfony/property-access": "~2.7", 25 | "symfony/dependency-injection": "~2.7", 26 | "symfony/event-dispatcher": "~2.7", 27 | "symfony/filesystem": "~2.7", 28 | "symfony/process": "~2.7", 29 | "symfony/var-dumper": "~2.7", 30 | "symfony/options-resolver": "~2.7", 31 | "symfony/finder": "~2.7", 32 | "monolog/monolog": "~1.12", 33 | "symfony/monolog-bridge": "~2.7", 34 | "kherge/amend": "~3.0", 35 | "clue/graph": "0.7.*", 36 | "jms/composer-deps-analyzer": "0.1.*", 37 | "jakub-onderka/php-console-highlighter": "0.*", 38 | "guzzlehttp/guzzle": "~6.0", 39 | "hoa/console": "~2.0", 40 | "gnugat/redaktilo": "^1.0" 41 | }, 42 | "minimum-stability": "stable", 43 | "extra": { 44 | "branch-alias": { 45 | "dev-master": "1.0-dev" 46 | } 47 | }, 48 | "bin": [ 49 | "bin/jarvis" 50 | ] 51 | } 52 | -------------------------------------------------------------------------------- /skeleton/git_hooks/pre-commit: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env bash 2 | # 3 | # Only run when we're on a branch (to avoid rebase hell) 4 | # http://git-blame.blogspot.nl/2013/06/checking-current-branch-programatically.html 5 | if branch=$(git symbolic-ref --short -q HEAD); then 6 | echo on branch $branch 7 | else 8 | echo not on any branch 9 | exit 0 10 | fi 11 | 12 | if git rev-parse --verify HEAD >/dev/null 2>&1 13 | then 14 | against=HEAD 15 | else 16 | # Initial commit: diff against an empty tree object 17 | against=4b825dc642cb6eb9a060e54bf8d69288fbee4904 18 | fi 19 | 20 | # If you want to allow non-ASCII filenames set this variable to true. 21 | allownonascii=$(git config --bool hooks.allownonascii) 22 | 23 | # Cross platform projects tend to avoid non-ASCII filenames; prevent 24 | # them from being added to the repository. We exploit the fact that the 25 | # printable range starts at the space character and ends with tilde. 26 | if [ "$allownonascii" != "true" ] && 27 | # Note that the use of brackets around a tr range is ok here, (it's 28 | # even required, for portability to Solaris 10's /usr/bin/tr), since 29 | # the square bracket bytes happen to fall in the designated range. 30 | test $(git diff --cached --name-only --diff-filter=A -z $against | 31 | LC_ALL=C tr -d '[ -~]\0' | wc -c) != 0 32 | then 33 | cat <<\EOF 34 | Error: Attempt to add a non-ASCII file name. 35 | 36 | This can cause problems if you want to work with people on other platforms. 37 | 38 | To be portable it is advisable to rename the file. 39 | 40 | If you know what you are doing you can disable this check using: 41 | 42 | git config hooks.allownonascii true 43 | EOF 44 | exit 1 45 | fi 46 | 47 | 48 | {{jarvis_command_name}} project:git:pre-commit --project-name={{project_name}} 49 | -------------------------------------------------------------------------------- /src/Command/Vagrant/SshAddPrivateKeyCommand.php: -------------------------------------------------------------------------------- 1 | 14 | */ 15 | 16 | namespace Jarvis\Command\Vagrant; 17 | 18 | use Symfony\Component\Console\Input\InputInterface; 19 | use Symfony\Component\Console\Input\InputOption; 20 | use Symfony\Component\Console\Output\OutputInterface; 21 | use Jarvis\Vagrant\Configuration\SshConfiguration; 22 | 23 | class SshAddPrivateKeyCommand extends BaseCommand 24 | { 25 | /** 26 | * {@inheritdoc} 27 | */ 28 | protected function configure() 29 | { 30 | $this->setName('vagrant:ssh-add-private-key'); 31 | $this->setDescription('Add private ssh key'); 32 | $this->addOption('name', null, InputOption::VALUE_REQUIRED, 'Vagrant virtual machine name', 'default'); 33 | } 34 | 35 | /** 36 | * {@inheritdoc} 37 | */ 38 | protected function execute(InputInterface $input, OutputInterface $output) 39 | { 40 | if (!$this->isVirtualMachineRunning($input->getOption('name'))) { 41 | $output->writeln('The virtual machine not already started'); 42 | 43 | return; 44 | } 45 | 46 | $configuration = new SshConfiguration($this->getVagrantExec()); 47 | if ($configuration->has('IdentityFile')) { 48 | $this->getExec()->run(sprintf( 49 | 'ssh-add %s', 50 | $configuration->get('IdentityFile') 51 | ), $output); 52 | } 53 | } 54 | } 55 | -------------------------------------------------------------------------------- /src/Command/VirtualMachine/EnablePhpExtensionCommand.php: -------------------------------------------------------------------------------- 1 | 14 | */ 15 | 16 | namespace Jarvis\Command\VirtualMachine; 17 | 18 | use Symfony\Component\Console\Input\InputArgument; 19 | use Symfony\Component\Console\Input\InputInterface; 20 | use Symfony\Component\Console\Output\OutputInterface; 21 | 22 | class EnablePhpExtensionCommand extends BaseCommand 23 | { 24 | /** 25 | * {@inheritdoc} 26 | */ 27 | protected function configure() 28 | { 29 | $this->setDescription('Enables PHP extension in virtual machine'); 30 | 31 | $this->addArgument( 32 | 'name', 33 | InputArgument::REQUIRED, 34 | 'Extension name' 35 | ); 36 | } 37 | 38 | /** 39 | * {@inheritdoc} 40 | */ 41 | protected function execute(InputInterface $input, OutputInterface $output) 42 | { 43 | $this->getSshExec()->run(sprintf('sudo php5enmod %s', $input->getArgument('name')), $output); 44 | 45 | $this->getApplication()->executeCommand('vm:service:php-fpm:restart', [], $output); 46 | 47 | if ($this->getSshExec()->getLastReturnStatus() == 0) { // EXIT_SUCCESS 48 | $output->writeln(sprintf( 49 | 'PHP extension "%s" is enabled in virtual machine', 50 | $input->getArgument('name') 51 | )); 52 | } 53 | 54 | return $this->getSshExec()->getLastReturnStatus(); 55 | } 56 | } 57 | -------------------------------------------------------------------------------- /src/Command/Vagrant/UpgradeCommand.php: -------------------------------------------------------------------------------- 1 | 14 | */ 15 | 16 | namespace Jarvis\Command\Vagrant; 17 | 18 | use Symfony\Component\Console\Input\InputInterface; 19 | use Symfony\Component\Console\Input\InputOption; 20 | use Symfony\Component\Console\Output\OutputInterface; 21 | 22 | class UpgradeCommand extends BaseCommand 23 | { 24 | /** 25 | * {@inheritdoc} 26 | */ 27 | protected function configure() 28 | { 29 | $this->setName('vagrant:upgrade'); 30 | $this->setDescription('Updates the box that is in use in the current Vagrant environment.'); 31 | 32 | $this->addOption('provider', null, InputOption::VALUE_REQUIRED, 'Vagrant provider'); 33 | $this->addOption('name', null, InputOption::VALUE_REQUIRED, 'Vagrant virtual machine name', 'default'); 34 | } 35 | 36 | /** 37 | * {@inheritdoc} 38 | */ 39 | protected function execute(InputInterface $input, OutputInterface $output) 40 | { 41 | $this->getApplication()->executeCommand('vagrant:stop', [], $output); 42 | 43 | $options = []; 44 | if (null !== $input->getOption('provider')) { 45 | $options['provider'] = $input->getOption('provider'); 46 | } 47 | $this->getVagrantExec()->exec('box update', $options); 48 | 49 | $this->getVagrantExec()->exec('destroy'); 50 | 51 | $this->getApplication()->executeCommand('vagrant:start', $options, $output); 52 | } 53 | } 54 | -------------------------------------------------------------------------------- /src/Command/VirtualMachine/DisablePhpExtensionCommand.php: -------------------------------------------------------------------------------- 1 | 14 | */ 15 | 16 | namespace Jarvis\Command\VirtualMachine; 17 | 18 | use Symfony\Component\Console\Command\Command; 19 | use Symfony\Component\Console\Input\InputArgument; 20 | use Symfony\Component\Console\Input\InputInterface; 21 | use Symfony\Component\Console\Output\OutputInterface; 22 | use Symfony\Component\Process\ProcessBuilder; 23 | 24 | class DisablePhpExtensionCommand extends BaseCommand 25 | { 26 | /** 27 | * {@inheritdoc} 28 | */ 29 | protected function configure() 30 | { 31 | $this->setDescription('Disables PHP extension in virtual machine'); 32 | 33 | $this->addArgument( 34 | 'name', 35 | InputArgument::REQUIRED, 36 | 'Extension name' 37 | ); 38 | } 39 | 40 | /** 41 | * {@inheritdoc} 42 | */ 43 | protected function execute(InputInterface $input, OutputInterface $output) 44 | { 45 | $this->getSshExec()->run(sprintf('sudo php5dismod %s', $input->getArgument('name')), $output); 46 | 47 | $this->getApplication()->executeCommand('vm:service:php-fpm:restart', [], $output); 48 | 49 | if ($this->getSshExec()->getLastReturnStatus() == 0) { // EXIT_SUCCESS 50 | $output->writeln(sprintf( 51 | 'PHP extension "%s" is disabled in virtual machine', 52 | $input->getArgument('name') 53 | )); 54 | } 55 | 56 | return $this->getSshExec()->getLastReturnStatus(); 57 | } 58 | } 59 | -------------------------------------------------------------------------------- /src/Command/Project/PhpDocCommand.php: -------------------------------------------------------------------------------- 1 | 14 | */ 15 | 16 | namespace Jarvis\Command\Project; 17 | 18 | use Symfony\Component\Console\Output\OutputInterface; 19 | use Jarvis\Project\ProjectConfiguration; 20 | 21 | class PhpDocCommand extends BaseBuildCommand 22 | { 23 | /** 24 | * {@inheritdoc} 25 | */ 26 | protected function configure() 27 | { 28 | $this->setDescription('Generates the PHP API documentation for to one or all projects'); 29 | 30 | parent::configure(); 31 | } 32 | 33 | /** 34 | * {@inheritdoc} 35 | */ 36 | protected function executeCommandByProject($projectName, ProjectConfiguration $projectConfig, OutputInterface $output) 37 | { 38 | $this->getSshExec()->passthru( 39 | strtr( 40 | 'cd %project_dir% && /usr/local/bin/sami update sami_config.php'.($output->isDebug() ? ' -v' : ''), 41 | [ 42 | '%project_dir%' => $projectConfig->getRemoteWebappDir(), 43 | ] 44 | ) 45 | ); 46 | 47 | $localBuildDir = sprintf('%s/build/apidoc', $projectConfig->getLocalWebappDir()); 48 | $apiDocIndexFilepath = strtr( 49 | '%build_dir%/index.html', 50 | [ 51 | '%project_name%' => $projectConfig->getProjectName(), 52 | '%build_dir%' => $localBuildDir, 53 | ] 54 | ); 55 | 56 | if (file_exists($apiDocIndexFilepath)) { 57 | $this->openFile($apiDocIndexFilepath); 58 | } 59 | } 60 | } 61 | -------------------------------------------------------------------------------- /src/Command/Project/LintPhpCommand.php: -------------------------------------------------------------------------------- 1 | 14 | */ 15 | 16 | namespace Jarvis\Command\Project; 17 | 18 | use Symfony\Component\Console\Output\OutputInterface; 19 | use Jarvis\Project\ProjectConfiguration; 20 | 21 | class LintPhpCommand extends BaseBuildCommand 22 | { 23 | /** 24 | * @{inheritdoc} 25 | */ 26 | protected function configure() 27 | { 28 | $this->setDescription('Static code analysis the php files of sourcecode files'); 29 | 30 | parent::configure(); 31 | } 32 | 33 | /** 34 | * @{inheritdoc} 35 | */ 36 | protected function executeCommandByProject($projectName, ProjectConfiguration $projectConfig, OutputInterface $output) 37 | { 38 | $output->writeln(sprintf( 39 | '%s for project "%s"', 40 | $this->getDescription(), 41 | $projectName 42 | )); 43 | 44 | if (strpos($projectName, 'bundle') === false) { 45 | $commandLine = 'php-parallel-lint -e php -j 10 %project_dir%/app %project_dir%/src %project_dir%/web --exclude %project_dir%/vendor'; 46 | } else { 47 | $commandLine = 'php-parallel-lint -e php -j 10 %project_dir%/src'; 48 | } 49 | 50 | $this->getSshExec()->passthru( 51 | strtr( 52 | $commandLine, 53 | [ 54 | '%project_dir%' => $projectConfig->getRemoteWebappDir(), 55 | ] 56 | ) 57 | ); 58 | 59 | return $this->getSshExec()->getLastReturnStatus(); 60 | } 61 | } 62 | -------------------------------------------------------------------------------- /src/DependencyInjection/Compiler/CommandCompilerPass.php: -------------------------------------------------------------------------------- 1 | 14 | */ 15 | 16 | namespace Jarvis\DependencyInjection\Compiler; 17 | 18 | use ReflectionClass; 19 | use Symfony\Component\DependencyInjection\Compiler\CompilerPassInterface; 20 | use Symfony\Component\DependencyInjection\ContainerBuilder; 21 | use Symfony\Component\DependencyInjection\Reference; 22 | use Jarvis\DependencyInjection\Compiler\Exception; 23 | 24 | /** 25 | * Registers tagged command services with the console. 26 | * 27 | * @author Kevin Herrera 28 | */ 29 | class CommandCompilerPass implements CompilerPassInterface 30 | { 31 | /** 32 | * {@inheritDoc} 33 | */ 34 | public function process(ContainerBuilder $builder) 35 | { 36 | $ids = $builder->findTaggedServiceIds('console.command'); 37 | $console = $builder->getDefinition('console.application'); 38 | 39 | foreach ($ids as $id => $tags) { 40 | $command = $builder->getDefinition($id); 41 | 42 | if ($command->isAbstract()) { 43 | throw Exception::commandIsAbstract($id); 44 | } 45 | 46 | if (!$command->isPublic()) { 47 | throw Exception::commandIsNotPublic($id); 48 | } 49 | 50 | $reflect = new ReflectionClass($command->getClass()); 51 | 52 | if (!$reflect->isSubclassOf('Symfony\Component\Console\Command\Command')) { 53 | throw Exception::commandIsNotCommand($id); 54 | } 55 | 56 | $console->addMethodCall('add', array(new Reference($id))); 57 | } 58 | } 59 | } 60 | -------------------------------------------------------------------------------- /src/Command/Project/PhpCsCommand.php: -------------------------------------------------------------------------------- 1 | 14 | */ 15 | 16 | namespace Jarvis\Command\Project; 17 | 18 | use Symfony\Component\Console\Input\InputInterface; 19 | use Symfony\Component\Console\Input\InputOption; 20 | use Symfony\Component\Console\Output\OutputInterface; 21 | use Jarvis\Project\ProjectConfiguration; 22 | 23 | class PhpCsCommand extends BaseBuildCommand 24 | { 25 | use \Jarvis\Process\PhpCsFixerAwareTrait; 26 | 27 | private $fixCodingStandardProblems = false; 28 | 29 | /** 30 | * @{inheritdoc} 31 | */ 32 | protected function configure() 33 | { 34 | $this->setDescription('Check syntax the php files of sourcecode files'); 35 | $this->addOption('fix', null, InputOption::VALUE_NONE, 'Tries to fix as much coding standards problems as possible.'); 36 | 37 | parent::configure(); 38 | } 39 | 40 | /** 41 | * @{inheritdoc} 42 | */ 43 | protected function initialize(InputInterface $input, OutputInterface $output) 44 | { 45 | $this->fixCodingStandardProblems = $input->getOption('fix'); 46 | } 47 | 48 | /** 49 | * @{inheritdoc} 50 | */ 51 | protected function executeCommandByProject($projectName, ProjectConfiguration $projectConfig, OutputInterface $output) 52 | { 53 | $output->writeln(sprintf( 54 | '%s for project "%s"', 55 | $this->getDescription(), 56 | $projectName 57 | )); 58 | 59 | return $this->getPhpCsFixer()->fixRemoteDir( 60 | $projectConfig->getRemoteWebappDir(), 61 | $output, 62 | [ 63 | 'dry-run' => !$this->fixCodingStandardProblems 64 | ] 65 | ); 66 | } 67 | } 68 | -------------------------------------------------------------------------------- /src/Command/Project/SymfonyAssetsBuildCommand.php: -------------------------------------------------------------------------------- 1 | 14 | */ 15 | 16 | namespace Jarvis\Command\Project; 17 | 18 | use Symfony\Component\Console\Output\OutputInterface; 19 | use Jarvis\Project\ProjectConfiguration; 20 | 21 | class SymfonyAssetsBuildCommand extends BaseSymfonyCommand 22 | { 23 | use \Jarvis\Filesystem\LocalFilesystemAwareTrait; 24 | 25 | use \Jarvis\Filesystem\RemoteFilesystemAwareTrait; 26 | 27 | /** 28 | * @{inheritdoc} 29 | */ 30 | protected function configure() 31 | { 32 | $this->setDescription('Builds assets for to one or all projects'); 33 | 34 | parent::configure(); 35 | } 36 | 37 | /** 38 | * @{inheritdoc} 39 | */ 40 | protected function executeCommandByProject($projectName, ProjectConfiguration $projectConfig, OutputInterface $output) 41 | { 42 | $returnStatus = 0; 43 | 44 | foreach ($this->getSymfonyEnvs() as $symfonyEnv) { 45 | if (0 !== $returnStatus) { 46 | break; 47 | } 48 | 49 | $output->writeln(sprintf( 50 | '%s for project "%s" and env "%s"', 51 | $this->getDescription(), 52 | $projectName, 53 | $symfonyEnv 54 | )); 55 | 56 | $this->getSymfonyRemoteConsoleExec()->run( 57 | $projectConfig->getRemoteSymfonyConsolePath(), 58 | strtr('assets:install %dir%', ['%dir%' => $projectConfig->getRemoteAssetsDir()]), 59 | $symfonyEnv, 60 | $output 61 | ); 62 | 63 | $returnStatus = $this->getSymfonyRemoteConsoleExec()->getLastReturnStatus(); 64 | } 65 | 66 | return $returnStatus; 67 | } 68 | } 69 | -------------------------------------------------------------------------------- /src/DependencyInjection/Compiler/HelperCompilerPass.php: -------------------------------------------------------------------------------- 1 | 14 | */ 15 | 16 | namespace Jarvis\DependencyInjection\Compiler; 17 | 18 | use ReflectionClass; 19 | use Symfony\Component\DependencyInjection\Compiler\CompilerPassInterface; 20 | use Symfony\Component\DependencyInjection\ContainerBuilder; 21 | use Symfony\Component\DependencyInjection\Reference; 22 | use Jarvis\DependencyInjection\Compiler\Exception; 23 | 24 | /** 25 | * Registers tagged helper services with the console. 26 | * 27 | * @author Kevin Herrera 28 | */ 29 | class HelperCompilerPass implements CompilerPassInterface 30 | { 31 | /** 32 | * {@inheritDoc} 33 | */ 34 | public function process(ContainerBuilder $builder) 35 | { 36 | $ids = $builder->findTaggedServiceIds('console.helper'); 37 | $helperSet = $builder->getDefinition('console.helper_set'); 38 | 39 | foreach ($ids as $id => $tags) { 40 | $helper = $builder->getDefinition($id); 41 | 42 | if ($helper->isAbstract()) { 43 | throw Exception::helperIsAbstract($id); 44 | } 45 | 46 | if (!$helper->isPublic()) { 47 | throw Exception::helperIsNotPublic($id); 48 | } 49 | 50 | $reflect = new ReflectionClass($helper->getClass()); 51 | 52 | if (!$reflect->isSubclassOf('Symfony\Component\Console\Helper\Helper')) { 53 | throw Exception::helperIsNotHelper($id); 54 | } 55 | 56 | foreach ($tags as $tag) { 57 | $helperSet->addMethodCall( 58 | 'set', 59 | array( 60 | new Reference($id), 61 | isset($tag['alias']) ? $tag['alias'] : null 62 | ) 63 | ); 64 | } 65 | } 66 | } 67 | } 68 | -------------------------------------------------------------------------------- /src/Command/Core/CacheClearCommand.php: -------------------------------------------------------------------------------- 1 | 14 | */ 15 | 16 | namespace Jarvis\Command\Core; 17 | 18 | use Symfony\Component\Console\Command\Command; 19 | use Symfony\Component\Console\Input\InputArgument; 20 | use Symfony\Component\Console\Input\InputInterface; 21 | use Symfony\Component\Console\Input\InputOption; 22 | use Symfony\Component\Console\Output\OutputInterface; 23 | use Symfony\Component\DependencyInjection\ContainerAwareTrait; 24 | 25 | class CacheClearCommand extends Command 26 | { 27 | use ContainerAwareTrait; 28 | 29 | /** 30 | * {@inheritdoc} 31 | */ 32 | protected function configure() 33 | { 34 | $this 35 | ->setName('core:container:cache-clear') 36 | ->setDescription('Clears the cache') 37 | ->setHelp(<<%command.name% command clears the jarvis cache: 39 | 40 | php %command.full_name% 41 | EOF 42 | ) 43 | ; 44 | } 45 | 46 | /** 47 | * {@inheritdoc} 48 | */ 49 | protected function execute(InputInterface $input, OutputInterface $output) 50 | { 51 | $containerCacheDir = realpath($this->container->getParameter('cache_dir')); 52 | 53 | if (!$containerCacheDir) { 54 | $output->writeln('Cache directory does not exists'); 55 | return; 56 | } 57 | 58 | $filesystem = $this->container->get('local.filesystem'); 59 | 60 | if (!is_writable($containerCacheDir)) { 61 | throw new \RuntimeException(sprintf('Unable to write in the "%s" directory', $containerCacheDir)); 62 | } 63 | 64 | $output->writeln(' Removing old cache directory'); 65 | 66 | $filesystem->remove($containerCacheDir); 67 | $filesystem->mkdir($containerCacheDir); 68 | 69 | $output->writeln(' Done'); 70 | } 71 | } 72 | -------------------------------------------------------------------------------- /src/Command/VirtualMachine/SyncRemoteToLocalCommand.php: -------------------------------------------------------------------------------- 1 | 14 | */ 15 | 16 | namespace Jarvis\Command\VirtualMachine; 17 | 18 | use Symfony\Component\Console\Input\InputArgument; 19 | use Symfony\Component\Console\Input\InputInterface; 20 | use Symfony\Component\Console\Input\InputOption; 21 | use Symfony\Component\Console\Output\OutputInterface; 22 | use Jarvis\Project\ProjectConfiguration; 23 | 24 | class SyncRemoteToLocalCommand extends BaseCommand 25 | { 26 | use \Jarvis\Filesystem\LocalFilesystemAwareTrait; 27 | 28 | use \Jarvis\Filesystem\RemoteFilesystemAwareTrait; 29 | 30 | /** 31 | * @{inheritdoc} 32 | */ 33 | protected function configure() 34 | { 35 | $this->setDescription('Synchronize remote to local directory.'); 36 | 37 | $this->addArgument('remote_dir', InputArgument::REQUIRED, 'Remote directory'); 38 | $this->addArgument('local_dir', InputArgument::REQUIRED, 'Local directory'); 39 | 40 | $this->addOption('delete', null, InputOption::VALUE_NONE, 'Whether to delete files that are not in the source directory (defaults to false)'); 41 | 42 | $this->addOption('dry-run', null, InputOption::VALUE_NONE, 'Show what would have been transferred'); 43 | 44 | parent::configure(); 45 | } 46 | 47 | /** 48 | * {@inheritdoc} 49 | */ 50 | protected function execute(InputInterface $input, OutputInterface $output) 51 | { 52 | $this->getLocalFilesystem()->mkdir($input->getArgument('local_dir')); 53 | 54 | return $this->getRemoteFilesystem()->syncRemoteToLocal( 55 | $input->getArgument('remote_dir'), 56 | $input->getArgument('local_dir'), 57 | [ 58 | 'delete' => $input->getOption('delete'), 59 | 'dry_run' => $input->getOption('dry-run'), 60 | ] 61 | ); 62 | } 63 | } 64 | -------------------------------------------------------------------------------- /src/Command/Project/GitStatusCommand.php: -------------------------------------------------------------------------------- 1 | 14 | */ 15 | 16 | namespace Jarvis\Command\Project; 17 | 18 | use Symfony\Component\Console\Output\OutputInterface; 19 | use Jarvis\Project\ProjectConfiguration; 20 | 21 | class GitStatusCommand extends BaseGitCommand 22 | { 23 | /** 24 | * @{inheritdoc} 25 | */ 26 | protected function configure() 27 | { 28 | $this->setDescription('Git status for to one or all projects'); 29 | 30 | parent::configure(); 31 | } 32 | 33 | /** 34 | * @{inheritdoc} 35 | */ 36 | protected function executeCommandByProject($projectName, ProjectConfiguration $projectConfig, OutputInterface $output) 37 | { 38 | $output->writeln( 39 | sprintf( 40 | 'Git status for project "%s"', 41 | $projectName 42 | ) 43 | ); 44 | 45 | if (!is_dir($projectConfig->getLocalGitRepositoryDir())) { 46 | throw new \RuntimeException(sprintf('The directory "%s" does not exist', $projectConfig->getLocalGitRepositoryDir())); 47 | } 48 | 49 | $this->getExec()->passthru('git status', $projectConfig->getLocalGitRepositoryDir()); 50 | $output->writeln( 51 | strtr( 52 | ob_get_clean(), 53 | [ 54 | 'up-to-date' => 'up-to-date', 55 | 'is behind' => 'is behind', 56 | 'can be fast-forwarded' => 'can be fast-forwarded', 57 | 'modified:' => 'modified:', 58 | 'both modified' => 'both modified:', 59 | 'deleted:' => 'deleted:', // red color 60 | 'deleted by us' => 'deleted by us', // red color 61 | ] 62 | ) 63 | ); 64 | } 65 | } 66 | -------------------------------------------------------------------------------- /src/Command/Vagrant/BaseCommand.php: -------------------------------------------------------------------------------- 1 | 14 | */ 15 | 16 | namespace Jarvis\Command\Vagrant; 17 | 18 | use Symfony\Component\Console\Command\Command; 19 | use Symfony\Component\Console\Input\InputInterface; 20 | use Symfony\Component\Console\Input\InputOption; 21 | use Symfony\Component\Console\Output\OutputInterface; 22 | use Jarvis\Vagrant\Exec as VagrantExec; 23 | 24 | class BaseCommand extends Command 25 | { 26 | use \Jarvis\Process\ExecAwareTrait; 27 | use \Jarvis\Filesystem\LocalFilesystemAwareTrait; 28 | use \Jarvis\Vagrant\CheckVirtualMachineStatusTrait; 29 | 30 | /** 31 | * @var bool 32 | */ 33 | private $enabled = false; 34 | 35 | /** 36 | * @var VagrantExec 37 | */ 38 | private $vagrantExec; 39 | 40 | /** 41 | * @param bool $bool 42 | */ 43 | public function setEnabled($bool) 44 | { 45 | $this->enabled = $bool; 46 | 47 | return $this; 48 | } 49 | 50 | /** 51 | * {@inheritdoc} 52 | */ 53 | public function isEnabled() 54 | { 55 | return $this->enabled && $this->isVagrantFileExist(); 56 | } 57 | 58 | /** 59 | * Sets the value of vagrantExec. 60 | * 61 | * @param VagrantExec $vagrantExec the vagrant exec 62 | * 63 | * @return self 64 | */ 65 | public function setVagrantExec(VagrantExec $vagrantExec) 66 | { 67 | $this->vagrantExec = $vagrantExec; 68 | 69 | return $this; 70 | } 71 | 72 | /** 73 | * Gets the value of vagrantExec. 74 | * 75 | * @return VagrantExec 76 | */ 77 | public function getVagrantExec() 78 | { 79 | return $this->vagrantExec; 80 | } 81 | 82 | protected function isVagrantFileExist() 83 | { 84 | $vagrantFilePath = sprintf('%s/Vagrantfile', $this->getVagrantExec()->getCwd()); 85 | 86 | return $this->getLocalFilesystem()->exists($vagrantFilePath); 87 | } 88 | } 89 | -------------------------------------------------------------------------------- /src/Command/Project/ConfigShowCommand.php: -------------------------------------------------------------------------------- 1 | setDescription('Add project in configuration'); 28 | 29 | parent::configure(); 30 | } 31 | 32 | /** 33 | * {@inheritdoc} 34 | */ 35 | protected function getProjectNamesToExclude() 36 | { 37 | return []; 38 | } 39 | 40 | /** 41 | * {@inheritdoc} 42 | */ 43 | protected function executeCommandByProject($projectName, ProjectConfiguration $projectConfig, OutputInterface $output) 44 | { 45 | $accessor = PropertyAccess::createPropertyAccessor(); 46 | 47 | foreach ([ 48 | 'project_name', 49 | 'git_repository_url', 50 | 'local_git_repository_dir', 51 | 'remote_git_repository_dir', 52 | 'git_target_branch', 53 | 'remote_webapp_dir', 54 | 'local_webapp_dir', 55 | 'remote_vendor_dir', 56 | 'local_vendor_dir', 57 | 'remote_symfony_console_path', 58 | 'remote_phpunit_configuration_xml_path', 59 | ] as $propertyPath) { 60 | $propertyValue = $accessor->getValue($projectConfig, $propertyPath); 61 | if (null !== $propertyValue) { 62 | $output->writeln(sprintf( 63 | '%s: %s', 64 | $propertyPath, 65 | $propertyValue 66 | )); 67 | } 68 | } 69 | } 70 | } 71 | -------------------------------------------------------------------------------- /bin/bump-version.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | # inspiration from https://github.com/MattKetmo/cliph/blob/master/bump-version.sh 3 | set -e 4 | 5 | if [ $# -ne 1 ]; then 6 | echo "Usage: `basename $0` " 7 | exit 65 8 | fi 9 | 10 | 11 | # CHECK MASTER BRANCH 12 | CURRENT_BRANCH=$(git rev-parse --abbrev-ref HEAD) 13 | if [[ "$CURRENT_BRANCH" != "master" ]]; then 14 | echo "You have to be on master branch currently on $CURRENT_BRANCH . Aborting" 15 | exit 65 16 | fi 17 | 18 | # CHECK FORMAT OF THE TAG 19 | php -r "if(preg_match('/^\d+\.\d+\.\d+(?:-([0-9A-Za-z-]+(?:\.[0-9A-Za-z-]+)*))?(?:\+([0-9A-Za-z-]+(?:\.[0-9A-Za-z-]+)*))?\$/',\$argv[1])) exit(0) ;else{ echo 'format of version tag is not invalid' . PHP_EOL ; exit(1);}" $1 20 | 21 | # CHECK box COMMAND 22 | command -v box >/dev/null 2>&1 || { echo "Error : Command box is not installed on the system"; echo "See : https://github.com/box-project/box2 "; echo "Exiting..." >&2; exit 65; } 23 | 24 | # CHECK THAT WE CAN CHANGE BRANCH 25 | git checkout gh-pages 26 | git checkout --quiet master 27 | 28 | TAG=$1 29 | 30 | # 31 | # Tag & build master branch 32 | # 33 | git checkout master 34 | git flow release start ${TAG} 35 | git flow release finish ${TAG} 36 | 37 | rm -fr vendor 38 | composer install 39 | 40 | mkdir -p build 41 | ulimit -Sn 4096 42 | box build 43 | 44 | SHA1=$(openssl sha1 build/jarvis.phar | awk '{print $2}') 45 | 46 | echo ${SHA1} 47 | 48 | # 49 | # Copy executable file into GH pages 50 | # 51 | git checkout gh-pages 52 | 53 | mkdir -p releases/download/${TAG} 54 | cp build/jarvis.phar releases/download/${TAG}/jarvis.phar 55 | git add releases/download/${TAG}/jarvis.phar 56 | 57 | # 58 | # Update manifest 59 | # 60 | JSON='"name":"jarvis.phar"' 61 | JSON="${JSON},\"sha1\":\"${SHA1}\"" 62 | JSON="${JSON},\"url\":\"http://pagesjaunes.github.io/jarvis/releases/download/${TAG}/jarvis.phar\"" 63 | JSON="${JSON},\"version\":\"${TAG}\"" 64 | 65 | echo '[{'${JSON}'}]' > build/manifest.json.tmp 66 | 67 | jq -s add manifest.json build/manifest.json.tmp > manifest.json.tmp 68 | mv manifest.json.tmp manifest.json 69 | rm build/manifest.json.tmp 70 | git add manifest.json 71 | 72 | git commit -m "Bump version ${TAG}" 73 | 74 | # 75 | # Go back to master 76 | # 77 | git checkout master 78 | 79 | echo "New version created. Now you should run:" 80 | echo "git push origin master" 81 | echo "git push origin gh-pages" 82 | echo "git push --tags" 83 | -------------------------------------------------------------------------------- /src/Command/Project/SshCommand.php: -------------------------------------------------------------------------------- 1 | 14 | */ 15 | 16 | namespace Jarvis\Command\Project; 17 | 18 | use Symfony\Component\Console\Input\InputArgument; 19 | use Symfony\Component\Console\Input\InputInterface; 20 | use Symfony\Component\Console\Input\InputOption; 21 | use Symfony\Component\Console\Output\OutputInterface; 22 | use Jarvis\Project\ProjectConfiguration; 23 | 24 | class SshCommand extends BaseCommand 25 | { 26 | use \Jarvis\Ssh\SshExecAwareTrait; 27 | 28 | /** 29 | * @var string|null 30 | */ 31 | private $commandName; 32 | 33 | /** 34 | * @{inheritdoc} 35 | */ 36 | protected function configure() 37 | { 38 | parent::configure(); 39 | 40 | $this->setDescription('This command will SSH into a running remote machine and give you access to a shell in project directory.'); 41 | 42 | $this->addArgument( 43 | 'command_name', 44 | InputArgument::OPTIONAL, 45 | 'Which command to run using ssh with working directory to project', 46 | 'bash' 47 | ); 48 | } 49 | 50 | /** 51 | * @{inheritdoc} 52 | */ 53 | protected function initialize(InputInterface $input, OutputInterface $output) 54 | { 55 | if (null !== $input->getArgument('command_name')) { 56 | $this->commandName = $input->getArgument('command_name'); 57 | } 58 | } 59 | 60 | /** 61 | * @{inheritdoc} 62 | */ 63 | protected function executeCommandByProject($projectName, ProjectConfiguration $projectConfig, OutputInterface $output) 64 | { 65 | $this->getSshExec()->passthru( 66 | strtr( 67 | 'cd %project_dir%;%command_name%', 68 | [ 69 | '%project_dir%' => $projectConfig->getRemoteWebappDir(), 70 | '%command_name%' => escapeshellcmd($this->commandName) 71 | ] 72 | ) 73 | ); 74 | 75 | return $this->getSshExec()->getLastReturnStatus(); 76 | } 77 | } 78 | -------------------------------------------------------------------------------- /src/Command/Project/LintYamlCommand.php: -------------------------------------------------------------------------------- 1 | 14 | */ 15 | 16 | namespace Jarvis\Command\Project; 17 | 18 | use Symfony\Component\Console\Output\OutputInterface; 19 | use Jarvis\Project\ProjectConfiguration; 20 | 21 | class LintYamlCommand extends BaseSymfonyCommand 22 | { 23 | /** 24 | * @{inheritdoc} 25 | */ 26 | protected function configure() 27 | { 28 | $this->setDescription('Lints a file YAML and outputs encountered errors'); 29 | 30 | parent::configure(); 31 | } 32 | 33 | /** 34 | * @{inheritdoc} 35 | */ 36 | protected function executeCommandByProject($projectName, ProjectConfiguration $projectConfig, OutputInterface $output) 37 | { 38 | $returnStatus = 0; 39 | 40 | foreach ($this->getSymfonyEnvs() as $symfonyEnv) { 41 | if (0 !== $returnStatus) { 42 | break; 43 | } 44 | 45 | $output->writeln(sprintf( 46 | '%s for project "%s" and env "%s"', 47 | $this->getDescription(), 48 | $projectName, 49 | $symfonyEnv 50 | )); 51 | 52 | if (! file_exists($projectConfig->getLocalVendorDir())) { 53 | $this->getApplication()->executeCommand('project:composer:install', [ 54 | '--project-name' => $projectName, 55 | ], $output); 56 | } 57 | 58 | $this->getSymfonyRemoteConsoleExec()->run( 59 | $projectConfig->getRemoteSymfonyConsolePath(), 60 | strtr( 61 | 'lint:yaml %project_dir%/src', 62 | [ 63 | '%project_dir%' => $projectConfig->getRemoteWebappDir(), 64 | ]), 65 | $symfonyEnv, 66 | $output 67 | ); 68 | 69 | $returnStatus = $this->getSymfonyRemoteConsoleExec()->getLastReturnStatus(); 70 | } 71 | 72 | return $returnStatus; 73 | } 74 | } 75 | -------------------------------------------------------------------------------- /src/Command/Vagrant/StartCommand.php: -------------------------------------------------------------------------------- 1 | 14 | */ 15 | 16 | namespace Jarvis\Command\Vagrant; 17 | 18 | use Symfony\Component\Console\Input\InputInterface; 19 | use Symfony\Component\Console\Input\InputOption; 20 | use Symfony\Component\Console\Output\OutputInterface; 21 | use Jarvis\Vagrant\Configuration\SshConfiguration; 22 | 23 | class StartCommand extends BaseCommand 24 | { 25 | /** 26 | * {@inheritdoc} 27 | */ 28 | protected function configure() 29 | { 30 | $this->setName('vagrant:start'); 31 | $this->setDescription('Starts and provisions the virtual machine'); 32 | 33 | $this->addOption('provider', null, InputOption::VALUE_REQUIRED, 'Vagrant provider'); 34 | $this->addOption('name', null, InputOption::VALUE_REQUIRED, 'Vagrant virtual machine name', 'default'); 35 | $this->addOption('force', null, InputOption::VALUE_NONE, 'Shut it down forcefully virtual machine name before start it'); 36 | $this->addOption('no-ssh-add-private-key', null, InputOption::VALUE_NONE, ''); 37 | } 38 | 39 | /** 40 | * {@inheritdoc} 41 | */ 42 | protected function execute(InputInterface $input, OutputInterface $output) 43 | { 44 | if ($this->isVirtualMachineRunning($input->getOption('name'))) { 45 | $output->writeln('The virtual machine already started'); 46 | 47 | return; 48 | } 49 | 50 | if ($input->hasOption('force')) { 51 | $this->getVagrantExec()->exec('halt'); 52 | } 53 | 54 | $options = []; 55 | if (null !== $input->getOption('provider')) { 56 | $options['provider'] = $input->getOption('provider'); 57 | } 58 | $this->getVagrantExec()->exec('up', $options); 59 | 60 | if (false === $input->getOption('no-ssh-add-private-key')) { 61 | $this->getApplication()->executeCommand( 62 | 'vagrant:ssh-add-private-key', 63 | [], 64 | $output 65 | ); 66 | } 67 | } 68 | } 69 | -------------------------------------------------------------------------------- /src/Command/Project/LintTwigCommand.php: -------------------------------------------------------------------------------- 1 | 14 | */ 15 | 16 | namespace Jarvis\Command\Project; 17 | 18 | use Symfony\Component\Console\Output\OutputInterface; 19 | use Jarvis\Project\ProjectConfiguration; 20 | 21 | class LintTwigCommand extends BaseSymfonyCommand 22 | { 23 | /** 24 | * @{inheritdoc} 25 | */ 26 | protected function configure() 27 | { 28 | $this->setDescription('Lints a template TWIG and outputs encountered errors'); 29 | 30 | parent::configure(); 31 | } 32 | 33 | /** 34 | * @{inheritdoc} 35 | */ 36 | protected function executeCommandByProject($projectName, ProjectConfiguration $projectConfig, OutputInterface $output) 37 | { 38 | $returnStatus = 0; 39 | 40 | foreach ($this->getSymfonyEnvs() as $symfonyEnv) { 41 | if (0 !== $returnStatus) { 42 | break; 43 | } 44 | 45 | $output->writeln(sprintf( 46 | '%s for project "%s" and env "%s"', 47 | $this->getDescription(), 48 | $projectName, 49 | $symfonyEnv 50 | )); 51 | 52 | if (! file_exists($projectConfig->getLocalVendorDir())) { 53 | $this->getApplication()->executeCommand('project:composer:install', [ 54 | '--project-name' => $projectName, 55 | ], $output); 56 | } 57 | 58 | $this->getSymfonyRemoteConsoleExec()->run( 59 | $projectConfig->getRemoteSymfonyConsolePath(), 60 | strtr( 61 | 'lint:twig %project_dir%/src', 62 | [ 63 | '%project_dir%' => $projectConfig->getRemoteWebappDir(), 64 | ] 65 | ), 66 | $symfonyEnv, 67 | $output 68 | ); 69 | 70 | $returnStatus = $this->getSymfonyRemoteConsoleExec()->getLastReturnStatus(); 71 | } 72 | 73 | return $returnStatus; 74 | } 75 | } 76 | -------------------------------------------------------------------------------- /config/services/command.core.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 6 | 7 | 8 | 12 | 13 | 14 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 28 | 29 | 30 | 31 | 32 | 33 | 34 | 38 | 39 | %phar_update_manifest_url% 40 | 41 | 42 | 43 | 44 | 45 | 46 | 47 | 48 | 49 | 50 | 51 | 52 | 56 | 57 | %cache_dir% 58 | 59 | 60 | 61 | 62 | 63 | 64 | 65 | 66 | 67 | 68 | -------------------------------------------------------------------------------- /src/Console/Readline/Autocompleter/Fuzzy.php: -------------------------------------------------------------------------------- 1 | 14 | */ 15 | 16 | namespace Jarvis\Console\Readline\Autocompleter; 17 | 18 | use Hoa\Console\Readline\Autocompleter\Autocompleter; 19 | use Jarvis\Ustring\Search; 20 | 21 | /** 22 | * Class \Hoa\Console\Readline\Autocompleter\Word. 23 | * 24 | * The fuzzy auto-completer: complete a word. 25 | */ 26 | class Fuzzy implements Autocompleter 27 | { 28 | /** 29 | * List of words. 30 | * 31 | * @var array 32 | */ 33 | protected $words; 34 | 35 | /** 36 | * @var Search 37 | */ 38 | protected $search; 39 | 40 | /** 41 | * Constructor. 42 | * 43 | * @param array $words Words. 44 | */ 45 | public function __construct(array $words, Search $search) 46 | { 47 | $this->words = $words; 48 | $this->search = $search; 49 | 50 | return; 51 | } 52 | 53 | /** 54 | * Complete a word. 55 | * Returns null for no word, a full-word or an array of full-words. 56 | * 57 | * @param string &$prefix Prefix to autocomplete. 58 | * 59 | * @return mixed 60 | */ 61 | public function complete(&$prefix) 62 | { 63 | $out = []; 64 | foreach ($this->search->fuzzy($this->words, $prefix) as $result) { 65 | $out[$result['match']] = $result['score']; 66 | } 67 | asort($out); 68 | 69 | if (0 === count($out)) { 70 | return; 71 | } 72 | 73 | if (1 === count($out)) { 74 | return key($out); 75 | } 76 | 77 | return array_keys($out); 78 | } 79 | 80 | /** 81 | * Get definition of a word. 82 | * 83 | * @return string 84 | */ 85 | public function getWordDefinition() 86 | { 87 | return '\b(\w|\-|_)+\b'; 88 | } 89 | 90 | /** 91 | * Set list of words. 92 | * 93 | * @param array $words Words. 94 | */ 95 | public function setWords(Array $words) 96 | { 97 | $this->words = $words; 98 | } 99 | } 100 | -------------------------------------------------------------------------------- /src/Ustring/Search.php: -------------------------------------------------------------------------------- 1 | 14 | */ 15 | 16 | namespace Jarvis\Ustring; 17 | 18 | class Search 19 | { 20 | /** 21 | * Perform a fuzzy string searching. 22 | * 23 | * @param string $searchSet is an array of possible matches (strings) 24 | * @param string $query is the string to search for 25 | * 26 | * @return array return a map with term match and score 27 | */ 28 | public function fuzzy($searchSet, $query) 29 | { 30 | $results = []; 31 | 32 | $query = strtolower($query); 33 | 34 | foreach ($searchSet as $word) { 35 | if ($word == $query) { // has exact match 36 | $results[] = [ 37 | 'match' => $word, 38 | 'score' => 0, 39 | ]; 40 | 41 | return $results; 42 | } 43 | 44 | $pos = strpos($word, $query); 45 | if (false !== $pos) { 46 | $results[] = [ 47 | 'match' => $word, 48 | 'score' => $pos, 49 | ]; 50 | } 51 | } 52 | 53 | if (0 === count($results)) { 54 | // Fuzzy search implements a fuzzy string search in the style of Sublime Text 55 | $tokens = str_split($query); 56 | foreach ($searchSet as $word) { 57 | $tokenIndex = 0; 58 | $score = 0; 59 | $word = strtolower($word); 60 | foreach (str_split($word) as $wordIndex => $letter) { 61 | if (isset($tokens[$tokenIndex]) && $letter === $tokens[$tokenIndex]) { 62 | ++$tokenIndex; 63 | ++$score; 64 | if ($tokenIndex >= count($tokens)) { 65 | $results[] = [ 66 | 'match' => $word, 67 | 'score' => $score, 68 | ]; 69 | break; 70 | } 71 | } 72 | } 73 | } 74 | } 75 | 76 | return $results; 77 | } 78 | } 79 | -------------------------------------------------------------------------------- /src/Command/Project/GitGuiCommand.php: -------------------------------------------------------------------------------- 1 | 14 | */ 15 | 16 | namespace Jarvis\Command\Project; 17 | 18 | use Symfony\Component\Console\Input\InputInterface; 19 | use Symfony\Component\Console\Input\InputOption; 20 | use Symfony\Component\Console\Output\OutputInterface; 21 | use Jarvis\Project\ProjectConfiguration; 22 | 23 | class GitGuiCommand extends BaseGitCommand 24 | { 25 | /** 26 | * @var string 27 | */ 28 | private $executable; 29 | 30 | /** 31 | * @{inheritdoc} 32 | */ 33 | protected function configure() 34 | { 35 | $this->setDescription('Opens Git gui for to one or all projects'); 36 | 37 | parent::configure(); 38 | 39 | $this->addOption('client-name', null, InputOption::VALUE_REQUIRED, 'Which GUI Client to use', $this->getDefaultClient()); 40 | } 41 | 42 | /** 43 | * @{inheritdoc} 44 | */ 45 | protected function initialize(InputInterface $input, OutputInterface $output) 46 | { 47 | $this->executable = $input->getOption('client-name'); 48 | } 49 | 50 | /** 51 | * @{inheritdoc} 52 | */ 53 | protected function executeCommandByProject($projectName, ProjectConfiguration $projectConfig, OutputInterface $output) 54 | { 55 | $output->writeln( 56 | sprintf( 57 | 'Opens Git gui for the project "%s"', 58 | $projectName 59 | ) 60 | ); 61 | 62 | if (!is_dir($projectConfig->getLocalGitRepositoryDir())) { 63 | throw new \RuntimeException(sprintf( 64 | 'The directory "%s" does not exist', 65 | $projectConfig->getLocalGitRepositoryDir() 66 | )); 67 | } 68 | 69 | $this->getExec()->passthru( 70 | $this->executable, 71 | $projectConfig->getLocalGitRepositoryDir() 72 | ); 73 | } 74 | 75 | /** 76 | * @return string 77 | */ 78 | protected function getDefaultClient() 79 | { 80 | if (strtoupper(PHP_OS) === 'DARWIN') { 81 | return 'gitup'; 82 | } else { 83 | return 'gitk'; 84 | } 85 | } 86 | } 87 | -------------------------------------------------------------------------------- /src/Command/Project/BaseBuildCommand.php: -------------------------------------------------------------------------------- 1 | 14 | */ 15 | 16 | namespace Jarvis\Command\Project; 17 | 18 | abstract class BaseBuildCommand extends BaseCommand 19 | { 20 | use \Jarvis\Filesystem\LocalFilesystemAwareTrait; 21 | use \Jarvis\Filesystem\RemoteFilesystemAwareTrait; 22 | use \Jarvis\Process\ExecAwareTrait; 23 | use \Jarvis\Ssh\SshExecAwareTrait; 24 | 25 | /** 26 | * @var string 27 | */ 28 | private $remoteBuildDir; 29 | 30 | /** 31 | * @var string 32 | */ 33 | private $localBuildDir; 34 | 35 | /** 36 | * Sets the value of remoteBuildDir. 37 | * 38 | * @param string $remoteBuildDir the remote build dir 39 | * 40 | * @return self 41 | */ 42 | public function setRemoteBuildDir($remoteBuildDir) 43 | { 44 | $this->remoteBuildDir = $remoteBuildDir; 45 | 46 | return $this; 47 | } 48 | 49 | /** 50 | * Sets the value of localBuildDir. 51 | * 52 | * @param string $localBuildDir the local build dir 53 | * 54 | * @return self 55 | */ 56 | public function setLocalBuildDir($localBuildDir) 57 | { 58 | $this->localBuildDir = $localBuildDir; 59 | 60 | return $this; 61 | } 62 | 63 | /** 64 | * Gets the value of remoteBuildDir. 65 | * 66 | * @return string 67 | */ 68 | public function getRemoteBuildDir() 69 | { 70 | if (null === $this->remoteBuildDir) { 71 | throw new \LogicException('Local build directory is not defined'); 72 | } 73 | 74 | return $this->remoteBuildDir; 75 | } 76 | 77 | /** 78 | * Gets the value of localBuildDir. 79 | * 80 | * @return string 81 | */ 82 | public function getLocalBuildDir() 83 | { 84 | if (null === $this->localBuildDir) { 85 | throw new \LogicException('Local build directory is not defined'); 86 | } 87 | 88 | return $this->localBuildDir; 89 | } 90 | 91 | public function openFile($filepath) 92 | { 93 | $this->getExec()->exec(strtr( 94 | 'which xdg-open && xdg-open %file% || which open && open %file%', 95 | [ 96 | '%file%' => $filepath 97 | ] 98 | )); 99 | } 100 | } 101 | -------------------------------------------------------------------------------- /config/services/command.project.build.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 6 | 7 | 8 | false 9 | 10 | 11 | 12 | 13 | 17 | 18 | 19 | 20 | 21 | 22 | %remote_build_dir% 23 | 24 | 25 | 26 | %local_build_dir% 27 | 28 | 29 | 30 | 31 | 32 | 33 | 34 | 35 | 36 | 37 | 38 | 39 | 40 | 41 | 42 | 43 | 44 | 45 | 46 | %command.project.enabled% 47 | 48 | 49 | 50 | 55 | project:php:metrics 56 | 57 | 58 | %command.project.build.enabled% 59 | 60 | 61 | 62 | 63 | 64 | 69 | project:php:doc 70 | 71 | 72 | %command.project.build.enabled% 73 | 74 | 75 | 76 | 77 | 78 | 79 | -------------------------------------------------------------------------------- /src/Command/VirtualMachine/BlackfireInstallCommand.php: -------------------------------------------------------------------------------- 1 | 14 | */ 15 | 16 | namespace Jarvis\Command\VirtualMachine; 17 | 18 | use Symfony\Component\Console\Input\InputArgument; 19 | use Symfony\Component\Console\Input\InputInterface; 20 | use Symfony\Component\Console\Output\OutputInterface; 21 | 22 | class BlackfireInstallCommand extends BaseCommand 23 | { 24 | /** 25 | * {@inheritdoc} 26 | */ 27 | protected function configure() 28 | { 29 | $this->setDescription('Installing Blackfire'); 30 | } 31 | 32 | /** 33 | * {@inheritdoc} 34 | */ 35 | protected function execute(InputInterface $input, OutputInterface $output) 36 | { 37 | $this->getSshExec()->run('wget -O - https://packagecloud.io/gpg.key | sudo apt-key add -', $output); 38 | if ($this->getSshExec()->getLastReturnStatus() == 0) { 39 | $this->getSshExec()->run('echo "deb http://packages.blackfire.io/debian any main" | sudo tee /etc/apt/sources.list.d/blackfire.list', $output); 40 | } 41 | if ($this->getSshExec()->getLastReturnStatus() == 0) { 42 | $this->getSshExec()->run('sudo apt-get update', $output); 43 | } 44 | if ($this->getSshExec()->getLastReturnStatus() == 0) { 45 | $this->getSshExec()->run('sudo apt-get install blackfire-agent', $output); 46 | } 47 | if ($this->getSshExec()->getLastReturnStatus() == 0) { 48 | $this->getSshExec()->passthru('sudo blackfire-agent -config="/etc/blackfire/agent" -register'); 49 | } 50 | if ($this->getSshExec()->getLastReturnStatus() == 0) { 51 | $this->getSshExec()->passthru('sudo blackfire-agent -config="/etc/blackfire/agent" -d'); 52 | } 53 | if ($this->getSshExec()->getLastReturnStatus() == 0) { 54 | $this->getSshExec()->run('sudo /etc/init.d/blackfire-agent restart', $output); 55 | } 56 | if ($this->getSshExec()->getLastReturnStatus() == 0) { 57 | $this->getSshExec()->passthru('blackfire config'); 58 | } 59 | if ($this->getSshExec()->getLastReturnStatus() == 0) { 60 | $this->getSshExec()->run('sudo apt-get install blackfire-php', $output); 61 | } 62 | if ($this->getSshExec()->getLastReturnStatus() == 0) { 63 | $this->getApplication()->executeCommand('vm:service:php-fpm:restart', [], $output); 64 | } 65 | 66 | return $this->getSshExec()->getLastReturnStatus(); 67 | } 68 | } 69 | -------------------------------------------------------------------------------- /config/services/command.vm.php_tools.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 6 | 7 | 8 | true 9 | 10 | 11 | 12 | 17 | vm:php_tools:install 18 | 19 | 20 | install 21 | 22 | 23 | 24 | 25 | 26 | 27 | 28 | 29 | 30 | 35 | vm:php_tools:update 36 | 37 | 38 | update 39 | 40 | 41 | 42 | 43 | 44 | 45 | 46 | 47 | 48 | 53 | vm:php_tools:version 54 | 55 | 56 | version 57 | 58 | 59 | 60 | 61 | 62 | 63 | 64 | 65 | 66 | 71 | vm:php_tools:status 72 | 73 | 74 | status 75 | 76 | 77 | 78 | 79 | 80 | 81 | 82 | 83 | 84 | 85 | -------------------------------------------------------------------------------- /src/Command/Project/InstallDependenciesAndAssetsCommand.php: -------------------------------------------------------------------------------- 1 | 14 | */ 15 | 16 | namespace Jarvis\Command\Project; 17 | 18 | use Symfony\Component\Console\Output\OutputInterface; 19 | use Jarvis\Project\ProjectConfiguration; 20 | 21 | class InstallDependenciesAndAssetsCommand extends BaseSymfonyCommand 22 | { 23 | /** 24 | * {@inheritdoc} 25 | */ 26 | protected function configure() 27 | { 28 | parent::configure(); 29 | 30 | $this->setDescription('Install dependencies with composer and build assets.'); 31 | } 32 | 33 | /** 34 | * {@inheritdoc} 35 | */ 36 | protected function executeCommandByProject($projectName, ProjectConfiguration $projectConfig, OutputInterface $output) 37 | { 38 | $returnStatus = 0; 39 | foreach ($this->getSymfonyEnvs() as $symfonyEnv) { 40 | $returnStatus = $this->composerInstall($projectName, $symfonyEnv, $output); 41 | 42 | if (0 == $returnStatus) { 43 | $returnStatus = $this->cacheWarmup($projectName, $symfonyEnv, $output); 44 | } 45 | 46 | if (0 == $returnStatus) { 47 | $returnStatus = $this->buildAssets($projectName, $symfonyEnv, $output); 48 | } 49 | } 50 | 51 | return $returnStatus; 52 | } 53 | 54 | protected function composerInstall($projectName, $symfonyEnv, OutputInterface $output) 55 | { 56 | $parameters = [ 57 | '--project-name' => $projectName, 58 | ]; 59 | 60 | if ($symfonyEnv == 'prod') { 61 | $parameters['--optimize-autoloader'] = true; 62 | $parameters['--prefer-dist'] = true; 63 | $parameters['--no-dev'] = true; 64 | } 65 | 66 | return $this->getApplication()->executeCommand('project:composer:install', $parameters, $output); 67 | } 68 | 69 | protected function cacheWarmup($projectName, $symfonyEnv, OutputInterface $output) 70 | { 71 | return $this->getApplication()->executeCommand('project:symfony:cache:warmup', [ 72 | '--project-name' => $projectName, 73 | '--symfony-env' => [$symfonyEnv], 74 | ], $output); 75 | } 76 | 77 | protected function buildAssets($projectName, $symfonyEnv, OutputInterface $output) 78 | { 79 | return $this->getApplication()->executeCommand('project:assets:build', [ 80 | '--project-name' => $projectName, 81 | '--symfony-env' => [$symfonyEnv], 82 | ], $output); 83 | } 84 | } 85 | -------------------------------------------------------------------------------- /src/Composer/GraphComposer.php: -------------------------------------------------------------------------------- 1 | 14 | */ 15 | 16 | namespace Jarvis\Composer; 17 | 18 | use \JMS\Composer\Graph\DependencyGraph; 19 | use Fhaculty\Graph\Graph; 20 | 21 | class GraphComposer 22 | { 23 | private $layoutVertex = array( 24 | 'fillcolor' => '#eeeeee', 25 | 'style' => 'filled, rounded', 26 | 'shape' => 'box', 27 | 'fontcolor' => '#314B5F', 28 | ); 29 | 30 | private $layoutEdge = array( 31 | 'fontcolor' => '#FFEBFF', 32 | 'fontsize' => 10, 33 | 'color' => '#1A2833', 34 | ); 35 | 36 | private $dependencyGraph; 37 | 38 | /** 39 | * 40 | * @param DependencyGraph $dependencyGraph 41 | */ 42 | public function __construct(DependencyGraph $dependencyGraph) 43 | { 44 | $this->dependencyGraph = $dependencyGraph; 45 | } 46 | 47 | /** 48 | * 49 | * @param string $dir 50 | * @return \Fhaculty\Graph\Graph 51 | */ 52 | public function createGraph($vendorName = null, $excludeDevDependency = true) 53 | { 54 | $graph = new Graph(); 55 | 56 | foreach ($this->dependencyGraph->getPackages() as $package) { 57 | $name = $package->getName(); 58 | 59 | if (null !== $vendorName && false === strpos($name, $vendorName)) { 60 | continue; 61 | } 62 | 63 | $start = $graph->createVertex($name, true); 64 | 65 | $label = $name; 66 | if ($package->getVersion() !== null) { 67 | $label .= ': '.$package->getVersion(); 68 | } 69 | 70 | $start->setLayout(array('label' => $label) + $this->getLayoutVertex($name)); 71 | 72 | foreach ($package->getOutEdges() as $requires) { 73 | $targetName = $requires->getDestPackage()->getName(); 74 | 75 | if (null !== $vendorName && false === strpos($targetName, $vendorName)) { 76 | continue; 77 | } 78 | 79 | if ($excludeDevDependency && $requires->isDevDependency()) { 80 | continue; 81 | } 82 | 83 | $target = $graph->createVertex($targetName, true); 84 | 85 | $label = $requires->getVersionConstraint(); 86 | 87 | $start->createEdgeTo($target)->setLayout(array('label' => $label) + $this->layoutEdge); 88 | } 89 | } 90 | 91 | return $graph; 92 | } 93 | 94 | private function getLayoutVertex($packageName) 95 | { 96 | return $this->layoutVertex; 97 | } 98 | } 99 | -------------------------------------------------------------------------------- /src/Vagrant/Configuration/SshConfiguration.php: -------------------------------------------------------------------------------- 1 | 14 | */ 15 | 16 | namespace Jarvis\Vagrant\Configuration; 17 | 18 | use Jarvis\Vagrant\Exec; 19 | 20 | class SshConfiguration 21 | { 22 | /** 23 | * @var Exec 24 | */ 25 | private $exec; 26 | 27 | /** 28 | * @var null|array 29 | */ 30 | private $parameters; 31 | 32 | public function __construct(Exec $exec, array $parameters = null) 33 | { 34 | $this->exec = $exec; 35 | $this->parameters = $parameters; 36 | } 37 | 38 | /** 39 | * Returns the parameters. 40 | * 41 | * @return array An array of parameters 42 | * 43 | * @api 44 | */ 45 | public function all() 46 | { 47 | $this->init(); 48 | 49 | return $this->parameters; 50 | } 51 | 52 | /** 53 | * Returns a parameter by name. 54 | * 55 | * @param string $path The key 56 | * @param mixed $default The default value if the parameter key does not exist 57 | * 58 | * @return mixed 59 | * 60 | * @throws \InvalidArgumentException 61 | * 62 | * @api 63 | */ 64 | public function get($path, $default = null) 65 | { 66 | $this->init(); 67 | 68 | return array_key_exists($path, $this->parameters) ? $this->parameters[$path] : $default; 69 | } 70 | 71 | /** 72 | * Returns true if the parameter is defined. 73 | * 74 | * @param string $key The key 75 | * 76 | * @return bool true if the parameter exists, false otherwise 77 | * 78 | * @api 79 | */ 80 | public function has($key) 81 | { 82 | $this->init(); 83 | 84 | return array_key_exists($key, $this->parameters); 85 | } 86 | 87 | protected function init() 88 | { 89 | if (null === $this->parameters) { 90 | $this->parse(); 91 | } 92 | } 93 | 94 | protected function parse() 95 | { 96 | $result = $this->exec->run(sprintf( 97 | 'ssh-config %s', 98 | 'default' 99 | // $input->getOption('name') 100 | )); 101 | 102 | $parts = explode("\n", $result); 103 | $parts = array_map('trim', $parts); 104 | 105 | $this->parameters = []; 106 | foreach ($parts as $part) { 107 | $subparts = explode(' ', $part); 108 | if (isset($subparts[1])) { 109 | $this->parameters[$subparts[0]] = $subparts[1]; 110 | } 111 | } 112 | } 113 | } 114 | -------------------------------------------------------------------------------- /config/services/command.project.lint.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 6 | 7 | 8 | false 9 | 10 | 11 | 12 | 17 | project:lint:all 18 | 19 | 20 | %command.project.lint.enabled% 21 | 22 | 23 | 24 | 25 | 26 | 31 | project:lint:php 32 | 33 | 34 | 35 | 36 | 37 | 38 | %command.project.lint.enabled% 39 | 40 | 41 | 42 | 43 | 44 | 49 | project:lint:twig 50 | 51 | 52 | %command.project.lint.enabled% 53 | 54 | 55 | 56 | 57 | 58 | 63 | project:lint:yaml 64 | 65 | 66 | %command.project.lint.enabled% 67 | 68 | 69 | 70 | 71 | 72 | 77 | project:lint:scss 78 | 79 | 80 | %working_dir% 81 | 82 | 83 | 84 | %command.project.lint.enabled% 85 | 86 | 87 | 88 | 89 | 90 | 91 | 92 | -------------------------------------------------------------------------------- /src/Command/Project/GitSummaryCommand.php: -------------------------------------------------------------------------------- 1 | 14 | */ 15 | 16 | namespace Jarvis\Command\Project; 17 | 18 | use Symfony\Component\Console\Output\OutputInterface; 19 | use Jarvis\Project\ProjectConfiguration; 20 | 21 | class GitSummaryCommand extends BaseGitCommand 22 | { 23 | /** 24 | * {@inheritdoc} 25 | */ 26 | protected function configure() 27 | { 28 | $this->setDescription('Retrieve contributors to to one project or all projects, both large and small'); 29 | 30 | parent::configure(); 31 | } 32 | 33 | /** 34 | * {@inheritdoc} 35 | */ 36 | protected function executeCommandByProject($projectName, ProjectConfiguration $projectConfig, OutputInterface $output) 37 | { 38 | $output->writeln( 39 | sprintf( 40 | 'Git contributors for project "%s"', 41 | $projectName 42 | ) 43 | ); 44 | 45 | if (!is_dir($projectConfig->getLocalGitRepositoryDir())) { 46 | throw new \RuntimeException(sprintf('The directory "%s" does not exist', $projectConfig->getLocalGitRepositoryDir())); 47 | } 48 | 49 | $output->writeln('repo age: '.$this->getRepositoryAge($projectConfig->getLocalGitRepositoryDir())); 50 | $output->writeln('commits: '.$this->getCommitCount($projectConfig->getLocalGitRepositoryDir())); 51 | $output->writeln('authors:'); 52 | $output->writeln($this->getListAuthors($projectConfig->getLocalGitRepositoryDir())); 53 | $output->writeln(''); 54 | } 55 | 56 | /** 57 | * Fetch repository age from oldest commit. 58 | * 59 | * @param string $localGitRepositoryDir 60 | * 61 | * @return string 62 | */ 63 | protected function getRepositoryAge($localGitRepositoryDir) 64 | { 65 | return $this->getExec()->exec( 66 | 'git log --reverse --pretty=oneline --format="%ar" | head -n 1 | LC_ALL=C sed \'s/ago//\'', 67 | $localGitRepositoryDir 68 | ); 69 | } 70 | 71 | /** 72 | * Get the commit total. 73 | * 74 | * @param string $localGitRepositoryDir 75 | * 76 | * @return string 77 | */ 78 | protected function getCommitCount($localGitRepositoryDir) 79 | { 80 | return $this->getExec()->exec( 81 | 'git log --oneline | wc -l | tr -d \' \'', 82 | $localGitRepositoryDir 83 | ); 84 | } 85 | 86 | /** 87 | * @param string $localGitRepositoryDir 88 | * 89 | * @return array 90 | */ 91 | protected function getListAuthors($localGitRepositoryDir) 92 | { 93 | return $this->getExec()->exec('git shortlog --numbered --summary', $localGitRepositoryDir); 94 | } 95 | } 96 | -------------------------------------------------------------------------------- /config/services/command.project.cs.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 6 | 7 | 8 | false 9 | 10 | 11 | 12 | 26 | 31 | project:cs:php 32 | 33 | 34 | %command.project.cs.enabled% 35 | 36 | 37 | 38 | 39 | 40 | 41 | 42 | 43 | 44 | 90 | 91 | 92 | -------------------------------------------------------------------------------- /src/Process/PhpCsFixer.php: -------------------------------------------------------------------------------- 1 | cacheDir = $cacheDir; 32 | 33 | return $this; 34 | } 35 | 36 | /** 37 | * Sets the value of localPhpcsStandardDir. 38 | * 39 | * @param mixed $localPhpcsStandardDir the local phpcs standard forbidden function names 40 | * 41 | * @return self 42 | */ 43 | public function setLocalPhpcsStandardDir($localPhpcsStandardDir) 44 | { 45 | $this->localPhpcsStandardDir = $localPhpcsStandardDir; 46 | 47 | return $this; 48 | } 49 | 50 | /** 51 | * Sets the value of remotePhpcsStandardDir. 52 | * 53 | * @param mixed $remotePhpcsStandardDir the remote phpcs standard forbidden function names 54 | * 55 | * @return self 56 | */ 57 | public function setRemotePhpcsStandardDir($remotePhpcsStandardDir) 58 | { 59 | $this->remotePhpcsStandardDir = $remotePhpcsStandardDir; 60 | 61 | return $this; 62 | } 63 | 64 | public function fixRemoteDir($remoteDir, OutputInterface $output, array $options = []) 65 | { 66 | $resolver = new OptionsResolver(); 67 | 68 | $resolver->setDefaults([ 69 | 'dry-run' => true 70 | ]); 71 | 72 | $options = $resolver->resolve($options); 73 | 74 | $this->getSshExec()->passthru( 75 | strtr( 76 | 'php-cs-fixer fix %command_options% --no-interaction %dir%', 77 | [ 78 | '%dir%' => $remoteDir, 79 | '%command_options%' => $options['dry-run'] ? '--dry-run --diff' : '' 80 | ] 81 | ) 82 | ); 83 | 84 | $returnStatus = $this->getSshExec()->getLastReturnStatus(); 85 | 86 | $this->getRemoteFilesystem()->mkdir($this->remotePhpcsStandardDir); 87 | 88 | $tmpDir = sprintf('%s/jarvis/phpcs_standard_dir', $this->cacheDir); 89 | $this->getLocalFilesystem()->mirror($this->localPhpcsStandardDir, $tmpDir); 90 | 91 | $this->getRemoteFilesystem()->syncLocalToRemote( 92 | $tmpDir, 93 | $this->remotePhpcsStandardDir, 94 | [ 95 | 'delete' => true 96 | ] 97 | ); 98 | 99 | return $returnStatus; 100 | } 101 | } 102 | -------------------------------------------------------------------------------- /src/Command/Project/PhpMetricsCommand.php: -------------------------------------------------------------------------------- 1 | 14 | */ 15 | 16 | namespace Jarvis\Command\Project; 17 | 18 | use Symfony\Component\Console\Input\InputInterface; 19 | use Symfony\Component\Console\Input\InputOption; 20 | use Symfony\Component\Console\Output\OutputInterface; 21 | use Jarvis\Project\ProjectConfiguration; 22 | 23 | class PhpMetricsCommand extends BaseBuildCommand 24 | { 25 | /** 26 | * @var string 27 | */ 28 | private $remoteBuildDir; 29 | 30 | /** 31 | * @var string 32 | */ 33 | private $localBuildDir; 34 | 35 | /** 36 | * @{inheritdoc} 37 | */ 38 | protected function configure() 39 | { 40 | $this->setDescription('Gives metrics about PHP project and classes for to one or all projects'); 41 | 42 | parent::configure(); 43 | } 44 | 45 | /** 46 | * @{inheritdoc} 47 | */ 48 | protected function initialize(InputInterface $input, OutputInterface $output) 49 | { 50 | $this->remoteBuildDir = sprintf('%s/metrics', $this->getRemoteBuildDir()); 51 | $this->localBuildDir = sprintf('%s/metrics', $this->getLocalBuildDir()); 52 | 53 | $this->getRemoteFilesystem()->mkdir($this->remoteBuildDir); 54 | $this->getLocalFilesystem()->mkdir($this->localBuildDir); 55 | } 56 | 57 | /** 58 | * @{inheritdoc} 59 | */ 60 | protected function executeCommandByProject($projectName, ProjectConfiguration $projectConfig, OutputInterface $output) 61 | { 62 | $remoteReportFilePath = strtr('%build_dir%/%project_name%.html', [ 63 | '%project_name%' => $projectConfig->getProjectName(), 64 | '%build_dir%' => $this->remoteBuildDir 65 | ]); 66 | 67 | // Analyse source project code 68 | $this->getSshExec()->passthru( 69 | strtr( 70 | 'mkdir -p %build_dir% && /usr/local/bin/phpmetrics --level=0 --report-html=%report_file% %project_dir%/src'.($output->isDebug() ? ' --verbose' : ''), 71 | [ 72 | '%report_file%' => $remoteReportFilePath, 73 | '%build_dir%' => $this->remoteBuildDir, 74 | '%project_dir%' => $projectConfig->getRemoteWebappDir(), 75 | ] 76 | ) 77 | ); 78 | 79 | $localReportFilePath = str_replace( 80 | $this->remoteBuildDir, 81 | $this->localBuildDir, 82 | $remoteReportFilePath 83 | ); 84 | $this->getRemoteFilesystem()->copyRemoteFileToLocal( 85 | $remoteReportFilePath, 86 | $localReportFilePath 87 | ); 88 | if ($this->getLocalFilesystem()->exists($localReportFilePath)) { 89 | $this->openFile($localReportFilePath); 90 | } 91 | 92 | return $this->getSshExec()->getLastReturnStatus(); 93 | } 94 | } 95 | -------------------------------------------------------------------------------- /src/Command/Core/SelfUpdateCommand.php: -------------------------------------------------------------------------------- 1 | 14 | */ 15 | 16 | namespace Jarvis\Command\Core; 17 | 18 | use Herrera\Version; 19 | use Symfony\Component\Console\Command\Command; 20 | use Symfony\Component\Console\Input\InputArgument; 21 | use Symfony\Component\Console\Input\InputInterface; 22 | use Symfony\Component\Console\Input\InputOption; 23 | use Symfony\Component\Console\Output\OutputInterface; 24 | use Jarvis\Phar\Manager; 25 | use Jarvis\Phar\Manifest; 26 | 27 | class SelfUpdateCommand extends Command 28 | { 29 | use \Jarvis\Filesystem\LocalFilesystemAwareTrait; 30 | 31 | use \Psr\Log\LoggerAwareTrait; 32 | 33 | const EXIT_SUCCESS = 0; 34 | const EXIT_ERROR = 1; 35 | 36 | /** 37 | * @var string 38 | */ 39 | private $pharUpdateManifestUrl; 40 | 41 | /** 42 | * Sets the value of pharUpdateManifestUrl. 43 | * 44 | * @param string $pharUpdateManifestUrl the phar update manifest url 45 | * 46 | * @return self 47 | */ 48 | public function setPharUpdateManifestUrl($pharUpdateManifestUrl) 49 | { 50 | $this->pharUpdateManifestUrl = $pharUpdateManifestUrl; 51 | 52 | return $this; 53 | } 54 | 55 | /** 56 | * {@inheritdoc} 57 | */ 58 | protected function configure() 59 | { 60 | $this 61 | ->setName('self-update') 62 | ->setDescription('Updates manifest.phar to the latest version') 63 | ->setDefinition([ 64 | new InputArgument('version', InputArgument::OPTIONAL, 'The version to update to'), 65 | new InputOption('major', null, InputOption::VALUE_NONE, 'Lock to current major version?'), 66 | ]) 67 | ; 68 | } 69 | 70 | /** 71 | * {@inheritdoc} 72 | */ 73 | public function isEnabled() 74 | { 75 | return '' != \Phar::running(false) && Version\Validator::isVersion($this->getApplication()->getVersion()); 76 | } 77 | 78 | /** 79 | * {@inheritdoc} 80 | */ 81 | protected function execute(InputInterface $input, OutputInterface $output) 82 | { 83 | $manifest = Manifest::download($this->pharUpdateManifestUrl, $output->isDebug()); 84 | 85 | $manager = new Manager($manifest, $this->getLocalFilesystem()); 86 | !$this->logger ?: $manager->setLogger($this->logger); 87 | 88 | $currentVersion = $this->getApplication()->getVersion(); 89 | $newVersion = (null !== $input->getArgument('version')) ? $input->getArgument('version') : null; 90 | $major = $input->getOption('major'); // Lock to current major version? 91 | $pre = true; //Allow pre-releases? 92 | 93 | if (false === $manager->update($currentVersion, $major, $pre, $newVersion, $output->isDebug())) { 94 | return self::EXIT_ERROR; 95 | } 96 | 97 | return self::EXIT_SUCCESS; 98 | } 99 | } 100 | -------------------------------------------------------------------------------- /src/Command/Project/BaseSymfonyCommand.php: -------------------------------------------------------------------------------- 1 | 14 | */ 15 | 16 | namespace Jarvis\Command\Project; 17 | 18 | use Symfony\Component\Console\Input\InputInterface; 19 | use Symfony\Component\Console\Input\InputOption; 20 | use Symfony\Component\Console\Output\OutputInterface; 21 | use Jarvis\Symfony\RemoteConsoleExec as SymfonyRemoteConsoleExec; 22 | 23 | abstract class BaseSymfonyCommand extends BaseCommand 24 | { 25 | use \Jarvis\Symfony\RemoteConsoleExecAwareTrait; 26 | 27 | /** 28 | * @var array 29 | */ 30 | private $symfonyEnvs; 31 | 32 | /** 33 | * @{inheritdoc} 34 | */ 35 | protected function initialize(InputInterface $input, OutputInterface $output) 36 | { 37 | $this->symfonyEnvs = $input->getOption('symfony-env'); 38 | } 39 | 40 | /** 41 | * @{inheritdoc} 42 | */ 43 | protected function configure() 44 | { 45 | $this->addOption( 46 | '--symfony-env', 47 | null, 48 | InputOption::VALUE_REQUIRED | InputOption::VALUE_IS_ARRAY, 49 | 'The Symfony Environment name.', 50 | ['dev'] 51 | ); 52 | 53 | parent::configure(); 54 | } 55 | 56 | protected function getSymfonyEnvs() 57 | { 58 | return $this->symfonyEnvs; 59 | } 60 | 61 | protected function getSymfonyCommandArguments(InputInterface $input) 62 | { 63 | $commandArguments = []; 64 | foreach ($input->getArguments() as $name => $value) { 65 | switch ($name) { 66 | case 'command': 67 | break; 68 | default: 69 | $commandArguments[] = $value; 70 | break; 71 | } 72 | } 73 | 74 | return $commandArguments; 75 | } 76 | 77 | protected function getSymfonyCommandOptions(InputInterface $input) 78 | { 79 | $commandOptions = []; 80 | 81 | foreach ($input->getOptions() as $name => $value) { 82 | if ($value === false) { 83 | continue; 84 | } 85 | 86 | switch ($name) { 87 | case 'symfony-env': 88 | case 'verbose': 89 | case 'profile': 90 | case 'working-dir': 91 | case 'project-name': 92 | case 'cache-dir': 93 | break; 94 | default: 95 | if ($value === true) { 96 | $commandOptions[] = sprintf('--%s', $name); 97 | continue; 98 | } 99 | 100 | if (!empty($value)) { 101 | $commandOptions[] = sprintf('--%s=%s', $name, $value); 102 | } 103 | break; 104 | } 105 | } 106 | 107 | return $commandOptions; 108 | } 109 | } 110 | -------------------------------------------------------------------------------- /config/services/command.project.test.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 6 | 7 | 8 | false 9 | 10 | 11 | 12 | 13 | 17 | 18 | 19 | 20 | 21 | 22 | %command.project.test.enabled% 23 | 24 | 25 | 26 | 31 | project:tests:all 32 | 33 | 34 | 35 | 36 | 41 | project:tests:unit 42 | 43 | 44 | 45 | 46 | %remote_build_dir% 47 | 48 | 49 | %local_build_dir% 50 | 51 | 52 | 53 | 54 | 55 | 56 | 57 | 58 | 59 | 60 | 65 | project:tests:integration 66 | 67 | 68 | 69 | 70 | %remote_build_dir% 71 | 72 | 73 | %local_build_dir% 74 | 75 | 76 | 77 | 78 | 79 | 80 | 81 | 82 | 83 | 84 | 85 | 86 | -------------------------------------------------------------------------------- /src/Command/Project/BaseGitCommand.php: -------------------------------------------------------------------------------- 1 | 14 | */ 15 | 16 | namespace Jarvis\Command\Project; 17 | 18 | use Symfony\Component\Console\Output\OutputInterface; 19 | use Jarvis\Process\ExecAwareTrait; 20 | use Jarvis\Project\ProjectConfiguration; 21 | 22 | class BaseGitCommand extends BaseCommand 23 | { 24 | use ExecAwareTrait; 25 | 26 | protected $gitCommand; 27 | 28 | protected $colorsConsoleOutput = false; 29 | 30 | /** 31 | * {@inheritdoc} 32 | */ 33 | protected function executeCommandByProject($projectName, ProjectConfiguration $projectConfig, OutputInterface $output) 34 | { 35 | $output->writeln( 36 | sprintf( 37 | 'Git %s for project "%s"', 38 | $this->getName(), 39 | $projectName 40 | ) 41 | ); 42 | 43 | if (!is_dir($projectConfig->getLocalGitRepositoryDir())) { 44 | throw new \RuntimeException(sprintf('The directory "%s" does not exist', $projectConfig->getLocalGitRepositoryDir())); 45 | } 46 | 47 | if (empty($this->gitCommand)) { 48 | throw new \LogicException('Git command is empty'); 49 | } 50 | 51 | if ($this->colorsConsoleOutput) { 52 | ob_start(); 53 | } 54 | 55 | $this->getExec()->passthru( 56 | sprintf('git %s', $this->gitCommand), 57 | $projectConfig->getLocalGitRepositoryDir() 58 | ); 59 | 60 | if ($this->colorsConsoleOutput) { 61 | $output->writeln( 62 | strtr( 63 | ob_get_clean(), 64 | [ 65 | 'up-to-date' => 'up-to-date', 66 | 'is behind' => 'is behind', 67 | 'can be fast-forwarded' => 'can be fast-forwarded', 68 | 'modified:' => 'modified:', 69 | 'both modified' => 'both modified:', 70 | 'deleted:' => 'deleted:', // red color 71 | 'deleted by us' => 'deleted by us', // red color 72 | '- ' => '- ', // red color 73 | '+ ' => '+', // green color 74 | ] 75 | ) 76 | ); 77 | } 78 | 79 | return $this->getExec()->getLastReturnStatus(); 80 | } 81 | 82 | /** 83 | * Sets the value of gitCommand. 84 | * 85 | * @param string $gitCommand the git command 86 | * 87 | * @return self 88 | */ 89 | public function setGitCommand($gitCommand) 90 | { 91 | $this->gitCommand = $gitCommand; 92 | 93 | return $this; 94 | } 95 | 96 | public function enableColorsConsoleOutput() 97 | { 98 | $this->colorsConsoleOutput = true; 99 | } 100 | } 101 | -------------------------------------------------------------------------------- /skeleton/editor/SublimeText3/Packages/User/SublimeLinter.sublime-settings: -------------------------------------------------------------------------------- 1 | { 2 | "user": { 3 | "debug": false, 4 | "delay": 0.25, 5 | "error_color": "D02000", 6 | "gutter_theme": "Packages/SublimeLinter/gutter-themes/Blueberry/cross/Blueberry - cross.gutter-theme", 7 | "gutter_theme_excludes": [], 8 | "lint_mode": "save only", 9 | "linters": { 10 | "annotations": { 11 | "@disable": false, 12 | "args": [], 13 | "errors": [ 14 | "FIXME" 15 | ], 16 | "excludes": [], 17 | "warnings": [ 18 | "TODO" 19 | ] 20 | }, 21 | "jshint": { 22 | "@disable": false, 23 | "args": [], 24 | "excludes": [] 25 | }, 26 | "json": { 27 | "@disable": false, 28 | "args": [], 29 | "excludes": [], 30 | "strict": true 31 | }, 32 | "php": { 33 | "@disable": false, 34 | "args": [], 35 | "excludes": [] 36 | }, 37 | "phpcs": { 38 | "@disable": true, 39 | "args": [ 40 | "--warning-severity=0" 41 | ], 42 | "excludes": [ 43 | "*Spec.php" 44 | ], 45 | "standard": "PSR2" 46 | }, 47 | "phpmd": { 48 | "@disable": true, 49 | "args": [], 50 | "excludes": [ 51 | "*Spec.php" 52 | ], 53 | "rulesets": "cleancode,codesize,controversial,design,unusedcode" 54 | }, 55 | "pyyaml": { 56 | "@disable": false, 57 | "args": [], 58 | "excludes": [] 59 | }, 60 | "scss": { 61 | "@disable": false, 62 | "args": [], 63 | "exclude-linter": "", 64 | "excludes": [], 65 | "include-linter": "" 66 | }, 67 | "summitlinter": { 68 | "@disable": false, 69 | "args": [], 70 | "excludes": [], 71 | "globals": "channel,require", 72 | "ignore": "", 73 | "limit": null, 74 | "only": "" 75 | }, 76 | "xmllint": { 77 | "@disable": false, 78 | "args": [], 79 | "excludes": [] 80 | } 81 | }, 82 | "mark_style": "fill", 83 | "no_column_highlights_line": false, 84 | "passive_warnings": false, 85 | "paths": { 86 | "linux": [], 87 | "osx": [], 88 | "windows": [] 89 | }, 90 | "python_paths": { 91 | "linux": [], 92 | "osx": [], 93 | "windows": [] 94 | }, 95 | "rc_search_limit": 3, 96 | "shell_timeout": 10, 97 | "show_errors_on_save": false, 98 | "show_marks_in_minimap": true, 99 | "syntax_map": { 100 | "html (django)": "html", 101 | "html (rails)": "html", 102 | "html 5": "html", 103 | "php": "html", 104 | "python django": "python" 105 | }, 106 | "warning_color": "DDB700", 107 | "wrap_find": true 108 | } 109 | } 110 | -------------------------------------------------------------------------------- /config/services/command.vagrant.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 6 | 7 | 8 | true 9 | 10 | 11 | 12 | 13 | 17 | %local_vagrant_dir% 18 | 19 | 20 | 21 | 22 | 23 | 24 | 28 | 29 | 30 | 31 | 32 | 33 | 34 | 35 | 36 | 37 | 38 | 39 | 40 | 41 | %command.vagrant.enabled% 42 | 43 | 44 | 45 | 46 | 51 | 52 | 53 | 54 | 59 | 60 | 61 | 62 | 67 | 68 | 69 | 70 | 75 | 76 | 77 | 78 | 83 | 84 | 85 | 86 | 91 | 92 | 93 | 94 | 99 | 100 | 101 | 102 | 107 | 108 | 109 | 110 | 111 | 112 | -------------------------------------------------------------------------------- /src/Command/Project/TestAllCommand.php: -------------------------------------------------------------------------------- 1 | 14 | */ 15 | 16 | namespace Jarvis\Command\Project; 17 | 18 | use Symfony\Component\Console\Input\InputInterface; 19 | use Symfony\Component\Console\Input\InputOption; 20 | use Symfony\Component\Console\Output\OutputInterface; 21 | use Jarvis\Project\ProjectConfiguration; 22 | 23 | class TestAllCommand extends BaseCommand 24 | { 25 | /** 26 | * @var boolean 27 | */ 28 | private $isTestUnitEnabled; 29 | 30 | /** 31 | * @var boolean 32 | */ 33 | private $isTestIntegrationEnabled; 34 | 35 | /** 36 | * @{inheritdoc} 37 | */ 38 | protected function configure() 39 | { 40 | $this->setDescription('Executing tests unit and integration'); 41 | 42 | parent::configure(); 43 | 44 | $this->addOption('no-unit', null, InputOption::VALUE_NONE); 45 | $this->addOption('no-integration', null, InputOption::VALUE_NONE); 46 | } 47 | 48 | /** 49 | * @{inheritdoc} 50 | */ 51 | protected function initialize(InputInterface $input, OutputInterface $output) 52 | { 53 | $this->isTestUnitEnabled = false === $input->getOption('no-unit'); 54 | $this->isTestIntegrationEnabled = false === $input->getOption('no-integration'); 55 | } 56 | 57 | /** 58 | * @{inheritdoc} 59 | */ 60 | protected function executeCommandByProject($projectName, ProjectConfiguration $projectConfig, OutputInterface $output) 61 | { 62 | $output->writeln( 63 | sprintf( 64 | 'Executes tests for project "%s"', 65 | $projectName 66 | ) 67 | ); 68 | 69 | $parameters = [ 70 | '--project-name' => $projectName, 71 | '--no-display-status-text' => true 72 | ]; 73 | 74 | $testUnitStatusCode = 0; 75 | $testIntegrationStatusCode = 0; 76 | 77 | if ($this->isTestUnitEnabled) { 78 | $testUnitStatusCode = $this->getApplication()->executeCommand('project:tests:unit', $parameters, $output); 79 | } 80 | 81 | if ($this->isTestIntegrationEnabled) { 82 | $testIntegrationStatusCode = $this->getApplication()->executeCommand('project:tests:integration', $parameters, $output); 83 | } 84 | 85 | if ($this->isTestUnitEnabled) { 86 | $output->writeln( 87 | sprintf( 88 | 'Executes unit tests for project "%s": %s', 89 | $projectName, 90 | $testUnitStatusCode == 0 ? 91 | 'SUCCESS' 92 | : 93 | 'ERROR' 94 | ) 95 | ); 96 | } 97 | 98 | if ($this->isTestIntegrationEnabled) { 99 | $output->writeln( 100 | sprintf( 101 | 'Executes integration tests for project "%s": %s', 102 | $projectName, 103 | $testIntegrationStatusCode == 0 ? 104 | ' SUCCESS' 105 | : 106 | ' ERROR' 107 | ) 108 | ); 109 | } 110 | 111 | return $testUnitStatusCode + $testIntegrationStatusCode; 112 | } 113 | } 114 | -------------------------------------------------------------------------------- /config/services/command.project.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 6 | 7 | 8 | false 9 | 10 | 11 | 12 | 16 | %local_projects_root_dir% 17 | %remote_projects_root_dir% 18 | %local_vendor_root_dir% 19 | %local_cdn_root_dir% 20 | %remote_vendor_root_dir% 21 | 22 | 23 | 27 | %projects_config_file_path% 28 | 29 | 30 | 31 | 35 | project:list 36 | 37 | 38 | 39 | 40 | 41 | 42 | 43 | 47 | 48 | 49 | 50 | 51 | 52 | %command.project.enabled% 53 | 54 | 55 | 60 | project:install-dependencies-and-assets 61 | 62 | 63 | %command.project.enabled% 64 | 65 | 66 | 67 | 68 | 73 | project:ssh 74 | 75 | 76 | %command.project.enabled% 77 | 78 | 79 | 80 | 81 | 82 | 83 | 84 | 85 | 90 | project:directory 91 | 92 | 93 | %command.project.enabled% 94 | 95 | 96 | 97 | 98 | 99 | 100 | -------------------------------------------------------------------------------- /src/Command/Project/SymfonyConsoleCommand.php: -------------------------------------------------------------------------------- 1 | 14 | */ 15 | 16 | namespace Jarvis\Command\Project; 17 | 18 | use Symfony\Component\Console\Input\InputArgument; 19 | use Symfony\Component\Console\Input\InputInterface; 20 | use Symfony\Component\Console\Input\InputOption; 21 | use Symfony\Component\Console\Output\OutputInterface; 22 | use Jarvis\Project\ProjectConfiguration; 23 | 24 | class SymfonyConsoleCommand extends BaseSymfonyCommand 25 | { 26 | /** 27 | * @var string 28 | */ 29 | private $symfonyCommandName; 30 | 31 | /** 32 | * {@inheritdoc} 33 | */ 34 | public function isEnabled() 35 | { 36 | return $this->enabled && count($this->getProjectConfigurationRepository()->getProjectNames()); 37 | } 38 | 39 | /** 40 | * @{inheritdoc} 41 | */ 42 | protected function configure() 43 | { 44 | $this->setDescription('Executes Symfony console command'); 45 | 46 | if ($this->getName() === 'project:symfony:console') { 47 | $this->addArgument('command_name', InputArgument::OPTIONAL, 'Command name', 'list'); 48 | } 49 | 50 | if (!$this->getDefinition()->hasOption('project-name')) { 51 | $this->addOption( 52 | 'project-name', 53 | 'p', 54 | InputOption::VALUE_REQUIRED | InputOption::VALUE_IS_ARRAY, 55 | 'The project name or many project names' 56 | ); 57 | } 58 | 59 | $this->addOption( 60 | '--symfony-env', 61 | null, 62 | InputOption::VALUE_REQUIRED | InputOption::VALUE_IS_ARRAY, 63 | 'The Symfony Environment name.', 64 | ['dev'] 65 | ); 66 | } 67 | 68 | /** 69 | * @{inheritdoc} 70 | */ 71 | protected function initialize(InputInterface $input, OutputInterface $output) 72 | { 73 | parent::initialize($input, $output); 74 | 75 | $this->symfonyCommandName = $input->hasArgument('command_name') ? 76 | $input->getArgument('command_name') 77 | : 78 | str_replace('project:symfony:', null, $this->getName()) 79 | ; 80 | $this->symfonyCommandArguments = $this->getSymfonyCommandArguments($input); 81 | $this->symfonyCommandOptions = $this->getSymfonyCommandOptions($input); 82 | } 83 | 84 | /** 85 | * @{inheritdoc} 86 | */ 87 | protected function executeCommandByProject($projectName, ProjectConfiguration $projectConfig, OutputInterface $output) 88 | { 89 | $returnStatus = 0; 90 | 91 | foreach ($this->getSymfonyEnvs() as $symfonyEnv) { 92 | $commandLine = strtr( 93 | '%command_name% %command_arguments% %command_options%', 94 | [ 95 | '%command_name%' => $this->symfonyCommandName, 96 | '%command_arguments%' => implode(' ', $this->symfonyCommandArguments), 97 | '%command_options%' => implode(' ', $this->symfonyCommandOptions), 98 | ] 99 | ); 100 | 101 | $this->getSymfonyRemoteConsoleExec()->passthru( 102 | $projectConfig->getRemoteSymfonyConsolePath(), 103 | $commandLine, 104 | $symfonyEnv, 105 | $output->getVerbosity() 106 | ); 107 | 108 | if (0 == $returnStatus) { 109 | $returnStatus = $this->getSymfonyRemoteConsoleExec()->getLastReturnStatus(); 110 | } 111 | } 112 | 113 | return $returnStatus; 114 | } 115 | } 116 | -------------------------------------------------------------------------------- /src/Process/Exec.php: -------------------------------------------------------------------------------- 1 | 14 | */ 15 | 16 | namespace Jarvis\Process; 17 | 18 | use Psr\Log\LoggerAwareTrait; 19 | use Symfony\Component\Console\Output\OutputInterface; 20 | 21 | class Exec 22 | { 23 | use LoggerAwareTrait; 24 | 25 | /** 26 | * Execute an external program 27 | * 28 | * @param string $commandLine 29 | * @param null|string $cwd The working directory 30 | */ 31 | public function passthru($commandLine, $cwd = null) 32 | { 33 | $previousCwd = getcwd(); 34 | 35 | if ($cwd) { 36 | chdir($cwd); 37 | 38 | !$this->logger ?: $this->logger->debug(sprintf('Changed CWD to %s', $cwd)); 39 | } 40 | 41 | !$this->logger ?: $this->logger->debug($commandLine); 42 | 43 | passthru($commandLine, $returnStatus); 44 | 45 | $this->lastReturnStatus = $returnStatus; 46 | 47 | !$previousCwd ?: chdir($previousCwd); 48 | } 49 | 50 | /** 51 | * Execute an external program 52 | * 53 | * @param string $commandLine 54 | * @param null|string $cwd The working directory 55 | * 56 | * @return array The array will be filled with every line of output from the command 57 | */ 58 | public function exec($commandLine, $cwd = null) 59 | { 60 | $previousCwd = getcwd(); 61 | 62 | if ($cwd) { 63 | chdir($cwd); 64 | 65 | !$this->logger ?: $this->logger->debug(sprintf('Changed CWD to %s', $cwd)); 66 | } 67 | 68 | !$this->logger ?: $this->logger->debug($commandLine); 69 | 70 | exec($commandLine, $output, $returnStatus); 71 | 72 | $this->lastReturnStatus = $returnStatus; 73 | 74 | !$previousCwd ?: chdir($previousCwd); 75 | 76 | return implode(PHP_EOL, $output); 77 | } 78 | 79 | /** 80 | * Runs local command. 81 | * 82 | * @param string $commandLine 83 | * @param OutputInterface|null $output 84 | * @param null|string $cwd The working directory 85 | * 86 | * @return string 87 | */ 88 | public function run($commandLine, OutputInterface $output = null, $cwd = null) 89 | { 90 | $previousCwd = getcwd(); 91 | 92 | if ($cwd) { 93 | chdir($cwd); 94 | 95 | !$this->logger ?: $this->logger->debug(sprintf('Changed CWD to %s', $cwd)); 96 | } 97 | 98 | !$this->logger ?: $this->logger->debug($commandLine); 99 | 100 | ob_start(); 101 | passthru($commandLine, $returnStatus); 102 | if ($output instanceof OutputInterface) { 103 | if ($returnStatus != 0) { // execute with error 104 | $output->writeln(''.trim(ob_get_contents()).''); 105 | } elseif ($output->isVerbose()) { 106 | $output->writeln(ob_get_contents(), OutputInterface::OUTPUT_RAW); 107 | } 108 | } elseif ($returnStatus != 0) { // execute with error 109 | if (!$this->logger) { 110 | throw new \RuntimeException(trim(ob_get_contents())); 111 | } else { 112 | $this->logger->debug(trim(ob_get_contents())); 113 | } 114 | } 115 | 116 | $this->lastReturnStatus = $returnStatus; 117 | 118 | !$previousCwd ?: chdir($previousCwd); 119 | 120 | return ob_get_clean(); 121 | } 122 | 123 | /** 124 | * Return last return status of the last Unix command has been executed 125 | * 126 | * @return int 127 | */ 128 | public function getLastReturnStatus() 129 | { 130 | return $this->lastReturnStatus; 131 | } 132 | } 133 | -------------------------------------------------------------------------------- /src/Command/Project/GitHooksInstallCommand.php: -------------------------------------------------------------------------------- 1 | 14 | */ 15 | 16 | namespace Jarvis\Command\Project; 17 | 18 | use Symfony\Component\Console\Input\InputInterface; 19 | use Symfony\Component\Console\Input\InputOption; 20 | use Symfony\Component\Console\Output\OutputInterface; 21 | use Jarvis\Project\ProjectConfiguration; 22 | 23 | class GitHooksInstallCommand extends BaseCommand 24 | { 25 | use \Jarvis\Process\ExecAwareTrait; 26 | use \Jarvis\Process\CommandExistTrait; 27 | use \Jarvis\Filesystem\LocalFilesystemAwareTrait; 28 | 29 | private $skeletonGitHooksDir; 30 | private $workingDir; 31 | 32 | /** 33 | * Sets the value of workingDir. 34 | * 35 | * @param mixed $workingDir the working dir 36 | * 37 | * @return self 38 | */ 39 | public function setWorkingDir($workingDir) 40 | { 41 | $this->workingDir = $workingDir; 42 | 43 | return $this; 44 | } 45 | 46 | /** 47 | * Sets the value of skeletonGitHooksDir. 48 | * 49 | * @param mixed $skeletonGitHooksDir the skeleton git hooks dir 50 | * 51 | * @return self 52 | */ 53 | public function setSkeletonGitHooksDir($skeletonGitHooksDir) 54 | { 55 | $this->skeletonGitHooksDir = $skeletonGitHooksDir; 56 | 57 | return $this; 58 | } 59 | 60 | /** 61 | * @{inheritdoc} 62 | */ 63 | protected function configure() 64 | { 65 | $this->setDescription('Install git hooks in to one or all projects.'); 66 | 67 | parent::configure(); 68 | } 69 | 70 | /** 71 | * @{inheritdoc} 72 | */ 73 | protected function initialize(InputInterface $input, OutputInterface $output) 74 | { 75 | $this->runningFile = realpath($_SERVER['argv'][0]); 76 | } 77 | 78 | /** 79 | * @{inheritdoc} 80 | */ 81 | protected function executeCommandByProject($projectName, ProjectConfiguration $projectConfig, OutputInterface $output) 82 | { 83 | $this->installGitHook('pre-commit', $projectConfig, $output); 84 | $this->installGitHook('post-merge', $projectConfig, $output); 85 | } 86 | 87 | protected function installGitHook($gitHookName, ProjectConfiguration $projectConfig, OutputInterface $output) 88 | { 89 | $content = $this->renderTemplate($gitHookName, $projectConfig->getProjectName()); 90 | $filename = $this->getTargetGitHookFile($gitHookName, $projectConfig); 91 | 92 | $this->getLocalFilesystem()->dumpFile($filename, $content); 93 | $this->getExec()->exec('chmod +x '.$filename); 94 | 95 | $output->writeln(sprintf( 96 | 'Install git hook %s for project "%s"', 97 | $gitHookName, 98 | $projectConfig->getProjectName() 99 | )); 100 | } 101 | 102 | protected function getTargetGitHookFile($gitHookName, ProjectConfiguration $projectConfig) 103 | { 104 | return sprintf('%s/%s', $projectConfig->getLocalGitHooksDir(), $gitHookName); 105 | } 106 | 107 | protected function renderTemplate($templateName, $projectName) 108 | { 109 | $filepath = $this->skeletonGitHooksDir.'/'.$templateName; 110 | 111 | if (!file_exists($filepath)) { 112 | throw new \RuntimeException(sprintf('The git hook template %s does not exist', $filepath)); 113 | } 114 | 115 | return strtr( 116 | file_get_contents($filepath), 117 | [ 118 | '{{jarvis_command_name}}' => sprintf( 119 | '%s --working-dir=%s', 120 | $this->runningFile, 121 | $this->workingDir 122 | ), 123 | '{{project_name}}' => $projectName, 124 | ] 125 | ); 126 | } 127 | } 128 | -------------------------------------------------------------------------------- /src/Command/Project/GitOpenCommand.php: -------------------------------------------------------------------------------- 1 | 14 | */ 15 | 16 | namespace Jarvis\Command\Project; 17 | 18 | use Symfony\Component\Console\Input\InputInterface; 19 | use Symfony\Component\Console\Input\InputOption; 20 | use Symfony\Component\Console\Output\OutputInterface; 21 | use Jarvis\Project\ProjectConfiguration; 22 | 23 | class GitOpenCommand extends BaseGitCommand 24 | { 25 | /** 26 | * @var string 27 | */ 28 | private $remote; 29 | 30 | /** 31 | * @var string 32 | */ 33 | private $branchName; 34 | 35 | /** 36 | * @{inheritdoc} 37 | */ 38 | protected function configure() 39 | { 40 | $this->setDescription('Opens the website for a repository in your browser'); 41 | 42 | $this->addOption('remote', null, InputOption::VALUE_REQUIRED, 'Remote', 'origin'); 43 | $this->addOption('branch', null, InputOption::VALUE_REQUIRED, 'Branch name'); 44 | 45 | parent::configure(); 46 | } 47 | 48 | /** 49 | * @{inheritdoc} 50 | */ 51 | protected function initialize(InputInterface $input, OutputInterface $output) 52 | { 53 | $this->remote = $input->getOption('remote'); 54 | $this->branchName = $input->getOption('branch'); 55 | } 56 | 57 | 58 | /** 59 | * @{inheritdoc} 60 | */ 61 | protected function executeCommandByProject($projectName, ProjectConfiguration $projectConfig, OutputInterface $output) 62 | { 63 | $output->writeln( 64 | sprintf( 65 | 'Opens the website for a repository in your browser for the project "%s"', 66 | $projectName 67 | ) 68 | ); 69 | 70 | if (!is_dir($projectConfig->getLocalGitRepositoryDir())) { 71 | throw new \RuntimeException(sprintf('The directory "%s" does not exist', $projectConfig->getLocalGitRepositoryDir())); 72 | } 73 | 74 | $giturl = $this->getGiturl($projectConfig); 75 | 76 | $this->openUrl($giturl); 77 | 78 | return 0; 79 | } 80 | 81 | protected function getGiturl(ProjectConfiguration $projectConfig) 82 | { 83 | $giturl = $this->getExec()->exec( 84 | 'git config --get remote.'.$this->remote.'.url', 85 | $projectConfig->getLocalGitRepositoryDir() 86 | ); 87 | 88 | if ($this->getExec()->getLastReturnStatus() !== 0) { 89 | throw new \LogicException('Error retrieve git URL'); 90 | } 91 | 92 | if (0 === strpos($giturl, 'git@')) { 93 | $giturl = str_replace(':', '/', $giturl); 94 | $giturl = str_replace('git@', 'http://', $giturl); 95 | } 96 | 97 | if (false !== strpos($giturl, '.git')) { 98 | $giturl = str_replace('.git', '', $giturl); 99 | } 100 | 101 | $branchName = null === $this->branchName ? 102 | $this->getCurrentBranch($projectConfig) 103 | : 104 | $this->branchName; 105 | 106 | $giturl .= '/tree/'.$branchName; 107 | 108 | return $giturl; 109 | } 110 | 111 | protected function getCurrentBranch($projectConfig) 112 | { 113 | $giturl = $this->getExec()->exec( 114 | 'git symbolic-ref -q --short HEAD', 115 | $projectConfig->getLocalGitRepositoryDir() 116 | ); 117 | 118 | if ($this->getExec()->getLastReturnStatus() !== 0) { 119 | throw new \LogicException('Error retrieve branch name'); 120 | } 121 | 122 | return $giturl; 123 | } 124 | 125 | protected function openUrl($url) 126 | { 127 | $this->getExec()->exec(strtr( 128 | 'which xdg-open && xdg-open %url% || which open && open %url%', 129 | [ 130 | '%url%' => $url 131 | ] 132 | )); 133 | } 134 | } 135 | -------------------------------------------------------------------------------- /src/Command/Core/AutocompleteCommand.php: -------------------------------------------------------------------------------- 1 | 14 | */ 15 | 16 | namespace Jarvis\Command\Core; 17 | 18 | use Symfony\Component\Console\Command\Command; 19 | use Symfony\Component\Console\Helper\DescriptorHelper; 20 | use Symfony\Component\Console\Input\InputArgument; 21 | use Symfony\Component\Console\Input\InputInterface; 22 | use Symfony\Component\Console\Output\BufferedOutput; 23 | use Symfony\Component\Console\Output\OutputInterface; 24 | use Symfony\Component\Filesystem\Filesystem; 25 | 26 | /** 27 | * @see https://raw.githubusercontent.com/gushphp/gush/a674121999bc8cb3d4446c1db54cd798a0e062c5/src/Command/Core/AutocompleteCommand.php 28 | */ 29 | class AutocompleteCommand extends Command 30 | { 31 | private $cacheDir; 32 | private $runningFile; 33 | 34 | use \Jarvis\Filesystem\LocalFilesystemAwareTrait; 35 | 36 | /** 37 | * {@inheritdoc} 38 | */ 39 | protected function configure() 40 | { 41 | $this 42 | ->setName('core:autocomplete') 43 | ->setDescription('Create file for Command-line completion') 44 | ->setHelp( 45 | <<%command.name% creates a script to active Command-line completion for Jarvis commands in Bash: 47 | 48 | $ %command.full_name% 49 | 50 | To enable Bash autocomplete, run the following command, 51 | or add the following line to the ~/.bash_profile or ~/.bashrc file: 52 | 53 | $ source $(%command.full_name%) 54 | 55 | EOF 56 | ) 57 | ->addArgument( 58 | 'name', 59 | InputArgument::OPTIONAL, 60 | 'It is the name of the command for which to add a completion', 61 | 'jarvis' 62 | ) 63 | ; 64 | } 65 | 66 | /** 67 | * Sets the value of cacheDir. 68 | * 69 | * @param mixed $cacheDir the cache dir 70 | * 71 | * @return self 72 | */ 73 | public function setCacheDir($cacheDir) 74 | { 75 | $this->cacheDir = $cacheDir; 76 | 77 | return $this; 78 | } 79 | 80 | /** 81 | * @{inheritdoc} 82 | */ 83 | protected function initialize(InputInterface $input, OutputInterface $output) 84 | { 85 | $this->runningFile = realpath($_SERVER['argv'][0]); 86 | } 87 | 88 | /** 89 | * {@inheritdoc} 90 | */ 91 | protected function execute(InputInterface $input, OutputInterface $output) 92 | { 93 | $buffer = new BufferedOutput(); 94 | (new DescriptorHelper())->describe( 95 | $buffer, 96 | $this->getApplication(), 97 | ['format' => 'json'] 98 | ); 99 | 100 | $autocompleteHelper = $this->getHelper('autocomplete'); 101 | $completeFunctionName = sprintf('_jarvis_%s', md5($this->runningFile)); 102 | $completeCommand = $input->getArgument('name'); 103 | 104 | $script = $autocompleteHelper->getAutoCompleteScript( 105 | $completeFunctionName, 106 | $completeCommand, 107 | json_decode($buffer->fetch(), true)['commands'] 108 | ); 109 | 110 | $scriptFile = $this->getCacheDir().DIRECTORY_SEPARATOR.sprintf('.%s-autocomplete.bash', $input->getArgument('name')); 111 | 112 | $this->getLocalFilesystem()->dumpFile($scriptFile, $script); 113 | 114 | if (OutputInterface::VERBOSITY_DEBUG === $output->getVerbosity()) { 115 | $output->writeln($script); 116 | } 117 | 118 | $output->write($scriptFile, true); 119 | } 120 | 121 | protected function getCacheDir() 122 | { 123 | if (!$this->cacheDir) { 124 | $this->cacheDir = sys_get_temp_dir().DIRECTORY_SEPARATOR.'jarvis'; 125 | } 126 | 127 | $this->getLocalFilesystem()->mkdir($this->cacheDir); 128 | 129 | return $this->cacheDir; 130 | } 131 | } 132 | -------------------------------------------------------------------------------- /src/Command/Project/TestIntegrationCommand.php: -------------------------------------------------------------------------------- 1 | 14 | */ 15 | 16 | namespace Jarvis\Command\Project; 17 | 18 | use Symfony\Component\Console\Input\InputInterface; 19 | use Symfony\Component\Console\Input\InputOption; 20 | use Symfony\Component\Console\Output\OutputInterface; 21 | use Jarvis\Filesystem\RemoteFilesystemAwareTrait; 22 | use Jarvis\Project\ProjectConfiguration; 23 | use Jarvis\Ssh\SshExecAwareTrait; 24 | 25 | class TestIntegrationCommand extends BaseCommand 26 | { 27 | use SshExecAwareTrait; 28 | 29 | use RemoteFilesystemAwareTrait; 30 | 31 | /** 32 | * @var string 33 | */ 34 | private $remoteBuildDir; 35 | 36 | /** 37 | * @var string 38 | */ 39 | private $localBuildDir; 40 | 41 | /** 42 | * @var bool 43 | */ 44 | private $displayStatusText; 45 | 46 | /** 47 | * Sets the value of remoteBuildDir. 48 | * 49 | * @param string $remoteBuildDir the remote build dir 50 | * 51 | * @return self 52 | */ 53 | public function setRemoteBuildDir($remoteBuildDir) 54 | { 55 | $this->remoteBuildDir = $remoteBuildDir; 56 | 57 | return $this; 58 | } 59 | 60 | /** 61 | * Sets the value of localBuildDir. 62 | * 63 | * @param string $localBuildDir the local build dir 64 | * 65 | * @return self 66 | */ 67 | public function setLocalBuildDir($localBuildDir) 68 | { 69 | $this->localBuildDir = $localBuildDir; 70 | 71 | return $this; 72 | } 73 | 74 | /** 75 | * @{inheritdoc} 76 | */ 77 | protected function configure() 78 | { 79 | $this->setDescription('Executes integration tests'); 80 | $this->addOption('no-display-status-text', null, InputOption::VALUE_NONE, 'Do not display the status '); 81 | 82 | parent::configure(); 83 | } 84 | 85 | /** 86 | * @{inheritdoc} 87 | */ 88 | protected function initialize(InputInterface $input, OutputInterface $output) 89 | { 90 | $this->displayStatusText = !$input->getOption('no-display-status-text'); 91 | } 92 | 93 | /** 94 | * @{inheritdoc} 95 | */ 96 | protected function executeCommandByProject($projectName, ProjectConfiguration $projectConfig, OutputInterface $output) 97 | { 98 | $this->getApplication()->executeCommand('project:symfony:cache:clear', [ 99 | '--project-name' => $projectName, 100 | '--symfony-env' => ['test'], 101 | '--no-warmup' => null, 102 | ], $output); 103 | 104 | $buildReportHtmlPath = !empty($this->remoteBuildDir) ? '--testdox-html '.$this->remoteBuildDir.'/tests/integration.html' : null; 105 | 106 | $this->getSshExec()->passthru( 107 | strtr( 108 | 'phpunit --configuration %remote_phpunit_configuration_xml_path% --colors %build_report_html% '.($output->isDebug() ? ' --verbose --debug' : ''), 109 | [ 110 | '%project_dir%' => $projectConfig->getRemoteWebappDir(), 111 | '%remote_phpunit_configuration_xml_path%' => $projectConfig->getRemotePhpunitConfigurationXmlPath(), 112 | '%build_report_html%' => $buildReportHtmlPath, 113 | ] 114 | ) 115 | ); 116 | 117 | if ($this->displayStatusText) { 118 | $output->writeln( 119 | sprintf( 120 | 'Executes integration tests for project "%s": %s', 121 | $projectName, 122 | $this->getSshExec()->getLastReturnStatus() == 0 ? 123 | ' SUCCESS' 124 | : 125 | ' ERROR' 126 | ) 127 | ); 128 | } 129 | 130 | return $this->getSshExec()->getLastReturnStatus(); 131 | } 132 | } 133 | -------------------------------------------------------------------------------- /src/Command/Composer/ComposerCommand.php: -------------------------------------------------------------------------------- 1 | 14 | */ 15 | 16 | namespace Jarvis\Command\Composer; 17 | 18 | use Symfony\Component\Console\Command\Command; 19 | use Symfony\Component\Console\Input\InputArgument; 20 | use Symfony\Component\Console\Input\InputInterface; 21 | use Symfony\Component\Console\Input\InputOption; 22 | use Symfony\Component\Console\Output\OutputInterface; 23 | 24 | class ComposerCommand extends Command 25 | { 26 | use \Jarvis\Ssh\SshExecAwareTrait; 27 | 28 | use \Jarvis\Filesystem\LocalFilesystemAwareTrait; 29 | 30 | use \Jarvis\Filesystem\RemoteFilesystemAwareTrait; 31 | 32 | /** 33 | * @var bool 34 | */ 35 | private $enabled = false; 36 | 37 | /** 38 | * @var string 39 | */ 40 | private $commandName; 41 | 42 | /** 43 | * @param bool $bool 44 | */ 45 | public function setEnabled($bool) 46 | { 47 | $this->enabled = $bool; 48 | 49 | return $this; 50 | } 51 | 52 | /** 53 | * {@inheritdoc} 54 | */ 55 | public function isEnabled() 56 | { 57 | return $this->enabled; 58 | } 59 | 60 | /** 61 | * Sets the value of commandName. 62 | * 63 | * @param string $commandName the command name 64 | * 65 | * @return self 66 | */ 67 | public function setCommandName($commandName) 68 | { 69 | $this->commandName = $commandName; 70 | 71 | return $this; 72 | } 73 | 74 | /** 75 | * @{inheritdoc} 76 | */ 77 | protected function execute(InputInterface $input, OutputInterface $output) 78 | { 79 | $output->writeln(''.$this->getDescription().''); 80 | 81 | $commandLine = strtr( 82 | 'sudo composer %command_name% %command_arguments% %command_options%', 83 | [ 84 | '%command_name%' => $this->commandName, 85 | '%command_arguments%' => implode(' ', $this->getCommandArguments($input)), 86 | '%command_options%' => implode(' ', $this->getCommandOptions($input)), 87 | ] 88 | ); 89 | 90 | $report = $this->getSshExec()->exec($commandLine); 91 | 92 | $report = str_replace('composer', $this->getName(), $report); 93 | 94 | $output->writeln( 95 | $report, 96 | OutputInterface::OUTPUT_RAW 97 | ); 98 | 99 | return $this->getSshExec()->getLastReturnStatus() == 0; 100 | } 101 | 102 | protected function getCommandArguments($input) 103 | { 104 | $commandArguments = []; 105 | foreach ($input->getArguments() as $name => $value) { 106 | switch ($name) { 107 | case 'command': 108 | break; 109 | default: 110 | $commandArguments[] = $value; 111 | break; 112 | } 113 | } 114 | 115 | return $commandArguments; 116 | } 117 | 118 | protected function getCommandOptions($input) 119 | { 120 | $commandOptions = []; 121 | foreach ($input->getOptions() as $name => $value) { 122 | if ($value === false) { 123 | continue; 124 | } 125 | 126 | switch ($name) { 127 | case 'verbose': 128 | case 'profile': 129 | case 'working-dir': 130 | case 'project-name': 131 | case 'cache-dir': 132 | case 'jarvis-extension-autoload-dir': 133 | break; 134 | default: 135 | if ($value === true) { 136 | $commandOptions[] = sprintf('--%s', $name); 137 | continue; 138 | } 139 | 140 | $commandOptions[] = sprintf('--%s=%s', $name, $value); 141 | break; 142 | } 143 | } 144 | 145 | return $commandOptions; 146 | } 147 | } 148 | -------------------------------------------------------------------------------- /src/Command/Project/GitCloneCommand.php: -------------------------------------------------------------------------------- 1 | 14 | */ 15 | 16 | namespace Jarvis\Command\Project; 17 | 18 | use Symfony\Component\Console\Output\OutputInterface; 19 | use Jarvis\Project\ProjectConfiguration; 20 | 21 | class GitCloneCommand extends BaseGitCommand 22 | { 23 | /** 24 | * @var ComposerCommand 25 | */ 26 | protected $composerInstallCommand; 27 | 28 | /** 29 | * Sets the composer install command service. 30 | * 31 | * @param ComposerCommand $command the composer install command 32 | * 33 | * @return self 34 | */ 35 | public function setComposerInstallCommand(ComposerCommand $command) 36 | { 37 | $this->composerInstallCommand = $command; 38 | 39 | return $this; 40 | } 41 | 42 | /** 43 | * Sets the build assets command service. 44 | * 45 | * @param SymfonyAssetsBuildCommand $command the composer install command 46 | * 47 | * @return self 48 | */ 49 | public function setSymfonyAssetsBuildCommand(SymfonyAssetsBuildCommand $command) 50 | { 51 | $this->SymfonyAssetsBuildCommand = $command; 52 | 53 | return $this; 54 | } 55 | 56 | /** 57 | * {@inheritdoc} 58 | */ 59 | public function isEnabled() 60 | { 61 | return $this->enabled && count($this->getProjectConfigurationRepository()->getProjectNames()); 62 | } 63 | 64 | /** 65 | * {@inheritdoc} 66 | */ 67 | protected function getProjectNamesToExclude() 68 | { 69 | return $this->getProjectConfigurationRepository()->getProjectAlreadyInstalledNames(); 70 | } 71 | 72 | /** 73 | * {@inheritdoc} 74 | */ 75 | protected function isProjectShouldBeInstalled() 76 | { 77 | return false; 78 | } 79 | 80 | /** 81 | * {@inheritdoc} 82 | */ 83 | protected function executeCommandByProject($projectName, ProjectConfiguration $projectConfig, OutputInterface $output) 84 | { 85 | $this->cloneGitProject($projectName, $projectConfig, $output); 86 | 87 | $this->getApplication()->add($this->composerInstallCommand); 88 | $this->getApplication()->add($this->SymfonyAssetsBuildCommand); 89 | 90 | $this->getApplication()->executeCommand($this->composerInstallCommand->getName(), [ 91 | '--project-name' => $projectName, 92 | ($output->isDebug() ? ' -vvv' : '-v'), 93 | ], $output); 94 | 95 | $this->getApplication()->executeCommand($this->SymfonyAssetsBuildCommand->getName(), [ 96 | '--project-name' => $projectName, 97 | ($output->isDebug() ? ' -vvv' : '-v'), 98 | ], $output); 99 | } 100 | 101 | protected function cloneGitProject($projectName, ProjectConfiguration $config, OutputInterface $output) 102 | { 103 | if (is_dir($config->getLocalGitRepositoryDir())) { 104 | $output->writeln( 105 | sprintf( 106 | 'A project with that name "%s" already exists', 107 | $projectName 108 | ) 109 | ); 110 | 111 | return; 112 | } 113 | 114 | $output->writeln( 115 | sprintf( 116 | 'Create git project "%s" in "%s"', 117 | $projectName, 118 | $config->getLocalGitRepositoryDir() 119 | ) 120 | ); 121 | 122 | $this->getExec()->run(strtr( 123 | 'git clone %git_repository_url% %local_git_repository_dir% && cd %local_git_repository_dir% && git checkout %git_target_branch%', 124 | [ 125 | '%local_git_repository_dir%' => $config->getLocalGitRepositoryDir(), 126 | '%git_repository_url%' => $config->getGitRepositoryUrl(), 127 | '%git_target_branch%' => $config->getGitTargetBranch(), 128 | ] 129 | ), $output); 130 | } 131 | } 132 | -------------------------------------------------------------------------------- /src/Vagrant/Exec.php: -------------------------------------------------------------------------------- 1 | 14 | */ 15 | 16 | namespace Jarvis\Vagrant; 17 | 18 | use Psr\Log\LoggerAwareTrait; 19 | use Symfony\Component\Console\Output\OutputInterface; 20 | 21 | class Exec 22 | { 23 | use LoggerAwareTrait; 24 | 25 | /** 26 | * @var string 27 | */ 28 | private $cwd; 29 | 30 | public function __construct($cwd) 31 | { 32 | $this->cwd = $cwd; 33 | } 34 | 35 | public function ssh($remoteCommandLine = null) 36 | { 37 | $previousCwd = getcwd(); 38 | 39 | $cwd = realpath($this->cwd); 40 | !$cwd ?: chdir($this->cwd); 41 | 42 | $commandLine = 'vagrant ssh'; 43 | 44 | if (!empty($remoteCommandLine)) { 45 | $commandLine .= sprintf(' --command "%s" -- -t -q', escapeshellcmd($remoteCommandLine)); 46 | } 47 | 48 | !$this->logger ?: $this->logger->debug($commandLine); 49 | 50 | passthru($commandLine); 51 | 52 | !$previousCwd ?: chdir($previousCwd); 53 | } 54 | 55 | /** 56 | * Execute a command using vagrant. 57 | * 58 | * @param string $commandLine 59 | * @param array $options 60 | * 61 | * @return array The array will be filled with every line of output from the command 62 | */ 63 | public function exec($commandLine, array $options = []) 64 | { 65 | $commandLine = sprintf('vagrant %s', escapeshellcmd($commandLine)); 66 | foreach ($options as $name => $value) { 67 | $commandLine .= sprintf(' --%s=%s', $name, $value); 68 | } 69 | $previousCwd = getcwd(); 70 | 71 | $cwd = realpath($this->cwd); 72 | if ($cwd) { 73 | chdir($this->cwd); 74 | !$this->logger ?: $this->logger->debug(sprintf('Changed CWD to %s', $cwd)); 75 | } 76 | 77 | !$this->logger ?: $this->logger->debug($commandLine); 78 | 79 | passthru($commandLine, $returnStatus); 80 | 81 | $this->lastReturnStatus = $returnStatus; 82 | 83 | !$previousCwd ?: chdir($previousCwd); 84 | } 85 | 86 | /** 87 | * Runs command using vagrant. 88 | * 89 | * @param string $commandLine 90 | * @param OutputInterface|null $output 91 | * 92 | * @return string 93 | */ 94 | public function run($commandLine, OutputInterface $output = null, $verbosityMin = OutputInterface::VERBOSITY_VERY_VERBOSE) 95 | { 96 | $commandLine = sprintf('vagrant %s', escapeshellcmd($commandLine)); 97 | 98 | $previousCwd = getcwd(); 99 | 100 | $cwd = realpath($this->cwd); 101 | if ($cwd) { 102 | chdir($this->cwd); 103 | !$this->logger ?: $this->logger->debug(sprintf('Changed CWD to %s', $cwd)); 104 | } 105 | 106 | !$this->logger ?: $this->logger->debug($commandLine); 107 | 108 | ob_start(); 109 | 110 | passthru($commandLine, $returnStatus); 111 | 112 | if ($output instanceof OutputInterface) { 113 | if ($returnStatus != 0) { // execute with error 114 | $output->writeln(''.trim(ob_get_contents()).''); 115 | } elseif ($output->getVerbosity() >= $verbosityMin) { 116 | $output->writeln(trim(ob_get_contents()), OutputInterface::OUTPUT_RAW); 117 | } 118 | } elseif ($returnStatus != 0) { // execute with error 119 | if (!$this->logger) { 120 | throw new \RuntimeException(trim(ob_get_contents())); 121 | } else { 122 | $this->logger->debug(trim(ob_get_contents())); 123 | } 124 | } 125 | 126 | $this->lastReturnStatus = $returnStatus; 127 | 128 | !$previousCwd ?: chdir($previousCwd); 129 | 130 | return ob_get_clean(); 131 | } 132 | 133 | /** 134 | * Gets the value of cwd. 135 | * 136 | * @return string 137 | */ 138 | public function getCwd() 139 | { 140 | return $this->cwd; 141 | } 142 | } 143 | -------------------------------------------------------------------------------- /src/Console/Helper/ReadlineHelper.php: -------------------------------------------------------------------------------- 1 | readline = $readline ?: new Readline(); 25 | } 26 | 27 | public function read(OutputInterface $output, $message, $default = null) 28 | { 29 | $message = $output->getFormatter()->format($message); 30 | 31 | return $this->readline->readLine($message) ?: $default; 32 | } 33 | 34 | public function autocomplete(OutputInterface $output, $message, Autocompleter $autocompleter, $validator = null, $default = null) 35 | { 36 | $this->readline->setAutocompleter($autocompleter); 37 | 38 | return $this->validate($output, $message, $validator ?: function () { return true; }, $default); 39 | } 40 | 41 | public function select(OutputInterface $output, $message, array $choices, $default = null, $keyAsValues = false, $multi = false, Autocompleter $autocompleter = null) 42 | { 43 | $words = array(); 44 | $values = $keyAsValues ? array_keys($choices) : array_values($choices); 45 | foreach ($choices as $key => $value) { 46 | if ($value !== self::SEPARATOR) { 47 | $words[] = $keyAsValues ? $key : $value; 48 | } 49 | } 50 | 51 | if (null === $autocompleter) { 52 | $autocompleter = new Word($words); 53 | } else { 54 | $autocompleter->setWords($words); 55 | } 56 | 57 | $list = ''; 58 | foreach ($choices as $key => $value) { 59 | if (self::SEPARATOR === $value) { 60 | if (is_string($key)) { 61 | $list .= $key; 62 | } 63 | } else { 64 | if ($keyAsValues) { 65 | $list .= sprintf( 66 | '%s%s: %s', 67 | null !== $default && $key === $default ? '* ' : ' ', 68 | sprintf($keyAsValues ? '%s' : '%s', $key), 69 | sprintf($keyAsValues ? '%s' : '%s', $value) 70 | ); 71 | } else { 72 | $list .= sprintf( 73 | '%s%s', 74 | null !== $default && $value === $default ? '* ' : ' ', 75 | sprintf($keyAsValues ? '%s' : '%s', $value) 76 | ); 77 | } 78 | } 79 | 80 | $list .= PHP_EOL; 81 | } 82 | 83 | $output->writeln($list); 84 | 85 | $validator = function ($data) use ($values, $multi) { 86 | if (true === $multi) { 87 | $data = explode(' ', $data); 88 | } else { 89 | $data = array($data); 90 | } 91 | 92 | return array_intersect($data, $values) === $data; 93 | }; 94 | 95 | $input = $this->autocomplete($output, $message, $autocompleter, $validator, $default); 96 | 97 | if (true === $multi) { 98 | $input = explode(' ', $input); 99 | } 100 | 101 | return $input; 102 | } 103 | 104 | public function validate(OutputInterface $output, $message, $validator, $default = null) 105 | { 106 | if (false === is_callable($validator)) { 107 | throw new \InvalidArgumentException('Argument is not callable'); 108 | } 109 | 110 | $data = null; 111 | $error = null; 112 | do { 113 | if (null !== $error) { 114 | $output->writeln(sprintf($error ?: ' Invalid input: %s ', $data)); 115 | } 116 | 117 | $data = $this->read($output, $message, $default); 118 | } while (true !== ($error = $validator($data))); 119 | 120 | return $data; 121 | } 122 | } 123 | --------------------------------------------------------------------------------