Update Composer, update everything

This commit is contained in:
Oliver Davies 2018-11-23 12:29:20 +00:00
parent ea3e94409f
commit dda5c284b6
19527 changed files with 1135420 additions and 351004 deletions

61
vendor/drush/drush/.circleci/config.yml vendored Normal file
View file

@ -0,0 +1,61 @@
# https://circleci.com/docs/2.0/workflows/#using-workspaces-to-share-data-among-jobs
defaults: &defaults
working_directory: ~/drush
environment:
TZ: "/usr/share/zoneinfo/America/Los_Angeles"
TERM: dumb
UNISH_NO_TIMEOUTS: y
UNISH_DB_URL: mysql://root:@127.0.0.1
UNISH_TMP: /tmp
PHPUNIT_ARGS: ""
version: 2
jobs:
build:
<<: *defaults
docker:
- image: circleci/php:7.1-apache-node
environment:
- MYSQL_HOST=127.0.0.1
- image: circleci/mysql:5.7.18
steps:
- checkout
- run: $HOME/drush/.circleci/setup.sh
- run: unish.sut.php
- run: unish.phpunit.php $PHPUNIT_ARGS
build_highest:
<<: *defaults
docker:
- image: circleci/php:7.1-apache-node
environment:
- MYSQL_HOST=127.0.0.1
- COMPOSER=composer-highest.json
- image: circleci/mysql:5.7.18
steps:
- checkout
- run: $HOME/drush/.circleci/setup.sh
- run: unish.sut.php
- run: unish.phpunit.php $PHPUNIT_ARGS
build_56:
<<: *defaults
docker:
- image: circleci/php:5.6-apache-node
environment:
- MYSQL_HOST=127.0.0.1
- image: circleci/mysql:5.7.18
steps:
- checkout
- run: $HOME/drush/.circleci/setup.sh
- run: unish.sut.php
- run: unish.phpunit.php $PHPUNIT_ARGS
workflows:
version: 2
build_test:
jobs:
- build
- build_highest
- build_56

38
vendor/drush/drush/.circleci/setup.sh vendored Executable file
View file

@ -0,0 +1,38 @@
#!/bin/bash
# Install PHP extensions
sudo docker-php-ext-install pdo_mysql
# Install extension
sudo apt-get install -y libpng-dev
# Install PHP Extensions
sudo docker-php-ext-install gd
# Install Composer
'curl -sS https://getcomposer.org/installer | sudo php -- --install-dir=/usr/local/bin --filename=composer'
# Display versions
php -v
composer --version
# Install mysql-client
sudo apt-get install mysql-client
# Configure bash environment variables
echo 'export PATH=~/.composer/vendor/bin:~/drush:$PATH' >> $BASH_ENV
echo 'export HOME=/tmp/drush-sandbox/home' >> $BASH_ENV
mkdir -p /tmp/drush-sandbox/home
# Configure php.ini
echo 'mbstring.http_input = pass' > $HOME/php.ini
echo 'mbstring.http_output = pass' >> $HOME/php.ini
echo 'memory_limit = -1' >> $HOME/php.ini
echo 'sendmail_path = /bin/true' >> $HOME/php.ini
echo 'date.timezone = "UTC"' >> $HOME/php.ini
echo 'opcache.enable_cli = 0' >> $HOME/php.ini
# Copy our php.ini configuration to the active php.ini file
# We can't use `php -r 'print php_ini_loaded_file();` when there is no php.ini
PHPINI_PATH="$(php -i | grep 'Configuration File (php.ini) Path' | sed -e 's#.*=> *##')/php.ini"
cat $HOME/php.ini | sudo tee "$PHPINI_PATH" > /dev/null

View file

@ -0,0 +1,31 @@
---
name: Bug report or support request
about: For support requests, please use Drupal Answers instead. See http://drupal.stackexchange.com/questions/tagged/drush
---
**Describe the bug**
A clear and concise description of what the bug is.
**To Reproduce**
What did you do?
**Expected behavior**
What did you expect would happen?
**Actual behavior**
What happened instead?
**Workaround**
Is there another way to do the desired action?
### System Configuration
| Q | A
| --------------- | ---
| Drush version? | 9.x/8.x (please be specific, and try latest dev build)
| Drupal version? | 7.x/8.x
| PHP version | 5.6/7.1
| OS? | Mac/Linux/Windows
**Additional information**
Add any other context about the problem here.

View file

@ -0,0 +1,19 @@
---
name: Documentation request
about: If you know what the documentation change should be, please consider submitting
a pull request instead. If you do know where the documentation you need is, please
submit a support request first.
---
**Existing document**
Please provide a link to the existing document that is unclear or incomplete.
**What are you attempting to do**
Please explain the task you are attempting to accomplish.
**In what way is the existing documentation unclear or incomplete**
Please explain any confusion or ambiguities in the existing documentation.
**What should the documentation say instead?**
To the best of your ability, explain what additional information would allow you to complete your task. If you already know what the documentation should say, please consider submitting a documentation pull request instead.

View file

@ -0,0 +1,17 @@
---
name: Feature request
about: Suggest an idea for this project
---
**Is your feature request related to a problem? Please describe.**
A clear and concise description of what the problem is. Ex. I'm always frustrated when [...]
**Describe the solution you'd like**
A clear and concise description of what you want to happen.
**Describe alternatives you've considered**
A clear and concise description of any alternative solutions or features you've considered.
**Additional context**
Add any other context or screenshots about the feature request here.

13
vendor/drush/drush/.gitignore vendored Normal file
View file

@ -0,0 +1,13 @@
tests/phpunit.xml
vendor
box.phar
drush.phar
#The mkdocs output directory.
site
#The sami output directories
api
.sami-cache
# IDE config
.idea/
# https://github.com/drush-ops/drush/issues/2688
composer.lock

66
vendor/drush/drush/.travis.yml vendored Normal file
View file

@ -0,0 +1,66 @@
# Configuration file for unit test runner at http://travis-ci.org/#!/drush-ops/drush
branches:
only:
- master
- 8.x
- 7.x
- 6.x
- 5.x
- /^[[:digit:]]+\.[[:digit:]]+\.[[:digit:]]+.*$/
language: php
# Cache Composer.
cache:
directories:
- $HOME/.composer/cache
# http://blog.travis-ci.com/2014-12-17-faster-builds-with-container-based-infrastructure/
sudo: false
matrix:
include:
- php: 7.2
env: 'SCENARIO=isolation DEPENDENCIES=highest'
- php: 7.2
env: 'SCENARIO=isolation'
- php: 7.0.11
env: 'SCENARIO=isolation'
- php: 5.6
env: 'SCENARIO=isolation-phpunit4 DEPENDENCIES=lowest'
- php: 5.6
env: 'SCENARIO=isolation-phpunit4 DEPENDENCIES=lowest'
env:
global:
# GitHub deploy
- secure: VfYokT2CchfuBRJp9/gSwfVGPfsVfkZdDVEuNWEqxww3z4vq+5aLKqoCtPL54E5EIMjhyCE3GVo+biG35Gab1KOVgUs8zD1hAUWA1FPKfMFhoPDfI3ZJC2rX2T1iWK4ZR90pBtcPzS+2OObzTYz8go0PfeSTT6eq69Na1KcNLaE=
- UNISH_NO_TIMEOUTS=y
- UNISH_DB_URL=mysql://root:@127.0.0.1
- UNISH_TMP=/tmp
before_install:
- echo 'mbstring.http_input = pass' >> ~/.phpenv/versions/$(phpenv version-name)/etc/conf.d/travis.ini
- echo 'mbstring.http_output = pass' >> ~/.phpenv/versions/$(phpenv version-name)/etc/conf.d/travis.ini
- echo 'memory_limit = -1' >> ~/.phpenv/versions/$(phpenv version-name)/etc/conf.d/travis.ini
# Build a System-Under-Test.
install:
- 'composer scenario "${SCENARIO}" "${DEPENDENCIES}"'
before_script:
- phpenv config-rm xdebug.ini
- echo 'sendmail_path = /bin/true' >> ~/.phpenv/versions/$(phpenv version-name)/etc/conf.d/travis.ini
# - echo "sendmail_path='true'" >> `php --ini | grep "Loaded Configuration" | awk '{print $4}'`
script:
- composer unit
after_success:
# Publish updated API documentation on every push to the master branch
- git config --global user.email $GITHUB_USER_EMAIL
- git config --global user.name "Drush Documentation Bot"
- cd $TRAVIS_BUILD_DIR && build/scripts/publish-api-docs.sh
# Background: https://github.com/drush-ops/drush/pull/1426
#- ${PWD}/tests/testChildren.sh

19
vendor/drush/drush/CONTRIBUTING.md vendored Normal file
View file

