-
-
Notifications
You must be signed in to change notification settings - Fork 645
Make Drupal VM into a Composer plugin that scaffolds a Vagrantfile #1256
base: master
Are you sure you want to change the base?
Changes from all commits
ed6d032
20db9b5
558b82e
2aa0620
d2b6c9a
1c53c9b
0da90e2
9a8b183
5df9430
25a7650
e27c427
5592ed1
fba5045
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,19 +1,37 @@ | ||
# -*- mode: ruby -*- | ||
# vi: set ft=ruby : | ||
|
||
require_relative 'lib/drupalvm/vagrant' | ||
require 'json' | ||
|
||
# Absolute paths on the host machine. | ||
host_drupalvm_dir = File.dirname(File.expand_path(__FILE__)) | ||
host_project_dir = ENV['DRUPALVM_PROJECT_ROOT'] || host_drupalvm_dir | ||
host_config_dir = ENV['DRUPALVM_CONFIG_DIR'] ? "#{host_project_dir}/#{ENV['DRUPALVM_CONFIG_DIR']}" : host_project_dir | ||
drupalvm_env = ENV['DRUPALVM_ENV'] || 'vagrant' | ||
|
||
# Absolute paths on the guest machine. | ||
guest_project_dir = '/vagrant' | ||
guest_drupalvm_dir = ENV['DRUPALVM_DIR'] ? "/vagrant/#{ENV['DRUPALVM_DIR']}" : guest_project_dir | ||
guest_config_dir = ENV['DRUPALVM_CONFIG_DIR'] ? "/vagrant/#{ENV['DRUPALVM_CONFIG_DIR']}" : guest_project_dir | ||
# Default paths when the project is based on Drupal VM. | ||
host_project_dir = host_drupalvm_dir = host_config_dir = __dir__ | ||
guest_project_dir = guest_drupalvm_dir = guest_config_dir = '/vagrant' | ||
|
||
drupalvm_env = ENV['DRUPALVM_ENV'] || 'vagrant' | ||
if File.exist?("#{host_project_dir}/composer.json") | ||
cconfig = {} | ||
composer_conf = JSON.parse(File.read("#{host_project_dir}/composer.json")) | ||
if composer_conf['extra'] && composer_conf['extra']['drupalvm'] | ||
cconfig = composer_conf['extra']['drupalvm'] | ||
end | ||
|
||
# If Drupal VM is a Composer dependency set the correct path. | ||
vendor_dir = ENV['COMPOSER_VENDOR_DIR'] || composer_conf.fetch('config', {}).fetch('vendor-dir', 'vendor') | ||
drupalvm_path = "#{vendor_dir}/geerlingguy/drupal-vm" | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. One problem here. There are some Windows developers who might prefer to code entirely within the VM right? This is why I'm avoiding calls to Also this setup requires the user to run There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Could also allow the user to specify the path to Drupal VM in the drupalvm_path = cconfig['path'] || "#{vendor_dir}/geerlingguy/drupal-vm" There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I like this better than depending on composer being available in the current session. Also need to consider env vars -- https://getcomposer.org/doc/03-cli.md#composer-vendor-dir There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more.
Yes. (And the occasional Mac or Linux user who likes the isolation.)
Preferably, yes. But right now there are a lot of Windows devs who neither want nor are allowed to set up PHP and/or Composer on Windows... but it could be possible we could make that a requirement for 5.0.0+... There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more.
Would these devs still be using Drupal VM as a composer dependency? There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. There's also the possibility that someone commits all dependencies and therefore not all Devs would need composer.. There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. So for example a tech lead might use composer on behalf of the rest of the team and track all dependencies - https://www.codeenigma.com/build/blog/do-you-really-need-composer-production I personally prefer an isolated build process but some might use DVM as composer dep without composer |
||
if Dir.exist?("#{host_project_dir}/#{drupalvm_path}") | ||
host_drupalvm_dir = "#{host_project_dir}/#{drupalvm_path}" | ||
guest_drupalvm_dir = "#{guest_project_dir}/#{drupalvm_path}" | ||
end | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. One annoying thing here is that this wouldn't support forks... any ideas? |
||
|
||
# Read config_dir from composer.json if set. | ||
if cconfig.include?('config_dir') | ||
host_config_dir = "#{host_project_dir}/#{cconfig['config_dir']}" | ||
guest_config_dir = "#{guest_project_dir}/#{cconfig['config_dir']}" | ||
end | ||
end | ||
|
||
require "#{host_drupalvm_dir}/lib/drupalvm/vagrant" | ||
|
||
default_config_file = "#{host_drupalvm_dir}/default.config.yml" | ||
unless File.exist?(default_config_file) | ||
|
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,91 @@ | ||
<?php | ||
/** | ||
* @file | ||
* Contains JJG\DrupalVM|Plugin. | ||
*/ | ||
|
||
namespace JJG\DrupalVM; | ||
|
||
use Composer\Composer; | ||
use Composer\EventDispatcher\EventSubscriberInterface; | ||
use Composer\Factory; | ||
use Composer\IO\IOInterface; | ||
use Composer\Plugin\PluginInterface; | ||
use Composer\Script\Event; | ||
use Composer\Script\ScriptEvents; | ||
|
||
class Plugin implements PluginInterface, EventSubscriberInterface { | ||
|
||
/** | ||
* @var \Composer\Composer | ||
*/ | ||
protected $composer; | ||
|
||
/** | ||
* @var \Composer\IO\IOInterface | ||
*/ | ||
protected $io; | ||
|
||
/** | ||
* {@inheritdoc} | ||
*/ | ||
public function activate(Composer $composer, IOInterface $io) { | ||
$this->composer = $composer; | ||
$this->io = $io; | ||
} | ||
|
||
/** | ||
* {@inheritdoc} | ||
*/ | ||
public static function getSubscribedEvents() { | ||
return array( | ||
ScriptEvents::POST_INSTALL_CMD => 'addVagrantfile', | ||
ScriptEvents::POST_UPDATE_CMD => 'addVagrantfile', | ||
); | ||
} | ||
|
||
/** | ||
* Add/update project Vagrantfile. | ||
* | ||
* @param \Composer\Script\Event $event | ||
*/ | ||
public function addVagrantfile(Event $event) { | ||
|
||
$baseDir = dirname(Factory::getComposerFile()); | ||
$source = __DIR__ . '/../../Vagrantfile'; | ||
$target = $baseDir . '/Vagrantfile'; | ||
|
||
if (file_exists($source)) { | ||
if (!file_exists($target) || md5_file($source) != md5_file($target)) { | ||
$isLegacy = $this->isLegacyVagrantfile($target); | ||
|
||
copy($source, $target); | ||
|
||
$extra = $this->composer->getPackage()->getExtra(); | ||
if ($isLegacy && !isset($extra['drupalvm']['config_dir'])) { | ||
$this->io->writeError( | ||
'<warning>' | ||
. 'Drupal VM has been updated and consequently written over your Vagrantfile which from now on will be managed by Drupal VM. ' | ||
. 'Due to this change, you are required to set the `config_dir` location in your composer.json file:' | ||
. "\n" | ||
. "\n $ composer config extra.drupalvm.config_dir <sub-directory>" | ||
. "\n" | ||
. '</warning>' | ||
); | ||
} | ||
} | ||
} | ||
} | ||
|
||
/** | ||
* Return if the parent project is using the < 5.0.0 delegating Vagrantfile. | ||
* | ||
* @return bool | ||
*/ | ||
private function isLegacyVagrantfile($vagrantfile) { | ||
if (!file_exists($vagrantfile)) { | ||
return false; | ||
} | ||
return strpos(file_get_contents($vagrantfile), '# Load the real Vagrantfile') !== false; | ||
} | ||
} |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,151 +1,38 @@ | ||
To make future Drupal VM updates easier to integrate with an existing project, you might consider the more complex setup of installing Drupal VM as a `composer` dependency. Using a delegating `Vagrantfile` you are able to run `vagrant` commands anywhere in your project as well as separate your custom configuration files from Drupal VM's own files. | ||
If you're setting up a new project you can get up and running quickly using [drupal-composer/drupal-project](https://github.com/drupal-composer/drupal-project) as a project template. | ||
|
||
### Add Drupal VM as a Composer dependency | ||
|
||
Add Drupal VM as a development dependency to your `composer.json`. | ||
|
||
``` | ||
composer require --dev geerlingguy/drupal-vm | ||
``` | ||
|
||
### Setup your configuration files | ||
|
||
Add and configure the `config.yml` anywhere you like, in this example we place it in a `config/` directory. | ||
|
||
_Note: This will be the directory where Drupal VM looks for other local configuration files as well. Such as `drupal_build_makefile` and `local.config.yml`._ | ||
|
||
``` | ||
├── composer.json | ||
├── config/ | ||
│ ├── config.yml | ||
│ ├── local.config.yml | ||
│ └── Vagrantfile.local | ||
├── docroot/ | ||
│ ├── ... | ||
│ └── index.php | ||
└── vendor/ | ||
├── ... | ||
└── geerlingguy/ | ||
└── drupal-vm/ | ||
``` | ||
|
||
Change the [build strategy to use your `composer.json`](composer.md#using-composer-when-drupal-vm-is-a-composer-dependency-itself) file by setting: | ||
|
||
```yaml | ||
drupal_build_composer_project: false | ||
drupal_build_composer: true | ||
drupal_composer_path: false | ||
drupal_composer_install_dir: "/var/www/drupalvm" | ||
drupal_core_path: "{{ drupal_composer_install_dir }}/docroot" | ||
``` | ||
|
||
If you intened to use the devel module, it must be added as a requirement to your `composer.json` file. Alternatively, if you do not intend to use it remove it from `drupal_enabled_modules` in your `config.yml` file: | ||
|
||
```yaml | ||
drupal_enabled_modules: [] | ||
``` | ||
|
||
If you're using `pre_provision_scripts` or `post_provision_scripts` you also need to adjust their paths to take into account the new directory structure. The examples used in `default.config.yml` assume the files are located in the Drupal VM directory. You can use the `config_dir` variable which is the absolute path of the directory where your `config.yml` is located. | ||
|
||
```yaml | ||
post_provision_scripts: | ||
# The default provided in `default.config.yml`: | ||
- "../../examples/scripts/configure-solr.sh" | ||
# With Drupal VM as a Composer dependency: | ||
- "{{ config_dir }}/../examples/scripts/configure-solr.sh" | ||
``` | ||
|
||
### Create a delegating `Vagrantfile` | ||
|
||
Create a delegating `Vagrantfile` that will catch all your `vagrant` commands and send them to Drupal VM's own `Vagrantfile`. Place this file in your project's root directory. | ||
|
||
```ruby | ||
# The absolute path to the root directory of the project. Both Drupal VM and | ||
# the config file need to be contained within this path. | ||
ENV['DRUPALVM_PROJECT_ROOT'] = "#{__dir__}" | ||
# The relative path from the project root to the config directory where you | ||
# placed your config.yml file. | ||
ENV['DRUPALVM_CONFIG_DIR'] = "config" | ||
# The relative path from the project root to the directory where Drupal VM is located. | ||
ENV['DRUPALVM_DIR'] = "vendor/geerlingguy/drupal-vm" | ||
|
||
# Load the real Vagrantfile | ||
load "#{__dir__}/#{ENV['DRUPALVM_DIR']}/Vagrantfile" | ||
```sh | ||
composer create-project drupal-composer/drupal-project:8.x-dev <some-dir> --stability dev --no-interaction | ||
``` | ||
|
||
When you issue `vagrant` commands anywhere in your project tree this file will be detected and used as a delegator for Drupal VM's own Vagrantfile. | ||
### Add Drupal VM as a Composer dependency | ||
|
||
Your project structure should now look like this: | ||
Require Drupal VM as a development dependency to your project. | ||
|
||
``` | ||
├── Vagrantfile | ||
├── composer.json | ||
├── config/ | ||
│ ├── config.yml | ||
│ ├── local.config.yml | ||
│ └── Vagrantfile.local | ||
├── docroot/ | ||
│ ├── ... | ||
│ └── index.php | ||
└── vendor/ | ||
├── ... | ||
└── geerlingguy/ | ||
└── drupal-vm/ | ||
``` | ||
composer require --dev geerlingguy/drupal-vm | ||
|
||
### Provision the VM | ||
_This command will scaffold a `Vagrantfile` in the root of your project. Feel free to add it to your `.gitignore` as the file is now managed by Drupal VM and will be reset each time you run `composer update`._ | ||
|
||
Finally provision the VM using the delegating `Vagrantfile`. | ||
### Create a `config.yml` to configure the VM | ||
|
||
```sh | ||
vagrant up | ||
``` | ||
Create and configure a config.yml file, eg. in `vm/config.yml`. You'll need at least the following variables: | ||
|
||
_Important: you should never issue `vagrant` commands through Drupal VM's own `Vagrantfile` from now on. If you do, it will create a secondary VM in that directory._ | ||
# Change the build strategy to use a composer.json file. | ||
drupal_build_composer: true | ||
drupal_build_composer_project: false | ||
|
||
## Drupal VM in a subdirectory without composer | ||
# Tell Drupal VM that the composer.json file already exists and doesn't need to be transfered. | ||
drupal_composer_path: false | ||
|
||
If you're not using `composer` in your project you can still download Drupal VM (or add it as a git submodule) to any subdirectory in your project. As an example let's name that directory `box/`. | ||
# Set the location of the composer.json file and Drupal core. | ||
drupal_composer_install_dir: "/var/www/drupalvm" | ||
drupal_core_path: "{{ drupal_composer_install_dir }}/web" | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Would it be too much to print this in the console if Drupal VM is added and no prior |
||
|
||
``` | ||
├── docroot/ | ||
│ ├── ... | ||
│ └── index.php | ||
└── box/ | ||
├── ... | ||
├── default.config.yml | ||
└── Vagrantfile | ||
``` | ||
_Note that `drupal_core_path` needs to match your `composer.json` configuration. `drupal-project` uses `web/` whereas Lightning and BLT uses `docroot/`_ | ||
|
||
Configure your `config.yml` as mentioned in the [`composer` section](#setup-your-configuration-files) above. | ||
If you placed the `config.yml` file in a subdirectory, tell Drupal VM where by adding the location to your `composer.json`. If not, Drupal VM will look for all configuration files in the root of your project. | ||
|
||
```yaml | ||
post_provision_scripts: | ||
# The default provided in `default.config.yml`: | ||
- "../../examples/scripts/configure-solr.sh" | ||
# With Drupal VM in a toplevel subdirectory | ||
- "{{ config_dir }}/../examples/scripts/configure-solr.sh" | ||
``` | ||
composer config extra.drupalvm.config_dir 'vm' | ||
|
||
Your directory structure should now look like this: | ||
## Patching Drupal VM | ||
|
||
``` | ||
├── Vagrantfile | ||
├── config/ | ||
│ ├── config.yml | ||
│ ├── local.config.yml | ||
│ └── Vagrantfile.local | ||
├── docroot/ | ||
│ ├── ... | ||
│ └── index.php | ||
└── box/ | ||
├── ... | ||
├── default.config.yml | ||
└── Vagrantfile | ||
``` | ||
|
||
Provision the VM using the delegating `Vagrantfile`. | ||
|
||
```sh | ||
vagrant up | ||
``` | ||
If you need to patch something in Drupal VM that you're otherwise unable to configure, you can do so with the help of the `composer-patches` plugin. Read the [documentation on how to create and apply patches](../extending/patching.md). |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,5 +1,7 @@ | ||
Drupal VM is configured to use `composer create-project` to build a Drupal 8 codebase by default but supports building Drupal from a custom `composer.json` file as well. | ||
|
||
_Note that if you already have a project built using a `composer.json` file you should instead add [Drupal VM as a dependency](composer-dependency.md) of your project. The method described below will make it somewhat difficult to manage your `composer.json` together with Drupal VM as the file will be copied from `drupal_composer_path` into `drupal_composer_install_dir` as a secondary `composer.json`._ | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Are you okay with this, or maybe too scary? Honestly I think we should default There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Or well that's a bit odd too. Maybe it should be renamed |
||
|
||
1. Copy `example.drupal.composer.json` to `drupal.composer.json` and modify it to your liking. | ||
2. Use the Composer build system by setting `drupal_build_composer: true` in your `config.yml` (make sure `drupal_build_makefile` and `drupal_build_composer_project` are set to `false`). | ||
3. Ensure `drupal_core_path` points to the webroot directory: `drupal_core_path: {{ drupal_composer_install_dir }}/web` | ||
|
@@ -11,18 +13,6 @@ drupal_build_composer: true | |
drupal_core_path: "{{ drupal_composer_install_dir }}/web" | ||
``` | ||
|
||
_The file set in `drupal_composer_path` (which defaults to `drupal.composer.json`) will be copied from your host computer into the VM's `drupal_composer_install_dir` and renamed `composer.json`._ | ||
|
||
## Using Composer when [Drupal VM is a composer dependency itself](composer-dependency.md) | ||
|
||
In the scenario where you have an existing `composer.json` in the root of your project, follow the usual steps for installing with a composer.json but instead of creating a `drupal.composer.json` file, disable the transfering of the file by setting `drupal_composer_path: false`, and change `drupal_composer_install_dir` to point to the the directory where it will be located. If `drupal_composer_path` is not truthy, Drupal VM assumes it already exists. | ||
|
||
```yaml | ||
drupal_build_composer_project: false | ||
drupal_build_composer: true | ||
drupal_composer_path: false | ||
drupal_composer_install_dir: "/var/www/drupalvm" | ||
drupal_core_path: "{{ drupal_composer_install_dir }}/docroot" | ||
``` | ||
The file set in `drupal_composer_path` (which defaults to `drupal.composer.json`) will be copied from your host computer into the VM's `drupal_composer_install_dir` and renamed `composer.json`. | ||
|
||
_Opting for composer based installs will most likely increase your VM's time to provision considerably. Find out how you can [improve composer build performance](../other/performance.md#improving-composer-build-performance)._ |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,21 @@ | ||
There are two supported methods of integrating Drupal VM with your site. You can either download Drupal VM and integrate your site inside the project, or you can add Drupal VM as a Composer dependency to your existing project. | ||
|
||
## Download Drupal VM and integrate your project. | ||
|
||
The easiest way to get started with Drupal VM is to download the [latest release](https://www.drupalvm.com/), open the terminal, `cd` to the directory, and type `vagrant up`. | ||
|
||
Using this method you have various options of how your site will be built, or if it will be built by Drupal VM at all: | ||
|
||
- [Build using a local codebase](../deployment/local-codebase.md) | ||
- [Build using a Composer package](../deployment/composer-package.md) (default) | ||
- [Build using a composer.json](../deployment/composer.md) | ||
- [Build using a Drush Make file](../deployment/drush-make.md) | ||
- [Deploy Drupal via Git](../deployment/git.md) | ||
|
||
## Add Drupal VM as a Composer depedency to an existing project | ||
|
||
_If you're using Composer to manage your project, having Drupal VM as dependency makes it easier to pull in future updates._ | ||
|
||
Using this method you only have one option of how your site will be built, it will be built using your parent project's `composer.json` file. | ||
|
||
- [Add Drupal VM to your project using Composer](../deployment/composer-dependency.md) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
vendor_dir
being a function seems very unclear to me coming from PHP. Rubocop complains if I add unnecessary parenthesis though. Maybe I should drop that lint?