@ -0,0 +1,19 @@
Drush is built by people like you! Please [join us](https://github.com/drush-ops/drush).
## Git and Pull requests
* Contributions are submitted, reviewed, and accepted using GitHub pull requests. [Read this article](https://help.github.com/articles/using-pull-requests) for some details. We use the _Fork and Pull_ model, as described there.
* The latest changes are in the `master` branch. PR's should initially target this branch.
* Try to make clean commits that are easily readable (including descriptive commit messages!)
* Test before you push. Get familiar with Unish, our test suite. See the test-specific [README.md](tests/README.md)
* We maintain branches named 9.x, 8.x, etc. These are release branches. From these branches, we make new tags for patch and minor versions.
## Coding style
* Do write comments. You don't have to comment every line, but if you come up with something thats a bit complex/weird, just leave a comment. Bear in mind that you will probably leave the project at some point and that other people will read your code. Undocumented huge amounts of code are nearly worthless!
* We use [PSR-2](http://www.php-fig.org/psr/psr-2/) in the /src directory. [Drupal's coding standards](https://drupal.org/coding-standards) are still used in the includes directory (deprecated code).
* Don't overengineer. Don't try to solve any possible problem in one step, but try to solve problems as easy as possible and improve the solution over time!
* Do generalize sooner or later! (if an old solution, quickly hacked together, poses more problems than it solves today, refactor it!)
* Keep it compatible. Do not introduce changes to the public API, or configurations too casually. Don't make incompatible changes without good reasons!
## Documentation
* The docs are in the [docs](docs) and [examples](examples) folders in the git repository, so people can easily find the suitable docs for the current git revision. You can read these from within Drush, with the `drush topic` command.
* Documentation should be kept up-to-date. This means, whenever you add a new API method, add a new hook or change the database model, pack the relevant changes to the docs in the same pull request.

56
vendor/drush/drush/README.md vendored Normal file
View file

@ -0,0 +1,56 @@
Drush is a command line shell and Unix scripting interface for Drupal. Drush core ships with lots of useful commands for interacting with code like modules/themes/profiles. Similarly, it runs update.php, executes SQL queries and DB migrations, and misc utilities like run cron or clear cache. Developers love the `generate` command, which jump starts your coding project by writing ready-to-customize PHP and YML files. Drush can be extended by [3rd party commandfiles](https://www.drupal.org/project/project_module?f[2]=im_vid_3%3A4654).
[![Latest Stable Version](https://poser.pugx.org/drush/drush/v/stable.png)](https://packagist.org/packages/drush/drush) [![Total Downloads](https://poser.pugx.org/drush/drush/downloads.png)](https://packagist.org/packages/drush/drush) [![Latest Unstable Version](https://poser.pugx.org/drush/drush/v/unstable.png)](https://packagist.org/packages/drush/drush) [![License](https://poser.pugx.org/drush/drush/license.png)](https://packagist.org/packages/drush/drush) [![Documentation Status](https://readthedocs.org/projects/drush/badge/?version=master)](https://readthedocs.org/projects/drush/?badge=master)
| Code style | Isolation Tests | Functional Tests |
| :--------: | :-------------: | :--------------: |
| <img src="https://api.shippable.com/projects/5507addd5ab6cc1352a213b5/badge?branch=master"> | <img src="https://travis-ci.org/drush-ops/drush.svg?branch=master"> | <img src="https://circleci.com/gh/drush-ops/drush.svg?style=shield"> |
Resources
-----------
* [Installing (and Upgrading)](http://docs.drush.org/en/master/install/)
* [General Documentation](http://docs.drush.org)
* [API Documentation](http://www.drush.org/api/master/index.html)
* [Drush Commands](http://drushcommands.com)
* Subscribe [this atom feed](https://github.com/drush-ops/drush/releases.atom) to receive notification of new releases. Also, [Version eye](https://www.versioneye.com/).
* [Drush packages available via Composer](https://packagist.org/search/?type=drupal-drush)
* [A list of modules that include Drush integration](https://www.drupal.org/project/project_module?f[2]=im_vid_3%3A4654&solrsort=ds_project_latest_release+desc)
* Drush comes with a [full test suite](https://github.com/drush-ops/drush/blob/master/tests/README.md) powered by [PHPUnit](https://github.com/sebastianbergmann/phpunit). Each commit gets tested by the awesome [Travis CI continuous integration service](https://travis-ci.org/drush-ops/drush).
Support
-----------
* Post support requests to [Drupal Answers](http://drupal.stackexchange.com/questions/tagged/drush). Tag question with 'drush'.
* Report bugs and request features in the [GitHub Drush Issue Queue](https://github.com/drush-ops/drush/issues).
* Use pull requests (PRs) to contribute to Drush.
Code of Conduct
---------------
The Drush project expects all participants to abide by the [Drupal Code of Conduct](https://www.drupal.org/dcoc).
FAQ
------
> Q: What does "Drush" stand for?<br>
> A: The Drupal Shell.
>
> Q: How do I pronounce Drush?<br>
> A: Some people pronounce the *dru* with a long 'u' like Dr*u*pal. Fidelity points
> go to them, but they are in the minority. Most pronounce Drush so that it
> rhymes with hush, rush, flush, etc. This is the preferred pronunciation.
>
> Q: Does Drush have unit tests?<br>
> A: Drush has an excellent suite of unit tests. See
> [tests/README.md](https://github.com/drush-ops/drush/blob/master/tests/README.md) for more information.
Credits
-----------
* Originally developed by [Arto Bendiken](http://bendiken.net) for Drupal 4.7.
* Redesigned by [Franz Heinzmann](http://unbiskant.org) in May 2007 for Drupal 5.
* Maintained by [Moshe Weitzman](http://drupal.org/moshe) with much help from
the folks listed at https://github.com/orgs/drush-ops/people.
* Thanks to [JetBrains](https://www.jetbrains.com) for [supporting this project and open source software](https://www.jetbrains.com/buy/opensource/).
![Drush Logo](drush_logo-black.png)
[![PhpStorm Logo](misc/icon_PhpStorm.png)](https://www.jetbrains.com/phpstorm/)

View file

@ -0,0 +1,49 @@
#!/bin/bash
# Test for master branch, or other branches matching 0.x, 1.x, etc.
BRANCH_REGEX='^\(master\|9\.[0-9x.]*\)$'
# Check to make sure that our build environment is right. Skip with no error otherwise.
test -n "$TRAVIS" || { echo "This script is only designed to be run on Travis."; exit 0; }
echo "$TRAVIS_BRANCH" | grep -q $BRANCH_REGEX || { echo "Skipping docs update for branch $TRAVIS_BRANCH - docs only updated for master branch and tagged builds."; exit 0; }
test "$TRAVIS_PULL_REQUEST" == "false" || { echo "Skipping docs update -- not done on pull requests. (PR #$TRAVIS_PULL_REQUEST)"; exit 0; }
test "${TRAVIS_PHP_VERSION:0:1}" == "7" || { echo "Skipping docs update for PHP $TRAVIS_PHP_VERSION -- only update for PHP 7 builds."; exit 0; }
test "$TRAVIS_REPO_SLUG" == "drush-ops/drush" || { echo "Skipping docs update for repository $TRAVIS_REPO_SLUG -- do not build docs for forks."; exit 0; }
# Check our requirements for running this script have been met.
test -n "$GITHUB_TOKEN" || { echo "GITHUB_TOKEN environment variable must be set to run this script."; exit 1; }
test -n "$(git config --global user.email)" || { echo 'Git user email not set. Use `git config --global user.email EMAIL`.'; exit 1; }
test -n "$(git config --global user.name)" || { echo 'Git user name not set. Use `git config --global user.name NAME`.'; exit 1; }
# Ensure that we exit on failure, and echo lines as they are executed.
# We don't need to see our sanity-checks get echoed, so we turn this on after they are done.
set -ev
# Install Sami using the install script in composer.json
composer sami-install
# Build the API documentation using the api script in composer.json
# We have Sami parse errors so ignore return value: https://stackoverflow.com/questions/35452147/allow-non-zero-return-codes-in-travis-ci-yml
composer -v api || true
echo "Create build $API_BUID_DIR dir if needed."
# Check out the gh-pages branch using our Github token (defined at https://travis-ci.org/lcache/lcache/settings)
API_BUILD_DIR="$HOME/.drush-build/gh-pages"
if [ ! -d "$API_BUILD_DIR" ]
then
mkdir -p "$(dirname $API_BUILD_DIR)"
git clone --quiet --branch=gh-pages https://${GITHUB_TOKEN}@github.com/drush-ops/drush "$API_BUILD_DIR" > /dev/null
fi
# Replace the old 'api' folder with the newly-built API documentation
rm -rf "$API_BUILD_DIR/api"
cp -R api "$API_BUILD_DIR"
echo "Commit new API docs."
# Commit any changes to the documentation
cd "$API_BUILD_DIR"
git add -A api
git commit -m "Update API documentation from Travis build $TRAVIS_BUILD_NUMBER, '$TRAVIS_COMMIT'."
git push

105
vendor/drush/drush/composer.json vendored Normal file
View file

@ -0,0 +1,105 @@
{
"name": "drush/drush",
"description": "Drush is a command line shell and scripting interface for Drupal, a veritable Swiss Army knife designed to make life easier for those of us who spend some of our working hours hacking away at the command prompt.",
"homepage": "http://www.drush.org",
"license": "GPL-2.0-or-later",
"minimum-stability": "dev",
"prefer-stable": true,
"authors": [
{ "name": "Moshe Weitzman", "email": "weitzman@tejasa.com" },
{ "name": "Owen Barton", "email": "drupal@owenbarton.com" },
{ "name": "Greg Anderson", "email": "greg.1.anderson@greenknowe.org" },
{ "name": "Jonathan Araña Cruz", "email": "jonhattan@faita.net" },
{ "name": "Jonathan Hedstrom", "email": "jhedstrom@gmail.com" },
{ "name": "Christopher Gervais", "email": "chris@ergonlogic.com" },
{ "name": "Dave Reid", "email": "dave@davereid.net" },
{ "name": "Damian Lee", "email": "damiankloip@googlemail.com" }
],
"support": {
"forum": "http://drupal.stackexchange.com/questions/tagged/drush",
"irc": "irc://irc.freenode.org/drush",
"slack": "https://drupal.slack.com/messages/C62H9CWQM"
},
"bin": [
"drush"
],
"require": {
"php": ">=5.6.0",
"ext-dom": "*",
"chi-teck/drupal-code-generator": "^1.24.0",
"composer/semver": "^1.4",
"consolidation/annotated-command": "^2.8.1",
"consolidation/config": "^1.1.0",
"consolidation/output-formatters": "^3.1.12",
"consolidation/robo": "^1.1.5",
"consolidation/site-alias": "^1.1.2",
"grasmash/yaml-expander": "^1.1.1",
"league/container": "~2",
"psr/log": "~1.0",
"psy/psysh": "~0.6",
"symfony/config": "~2.2|^3",
"symfony/console": "~2.7|^3",
"symfony/event-dispatcher": "~2.7|^3",
"symfony/finder": "~2.7|^3",
"symfony/process": "~2.7|^3",
"symfony/var-dumper": "~2.7|^3|^4",
"symfony/yaml": "~2.3|^3",
"webflo/drupal-finder": "^1.1",
"webmozart/path-util": "^2.1.0"
},
"require-dev": {
"lox/xhprof": "dev-master",
"g1a/composer-test-scenarios": "^2.2.0",
"phpunit/phpunit": "^4.8.36|^5.5.4",
"squizlabs/php_codesniffer": "^2.7"
},
"autoload": {
"psr-4": {
"Drush\\": "src/",
"Drush\\Internal\\": "internal-copy/",
"Unish\\": "tests/"
}
},
"autoload-dev": {
"psr-4": {
"Drush\\": "isolation/src/"
}
},
"config": {
"optimize-autoloader": true,
"preferred-install": "dist",
"sort-packages": true,
"platform": {
"php": "5.6"
}
},
"scripts": {
"cs": "phpcs -n --standard=PSR2 src tests examples",
"cbf": "phpcbf -n --standard=PSR2 src tests examples",
"lint": [
"find includes -name '*.inc' -print0 | xargs -0 -n1 php -l",
"find src -name '*.php' -print0 | xargs -0 -n1 php -l",
"find tests -name '*.php' -print0 | xargs -0 -n1 php -l"
],
"test": [
"@lint",
"@unit",
"@cs",
"@functional"
],
"api": "PATH=$HOME/bin:$PATH sami.phar --ansi update sami-config.php",
"sami-install": "mkdir -p $HOME/bin && curl --output $HOME/bin/sami.phar http://get.sensiolabs.org/sami.phar && chmod +x $HOME/bin/sami.phar",
"scenario": "scenarios/install",
"unit": "phpunit --colors=always",
"functional": "./unish.phpunit.php",
"post-update-cmd": [
"create-scenario isolation --autoload-dir isolation --autoload-dir internal-copy --keep '\\(psr/log\\|consolidation/config\\|site-alias\\|var-dumper\\|symfony/finder\\|drupal-finder\\|path-util\\|sebastian/version\\|xhprof\\)' 'phpunit/phpunit:^5.5.4'",
"create-scenario isolation-phpunit4 --base isolation --autoload-dir isolation --autoload-dir internal-copy 'phpunit/phpunit:^4.8.36'"
]
},
"extra": {
"branch-alias": {
"dev-master": "9.x-dev"
}
}
}

36
vendor/drush/drush/docs/bootstrap.md vendored Normal file
View file

@ -0,0 +1,36 @@
The Drush Bootstrap Process
===========================
When preparing to run a command, Drush works by "bootstrapping" the Drupal environment in very much the same way that is done during a normal page request from the web server, so most Drush commands run in the context of a fully-initialized website.
For efficiency and convenience, some Drush commands can work without first bootstrapping a Drupal site, or by only partially bootstrapping a site. This is faster than a full bootstrap. It is also a matter of convenience, because some commands are useful even when you don't have a working Drupal site.
Commands may specify their bootstrap level with a `@bootstrap` annotation. Commands supplied by Drupal modules are always `@bootstrap full`.
@bootstrap none
-----------------------
Only run Drush _preflight_, without considering Drupal at all. Any code that operates on the Drush installation, and not specifically any Drupal directory, should bootstrap to this phase.
@bootstrap root
------------------------------
Set up and test for a valid Drupal root, either through the --root options, or evaluated based on the current working directory. Any code that interacts with an entire Drupal installation, and not a specific site on the Drupal installation should use this bootstrap phase.
@bootstrap site
------------------------------
Set up a Drupal site directory and the correct environment variables to allow Drupal to find the configuration file. If no site is specified with the --uri options, Drush will assume the site is 'default', which mimics Drupal's behaviour. Note that it is necessary to specify a full URI, e.g. --uri=http://example.com, in order for certain Drush commands and Drupal modules to behave correctly. See the [example Config file](../examples/example.drush.yml) for more information. Any code that needs to modify or interact with a specific Drupal site's settings.php file should bootstrap to this phase.
@bootstrap configuration
---------------------------------------
Load the settings from the Drupal sites directory. This phase is analogous to the DRUPAL\_BOOTSTRAP\_CONFIGURATION bootstrap phase in Drupal itself, and this is also the first step where Drupal specific code is included. This phase is commonly used for code that interacts with the Drupal install API, as both install.php and update.php start at this phase.
@bootstrap database
----------------------------------
Connect to the Drupal database using the database credentials loaded during the previous bootstrap phase. This phase is analogous to the DRUPAL\_BOOTSTRAP\_DATABASE bootstrap phase in Drupal. Any code that needs to interact with the Drupal database API needs to be bootstrapped to at least this phase.
@bootstrap full
------------------------------
Fully initialize Drupal. This is analogous to the DRUPAL\_BOOTSTRAP\_FULL bootstrap phase in Drupal. Any code that interacts with the general Drupal API should be bootstrapped to this phase.
@bootstrap max
---------------------
This is not an actual bootstrap phase. Commands that use the "max" bootstrap level will cause Drush to bootstrap as far as possible, and then run the command regardless of the bootstrap phase that was reached. This is useful for Drush commands that work without a bootstrapped site, but that provide additional information or capabilities in the presence of a bootstrapped site. For example, `drush status` will show progressively more information the farther the site bootstraps.

77
vendor/drush/drush/docs/commands.md vendored Normal file
View file

@ -0,0 +1,77 @@
Creating Custom Drush Commands
==============================
Creating a new Drush command or porting a legacy command is easy. Follow the steps below.
1. Run `drush generate drush-command-file`.
1. Drush will prompt for the machine name of the module that should "own" the file.
1. (optional) Drush will also prompt for the path to a legacy command file to port. See [tips on porting command to Drush 9](https://weitzman.github.io/blog/port-to-drush9)
1. The module selected must already exist and be enabled. Use `drush generate module-standard` to create a new module.
1. Drush will then report that it created a commandfile, a drush.services.yml file and a composer.json file. Edit those files as needed.
1. Use the classes for the core Drush commands at [/src/Drupal/Commands](https://github.com/drush-ops/drush/tree/master/src/Drupal/Commands) as inspiration and documentation.
1. See the [dependency injection docs](dependency-injection.md) for interfaces you can implement to gain access to Drush config, Drupal site aliases, etc.
1. Once your two files are ready, run `drush cr` to get your command recognized by the Drupal container.
Specifying the Services File
================================
A module's composer.json file stipulates the filename where the Drush services (e.g. the Drush command files) are defined. The default services file is `drush.services.yml`, which is defined in the extra section of the composer.json file as follows:
```
"extra": {
"drush": {
"services": {
"drush.services.yml": "^9"
}
}
}
```
If for some reason you need to load different services for different versions of Drush, simply define multiple services files in the `services` section. The first one found will be used. For example:
```
"extra": {
"drush": {
"services": {
"drush-9-99.services.yml": "^9.99",
"drush.services.yml": "^9"
}
}
}
```
In this example, the file `drush-9-99.services.yml` loads commandfile classes that require features only available in Drush 9.99 and later, and drush.services.yml loads an older commandfile implementation for earlier versions of Drush.
It is also possible to use [version ranges](https://getcomposer.org/doc/articles/versions.md#version-range) to exactly specify which version of Drush the services file should be used with (e.g. `"drush.services.yml": ">=9 <9.99"`).
In Drush 9, the default services file, `drush.services.yml`, will be used in instances where there is no `services` section in the Drush extras of the project's composer.json file. In Drush 10, however, the services section must exist, and must name the services file to be used. If a future Drush extension is written such that it only works with Drush 10 and later, then its entry would read `"drush.services.yml": "^10"`, and Drush 9 would not load the extension's commands. It is all the same recommended that Drush 9 extensions explicitly declare their services file with an appropriate version constraint.
Altering Drush Command Info
===========================
Drush command info (annotations) can be altered from other modules. This is done by creating and registering 'command info alterers'. Alterers are class services that are able to intercept and manipulate an existing command annotation.
In order to alter an existing command info, follow the next steps:
1. In the module that wants to alter a command info, add a service class that implements the `\Consolidation\AnnotatedCommand\CommandInfoAltererInterface`.
1. In the module `drush.services.yml` declare a service pointing to this class and tag the service with the `drush.command_info_alterer` tag.
1. In the class implement the alteration logic the `alterCommandInfo()` method.
1. Along with the alter code, it's strongly recommended to log a debug message explaining what exactly was altered. This would allow the easy debugging. Also it's a good practice to inject the the logger in the class constructor.
For an example, see the alterer class provided by the testing 'woot' module: `tests/resources/modules/d8/woot/src/WootCommandInfoAlterer.php`.
Global Drush Commands
==============================
Commandfiles that don't ship inside Drupal modules are called 'global' commandfiles. See the [examples/Commands](/examples/Commands) folder for examples. In general, it's better to use modules to carry your Drush commands. If you still prefer using a global commandfiles, here are two examples of valid commandfile names and namespaces:
1. Simple
- Filename: $PROJECT_ROOT/drush/Commands/ExampleCommands.php
- Namespace: Drush\Commands
1. Nested (e.g. Commandfile is part of a Composer package)
- Filename: $PROJECT_ROOT/drush/Commands/dev_modules/ExampleCommands.php
- Namespace: Drush\Commands\dev_modules
##### Tips
1. The filename must be have a name like Commands/ExampleCommands.php
1. The prefix `Example` can be whatever string you want.
1. The file must end in `Commands.php`
1. The directory above Commands must be one of:
1. A Folder listed in the 'include' option. include may be provided via config or via CLI.
1. ../drush, /drush or /sites/all/drush. These paths are relative to Drupal root.

View file

@ -0,0 +1,37 @@
# Exporting and Importing Configuration
Drush provides commands to export, transfer, and import configuration files
to and from a Drupal 8 site. Configuration can be altered by different
methods in order to provide different behaviors in different environments;
for example, a development server might be configured slightly differently
than the production server.
This document describes how to make simple value changes to configuration
based on the environment, how to have a different set of enabled modules
in different configurations without affecting your exported configuration
values, and how to make more complex changes.
## Simple Value Changes
It is not necessary to alter the configuration system values to
make simple value changes to configuration variables, as this may be
done by the [configuration override system](https://www.drupal.org/node/1928898).
The configuration override system allows you to change configuration
values for a given instance of a site (e.g. the development server) by
setting configuration variables in the site's settings.php file.
For example, to change the name of a local development site:
```
$config['system.site']['name'] = 'Local Install of Awesome Widgets, Inc.';
```
Note that the configuration override system is a Drupal feature, not
a Drush feature. It should be the preferred method for changing
configuration values on a per-environment basis; however, it does not
work for some things, such as enabling and disabling modules. For
configuration changes not handled by the configuration override system,
you can use Drush configuration filters.
## Ignoring Development Modules
Use the [Config Split](https://www.drupal.org/project/config_split) module to
split off development configuration in a dedicated config directory.

49
vendor/drush/drush/docs/cron.md vendored Normal file
View file

@ -0,0 +1,49 @@
Running Drupal cron tasks from Drush
====================================
Drupal cron tasks are often set up to be run via a wget call to cron.php; this same task can also be accomplished via the `drush cron` command, which circumvents the need to provide a web server interface to cron.
Quick start
----------
If you just want to get started quickly, here is a crontab entry that will run cron once every hour at ten minutes after the hour:
10 * * * * /usr/bin/env PATH=/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin COLUMNS=72 cd [DOCROOT] && ../vendor/bin/drush --uri=your.drupalsite.org --quiet cron
You should set up crontab to run your cron tasks as the same user that runs the web server; for example, if you run your web server as the user www-data:
sudo crontab -u www-data -e
You might need to edit the crontab entry shown above slightly for your particular setup; for example, if you have installed Drush to some directory other than /usr/local/drush, then you will need to adjust the path to drush appropriately. We'll break down the meaning of each section of the crontab entry in the documentation that continues below.
Setting the schedule
--------------------
See `man 5 crontab` for information on how to format the information in a crontab entry. In the example above, the schedule for the crontab is set by the string `10 * * * *`. These fields are the minute, hour, day of month, month and day of week; `*` means essentially 'all values', so `10 * * * *` will run any time the minute == 10 (once every hour).
Setting the PATH
----------------
We use /usr/bin/env to run Drush so that we can set up some necessary environment variables that Drush needs to execute. By default, cron will run each command with an empty PATH, which would not work well with Drush. To find out what your PATH needs to be, just type:
echo $PATH
Take the value that is output and place it into your crontab entry in the place of the one shown above. You can remove any entry that is known to not be of interest to Drush (e.g. /usr/games), or is only useful in a graphic environment (e.g. /usr/X11/bin).
Setting COLUMNS
---------------
When running Drush in a terminal, the number of columns will be automatically determined by Drush by way of the tput command, which queries the active terminal to determine what the width of the screen is. When running Drush from cron, there will not be any terminal set, and the call to tput will produce an error message. Spurious error messages are undesirable, as cron is often configured to send email whenever any output is produced, so it is important to make an effort to insure that successful runs of cron complete with no output.
In some cases, Drush is smart enough to recognize that there is no terminal -- if the terminal value is empty or "dumb", for example. However, there are some "non-terminal" values that Drush does not recognize, such as "unknown." If you manually set `COLUMNS`, then Drush will respect your setting and will not attempt to call tput.
Using --quiet
-------------
By default, Drush will print a success message when the run of cron is completed. The --quiet flag will suppress these and other progress messages, again avoiding an unnecessary email message.
Specifying the Drupal site to run
---------------------------------
There are many ways to tell Drush which Drupal site to select for the active command, and any may be used here. The example uses `cd [DOCROOT]`, but you could also use the --root and --uri flags.

View file

@ -0,0 +1,76 @@
Dependency Injection
==================
Drush 9 command files obtain references to the resources they need through a technique called _dependency injection_. When using this programing paradigm, a class by convention will never use the `new` operator to instantiate dependencies. Instead, it will store the other objects it needs in class variables, and provide a way for other code to assign an object to that variable.
Types of Injection
-----------------------
There are two ways that a class can receive its dependencies. One is called “constructor injection”, and the other is called “setter injection”.
*Example of constructor injection:*
```
public function __construct(DependencyType $service)
{
$this->service = $service;
}
```
*Example of setter injection:*
```
public function setService(DependencyType $service)
{
$this->service = $service;
}
```
A class should use one or the other of these methods. The code that is responsible for providing the dependencies a class need is usually an object called the dependency injection container.
Services Files
------------------
Drush command files can request that Drupal inject services by using a drush.services.yml file. See the document [commands](commands.md) for instructions on how to use the Drupal Code Generator to create a simple command file starter with a drush.services.yml file. An initial services file will look something like this:
```
services:
my_module.commands:
class: \Drupal\my_module\Commands\MyModuleiCommands
tags:
- { name: drush.command }
```
See the [Drupal Documentation](drupal.org) for details on how to inject Drupal services into your command file. The process is exactly the same as using a Drupal services.yml file to inject services into your module classes.
Inflection
-------------
Drush will also inject dependencies that it provides using a technique called inflection. Inflection is a kind of dependency injection that works by way of a set of provided inflection interfaces, one for each available service. Each of these interfaces will define one or more setter methods (usually only one); these will automatically be called by Drush when the commandfile object is instantiated. The command only needs to implement this method and save the provided object in a class field. There is usually a corresponding trait that may be included via a `use` statement to fulfill this requirement.
For example:
```
<?php
namespace Drupal\my_module\Commands;
use Drush\Commands\DrushCommands;
use Consolidation\SiteAlias\SiteAliasManagerAwareInterface;
use Consolidation\SiteAlias\SiteSliasManagerAwareTrait;
class MyModuleiCommands extends DrushCommands implements SiteAliasManagerAwareInterface
{
use SiteAliasManagerAwareTrait;
public function commandName($)
{
$selfAlias = $this->aliasManager()->getSelf();
$this->logger()->success(The current alias is {name}, [name => $selfAlias]);
}
}
```
All Drush command files extend DrushCommands. DrushCommands implements ConfigAwareInterface, IOAwareInterface, LoggerAwareInterface, which gives access to `$this->getConfig()`, `$this->logger()` and other ways to do input and output. See the [IO documentation](io.md) for more information.
Any additional services that are desired must be injected by implementing the appropriate inflection interface.
Additional Interfaces:
- AutoloaderAwareInterface: Provides access to the class loader.
- SiteAliasManagerAwareInterface: The site alias manager [allows alias records to be obtained](site-alias-manager.md).
- CustomEventAwareInterface: Allows command files to [define and fire custom events](hooks.md) that other command files can hook.
- ContainerAwareInterface: Provides Drush's dependency injection container.
Note that although the autoloader and Drush dependency injection container is available and may be injected into your command file if needed, this should be avoided. Favor using services that can be injected from Drupal or Drush. Some of the objects in the container are not part of the Drush public API, and may not maintain compatibility in minor and patch releases.

13
vendor/drush/drush/docs/examples.md vendored Normal file
View file

@ -0,0 +1,13 @@
The _examples_ folder contains excellent example files which you may copy and edit as needed. Read the documentation right in the file. If you see an opportunity to improve the file, please submit a pull request.
* [example.site.yml](https://raw.githubusercontent.com/drush-ops/drush/master/examples/example.site.yml). Example site alias definitions.
* [example.bashrc](https://raw.githubusercontent.com/drush-ops/drush/master/examples/example.bashrc). Enhance your shell with lots of Drush niceties including bash completion.
* [example.drush.yml](https://raw.githubusercontent.com/drush-ops/drush/master/examples/example.drush.yml). A Drush configuration file.
* [example.prompt.sh](https://raw.githubusercontent.com/drush-ops/drush/master/examples/example.prompt.sh). Displays Git repository and Drush alias status in your prompt.
* [git-bisect.example.sh](https://raw.githubusercontent.com/drush-ops/drush/master/examples/git-bisect.example.sh). Spelunking through Drush's git history with bisect.
* [helloworld.script](https://raw.githubusercontent.com/drush-ops/drush/master/examples/helloworld.script). An example Drush script.
* [PolicyCommands](https://raw.githubusercontent.com/drush-ops/drush/master/examples/Commands/PolicyCommands.php). A policy file can disallow prohibited commands/options etc.
* [ArtCommands](https://raw.githubusercontent.com/drush-ops/drush/master/examples/Commands/ArtCommands.php). A fun example command inspired by a famous XKCD comic.
* [SiteAliasAlterCommands](https://raw.githubusercontent.com/drush-ops/drush/master/examples/Commands/SiteAliasAlterCommands.php). An example of dynamically changing site alias definition.
* [SyncViaHttpCommands](https://raw.githubusercontent.com/drush-ops/drush/master/examples/Commands/SyncViaHttpCommands.php). sql-sync modification that transfers via http instead of rsync.
* [XkcdCommands](https://raw.githubusercontent.com/drush-ops/drush/master/examples/Commands/XkcdCommands.php). A fun example command that browses XKCD comics.

29
vendor/drush/drush/docs/generators.md vendored Normal file
View file

@ -0,0 +1,29 @@
Overview
==========================
Generators jump start your coding by building all the boring boilerplate code for you. After running a `drush generate [foo]` command, you have a guide for where to insert your custom logic.
Drush's generators reuse classes provided by the excellent [Drupal Code Generator](https://github.com/Chi-teck/drupal-code-generator) project. See its [Commands directory](https://github.com/Chi-teck/drupal-code-generator/tree/master/src/Command/Drupal_8) for inspiration.
Writing Custom Generators
==========================
Drupal modules may supply their own Generators, just like they can supply Commands.
See [Woot module](https://github.com/drush-ops/drush/blob/master/tests/resources/modules/d8/woot), which Drush uses for testing. Specifically,
1. Write a class similar to [ExampleGenerator](https://github.com/drush-ops/drush/tree/master/tests/resources/modules/d8/woot/src/Generators/). Implement your custom logic in the interact() method. Typically this class is placed in the src/Generators directory.
1. Add a .twig file to the same directory. This template specifies what gets output from the generator.
1. Add your class to your module's drush.services.yml file ([example](https://github.com/drush-ops/drush/blob/master/tests/resources/modules/d8/woot/drush.services.yml)). Use the tag `drush.generator` instead of `drush.command`.
1. Perform a `drush cache-rebuild` to compile your drush.services.yml changes into the Drupal container.
Global Generators
==============================
Generators that don't ship inside Drupal modules are called 'global' generators. In general, its better to use modules to carry your generators. If you still prefer using a global generator, please note:
1. The file's namespace should be `\Drush\Generators`.
1. The filename must be have a name like Generators/FooGenerator.php
1. The prefix `Foo` can be whatever string you want. The file must end in `Generator.php`
1. The enclosing directory must be named `Generators`
1. The directory above Generators must be one of:
1. A Folder listed in the 'include' option. include may be provided via config or via CLI.
1. ../drush, /drush or /sites/all/drush. These paths are relative to Drupal root.

47
vendor/drush/drush/docs/hooks.md vendored Normal file
View file

@ -0,0 +1,47 @@
Core Hooks
============
All commandfiles may implement methods that are called by Drush at various times in the request cycle. To implement one, add a `@hook validate` (for example) to the top of your method.
- [Documentation about available hooks](https://github.com/consolidation/annotated-command#hooks).
- To see how core commands implement a hook, you can [search the Drush source code](https://github.com/drush-ops/drush/search?q=%40hook+validate&type=Code&utf8=%E2%9C%93). This link uses validate hook as an example.
Custom Hooks
============
Drush commands can define custom events that other command files can hook. You can find examples in [CacheCommands](https://github.com/drush-ops/drush/blob/master/src/Commands/core/CacheCommands.php) and [SanitizeCommands](https://github.com/drush-ops/drush/blob/master/src/Drupal/Commands/sql/SanitizeCommands.php)
First, the command must implement CustomEventAwareInterface and use CustomEventAwareTrait, as described in the [dependency injection](dependency-injection.md) documentation.
Then, the command may ask the provided hook manager to return a list of handlers with a certain annotation. In the example below, the `my-event` label is used:
```
/**
* This command uses a custom event 'my-event' to collect data. Note that
* the event handlers will not be found unless the hook manager is
* injected into this command handler object via `setHookManager()`
* (defined in CustomEventAwareTrait).
*
* @command example:command
*/
public function exampleCommand()
{
$myEventHandlers = $this->getCustomEventHandlers('my-event');
$result = [];
foreach ($myEventHandlers as $handler) {
$result[] = $handler();
}
sort($result);
return implode(',', $result);
}
```
Other command handlers may provide implementations by implementing `@hook on-event my-event`.
```
/**
* @hook on-event my-event
*/
public function hookOne()
{
return 'one';
}
```

29
vendor/drush/drush/docs/index.md vendored Normal file
View file

@ -0,0 +1,29 @@
Drush is a command line shell and Unix scripting interface for Drupal. Drush core ships with lots of useful commands for interacting with code like modules/themes/profiles. Similarly, it runs update.php, executes sql queries and DB migrations, and misc utilities like run cron or clear cache. Drush can be extended by [3rd party commandfiles](https://www.drupal.org/project/project_module?f[2]=im_vid_3%3A4654).
[![Latest Stable Version](https://poser.pugx.org/drush/drush/v/stable.png)](https://packagist.org/packages/drush/drush) [![Total Downloads](https://poser.pugx.org/drush/drush/downloads.png)](https://packagist.org/packages/drush/drush) [![Latest Unstable Version](https://poser.pugx.org/drush/drush/v/unstable.png)](https://packagist.org/packages/drush/drush) [![License](https://poser.pugx.org/drush/drush/license.png)](https://packagist.org/packages/drush/drush)
!!! note
Go to the [Drush 8 docs](http://docs.drush.org/en/8.x) if you want prior version of Drush.
Resources
-----------
* [Install documentation](http://docs.drush.org/en/master/install/)
* [General documentation](http://docs.drush.org)
* [API Documentation](www.drush.org/api/master/)
* [Drush Commands](http://drushcommands.com)
* Subscribe [this atom feed](https://github.com/drush-ops/drush/releases.atom) to receive notification on new releases. Also, [Version eye](https://www.versioneye.com/).
* [Drush packages available via Composer](https://packagist.org/?query=drush)
* [A list of modules that include Drush integration](https://www.drupal.org/project/project_module?f[2]=im_vid_3%3A4654&solrsort=ds_project_latest_release+desc)
* Drush comes with a [full test suite](https://github.com/drush-ops/drush/blob/master/tests/README.md) powered by [PHPUnit](https://github.com/sebastianbergmann/phpunit). Each commit gets tested by the awesome [Travis.ci continuous integration service](https://travis-ci.org/drush-ops/drush).
Support
-----------
Please take a moment to review the rest of the information in this file before
pursuing one of the support options below.
* Post support requests to [Drupal Answers](http://drupal.stackexchange.com/questions/tagged/drush).
* Bug reports and feature requests should be reported in the [GitHub Drush Issue Queue](https://github.com/drush-ops/drush/issues).
* Use pull requests (PRs) to contribute to Drush.

85
vendor/drush/drush/docs/install.md vendored Normal file
View file

@ -0,0 +1,85 @@
!!! note
Drush 9 only supports one install method. It requires that your Drupal 8 site be built with Composer and Drush be listed as a dependency.
See the [Drush 8 docs](http://docs.drush.org/en/8.x) for installing prior versions of Drush.
Install a site-local Drush and Drush Launcher.
-----------------
1. It is recommended that Drupal 8 sites be [built using Composer, with Drush listed as a dependency](https://github.com/drupal-composer/drupal-project). That project already includes Drush in its composer.json. If your Composer project doesn't yet depend on Drush, run `composer require drush/drush` to add it. After this step, you may call Drush via `vendor/bin/drush`.
1. Optional. To be able to call `drush` from anywhere, install the [Drush Launcher](https://github.com/drush-ops/drush-launcher). That is a small program which listens on your $PATH and hands control to a site-local Drush that is in the /vendor directory of your Composer project.
1. Optional. Run `drush init`. This edits ~/.bashrc so that Drush's custom prompt and bash integration are active.
See [Usage](http://docs.drush.org/en/master/usage/) for details on using Drush.
- Tip: To use a non-default PHP, [edit ~/.bashrc so that the desired PHP is in front of your $PATH](http://stackoverflow.com/questions/4145667/how-to-override-the-path-of-php-to-use-the-mamp-path/10653443#10653443). If that is not desirable, you can change your PATH for just one request: `PATH=/path/to/php:$PATH` drush status ...`
- Tip: To use a custom php.ini for Drush requests, [see this comment](https://github.com/drush-ops/drush/issues/3294#issuecomment-370201342).
!!! note
Drush 9 cannot run commandfiles from Drush 8 and below (e.g. example.drush.inc). See our [guide on porting commandfiles](https://weitzman.github.io/blog/port-to-drush9). Also note that alias and config files use a new .yml format in Drush 9.
Drupal Compatibility
-----------------
<table>
<tr>
<th> Drush Version </th>
<th> Drush Branch </th>
<th> PHP </th>
<th> Supported Drupal versions </th>
<th> Code Style </th>
<th> Isolation Tests </th>
<th> Functional Tests </th>
</tr>
<tr>
<td> Drush 9 </td>
<td> <a href="https://travis-ci.org/drush-ops/drush">master</a> </td>
<td> 5.6+ </td>
<td> D8.4+ </td>
<td align="center">
<img src="https://api.shippable.com/projects/5507addd5ab6cc1352a213b5/badge?branch=master" />
</td>
<td align="center">
<img src="https://travis-ci.org/drush-ops/drush.svg?branch=master" />
</td>
<td align="center">
<img src="https://circleci.com/gh/drush-ops/drush.svg?style=shield" />
</td>
</tr>
<tr>
<td> Drush 8 </td>
<td> <a href="https://travis-ci.org/drush-ops/drush">8.x</a> </td>
<td> 5.4.5+ </td>
<td> D6, D7, D8.3- </td>
<td align="center">
<img src="https://circleci.com/gh/drush-ops/drush.svg?style=shield" />
</td>
<td align="center">
-
</td>
<td align="center">
<img src="https://travis-ci.org/drush-ops/drush.svg?branch=8.x" />
</td>
</tr>
<tr>
<td> Drush 7 </td>
<td> <a href="https://travis-ci.org/drush-ops/drush">7.x</a> </td>
<td> 5.3.0+ </td>
<td> D6, D7 </td>
<td colspan="3" align="center"> Unsupported </td>
</tr>
<tr>
<td> Drush 6 </td>
<td> <a href="https://travis-ci.org/drush-ops/drush">6.x</a> </td>
<td> 5.3.0+ </td>
<td> D6, D7 </td>
<td colspan="3" align="center"> Unsupported </td>
</tr>
<tr>
<td> Drush 5 </td>
<td> <a href="https://travis-ci.org/drush-ops/drush">5.x</a> </td>
<td> 5.2.0+ </td>
<td> D6, D7 </td>
<td colspan="3" align="center"> Unsupported </td>
</tr>
</table>

14
vendor/drush/drush/docs/io.md vendored Normal file
View file

@ -0,0 +1,14 @@
Input / Output
==============
- The Input object holds information about the request such option and argument values. You may need to this information when coding a hook implementation. You don't need this object in your command callback method since these values are passed as parameters.
- The Output object is rarely needed. Instead, return an object that gets formatted via the Output Formatter system. If you want to send additional output, use the io system (see below).
The io() system
====================
- If you need to ask the user a question, or print non-object content, use the io() system.
- A command callback gets access via `$this->io()`.
- The main methods for gathering user input are `$this->io->choice()` and `$this->io()->confirm`.
- You may use any of the methods described in the [Symfony Style docs](https://symfony.com/doc/current/console/style.html).

1
vendor/drush/drush/docs/repl.md vendored Normal file
View file

@ -0,0 +1 @@
You can then use an interactive PHP REPL with your bootstrapped site (remote or local). Its a Drupal code playground. You can do quick code experimentation, grab some data, or run Drush commands. This can also help with debugging certain issues. See [this blog post](http://blog.damiankloip.net/2015/drush-php) for an introduction. Run `help` for a list of commands.

View file

@ -0,0 +1,12 @@
Site Alias Manager
==================
The [Site Alias Manager (SAM)](https://github.com/consolidation/site-alias/blob/master/src/SiteAliasManager.php) service is used to retrieve information about one or all of the site aliases for the current installation.
- An informative example is the [browse command](https://github.com/drush-ops/drush/blob/master/src/Commands/core/BrowseCommands.php)
- A commandfile gets access to the SAM by implementing the SiteAliasManagerAwareInterface and *use*ing the SiteAliasManagerAwareTrait trait. Then you gain access via `$this->siteAliasManager()`.
- If an alias was used for the current request, it is available via $this->siteAliasManager()->getself().
- The SAM generally deals in [AliasRecord](https://github.com/consolidation/site-alias/blob/master/src/AliasRecord.php) objects. That is how any given site alias is represented. See its methods for determining things like whether the alias points to a local host or remote host.
- [An example site alias file](https://raw.githubusercontent.com/drush-ops/drush/master/examples/example.site.yml).
- [Dynamically alter site aliases](https://raw.githubusercontent.com/drush-ops/drush/master/examples/Commands/SiteAliasAlterCommands.php).
- The SAM is also available for as [a standalone Composer project](https://github.com/consolidation/site-alias). More information available in the README there.

40
vendor/drush/drush/docs/usage.md vendored Normal file
View file

@ -0,0 +1,40 @@
Usage
-----------
Drush can be run in your shell by typing "drush" from within your project root directory or anywhere within Drupal.
$ drush [options] <command> [argument1] [argument2]
Use the 'help' command to get a list of available options and commands:
$ drush help
For even more documentation, use the 'topic' command:
$ drush topic
Using the --uri option and --root options.
-----------
For multi-site installations, use a site alias or the --uri option to target a particular site.
$ drush --uri=http://example.com pm:enable
If you are outside the Composer project and not using a site alias, you need to specify --root and --uri for Drush to locate and bootstrap the right Drupal site.
Site Aliases
------------
Drush lets you run commands on a remote server. Once defined, aliases can be referenced with the @ nomenclature, i.e.
```bash
# Run pending updates on staging site.
$ drush @staging updatedb
# Synchronize staging files to production
$ drush rsync @staging:%files/ @live:%files
# Synchronize database from production to local, excluding the cache table
$ drush sql:sync --structure-tables-key=custom @live @self
```
See [example.site.yml](https://raw.githubusercontent.com/drush-ops/drush/master/examples/example.site.yml) for more information.

View file

@ -0,0 +1,13 @@
Drush Configuration
===================
Drush users may provide configuration via:
1. yml files that are placed in specific directories. [See our example file](https://raw.githubusercontent.com/drush-ops/drush/master/examples/example.drush.yml) for more information. You may also add configuration to a site alias - [see example site alias](https://raw.githubusercontent.com/drush-ops/drush/master/examples/example.site.yml).
1. Properly named environment variables are automatically used as configuration. To populate the options.uri config item, create an environment variable like so `DRUSH_OPTIONS_URI=http://example.com`. As you can see, variable names should be uppercased, prefixed with `DRUSH_`, and periods replaced with dashes.
If you are authoring a commandfile and wish to access the user's configuration, see [Command Authoring](commands.md).
The Drush configuration system has been factored out of Drush and shared with the world at [https://github.com/consolidation/config](https://github.com/consolidation/config). Feel free to use it for your projects. Lots more usage information is there.

5
vendor/drush/drush/dr.bat vendored Normal file
View file

@ -0,0 +1,5 @@
@ECHO OFF
REM Running this file is equivalent to running `php drush`
setlocal DISABLEDELAYEDEXPANSION
SET BIN_TARGET=%~dp0drush
php "%BIN_TARGET%" %*

4
vendor/drush/drush/drush vendored Executable file
View file

@ -0,0 +1,4 @@
#!/usr/bin/env php
<?php
require __DIR__ . '/drush.php';

1
vendor/drush/drush/drush.info vendored Normal file
View file

@ -0,0 +1 @@
drush_version=9.4.0

68
vendor/drush/drush/drush.php vendored Executable file
View file

@ -0,0 +1,68 @@
<?php
use Drush\Drush;
use Drush\Config\Environment;
use Drush\Preflight\Preflight;
use Drush\Runtime\Runtime;
use Webmozart\PathUtil\Path;
/**
* This script runs Drush.
*
* Responsibilities of this script:
* - Locate and include the Composer autoload file for Drush.
* - Set up the environment (record user home directory, cwd, etc.).
* - Call the Preflight object to do all necessary setup and execution.
* - Exit with status code returned
*
* It is our goal to put all $_SERVER access and other constructs that are
* difficult to test in this script to reduce the burden on the unit tests.
* This script will only be tested via the functional tests.
*
* The Drush bootstrap goes through the following steps:
* - (ArgsPreprocessor) Preprocess the commandline arguments, considering only:
* - The named alias `@sitealias` (removed from arguments if present)
* - The --root option (read and retained)
* - The --config option (read and retained)
* - The --alias-path option (read and retained)
* - Load the Drush configuration and alias files from the standard
* global locations (including --config and --alias-path)
* - Determine the local Drupal site targeted, if any
* - Include the Composer autoload for Drupal (if different)
* - Extend configuration and alias files to include files in target Drupal site.
* - Create the Robo DI container and Symfony Application et. al.
* - Run the Symfony Application
* - Predispatch: call a remote Drush command if applicable
* - Bootstrap Drupal via @bootstrap command hook
* - Run commands and command hooks via annotated commands library
* - Catch 'command not found' exception, bootstrap Drupal and run again
* - Return status code
*/
// We use PWD if available because getcwd() resolves symlinks, which
// could take us outside of the Drupal root, making it impossible to find.
$cwd = empty($_SERVER['PWD']) ? getcwd() : $_SERVER['PWD'];
// Set up autoloader
$loader = false;
if (file_exists($autoloadFile = __DIR__ . '/vendor/autoload.php')
|| file_exists($autoloadFile = __DIR__ . '/../autoload.php')
|| file_exists($autoloadFile = __DIR__ . '/../../autoload.php')
) {
$loader = include_once($autoloadFile);
} else {
throw new \Exception("Could not locate autoload.php. cwd is $cwd; __DIR__ is " . __DIR__);
}
// Set up environment
$environment = new Environment(Path::getHomeDirectory(), $cwd, $autoloadFile);
$environment->setConfigFileVariant(Drush::getMajorVersion());
$environment->setLoader($loader);
$environment->applyEnvironment();
// Preflight and run
$preflight = new Preflight($environment);
$runtime = new Runtime($preflight);
$status_code = $runtime->run($_SERVER['argv']);
exit($status_code);

4
vendor/drush/drush/drush.yml vendored Normal file
View file

@ -0,0 +1,4 @@
#This is a Drush config file. Sites may override this config to change minimum PHP.
drush:
php:
minimum-version: 5.6.0

BIN
vendor/drush/drush/drush_logo-black.png vendored Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 23 KiB

View file

@ -0,0 +1,184 @@
<?php
namespace Drush\Commands;
use Consolidation\AnnotatedCommand\AnnotationData;
use Consolidation\AnnotatedCommand\CommandData;
use Consolidation\AnnotatedCommand\Events\CustomEventAwareInterface;
use Consolidation\AnnotatedCommand\Events\CustomEventAwareTrait;
use Consolidation\OutputFormatters\StructuredData\RowsOfFields;
use Symfony\Component\Console\Input\InputInterface;
use Symfony\Component\Console\Output\OutputInterface;
use Symfony\Component\Console\Style\SymfonyStyle;
use Drush\Style\DrushStyle;
use Drush\Utils\StringUtils;
/**
* Run these commands using the --include option - e.g. `drush --include=/path/to/drush/examples art sandwich`
*
* For an example of a Drupal module implementing commands, see
* - http://cgit.drupalcode.org/devel/tree/devel_generate/src/Commands
* - http://cgit.drupalcode.org/devel/tree/devel_generate/drush.services.yml
*
* This file is a good example of the first of those bullets (a commandfile) but
* since it isn't part of a module, it does not implement drush.services.yml.
*/
class ArtCommands extends DrushCommands implements CustomEventAwareInterface
{
use CustomEventAwareTrait;
/** @var string[] */
protected $arts;
/**
* Show a fabulous picture.
*
* @command artwork:show
* @aliases arts
* @param $art The name of the art to display
* @usage drush art sandwich
* Show a marvelous picture of a sandwich with pickles.
*/
public function art($art = '')
{
$data = $this->getArt();
$name = $data[$art]['name'];
$description = $data[$art]['description'];
$path = $data[$art]['path'];
$msg = dt(
'Okay. Here is {art}: {description}',
['art' => $name, 'description' => $description]
);
$this->output()->writeln("\n" . $msg . "\n");
$this->printFile($path);
}
/**
* Show a table of information about available art.
*
* @command artwork:list
* @aliases artls
* @field-labels
* name: Name
* description: Description
* path: Path
* @default-fields name,description
*
* @return \Consolidation\OutputFormatters\StructuredData\RowsOfFields
*/
public function listArt($options = ['format' => 'table'])
{
$data = $this->getArt();
return new RowsOfFields($data);
}
/**
* Commandfiles may also add topics. These will appear in
* the list of topics when `drush topic` is executed.
* To view the topic below, run `drush --include=/full/path/to/examples topic`
*/
/**
* Ruminations on the true meaning and philosophy of artwork.
*
* @command artwork:explain
* @hidden
* @topic
*/
public function ruminate()
{
self::printFile(__DIR__ . '/art-topic.md');
}
/**
* Return the available built-in art. Any Drush commandfile may provide
* more art by implementing a 'drush-art' on-event hook. This on-event
* hook is defined in the 'findArt' method beolw.
*
* @hook on-event drush-art
*/
public function builtInArt()
{
return [
'drush' => [
'name' => 'Drush',
'description' => 'The Drush logo.',
'path' => __DIR__ . '/art/drush-nocolor.txt',
],
'sandwich' => [
'name' => 'Sandwich',
'description' => 'A tasty meal with bread often consumed at lunchtime.',
'path' => __DIR__ . '/art/sandwich-nocolor.txt',
],
];
}
/**
* @hook interact artwork:show
*/
public function interact(InputInterface $input, OutputInterface $output, AnnotationData $annotationData)
{
$io = new DrushStyle($input, $output);
// If the user did not specify any artwork, then prompt for one.
$art = $input->getArgument('art');
if (empty($art)) {
$data = $this->getArt();
$selections = $this->convertArtListToKeyValue($data);
$selection = $io->choice('Select art to display', $selections);
$input->setArgument('art', $selection);
}
}
/**
* @hook validate artwork:show
*/
public function artValidate(CommandData $commandData)
{
$art = $commandData->input()->getArgument('art');
$data = $this->getArt();
if (!isset($data[$art])) {
throw new \Exception(dt('I do not have any art called "{name}".', ['name' => $art]));
}
}
/**
* Get a list of available artwork. Cache result for future fast access.
*/
protected function getArt()
{
if (!isset($this->arts)) {
$this->arts = $this->findArt();
}
return $this->arts;
}
/**
* Use custom defined on-event hook 'drush-art' to find available artwork.
*/
protected function findArt()
{
$arts = [];
$handlers = $this->getCustomEventHandlers('drush-art');
foreach ($handlers as $handler) {
$handlerResult = $handler();
$arts = array_merge($arts, $handlerResult);
}
return $arts;
}
/**
* Given a list of artwork, converte to a 'key' => 'Name: Description' array.
* @param array $data
* @return array
*/
protected function convertArtListToKeyValue($data)
{
$result = [];
foreach ($data as $key => $item) {
$result[$key] = $item['name'] . ': ' . $item['description'];
}
return $result;
}
}

View file

@ -0,0 +1,60 @@
<?php
namespace Drush\Commands;
use Consolidation\AnnotatedCommand\CommandData;
use Drush\Commands\DrushCommands;
use Symfony\Component\Console\Input\InputOption;
/**
* Load this commandfile using the --include option - e.g. `drush --include=/path/to/drush/examples`
*/
class PolicyCommands extends DrushCommands
{
/**
* Prevent catastrophic braino. Note that this file has to be local to the
* machine that initiates the sql:sync command.
*
* hook validate sql:sync
* @throws \Exception
*/
public function sqlSyncValidate(CommandData $commandData)
{
if ($commandData->input()->getArgument('destination') == '@prod') {
throw new \Exception(dt('Per !file, you may never overwrite the production database.', ['!file' => __FILE__]));
}
}
/**
* Limit rsync operations to production site.
*
* hook validate core:rsync
*/
public function rsyncValidate(CommandData $commandData)
{
if (preg_match("/^@prod/", $commandData->input()->getArgument('destination'))) {
throw new \Exception(dt('Per !file, you may never rsync to the production site.', ['!file' => __FILE__]));
}
}
/**
* Unauthorized may not execute updates.
*
* @hook validate updatedb
*/
public function validateUpdateDb(CommandData $commandData)
{
if (!$commandData->input()->getOption('secret') == 'mysecret') {
throw new \Exception(dt('UpdateDb command requires a secret token per site policy.'));
}
}
/**
* @hook option updatedb
* @option secret A required token else user may not run updatedb command.
*/
public function optionsetUpdateDb($options = ['secret' => self::REQ])
{
}
}

View file

@ -0,0 +1,39 @@
<?php
namespace Drush\Commands;
use Consolidation\AnnotatedCommand\AnnotationData;
use Consolidation\SiteAlias\SiteAliasManagerAwareInterface;
use Consolidation\SiteAlias\SiteAliasManagerAwareTrait;
use Symfony\Component\Console\Input\InputInterface;
/**
* Load this example by using the --include option - e.g. `drush --include=/path/to/drush/examples`
*/
class SiteAliasAlterCommands extends DrushCommands implements SiteAliasManagerAwareInterface
{
use SiteAliasManagerAwareTrait;
/**
* A few example alterations to site aliases.
*
* @hook pre-init *
*
* @param \Symfony\Component\Console\Input\InputInterface $input
* @param \Consolidation\AnnotatedCommand\AnnotationData $annotationData
*/
public function alter(InputInterface $input, AnnotationData $annotationData)
{
$self = $this->siteAliasManager()->getSelf();
if ($self->isRemote()) {
// Always pass along ssh keys.
if (!$self->has('ssh.options')) {
// Don't edit the alias - edit the general config service instead.
$this->getConfig()->set('ssh.options', '-o ForwardAgent=yes');
}
// Change the SSH user.
$input->setOption('remote-user', 'mw2');
}
}
}

View file

@ -0,0 +1,96 @@
<?php
namespace Drush\Commands;
use Consolidation\AnnotatedCommand\CommandData;
use Drush\Commands\DrushCommands;
use Drush\Drush;
use Symfony\Component\Filesystem\Filesystem;
/**
* Load this commandfile using the --include option - e.g. `drush --include=/path/to/drush/examples`
*/
class SyncViaHttpCommands extends DrushCommands
{
/**
* When a hook extends a command with additional options, it must
* implement declare those option(s) in a @hook option like this one. Doing so will add
* the option to the help text for the modified command, and will also
* allow the new option to be specified on the command line. Without
* this, Drush will fail with an error when a user attempts to use
* an unknown option.
*
* @hook option sql-sync
* @option http-sync Copy the database via http instead of rsync. Value is the url that the existing database dump can be found at.
* @option http-sync-user Username for the protected directory containing the sql dump.
* @option http-sync-password Password for the same directory.
*/
public function optionsetSqlSync()
{
}
/**
* During the pre hook, determine if the http-sync option has been
* specified. If it has been, then disable the normal ssh + rsync
* dump-and-transfer that sql-sync usually does, and transfer the
* database dump via an http download.
*
* @hook pre-command sql-sync
*/
public function preSqlSync(CommandData $commandData)
{
$sql_dump_download_url = $commandData->input()->getOption('http-sync');
if (!empty($sql_dump_download_url)) {
$user = $commandData->input()->getOption('http-sync-user');
$password = $commandData->input()->getOption('http-sync-password');
$source_dump_file = $this->downloadFile($sql_dump_download_url, $user, $password);
$commandData->input()->setOption('target-dump', $source_dump_file);
$commandData->input()->setOption('no-dump', true);
$commandData->input()->setOption('no-sync', true);
}
}
/**
* Downloads a file.
*
* Optionally uses user authentication, using either wget or curl, as available.
*/
protected function downloadFile($url, $user = false, $password = false, $destination = false, $overwrite = true)
{
static $use_wget;
if ($use_wget === null) {
$use_wget = drush_shell_exec('which wget');
}
$destination_tmp = drush_tempnam('download_file');
if ($use_wget) {
if ($user && $password) {
drush_shell_exec("wget -q --timeout=30 --user=%s --password=%s -O %s %s", $user, $password, $destination_tmp, $url);
} else {
drush_shell_exec("wget -q --timeout=30 -O %s %s", $destination_tmp, $url);
}
} else {
if ($user && $password) {
drush_shell_exec("curl -s -L --connect-timeout 30 --user %s:%s -o %s %s", $user, $password, $destination_tmp, $url);
} else {
drush_shell_exec("curl -s -L --connect-timeout 30 -o %s %s", $destination_tmp, $url);
}
}
if (!Drush::simulate()) {
if (!drush_file_not_empty($destination_tmp) && $file = @file_get_contents($url)) {
@file_put_contents($destination_tmp, $file);
}
if (!drush_file_not_empty($destination_tmp)) {
// Download failed.
throw new \Exception(dt("The URL !url could not be downloaded.", ['!url' => $url]));
}
}
if ($destination) {
$fs = new Filesystem();
$fs->rename($destination_tmp, $destination, $overwrite);
return $destination;
}
return $destination_tmp;
}
}

View file

@ -0,0 +1,55 @@
<?php
namespace Drush\Commands;
use Drush\Exec\ExecTrait;
/**
* Run these commands using the --include option - e.g. `drush --include=/path/to/drush/examples xkcd`
*/
class XkcdCommands extends DrushCommands
{
use ExecTrait;
/**
* Retrieve and display xkcd cartoons.
*
* @command xkcd:fetch
* @param $search Optional argument to retrieve the cartoons matching an index number, keyword search or "random". If omitted the latest cartoon will be retrieved.
* @option image-viewer Command to use to view images (e.g. xv, firefox). Defaults to "display" (from ImageMagick).
* @option google-custom-search-api-key Google Custom Search API Key, available from https://code.google.com/apis/console/. Default key limited to 100 queries/day globally.
* @usage drush xkcd
* Retrieve and display the latest cartoon.
* @usage drush xkcd sandwich
* Retrieve and display cartoons about sandwiches.
* @usage drush xkcd 123 --image-viewer=eog
* Retrieve and display cartoon #123 in eog.
* @usage drush xkcd random --image-viewer=firefox
* Retrieve and display a random cartoon in Firefox.
* @aliases xkcd
*/
public function fetch($search = null, $options = ['image-viewer' => 'open', 'google-custom-search-api-key' => 'AIzaSyDpE01VDNNT73s6CEeJRdSg5jukoG244ek'])
{
if (empty($search)) {
$this->startBrowser('http://xkcd.com');
} elseif (is_numeric($search)) {
$this->startBrowser('http://xkcd.com/' . $search);
} elseif ($search == 'random') {
$xkcd_response = @json_decode(file_get_contents('http://xkcd.com/info.0.json'));
if (!empty($xkcd_response->num)) {
$this->startBrowser('http://xkcd.com/' . rand(1, $xkcd_response->num));
}
} else {
// This uses an API key with a limited number of searches per.
$search_response = @json_decode(file_get_contents('https://www.googleapis.com/customsearch/v1?key=' . $options['google-custom-search-api-key'] . '&cx=012652707207066138651:zudjtuwe28q&q=' . $search));
if (!empty($search_response->items)) {
foreach ($search_response->items as $item) {
$this->startBrowser($item->link);
}
} else {
throw new \Exception(dt('The search failed or produced no results.'));
}
}
}
}

View file

@ -0,0 +1,6 @@
I have discovered a truly marvelous proof that it is impossible to
separate a piece of art into two cubes, or four pieces of art into two
fourth of a piece of art, or in general, any artwork larger than the
second into two like artistic expressions.
This text file is too narrow to contain it.

View file

@ -0,0 +1,73 @@
.`
`++++++++++
,'',+++#####++
;;,,,,++#######+
',,,,,++#######+
',,,,,++#######+:
;,,,,:+########++
:,,,,'+########++ .
.,,,,,++########++ ,'''';+++.
,'+++. ;,,,,,++#########+ `',,,,,++#++:
',++++++ ',,,,,++#########+; :;,,,,;++###++;
',+++##+++` ';''++++#########+++++,,,,,+++#####++;
',+++#####++'`'',;++++##############++++,,+++#######++.
',;++#######+++,:+++'##################+++++##########++
',,++#########'++++'#######################+###########++
';'+++###########++####################################++
':::++#################################################+;
':::++###############################################++
::::;++#############################################++
':::+++############################################+'
':::++###########################################++
`;:::++##########################################+`
':::;++#########################################++
''''++##########################################+:
,,,,'+###########################################++
',,.++############################################+,
`:,,;+#############################################++
',,,++##############################################+
',,,++##############################################++;.
:,,,'+###############################################+++++++++:
`;';,,++#####################################################++++'
.'';,,,,,+++########################################################++
;';,,,,;++++++#########################################################++
;,;++++++++#############################################################+
,,,+++#################################################################++
.,,++###################################################################+
.,,++#################################################################@#+
.:,++############################,` .##################################++
`:,++########################## ################ #######+++++++
;,++########################: .############ ###++++++.
',++#######################; ########## ###+:
'++++##################### :###### :##+
:++++++++++#############` ###: .#++
,+++++############ :#++
',,;+############ ##+,
;,,++########### `###, ##+
'::++########### ######' #++
;:;+########### ########## ##+`
'::++########### :###' `#### #++
.':;+############ .#### #### ###++
',':++############; ###### ##### #####.,#####+,
',,,:'++####################### ######.###########@++
:,,,,,++#########################################@@@++
',,,,,'+#########################################@@@@#+;
:,,,,,,++################### `########+ #######@@@@@@++`
',,,,,++##################### #######@@@@@@@@++
',,,,,'+#######################+ ;######+#@@@@@@@@@++
',,,,++####################################+++++@@@@@@@++
',,++####################################++;:'++#@@@@#+;
''+###########+++#####################+++ '':+++@@#++
++#########+++:++++###############++++ ,'+++#++
.++#######+++ ,++++++##########+++ `'+++
.++#####++: ':;++++#########+; .
`++###++ ;::::,++#######@+,
+++++ ::::,++#####@@#+
++' ;:::,++##@@@@@#+
'::::;+@@@@@@@++
'::::,+#@@@@@@++
,'::,+#@@@@@@++
':,++@@@@@@+;
':++@##++++.

View file

@ -0,0 +1,34 @@
::::::::::::::::::::::::::::::::::MMMMMMMMMMMM:::::::::::::::::::::::::::::::::
:::::::::::::::::::::::::MMMMMMMM:::::::::::MM:::::::::::::::::::::::::::::::::
:::::::::::::::::::MMMMM::::::::::::::::::::MMMM:::::::::::::::::::::::::::::::
::::::::::::::MMMMM:::::::::M::::::::M::::::::::MMMM:::::::::::::::::::::::::::
::::::::::MMMM::M:::::::::::::::::::::::::::::::::::MMMM:::::::::::::::::::::::
:::::::MMM::::::::::::::::::::::::::::::::::::::::::::::MMMM:::::::::::::::::::
:::::MM:::::::::::::::::::::::::::::::::::::::::::::::::::::MMMM:::::::::::::::
:::::M::::::::::::::::::::::::::::::::::::::::::::::::::::::::::MMM::::::::::::
:::::MMM$MM::::::::::::::::::::::::::::::::::::::::::::::::::::::::MMM:::::::::
:::::M$$$$$MM:::::::::::::::::::::::::::::::::::::::::::::M::::::::::MMM:::::::
::MMMMM$M$$$$MM:::::::::M:::::::::::::::::::::::::::::::::::::::::::MMMMM::::::
::MIIIMMMM$M$$$MM:::::::::::::::::::::::::::::::::::::::::::MMMMMMM$$$$M:::::::
:::MIIIIIIMM$$$$$MM::::::::::::::M:::::::::::::::::::MMMMMMM$$$$$$$$$$$$:::::::
:MMIIIIIIIIMM$$$$$$MMM::::::::::::::::::::::::MMMMMM$$$$$$$$$$$$$$$$$$$$M::::::
MIIMMMMMIIIIIMMM$$$$$$MM:::::::::::::::MMMMMM$$$$$$$$$$$$$$$$$$$$$$$$$$$M::::::
MMM:MM:MMMMIIIIMMM$$$$$$MM:::::::MMMMMMM$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$MMMMM::
::M::::MM::IIIIIIMM$$$$$$$$MMMMM$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$MMMMMMMMMIIM:::
::MM:::M::MIIMMIIIIIM$M$$$$M$$$$$$$$$$$$$$$$$$$$$$$$$$$$MMMMMMMIIIIIMMMMMMM::::
::::MM::MMMMM:MIIIIIIMM$M$$M$$$$$$$$$$$$$$$$$$$$$$MMMMMMMIIIIIIIIIIIM::MMM:::::
::::::$MM:::::MIIIMMIIIMM$M$$$$$$$$$$$$$$$$MMMMMMIMMMIIIIM:::MMMIIIIM:::::MM:::
::::::$$$MM:::::M::MIIIMMMM$M$$$$$$$MMMMMMIIIIIIMMM:MMMMM:::::::::::::MMMMMM:::
::::::M$$$$MM:MMM::MMM:::MIMMMMMMMMMMIIMMIIIIIIIMM+M:::::MMMM::::MMMMM$M:::::::
::::::MM$M$$$M+$$M::::::MIIIIIIIMIIIIM::::MIIIIIM:MM::::M$$M+MM$$$$$$$$::::::::
:::::::MMM$$$$$$$M:::::::MIIIIIM::MMM:::::::MMMM::::::::M$$M$$$$$$$$$$$M:::::::
::::::::::MM$$$$$$$MM::::MMMMMM:::::::::::::::::::MMMMMMM$$$$$$$$$$$$$$M:::::::
::::::::::::MM$M$$$$$MM:MM$$$$M::::::::::MMMMMMM$$$$$$$$$$$$$$$$$$MMMMM::::::::
::::::::::::::MMM$M$$$$MM$$$$$M:MMMMMMM$$$$$$$$$$$$$$$$$$$$$MMMMMM:::::::::::::
:::::::::::::::::MMM$M$M$$$$$$MMM$$$$$$$$$$$$$$$$$$$$$$MMMMM:M:M:::::::::::::::
:::::::::::::::::::MMMM$$M$$$$$$M$$$$$$$$$$$$$$$$$MMMMMM::::::M::::::::::::::::
::::::::::::::::::::::MMMMM$$$$$M$$$$$$$$$$$$$MMMMM::::::::::::::::::::::::::::
:::::::::::::::::::::::::MMMM$M$M$$$$$$$$$MMMMM::::::::::::::::::::::::::::::::
::::::::::::::::::::::::::::MMMMM$$$$MMMM::::::::::::::::::::::::::::::::::::::
:::::::::::::::::::::::::::::::MMMMM:::::::::::::::::::::::::::::::::::::::::::
:::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::

View file

@ -0,0 +1,24 @@
 . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .
 . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .
 . . . . . . . . . . .:8 ;t;;t;;;;:..:;%SX888@X%t;.. . . . 
 . . .. . . . . . .%t%;%@%%%%%%%%%%X@8888XS%t;...:;ttt%X. .
 . . . . . . . . .X:8%X%%%XS%%%%%%%XS%%%%%@%%%%X%%%@%S88 . 
 . . . . . . . . X@ @%%%X8X%%%88%%%8X%%%%%%%%%XXt@8@88@. .
 . . . . . . . .t@tS;%%8XSX%@XSX%@XSS%8@@88X@888X8SS S;S. 
 . . . . . . .@%XS%%%%%S8@X%@8%XXSSXX%S@SSSX888.;@ 888@ . . 
 . . . . . :.8:S%%%XS8X@@X%S@SSSS8SXSXXX%X88X:;@8@:S  88S. .
 . . . .8%S8%%%%%%8@SSSXXXSXSXSXSXSSS8S888 :@%:%XX:%8%:X: 
 . . .:8 %%%%@%%8@S%%XXSXSSSS8S@X%XSXX88 ;@X;SX88X8;%X88t. 
 . . 88S%S%%%%8XSSXSX@@S@%XS8@SS%@S%888 88@S:8. .;.@%X:@8;. 
 . .  88.8888888@XX 888888%X%@XX 88SS8@@;S@8.%;8@S%%:8  .
 . .  S%:8 @SSSS8 @@8@8 8 88888888@%S:8:S8 @..%S SXX8888;. .
 . . %:8S8888@88SXS S S::X@.8.8 X%S%8X:X88..% @@.S.%% .;. . 
 . .XX8@8;;%%t;;;;:@X@888888@888888.88S;8:8  ... . . .
 . . 8.;;@8@8:%%%%%t.8@%ttX@8@@@S8%8 X8S;X:@; :... . . . . .
 . tS:8@;88.;:8888X8S:.tX88888X88  S8tStS88 :.. . . . . . . 
 .:X;;:t%;tt%888S@8XS888@8.:tt@;88.tXXX8:::... . . . . . . .
 .:X8St:8SXS XS8@X 8.8%888%X8@@X88tXS8t; . . . . . . . . . 
 . :8888.88888888X@@X @ X X%S%;88;8t .. . . . . . . . .
 ... ..: . .@@888%St @ @ 8SS 8:; . . . . . . . . . . .
 . . . ..::. ..:;;::::. ... . . . . . . . . . . . .
 .. . . . . .. . . . . .. . . . . . . . . . . . . . 

View file

@ -0,0 +1,239 @@
# -*- mode: shell-script; mode: flyspell-prog; ispell-local-dictionary: "american" -*-
#
# Example bash aliases to improve your Drush experience with bash.
# Use `drush init` to copy this file to your home directory, rename and
# customize it to suit, and source it from your ~/.bashrc file.
#
# Creates aliases to common Drush commands that work in a global context:
#
# dr - drush
# ddd - drush drupal-directory
# ev - drush php-eval
# sa - drush site-alias
# sa - drush site-alias --local-only (show local site aliases)
# st - drush core-status
# use - drush site-set
#
# Aliases for Drush commands that work on the current drupal site:
#
# cr - drush cache-rebuild
# en - drush pm-enable
# pml - drush pm-list
# unin - drush pm-uninstall
# updb - drush updatedb
# q - drush sql-query
#
# Provides several common shell commands to work better with Drush:
#
# ddd @dev - print the path to the root directory of @dev
# cdd @dev - change the current working directory to @dev
# lsd @dev - ls root folder of @dev
# lsd %files - ls "files" directory of current site
# lsd @dev:%devel - ls devel module directory in @dev
# @dev st - drush @dev core-status
# dssh @live - ssh to the remote server @live points at
# gitd @live pull - run `git pull` on the drupal root of @live
#
# Drush site alias expansion is also done for the cpd command:
#
# cpd -R @site1:%files @site2:%files
#
# Note that the 'cpd' alias only works for local sites. Use
# `drush rsync` or gitd` to move files between remote sites.
#
# Aliases are also possible for the following standard
# commands. Uncomment their definitions below as desired.
#
# cd - cddl [*]
# ls - lsd
# cp - cpd
# ssh - dssh
# git - gitd
#
# These standard commands behave exactly the same as they always
# do, unless a Drush site specification such as @dev or @live:%files
# is used in one of the arguments.
# Aliases for common Drush commands that work in a global context.
alias dr='drush'
alias ddd='drush drupal:directory'
alias ev='drush php:eval'
alias sa='drush site:alias'
alias st='drush core:status'
alias use='drush site:set'
# Aliases for Drush commands that work on the current drupal site
alias cr='drush cache:rebuild'
alias en='drush pm:enable'
alias pml='drush pm:list'
alias unin='drush pm:uninstall'
alias updb='drush updatedb'
alias q='drush sql:query'
# Overrides for standard shell commands. Uncomment to enable. Alias
# cd='cdd' if you want to be able to use cd @remote to ssh to a
# remote site.
# alias cd='cddl'
# alias ls='lsd'
# alias cp='cpd'
# alias ssh='dssh'
# alias git='gitd'
# We extend the cd command to allow convenient
# shorthand notations, such as:
# cd @site1
# cd %modules
# cd %devel
# cd @site2:%files
# You must use 'cddl' instead of 'cd' if you are not using
# the optional 'cd' alias from above.
# This is the "local-only" version of the function;
# see the cdd function, below, for an expanded implementation
# that will ssh to the remote server when a remote site
# specification is used.
function cddl() {
fastcddl "$1"
use @self
}
# Use this function instead of 'cddl' if you have a very large number
# of alias files, and the 'cddl' function is getting too slow as a result.
# This function does not automatically set your prompt to the site that
# you 'cd' to, as 'cddl' does.
function fastcddl() {
s="$1"
if [ -z "$s" ]
then
builtin cd
elif [ "${s:0:1}" == "@" ] || [ "${s:0:1}" == "%" ]
then
d="$(drush drupal:directory $1 --local-only 2>/dev/null)"
if [ $? == 0 ]
then
echo "cd $d";
builtin cd "$d";
else
t="$(drush site-alias $1 >/dev/null 2>/dev/null)"
if [ $? == 0 ]
then
echo "Cannot cd to remote site $s"
else
echo "Cannot cd to $s"
fi
fi
else
builtin cd "$s";
fi
}
# Works just like the `cddl` shell alias above, with one additional
# feature: `cdd @remote-site` works like `ssh @remote-site`,
# whereas cd above will fail unless the site alias is local. If
# you prefer this behavior, you can add `alias cd='cdd'` to your .bashrc
function cdd() {
s="$1"
if [ -z "$s" ]
then
builtin cd
elif [ "${s:0:1}" == "@" ] || [ "${s:0:1}" == "%" ]
then
d="$(drush drupal:directory $s 2>/dev/null)"
rh="$(drush sa ${s%%:*} --fields=host --format=list)"
if [ -z "$rh" ]
then
echo "cd $d"
builtin cd "$d"
else
if [ -n "$d" ]
then
c="cd \"$d\" \; bash"
drush -s ${s%%:*} ssh --tty
drush ${s%%:*} ssh --tty
else
drush ssh ${s%%:*}
fi
fi
else
builtin cd "$s"
fi
}
# Allow `git @site gitcommand` as a shortcut for `cd @site; git gitcommand`.
# Also works on remote sites, though.
function gitd() {
s="$1"
if [ -n "$s" ] && [ ${s:0:1} == "@" ] || [ ${s:0:1} == "%" ]
then
d="$(drush drupal-directory $s 2>/dev/null)"
rh="$(drush sa ${s%%:*} --fields=host --format=list)"
if [ -n "$rh" ]
then
drush ${s%%:*} ssh "cd '$d' ; git ${@:2}"
else
echo cd "$d" \; git "${@:2}"
(
cd "$d"
"git" "${@:2}"
)
fi
else
"git" "$@"
fi
}
# Get a directory listing on @site or @site:%files, etc, for local or remote sites.
function lsd() {
p=()
r=
for a in "$@" ; do
if [ ${a:0:1} == "@" ] || [ ${a:0:1} == "%" ]
then
p[${#p[@]}]="$(drush drupal:directory $a 2>/dev/null)"
if [ ${a:0:1} == "@" ]
then
rh="$(drush sa ${a%:*} --fields=host --format=list)"
if [ -n "$rh" ]
then
r=${a%:*}
fi
fi
elif [ -n "$a" ]
then
p[${#p[@]}]="$a"
fi
done
if [ -n "$r" ]
then
drush $r ssh 'ls "${p[@]}"'
else
"ls" "${p[@]}"
fi
}
# Copy files from or to @site or @site:%files, etc; local sites only.
function cpd() {
p=()
for a in "$@" ; do
if [ ${a:0:1} == "@" ] || [ ${a:0:1} == "%" ]
then
p[${#p[@]}]="$(drush drupal:directory $a --local-only 2>/dev/null)"
elif [ -n "$a" ]
then
p[${#p[@]}]="$a"
fi
done
"cp" "${p[@]}"
}
# This alias allows `dssh @site` to work like `drush @site ssh`.
# Ssh commands, such as `dssh @site ls /tmp`, are also supported.
function dssh() {
d="$1"
if [ ${d:0:1} == "@" ]
then
drush "$d" ssh "${@:2}"
else
"ssh" "$@"
fi
}

View file

@ -0,0 +1,165 @@
#
# Examples of valid statements for a Drush runtime config (drush.yml) file.
#
# Use this file to cut down on typing out lengthy and repetitive command line
# options in the Drush commands you use and to avoid mistakes.
#
# The Drush configuration system has been factored out and shared with
# the world at https://github.com/consolidation/config. Feel free to use it
# for your projects. Lots more usage information is there.
# Directories and Discovery
#
# Rename this file to drush.yml and copy it to one of the places listed below
# in order of precedence:
#
# 1. Drupal site folder (e.g. sites/{default|example.com}/drush.yml).
# 2. Drupal /drush and sites/all/drush folders, or the /drush folder
# in the directory above the Drupal root.
# 3. In any location, as specified by the --config (-c) option.
# 4. User's .drush folder (i.e. ~/.drush/drush.yml).
# 5. System wide configuration folder (e.g. /etc/drush/drush.yml or C:\ProgramData\Drush\drush.yml).
#
# If a configuration file is found in any of the above locations, it will be
# loaded and merged with other configuration files in the search list.
#
# Version-specific configuration
#
# Drush started using yml files for configuration in version 9; earlier versions
# of Drush will never attempt to load a drush.yml file. It is also possible
# to limit the version of Drush that will load a configuration file by placing
# the Drush major version number in the filename, e.g. drush9.yml.
# Environment variables
#
# Your Drush config file may reference environment variables using a syntax like ${env.home}.
# For example see the drush.paths examples below.
#
# An alternative way to populate Drush configuration is to define environment variables that
# correspond to config keys. For example, to populate the options.uri config item,
# create an environment variable `DRUSH_OPTIONS_URI=http://example.com`.
# As you can see, variable names should be uppercased, prefixed with `DRUSH_`, and periods
# replaced with dashes.
drush:
paths:
# Specify config files to load.
config:
# Load any personal config files. Is silently skipped if not found. Filename must be drush.yml
- ${env.home}/.drush/config/drush.yml
# Specify folders to search for Drush command files. These locations
# are always merged with include paths defined on the command line or
# in other configuration files. On the command line, paths may be separated
# by a colon (:) on Unix-based systems or a semi-colon (;) on Windows,
# or multiple --include options may be provided. Drush 8 and earlier did
# a deep search in ~/.drush and /usr/share/drush/commands when loading
# command files.
include:
- '${env.home}/.drush/commands'
- /usr/share/drush/commands
# Specify the folders to search for Drush alias files (*.site.yml). These
# locations are always merged with alias paths defined on the command line
# or in other configuration files. On the command line, paths may be
# separated by a colon (:) on Unix-based systems or a semi-colon (;) on
# Windows, or multiple --alias-path options may be provided. Note that
# Drush 8 and earlier did a deep search in ~/.drush and /etc/drush when
# loading alias files.
alias-path:
- '${env.home}/.drush/sites'
- /etc/drush/sites
# Specify a folder where Drush should store its file based caches. If unspecified, defaults to $HOME/.drush.
cache-directory: /tmp/.drush
# This section is for setting global options.
options:
# Specify the base_url that should be used when generating links.
# Not recommended if you have more than one Drupal site on your system.
uri: 'http://example.com/subdir'
# Specify your Drupal core base directory (useful if you use symlinks).
# Not recommended if you have more than one Drupal root on your system.
root: '/home/USER/workspace/drupal-6'
# Enable verbose mode.
verbose: true
# This section is for setting command-specific options.
command:
sql:
dump:
options:
# Uncomment to omit cache and similar tables (including during a sql:sync).
# structure-tables-key: common
php:
script:
options:
# Additional folders to search for scripts.
# script-path: 'sites/all/scripts:profiles/myprofile/scripts'
core:
rsync:
options:
# Ensure all rsync commands use verbose output.
# verbose: true
site:
install:
options:
# Set a predetermined username and password when using site-install.
# account-name: 'alice'
# account-pass: 'secret'
#
# The sections below are configuration thats consulted by various commands, outside
# of the option system.
#
sql:
# An explicit list of tables which should be included in sql-dump and sql-sync.
tables:
common:
- user
- permissions
- role_permissions
- role
# List of tables whose *data* is skipped by the 'sql-dump' and 'sql-sync'
# commands when the "--structure-tables-key=common" option is provided.
# You may add specific tables to the existing array or add a new element.
structure-tables:
common:
- cache
- 'cache_*'
- history
- 'search_*'
- 'sessions'
- 'watchdog'
# List of tables to be omitted entirely from SQL dumps made by the 'sql-dump'
# and 'sql-sync' commands when the "--skip-tables-key=common" option is
# provided on the command line. This is useful if your database contains
# non-Drupal tables used by some other application or during a migration for
# example. You may add new tables to the existing array or add a new element.
skip-tables:
common:
- 'migration_*'
ssh:
# Specify options to pass to ssh in backend invoke. The default is to prohibit
# password authentication, and is included here, so you may add additional
# parameters without losing the default configuration.
options: '-o PasswordAuthentication=no'
notify:
# Notify when command takes more than 30 seconds.
duration: 30
# Specify a command to run. Defaults to Notification Center (OSX) or libnotify (Linux)
# cmd: /path/to/program
# See src/Commands/core/NotifyCommands.php for more configuration settings.
xh:
# Start profiling via xhprof/tideways and show a link to the run report.
# link: http://xhprof.local
# See src/Commands/core/XhprofCommands.php for more configuration settings.

View file

@ -0,0 +1,100 @@
# -*- mode: shell-script; mode: flyspell-prog; ispell-local-dictionary: "american" -*-
#
# Example PS1 prompt.
#
# Use `drush init` to copy this to ~/.drush/drush.prompt.sh, and source it in
# ~/.bashrc or ~/.bash_profile.
#
# Note that your Bash session must already have the __git_ps1 function available.
# Typically this is provided by git-prompt.sh, see instructions for downloading
# and including this file here:
# https://github.com/git/git/blob/master/contrib/completion/git-prompt.sh
#
# Features:
#
# Displays Git repository and Drush alias status in your prompt.
__drush_ps1() {
f="${TMPDIR:-/tmp/}/drush-env-${USER}/drush-drupal-site-$$"
if [ -f $f ]
then
__DRUPAL_SITE=$(cat "$f")
else
__DRUPAL_SITE="$DRUPAL_SITE"
fi
# Set DRUSH_PS1_SHOWCOLORHINTS to a non-empty value and define a
# __drush_ps1_colorize_alias() function for color hints in your Drush PS1
# prompt. See example.prompt.sh for an example implementation.
if [ -n "${__DRUPAL_SITE-}" ] && [ -n "${DRUSH_PS1_SHOWCOLORHINTS-}" ]; then
__drush_ps1_colorize_alias
fi
[[ -n "$__DRUPAL_SITE" ]] && printf "${1:- (%s)}" "$__DRUPAL_SITE"
}
if [ -n "$(type -t __git_ps1)" ] && [ "$(type -t __git_ps1)" = function ] && [ "$(type -t __drush_ps1)" ] && [ "$(type -t __drush_ps1)" = function ]; then
# This line enables color hints in your Drush prompt. Modify the below
# __drush_ps1_colorize_alias() to customize your color theme.
DRUSH_PS1_SHOWCOLORHINTS=true
# Git offers various prompt customization options as well as seen in
# https://github.com/git/git/blob/master/contrib/completion/git-prompt.sh.
# Adjust the following lines to enable the corresponding features:
#
GIT_PS1_SHOWDIRTYSTATE=true
GIT_PS1_SHOWUPSTREAM=auto
# GIT_PS1_SHOWSTASHSTATE=true
# GIT_PS1_SHOWUNTRACKEDFILES=true
GIT_PS1_SHOWCOLORHINTS=true
# The following line sets your bash prompt according to this example:
#
# username@hostname ~/working-directory (git-branch)[@drush-alias] $
#
# See http://ss64.com/bash/syntax-prompt.html for customization options.
export PROMPT_COMMAND='__git_ps1 "\u@\h \w" "$(__drush_ps1 "[%s]") \\\$ "'
# PROMPT_COMMAND is used in the example above rather than PS1 because neither
# Git nor Drush color hints are compatible with PS1. If you don't want color
# hints, however, and prefer to use PS1, you can still do so by commenting out
# the PROMPT_COMMAND line above and uncommenting the PS1 line below:
#
# export PS1='\u@\h \w$(__git_ps1 " (%s)")$(__drush_ps1 "[%s]")\$ '
__drush_ps1_colorize_alias() {
if [[ -n ${ZSH_VERSION-} ]]; then
local COLOR_BLUE='%F{blue}'
local COLOR_CYAN='%F{cyan}'
local COLOR_GREEN='%F{green}'
local COLOR_MAGENTA='%F{magenta}'
local COLOR_RED='%F{red}'
local COLOR_WHITE='%F{white}'
local COLOR_YELLOW='%F{yellow}'
local COLOR_NONE='%f'
else
# Using \[ and \] around colors is necessary to prevent issues with
# command line editing/browsing/completion.
local COLOR_BLUE='\[\e[94m\]'
local COLOR_CYAN='\[\e[36m\]'
local COLOR_GREEN='\[\e[32m\]'
local COLOR_MAGENTA='\[\e[35m\]'
local COLOR_RED='\[\e[91m\]'
local COLOR_WHITE='\[\e[37m\]'
local COLOR_YELLOW='\[\e[93m\]'
local COLOR_NONE='\[\e[0m\]'
fi
# Customize your color theme below.
case "$__DRUPAL_SITE" in
*.live|*.prod) local ENV_COLOR="$COLOR_RED" ;;
*.stage|*.test) local ENV_COLOR="$COLOR_YELLOW" ;;
*.local) local ENV_COLOR="$COLOR_GREEN" ;;
*) local ENV_COLOR="$COLOR_BLUE" ;;
esac
__DRUPAL_SITE="${ENV_COLOR}${__DRUPAL_SITE}${COLOR_NONE}"
}
fi

View file

@ -0,0 +1,242 @@
#
# Example of valid statements for an alias file.
# Basic Alias File Usage
#
# In its most basic form, the Drush site alias feature provides a way
# for teams to share short names that refer to the live and staging sites
# (usually remote) for a given Drupal site.
#
# 1. Make a local working clone of your Drupal site and then
# `cd` to the project work to select it.
# 2. Add an alias file called $PROJECT/drush/sites/self.site.yml,
# where $PROJECT is the project root (location of composer.json file).
# 3. Run remote commands against the shared live or stage sites
#
# Following these steps, a cache:rebuild on the live environment would be:
#
# $ drush @live cache:rebuild
#
# The site alias file should be named `self.site.yml` because this name is
# special, and is used to define the different environments (usually remote)
# of the current Drupal site.
#
# The contents of the alias file should look something like the example below:
#
# @code
# # File: self.site.yml
# live:
# host: server.domain.com
# user: www-admin
# root: /other/path/to/live/drupal
# uri: http://example.com
# stage:
# host: server.domain.com
# user: www-admin
# root: /other/path/to/stage/drupal
# uri: http://stage.example.com
# @endcode
#
# The top-level element names (`live` and `stage` in the example above) are
# used to identify the different environments available for this site. These
# may be used on the command line to select a different target environment
# to operate on by prepending an `@` character, e.g. `@live` or `@stage`.
#
# All of the available aliases for a site's environments may be listed via:
#
# $ drush site:alias @self
#
# The elements of a site alias environment are:
#
# - 'host': The fully-qualified domain name of the remote system
# hosting the Drupal instance. **Important Note: The remote-host option
# must be omitted for local sites, as this option controls various
# operations, such as whether or not rsync parameters are for local or
# remote machines, and so on.
# - 'user': The username to log in as when using ssh or rsync.
# - 'root': The Drupal root; must not be specified as a relative path.
# - 'uri': The value of --uri should always be the same as
# when the site is being accessed from a web browser (e.g. http://example.com)
#
# Drush uses ssh to run commands on remote systems; all team members should
# install ssh keys on the target servers (e.g. via ssh-add).
# Advanced Site Alias File Usage
#
# It is also possible to create site alias files that reference other
# sites on the same local system. Site alias files for other local sites
# are usually stored in the directory `~/.drush/sites`; however, Drush does
# not search this location for alias files by default. To use this location,
# you must add the path in your Drush configuration file. For example,
# to re-add both of the default user alias path from Drush 8, put the following
# in your ~/.drush/drush.yml configuration file:
#
# @code
# drush:
# paths:
# alias-path:
# - '${env.home}/.drush/sites'
# - /etc/drush/sites
# @endcode
#
# The command `drush core:init` will automatically configure your
# ~/.drush/drush.yml configuration file to add `~/.drush/sites` and
# `/etc/drush/sites` as locations where alias files may be placed.
#
# A canonical alias named "example" that points to a local
# Drupal site named "http://example.com" looks like this:
#
# @code
# File: example.site.yml
# dev:
# root: /path/to/drupal
# uri: http://example.com
# @endcode
#
# Note that the first part of the filename (in this case "example")
# defines the name of the site alias, and the top-level key ("dev")
# defines the name of the environment.
#
# With these definitions in place, it is possible to run commands targeting
# the dev environment of the target site via:
#
# $ drush @example.dev status
#
# This command is equivalent to the longer form:
#
# $ drush --root=/path/to/drupal --uri=http://example.com status
#
# See "Additional Site Alias Options" below for more information.
# Converting Legacy Alias Files
#
# To convert legacy alias (*.aliases.drushrc.php) to yml, run the
# site:alias-convert command.
# Altering aliases:
#
# See examples/Commands/SiteAliasAlterCommands.php for an example.
# Environment variables:
#
# It is no longer possible to set environment variables from within an alias.
# This is a planned feature.
# Additional Site Alias Options
#
# Aliases are commonly used to define short names for
# local or remote Drupal installations; however, an alias
# is really nothing more than a collection of options.
#
# - 'os': The operating system of the remote server. Valid values
# are 'Windows' and 'Linux'. Be sure to set this value for all remote
# aliases because the default value is PHP_OS if 'remote-host'
# is not set, and 'Linux' (or $options['remote-os']) if it is. Therefore,
# if you set a 'remote-host' value, and your remote OS is Windows, if you
# do not set the 'OS' value, it will default to 'Linux' and could cause
# unintended consequences, particularly when running 'drush sql-sync'.
# - 'ssh': Contains settings used to control how ssh commands are generated
# when running remote commands.
# - 'options': Contains additional commandline options for the ssh command
# itself, e.g. "-p 100"
# - 'tty': Usually, Drush will decide whether or not to create a tty (via
# the ssh '--t' option) based on whether the local Drush command is running
# interactively or not. To force Drush to always or never create a tty,
# set the 'ssh.tty' option to 'true' or 'false', respectively.
# - 'paths': An array of aliases for common rsync targets.
# Relative aliases are always taken from the Drupal root.
# - 'files': Path to 'files' directory. This will be looked up if not
# specified.
# - 'drush-script': Path to the remote Drush command.
# - 'command': These options will only be set if the alias
# is used with the specified command. In the example below, the option
# `--no-dump` will be selected whenever the @stage alias
# is used in any of the following ways:
# - `drush @stage sql-sync @self @live`
# - `drush sql-sync @stage @live`
# - `drush sql-sync @live @stage`
# NOTE: Setting boolean options broke with Symfony 3. This will be fixed
# in a future release. See: https://github.com/drush-ops/drush/issues/2956
#
# Complex example:
#
# @code
# # File: remote.site.yml
# live:
# host: server.domain.com
# user: www-admin
# root: /other/path/to/drupal
# uri: http://example.com
# ssh:
# options: '-p 100'
# paths:
# drush-script: '/path/to/drush'
# command:
# site:
# install:
# options:
# admin-password: 'secret-secret'
# @endcode
# Site Alias Files for Service Providers
#
# There are a number of service providers that manage Drupal sites as a
# service. Drush allows service providers to create collections of site alias
# files to reference all of the sites available to a single user. In order
# to so this, a new location must be defined in your Drush configuration
# file:
#
# @code
# drush:
# paths:
# alias-path:
# - '${env.home}/.drush/sites/provider-name'
# @endcode
#
# Site aliases stored in this directory may then be referenced by its
# full alias name, including its location, e.g.:
#
# $ drush @provider-name.example.dev
#
# Such alias files may still be referenced by their shorter name, e.g.
# `@example.dev`. Note that it is necessary to individually list every
# location where site alias files may be stored; Drush never does recursive
# (deep) directory searches for alias files.
#
# The `site:alias` command may also be used to list all of the sites and
# environments in a given location, e.g.:
#
# $ drush site:alias @provider-name
#
# Add the option `--format=list` to show only the names of each site and
# environment without also showing the values in each alias record.
# Developer Information
#
# See https://github.com/consolidation/site-alias for more developer
# information about Site Aliases.
#
# An example appears below. Edit to suit and remove the @code / @endcode and
# leading hashes to enable.
#
# @code
# # File: mysite.site.yml
# stage:
# uri: http://stage.example.com
# root: /path/to/remote/drupal/root
# host: mystagingserver.myisp.com
# user: publisher
# os: Linux
# paths:
# - files: sites/mydrupalsite.com/files
# - custom: /my/custom/path
# command:
# sql:
# sync:
# options:
# no-dump: true
# dev:
# root: /path/to/docroot
# uri: https://dev.example.com
# @endcode

View file

@ -0,0 +1,50 @@
#!/usr/bin/env sh
#
# Git bisect is a helpful way to discover which commit an error
# occurred in. This example file gives simple instructions for
# using git bisect with Drush to quickly find erroneous commits
# in Drush commands or Drupal modules, presuming that you can
# trigger the error condition via Drush (e.g. using `drush php-eval`).
#
# Follow these simple steps:
#
# $ git bisect start
# $ git bisect bad # Tell git that the current commit does not work
# $ git bisect good bcadd5a # Tell drush that the commithash 12345 worked fine
# $ git bisect run mytestscript.sh
#
# 'git bisect run' will continue to call 'git bisect good' and 'git bisect bad',
# based on whether the script's exit code was 0 or 1, respectively.
#
# Replace 'mytestscript.sh' in the example above with a custom script that you
# write yourself. Use the example script at the end of this document as a
# guide. Replace the example command with one that calls the Drush command
# that you would like to test, and replace the 'grep' string with a value
# that appears when the error exists in the commit, but does not appear when
# commit is okay.
#
# If you are using Drush to test Drupal or an external Drush module, use:
#
# $ git bisect run drush mycommand --strict=2
#
# This presumes that there is one or more '[warning]' or '[error]'
# messages emitted when there is a problem, and no warnings or errors
# when the commit is okay. Omit '--strict=2' to ignore warnings, and
# signal failure only when 'error' messages are emitted.
#
# If you need to test for an error condition explicitly, to find errors
# that do not return any warning or error log messages on their own, you
# can use the Drush php-eval command to force an error when `myfunction()`
# returns FALSE. Replace 'myfunction()' with the name of an appropriate
# function in your module that can be used to detect the error condition
# you are looking for.
#
# $ git bisect run drush ev 'if(!myfunction()) { return drush_set_error("ERR"); }'
#
drush mycommand --myoption 2>&1 | grep -q 'string that indicates there was a problem'
if [ $? == 0 ] ; then
exit 1
else
exit 0
fi

27
vendor/drush/drush/examples/helloworld.script vendored Executable file
View file

@ -0,0 +1,27 @@
<?php
//
// This example demonstrates how to write a drush
// script. These scripts are run with the php-script command.
//
use Drush\Drush;
$this->output()->writeln("Hello world!");
$this->output()->writeln("The extra options/arguments to this command were:");
$this->output()->writeln(print_r($extra, true));
//
// We can check which site was bootstrapped via
// the '@self' alias, which is defined only if
// there is a bootstrapped site.
//
$self = Drush::aliasManager()->getSelf();;
if (empty($self->root())) {
$this->output()->writeln('No bootstrapped site.');
}
else {
$this->output()->writeln('The following site is bootstrapped:');
$this->output()->writeln(print_r($self->legacyRecord(), true));
}

1304
vendor/drush/drush/includes/backend.inc vendored Normal file

File diff suppressed because it is too large Load diff

371
vendor/drush/drush/includes/batch.inc vendored Normal file
View file

@ -0,0 +1,371 @@
<?php
/**
* @file
* Drush batch API.
*
* This file contains a fork of the Drupal Batch API that has been drastically
* simplified and tailored to Drush's unique use case.
*
* The existing API is very targeted towards environments that are web accessible,
* and would frequently attempt to redirect the user which would result in the
* drush process being completely destroyed with no hope of recovery.
*
* While the original API does offer a 'non progressive' mode which simply
* calls each operation in sequence within the current process, in most
* implementations (D6), it would still attempt to redirect
* unless very specific conditions were met.
*
* When operating in 'non progressive' mode, Drush would experience the problems
* that the API was written to solve in the first place, specifically that processes
* would exceed the available memory and exit with an error.
*
* Each major release of Drupal has also had slightly different implementations
* of the batch API, and this provides a uniform interface to all of these
* implementations.
*/
use Drush\Log\LogLevel;
/**
* Class extending ArrayObject to allow the batch API to perform logging when
* some keys of the array change.
*
* It is used to wrap batch's $context array and set log messages when values
* are assigned to keys 'message' or 'error_message'.
*
* @see _drush_batch_worker().
*/
class DrushBatchContext extends ArrayObject {
function offsetSet($name, $value) {
if ($name == 'message') {
drush_log(strip_tags($value), LogLevel::OK);
}
elseif ($name == 'error_message') {
drush_set_error('DRUSH_BATCH_ERROR', strip_tags($value));
}
parent::offsetSet($name, $value);
}
}
/**
* Process a Drupal batch by spawning multiple Drush processes.
*
* This function will include the correct batch engine for the current
* major version of Drupal, and will make use of the drush_backend_invoke
* system to spawn multiple worker threads to handle the processing of
* the current batch, while keeping track of available memory.
*
* The batch system will process as many batch sets as possible until
* the entire batch has been completed or half of the available memory
* has been used.
*
* This function is a drop in replacement for the existing batch_process()
* function of Drupal.
*
* @param string $command
* (optional) The command to call for the back end process. By default this will be
* the 'batch-process' command, but some commands will
* have special initialization requirements, and will need to define and
* use their own command.
* @param array $args
* (optional)
* @param array $options
* (optional)
*/
function drush_backend_batch_process($command = 'batch-process', $args = [], $options = []) {
// Command line options to pass to the command.
$options['u'] = \Drupal::currentUser()->id();
return _drush_backend_batch_process($command, $args, $options);
}
/**
* Process sets from the specified batch.
*
* This function is called by the worker process that is spawned by the
* drush_backend_batch_process function.
*
* The command called needs to call this function after it's special bootstrap
* requirements have been taken care of.
*
* @param int $id
* The batch ID of the batch being processed.
*/
function drush_batch_command($id) {
include_once(DRUSH_DRUPAL_CORE . '/includes/batch.inc');
return _drush_batch_command($id);
}
/**
* Main loop for the Drush batch API.
*
* Saves a record of the batch into the database, and progressively call $command to
* process the operations.
*
* @param command
* The command to call to process the batch.
*
*/
function _drush_backend_batch_process($command = 'batch-process', $args, $options) {
$result = NULL;
$batch =& batch_get();
if (isset($batch)) {
$process_info = [
'current_set' => 0,
];
$batch += $process_info;
// The batch is now completely built. Allow other modules to make changes
// to the batch so that it is easier to reuse batch processes in other
// enviroments.
\Drupal::moduleHandler()->alter('batch', $batch);
// Assign an arbitrary id: don't rely on a serial column in the 'batch'
// table, since non-progressive batches skip database storage completely.
$batch['id'] = db_next_id();
$args[] = $batch['id'];
$batch['progressive'] = TRUE;
// Move operations to a job queue. Non-progressive batches will use a
// memory-based queue.
foreach ($batch['sets'] as $key => $batch_set) {
_batch_populate_queue($batch, $key);
}
// Store the batch.
/** @var \Drupal\Core\Batch\BatchStorage $batch_storage */
$batch_storage = \Drupal::service('batch.storage');
$batch_storage->create($batch);
$finished = FALSE;
while (!$finished) {
$result = drush_invoke_process('@self', $command, $args);
$finished = drush_get_error() || !$result || (isset($result['context']['drush_batch_process_finished']) && $result['context']['drush_batch_process_finished'] == TRUE);
}
}
return $result;
}
/**
* Initialize the batch command and call the worker function.
*
* Loads the batch record from the database and sets up the requirements
* for the worker, such as registering the shutdown function.
*
* @param id
* The batch id of the batch being processed.
*/
function _drush_batch_command($id) {
$batch =& batch_get();
$data = db_query("SELECT batch FROM {batch} WHERE bid = :bid", [
':bid' => $id
])->fetchField();
if ($data) {
$batch = unserialize($data);
}
else {
return FALSE;
}
if (!isset($batch['running'])) {
$batch['running'] = TRUE;
}
// Register database update for end of processing.
register_shutdown_function('_drush_batch_shutdown');
if (_drush_batch_worker()) {
return _drush_batch_finished();
}
}
/**
* Process batch operations
*
* Using the current $batch process each of the operations until the batch
* has been completed or half of the available memory for the process has been
* reached.
*/
function _drush_batch_worker() {
$batch =& batch_get();
$current_set =& _batch_current_set();
$set_changed = TRUE;
if (empty($current_set['start'])) {
$current_set['start'] = microtime(TRUE);
}
$queue = _batch_queue($current_set);
while (!$current_set['success']) {
// If this is the first time we iterate this batch set in the current
// request, we check if it requires an additional file for functions
// definitions.
if ($set_changed && isset($current_set['file']) && is_file($current_set['file'])) {
include_once DRUPAL_ROOT . '/' . $current_set['file'];
}
$task_message = '';
// Assume a single pass operation and set the completion level to 1 by
// default.
$finished = 1;
if ($item = $queue->claimItem()) {
list($function, $args) = $item->data;
// Build the 'context' array and execute the function call.
$batch_context = [
'sandbox' => &$current_set['sandbox'],
'results' => &$current_set['results'],
'finished' => &$finished,
'message' => &$task_message,
];
// Magic wrap to catch changes to 'message' key.
$batch_context = new DrushBatchContext($batch_context);
// Tolerate recoverable errors.
// See https://github.com/drush-ops/drush/issues/1930
$halt_on_error = \Drush\Drush::config()->get('runtime.php.halt-on-error', TRUE);
\Drush\Drush::config()->set('runtime.php.halt-on-error', FALSE);
$message = call_user_func_array($function, array_merge($args, [&$batch_context]));
if (!empty($message)) {
drush_print(strip_tags($message), 2);
}
\Drush\Drush::config()->set('runtime.php.halt-on-error', $halt_on_error);
$finished = $batch_context['finished'];
if ($finished >= 1) {
// Make sure this step is not counted twice when computing $current.
$finished = 0;
// Remove the processed operation and clear the sandbox.
$queue->deleteItem($item);
$current_set['count']--;
$current_set['sandbox'] = [];
}
}
// When all operations in the current batch set are completed, browse
// through the remaining sets, marking them 'successfully processed'
// along the way, until we find a set that contains operations.
// _batch_next_set() executes form submit handlers stored in 'control'
// sets (see form_execute_handlers()), which can in turn add new sets to
// the batch.
$set_changed = FALSE;
$old_set = $current_set;
while (empty($current_set['count']) && ($current_set['success'] = TRUE) && _batch_next_set()) {
$current_set = &_batch_current_set();
$current_set['start'] = microtime(TRUE);
$set_changed = TRUE;
}
// At this point, either $current_set contains operations that need to be
// processed or all sets have been completed.
$queue = _batch_queue($current_set);
// If we are in progressive mode, break processing after 1 second.
if (drush_memory_limit() > 0 && (memory_get_usage() * 2) >= drush_memory_limit()) {
drush_log(dt("Batch process has consumed in excess of 50% of available memory. Starting new thread"), LogLevel::BATCH);
// Record elapsed wall clock time.
$current_set['elapsed'] = round((microtime(TRUE) - $current_set['start']) * 1000, 2);
break;
}
}
// Reporting 100% progress will cause the whole batch to be considered
// processed. If processing was paused right after moving to a new set,
// we have to use the info from the new (unprocessed) set.
if ($set_changed && isset($current_set['queue'])) {
// Processing will continue with a fresh batch set.
$remaining = $current_set['count'];
$total = $current_set['total'];
$progress_message = $current_set['init_message'];
$task_message = '';
}
else {
// Processing will continue with the current batch set.
$remaining = $old_set['count'];
$total = $old_set['total'];
$progress_message = $old_set['progress_message'];
}
$current = $total - $remaining + $finished;
$percentage = _batch_api_percentage($total, $current);
return ($percentage == 100);
}
/**
* End the batch processing:
* Call the 'finished' callbacks to allow custom handling of results,
* and resolve page redirection.
*/
function _drush_batch_finished() {
$results = [];
$batch = &batch_get();
// Execute the 'finished' callbacks for each batch set, if defined.
foreach ($batch['sets'] as $id => $batch_set) {
if (isset($batch_set['finished'])) {
// Check if the set requires an additional file for function definitions.
if (isset($batch_set['file']) && is_file($batch_set['file'])) {
include_once DRUPAL_ROOT . '/' . $batch_set['file'];
}
if (is_callable($batch_set['finished'])) {
$queue = _batch_queue($batch_set);
$operations = $queue->getAllItems();
$elapsed = $batch_set['elapsed'] / 1000;
$elapsed = drush_drupal_major_version() >=8 ? \Drupal::service('date.formatter')->formatInterval($elapsed) : format_interval($elapsed);
call_user_func_array($batch_set['finished'], [$batch_set['success'], $batch_set['results'], $operations, $elapsed]);
$results[$id] = $batch_set['results'];
}
}
}
// Clean up the batch table and unset the static $batch variable.
if (drush_drupal_major_version() >= 8) {
/** @var \Drupal\Core\Batch\BatchStorage $batch_storage */
$batch_storage = \Drupal::service('batch.storage');
$batch_storage->delete($batch['id']);
}
else {
db_delete('batch')
->condition('bid', $batch['id'])
->execute();
}
foreach ($batch['sets'] as $batch_set) {
if ($queue = _batch_queue($batch_set)) {
$queue->deleteQueue();
}
}
$_batch = $batch;
$batch = NULL;
drush_set_option('drush_batch_process_finished', TRUE);
return $results;
}
/**
* Shutdown function: store the batch data for next request,
* or clear the table if the batch is finished.
*/
function _drush_batch_shutdown() {
if ($batch = batch_get()) {
if (drush_drupal_major_version() >= 8) {
/** @var \Drupal\Core\Batch\BatchStorage $batch_storage */
$batch_storage = \Drupal::service('batch.storage');
$batch_storage->update($batch);
}
else {
db_update('batch')
->fields(['batch' => serialize($batch)])
->condition('bid', $batch['id'])
->execute();
}
}
}

View file

@ -0,0 +1,117 @@
<?php
use Drush\Drush;
use Drush\Log\LogLevel;
/**
* No bootstrap.
*
* Commands that only preflight, but do not bootstrap, should use
* a bootstrap level of DRUSH_BOOTSTRAP_NONE.
*/
define('DRUSH_BOOTSTRAP_NONE', 0);
/**
* Use drush_bootstrap_max instead of drush_bootstrap_to_phase
*
* This constant is only usable as the value of the 'bootstrap'
* item of a command object, or as the parameter to
* drush_bootstrap_to_phase. It is not a real bootstrap state.
*/
define('DRUSH_BOOTSTRAP_MAX', -2);
/**
* @deprecated
*
* No longer used, but 0 remains reserved. Drush always runs preflight.
* Commands may alternatively use DRUSH_BOOTSTRAP_NONE.
*/
define('DRUSH_BOOTSTRAP_DRUSH', 0);
/**
* Set up and test for a valid drupal root, either through the -r/--root options,
* or evaluated based on the current working directory.
*
* Any code that interacts with an entire Drupal installation, and not a specific
* site on the Drupal installation should use this bootstrap phase.
*/
define('DRUSH_BOOTSTRAP_DRUPAL_ROOT', 1);
/**
* Set up a Drupal site directory and the correct environment variables to
* allow Drupal to find the configuration file.
*
* If no site is specified with the -l / --uri options, Drush will assume the
* site is 'default', which mimics Drupal's behaviour.
*
* If you want to avoid this behaviour, it is recommended that you use the
* DRUSH_BOOTSTRAP_DRUPAL_ROOT bootstrap phase instead.
*
* Any code that needs to modify or interact with a specific Drupal site's
* settings.php file should bootstrap to this phase.
*/
define('DRUSH_BOOTSTRAP_DRUPAL_SITE', 2);
/**
* Load the settings from the Drupal sites directory.
*
* This phase is analagous to the DRUPAL_BOOTSTRAP_CONFIGURATION bootstrap phase in Drupal
* itself, and this is also the first step where Drupal specific code is included.
*
* This phase is commonly used for code that interacts with the Drupal install API,
* as both install.php and update.php start at this phase.
*/
define('DRUSH_BOOTSTRAP_DRUPAL_CONFIGURATION', 3);
/**
* Connect to the Drupal database using the database credentials loaded
* during the previous bootstrap phase.
*
* This phase is analogous to the DRUPAL_BOOTSTRAP_DATABASE bootstrap phase in
* Drupal.
*
* Any code that needs to interact with the Drupal database API needs to
* be bootstrapped to at least this phase.
*/
define('DRUSH_BOOTSTRAP_DRUPAL_DATABASE', 4);
/**
* Fully initialize Drupal.
*
* This is analogous to the DRUPAL_BOOTSTRAP_FULL bootstrap phase in
* Drupal.
*
* Any code that interacts with the general Drupal API should be
* bootstrapped to this phase.
*/
define('DRUSH_BOOTSTRAP_DRUPAL_FULL', 5);
/**
* Helper function to store any context settings that are being validated.
*/
function drush_bootstrap_value($context, $value = null) {
$values =& drush_get_context('DRUSH_BOOTSTRAP_VALUES', []);
if (isset($value)) {
$values[$context] = $value;
}
if (array_key_exists($context, $values)) {
return $values[$context];
}
return null;
}
/**
* Helper function to collect any errors that occur during the bootstrap process.
* Always returns FALSE, for convenience.
*/
function drush_bootstrap_error($code, $message = null) {
$errors = drush_get_context('DRUSH_BOOTSTRAP_ERRORS');
$errors[$code] = $message;
drush_set_context('DRUSH_BOOTSTRAP_ERRORS', $errors);
return FALSE;
}

203
vendor/drush/drush/includes/cache.inc vendored Normal file
View file

@ -0,0 +1,203 @@
<?php
/**
* @file
* Drush cache API
*
* Provides a cache API for drush core and commands, forked from Drupal 7.
*
* The default storage backend uses the plain text files to store serialized php
* objects, which can be extended or replaced by setting the cache-default-class
* option in drushrc.php.
*/
use Drush\Drush;
use Drush\Log\LogLevel;
/**
* Indicates that the item should never be removed unless explicitly selected.
*
* The item may be removed using cache_clear_all() with a cache ID.
*/
define('DRUSH_CACHE_PERMANENT', 0);
/**
* Indicates that the item should be removed at the next general cache wipe.
*/
define('DRUSH_CACHE_TEMPORARY', -1);
/**
* Get the cache object for a cache bin.
*
* By default, this returns an instance of the \Drush\Cache\FileCache class.
* Classes implementing \Drush\Cache\CacheInterface can register themselves
* both as a default implementation and for specific bins.
*
* @see \Drush\Cache\CacheInterface
*
* @param string $bin
* The cache bin for which the cache object should be returned.
*
* @return \Drush\Cache\CacheInterface
* The cache object associated with the specified bin.
*/
function _drush_cache_get_object($bin) {
static $cache_objects;
if (!isset($cache_objects[$bin])) {
$class = drush_get_option('cache-class-' . $bin, NULL);
if (!isset($class)) {
$class = drush_get_option('cache-default-class', '\Drush\Cache\JSONCache');
}
$cache_objects[$bin] = new $class($bin);
}
return $cache_objects[$bin];
}
/**
* Return data from the persistent cache.
*
* Data may be stored as either plain text or as serialized data.
* _drush_cache_get() will automatically return unserialized
* objects and arrays.
*
* @param string $cid
* The cache ID of the data to retrieve.
* @param string $bin
* The cache bin to store the data in.
*
* @return
* The cache or FALSE on failure.
*
*/
function drush_cache_get($cid, $bin = 'default') {
$ret = _drush_cache_get_object($bin)->get($cid);
$mess = $ret ? "HIT" : "MISS";
drush_log(dt("Cache !mess cid: !cid", ['!mess' => $mess, '!cid' => $cid]), LogLevel::DEBUG);
return $ret;
}
/**
* Return data from the persistent cache when given an array of cache IDs.
*
* @param array $cids
* An array of cache IDs for the data to retrieve. This is passed by
* reference, and will have the IDs successfully returned from cache removed.
* @param string $bin
* The cache bin where the data is stored.
*
* @return
* An array of the items successfully returned from cache indexed by cid.
*/
function drush_cache_get_multiple(array &$cids, $bin = 'default') {
return _drush_cache_get_object($bin)->getMultiple($cids);
}
/**
* Store data in the persistent cache.
*
* @param string $cid
* The cache ID of the data to store.
*
* @param $data
* The data to store in the cache.
* @param string $bin
* The cache bin to store the data in.
* @param $expire
* One of the following values:
* - DRUSH_CACHE_PERMANENT: Indicates that the item should never be removed
* unless explicitly told to using drush_cache_clear_all() with a cache ID.
* - DRUSH_CACHE_TEMPORARY: Indicates that the item should be removed at
* the next general cache wipe.
* - A Unix timestamp: Indicates that the item should be kept at least until
* the given time, after which it behaves like DRUSH_CACHE_TEMPORARY.
*
* @return bool
*/
function drush_cache_set($cid, $data, $bin = 'default', $expire = DRUSH_CACHE_PERMANENT) {
$ret = _drush_cache_get_object($bin)->set($cid, $data, $expire);
if ($ret) drush_log(dt("Cache SET cid: !cid", ['!cid' => $cid]), LogLevel::DEBUG);
return $ret;
}
/**
* Expire data from the cache.
*
* If called without arguments, expirable entries will be cleared from all known
* cache bins.
*
* @param string $cid
* If set, the cache ID to delete. Otherwise, all cache entries that can
* expire are deleted.
* @param string $bin
* If set, the bin $bin to delete from. Mandatory
* argument if $cid is set.
* @param bool $wildcard
* If $wildcard is TRUE, cache IDs starting with $cid are deleted in
* addition to the exact cache ID specified by $cid. If $wildcard is
* TRUE and $cid is '*' then the entire bin $bin is emptied.
*/
function drush_cache_clear_all($cid = NULL, $bin = 'default', $wildcard = FALSE) {
if (!isset($cid) && !isset($bin)) {
foreach (drush_cache_get_bins() as $bin) {
_drush_cache_get_object($bin)->clear();
}
return;
}
return _drush_cache_get_object($bin)->clear($cid, $wildcard);
}
/**
* Check if a cache bin is empty.
*
* A cache bin is considered empty if it does not contain any valid data for any
* cache ID.
*
* @param $bin
* The cache bin to check.
*
* @return
* TRUE if the cache bin specified is empty.
*/
function _drush_cache_is_empty($bin) {
return _drush_cache_get_object($bin)->isEmpty();
}
/**
* Return drush cache bins and any bins added by hook_drush_flush_caches().
*/
function drush_cache_get_bins() {
$drush = ['default'];
return $drush;
// return array_merge(drush_command_invoke_all('drush_flush_caches'), $drush);
}
/**
* Create a cache id from a given prefix, contexts, and additional parameters.
*
* @param prefix
* A human readable cid prefix that will not be hashed.
* @param contexts
* Array of drush contexts that will be used to build a unique hash.
* @param params
* Array of any addition parameters to be hashed.
*
* @return
* A cache id string.
*/
function drush_get_cid($prefix, $contexts = [], $params = []) {
$cid = [];
foreach ($contexts as $context) {
$c = drush_get_context($context);
if (!empty($c)) {
$cid[] = is_scalar($c) ? $c : serialize($c);
}
}
foreach ($params as $param) {
$cid[] = $param;
}
return Drush::getVersion() . '-' . $prefix . '-' . md5(implode("", $cid));
}

100
vendor/drush/drush/includes/command.inc vendored Normal file
View file

@ -0,0 +1,100 @@
<?php
use Consolidation\AnnotatedCommand\AnnotatedCommand;
use Drush\Drush;
use Drush\Log\LogLevel;
use Webmozart\PathUtil\Path;
use Consolidation\AnnotatedCommand\AnnotationData;
use Drush\Command\DrushInputAdapter;
use Consolidation\SiteAlias\AliasRecord;
use Consolidation\AnnotatedCommand\CommandData;
use Symfony\Component\Console\Output\ConsoleOutput;
/**
* @defgroup dispatching Command dispatching functions.
* @{
*
* These functions handle command dispatching, and can
* be used to programmatically invoke Drush commands in
* different ways.
*/
/**
* Invoke a command in a new process, targeting the site specified by
* the provided site alias record.
*
* @param array|string $site_alias_record
* The site record to execute the command on. Use '@self' to run on the current site.
* @param string $command_name
* The command to invoke.
* @param array $commandline_args
* The arguments to pass to the command.
* @param array $commandline_options
* The options (e.g. --select) to provide to the command.
* @param mixed $backend_options
* TRUE - integrate errors
* FALSE - do not integrate errors
* array - @see drush_backend_invoke_concurrent
* There are also several options that _only_ work when set in
* this parameter. They include:
* 'invoke-multiple'
* If $site_alias_record represents a single site, then 'invoke-multiple'
* will cause the _same_ command with the _same_ arguments and options
* to be invoked concurrently (e.g. for running concurrent batch processes).
* 'concurrency'
* Limits the number of concurrent processes that will run at the same time.
* Defaults to '4'.
* 'override-simulated'
* Forces the command to run, even in 'simulated' mode. Useful for
* commands that do not change any state on the machine, e.g. to fetch
* database information for sql-sync via sql-conf.
* 'interactive'
* Overrides the backend invoke process to run commands interactively.
* 'fork'
* Overrides the backend invoke process to run non blocking commands in
* the background. Forks a new process by adding a '&' at the end of the
* command. The calling process does not receive any output from the child
* process. The fork option is used to spawn a process that outlives its
* parent.
*
* @return
* If the command could not be completed successfully, FALSE.
* If the command was completed, this will return an associative
* array containing the results of the API call.
* @see drush_backend_get_result()
*
* Do not change the signature of this function! drush_invoke_process
* is one of the key Drush APIs. See http://drupal.org/node/1152908
*/
function drush_invoke_process($site_alias_record, $command_name, $commandline_args = [], $commandline_options = [], $backend_options = TRUE) {
if ($site_alias_record instanceof AliasRecord) {
$site_alias_record = $site_alias_record->legacyRecord();
}
$invocations[] = [
'site' => $site_alias_record,
'command' => $command_name,
'args' => $commandline_args
];
$invoke_multiple = drush_get_option_override($backend_options, 'invoke-multiple', 0);
if ($invoke_multiple) {
$invocations = array_fill(0, $invoke_multiple, $invocations[0]);
}
return drush_backend_invoke_concurrent($invocations, $commandline_options, $backend_options);
}
/**
* Substrings to ignore during commandfile and site alias searching.
* TODO: Do we do any searching in the new code that should be filtered like this?
*/
function drush_filename_blacklist() {
$blacklist = ['.', '..', 'drush_make', 'examples', 'tests', 'disabled', 'gitcache', 'cache'];
for ($v=4; $v<=(DRUSH_MAJOR_VERSION)+3; ++$v) {
if ($v != DRUSH_MAJOR_VERSION) {
$blacklist[] = 'drush' . $v;
}
}
$blacklist = array_merge($blacklist, drush_get_option_list('exclude'));
return $blacklist;
}

531
vendor/drush/drush/includes/context.inc vendored Normal file
View file

@ -0,0 +1,531 @@
<?php
/**
* @file
* The Drush context API implementation.
*
* This API acts as a storage mechanism for all options, arguments and
* configuration settings that are loaded into drush.
*
* This API also acts as an IPC mechanism between the different drush commands,
* and provides protection from accidentally overriding settings that are
* needed by other parts of the system.
*
* It also avoids the necessity to pass references through the command chain
* and allows the scripts to keep track of whether any settings have changed
* since the previous execution.
*
* This API defines several contexts that are used by default.
*
* Argument contexts :
* These contexts are used by Drush to store information on the command.
* They have their own access functions in the forms of
* drush_set_arguments(), drush_get_arguments(), drush_set_command(),
* drush_get_command().
*
* command : The drush command being executed.
* arguments : Any additional arguments that were specified.
*
* Setting contexts :
* These contexts store options that have been passed to the drush.php
* script, either through the use of any of the config files, directly from
* the command line through --option='value' or through a JSON encoded string
* passed through the STDIN pipe.
*
* These contexts are accessible through the drush_get_option() and
* drush_set_option() functions. See drush_context_names() for a description
* of all of the contexts.
*
* Drush commands may also choose to save settings for a specific context to
* the matching configuration file through the drush_save_config() function.
*/
use Drush\Drush;
use Drush\Log\LogLevel;
/**
* Return a list of the valid drush context names.
*
* These context names are carefully ordered from
* highest to lowest priority.
*
* These contexts are evaluated in a certain order, and the highest priority value
* is returned by default from drush_get_option. This allows scripts to check whether
* an option was different before the current execution.
*
* Specified by the script itself :
* process : Generated in the current process.
* cli : Passed as --option=value to the command line.
* stdin : Passed as a JSON encoded string through stdin.
* specific : Defined in a command-specific option record, and
* set in the command context whenever that command is used.
* alias : Defined in an alias record, and set in the
* alias context whenever that alias is used.
*
* Specified by config files :
* custom : Loaded from the config file specified by --config or -c
* site : Loaded from the drushrc.php file in the Drupal site directory.
* drupal : Loaded from the drushrc.php file in the Drupal root directory.
* user : Loaded from the drushrc.php file in the user's home directory.
* home.drush Loaded from the drushrc.php file in the $HOME/.drush directory.
* system : Loaded from the drushrc.php file in the system's $PREFIX/etc/drush directory.
* drush : Loaded from the drushrc.php file in the same directory as drush.php.
*
* Specified by the script, but has the lowest priority :
* default : The script might provide some sensible defaults during init.
*/
function drush_context_names() {
static $contexts = [
'process', 'cli', 'stdin', 'specific', 'alias',
'custom', 'site', 'drupal', 'user', 'home.drush', 'system',
'drush', 'default'
];
return $contexts;
}
function drush_set_config_options($context, $options, $override = []) {
// Copy 'config-file' into 'context-path', converting to an array to hold multiple values if necessary
if (isset($options['config-file'])) {
if (isset($options['context-path'])) {
$options['context-path'] = array_merge([$options['config-file']], is_array($options['context-path']) ? $options['context-path'] : [$options['context-path']]);
}
else {
$options['context-path'] = $options['config-file'];
}
}
// Take out $aliases and $command_specific options
drush_set_config_special_contexts($options);
drush_set_context($context, $options);
}
/**
* For all global options with a short form, convert all options in the option
* array that use the short form into the long form.
*/
function drush_expand_short_form_options(&$options) {
foreach (drush_get_global_options() as $name => $info) {
if (is_array($info)) {
// For any option with a short form, check to see if the short form was set in the
// options. If it was, then rename it to its long form.
if (array_key_exists('short-form', $info) && array_key_exists($info['short-form'], $options)) {
if (!array_key_exists($name, $options) || !array_key_exists('merge-pathlist', $info)) {
$options[$name] = $options[$info['short-form']];
}
else {
$options[$name] = array_merge((array)$options[$name], (array)$options[$info['short-form']]);
}
unset($options[$info['short-form']]);
}
}
}
}
/**
* There are certain options such as 'site-aliases' and 'command-specific'
* that must be merged together if defined in multiple drush configuration
* files. If we did not do this merge, then the last configuration file
* that defined any of these properties would overwrite all of the options
* that came before in previously-loaded configuration files. We place
* all of them into their own context so that this does not happen.
*/
function drush_set_config_special_contexts(&$options) {
if (isset($options) && is_array($options)) {
$has_command_specific = array_key_exists('command-specific', $options);
// Change the keys of the site aliases from 'alias' to '@alias'
if (array_key_exists('site-aliases', $options)) {
$user_aliases = $options['site-aliases'];
$options['site-aliases'] = [];
foreach ($user_aliases as $alias_name => $alias_value) {
if (substr($alias_name,0,1) != '@') {
$alias_name = "@$alias_name";
}
$options['site-aliases'][$alias_name] = $alias_value;
}
}
// Expand -s into --simulate, etc.
drush_expand_short_form_options($options);
foreach (drush_get_global_options() as $name => $info) {
if (is_array($info)) {
// For any global option with the 'merge-pathlist' or 'merge-associative' flag, set its
// value in the specified context. The option is 'merged' because we
// load $options with the value from the context prior to including the
// configuration file. If the configuration file sets $option['special'][] = 'value',
// then the configuration will be merged. $option['special'] = array(...), on the
// other hand, will replace rather than merge the values together.
if ((array_key_exists($name, $options)) && (array_key_exists('merge', $info) || (array_key_exists('merge-pathlist', $info) || array_key_exists('merge-associative', $info)))) {
$context = array_key_exists('context', $info) ? $info['context'] : $name;
$cache =& drush_get_context($context);
$value = $options[$name];
if (!is_array($value) && array_key_exists('merge-pathlist', $info)) {
$value = explode(PATH_SEPARATOR, $value);
}
if (array_key_exists('merge-associative', $info)) {
foreach ($value as $subkey => $subvalue) {
$cache[$subkey] = array_merge(isset($cache[$subkey]) ? $cache[$subkey] : [], $subvalue);
}
}
else {
$cache = array_unique(array_merge($cache, $value));
}
// Once we have moved the option to its special context, we
// can remove it from its option context -- unless 'propagate-cli-value'
// is set, in which case we need to let it stick around in options
// in case it is needed in backend invoke.
if (!array_key_exists('propagate-cli-value', $info)) {
unset($options[$name]);
}
}
}
}
// If command-specific options were set and if we already have
// a command, then apply the command-specific options immediately.
if ($has_command_specific) {
drush_command_default_options();
}
}
}
/**
* Set a specific context.
*
* @param context
* Any of the default defined contexts.
* @param value
* The value to store in the context
*
* @return
* An associative array of the settings specified in the request context.
*/
function drush_set_context($context, $value) {
$cache =& drush_get_context($context);
$cache = $value;
return $value;
}
/**
* Return a specific context, or the whole context cache
*
* This function provides a storage mechanism for any information
* the currently running process might need to communicate.
*
* This avoids the use of globals, and constants.
*
* Functions that operate on the context cache, can retrieve a reference
* to the context cache using :
* $cache = &drush_get_context($context);
*
* This is a private function, because it is meant as an internal
* generalized API for writing static cache functions, not as a general
* purpose function to be used inside commands.
*
* Code that modifies the reference directly might have unexpected consequences,
* such as modifying the arguments after they have already been parsed and dispatched
* to the callbacks.
*
* @param context
* Optional. Any of the default defined contexts.
*
* @return
* If context is not supplied, the entire context cache will be returned.
* Otherwise only the requested context will be returned.
* If the context does not exist yet, it will be initialized to an empty array.
*/
function &drush_get_context($context = NULL, $default = NULL) {
static $cache = [];
if (isset($context)) {
if (!isset($cache[$context])) {
$default = !isset($default) ? [] : $default;
$cache[$context] = $default;
}
return $cache[$context];
}
return $cache;
}
/**
* Set the arguments passed to the drush.php script.
*
* This function will set the 'arguments' context of the current running script.
*
* When initially called by drush_parse_args, the entire list of arguments will
* be populated. Once the command is dispatched, this will be set to only the remaining
* arguments to the command (i.e. the command name is removed).
*
* @param arguments
* Command line arguments, as an array.
*/
function drush_set_arguments($arguments) {
drush_set_context('arguments', $arguments);
}
/**
* Gets the command line arguments passed to Drush.
*
* @return array
* An indexed array of arguments. Until Drush has dispatched the command, the
* array will include the command name as the first element. After that point
* the array will not include the command name.
*
* @see drush_set_arguments()
*/
function drush_get_arguments() {
return drush_get_context('arguments');
}
/**
* Set the command being executed.
*
* Drush_dispatch will set the correct command based on it's
* matching of the script arguments retrieved from drush_get_arguments
* to the implemented commands specified by drush_get_commands.
*
* @param
* A numerically indexed array of command components.
*/
function drush_set_command($command) {
drush_set_context('command', $command);
}
/**
* Return the command being executed.
*/
function drush_get_command() {
return drush_get_context('command');
}
/**
* Get the value for an option.
*
* If the first argument is an array, then it checks whether one of the options
* exists and return the value of the first one found. Useful for allowing both
* -h and --host-name
*
* @param option
* The name of the option to get
* @param default
* Optional. The value to return if the option has not been set
* @param context
* Optional. The context to check for the option. If this is set, only this context will be searched.
*/
function drush_get_option($option, $default = NULL, $context = NULL) {
// Uncomment when fumigating.
// $backtrace = debug_backtrace()[1];
// if (!strpos($backtrace['file'], 'engines') && !strpos($backtrace['file'], 'preflight') && !strpos($backtrace['file'], 'backend')) {
// drush_log('drush_get_option() has been deprecated and is unreliable. Called by '. $backtrace['function']. ' in '. $backtrace['file']. ':'. $backtrace['line'], LogLevel::WARNING);
// }
$value = NULL;
if ($context) {
// We have a definite context to check for the presence of an option.
$value = _drush_get_option($option, drush_get_context($context));
}
else {
// We are not checking a specific context, so check them in a predefined order of precedence.
$contexts = drush_context_names();
foreach ($contexts as $context) {
$value = _drush_get_option($option, drush_get_context($context));
if ($value !== NULL) {
return $value;
}
}
}
if ($value !== NULL) {
return $value;
}
return $default;
}
/**
* Get the value for an option and return it as a list. If the
* option in question is passed on the command line, its value should
* be a comma-separated list (e.g. --flag=1,2,3). If the option
* was set in a drushrc.php file, then its value may be either a
* comma-separated list or an array of values (e.g. $option['flag'] = array('1', '2', '3')).
*
* @param option
* The name of the option to get
* @param default
* Optional. The value to return if the option has not been set
* @param context
* Optional. The context to check for the option. If this is set, only this context will be searched.
*/
function drush_get_option_list($option, $default = [], $context = NULL) {
$result = drush_get_option($option, $default, $context);
if (!is_array($result)) {
$result = array_map('trim', array_filter(explode(',', $result)));
}
return $result;
}
/**
* Get the value for an option, but first checks the provided option overrides.
*
* The feature of drush_get_option that allows a list of option names
* to be passed in an array is NOT supported.
*
* @param option_overrides
* An array to check for values before calling drush_get_option.
* @param option
* The name of the option to get.
* @param default
* Optional. The value to return if the option has not been set.
* @param context
* Optional. The context to check for the option. If this is set, only this context will be searched.
*
*/
function drush_get_option_override($option_overrides, $option, $default = NULL, $context = NULL) {
return drush_sitealias_get_option($option_overrides, $option, $default, '', $context);
}
/**
* Get an option out of the specified alias. If it has not been
* set in the alias, then get it via drush_get_option.
*
* @param site_alias_record
* An array of options for an alias record.
* @param option
* The name of the option to get.
* @param default
* Optional. The value to return if the option does not exist in the site record and has not been set in a context.
* @param context
* Optional. The context to check for the option. If this is set, only this context will be searched.
*/
function drush_sitealias_get_option($site_alias_record, $option, $default = NULL, $prefix = '', $context = NULL) {
if (is_array($site_alias_record) && array_key_exists($option, $site_alias_record)) {
return $site_alias_record[$option];
}
else {
return drush_get_option($prefix . $option, $default, $context);
}
}
/**
* Get all of the values for an option in every context.
*
* @param option
* The name of the option to get
* @return
* An array whose key is the context name and value is
* the specific value for the option in that context.
*/
function drush_get_context_options($option, $flatten = FALSE) {
$result = [];
$contexts = drush_context_names();
foreach ($contexts as $context) {
$value = _drush_get_option($option, drush_get_context($context));
if ($value !== NULL) {
if ($flatten && is_array($value)) {
$result = array_merge($value, $result);
}
else {
$result[$context] = $value;
}
}
}
return $result;
}
/**
* Retrieves a collapsed list of all options.
*/
function drush_get_merged_options() {
$contexts = drush_context_names();
$cache = drush_get_context();
$result = [];
foreach (array_reverse($contexts) as $context) {
if (array_key_exists($context, $cache)) {
$result = array_merge($result, $cache[$context]);
}
}
return $result;
}
/**
* Helper function to recurse through possible option names
*/
function _drush_get_option($option, $context) {
if (is_array($option)) {
foreach ($option as $current) {
$current_value = _drush_get_option($current, $context);
if (isset($current_value)) {
return $current_value;
}
}
}
elseif (array_key_exists('no-' . $option, $context)) {
return FALSE;
}
elseif (array_key_exists($option, $context)) {
return $context[$option];
}
return NULL;
}
/**
* Set an option in one of the option contexts.
*
* @param option
* The option to set.
* @param value
* The value to set it to.
* @param context
* Optional. Which context to set it in.
* @return
* The value parameter. This allows for neater code such as
* $myvalue = drush_set_option('http_host', $_SERVER['HTTP_HOST']);
* Without having to constantly type out the value parameter.
*/
function drush_set_option($option, $value, $context = 'process') {
$cache =& drush_get_context($context);
$cache[$option] = $value;
return $value;
}
/**
* A small helper function to set the value in the default context
*/
function drush_set_default($option, $value) {
return drush_set_option($option, $value, 'default');
}
/**
* Remove a setting from a specific context.
*
* @param
* Option to be unset
* @param
* Context in which to unset the value in.
*/
function drush_unset_option($option, $context = NULL) {
if ($context != NULL) {
$cache =& drush_get_context($context);
if (array_key_exists($option, $cache)) {
unset($cache[$option]);
}
}
else {
$contexts = drush_context_names();
foreach ($contexts as $context) {
drush_unset_option($option, $context);
}
}
}

49
vendor/drush/drush/includes/drupal.inc vendored Normal file
View file

@ -0,0 +1,49 @@
<?php
/**
* @file
* Utility functions related to Drupal.
*/
use Drush\Drush;
/**
* Detects the version number of the current Drupal installation,
* if any. Returns FALSE if there is no current Drupal installation,
* or it is somehow broken.
*
* @return
* A string containing the version number of the current
* Drupal installation, if any. Otherwise, return FALSE.
*/
function drush_drupal_version($drupal_root = NULL) {
static $version = FALSE;
if (!$version) {
if (($drupal_root != NULL) || ($drupal_root = drush_get_context('DRUSH_DRUPAL_ROOT'))) {
$bootstrap = Drush::bootstrapManager()->bootstrapObjectForRoot($drupal_root);
if ($bootstrap) {
$version = $bootstrap->getVersion($drupal_root);
}
}
}
return $version;
}
function drush_drupal_cache_clear_all() {
drush_invoke_process('@self', 'cache-rebuild');
}
/**
* Returns the Drupal major version number (6, 7, 8 ...)
*/
function drush_drupal_major_version($drupal_root = NULL) {
$major_version = FALSE;
if ($version = drush_drupal_version($drupal_root)) {
$version_parts = explode('.', $version);
if (is_numeric($version_parts[0])) {
$major_version = (integer)$version_parts[0];
}
}
return $major_version;
}

740
vendor/drush/drush/includes/drush.inc vendored Normal file
View file

@ -0,0 +1,740 @@
<?php
/**
* @file
* The drush API implementation and helpers.
*/
use Drush\Drush;
use Drush\Log\LogLevel;
use Drush\Utils\StringUtils;
use Psr\Log\LoggerInterface;
/**
* @name Error status definitions
* @{
* Error code definitions for interpreting the current error status.
* @see drush_set_error(), drush_get_error(), drush_get_error_log(), drush_cmp_error()
*/
/** The command completed successfully. */
define('DRUSH_SUCCESS', 0);
/** The command could not be completed because the framework has specified errors that have occured. */
define('DRUSH_FRAMEWORK_ERROR', 1);
/** The command was aborted because the user chose to cancel it at some prompt.
This exit code is arbitrarily the same as EX_TEMPFAIL in sysexits.h, although
note that shell error codes are distinct from C exit codes, so this alignment
not meaningful. */
define('DRUSH_EXITCODE_USER_ABORT', 75);
/** The command that was executed resulted in an application error,
The most commom causes for this is invalid PHP or a broken SSH
pipe when using drush_backend_invoke in a distributed manner. */
define('DRUSH_APPLICATION_ERROR', 255);
/**
* @} End of "name Error status defintions".
*/
/**
* The number of bytes in a kilobyte. Copied from Drupal.
*/
define('DRUSH_KILOBYTE', 1024);
/**
* Convert a csv string, or an array of items which
* may contain csv strings, into an array of items.
*
* @param $args
* A simple csv string; e.g. 'a,b,c'
* or a simple list of items; e.g. array('a','b','c')
* or some combination; e.g. array('a,b','c') or array('a,','b,','c,')
*
* @returns array
* A simple list of items (e.g. array('a','b','c')
*
* @deprecated Use \Drush\StringUtils::csvToArray
*/
function _convert_csv_to_array($args) {
return StringUtils::csvToArray($args);
}
/**
* Convert a nested array into a flat array. Thows away
* the array keys, returning only the values.
*
* @param $args
* An array that may potentially be nested.
* e.g. array('a', array('b', 'c'))
*
* @returns array
* A simple list of items (e.g. array('a','b','c')
*/
function drush_flatten_array($a) {
$result = [];
if (!is_array($a)) {
return [$a];
}
foreach ($a as $value) {
$result = array_merge($result, drush_flatten_array($value));
}
return $result;
}
/**
* Get the available global options. Used by list/help commands. All other users
* should pull options from $application.
*
* @param boolean $brief
* Return a reduced set of important options. Used by help command.
*
* @return
* An associative array containing the option definition as the key,
* and a descriptive array for each of the available options. The array
* elements for each item are:
*
* - short-form: The shortcut form for specifying the key on the commandline.
* - propagate: backend invoke will use drush_get_option to propagate this
* option, when set, to any other Drush command that is called.
* - context: The drush context where the value of this item is cached. Used
* by backend invoke to propagate values set in code.
* - never-post: If TRUE, backend invoke will never POST this item's value
* on STDIN; it will always be sent as a commandline option.
* - never-propagate: If TRUE, backend invoke will never pass this item on
* to the subcommand being executed.
* - local-context-only: Backend invoke will only pass this value on for local calls.
* - merge: For options such as $options['shell-aliases'] that consist of an array
* of items, make a merged array that contains all of the values specified for
* all of the contexts (config files) where the option is defined. The value is stored in
* the specified 'context', or in a context named after the option itself if the
* context flag is not specified.
* IMPORTANT: When the merge flag is used, the option value must be obtained via
* drush_get_context('option') rather than drush_get_option('option').
* - merge-pathlist: For options such as --include and --config, make a merged list
* of options from all contexts; works like the 'merge' flag, but also handles string
* values separated by the PATH_SEPARATOR.
* - merge-associative: Like 'merge-pathlist', but key values are preserved.
* - propagate-cli-value: Used to tell backend invoke to include the value for
* this item as specified on the cli. This can either override 'context'
* (e.g., propagate --include from cli value instead of DRUSH_INCLUDE context),
* or for an independent global setting (e.g. --user)
* - description: The help text for this item. displayed by `drush help`.
*/
function drush_get_global_options($brief = FALSE) {
$options['root'] = ['short-form' => 'r', 'short-has-arg' => TRUE, 'never-post' => TRUE, 'description' => "Drupal root directory to use.", 'example-value' => 'path'];
$options['uri'] = ['short-form' => 'l', 'short-has-arg' => TRUE, 'never-post' => TRUE, 'description' => 'URI of the drupal site to use.', 'example-value' => 'http://example.com:8888'];
$options['verbose'] = ['short-form' => 'v', 'context' => 'DRUSH_VERBOSE', 'description' => 'Display extra information about the command.', 'symfony-conflict' => TRUE];
$options['debug'] = ['short-form' => 'd', 'context' => 'DRUSH_DEBUG', 'description' => 'Display even more information.'];
$options['yes'] = ['short-form' => 'y', 'context' => 'DRUSH_AFFIRMATIVE', 'description' => "Assume 'yes' as answer to all prompts."];
$options['no'] = ['short-form' => 'n', 'context' => 'DRUSH_NEGATIVE', 'description' => "Assume 'no' as answer to all prompts."];
$options['help'] = ['short-form' => 'h', 'description' => "This help system."];
if (!$brief) {
$options['simulate'] = ['short-form' => 's', 'context' => 'DRUSH_SIMULATE', 'never-propagate' => TRUE, 'description' => "Simulate all relevant actions (don't actually change the system).", 'symfony-conflict' => TRUE];
$options['pipe'] = ['short-form' => 'p', 'hidden' => TRUE, 'description' => "Emit a compact representation of the command for scripting."];
$options['php'] = ['description' => "The absolute path to your PHP interpreter, if not 'php' in the path.", 'example-value' => '/path/to/file', 'never-propagate' => TRUE];
$options['interactive'] = ['short-form' => 'ia', 'description' => "Force interactive mode for commands run on multiple targets (e.g. `drush @site1,@site2 cc --ia`).", 'never-propagate' => TRUE];
$options['tty'] = ['hidden' => TRUE, 'description' => "Force allocation of tty for remote commands", 'never-propagate' => TRUE];
$options['quiet'] = ['short-form' => 'q', 'description' => 'Suppress non-error messages.'];
$options['include'] = ['short-form' => 'i', 'short-has-arg' => TRUE, 'context' => 'DRUSH_INCLUDE', 'never-post' => TRUE, 'propagate-cli-value' => TRUE, 'merge-pathlist' => TRUE, 'description' => "A list of additional directory paths to search for Drush commands. Commandfiles should be placed in a subfolder called 'Commands'.", 'example-value' => '/path/dir'];
$options['exclude'] = ['propagate-cli-value' => TRUE, 'never-post' => TRUE, 'merge-pathlist' => TRUE, 'description' => "A list of files and directory paths to exclude from consideration when searching for drush commandfiles.", 'example-value' => '/path/dir'];
$options['config'] = ['short-form' => 'c', 'short-has-arg' => TRUE, 'context' => 'DRUSH_CONFIG', 'never-post' => TRUE, 'propagate-cli-value' => TRUE, 'merge-pathlist' => TRUE, 'description' => "Specify an additional config file to load. See example.drush.yml", 'example-value' => '/path/file'];
$options['backend'] = ['short-form' => 'b', 'never-propagate' => TRUE, 'description' => "Hide all output and return structured data."];
$options['choice'] = ['description' => "Provide an answer to a multiple-choice prompt.", 'example-value' => 'number'];
$options['search-depth'] = ['description' => "Control the depth that drush will search for alias files.", 'example-value' => 'number'];
$options['ignored-modules'] = ['description' => "Exclude some modules from consideration when searching for drush command files.", 'example-value' => 'token,views'];
$options['no-label'] = ['description' => "Remove the site label that drush includes in multi-site command output (e.g. `drush @site1,@site2 status`)."];
$options['label-separator'] = ['description' => "Specify the separator to use in multi-site command output (e.g. `drush @sites pm-list --label-separator=',' --format=csv`).", 'example-value' => ','];
$options['show-invoke'] = ['description' => "Show all function names which could have been called for the current command. See drush_invoke()."];
$options['cache-default-class'] = ['description' => "A cache backend class that implements CacheInterface. Defaults to JSONCache.", 'example-value' => 'JSONCache'];
$options['cache-class-<bin>'] = ['description' => "A cache backend class that implements CacheInterface to use for a specific cache bin.", 'example-value' => 'className'];
$options['early'] = ['description' => "Include a file (with relative or full path) and call the drush_early_hook() function (where 'hook' is the filename)"];
$options['alias-path'] = ['context' => 'ALIAS_PATH', 'local-context-only' => TRUE, 'merge-pathlist' => TRUE, 'propagate-cli-value' => TRUE, 'description' => "Specifies the list of paths where drush will search for alias files.", 'example-value' => '/path/alias1:/path/alias2'];
$options['confirm-rollback'] = ['description' => 'Wait for confirmation before doing a rollback when something goes wrong.'];
$options['php-options'] = ['hidden' => TRUE, 'description' => "Options to pass to `php` when running drush. Only effective when specified in a site alias definition.", 'never-propagate' => TRUE, 'example-value' => '-d error_reporting="E_ALL"'];
$options['halt-on-error'] = ['propagate-cli-value' => TRUE, 'description' => "Manage recoverable errors. Values: 1=Execution halted. 0=Execution continues."];
$options['remote-host'] = ['hidden' => TRUE, 'description' => 'Remote site to execute drush command on. Managed by site alias.', 'example-value' => 'http://example.com'];
$options['remote-user'] = ['hidden' => TRUE, 'description' => 'User account to use with a remote drush command. Managed by site alias.', 'example-value' => 'www-data'];
$options['remote-os'] = ['hidden' => TRUE, 'description' => 'The operating system used on the remote host. Managed by site alias.', 'example-value' => 'linux'];
$options['site-list'] = ['hidden' => TRUE, 'description' => 'List of sites to run commands on. Managed by site alias.', 'example-value' => '@site1,@site2'];
$options['reserve-margin'] = ['hidden' => TRUE, 'description' => 'Remove columns from formatted opions. Managed by multi-site command handling.', 'example-value' => 'number'];
$options['strict'] = ['propagate' => TRUE, 'description' => 'Return an error on unrecognized options. --strict=0: Allow unrecognized options.'];
$options['command-specific'] = ['hidden' => TRUE, 'merge-associative' => TRUE, 'description' => 'Command-specific options.'];
$options['site-aliases'] = ['hidden' => TRUE, 'merge-associative' => TRUE, 'description' => 'List of site aliases.'];
$options['shell-aliases'] = ['hidden' => TRUE, 'merge' => TRUE, 'never-propagate' => TRUE, 'description' => 'List of shell aliases.'];
$options['path-aliases'] = ['hidden' => TRUE, 'never-propagate' => TRUE, 'description' => 'Path aliases from site alias.'];
$options['ssh-options'] = ['never-propagate' => TRUE, 'description' => 'A string of extra options that will be passed to the ssh command', 'example-value' => '-p 100'];
$options['drush-coverage'] = ['hidden' => TRUE, 'never-post' => TRUE, 'propagate-cli-value' => TRUE, 'description' => 'File to save code coverage data into.'];
$options['local'] = ['propagate' => TRUE, 'description' => 'Don\'t look in global locations for commandfiles, config, and site aliases'];
}
return $options;
}
/**
* Calls a given function, passing through all arguments unchanged.
*
* This should be used when calling possibly mutative or destructive functions
* (e.g. unlink() and other file system functions) so that can be suppressed
* if the simulation mode is enabled.
*
* Important: Call @see drush_op_system() to execute a shell command,
* or @see drush_shell_exec() to execute a shell command and capture the
* shell output.
*
* @param $callable
* The name of the function. Any additional arguments are passed along.
* @return
* The return value of the function, or TRUE if simulation mode is enabled.
*
*/
function drush_op($callable) {
$args_printed = [];
$args = func_get_args();
array_shift($args); // Skip function name
foreach ($args as $arg) {
$args_printed[] = is_scalar($arg) ? $arg : (is_array($arg) ? 'Array' : 'Object');
}
if (!is_array($callable)) {
$callable_string = $callable;
}
else {
if (is_object($callable[0])) {
$callable_string = get_class($callable[0]) . '::' . $callable[1];
}
else {
$callable_string = implode('::', $callable);
}
}
// Special checking for drush_op('system')
if ($callable == 'system') {
drush_log(dt("Do not call drush_op('system'); use drush_op_system instead"), LogLevel::DEBUG);
}
if (\Drush\Drush::verbose() || \Drush\Drush::simulate()) {
drush_log(sprintf("Calling %s(%s)", $callable_string, implode(", ", $args_printed)), LogLevel::DEBUG);
}
if (\Drush\Drush::simulate()) {
return TRUE;
}
return drush_call_user_func_array($callable, $args);
}
/**
* Mimic cufa but still call function directly. See http://drupal.org/node/329012#comment-1260752
*/
function drush_call_user_func_array($function, $args = []) {
if (is_array($function)) {
// $callable is a method so always use CUFA.
return call_user_func_array($function, $args);
}
switch (count($args)) {
case 0: return $function(); break;
case 1: return $function($args[0]); break;
case 2: return $function($args[0], $args[1]); break;
case 3: return $function($args[0], $args[1], $args[2]); break;
case 4: return $function($args[0], $args[1], $args[2], $args[3]); break;
case 5: return $function($args[0], $args[1], $args[2], $args[3], $args[4]); break;
case 6: return $function($args[0], $args[1], $args[2], $args[3], $args[4], $args[5]); break;
case 7: return $function($args[0], $args[1], $args[2], $args[3], $args[4], $args[5], $args[6]); break;
case 8: return $function($args[0], $args[1], $args[2], $args[3], $args[4], $args[5], $args[6], $args[7]); break;
case 9: return $function($args[0], $args[1], $args[2], $args[3], $args[4], $args[5], $args[6], $args[7], $args[8]); break;
default: return call_user_func_array($function,$args);
}
}
/**
* Determines the MIME content type of the specified file.
*
* The power of this function depends on whether the PHP installation
* has either mime_content_type() or finfo installed -- if not, only tar,
* gz, zip and bzip2 types can be detected.
*
* If mime type can't be obtained, an error will be set.
*
* @return mixed
* The MIME content type of the file or FALSE.
*/
function drush_mime_content_type($filename) {
$content_type = drush_attempt_mime_content_type($filename);
if ($content_type) {
drush_log(dt('Mime type for !file is !mt', ['!file' => $filename, '!mt' => $content_type]), LogLevel::INFO);
return $content_type;
}
return drush_set_error('MIME_CONTENT_TYPE_UNKNOWN', dt('Unable to determine mime type for !file.', ['!file' => $filename]));
}
/**
* Works like drush_mime_content_type, but does not set an error
* if the type is unknown.
*/
function drush_attempt_mime_content_type($filename) {
$content_type = FALSE;
if (class_exists('finfo')) {
$finfo = new finfo(FILEINFO_MIME_TYPE);
$content_type = $finfo->file($filename);
if ($content_type == 'application/octet-stream') {
drush_log(dt('Mime type for !file is application/octet-stream.', ['!file' => $filename]), LogLevel::DEBUG);
$content_type = FALSE;
}
}
// If apache is configured in such a way that all files are considered
// octet-stream (e.g with mod_mime_magic and an http conf that's serving all
// archives as octet-stream for other reasons) we'll detect mime types on our
// own by examing the file's magic header bytes.
if (!$content_type) {
drush_log(dt('Examining !file headers.', ['!file' => $filename]), LogLevel::DEBUG);
if ($file = fopen($filename, 'rb')) {
$first = fread($file, 2);
fclose($file);
if ($first !== FALSE) {
// Interpret the two bytes as a little endian 16-bit unsigned int.
$data = unpack('v', $first);
switch ($data[1]) {
case 0x8b1f:
// First two bytes of gzip files are 0x1f, 0x8b (little-endian).
// See http://www.gzip.org/zlib/rfc-gzip.html#header-trailer
$content_type = 'application/x-gzip';
break;
case 0x4b50:
// First two bytes of zip files are 0x50, 0x4b ('PK') (little-endian).
// See http://en.wikipedia.org/wiki/Zip_(file_format)#File_headers
$content_type = 'application/zip';
break;
case 0x5a42:
// First two bytes of bzip2 files are 0x5a, 0x42 ('BZ') (big-endian).
// See http://en.wikipedia.org/wiki/Bzip2#File_format
$content_type = 'application/x-bzip2';
break;
default:
drush_log(dt('Unable to determine mime type from header bytes 0x!hex of !file.', ['!hex' => dechex($data[1]), '!file' => $filename,]), LogLevel::DEBUG);
}
}
else {
drush_log(dt('Unable to read !file.', ['!file' => $filename]), LogLevel::WARNING);
}
}
else {
drush_log(dt('Unable to open !file.', ['!file' => $filename]), LogLevel::WARNING);
}
}
// 3. Lastly if above methods didn't work, try to guess the mime type from
// the file extension. This is useful if the file has no identificable magic
// header bytes (for example tarballs).
if (!$content_type) {
drush_log(dt('Examining !file extension.', ['!file' => $filename]), LogLevel::DEBUG);
// Remove querystring from the filename, if present.
$filename = basename(current(explode('?', $filename, 2)));
$extension_mimetype = [
'.tar' => 'application/x-tar',
'.sql' => 'application/octet-stream',
];
foreach ($extension_mimetype as $extension => $ct) {
if (substr($filename, -strlen($extension)) === $extension) {
$content_type = $ct;
break;
}
}
}
return $content_type;
}
/**
* Check whether a file is a supported tarball.
*
* @return mixed
* The file content type if it's a tarball. FALSE otherwise.
*/
function drush_file_is_tarball($path) {
$content_type = drush_attempt_mime_content_type($path);
$supported = [
'application/x-bzip2',
'application/x-gzip',
'application/x-tar',
'application/x-zip',
'application/zip',
];
if (in_array($content_type, $supported)) {
return $content_type;
}
return FALSE;
}
/**
* @defgroup logging Logging information to be provided as output.
* @{
*
* These functions are primarily for diagnostic purposes, but also provide an overview of tasks that were taken
* by drush.
*/
/**
* Add a log message to the log history.
*
* This function calls the callback stored in the 'DRUSH_LOG_CALLBACK' context with
* the resulting entry at the end of execution.
*
* This allows you to replace it with custom logging implementations if needed,
* such as logging to a file or logging to a database (drupal or otherwise).
*
* The default callback is the Drush\Log\Logger class with prints the messages
* to the shell.
*
* @param message
* String containing the message to be logged.
* @param type
* The type of message to be logged. Common types are 'warning', 'error', 'success' and 'notice'.
* A type of 'ok' or 'success' can also be supplied to flag something that worked.
* If you want your log messages to print to screen without the user entering
* a -v or --verbose flag, use type 'ok' or 'notice', this prints log messages out to
* STDERR, which prints to screen (unless you have redirected it). All other
* types of messages will be assumed to be info.
*
* @deprecated
* Use this->logger()->warning (for example) from an Annotated command method.
*/
function drush_log($message, $type = LogLevel::INFO, $error = null) {
$entry = [
'type' => $type,
'message' => $message,
'timestamp' => microtime(TRUE),
'memory' => memory_get_usage(),
];
$entry['error'] = $error;
return _drush_log($entry);
}
/**
* Call the default logger, or the user's log callback, as
* appropriate.
*/
function _drush_log($entry) {
$callback = drush_get_context('DRUSH_LOG_CALLBACK');
if (!$callback) {
$callback = Drush::logger();
}
if ($callback instanceof LoggerInterface) {
_drush_log_to_logger($callback, $entry);
}
elseif ($callback) {
$log =& drush_get_context('DRUSH_LOG', []);
$log[] = $entry;
drush_backend_packet('log', $entry);
return $callback($entry);
}
}
// Maintain compatibility with extensions that hook into
// DRUSH_LOG_CALLBACK (e.g. drush_ctex_bonus)
function _drush_print_log($entry) {
$drush_logger = Drush::logger();
if ($drush_logger) {
_drush_log_to_logger($drush_logger, $entry);
}
}
function _drush_log_to_logger($logger, $entry) {
$context = $entry;
$log_level = $entry['type'];
$message = $entry['message'];
unset($entry['type']);
unset($entry['message']);
$logger->log($log_level, $message, $context);
}
function drush_log_has_errors($types = [LogLevel::WARNING, LogLevel::ERROR, LogLevel::FAILED]) {
$log =& drush_get_context('DRUSH_LOG', []);
foreach ($log as $entry) {
if (in_array($entry['type'], $types)) {
return TRUE;
}
}
return FALSE;
}
/**
* Backend command callback. Add a log message to the log history.
*
* @param entry
* The log entry.
*/
function drush_backend_packet_log($entry, $backend_options) {
if (!$backend_options['log']) {
return;
}
if (!is_string($entry['message'])) {
$entry['message'] = implode("\n", (array)$entry['message']);
}
$entry['message'] = $entry['message'];
if (array_key_exists('#output-label', $backend_options)) {
$entry['message'] = $backend_options['#output-label'] . $entry['message'];
}
// If integrate is FALSE, then log messages are stored in DRUSH_LOG,
// but are -not- printed to the console.
if ($backend_options['integrate']) {
_drush_log($entry);
}
else {
$log =& drush_get_context('DRUSH_LOG', []);
$log[] = $entry;
// Yes, this looks odd, but we might in fact be a backend command
// that ran another backend command.
drush_backend_packet('log', $entry);
}
}
/**
* Retrieve the log messages from the log history
*
* @return
* Entire log history
*/
function drush_get_log() {
return drush_get_context('DRUSH_LOG', []);
}
/**
* Run print_r on a variable and log the output.
*/
function dlm($object) {
drush_log(print_r($object, TRUE));
}
// Copy of format_size() in Drupal.
function drush_format_size($size) {
if ($size < DRUSH_KILOBYTE) {
// format_plural() not always available.
return dt('@count bytes', ['@count' => $size]);
}
else {
$size = $size / DRUSH_KILOBYTE; // Convert bytes to kilobytes.
$units = [
dt('@size KB', []),
dt('@size MB', []),
dt('@size GB', []),
dt('@size TB', []),
dt('@size PB', []),
dt('@size EB', []),
dt('@size ZB', []),
dt('@size YB', []),
];
foreach ($units as $unit) {
if (round($size, 2) >= DRUSH_KILOBYTE) {
$size = $size / DRUSH_KILOBYTE;
}
else {
break;
}
}
return str_replace('@size', round($size, 2), $unit);
}
}
/**
* @} End of "defgroup logging".
*/
/**
* @defgroup errorhandling Managing errors that occur in the Drush framework.
* @{
* Functions that manage the current error status of the Drush framework.
*
* These functions operate by maintaining a static variable that is a equal to the constant DRUSH_FRAMEWORK_ERROR if an
* error has occurred.
* This error code is returned at the end of program execution, and provide the shell or calling application with
* more information on how to diagnose any problems that may have occurred.
*/
/**
* Set an error code for the error handling system.
*
* @param \Drupal\Component\Render\MarkupInterface|string $error
* A text string identifying the type of error.
* @param null|string $message
* Optional. Error message to be logged. If no message is specified,
* hook_drush_help will be consulted, using a key of 'error:MY_ERROR_STRING'.
* @param null|string $output_label
* Optional. Label to prepend to the error message.
*
* @return bool
* Always returns FALSE, to allow returning false in the calling functions,
* such as <code>return drush_set_error('DRUSH_FRAMEWORK_ERROR')</code>.
*/
function drush_set_error($error, $message = null, $output_label = "") {
$error_code =& drush_get_context('DRUSH_ERROR_CODE', DRUSH_SUCCESS);
$error_code = DRUSH_FRAMEWORK_ERROR;
$error_log =& drush_get_context('DRUSH_ERROR_LOG', []);
if (is_numeric($error)) {
$error = 'DRUSH_FRAMEWORK_ERROR';
}
elseif (!is_string($error)) {
// Typical case: D8 TranslatableMarkup, implementing MarkupInterface.
$error = "$error";
}
$message = ($message) ? $message : ''; // drush_command_invoke_all('drush_help', 'error:' . $error);
if (is_array($message)) {
$message = implode("\n", $message);
}
$error_log[$error][] = $message;
if (!drush_backend_packet('set_error', ['error' => $error, 'message' => $message])) {
drush_log(($message) ? $output_label . $message : $output_label . $error, LogLevel::ERROR, $error);
}
return FALSE;
}
/**
* Return the current error handling status
*
* @return
* The current aggregate error status
*/
function drush_get_error() {
return drush_get_context('DRUSH_ERROR_CODE', DRUSH_SUCCESS);
}
/**
* Return the current list of errors that have occurred.
*
* @return
* An associative array of error messages indexed by the type of message.
*/
function drush_get_error_log() {
return drush_get_context('DRUSH_ERROR_LOG', []);
}
/**
* Check if a specific error status has been set.
*
* @param error
* A text string identifying the error that has occurred.
* @return
* TRUE if the specified error has been set, FALSE if not
*/
function drush_cmp_error($error) {
$error_log = drush_get_error_log();
if (is_numeric($error)) {
$error = 'DRUSH_FRAMEWORK_ERROR';
}
return array_key_exists($error, $error_log);
}
/**
* Clear error context.
*/
function drush_clear_error() {
drush_set_context('DRUSH_ERROR_CODE', DRUSH_SUCCESS);
}
/**
* Turn PHP error handling off.
*
* This is commonly used while bootstrapping Drupal for install
* or updates.
*
* This also records the previous error_reporting setting, in
* case it wasn't recorded previously.
*
* @see drush_errors_off()
*/
function drush_errors_off() {
drush_get_context('DRUSH_ERROR_REPORTING', error_reporting(0));
ini_set('display_errors', FALSE);
}
/**
* Turn PHP error handling on.
*
* We default to error_reporting() here just in
* case drush_errors_on() is called before drush_errors_off() and
* the context is not yet set.
*
* @arg $errors string
* The default error level to set in drush. This error level will be
* carried through further drush_errors_on()/off() calls even if not
* provided in later calls.
*
* @see error_reporting()
* @see drush_errors_off()
*/
function drush_errors_on($errors = null) {
if (!isset($errors)) {
$errors = error_reporting();
}
else {
drush_set_context('DRUSH_ERROR_REPORTING', $errors);
}
error_reporting(drush_get_context('DRUSH_ERROR_REPORTING', $errors));
ini_set('display_errors', TRUE);
}
/**
* @} End of "defgroup errorhandling".
*/
/**
* Get the PHP memory_limit value in bytes.
*/
function drush_memory_limit() {
$value = trim(ini_get('memory_limit'));
$last = strtolower($value[strlen($value)-1]);
$size = (int) substr($value, 0, -1);
switch ($last) {
case 'g':
$size *= DRUSH_KILOBYTE;
case 'm':
$size *= DRUSH_KILOBYTE;
case 'k':
$size *= DRUSH_KILOBYTE;
}
return $size;
}
/**
* Form an associative array from a linear array.
*
* This function walks through the provided array and constructs an associative
* array out of it. The keys of the resulting array will be the values of the
* input array. The values will be the same as the keys unless a function is
* specified, in which case the output of the function is used for the values
* instead.
*
* @param $array
* A linear array.
* @param $function
* A name of a function to apply to all values before output.
*
* @return
* An associative array.
*/
function drush_map_assoc($array, $function = NULL) {
// array_combine() fails with empty arrays:
// http://bugs.php.net/bug.php?id=34857.
$array = !empty($array) ? array_combine($array, $array) : [];
if (is_callable($function)) {
$array = array_map($function, $array);
}
return $array;
}

View file

@ -0,0 +1,297 @@
<?php
/**
* @file
* Functions used by drush to query the environment and
* setting the current configuration.
*
* Bootstrapping now occurs in bootstrap.inc.
*
* @see includes/bootstrap.inc
*/
use Drush\Drush;
use Drush\Log\LogLevel;
use Webmozart\PathUtil\Path;
/**
* Log PHP errors to the Drush log. This is in effect until Drupal's error
* handler takes over.
*/
function drush_error_handler($errno, $message, $filename, $line, $context) {
// E_DEPRECATED was added in PHP 5.3. Drupal 6 will not fix all the
// deprecated errors, but suppresses them. So we suppress them as well.
if (defined('E_DEPRECATED')) {
$errno = $errno & ~E_DEPRECATED;
}
// "error_reporting" is usually set in php.ini, but may be changed by
// drush_errors_on() and drush_errors_off().
if ($errno & error_reporting()) {
// By default we log notices.
$type = Drush::config()->get('runtime.php.notices', LogLevel::INFO);
$halt_on_error = Drush::config()->get('runtime.php.halt-on-error', (drush_drupal_major_version() != 6));
// Bitmask value that constitutes an error needing to be logged.
$error = E_ERROR | E_PARSE | E_CORE_ERROR | E_COMPILE_ERROR | E_USER_ERROR | E_RECOVERABLE_ERROR;
if ($errno & $error) {
$type = 'error';
}
// Bitmask value that constitutes a warning being logged.
$warning = E_WARNING | E_CORE_WARNING | E_COMPILE_WARNING | E_USER_WARNING;
if ($errno & $warning) {
$type = LogLevel::WARNING;
}
drush_log($message . ' ' . basename($filename) . ':' . $line, $type);
if ($errno == E_RECOVERABLE_ERROR && $halt_on_error) {
drush_log(dt('E_RECOVERABLE_ERROR encountered; aborting. To ignore recoverable errors, run again with --no-halt-on-error'), 'error');
exit(DRUSH_APPLICATION_ERROR);
}
return TRUE;
}
}
/**
* Evalute the environment after an abnormal termination and
* see if we can determine any configuration settings that the user might
* want to adjust.
*/
function _drush_postmortem() {
// Make sure that the memory limit has been bumped up from the minimum default value of 32M.
$php_memory_limit = drush_memory_limit();
if (($php_memory_limit > 0) && ($php_memory_limit <= 32*DRUSH_KILOBYTE*DRUSH_KILOBYTE)) {
drush_set_error('DRUSH_MEMORY_LIMIT', dt('Your memory limit is set to !memory_limit; Drush needs as much memory to run as Drupal. !php_ini_msg', ['!memory_limit' => $php_memory_limit / (DRUSH_KILOBYTE*DRUSH_KILOBYTE) . 'M', '!php_ini_msg' => _drush_php_ini_loaded_file_message()]));
}
}
/**
* Converts a Windows path (dir1\dir2\dir3) into a Unix path (dir1/dir2/dir3).
* Also converts a cygwin "drive emulation" path (/cygdrive/c/dir1) into a
* proper drive path, still with Unix slashes (c:/dir1).
*/
function _drush_convert_path($path) {
$path = str_replace('\\','/', $path);
if (drush_is_windows() && !drush_is_cygwin()) {
$path = preg_replace('/^\/cygdrive\/([A-Za-z])(.*)$/', '\1:\2', $path);
}
return $path;
}
/**
* Build a drush command suitable for use for Drush to call itself.
* Used in backend_invoke.
*/
function drush_build_drush_command($drush_path = NULL, $php = NULL, $os = NULL, $remote_command = FALSE, $environment_variables = []) {
$os = _drush_get_os($os);
$additional_options = '';
$prefix = '';
if (!$drush_path) {
if (!$remote_command) {
$drush_path = DRUSH_COMMAND;
}
else {
$drush_path = 'drush'; // drush_is_windows($os) ? 'drush.bat' : 'drush';
}
}
// If the path to drush points to drush.php, then we will need to
// run it via php rather than direct execution. By default, we
// will use 'php' unless something more specific was passed in
// via the --php flag.
if (substr($drush_path, -4) == ".php") {
if (!isset($php)) {
$php = Drush::config()->get('php', 'php');
}
if (isset($php) && ($php != "php")) {
$additional_options .= ' --php=' . drush_escapeshellarg($php, $os);
}
// We will also add in the php options from --php-options
$prefix .= drush_escapeshellarg($php, $os);
$php_options = implode(' ', drush_get_context_options('php-options'));
if (!empty($php_options)) {
$prefix .= ' ' . $php_options;
$additional_options .= ' --php-options=' . drush_escapeshellarg($php_options, $os);
}
}
else {
// Set environment variables to propogate config to redispatched calls.
if (drush_has_bash($os)) {
if ($php) {
$environment_variables['DRUSH_PHP'] = $php;
}
if ($php_options_alias = drush_get_option('php-options', NULL, 'alias')) {
$environment_variables['PHP_OPTIONS'] = $php_options_alias;
}
$columns = drush_get_context('DRUSH_COLUMNS');
if (($columns) && ($columns != 80)) {
$environment_variables['COLUMNS'] = $columns;
}
}
}
// Add environmental variables, if present
if (!empty($environment_variables)) {
$prefix .= ' env';
foreach ($environment_variables as $key=>$value) {
$prefix .= ' ' . drush_escapeshellarg($key, $os) . '=' . drush_escapeshellarg($value, $os);
}
}
return trim($prefix . ' ' . drush_escapeshellarg($drush_path, $os) . $additional_options);
}
/**
* Check if the operating system is Winodws
* running some variant of cygwin -- either
* Cygwin or the MSYSGIT shell. If you care
* which is which, test mingw first.
*/
function drush_is_cygwin($os = NULL) {
return _drush_test_os($os, ["CYGWIN","CWRSYNC","MINGW"]);
}
function drush_is_mingw($os = NULL) {
return _drush_test_os($os, ["MINGW"]);
}
/**
* Check if the operating system is OS X.
* This will return TRUE for Mac OS X (Darwin).
*/
function drush_is_osx($os = NULL) {
return _drush_test_os($os, ["DARWIN"]);
}
/**
* Checks if the operating system has bash.
*
* MinGW has bash, but PHP isn't part of MinGW and hence doesn't run in bash.
*/
function drush_has_bash($os = NULL) {
return (drush_is_cygwin($os) && !drush_is_mingw($os)) || !drush_is_windows($os);
}
/**
* Checks operating system and returns supported bit bucket folder.
*/
function drush_bit_bucket() {
return drush_has_bash() ? '/dev/null' : 'nul';
}
/**
* Return the OS we are running under.
*
* @return string
* Linux
* WIN* (e.g. WINNT)
* CYGWIN
* MINGW* (e.g. MINGW32)
*/
function _drush_get_os($os = NULL) {
// In most cases, $os will be NULL and PHP_OS will be returned. However, if an
// OS is specified in $os, return that instead.
return $os ?: PHP_OS;
}
function _drush_test_os($os, $os_list_to_check) {
$os = _drush_get_os($os);
foreach ($os_list_to_check as $test) {
if (strtoupper(substr($os, 0, strlen($test))) == strtoupper($test)) {
return TRUE;
}
}
return FALSE;
}
/**
* Make a determination whether or not the given
* host is local or not.
*
* @param host
* A hostname, 'localhost' or '127.0.0.1'.
* @return
* True if the host is local.
*/
function drush_is_local_host($host) {
// Check to see if the provided host is "local".
// @see hook_drush_sitealias_alter() in drush.api.php.
return $host == 'localhost' || $host == '127.0.0.1';
}
/**
* Determine whether current OS is a Windows variant.
*/
function drush_is_windows($os = NULL) {
return strtoupper(substr(_drush_get_os($os), 0, 3)) === 'WIN';
}
function drush_escapeshellarg($arg, $os = NULL, $raw = FALSE) {
// Short-circuit escaping for simple params (keep stuff readable)
if (preg_match('|^[a-zA-Z0-9.:/_-]*$|', $arg)) {
return $arg;
}
elseif (drush_is_windows($os)) {
return _drush_escapeshellarg_windows($arg, $raw);
}
else {
return _drush_escapeshellarg_linux($arg, $raw);
}
}
/**
* Linux version of escapeshellarg().
*
* This is intended to work the same way that escapeshellarg() does on
* Linux. If we need to escape a string that will be used remotely on
* a Linux system, then we need our own implementation of escapeshellarg,
* because the Windows version behaves differently.
*/
function _drush_escapeshellarg_linux($arg, $raw = FALSE) {
// For single quotes existing in the string, we will "exit"
// single-quote mode, add a \' and then "re-enter"
// single-quote mode. The result of this is that
// 'quote' becomes '\''quote'\''
$arg = preg_replace('/\'/', '\'\\\'\'', $arg);
// Replace "\t", "\n", "\r", "\0", "\x0B" with a whitespace.
// Note that this replacement makes Drush's escapeshellarg work differently
// than the built-in escapeshellarg in PHP on Linux, as these characters
// usually are NOT replaced. However, this was done deliberately to be more
// conservative when running _drush_escapeshellarg_linux on Windows
// (this can happen when generating a command to run on a remote Linux server.)
$arg = str_replace(["\t", "\n", "\r", "\0", "\x0B"], ' ', $arg);
// Only wrap with quotes when needed.
if(!$raw) {
// Add surrounding quotes.
$arg = "'" . $arg . "'";
}
return $arg;
}
/**
* Windows version of escapeshellarg().
*/
function _drush_escapeshellarg_windows($arg, $raw = FALSE) {
// Double up existing backslashes
$arg = preg_replace('/\\\/', '\\\\\\\\', $arg);
// Double up double quotes
$arg = preg_replace('/"/', '""', $arg);
// Double up percents.
// $arg = preg_replace('/%/', '%%', $arg);
// Only wrap with quotes when needed.
if(!$raw) {
// Add surrounding quotes.
$arg = '"' . $arg . '"';
}
return $arg;
}

409
vendor/drush/drush/includes/exec.inc vendored Normal file
View file

@ -0,0 +1,409 @@
<?php
/**
* @file
* Functions for executing system commands. (e.g. exec(), system(), ...).
*/
use Drush\Drush;
use Drush\Log\LogLevel;
use \Consolidation\SiteAlias\AliasRecord;
/**
* @defgroup commandwrappers Functions to execute commands.
* @{
*/
/**
* Calls 'system()' function, passing through all arguments unchanged.
*
* This should be used when calling possibly mutative or destructive functions
* (e.g. unlink() and other file system functions) so that can be suppressed
* if the simulation mode is enabled.
*
* @param $exec
* The shell command to execute. Parameters should already be escaped.
* @return
* The result code from system(): 0 == success.
*
* @see drush_shell_exec()
*/
function drush_op_system($exec) {
if (Drush::verbose() || Drush::simulate()) {
drush_print("Calling system($exec);", 0, STDERR);
}
if (Drush::simulate()) {
return 0;
}
// Throw away output. Use drush_shell_exec() to capture output.
system($exec, $result_code);
return $result_code;
}
/**
* Executes a shell command at a new working directory.
* The old cwd is restored on exit.
*
* @param $effective_wd
* The new working directory to execute the shell command at.
* @param $cmd
* The command to execute. May include placeholders used for sprintf.
* @param ...
* Values for the placeholders specified in $cmd. Each of these will be passed through escapeshellarg() to ensure they are safe to use on the command line.
* @return
* TRUE on success, FALSE on failure
*/
function drush_shell_cd_and_exec($effective_wd, $cmd) {
$args = func_get_args();
$effective_wd = array_shift($args);
$cwd = getcwd();
drush_op('chdir', $effective_wd);
$result = call_user_func_array('drush_shell_exec', $args);
drush_op('chdir', $cwd);
return $result;
}
/**
* Executes a shell command.
* Output is only printed if in verbose mode.
* Output is stored and can be retrieved using drush_shell_exec_output().
* If in simulation mode, no action is taken.
*
* @param $cmd
* The command to execute. May include placeholders used for sprintf.
* @param ...
* Values for the placeholders specified in $cmd. Each of these will be passed through escapeshellarg() to ensure they are safe to use on the command line.
* @return
* TRUE on success, FALSE on failure
*/
function drush_shell_exec($cmd) {
return _drush_shell_exec(func_get_args(), FALSE, Drush::simulate());
}
/**
* A version of drush_shell_exec() that ignores simulate mode
*/
function drush_always_exec($cmd) {
return _drush_shell_exec(func_get_args(), FALSE, FALSE);
}
/**
* Returns executable code for invoking preferred test editor.
*
* The next line after calling this function is usually
* @code drush_shell_exec_interactive($exec, $filepath, $filepath) @endcode
*
* @see drush_config_edit()
*/
function drush_get_editor() {
$bg = drush_get_option('bg') ? '&' : '';
// see http://drupal.org/node/1740294
$exec = drush_get_option('editor', '${VISUAL-${EDITOR-vi}}') . " %s $bg";
return $exec;
}
/**
* Executes a command in interactive mode.
*
* @see drush_shell_exec.
*/
function drush_shell_exec_interactive($cmd) {
return _drush_shell_exec(func_get_args(), TRUE, Drush::simulate());
}
/**
* Internal function: executes a shell command on the
* local machine. This function should not be used
* in instances where ssh is utilized to execute a
* command remotely; otherwise, remote operations would
* fail if executed from a Windows machine to a remote
* Linux server.
*
* @param $args
* The command and its arguments.
* @param $interactive
* Whether to run in
*
* @return
* TRUE on success, FALSE on failure
*
* @see drush_shell_exec.
*/
function _drush_shell_exec($args, $interactive = FALSE, $simulate = false) {
// Do not change the command itself, just the parameters.
for ($x = 1; $x < count($args); $x++) {
$args[$x] = drush_escapeshellarg($args[$x]);
}
// Important: we allow $args to take one of two forms here. If
// there is only one item in the array, it is the already-escaped
// command string, but otherwise sprintf is used. In the case
// of pre-escaped strings, sprintf will fail if any of the escaped
// parameters contain '%', so we must not call sprintf unless necessary.
if (count($args) == 1) {
$command = $args[0];
}
else {
$command = call_user_func_array('sprintf', $args);
}
drush_log('Executing: ' . $command, LogLevel::INFO);
if (!$simulate) {
if ($interactive) {
$result = drush_shell_proc_open($command);
return ($result == 0) ? TRUE : FALSE;
}
else {
exec($command . ' 2>&1', $output, $result);
_drush_shell_exec_output_set($output);
if (Drush::debug()) {
foreach ($output as $line) {
drush_print($line, 2);
}
}
// Exit code 0 means success.
return ($result == 0);
}
}
else {
return TRUE;
}
}
/**
* Determine whether 'which $command' can find
* a command on this system.
*/
function drush_which($command) {
exec("which $command 2>&1", $output, $result);
return ($result == 0);
}
/**
* Build an SSH string including an optional fragment of bash. Commands that use
* this should also merge drush_shell_proc_build_options() into their
* command options. @see ssh_drush_command().
*
* @param array $site
* A site alias record.
* @param string $command
* An optional bash fragment.
* @param string $cd
* An optional directory to change into before executing the $command. Set to
* boolean TRUE to change into $site['root'] if available.
* @param boolean $interactive
* Force creation of a tty
* @return string
* A string suitable for execution with drush_shell_remote_exec().
*
*/
function drush_shell_proc_build(AliasRecord $site, $command = '', $cd = NULL, $interactive = FALSE) {
// Build up the command. TODO: We maybe refactor this soon.
$hostname = $site->remoteHostWithUser();
$ssh_options = $site->getConfig(Drush::config(), 'ssh.options', "-o PasswordAuthentication=no");
$os = drush_os($site);
if ($site->get('tty') || $interactive) {
$ssh_options .= ' -t';
}
$cmd = "ssh " . $ssh_options . " " . $hostname;
if ($cd === TRUE) {
if ($site->hasRoot()) {
$cd = $site->root();
}
else {
$cd = FALSE;
}
}
if ($cd) {
$command = 'cd ' . drush_escapeshellarg($cd, $os) . ' && ' . $command;
}
if (!empty($command)) {
$cmd .= " " . drush_escapeshellarg($command, $os);
}
return $cmd;
}
/**
* Execute bash command using proc_open().
*
* @returns
* Exit code from launched application
* 0 no error
* 1 general error
* 127 command not found
*/
function drush_shell_proc_open($cmd) {
if (Drush::verbose() || Drush::simulate()) {
drush_print("Calling proc_open($cmd);", 0, STDERR);
}
if (!Drush::simulate()) {
$process = proc_open($cmd, [0 => STDIN, 1 => STDOUT, 2 => STDERR], $pipes);
$proc_status = proc_get_status($process);
$exit_code = proc_close($process);
return ($proc_status["running"] ? $exit_code : $proc_status["exitcode"] );
}
return 0;
}
/**
* Determine the appropriate os value for the
* specified site record
*
* @returns
* NULL for 'same as local machine', 'Windows' or 'Linux'.
*/
function drush_os($site_record = NULL) {
if (!$site_record instanceof AliasRecord) {
return legacy_drush_os($site_record);
}
// n.b. $options['remote-os'] has become 'ssh.os' in drush.yml
return $site_record->getConfig(Drush::config(), 'ssh.os', 'Linux');
}
function legacy_drush_os($site_record = NULL) {
// Default to $os = NULL, meaning 'same as local machine'
$os = NULL;
// If the site record has an 'os' element, use it
if (isset($site_record) && array_key_exists('os', $site_record)) {
$os = $site_record['os'];
}
// Otherwise, we will assume that all remote machines are Linux
// (or whatever value 'remote-os' is set to in drush.yml).
elseif (isset($site_record) && array_key_exists('remote-host', $site_record) && !empty($site_record['remote-host'])) {
$os = Drush::config()->get('ssh.os', 'Linux');
}
return $os;
}
/**
* Make an attempt to simply wrap the arg with the
* kind of quote characters it does not already contain.
* If it contains both kinds, then this function reverts to drush_escapeshellarg.
*/
function drush_wrap_with_quotes($arg) {
$has_double = strpos($arg, '"') !== FALSE;
$has_single = strpos($arg, "'") !== FALSE;
if ($has_double && $has_single) {
return drush_escapeshellarg($arg);
}
elseif ($has_double) {
return "'" . $arg . "'";
}
else {
return '"' . $arg . '"';
}
}
/**
* Platform-dependent version of escapeshellarg().
* Given the target platform, return an appropriately-escaped
* string. The target platform may be omitted for args that
* are /known/ to be for the local machine.
* Use raw to get an unquoted version of the escaped arg.
* Notice that you can't add quotes later until you know the platform.
*/
/**
* Stores output for the most recent shell command.
* This should only be run from drush_shell_exec().
*
* @param array|bool $output
* The output of the most recent shell command.
* If this is not set the stored value will be returned.
*/
function _drush_shell_exec_output_set($output = FALSE) {
static $stored_output;
if ($output === FALSE) return $stored_output;
$stored_output = $output;
}
/**
* Returns the output of the most recent shell command as an array of lines.
*/
function drush_shell_exec_output() {
return _drush_shell_exec_output_set();
}
/**
* Starts a background browser/tab for the current site or a specified URL.
*
* Uses a non-blocking proc_open call, so Drush execution will continue.
*
* @param $uri
* Optional URI or site path to open in browser. If omitted, or if a site path
* is specified, the current site home page uri will be prepended if the sites
* hostname resolves.
* @return
* TRUE if browser was opened, FALSE if browser was disabled by the user or a,
* default browser could not be found.
*/
function drush_start_browser($uri = NULL, $sleep = FALSE, $port = FALSE, $browser = true) {
if ($browser) {
// We can only open a browser if we have a DISPLAY environment variable on
// POSIX or are running Windows or OS X.
if (!Drush::simulate() && !getenv('DISPLAY') && !drush_is_windows() && !drush_is_osx()) {
drush_log(dt('No graphical display appears to be available, not starting browser.'), LogLevel::INFO);
return FALSE;
}
$host = parse_url($uri, PHP_URL_HOST);
if (!$host) {
// Build a URI for the current site, if we were passed a path.
$site = drush_get_context('DRUSH_URI');
$host = parse_url($site, PHP_URL_HOST);
$uri = $site . '/' . ltrim($uri, '/');
}
// Validate that the host part of the URL resolves, so we don't attempt to
// open the browser for http://default or similar invalid hosts.
$hosterror = (gethostbynamel($host) === FALSE);
$iperror = (ip2long($host) && gethostbyaddr($host) == $host);
if (!Drush::simulate() && ($hosterror || $iperror)) {
drush_log(dt('!host does not appear to be a resolvable hostname or IP, not starting browser. You may need to use the --uri option in your command or site alias to indicate the correct URL of this site.', ['!host' => $host]), LogLevel::WARNING);
return FALSE;
}
if ($port) {
$uri = str_replace($host, "localhost:$port", $uri);
}
if ($browser === TRUE) {
// See if we can find an OS helper to open URLs in default browser.
if (drush_shell_exec('which xdg-open')) {
$browser = 'xdg-open';
}
else if (drush_shell_exec('which open')) {
$browser = 'open';
}
else if (!drush_has_bash()) {
$browser = 'start';
}
else {
// Can't find a valid browser.
$browser = FALSE;
}
}
$prefix = '';
if ($sleep) {
$prefix = 'sleep ' . $sleep . ' && ';
}
if ($browser) {
drush_log(dt('Opening browser !browser at !uri', ['!browser' => $browser, '!uri' => $uri]));
if (!Drush::simulate()) {
$pipes = [];
proc_close(proc_open($prefix . $browser . ' ' . drush_escapeshellarg($uri) . ' 2> ' . drush_bit_bucket() . ' &', [], $pipes));
}
return TRUE;
}
}
return FALSE;
}
/**
* @} End of "defgroup commandwrappers".
*/

View file

@ -0,0 +1,361 @@
<?php
/**
* @file
* Filesystem utilities.
*/
use Drush\Drush;
use Drush\Sql\SqlBase;
use Symfony\Component\Filesystem\Filesystem;
use Webmozart\PathUtil\Path;
/**
* @defgroup filesystemfunctions Filesystem convenience functions.
* @{
*/
/**
* Behavior for drush_copy_dir() when destinations exist.
*/
define('FILE_EXISTS_ABORT', 0);
define('FILE_EXISTS_OVERWRITE', 1);
define('FILE_EXISTS_MERGE', 2);
/**
* Deletes the specified file or directory and everything inside it.
*
* Usually respects read-only files and folders. To do a forced delete use
* drush_delete_tmp_dir() or set the parameter $forced.
*
* @param string $dir
* The file or directory to delete.
* @param bool $force
* Whether or not to try everything possible to delete the directory, even if
* it's read-only. Defaults to FALSE.
* @param bool $follow_symlinks
* Whether or not to delete symlinked files. Defaults to FALSE--simply
* unlinking symbolic links.
*
* @return bool
* FALSE on failure, TRUE if everything was deleted.
*
* @deprecated Use \Symfony\Component\Filesystem\Filesystem::remove.
*/
function drush_delete_dir($dir, $force = FALSE, $follow_symlinks = FALSE) {
// Do not delete symlinked files, only unlink symbolic links
if (is_link($dir) && !$follow_symlinks) {
return unlink($dir);
}
// Allow to delete symlinks even if the target doesn't exist.
if (!is_link($dir) && !file_exists($dir)) {
return TRUE;
}
if (!is_dir($dir)) {
if ($force) {
// Force deletion of items with readonly flag.
@chmod($dir, 0777);
}
return unlink($dir);
}
if (drush_delete_dir_contents($dir, $force) === FALSE) {
return FALSE;
}
if ($force) {
// Force deletion of items with readonly flag.
@chmod($dir, 0777);
}
return rmdir($dir);
}
/**
* Deletes the contents of a directory.
*
* @param string $dir
* The directory to delete.
* @param bool $force
* Whether or not to try everything possible to delete the contents, even if
* they're read-only. Defaults to FALSE.
*
* @return bool
* FALSE on failure, TRUE if everything was deleted.
*/
function drush_delete_dir_contents($dir, $force = FALSE) {
$scandir = @scandir($dir);
if (!is_array($scandir)) {
return FALSE;
}
foreach ($scandir as $item) {
if ($item == '.' || $item == '..') {
continue;
}
if ($force) {
@chmod($dir, 0777);
}
if (!drush_delete_dir($dir . '/' . $item, $force)) {
return FALSE;
}
}
return TRUE;
}
/**
* Copy $src to $dest.
*
* @param $src
* The directory to copy.
* @param $dest
* The destination to copy the source to, including the new name of
* the directory. To copy directory "a" from "/b" to "/c", then
* $src = "/b/a" and $dest = "/c/a". To copy "a" to "/c" and rename
* it to "d", then $dest = "/c/d".
* @param $overwrite
* Action to take if destination already exists.
* - FILE_EXISTS_OVERWRITE - completely removes existing directory.
* - FILE_EXISTS_ABORT - aborts the operation.
* - FILE_EXISTS_MERGE - Leaves existing files and directories in place.
* @return
* TRUE on success, FALSE on failure.
*
* @deprecated Use \Symfony\Component\Filesystem\Filesystem::copy.
*/
function drush_copy_dir($src, $dest, $overwrite = FILE_EXISTS_ABORT) {
// Preflight based on $overwrite if $dest exists.
if (file_exists($dest)) {
if ($overwrite === FILE_EXISTS_OVERWRITE) {
drush_op('drush_delete_dir', $dest, TRUE);
}
elseif ($overwrite === FILE_EXISTS_ABORT) {
return drush_set_error('DRUSH_DESTINATION_EXISTS', dt('Destination directory !dest already exists.', array('!dest' => $dest)));
}
elseif ($overwrite === FILE_EXISTS_MERGE) {
// $overwrite flag may indicate we should merge instead.
drush_log(dt('Merging existing !dest directory', array('!dest' => $dest)));
}
}
// $src readable?
if (!is_readable($src)) {
return drush_set_error('DRUSH_SOURCE_NOT_EXISTS', dt('Source directory !src is not readable or does not exist.', array('!src' => $src)));
}
// $dest writable?
if (!is_writable(dirname($dest))) {
return drush_set_error('DRUSH_DESTINATION_NOT_WRITABLE', dt('Destination directory !dest is not writable.', array('!dest' => dirname($dest))));
}
// Try to do a recursive copy.
if (@_drush_recursive_copy($src, $dest)) {
return TRUE;
}
return drush_set_error('DRUSH_COPY_DIR_FAILURE', dt('Unable to copy !src to !dest.', array('!src' => $src, '!dest' => $dest)));
}
/**
* Internal function called by drush_copy_dir; do not use directly.
*/
function _drush_recursive_copy($src, $dest) {
// all subdirectories and contents:
if(is_dir($src)) {
if (!mkdir($dest)) {
return FALSE;
}
$dir_handle = opendir($src);
while($file = readdir($dir_handle)) {
if ($file != "." && $file != "..") {
if (_drush_recursive_copy("$src/$file", "$dest/$file") !== TRUE) {
return FALSE;
}
}
}
closedir($dir_handle);
}
elseif (is_link($src)) {
symlink(readlink($src), $dest);
}
elseif (!copy($src, $dest)) {
return FALSE;
}
// Preserve file modification time.
// https://github.com/drush-ops/drush/pull/1146
touch($dest, filemtime($src));
// Preserve execute permission.
if (!is_link($src) && (!function_exists('drush_is_windows') || !drush_is_windows())) {
// Get execute bits of $src.
$execperms = fileperms($src) & 0111;
// Apply execute permissions if any.
if ($execperms > 0) {
$perms = fileperms($dest) | $execperms;
chmod($dest, $perms);
}
}
return TRUE;
}
/**
* Recursively create a directory tree.
*
* @param path
* Path to directory to create.
*
* @throws IOException On any directory creation failure
* @deprecated See \Symfony\Component\Filesystem\Filesystem::mkdir.
*/
function drush_mkdir($path) {
$fs = new Filesystem();
$fs->mkdir($path);
return true;
}
/*
* Determine if program exists on user's PATH.
*
* @return bool|null
*/
function drush_program_exists($program) {
if (drush_has_bash()) {
$bucket = drush_bit_bucket();
// Remove environment variables (eg. PGPASSFILE=) before testing program.
$program = preg_replace('#^([A-Z0-9]+=.+? )+#', '', $program);
// Dont't use drush_op_system() since we don't want output during tests.
system("command -v $program > $bucket 2>&1", $result_code);
return $result_code === 0 ? TRUE : FALSE;
}
}
/**
* Save a string to a temporary file. Does not depend on Drupal's API.
* The temporary file will be automatically deleted when drush exits.
*
* @param string $data
* @param string $suffix
* Append string to filename. use of this parameter if is discouraged. @see
* drush_tempnam().
* @return string
* A path to the file.
*/
function drush_save_data_to_temp_file($data, $suffix = NULL) {
static $fp;
$file = drush_tempnam('drush_', NULL, $suffix);
$fp = fopen($file, "w");
fwrite($fp, $data);
$meta_data = stream_get_meta_data($fp);
$file = $meta_data['uri'];
fclose($fp);
return $file;
}
/**
* Returns the path to a temporary directory.
*
* @deprecated Use $this->getConfig()->tmp() in a ConfigAware command.
*/
function drush_find_tmp() {
return Drush::config()->tmp();
}
/**
* Creates a temporary file, and registers it so that
* it will be deleted when drush exits. Whenever possible,
* drush_save_data_to_temp_file() should be used instead
* of this function.
*
* @param string $suffix
* Append this suffix to the filename. Use of this parameter is discouraged as
* it can break the guarantee of tempname(). See http://www.php.net/manual/en/function.tempnam.php#42052.
* Originally added to support Oracle driver.
*/
function drush_tempnam($pattern, $tmp_dir = NULL, $suffix = '') {
if ($tmp_dir == NULL) {
$tmp_dir = Drush::config()->tmp();
}
$tmp_file = tempnam($tmp_dir, $pattern);
drush_register_file_for_deletion($tmp_file);
$tmp_file_with_suffix = $tmp_file . $suffix;
drush_register_file_for_deletion($tmp_file_with_suffix);
return $tmp_file_with_suffix;
}
/**
* Creates a temporary directory and return its path.
*/
function drush_tempdir() {
$tmp_dir = Path::join(Drush::config()->tmp(), 'drush_tmp_' . uniqid(time() . '_'));
$fs = new Filesystem();
$fs->mkdir($tmp_dir);
drush_register_file_for_deletion($tmp_dir);
return $tmp_dir;
}
/**
* Any file passed in to this function will be deleted
* when drush exits.
*/
function drush_register_file_for_deletion($file = NULL) {
static $registered_files = array();
if (isset($file)) {
if (empty($registered_files)) {
register_shutdown_function('_drush_delete_registered_files');
}
$registered_files[] = $file;
}
return $registered_files;
}
/**
* Delete all of the registered temporary files.
*/
function _drush_delete_registered_files() {
$files_to_delete = drush_register_file_for_deletion();
foreach ($files_to_delete as $file) {
// We'll make sure that the file still exists, just
// in case someone came along and deleted it, even
// though they did not need to.
if (file_exists($file)) {
if (is_dir($file)) {
drush_delete_dir($file, TRUE);
}
else {
@chmod($file, 0777); // Make file writeable
unlink($file);
}
}
}
}
/**
* Test to see if a file exists and is not empty
*/
function drush_file_not_empty($file_to_test) {
if (file_exists($file_to_test)) {
clearstatcache();
$stat = stat($file_to_test);
if ($stat['size'] > 0) {
return TRUE;
}
}
return FALSE;
}
/**
* Return 'TRUE' if one directory is located anywhere inside
* the other.
*/
function drush_is_nested_directory($base_dir, $test_is_nested) {
$common = Path::getLongestCommonBasePath([$test_is_nested, $base_dir]);
return $common == Path::canonicalize($base_dir);
}
/**
* @} End of "defgroup filesystemfunctions".
*/

91
vendor/drush/drush/includes/output.inc vendored Normal file
View file

@ -0,0 +1,91 @@
<?php
use Drupal\Core\Render\Markup;
use Drush\Utils\StringUtils;
/**
* @defgroup outputfunctions Process output text.
* @{
*/
/**
* Prints a message with optional indentation. In general,
* $this->>logger()->$method($message) is often a better choice than this function.
* That gets your confirmation message (for example) into the logs for this
* drush request. Consider that Drush requests may be executed remotely and
* non interactively.
*
* @param $message
* The message to print.
* @param $indent
* The indentation (space chars)
* @param $handle
* File handle to write to. NULL will write
* to standard output, STDERR will write to the standard
* error. See http://php.net/manual/en/features.commandline.io-streams.php
* @param $newline
* Add a "\n" to the end of the output. Defaults to TRUE.
*
* @deprecated
* Use $this->output()->writeln() in a command method.
*/
function drush_print($message = '', $indent = 0, $handle = NULL, $newline = TRUE) {
$msg = str_repeat(' ', $indent) . (string)$message;
if ($newline) {
$msg .= "\n";
}
if (($charset = drush_get_option('output_charset')) && function_exists('iconv')) {
$msg = iconv('UTF-8', $charset, $msg);
}
if (!$handle) {
$handle = STDOUT;
}
fwrite($handle, $msg);
}
/**
* Rudimentary translation system, akin to Drupal's t() function.
*
* @param string
* String to process, possibly with replacement item.
* @param array
* An associative array of replacement items.
*
* @return
* The processed string.
*/
function dt($string, $args = []) {
return StringUtils::interpolate($string, $args);
}
/**
* Convert html to readable text. Compatible API to
* drupal_html_to_text, but less functional. Caller
* might prefer to call drupal_html_to_text if there
* is a bootstrapped Drupal site available.
*
* @param string $html
* The html text to convert.
*
* @return string
* The plain-text representation of the input.
*/
function drush_html_to_text($html, $allowed_tags = NULL) {
$replacements = [
'<hr>' => '------------------------------------------------------------------------------',
'<li>' => ' * ',
'<h1>' => '===== ',
'</h1>' => ' =====',
'<h2>' => '---- ',
'</h2>' => ' ----',
'<h3>' => '::: ',
'</h3>' => ' :::',
'<br/>' => "\n",
];
$text = str_replace(array_keys($replacements), array_values($replacements), $html);
return html_entity_decode(preg_replace('/ *<[^>]*> */', ' ', $text));
}
/**
* @} End of "defgroup outputfunctions".
*/

View file

@ -0,0 +1,119 @@
<?php
/**
* @file
* Postflight and shutdown code.
*/
use Drush\Drush;
/**
* The main Drush function.
*
* This function is still called by drush-launcher. It is no longer used by
* Drush itself.
*/
function drush_main() {
require dirname(__DIR__) . '/drush.php';
}
/**
* We set this context to let the shutdown function know we reached the end of drush_main().
*
* @see drush_main()
*/
function drush_postflight() {
drush_set_context("DRUSH_EXECUTION_COMPLETED", TRUE);
}
/**
* Shutdown function for use while Drush and Drupal are bootstrapping and to return any
* registered errors.
*
* The shutdown command checks whether certain options are set to reliably
* detect and log some common Drupal initialization errors.
*
* If the command is being executed with the --backend option, the script
* will return a json string containing the options and log information
* used by the script.
*
* The command will exit with '1' if it was successfully executed, and the
* result of drush_get_error() if it wasn't.
*/
function drush_shutdown() {
// Avoid doing anything if our container has not been initialized yet.
if (!Drush::hasContainer()) {
return;
}
// Mysteriously make $user available during sess_write(). Avoids a NOTICE.
global $user;
if (!drush_get_context('DRUSH_EXECUTION_COMPLETED', FALSE) && !drush_get_context('DRUSH_USER_ABORT', FALSE)) {
$php_error_message = '';
if ($error = error_get_last()) {
$php_error_message = "\n" . dt('Error: !message in !file, line !line', ['!message' => $error['message'], '!file' => $error['file'], '!line' => $error['line']]);
}
// We did not reach the end of the drush_main function,
// this generally means somewhere in the code a call to exit(),
// was made. We catch this, so that we can trigger an error in
// those cases.
drush_set_error("DRUSH_NOT_COMPLETED", dt("Drush command terminated abnormally due to an unrecoverable error.!message", ['!message' => $php_error_message]));
// Attempt to give the user some advice about how to fix the problem
_drush_postmortem();
}
if (Drush::backend()) {
drush_backend_output();
}
// This way drush_return_status() will always be the last shutdown function (unless other shutdown functions register shutdown functions...)
// and won't prevent other registered shutdown functions (IE from numerous cron methods) from running by calling exit() before they get a chance.
register_shutdown_function('drush_return_status');
}
/**
* Shutdown function to save code coverage data.
*/
function drush_coverage_shutdown() {
if ($file_name = drush_get_context('DRUSH_CODE_COVERAGE', FALSE)) {
$data = xdebug_get_code_coverage();
xdebug_stop_code_coverage();
// If coverage dump file contains anything, merge in the old data before
// saving. This happens if the current drush command invoked another drush
// command.
if (file_exists($file_name) && $content = file_get_contents($file_name)) {
$merge_data = unserialize($content);
if (is_array($merge_data)) {
foreach ($merge_data as $file => $lines) {
if (!isset($data[$file])) {
$data[$file] = $lines;
}
else {
foreach ($lines as $num => $executed) {
if (!isset($data[$file][$num])) {
$data[$file][$num] = $executed;
}
else {
$data[$file][$num] = ($executed == 1 ? $executed : $data[$file][$num]);
}
}
}
}
}
}
file_put_contents($file_name, serialize($data));
}
}
function drush_return_status() {
// If a specific exit code was set, then use it.
$exit_code = drush_get_context('DRUSH_EXIT_CODE');
if (empty($exit_code)) {
$exit_code = (drush_get_error()) ? DRUSH_FRAMEWORK_ERROR : DRUSH_SUCCESS;
}
exit($exit_code);
}

View file

@ -0,0 +1,16 @@
<?php
/**
* A sneaky implementation of hook_module_implements_alter().
*
* site:install includes this file in order to not run any cron hooks during install.
* That's a bad idea.
*
* @param $implementations
* @param $hook
*/
function system_module_implements_alter(&$implementations, $hook) {
if ($hook == 'cron') {
$implementations = [];
}
}

View file

@ -0,0 +1,98 @@
<?php
/**
* @file
* The site alias API.
*
* Run commands on remote server(s).
* @see example.aliases.yml
* @see http://drupal.org/node/670460
*/
use Drush\Commands\core\StatusCommands;
use Drush\Drush;
use Drush\Log\LogLevel;
use Consolidation\SiteAlias\AliasRecord;
use Webmozart\PathUtil\Path;
/**
* Option keys used for site selection.
*/
function drush_sitealias_site_selection_keys() {
return ['remote-host', 'remote-user', 'ssh-options', '#name', 'os'];
}
/**
* Get a site alias record given an alias name or site specification.
*
* If it is the name of a site alias, return the alias record from
* the site aliases array.
*
* If it is the name of a folder in the 'sites' folder, construct
* an alias record from values stored in settings.php.
*
* If it is a site specification, construct an alias record from the
* values in the specification.
*
* Site specifications come in several forms:
* - /path/to/drupal#sitename
* - user@server/path/to/drupal#sitename
* - user@server/path/to/drupal (sitename == server)
* - user@server#sitename (only if $option['r'] set in some drushrc file on server)
* - #sitename (only if $option['r'] already set, and 'sitename' is a folder in $option['r']/sites)
* - sitename (only if $option['r'] already set, and 'sitename' is a folder in $option['r']/sites)
*
* Note that in the case of the first four forms, it is also possible
* to add additional site variable to the specification using uri query
* syntax. For example:
*
* user@server/path/to/drupal?db-url=...#sitename
*
* @param alias
* An alias name or site specification
* @return array
* An alias record, or empty if none found.
*/
function drush_sitealias_get_record($alias, $alias_context = NULL) {
// If legacy code is still looking for an alias record this way, redirect the
// request to the alias manager.
$alias_record = Drush::aliasManager()->get($alias);
if (empty($alias_record)) {
return [];
}
$config_record = $alias_record->exportConfig();
$exported_config = $config_record->export();
return isset($exported_config['options']) ? $exported_config['options'] : [];
}
/**
* Determines whether a given site alias is for a remote site.
*
* @param string $alias
* An alias name or site specification.
*
* @return bool
* Returns TRUE if the alias refers to a remote site, FALSE if it does not, or NULL is unsure.
*/
function drush_sitealias_is_remote_site($alias) {
if (is_array($alias) && !empty($alias['remote-host'])) {
return TRUE;
}
if (!is_string($alias) || !strlen($alias)) {
return NULL;
}
$site_record = drush_sitealias_get_record($alias);
if ($site_record) {
if (!empty($site_record['remote-host'])) {
return TRUE;
}
else {
return FALSE;
}
}
else {
drush_set_error('Unrecognized site alias.');
}
}

View file

@ -0,0 +1,101 @@
<?php
/*
* This file is part of the Symfony package.
*
* (c) Fabien Potencier <fabien@symfony.com>
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/
namespace Drush\Internal\Config\Yaml;
/**
* Escaper encapsulates escaping rules for single and double-quoted
* YAML strings.
*
* @author Matthew Lewinski <matthew@lewinski.org>
*
* @internal
*/
class Escaper
{
// Characters that would cause a dumped string to require double quoting.
const REGEX_CHARACTER_TO_ESCAPE = "[\\x00-\\x1f]|\xc2\x85|\xc2\xa0|\xe2\x80\xa8|\xe2\x80\xa9";
// Mapping arrays for escaping a double quoted string. The backslash is
// first to ensure proper escaping because str_replace operates iteratively
// on the input arrays. This ordering of the characters avoids the use of strtr,
// which performs more slowly.
private static $escapees = array('\\', '\\\\', '\\"', '"',
"\x00", "\x01", "\x02", "\x03", "\x04", "\x05", "\x06", "\x07",
"\x08", "\x09", "\x0a", "\x0b", "\x0c", "\x0d", "\x0e", "\x0f",
"\x10", "\x11", "\x12", "\x13", "\x14", "\x15", "\x16", "\x17",
"\x18", "\x19", "\x1a", "\x1b", "\x1c", "\x1d", "\x1e", "\x1f",
"\xc2\x85", "\xc2\xa0", "\xe2\x80\xa8", "\xe2\x80\xa9",
);
private static $escaped = array('\\\\', '\\"', '\\\\', '\\"',
'\\0', '\\x01', '\\x02', '\\x03', '\\x04', '\\x05', '\\x06', '\\a',
'\\b', '\\t', '\\n', '\\v', '\\f', '\\r', '\\x0e', '\\x0f',
'\\x10', '\\x11', '\\x12', '\\x13', '\\x14', '\\x15', '\\x16', '\\x17',
'\\x18', '\\x19', '\\x1a', '\\e', '\\x1c', '\\x1d', '\\x1e', '\\x1f',
'\\N', '\\_', '\\L', '\\P',
);
/**
* Determines if a PHP value would require double quoting in YAML.
*
* @param string $value A PHP value
*
* @return bool True if the value would require double quotes
*/
public static function requiresDoubleQuoting($value)
{
return 0 < preg_match('/'.self::REGEX_CHARACTER_TO_ESCAPE.'/u', $value);
}
/**
* Escapes and surrounds a PHP value with double quotes.
*
* @param string $value A PHP value
*
* @return string The quoted, escaped string
*/
public static function escapeWithDoubleQuotes($value)
{
return sprintf('"%s"', str_replace(self::$escapees, self::$escaped, $value));
}
/**
* Determines if a PHP value would require single quoting in YAML.
*
* @param string $value A PHP value
*
* @return bool True if the value would require single quotes
*/
public static function requiresSingleQuoting($value)
{
// Determines if a PHP value is entirely composed of a value that would
// require single quoting in YAML.
if (in_array(strtolower($value), array('null', '~', 'true', 'false', 'y', 'n', 'yes', 'no', 'on', 'off'))) {
return true;
}
// Determines if the PHP value contains any single characters that would
// cause it to require single quoting in YAML.
return 0 < preg_match('/[ \s \' " \: \{ \} \[ \] , & \* \# \?] | \A[ \- ? | < > = ! % @ ` ]/x', $value);
}
/**
* Escapes and surrounds a PHP value with single quotes.
*
* @param string $value A PHP value
*
* @return string The quoted, escaped string
*/
public static function escapeWithSingleQuotes($value)
{
return sprintf("'%s'", str_replace('\'', '\'\'', $value));
}
}

View file

@ -0,0 +1,21 @@
<?php
/*
* This file is part of the Symfony package.
*
* (c) Fabien Potencier <fabien@symfony.com>
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/
namespace Drush\Internal\Config\Yaml\Exception;
/**
* Exception interface for all exceptions thrown by the component.
*
* @author Fabien Potencier <fabien@symfony.com>
*/
interface ExceptionInterface
{
}

View file

@ -0,0 +1,139 @@
<?php
/*
* This file is part of the Symfony package.
*
* (c) Fabien Potencier <fabien@symfony.com>
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/
namespace Drush\Internal\Config\Yaml\Exception;
/**
* Exception class thrown when an error occurs during parsing.
*
* @author Fabien Potencier <fabien@symfony.com>
*/
class ParseException extends RuntimeException
{
private $parsedFile;
private $parsedLine;
private $snippet;
private $rawMessage;
/**
* @param string $message The error message
* @param int $parsedLine The line where the error occurred
* @param string|null $snippet The snippet of code near the problem
* @param string|null $parsedFile The file name where the error occurred
* @param \Exception|null $previous The previous exception
*/
public function __construct($message, $parsedLine = -1, $snippet = null, $parsedFile = null, \Exception $previous = null)
{
$this->parsedFile = $parsedFile;
$this->parsedLine = $parsedLine;
$this->snippet = $snippet;
$this->rawMessage = $message;
$this->updateRepr();
parent::__construct($this->message, 0, $previous);
}
/**
* Gets the snippet of code near the error.
*
* @return string The snippet of code
*/
public function getSnippet()
{
return $this->snippet;
}
/**
* Sets the snippet of code near the error.
*
* @param string $snippet The code snippet
*/
public function setSnippet($snippet)
{
$this->snippet = $snippet;
$this->updateRepr();
}
/**
* Gets the filename where the error occurred.
*
* This method returns null if a string is parsed.
*
* @return string The filename
*/
public function getParsedFile()
{
return $this->parsedFile;
}
/**
* Sets the filename where the error occurred.
*
* @param string $parsedFile The filename
*/
public function setParsedFile($parsedFile)
{
$this->parsedFile = $parsedFile;
$this->updateRepr();
}
/**
* Gets the line where the error occurred.
*
* @return int The file line
*/
public function getParsedLine()
{
return $this->parsedLine;
}
/**
* Sets the line where the error occurred.
*
* @param int $parsedLine The file line
*/
public function setParsedLine($parsedLine)
{
$this->parsedLine = $parsedLine;
$this->updateRepr();
}
private function updateRepr()
{
$this->message = $this->rawMessage;
$dot = false;
if ('.' === substr($this->message, -1)) {
$this->message = substr($this->message, 0, -1);
$dot = true;
}
if (null !== $this->parsedFile) {
$this->message .= sprintf(' in %s', json_encode($this->parsedFile, JSON_UNESCAPED_SLASHES | JSON_UNESCAPED_UNICODE));
}
if ($this->parsedLine >= 0) {
$this->message .= sprintf(' at line %d', $this->parsedLine);
}
if ($this->snippet) {
$this->message .= sprintf(' (near "%s")', $this->snippet);
}
if ($dot) {
$this->message .= '.';
}
}
}

View file

@ -0,0 +1,21 @@
<?php
/*
* This file is part of the Symfony package.
*
* (c) Fabien Potencier <fabien@symfony.com>
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/
namespace Drush\Internal\Config\Yaml\Exception;
/**
* Exception class thrown when an error occurs during parsing.
*
* @author Romain Neutron <imprec@gmail.com>
*/
class RuntimeException extends \RuntimeException implements ExceptionInterface
{
}

View file

@ -0,0 +1,833 @@
<?php
/*
* This file is part of the Symfony package.
*
* (c) Fabien Potencier <fabien@symfony.com>
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/
namespace Drush\Internal\Config\Yaml;
use Drush\Internal\Config\Yaml\Exception\ParseException;
use Drush\Internal\Config\Yaml\Exception\DumpException;
use Drush\Internal\Config\Yaml\Tag\TaggedValue;
/**
* Inline implements a YAML parser/dumper for the YAML inline syntax.
*
* @author Fabien Potencier <fabien@symfony.com>
*
* @internal
*/
class Inline
{
const REGEX_QUOTED_STRING = '(?:"([^"\\\\]*+(?:\\\\.[^"\\\\]*+)*+)"|\'([^\']*+(?:\'\'[^\']*+)*+)\')';
public static $parsedLineNumber;
private static $exceptionOnInvalidType = false;
private static $objectSupport = false;
private static $objectForMap = false;
private static $constantSupport = false;
/**
* Converts a YAML string to a PHP value.
*
* @param string $value A YAML string
* @param int $flags A bit field of PARSE_* constants to customize the YAML parser behavior
* @param array $references Mapping of variable names to values
*
* @return mixed A PHP value
*
* @throws ParseException
*/
public static function parse($value, $flags = 0, $references = array())
{
if (is_bool($flags)) {
@trigger_error('Passing a boolean flag to toggle exception handling is deprecated since version 3.1 and will be removed in 4.0. Use the Yaml::PARSE_EXCEPTION_ON_INVALID_TYPE flag instead.', E_USER_DEPRECATED);
if ($flags) {
$flags = Yaml::PARSE_EXCEPTION_ON_INVALID_TYPE;
} else {
$flags = 0;
}
}
if (func_num_args() >= 3 && !is_array($references)) {
@trigger_error('Passing a boolean flag to toggle object support is deprecated since version 3.1 and will be removed in 4.0. Use the Yaml::PARSE_OBJECT flag instead.', E_USER_DEPRECATED);
if ($references) {
$flags |= Yaml::PARSE_OBJECT;
}
if (func_num_args() >= 4) {
@trigger_error('Passing a boolean flag to toggle object for map support is deprecated since version 3.1 and will be removed in 4.0. Use the Yaml::PARSE_OBJECT_FOR_MAP flag instead.', E_USER_DEPRECATED);
if (func_get_arg(3)) {
$flags |= Yaml::PARSE_OBJECT_FOR_MAP;
}
}
if (func_num_args() >= 5) {
$references = func_get_arg(4);
} else {
$references = array();
}
}
self::$exceptionOnInvalidType = (bool) (Yaml::PARSE_EXCEPTION_ON_INVALID_TYPE & $flags);
self::$objectSupport = (bool) (Yaml::PARSE_OBJECT & $flags);
self::$objectForMap = (bool) (Yaml::PARSE_OBJECT_FOR_MAP & $flags);
self::$constantSupport = (bool) (Yaml::PARSE_CONSTANT & $flags);
$value = trim($value);
if ('' === $value) {
return '';
}
if (2 /* MB_OVERLOAD_STRING */ & (int) ini_get('mbstring.func_overload')) {
$mbEncoding = mb_internal_encoding();
mb_internal_encoding('ASCII');
}
$i = 0;
$tag = self::parseTag($value, $i, $flags);
switch ($value[$i]) {
case '[':
$result = self::parseSequence($value, $flags, $i, $references);
++$i;
break;
case '{':
$result = self::parseMapping($value, $flags, $i, $references);
++$i;
break;
default:
$result = self::parseScalar($value, $flags, null, $i, null === $tag, $references);
}
if (null !== $tag) {
return new TaggedValue($tag, $result);
}
// some comments are allowed at the end
if (preg_replace('/\s+#.*$/A', '', substr($value, $i))) {
throw new ParseException(sprintf('Unexpected characters near "%s".', substr($value, $i)));
}
if (isset($mbEncoding)) {
mb_internal_encoding($mbEncoding);
}
return $result;
}
/**
* Dumps a given PHP variable to a YAML string.
*
* @param mixed $value The PHP variable to convert
* @param int $flags A bit field of Yaml::DUMP_* constants to customize the dumped YAML string
*
* @return string The YAML string representing the PHP value
*
* @throws DumpException When trying to dump PHP resource
*/
public static function dump($value, $flags = 0)
{
if (is_bool($flags)) {
@trigger_error('Passing a boolean flag to toggle exception handling is deprecated since version 3.1 and will be removed in 4.0. Use the Yaml::DUMP_EXCEPTION_ON_INVALID_TYPE flag instead.', E_USER_DEPRECATED);
if ($flags) {
$flags = Yaml::DUMP_EXCEPTION_ON_INVALID_TYPE;
} else {
$flags = 0;
}
}
if (func_num_args() >= 3) {
@trigger_error('Passing a boolean flag to toggle object support is deprecated since version 3.1 and will be removed in 4.0. Use the Yaml::DUMP_OBJECT flag instead.', E_USER_DEPRECATED);
if (func_get_arg(2)) {
$flags |= Yaml::DUMP_OBJECT;
}
}
switch (true) {
case is_resource($value):
if (Yaml::DUMP_EXCEPTION_ON_INVALID_TYPE & $flags) {
throw new DumpException(sprintf('Unable to dump PHP resources in a YAML file ("%s").', get_resource_type($value)));
}
return 'null';
case $value instanceof \DateTimeInterface:
return $value->format('c');
case is_object($value):
if ($value instanceof TaggedValue) {
return '!'.$value->getTag().' '.self::dump($value->getValue(), $flags);
}
if (Yaml::DUMP_OBJECT & $flags) {
return '!php/object:'.serialize($value);
}
if (Yaml::DUMP_OBJECT_AS_MAP & $flags && ($value instanceof \stdClass || $value instanceof \ArrayObject)) {
return self::dumpArray($value, $flags & ~Yaml::DUMP_EMPTY_ARRAY_AS_SEQUENCE);
}
if (Yaml::DUMP_EXCEPTION_ON_INVALID_TYPE & $flags) {
throw new DumpException('Object support when dumping a YAML file has been disabled.');
}
return 'null';
case is_array($value):
return self::dumpArray($value, $flags);
case null === $value:
return 'null';
case true === $value:
return 'true';
case false === $value:
return 'false';
case ctype_digit($value):
return is_string($value) ? "'$value'" : (int) $value;
case is_numeric($value):
$locale = setlocale(LC_NUMERIC, 0);
if (false !== $locale) {
setlocale(LC_NUMERIC, 'C');
}
if (is_float($value)) {
$repr = (string) $value;
if (is_infinite($value)) {
$repr = str_ireplace('INF', '.Inf', $repr);
} elseif (floor($value) == $value && $repr == $value) {
// Preserve float data type since storing a whole number will result in integer value.
$repr = '!!float '.$repr;
}
} else {
$repr = is_string($value) ? "'$value'" : (string) $value;
}
if (false !== $locale) {
setlocale(LC_NUMERIC, $locale);
}
return $repr;
case '' == $value:
return "''";
case self::isBinaryString($value):
return '!!binary '.base64_encode($value);
case Escaper::requiresDoubleQuoting($value):
return Escaper::escapeWithDoubleQuotes($value);
case Escaper::requiresSingleQuoting($value):
case Parser::preg_match('{^[0-9]+[_0-9]*$}', $value):
case Parser::preg_match(self::getHexRegex(), $value):
case Parser::preg_match(self::getTimestampRegex(), $value):
return Escaper::escapeWithSingleQuotes($value);
default:
return $value;
}
}
/**
* Check if given array is hash or just normal indexed array.
*
* @internal
*
* @param array|\ArrayObject|\stdClass $value The PHP array or array-like object to check
*
* @return bool true if value is hash array, false otherwise
*/
public static function isHash($value)
{
if ($value instanceof \stdClass || $value instanceof \ArrayObject) {
return true;
}
$expectedKey = 0;
foreach ($value as $key => $val) {
if ($key !== $expectedKey++) {
return true;
}
}
return false;
}
/**
* Dumps a PHP array to a YAML string.
*
* @param array $value The PHP array to dump
* @param int $flags A bit field of Yaml::DUMP_* constants to customize the dumped YAML string
*
* @return string The YAML string representing the PHP array
*/
private static function dumpArray($value, $flags)
{
// array
if (($value || Yaml::DUMP_EMPTY_ARRAY_AS_SEQUENCE & $flags) && !self::isHash($value)) {
$output = array();
foreach ($value as $val) {
$output[] = self::dump($val, $flags);
}
return sprintf('[%s]', implode(', ', $output));
}
// hash
$output = array();
foreach ($value as $key => $val) {
$output[] = sprintf('%s: %s', self::dump($key, $flags), self::dump($val, $flags));
}
return sprintf('{ %s }', implode(', ', $output));
}
/**
* Parses a YAML scalar.
*
* @param string $scalar
* @param int $flags
* @param string[] $delimiters
* @param int &$i
* @param bool $evaluate
* @param array $references
*
* @return string
*
* @throws ParseException When malformed inline YAML string is parsed
*
* @internal
*/
public static function parseScalar($scalar, $flags = 0, $delimiters = null, &$i = 0, $evaluate = true, $references = array(), $legacyOmittedKeySupport = false)
{
if (in_array($scalar[$i], array('"', "'"))) {
// quoted scalar
$output = self::parseQuotedScalar($scalar, $i);
if (null !== $delimiters) {
$tmp = ltrim(substr($scalar, $i), ' ');
if (!in_array($tmp[0], $delimiters)) {
throw new ParseException(sprintf('Unexpected characters (%s).', substr($scalar, $i)));
}
}
} else {
// "normal" string
if (!$delimiters) {
$output = substr($scalar, $i);
$i += strlen($output);
// remove comments
if (Parser::preg_match('/[ \t]+#/', $output, $match, PREG_OFFSET_CAPTURE)) {
$output = substr($output, 0, $match[0][1]);
}
} elseif (Parser::preg_match('/^(.'.($legacyOmittedKeySupport ? '+' : '*').'?)('.implode('|', $delimiters).')/', substr($scalar, $i), $match)) {
$output = $match[1];
$i += strlen($output);
} else {
throw new ParseException(sprintf('Malformed inline YAML string: %s.', $scalar));
}
// a non-quoted string cannot start with @ or ` (reserved) nor with a scalar indicator (| or >)
if ($output && ('@' === $output[0] || '`' === $output[0] || '|' === $output[0] || '>' === $output[0])) {
throw new ParseException(sprintf('The reserved indicator "%s" cannot start a plain scalar; you need to quote the scalar.', $output[0]));
}
if ($output && '%' === $output[0]) {
@trigger_error(sprintf('Not quoting the scalar "%s" starting with the "%%" indicator character is deprecated since Symfony 3.1 and will throw a ParseException in 4.0 on line %d.', $output, self::$parsedLineNumber + 1), E_USER_DEPRECATED);
}
if ($evaluate) {
$output = self::evaluateScalar($output, $flags, $references);
}
}
return $output;
}
/**
* Parses a YAML quoted scalar.
*
* @param string $scalar
* @param int &$i
*
* @return string
*
* @throws ParseException When malformed inline YAML string is parsed
*/
private static function parseQuotedScalar($scalar, &$i)
{
if (!Parser::preg_match('/'.self::REGEX_QUOTED_STRING.'/Au', substr($scalar, $i), $match)) {
throw new ParseException(sprintf('Malformed inline YAML string: %s.', substr($scalar, $i)));
}
$output = substr($match[0], 1, strlen($match[0]) - 2);
$unescaper = new Unescaper();
if ('"' == $scalar[$i]) {
$output = $unescaper->unescapeDoubleQuotedString($output);
} else {
$output = $unescaper->unescapeSingleQuotedString($output);
}
$i += strlen($match[0]);
return $output;
}
/**
* Parses a YAML sequence.
*
* @param string $sequence
* @param int $flags
* @param int &$i
* @param array $references
*
* @return array
*
* @throws ParseException When malformed inline YAML string is parsed
*/
private static function parseSequence($sequence, $flags, &$i = 0, $references = array())
{
$output = array();
$len = strlen($sequence);
++$i;
// [foo, bar, ...]
while ($i < $len) {
if (']' === $sequence[$i]) {
return $output;
}
if (',' === $sequence[$i] || ' ' === $sequence[$i]) {
++$i;
continue;
}
$tag = self::parseTag($sequence, $i, $flags);
switch ($sequence[$i]) {
case '[':
// nested sequence
$value = self::parseSequence($sequence, $flags, $i, $references);
break;
case '{':
// nested mapping
$value = self::parseMapping($sequence, $flags, $i, $references);
break;
default:
$isQuoted = in_array($sequence[$i], array('"', "'"));
$value = self::parseScalar($sequence, $flags, array(',', ']'), $i, null === $tag, $references);
// the value can be an array if a reference has been resolved to an array var
if (is_string($value) && !$isQuoted && false !== strpos($value, ': ')) {
// embedded mapping?
try {
$pos = 0;
$value = self::parseMapping('{'.$value.'}', $flags, $pos, $references);
} catch (\InvalidArgumentException $e) {
// no, it's not
}
}
--$i;
}
if (null !== $tag) {
$value = new TaggedValue($tag, $value);
}
$output[] = $value;
++$i;
}
throw new ParseException(sprintf('Malformed inline YAML string: %s.', $sequence));
}
/**
* Parses a YAML mapping.
*
* @param string $mapping
* @param int $flags
* @param int &$i
* @param array $references
*
* @return array|\stdClass
*
* @throws ParseException When malformed inline YAML string is parsed
*/
private static function parseMapping($mapping, $flags, &$i = 0, $references = array())
{
$output = array();
$len = strlen($mapping);
++$i;
$allowOverwrite = false;
// {foo: bar, bar:foo, ...}
while ($i < $len) {
switch ($mapping[$i]) {
case ' ':
case ',':
++$i;
continue 2;
case '}':
if (self::$objectForMap) {
return (object) $output;
}
return $output;
}
// key
$isKeyQuoted = in_array($mapping[$i], array('"', "'"), true);
$key = self::parseScalar($mapping, $flags, array(':', ' '), $i, false, array(), true);
if (':' !== $key && false === $i = strpos($mapping, ':', $i)) {
break;
}
if (':' === $key) {
@trigger_error(sprintf('Omitting the key of a mapping is deprecated and will throw a ParseException in 4.0 on line %d.', self::$parsedLineNumber + 1), E_USER_DEPRECATED);
}
if (!(Yaml::PARSE_KEYS_AS_STRINGS & $flags)) {
$evaluatedKey = self::evaluateScalar($key, $flags, $references);
if ('' !== $key && $evaluatedKey !== $key && !is_string($evaluatedKey) && !is_int($evaluatedKey)) {
@trigger_error(sprintf('Implicit casting of incompatible mapping keys to strings is deprecated since version 3.3 and will throw \Symfony\Component\Yaml\Exception\ParseException in 4.0. Quote your evaluable mapping keys instead on line %d.', self::$parsedLineNumber + 1), E_USER_DEPRECATED);
}
}
if (':' !== $key && !$isKeyQuoted && (!isset($mapping[$i + 1]) || !in_array($mapping[$i + 1], array(' ', ',', '[', ']', '{', '}'), true))) {
@trigger_error(sprintf('Using a colon after an unquoted mapping key that is not followed by an indication character (i.e. " ", ",", "[", "]", "{", "}") is deprecated since version 3.2 and will throw a ParseException in 4.0 on line %d.', self::$parsedLineNumber + 1), E_USER_DEPRECATED);
}
if ('<<' === $key) {
$allowOverwrite = true;
}
while ($i < $len) {
if (':' === $mapping[$i] || ' ' === $mapping[$i]) {
++$i;
continue;
}
$tag = self::parseTag($mapping, $i, $flags);
switch ($mapping[$i]) {
case '[':
// nested sequence
$value = self::parseSequence($mapping, $flags, $i, $references);
// Spec: Keys MUST be unique; first one wins.
// Parser cannot abort this mapping earlier, since lines
// are processed sequentially.
// But overwriting is allowed when a merge node is used in current block.
if ('<<' === $key) {
foreach ($value as $parsedValue) {
$output += $parsedValue;
}
} elseif ($allowOverwrite || !isset($output[$key])) {
if (null !== $tag) {
$output[$key] = new TaggedValue($tag, $value);
} else {
$output[$key] = $value;
}
} elseif (isset($output[$key])) {
@trigger_error(sprintf('Duplicate key "%s" detected whilst parsing YAML. Silent handling of duplicate mapping keys in YAML is deprecated since version 3.2 and will throw \Symfony\Component\Yaml\Exception\ParseException in 4.0 on line %d.', $key, self::$parsedLineNumber + 1), E_USER_DEPRECATED);
}
break;
case '{':
// nested mapping
$value = self::parseMapping($mapping, $flags, $i, $references);
// Spec: Keys MUST be unique; first one wins.
// Parser cannot abort this mapping earlier, since lines
// are processed sequentially.
// But overwriting is allowed when a merge node is used in current block.
if ('<<' === $key) {
$output += $value;
} elseif ($allowOverwrite || !isset($output[$key])) {
if (null !== $tag) {
$output[$key] = new TaggedValue($tag, $value);
} else {
$output[$key] = $value;
}
} elseif (isset($output[$key])) {
@trigger_error(sprintf('Duplicate key "%s" detected whilst parsing YAML. Silent handling of duplicate mapping keys in YAML is deprecated since version 3.2 and will throw \Symfony\Component\Yaml\Exception\ParseException in 4.0 on line %d.', $key, self::$parsedLineNumber + 1), E_USER_DEPRECATED);
}
break;
default:
$value = self::parseScalar($mapping, $flags, array(',', '}'), $i, null === $tag, $references);
// Spec: Keys MUST be unique; first one wins.
// Parser cannot abort this mapping earlier, since lines
// are processed sequentially.
// But overwriting is allowed when a merge node is used in current block.
if ('<<' === $key) {
$output += $value;
} elseif ($allowOverwrite || !isset($output[$key])) {
if (null !== $tag) {
$output[$key] = new TaggedValue($tag, $value);
} else {
$output[$key] = $value;
}
} elseif (isset($output[$key])) {
@trigger_error(sprintf('Duplicate key "%s" detected whilst parsing YAML. Silent handling of duplicate mapping keys in YAML is deprecated since version 3.2 and will throw \Symfony\Component\Yaml\Exception\ParseException in 4.0 on line %d.', $key, self::$parsedLineNumber + 1), E_USER_DEPRECATED);
}
--$i;
}
++$i;
continue 2;
}
}
throw new ParseException(sprintf('Malformed inline YAML string: %s.', $mapping));
}
/**
* Evaluates scalars and replaces magic values.
*
* @param string $scalar
* @param int $flags
* @param array $references
*
* @return mixed The evaluated YAML string
*
* @throws ParseException when object parsing support was disabled and the parser detected a PHP object or when a reference could not be resolved
*/
private static function evaluateScalar($scalar, $flags, $references = array())
{
$scalar = trim($scalar);
$scalarLower = strtolower($scalar);
if (0 === strpos($scalar, '*')) {
if (false !== $pos = strpos($scalar, '#')) {
$value = substr($scalar, 1, $pos - 2);
} else {
$value = substr($scalar, 1);
}
// an unquoted *
if (false === $value || '' === $value) {
throw new ParseException('A reference must contain at least one character.');
}
if (!array_key_exists($value, $references)) {
throw new ParseException(sprintf('Reference "%s" does not exist.', $value));
}
return $references[$value];
}
switch (true) {
case 'null' === $scalarLower:
case '' === $scalar:
case '~' === $scalar:
return;
case 'true' === $scalarLower:
return true;
case 'false' === $scalarLower:
return false;
case '!' === $scalar[0]:
switch (true) {
case 0 === strpos($scalar, '!str'):
return (string) substr($scalar, 5);
case 0 === strpos($scalar, '! '):
return (int) self::parseScalar(substr($scalar, 2), $flags);
case 0 === strpos($scalar, '!php/object:'):
if (self::$objectSupport) {
return unserialize(substr($scalar, 12));
}
if (self::$exceptionOnInvalidType) {
throw new ParseException('Object support when parsing a YAML file has been disabled.');
}
return;
case 0 === strpos($scalar, '!!php/object:'):
if (self::$objectSupport) {
@trigger_error(sprintf('The !!php/object tag to indicate dumped PHP objects is deprecated since version 3.1 and will be removed in 4.0. Use the !php/object tag instead on line %d.', self::$parsedLineNumber + 1), E_USER_DEPRECATED);
return unserialize(substr($scalar, 13));
}
if (self::$exceptionOnInvalidType) {
throw new ParseException('Object support when parsing a YAML file has been disabled.');
}
return;
case 0 === strpos($scalar, '!php/const:'):
if (self::$constantSupport) {
if (defined($const = substr($scalar, 11))) {
return constant($const);
}
throw new ParseException(sprintf('The constant "%s" is not defined.', $const));
}
if (self::$exceptionOnInvalidType) {
throw new ParseException(sprintf('The string "%s" could not be parsed as a constant. Have you forgotten to pass the "Yaml::PARSE_CONSTANT" flag to the parser?', $scalar));
}
return;
case 0 === strpos($scalar, '!!float '):
return (float) substr($scalar, 8);
case 0 === strpos($scalar, '!!binary '):
return self::evaluateBinaryScalar(substr($scalar, 9));
default:
@trigger_error(sprintf('Using the unquoted scalar value "%s" is deprecated since version 3.3 and will be considered as a tagged value in 4.0. You must quote it on line %d.', $scalar, self::$parsedLineNumber + 1), E_USER_DEPRECATED);
}
// Optimize for returning strings.
// no break
case '+' === $scalar[0] || '-' === $scalar[0] || '.' === $scalar[0] || is_numeric($scalar[0]):
switch (true) {
case Parser::preg_match('{^[+-]?[0-9][0-9_]*$}', $scalar):
$scalar = str_replace('_', '', (string) $scalar);
// omitting the break / return as integers are handled in the next case
// no break
case ctype_digit($scalar):
$raw = $scalar;
$cast = (int) $scalar;
return '0' == $scalar[0] ? octdec($scalar) : (((string) $raw == (string) $cast) ? $cast : $raw);
case '-' === $scalar[0] && ctype_digit(substr($scalar, 1)):
$raw = $scalar;
$cast = (int) $scalar;
return '0' == $scalar[1] ? octdec($scalar) : (((string) $raw === (string) $cast) ? $cast : $raw);
case is_numeric($scalar):
case Parser::preg_match(self::getHexRegex(), $scalar):
$scalar = str_replace('_', '', $scalar);
return '0x' === $scalar[0].$scalar[1] ? hexdec($scalar) : (float) $scalar;
case '.inf' === $scalarLower:
case '.nan' === $scalarLower:
return -log(0);
case '-.inf' === $scalarLower:
return log(0);
case Parser::preg_match('/^(-|\+)?[0-9][0-9,]*(\.[0-9_]+)?$/', $scalar):
case Parser::preg_match('/^(-|\+)?[0-9][0-9_]*(\.[0-9_]+)?$/', $scalar):
if (false !== strpos($scalar, ',')) {
@trigger_error(sprintf('Using the comma as a group separator for floats is deprecated since version 3.2 and will be removed in 4.0 on line %d.', self::$parsedLineNumber + 1), E_USER_DEPRECATED);
}
return (float) str_replace(array(',', '_'), '', $scalar);
case Parser::preg_match(self::getTimestampRegex(), $scalar):
if (Yaml::PARSE_DATETIME & $flags) {
// When no timezone is provided in the parsed date, YAML spec says we must assume UTC.
return new \DateTime($scalar, new \DateTimeZone('UTC'));
}
$timeZone = date_default_timezone_get();
date_default_timezone_set('UTC');
$time = strtotime($scalar);
date_default_timezone_set($timeZone);
return $time;
}
}
return (string) $scalar;
}
/**
* @param string $value
* @param int &$i
* @param int $flags
*
* @return null|string
*/
private static function parseTag($value, &$i, $flags)
{
if ('!' !== $value[$i]) {
return;
}
$tagLength = strcspn($value, " \t\n", $i + 1);
$tag = substr($value, $i + 1, $tagLength);
$nextOffset = $i + $tagLength + 1;
$nextOffset += strspn($value, ' ', $nextOffset);
// Is followed by a scalar
if (!isset($value[$nextOffset]) || !in_array($value[$nextOffset], array('[', '{'), true)) {
// Manage scalars in {@link self::evaluateScalar()}
return;
}
// Built-in tags
if ($tag && '!' === $tag[0]) {
throw new ParseException(sprintf('The built-in tag "!%s" is not implemented.', $tag));
}
if (Yaml::PARSE_CUSTOM_TAGS & $flags) {
$i = $nextOffset;
return $tag;
}
throw new ParseException(sprintf('Tags support is not enabled. Enable the `Yaml::PARSE_CUSTOM_TAGS` flag to use "!%s".', $tag));
}
/**
* @param string $scalar
*
* @return string
*
* @internal
*/
public static function evaluateBinaryScalar($scalar)
{
$parsedBinaryData = self::parseScalar(preg_replace('/\s/', '', $scalar));
if (0 !== (strlen($parsedBinaryData) % 4)) {
throw new ParseException(sprintf('The normalized base64 encoded data (data without whitespace characters) length must be a multiple of four (%d bytes given).', strlen($parsedBinaryData)));
}
if (!Parser::preg_match('#^[A-Z0-9+/]+={0,2}$#i', $parsedBinaryData)) {
throw new ParseException(sprintf('The base64 encoded data (%s) contains invalid characters.', $parsedBinaryData));
}
return base64_decode($parsedBinaryData, true);
}
private static function isBinaryString($value)
{
return !preg_match('//u', $value) || preg_match('/[^\x00\x07-\x0d\x1B\x20-\xff]/', $value);
}
/**
* Gets a regex that matches a YAML date.
*
* @return string The regular expression
*
* @see http://www.yaml.org/spec/1.2/spec.html#id2761573
*/
private static function getTimestampRegex()
{
return <<<EOF
~^
(?P<year>[0-9][0-9][0-9][0-9])
-(?P<month>[0-9][0-9]?)
-(?P<day>[0-9][0-9]?)
(?:(?:[Tt]|[ \t]+)
(?P<hour>[0-9][0-9]?)
:(?P<minute>[0-9][0-9])
:(?P<second>[0-9][0-9])
(?:\.(?P<fraction>[0-9]*))?
(?:[ \t]*(?P<tz>Z|(?P<tz_sign>[-+])(?P<tz_hour>[0-9][0-9]?)
(?::(?P<tz_minute>[0-9][0-9]))?))?)?
$~x
EOF;
}
/**
* Gets a regex that matches a YAML number in hexadecimal notation.
*
* @return string
*/
private static function getHexRegex()
{
return '~^0x[0-9a-f_]++$~i';
}
}

View file

@ -0,0 +1,19 @@
Copyright (c) 2004-2017 Fabien Potencier
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is furnished
to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in all
copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
THE SOFTWARE.

File diff suppressed because it is too large Load diff

View file

@ -0,0 +1,20 @@
Yaml Component
==============
The Yaml component loads and dumps YAML files.
This is a COPY of symfony/yaml re-namespaced to Drush\Config\Yaml. This is
here so that Drush can parse its yaml config and aliasfiles prior to autoloading
any Symfony packages. This helps avoid dependency conflicts when the global
Drush includes the autoload file from Drupal.
DO NOT USE THESE CLASSES OUTSIDE OF PREFLIGHT. Instead, use symfony/yaml.
Resources
---------
* [Documentation](https://symfony.com/doc/current/components/yaml/index.html)
* [Contributing](https://symfony.com/doc/current/contributing/index.html)
* [Report issues](https://github.com/symfony/symfony/issues) and
[send Pull Requests](https://github.com/symfony/symfony/pulls)
in the [main Symfony repository](https://github.com/symfony/symfony)

View file

@ -0,0 +1,48 @@
<?php
/*
* This file is part of the Symfony package.
*
* (c) Fabien Potencier <fabien@symfony.com>
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/
namespace Drush\Internal\Config\Yaml\Tag;
/**
* @author Nicolas Grekas <p@tchwork.com>
* @author Guilhem N. <egetick@gmail.com>
*/
final class TaggedValue
{
private $tag;
private $value;
/**
* @param string $tag
* @param mixed $value
*/
public function __construct($tag, $value)
{
$this->tag = $tag;
$this->value = $value;
}
/**
* @return string
*/
public function getTag()
{
return $this->tag;
}
/**
* @return mixed
*/
public function getValue()
{
return $this->value;
}
}

View file

@ -0,0 +1,142 @@
<?php
/*
* This file is part of the Symfony package.
*
* (c) Fabien Potencier <fabien@symfony.com>
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/
namespace Drush\Internal\Config\Yaml;
use Drush\Internal\Config\Yaml\Exception\ParseException;
/**
* Unescaper encapsulates unescaping rules for single and double-quoted
* YAML strings.
*
* @author Matthew Lewinski <matthew@lewinski.org>
*
* @internal
*/
class Unescaper
{
/**
* Regex fragment that matches an escaped character in a double quoted string.
*/
const REGEX_ESCAPED_CHARACTER = '\\\\(x[0-9a-fA-F]{2}|u[0-9a-fA-F]{4}|U[0-9a-fA-F]{8}|.)';
/**
* Unescapes a single quoted string.
*
* @param string $value A single quoted string
*
* @return string The unescaped string
*/
public function unescapeSingleQuotedString($value)
{
return str_replace('\'\'', '\'', $value);
}
/**
* Unescapes a double quoted string.
*
* @param string $value A double quoted string
*
* @return string The unescaped string
*/
public function unescapeDoubleQuotedString($value)
{
$callback = function ($match) {
return $this->unescapeCharacter($match[0]);
};
// evaluate the string
return preg_replace_callback('/'.self::REGEX_ESCAPED_CHARACTER.'/u', $callback, $value);
}
/**
* Unescapes a character that was found in a double-quoted string.
*
* @param string $value An escaped character
*
* @return string The unescaped character
*/
private function unescapeCharacter($value)
{
switch ($value[1]) {
case '0':
return "\x0";
case 'a':
return "\x7";
case 'b':
return "\x8";
case 't':
return "\t";
case "\t":
return "\t";
case 'n':
return "\n";
case 'v':
return "\xB";
case 'f':
return "\xC";
case 'r':
return "\r";
case 'e':
return "\x1B";
case ' ':
return ' ';
case '"':
return '"';
case '/':
return '/';
case '\\':
return '\\';
case 'N':
// U+0085 NEXT LINE
return "\xC2\x85";
case '_':
// U+00A0 NO-BREAK SPACE
return "\xC2\xA0";
case 'L':
// U+2028 LINE SEPARATOR
return "\xE2\x80\xA8";
case 'P':
// U+2029 PARAGRAPH SEPARATOR
return "\xE2\x80\xA9";
case 'x':
return self::utf8chr(hexdec(substr($value, 2, 2)));
case 'u':
return self::utf8chr(hexdec(substr($value, 2, 4)));
case 'U':
return self::utf8chr(hexdec(substr($value, 2, 8)));
default:
throw new ParseException(sprintf('Found unknown escape character "%s".', $value));
}
}
/**
* Get the UTF-8 character for the given code point.
*
* @param int $c The unicode code point
*
* @return string The corresponding UTF-8 character
*/
private static function utf8chr($c)
{
if (0x80 > $c %= 0x200000) {
return chr($c);
}
if (0x800 > $c) {
return chr(0xC0 | $c >> 6).chr(0x80 | $c & 0x3F);
}
if (0x10000 > $c) {
return chr(0xE0 | $c >> 12).chr(0x80 | $c >> 6 & 0x3F).chr(0x80 | $c & 0x3F);
}
return chr(0xF0 | $c >> 18).chr(0x80 | $c >> 12 & 0x3F).chr(0x80 | $c >> 6 & 0x3F).chr(0x80 | $c & 0x3F);
}
}

View file

@ -0,0 +1,84 @@
<?php
/*
* This file is part of the Symfony package.
*
* (c) Fabien Potencier <fabien@symfony.com>
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/
namespace Drush\Internal\Config\Yaml;
use Drush\Internal\Config\Yaml\Exception\ParseException;
/**
* Yaml offers convenience methods to load and dump YAML.
*
* @author Fabien Potencier <fabien@symfony.com>
*/
class Yaml
{
const DUMP_OBJECT = 1;
const PARSE_EXCEPTION_ON_INVALID_TYPE = 2;
const PARSE_OBJECT = 4;
const PARSE_OBJECT_FOR_MAP = 8;
const DUMP_EXCEPTION_ON_INVALID_TYPE = 16;
const PARSE_DATETIME = 32;
const DUMP_OBJECT_AS_MAP = 64;
const DUMP_MULTI_LINE_LITERAL_BLOCK = 128;
const PARSE_CONSTANT = 256;
const PARSE_CUSTOM_TAGS = 512;
const DUMP_EMPTY_ARRAY_AS_SEQUENCE = 1024;
const PARSE_KEYS_AS_STRINGS = 2048;
/**
* Parses YAML into a PHP value.
*
* Usage:
* <code>
* $array = Yaml::parse(file_get_contents('config.yml'));
* print_r($array);
* </code>
*
* @param string $input A string containing YAML
* @param int $flags A bit field of PARSE_* constants to customize the YAML parser behavior
*
* @return mixed The YAML converted to a PHP value
*
* @throws ParseException If the YAML is not valid
*/
public static function parse($input, $flags = 0)
{
if (is_bool($flags)) {
@trigger_error('Passing a boolean flag to toggle exception handling is deprecated since version 3.1 and will be removed in 4.0. Use the PARSE_EXCEPTION_ON_INVALID_TYPE flag instead.', E_USER_DEPRECATED);
if ($flags) {
$flags = self::PARSE_EXCEPTION_ON_INVALID_TYPE;
} else {
$flags = 0;
}
}
if (func_num_args() >= 3) {
@trigger_error('Passing a boolean flag to toggle object support is deprecated since version 3.1 and will be removed in 4.0. Use the PARSE_OBJECT flag instead.', E_USER_DEPRECATED);
if (func_get_arg(2)) {
$flags |= self::PARSE_OBJECT;
}
}
if (func_num_args() >= 4) {
@trigger_error('Passing a boolean flag to toggle object for map support is deprecated since version 3.1 and will be removed in 4.0. Use the Yaml::PARSE_OBJECT_FOR_MAP flag instead.', E_USER_DEPRECATED);
if (func_get_arg(3)) {
$flags |= self::PARSE_OBJECT_FOR_MAP;
}
}
$yaml = new Parser();
return $yaml->parse($input, $flags);
}
}

View file

@ -0,0 +1,2 @@
vendor
build

View file

@ -0,0 +1,2 @@
test:
system: 'A system-wide setting'

View file

@ -0,0 +1,2 @@
test:
variant: 'This file should be ignored'

View file

@ -0,0 +1,2 @@
test:
variant: 'A variable that only exists in the variant drush.yml'

View file

@ -0,0 +1,7 @@
test:
home: 'A user-specific setting'
command:
test:
foo:
options:
bar: baz

View file

@ -0,0 +1,43 @@
<?php
$aliases['live'] = array (
'parent' => '@server.digital-ocean',
'project-type' => 'live',
'root' => '/srv/www/couturecostume.com/htdocs',
'uri' => 'couturecostume.com',
'path-aliases' => array(
'%dump-dir' => '/var/sql-dump/',
),
'target-command-specific' => array(
'sql-sync' => array(
'disable' => array('stage_file_proxy'),
'permission' => array(
'authenticated user' => array(
'remove' => array('access environment indicator'),
),
'anonymous user' => array(
'remove' => 'access environment indicator',
),
),
),
),
);
$aliases['update'] = array (
'parent' => '@server.nitrogen',
'root' => '/srv/www/update.couturecostume.com/htdocs',
'uri' => 'update.couturecostume.com',
'target-command-specific' => array(
'sql-sync' => array(
'enable' => array('environment_indicator', 'stage_file_proxy'),
'permission' => array(
'authenticated user' => array(
'add' => array('access environment indicator'),
),
'anonymous user' => array(
'add' => 'access environment indicator',
),
),
),
),
);

View file

@ -0,0 +1,4 @@
<?php
$options['uri'] = 'http://example.com';
$options['root'] = '/path/to/drupal';

View file

@ -0,0 +1,50 @@
<?php
/**
* Pantheon drush alias file, to be placed in your ~/.drush directory or the aliases
* directory of your local Drush home. Once it's in place, clear drush cache:
*
* drush cc drush
*
* To see all your available aliases:
*
* drush sa
*
* See http://helpdesk.getpantheon.com/customer/portal/articles/411388 for details.
*/
$aliases['outlandish-josh.test'] = array(
'uri' => 'test-outlandish-josh.pantheonsite.io',
'db-url' => 'mysql://pantheon:pw@dbserver.test.site-id.drush.in:11621/pantheon',
'db-allows-remote' => TRUE,
'remote-host' => 'appserver.test.site-id.drush.in',
'remote-user' => 'test.site-id',
'ssh-options' => '-p 2222 -o "AddressFamily inet"',
'path-aliases' => array(
'%files' => 'code/sites/default/files',
'%drush-script' => 'drush',
),
);
$aliases['outlandish-josh.live'] = array(
'uri' => 'www.outlandishjosh.com',
'db-url' => 'mysql://pantheon:pw@dbserver.live.site-id.drush.in:10516/pantheon',
'db-allows-remote' => TRUE,
'remote-host' => 'appserver.live.site-id.drush.in',
'remote-user' => 'live.site-id',
'ssh-options' => '-p 2222 -o "AddressFamily inet"',
'path-aliases' => array(
'%files' => 'code/sites/default/files',
'%drush-script' => 'drush',
),
);
$aliases['outlandish-josh.dev'] = array(
'uri' => 'dev-outlandish-josh.pantheonsite.io',
'db-url' => 'mysql://pantheon:pw@dbserver.dev.site-id.drush.in:21086/pantheon',
'db-allows-remote' => TRUE,
'remote-host' => 'appserver.dev.site-id.drush.in',
'remote-user' => 'dev.site-id',
'ssh-options' => '-p 2222 -o "AddressFamily inet"',
'path-aliases' => array(
'%files' => 'code/sites/default/files',
'%drush-script' => 'drush',
),
);

View file

@ -0,0 +1,11 @@
<?php
$aliases['isp'] = array (
'remote-host' => 'hydrogen.server.org',
'remote-user' => 'www-admin',
);
$aliases['nitrogen'] = array (
'remote-host' => 'nitrogen.server.org',
'remote-user' => 'admin',
);

View file

@ -0,0 +1 @@
root: /path/to/simple

View file

@ -0,0 +1,7 @@
default: dev
dev:
root: /path/to/single
alternate:
root: /alternate/path/to/single
common:
foo: bar

View file

@ -0,0 +1,2 @@
test:
site: 'A site-specific setting'

View file

@ -0,0 +1,6 @@
test:
root: /path/to/drupal-test
uri: https://test.example.com
live:
root: /path/to/drupal-live
uri: https://live.example.com

View file

@ -0,0 +1 @@
<?php

View file

@ -0,0 +1,19 @@
<?php
namespace Drush;
// We want to avoid using symfony/filesystem in the isolation tests.
trait FSUtils
{
function removeDir($dir)
{
$files = array_diff(scandir($dir), ['.','..']);
foreach ($files as $file) {
if (is_dir("$dir/$file") && !is_link("$dir/$file")) {
$this->removeDir("$dir/$file");
} else {
unlink("$dir/$file");
}
}
return rmdir($dir);
}
}

View file

@ -0,0 +1,41 @@
<?php
namespace Drush;
use \Drush\Config\Environment;
trait FixtureFactory
{
protected function fixturesDir()
{
return dirname(__DIR__) . '/fixtures';
}
protected function homeDir()
{
return $this->fixturesDir() . '/home';
}
// It is still an aspirational goal to add Drupal 7 support back to Drush. :P
// For now, only Drupal 8 is supported.
protected function siteDir($majorVersion = '8')
{
return $this->fixturesDir() . '/sites/d' . $majorVersion;
}
protected function environment($cwd = false)
{
$fixturesDir = $this->fixturesDir();
$home = $this->homeDir();
if (!$cwd) {
$cwd = $home;
}
$autoloadFile = dirname(__DIR__) . '/vendor/autoload.php';
$environment = new Environment($home, $cwd, $autoloadFile);
$environment
->setEtcPrefix($fixturesDir)
->setSharePrefix($fixturesDir . '/usr');
return $environment;
}
}

View file

@ -0,0 +1,14 @@
<?php
namespace Drush;
trait FunctionUtils
{
protected $sut;
protected function callProtected($methodName, $args = [])
{
$r = new \ReflectionMethod($this->sut, $methodName);
$r->setAccessible(true);
return $r->invokeArgs($this->sut, $args);
}
}

View file

@ -0,0 +1,360 @@
<?php
namespace Drush\Preflight;
use PHPUnit\Framework\TestCase;
class ArgsPreprocessorTest extends TestCase
{
use \Drush\FixtureFactory;
/**
* @dataProvider argTestValues
*/
public function testArgPreprocessor(
$argv,
$alias,
$selectedSite,
$configPath,
$aliasPath,
$commandPath,
$isLocal,
$unprocessedArgs)
{
$argProcessor = new ArgsPreprocessor();
$preflightArgs = new PreflightArgs();
$preflightArgs->setHomeDir($this->environment()->homeDir());
$argProcessor->parse($argv, $preflightArgs);
$this->assertEquals($unprocessedArgs, implode(',', $preflightArgs->args()));
$this->assertEquals($alias, $preflightArgs->alias());
$this->assertEquals($selectedSite, $preflightArgs->selectedSite());
$this->assertEquals($configPath, $preflightArgs->configPaths());
$this->assertEquals($aliasPath, $preflightArgs->aliasPaths());
}
public static function argTestValues()
{
return [
[
[
'drush',
'@alias',
'status',
'version',
],
'@alias',
null,
[],
[],
[],
null,
'drush,status,version',
],
[
[
'drush',
'#multisite',
'status',
'version',
],
'#multisite',
null,
[],
[],
[],
null,
'drush,status,version',
],
[
[
'drush',
'user@server/path',
'status',
'version',
],
'user@server/path',
null,
[],
[],
[],
null,
'drush,status,version',
],
[
[
'drush',
'rsync',
'@from',
'@to',
'--delete',
],
null,
null,
[],
[],
[],
null,
'drush,rsync,@from,@to,--delete',
],
[
[
'drush',
'--root',
'/path/to/drupal',
'status',
'--verbose',
],
null,
'/path/to/drupal',
[],
[],
[],
null,
'drush,status,--verbose',
],
[
[
'drush',
'--root=/path/to/drupal',
'status',
'--verbose',
],
null,
'/path/to/drupal',
[],
[],
[],
null,
'drush,status,--verbose',
],
[
[
'drush',
'status',
'--verbose',
'--config',
'/path/to/config',
],
null,
null,
['/path/to/config'],
[],
[],
null,
'drush,status,--verbose',
],
[
[
'drush',
'status',
'--verbose',
'--config=/path/to/config',
],
null,
null,
['/path/to/config'],
[],
[],
null,
'drush,status,--verbose',
],
[
[
'drush',
'status',
'--verbose',
'--config=/path/to/config',
'--config=/other/path/to/config',
],
null,
null,
['/path/to/config','/other/path/to/config'],
[],
[],
null,
'drush,status,--verbose',
],
[
[
'drush',
'status',
'--verbose',
'--alias-path',
'/path/to/aliases',
],
null,
null,
[],
['/path/to/aliases'],
[],
null,
'drush,status,--verbose',
],
[
[
'drush',
'status',
'--verbose',
'--alias-path=/path/to/aliases',
],
null,
null,
[],
['/path/to/aliases'],
[],
null,
'drush,status,--verbose',
],
[
[
'drush',
'status',
'--verbose',
'--alias-path=/path/to/aliases',
'--alias-path=/other/path/to/aliases',
],
null,
null,
[],
['/path/to/aliases','/other/path/to/aliases'],
[],
null,
'drush,status,--verbose',
],
[
[
'drush',
'status',
'--verbose',
'--include',
'/path/to/commands',
],
null,
null,
[],
[],
['path/to/commands'],
null,
'drush,status,--verbose',
],
[
[
'drush',
'status',
'--verbose',
'--include=/path/to/commands',
],
null,
null,
[],
[],
['path/to/commands'],
null,
'drush,status,--verbose',
],
[
[
'drush',
'status',
'--verbose',
'--include=/path/to/commands',
],
null,
null,
[],
[],
['path/to/commands'],
null,
'drush,status,--verbose',
],
[
[
'drush',
'status',
'--verbose',
'--include=/path/to/commands',
'--include=/other/path/to/commands',
],
null,
null,
[],
[],
['path/to/commands','/other/path/to/commands'],
null,
'drush,status,--verbose',
],
[
[
'drush',
'status',
'--verbose',
'--local',
],
null,
null,
[],
[],
[],
true,
'drush,status,--verbose',
],
[
[
'drush',
'@alias',
'status',
'--verbose',
'--local',
'--alias-path=/path/to/aliases',
'--config=/path/to/config',
'--root=/path/to/drupal',
'--include=/path/to/commands',
],
'@alias',
'/path/to/drupal',
['/path/to/config'],
['/path/to/aliases'],
['path/to/commands'],
true,
'drush,status,--verbose',
],
];
}
}

View file

@ -0,0 +1,107 @@
<?php
namespace Drush\Config;
use PHPUnit\Framework\TestCase;
/**
* Test the config loader. Also exercises the EnvironmentConfigLoader.
*/
class ConfigLocatorTest extends TestCase
{
use \Drush\FixtureFactory;
/**
* Test a config locator initialized only with data from the fixture's environment
*/
function testOnlyEnvironmentData()
{
$configLocator = new ConfigLocator('TEST_');
$configLocator->addEnvironment($this->environment());
$config = $configLocator->config();
$this->assertEquals($this->homeDir(), $config->get('env.cwd'));
}
/**
* Test a comprehensive load of all default fixture data.
*/
function testLoadAll()
{
$configLocator = $this->createConfigLocator();
$sources = $configLocator->sources();
//$this->assertEquals('environment', $sources['env']['cwd']);
$this->assertEquals($this->fixturesDir() . '/etc/drush/drush.yml', $sources['test']['system']);
$this->assertEquals($this->fixturesDir() . '/etc/drush/drushVARIANT.yml', $sources['test']['variant']);
$this->assertEquals($this->fixturesDir() . '/home/.drush/drush.yml', $sources['test']['home']);
$this->assertEquals($this->fixturesDir() . '/sites/d8/drush/drush.yml', $sources['test']['site']);
$this->assertEquals($this->environment()->drushBasePath() . '/drush.yml', $sources['drush']['php']['minimum-version']);
$config = $configLocator->config();
$this->assertEquals($this->homeDir(), $config->get('env.cwd'));
$this->assertEquals('A system-wide setting', $config->get('test.system'));
$this->assertEquals('A user-specific setting', $config->get('test.home'));
$this->assertEquals('A site-specific setting', $config->get('test.site'));
$this->assertTrue($config->has('drush.php.minimum-version'));
}
/**
* Test loading default fixture data in 'local' mode. This prevents Drush
* from loading any configuration file in any "global" location. In this
* context, "global" means anything that is not site-local, including the
* configuration file in the user's home directory, etc.
*/
function testLocalMode()
{
$configLocator = $this->createConfigLocator(true);
/*
$sources = $configLocator->sources();
//$this->assertEquals('environment', $sources['env']['cwd']);
$this->assertArrayNotHasKey('system', $sources['test']);
$this->assertArrayNotHasKey('home', $sources['test']);
$this->assertEquals($this->siteDir() . '/drush/drush.yml', $sources['test']['site']);
*/
$config = $configLocator->config();
$this->assertEquals($this->homeDir(), $config->get('env.cwd'));
$this->assertFalse($config->has('test.system'));
$this->assertFalse($config->has('test.home'));
$this->assertEquals('A site-specific setting', $config->get('test.site'));
}
function testAliasPaths()
{
$configLocator = $this->createConfigLocator();
$aliasPaths = $configLocator->getSiteAliasPaths(['/home/user/aliases'], $this->environment());
$aliasPaths = array_map(
function ($item) {
return str_replace(dirname(__DIR__) . '/', '', $item);
},
$aliasPaths
);
sort($aliasPaths);
$expected = '/home/user/aliases,fixtures/sites/d8/drush/sites';
$this->assertEquals($expected, implode(',', $aliasPaths));
}
/**
* Create a config locator from All The Sources, for use in multiple tests.
*/
protected function createConfigLocator($isLocal = false, $configPath = '')
{
$configLocator = new ConfigLocator('TEST_', 'VARIANT');
$configLocator->collectSources();
$configLocator->setLocal($isLocal);
$configLocator->addUserConfig([$configPath], $this->environment()->systemConfigPath(), $this->environment()->userConfigPath());
$configLocator->addDrushConfig($this->environment()->drushBasePath());
// Make our environment settings available as configuration items
$configLocator->addEnvironment($this->environment());
$configLocator->addSitewideConfig($this->siteDir());
return $configLocator;
}
}

View file

@ -0,0 +1,33 @@
<?php
namespace Drush\Config;
use PHPUnit\Framework\TestCase;
/**
* The code tested here is pretty trivial; this test suite also serves
* the dual purpose of testing that the fixture data is reasonable.
*/
class EnvironmentTest extends TestCase
{
use \Drush\FixtureFactory;
function testExportConfigData()
{
$data = $this->environment()->exportConfigData();
$this->assertEquals($this->homeDir(), $data['env']['cwd']);
}
function testDocsPath()
{
$docsPath = $this->environment()->docsPath();
$this->assertInternalType('string', $docsPath, 'A docsPath was found');
$this->assertFileExists("$docsPath/README.md", 'README.md exists at docsPath');
}
function testDrushConfigFileFixturesExist()
{
$fixturesDir = $this->fixturesDir();
$this->assertFileExists("$fixturesDir/etc/drush/drush.yml", '/etc/drush/drush.yml exists');
$this->assertFileExists("$fixturesDir/home/.drush/drush.yml", '/home/.drush/drush.yml exists');
}
}

View file

@ -0,0 +1,255 @@
<?php
namespace Drush\SiteAlias;
use PHPUnit\Framework\TestCase;
use Consolidation\SiteAlias\SiteAliasFileDiscovery;
class LegacyAliasConverterTest extends TestCase
{
use \Drush\FixtureFactory;
use \Drush\FunctionUtils;
use \Drush\FSUtils;
protected $discovery;
protected $target;
protected function setUp()
{
$this->discovery = new SiteAliasFileDiscovery();
$this->discovery->addSearchLocation($this->fixturesDir() . '/sitealiases/legacy');
$this->sut = new LegacyAliasConverter($this->discovery);
$this->target = $this->tempdir();
$this->sut->setTargetDir($this->target);
}
protected function tearDown()
{
$this->removeDir($this->target);
}
protected function tempdir()
{
$tempfile = tempnam(sys_get_temp_dir(),'');
if (file_exists($tempfile)) {
unlink($tempfile);
}
mkdir($tempfile);
if (is_dir($tempfile)) {
return $tempfile;
}
}
public function testWriteOne()
{
$testPath = $this->target . '/testWriteOne.yml';
$checksumPath = $this->target . '/.checksums/testWriteOne.md5';
$testContents = 'test: This is the initial file contents';
// Write the data once, and confirm it was written.
$this->callProtected('writeOne', [$testPath, $testContents]);
$this->assertStringEqualsFile($testPath, $testContents);
// Check to see that the checksum file was written, and that
// it contains a useful comment.
$checksumContents = file_get_contents($checksumPath);
$this->assertContains("# Checksum for converted Drush alias file testWriteOne.yml.\n# Delete this checksum file or modify testWriteOne.yml to prevent further updates to it.", $checksumContents);
$overwriteContents = 'test: Overwrite the file contents';
// Write the data again, and confirm it was changed.
$this->callProtected('writeOne', [$testPath, $overwriteContents]);
$this->assertStringEqualsFile($testPath, $overwriteContents);
$simulatedEditedContents = 'test: My simulated edit';
file_put_contents($testPath, $simulatedEditedContents);
$ignoredContents = 'test: Data that is not written';
// Write the yet data again; this time, confirm that
// nothing changed, because the checksum does not match.
$this->callProtected('writeOne', [$testPath, $ignoredContents]);
$this->assertStringEqualsFile($testPath, $simulatedEditedContents);
// Write yet again, this time removing the target so that it will
// be writable again.
unlink($testPath);
$this->callProtected('writeOne', [$testPath, $overwriteContents]);
$this->assertStringEqualsFile($testPath, $overwriteContents);
$this->assertFileExists($checksumPath);
// Remove the checksum file, and confirm that the target cannot
// be overwritten
unlink($checksumPath);
$this->callProtected('writeOne', [$testPath, $ignoredContents]);
$this->assertStringEqualsFile($testPath, $overwriteContents);
}
public function testConvertAll()
{
$legacyFiles = $this->discovery->findAllLegacyAliasFiles();
$result = $this->callProtected('convertAll', [$legacyFiles]);
ksort($result);
$this->assertEquals('cc.site.yml,isp.site.yml,live.site.yml,nitrogen.site.yml,one.site.yml,outlandish-josh.site.yml,pantheon.site.yml,server.site.yml,update.site.yml', implode(',', array_keys($result)));
//$this->assertEquals('', var_export($result, true));
$this->assertEquals('dev-outlandish-josh.pantheonsite.io', $result['outlandish-josh.site.yml']['dev']['uri']);
}
public function testWriteAll()
{
$convertedFileFixtures = [
'a.yml' => [
'foo' => 'bar',
],
'b.yml' => [
],
];
$this->callProtected('cacheConvertedFilePath', ['b.aliases.drushrc.php', 'b.yml']);
$this->callProtected('writeAll', [$convertedFileFixtures]);
$this->assertFileExists($this->target . '/a.yml');
$this->assertFileExists($this->target . '/.checksums/a.md5');
$this->assertFileExists($this->target . '/b.yml');
$this->assertFileExists($this->target . '/.checksums/b.md5');
$this->assertStringEqualsFile($this->target . '/b.yml', "# This is a placeholder file used to track when b.aliases.drushrc.php was converted.\n# If you delete b.aliases.drushrc.php, then you may delete this file.");
$aContents = file_get_contents($this->target . '/a.yml');
$this->assertEquals('foo: bar', trim($aContents));
}
/**
* Test to see if the data converter produces the right data for the
* legacy alias file fixtures.
*
* @dataProvider convertLegacyFileTestData
*/
public function testConvertLegacyFile($source, $expected)
{
$legacyFile = $this->fixturesDir() . '/sitealiases/legacy/' . $source;
$result = $this->callProtected('convertLegacyFile', [$legacyFile]);
$this->assertEquals($expected, $result);
}
public function convertLegacyFileTestData()
{
return [
[
'one.alias.drushrc.php',
[
'one.site.yml' =>
[
'dev' =>
[
'uri' => 'http://example.com',
'root' => '/path/to/drupal',
],
],
],
],
[
'server.aliases.drushrc.php',
[
'isp.site.yml' =>
[
'dev' =>
[
'host' => 'hydrogen.server.org',
'user' => 'www-admin',
],
],
'nitrogen.site.yml' =>
[
'dev' =>
[
'host' => 'nitrogen.server.org',
'user' => 'admin',
],
],
],
],
[
'pantheon.aliases.drushrc.php',
[
'outlandish-josh.site.yml' =>
[
'dev' =>
[
'uri' => 'dev-outlandish-josh.pantheonsite.io',
'host' => 'appserver.dev.site-id.drush.in',
'user' => 'dev.site-id',
'paths' => [
'files' => 'code/sites/default/files',
'drush-script' => 'drush',
],
'options' => [
'db-url' => 'mysql://pantheon:pw@dbserver.dev.site-id.drush.in:21086/pantheon',
'db-allows-remote' => true,
],
'ssh' => [
'options' => '-p 2222 -o "AddressFamily inet"',
],
],
'live' =>
[
'uri' => 'www.outlandishjosh.com',
'host' => 'appserver.live.site-id.drush.in',
'user' => 'live.site-id',
'paths' => [
'files' => 'code/sites/default/files',
'drush-script' => 'drush',
],
'options' => [
'db-url' => 'mysql://pantheon:pw@dbserver.live.site-id.drush.in:10516/pantheon',
'db-allows-remote' => true,
],
'ssh' => [
'options' => '-p 2222 -o "AddressFamily inet"',
],
],
'test' =>
[
'uri' => 'test-outlandish-josh.pantheonsite.io',
'host' => 'appserver.test.site-id.drush.in',
'user' => 'test.site-id',
'paths' => [
'files' => 'code/sites/default/files',
'drush-script' => 'drush',
],
'options' => [
'db-url' => 'mysql://pantheon:pw@dbserver.test.site-id.drush.in:11621/pantheon',
'db-allows-remote' => true,
],
'ssh' => [
'options' => '-p 2222 -o "AddressFamily inet"',
],
],
],
],
],
/*
// Future: this test includes 'parent' and 'target-command-specific',
// which are not converted yet.
[
'cc.aliases.drushrc.php',
[
'cc.site.yml' =>
[
'live' =>
[
],
'update' =>
[
],
],
],
],
*/
];
}
}

View file

@ -0,0 +1,71 @@
<?php
namespace Drush\SiteAlias;
use PHPUnit\Framework\TestCase;
use Consolidation\SiteAlias\SiteAliasFileDiscovery;
class SiteAliasFileDiscoveryTest extends TestCase
{
use \Drush\FixtureFactory;
use \Drush\FunctionUtils;
function setUp()
{
$this->sut = new SiteAliasFileDiscovery();
}
public function testSearchForSingleAliasFile()
{
$this->sut->addSearchLocation($this->fixturesDir() . '/sitealiases/single');
$path = $this->sut->findSingleSiteAliasFile('single');
$this->assertLocation('single', $path);
$this->assertBasename('single.site.yml', $path);
}
public function testSearchForMissingSingleAliasFile()
{
$this->sut->addSearchLocation($this->fixturesDir() . '/sitealiases/single');
$path = $this->sut->findSingleSiteAliasFile('missing');
$this->assertFalse($path);
}
public function testFindAllLegacyAliasFiles()
{
$this->sut->addSearchLocation($this->fixturesDir() . '/sitealiases/legacy');
$result = $this->sut->findAllLegacyAliasFiles();
$paths = $this->simplifyToBasenamesWithLocation($result);
$this->assertEquals('legacy/cc.aliases.drushrc.php,legacy/one.alias.drushrc.php,legacy/pantheon.aliases.drushrc.php,legacy/server.aliases.drushrc.php', implode(',', $paths));
}
protected function assertLocation($expected, $path)
{
$this->assertEquals($expected, basename(dirname($path)));
}
protected function assertBasename($expected, $path)
{
$this->assertEquals($expected, basename($path));
}
protected function simplifyToBasenamesWithLocation($result)
{
if (!is_array($result)) {
return $result;
}
$result = array_map(
function ($item) {
return basename(dirname($item)) . '/' . basename($item);
}
,
$result
);
sort($result);
return $result;
}
}

View file

@ -0,0 +1,105 @@
<?php
namespace Drush\SiteAlias;
use PHPUnit\Framework\TestCase;
use Consolidation\SiteAlias\Util\YamlDataFileLoader;
use Consolidation\SiteAlias\AliasRecord;
class SiteAliasFileLoaderTest extends TestCase
{
use \Drush\FixtureFactory;
use \Drush\FunctionUtils;
function setUp()
{
$this->sut = new SiteAliasFileLoader();
$ymlLoader = new YamlDataFileLoader();
$this->sut->addLoader('yml', $ymlLoader);
}
public function testLoadSingleAliasFile()
{
$siteAliasFixtures = $this->fixturesDir() . '/sitealiases/single';
$this->assertTrue(is_dir($siteAliasFixtures));
$this->assertTrue(is_file($siteAliasFixtures . '/simple.site.yml'));
$this->assertTrue(is_file($siteAliasFixtures . '/single.site.yml'));
$this->sut->addSearchLocation($siteAliasFixtures);
// Look for a simple alias with no environments defined
$name = new SiteAliasName('simple');
$result = $this->callProtected('loadSingleAliasFile', [$name]);
$this->assertEquals(AliasRecord::class, get_class($result));
$this->assertEquals('/path/to/simple', $result->get('root'));
// Look for a single alias without an environment specified.
$name = new SiteAliasName('single');
$result = $this->callProtected('loadSingleAliasFile', [$name]);
$this->assertTrue($result instanceof AliasRecord);
$this->assertEquals('/path/to/single', $result->get('root'));
$this->assertEquals('bar', $result->get('foo'));
// Same test, but with environment explicitly requested.
$name = new SiteAliasName('single', 'alternate');
$result = $this->callProtected('loadSingleAliasFile', [$name]);
$this->assertTrue($result instanceof AliasRecord);
$this->assertEquals('/alternate/path/to/single', $result->get('root'));
$this->assertEquals('bar', $result->get('foo'));
// Try to fetch an alias that does not exist.
$name = new SiteAliasName('missing');
$result = $this->callProtected('loadSingleAliasFile', [$name]);
$this->assertFalse($result);
}
public function testLoadLegacy()
{
$this->sut->addSearchLocation($this->fixturesDir() . '/sitealiases/legacy');
}
public function testLoad()
{
$this->sut->addSearchLocation($this->fixturesDir() . '/sitealiases/single');
$this->sut->addSearchLocation($this->fixturesDir() . '/sitealiases/group');
// Look for a simple alias with no environments defined
$name = new SiteAliasName('simple');
$result = $this->sut->load($name);
$this->assertTrue($result instanceof AliasRecord);
$this->assertEquals('/path/to/simple', $result->get('root'));
// Look for a single alias without an environment specified.
$name = new SiteAliasName('single');
$result = $this->sut->load($name);
$this->assertTrue($result instanceof AliasRecord);
$this->assertEquals('/path/to/single', $result->get('root'));
$this->assertEquals('bar', $result->get('foo'));
// Same test, but with environment explicitly requested.
$name = new SiteAliasName('single', 'alternate');
$result = $this->sut->load($name);
$this->assertTrue($result instanceof AliasRecord);
$this->assertEquals('/alternate/path/to/single', $result->get('root'));
$this->assertEquals('bar', $result->get('foo'));
// Try to fetch an alias that does not exist.
$name = new SiteAliasName('missing');
$result = $this->sut->load($name);
$this->assertFalse($result);
// Try to fetch an alias that does not exist.
$name = new SiteAliasName('missing');
$result = $this->sut->load($name);
$this->assertFalse($result);
}
public function testLoadAll()
{
$this->sut->addSearchLocation($this->fixturesDir() . '/sitealiases/single');
$all = $this->sut->loadAll();
$this->assertEquals('@single.single.alternate,@single.single.common,@single.single.dev', implode(',', array_keys($all)));
}
}

View file

@ -0,0 +1,30 @@
<?php
namespace Drush\SiteAlias;
use PHPUnit\Framework\TestCase;
class SiteAliasNameTest extends TestCase
{
public function testSiteAliasName()
{
// Test an ambiguous sitename or env alias.
$name = SiteAliasName::parse('@simple');
$this->assertFalse($name->hasSitename());
$this->assertTrue($name->hasEnv());
$this->assertEquals('simple', $name->env());
$this->assertEquals('@self.simple', (string)$name);
// Test a non-ambiguous sitename.env alias.
$name = SiteAliasName::parse('@site.env');
$this->assertTrue($name->hasSitename());
$this->assertTrue($name->hasEnv());
$this->assertEquals('site', $name->sitename());
$this->assertEquals('env', $name->env());
$this->assertEquals('@site.env', (string)$name);
// Test an invalid alias
$name = SiteAliasName::parse('!site.env');
$this->assertFalse($name->hasSitename());
$this->assertFalse($name->hasEnv());
}
}

View file

@ -0,0 +1,174 @@
<?php
namespace Drush\SiteAlias;
use PHPUnit\Framework\TestCase;
class SiteSpecParserTest extends TestCase
{
use \Drush\FixtureFactory;
/**
* @dataProvider parserTestValues
*/
public function testSiteSpecParser(
$spec,
$expected)
{
$root = $this->siteDir();
$fixtureSite = '/' . basename($root);
$parser = new SiteSpecParser();
// If the test spec begins with '/fixtures', substitute the
// actual path to our fixture site.
$spec = preg_replace('%^/fixtures%', $root, $spec);
// Parse it!
$result = $parser->parse($spec, $root);
// If the result contains the path to our fixtures site, replace
// it with the simple string '/fixtures'.
if (isset($result['root'])) {
$result['root'] = preg_replace("%.*$fixtureSite%", '/fixtures', $result['root']);
}
// Compare the altered result with the expected value.
$this->assertEquals($expected, $result);
}
/**
* @dataProvider validSiteSpecs
*/
public function testValidSiteSpecs($spec)
{
$this->isSpecValid($spec, true);
}
/**
* @dataProvider invalidSiteSpecs
*/
public function testInvalidSiteSpecs($spec)
{
$this->isSpecValid($spec, false);
}
protected function isSpecValid($spec, $expected)
{
$parser = new SiteSpecParser();
$result = $parser->validSiteSpec($spec);
$this->assertEquals($expected, $result);
}
public static function validSiteSpecs()
{
return [
[ '/path/to/drupal#uri' ],
[ 'user@server/path/to/drupal#uri' ],
[ 'user.name@example.com/path/to/drupal#uri' ],
[ 'user@server/path/to/drupal' ],
[ 'user@example.com/path/to/drupal' ],
[ 'user@server#uri' ],
[ 'user@example.com#uri' ],
[ '#uri' ],
];
}
public static function invalidSiteSpecs()
{
return [
[ 'uri' ],
[ '@/#' ],
[ 'user@#uri' ],
[ '@server/path/to/drupal#uri' ],
[ 'user@server/path/to/drupal#' ],
[ 'user@server/path/to/drupal#uri!' ],
[ 'user@server/path/to/drupal##uri' ],
[ 'user#server/path/to/drupal#uri' ],
];
}
public static function parserTestValues()
{
return [
[
'user@server/path#somemultisite',
[
'user' => 'user',
'host' => 'server',
'root' => '/path',
'uri' => 'somemultisite',
],
],
[
'user.name@example.com/path#somemultisite',
[
'user' => 'user.name',
'host' => 'example.com',
'root' => '/path',
'uri' => 'somemultisite',
],
],
[
'user@server/path',
[
'user' => 'user',
'host' => 'server',
'root' => '/path',
'uri' => 'default',
],
],
[
'user.name@example.com/path',
[
'user' => 'user.name',
'host' => 'example.com',
'root' => '/path',
'uri' => 'default',
],
],
[
'/fixtures#mymultisite',
[
'root' => '/fixtures',
'uri' => 'mymultisite',
],
],
[
'#mymultisite',
[
'root' => '/fixtures',
'uri' => 'mymultisite',
],
],
[
'/fixtures#somemultisite',
[
],
],
[
'/path#somemultisite',
[
],
],
[
'/path#mymultisite',
[
],
],
[
'#somemultisite',
[
],
],
];
}
}

View file

@ -0,0 +1,62 @@
<?php
// Get a $_SERVER key, or equivalent environment variable
// if it is not set in $_SERVER.
function runserver_env($key) {
if (isset($_SERVER[$key])) {
return $_SERVER[$key];
}
else {
return getenv($key);
}
}
$url = parse_url($_SERVER["REQUEST_URI"]);
if (file_exists('.' . urldecode($url['path']))) {
// Serve the requested resource as-is.
return FALSE;
}
// We set the base_url so that Drupal generates correct URLs for runserver
// (e.g. http://127.0.0.1:8888/...), but can still select and serve a specific
// site in a multisite configuration (e.g. http://mysite.com/...).
$base_url = runserver_env('RUNSERVER_BASE_URL');
// The built in webserver incorrectly sets $_SERVER['SCRIPT_NAME'] when URLs
// contain multiple dots (such as config entity IDs) in the path. Since this is
// a virtual resource, served by index.php set the script name explicitly.
// See https://github.com/drush-ops/drush/issues/2033 for more information.
// Work around the PHP bug. Update $_SERVER variables to point to the correct
// index-file.
$path = $url['path'];
$script = 'index.php';
if (strpos($path, '.php') !== FALSE) {
// Work backwards through the path to check if a script exists. Otherwise
// fallback to index.php.
do {
$path = dirname($path);
if (preg_match('/\.php$/', $path) && is_file('.' . $path)) {
// Discovered that the path contains an existing PHP file. Use that as the
// script to include.
$script = ltrim($path, '/');
break;
}
} while ($path !== '/' && $path !== '.');
}
// Update $_SERVER variables to point to the correct index-file.
$index_file_absolute = $_SERVER['DOCUMENT_ROOT'] . DIRECTORY_SEPARATOR . $script;
$index_file_relative = DIRECTORY_SEPARATOR . $script;
// SCRIPT_FILENAME will point to the router script itself, it should point to
// the full path of index.php.
$_SERVER['SCRIPT_FILENAME'] = $index_file_absolute;
// SCRIPT_NAME and PHP_SELF will either point to index.php or contain the full
// virtual path being requested depending on the URL being requested. They
// should always point to index.php relative to document root.
$_SERVER['SCRIPT_NAME'] = $index_file_relative;
$_SERVER['PHP_SELF'] = $index_file_relative;
// Require the script and let core take over.
require $_SERVER['SCRIPT_FILENAME'];

Some files were not shown because too many files have changed in this diff Show more