commit 33d8670b1f72d89dddc2055736f884867cfa3c9e Author: Bruno Skvorc Date: Tue Dec 25 15:55:43 2018 +0100 Initial commit diff --git a/.gitattributes b/.gitattributes new file mode 100644 index 0000000..fcadb2c --- /dev/null +++ b/.gitattributes @@ -0,0 +1 @@ +* text eol=lf diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..76cc12e --- /dev/null +++ b/.gitignore @@ -0,0 +1,2 @@ +/vendor +/.vagrant diff --git a/Homestead.yaml b/Homestead.yaml new file mode 100644 index 0000000..47cf282 --- /dev/null +++ b/Homestead.yaml @@ -0,0 +1,42 @@ +--- +ip: "192.168.10.10" +memory: 2048 +cpus: 1 +provider: virtualbox + +folders: + - map: . + to: /home/vagrant/Code + +sites: + - map: homestead.test + to: /home/vagrant/Code/Project/public + +databases: + - homestead + +#variables: +# - key: APP_ENV +# value: local + +# blackfire: +# - id: foo +# token: bar +# client-id: foo +# client-token: bar + +ports: + - send: 8545 + to: 8545 + - send: 30301 + to: 30301 + - send: 30302 + to: 30302 + - send: 30303 + to: 30303 + - send: 30304 + to: 30304 + - send: 30305 + to: 30305 + - send: 30306 + to: 30306 diff --git a/LICENSE.txt b/LICENSE.txt new file mode 100644 index 0000000..1ce5963 --- /dev/null +++ b/LICENSE.txt @@ -0,0 +1,21 @@ +The MIT License (MIT) + +Copyright (c) + +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. diff --git a/Vagrantfile b/Vagrantfile new file mode 100644 index 0000000..ef2ba1f --- /dev/null +++ b/Vagrantfile @@ -0,0 +1,28 @@ +require 'json' +require 'yaml' + +VAGRANTFILE_API_VERSION = "2" +confDir = $confDir ||= File.expand_path(".") + +homesteadYamlPath = confDir + "/Homestead.yaml" +homesteadJsonPath = confDir + "/Homestead.json" +afterScriptPath = confDir + "/after.sh" +aliasesPath = confDir + "/aliases" + +require File.expand_path(File.dirname(__FILE__) + '/scripts/homestead.rb') + +Vagrant.configure(VAGRANTFILE_API_VERSION) do |config| + if File.exists? aliasesPath then + config.vm.provision "file", source: aliasesPath, destination: "~/.bash_aliases" + end + + if File.exists? homesteadYamlPath then + Homestead.configure(config, YAML::load(File.read(homesteadYamlPath))) + elsif File.exists? homesteadJsonPath then + Homestead.configure(config, JSON.parse(File.read(homesteadJsonPath))) + end + + if File.exists? afterScriptPath then + config.vm.provision "shell", path: afterScriptPath + end +end diff --git a/after.sh b/after.sh new file mode 100644 index 0000000..85402e8 --- /dev/null +++ b/after.sh @@ -0,0 +1,5 @@ +#!/bin/sh + +# If you would like to do some extra provisioning you may +# add any commands you wish to this file and they will +# be run after the Homestead machine is provisioned. diff --git a/aliases b/aliases new file mode 100644 index 0000000..72f14ce --- /dev/null +++ b/aliases @@ -0,0 +1,33 @@ +alias ..="cd .." +alias ...="cd ../.." + +alias h='cd ~' +alias c='clear' +alias artisan='php artisan' + +alias phpspec='vendor/bin/phpspec' +alias phpunit='vendor/bin/phpunit' + +function serve() { + if [[ "$1" && "$2" ]] + then + sudo dos2unix /vagrant/scripts/serve.sh + sudo bash /vagrant/scripts/serve.sh "$1" "$2" 80 + else + echo "Error: missing required parameters." + echo "Usage: " + echo " serve domain path" + fi +} + +function serve-hhvm() { + if [[ "$1" && "$2" ]] + then + sudo dos2unix /vagrant/scripts/serve-hhvm.sh + sudo bash /vagrant/scripts/serve-hhvm.sh "$1" "$2" 80 + else + echo "Error: missing required parameters." + echo "Usage: " + echo " serve-hhvm domain path" + fi +} diff --git a/bin/folderfix.sh b/bin/folderfix.sh new file mode 100644 index 0000000..103ccbf --- /dev/null +++ b/bin/folderfix.sh @@ -0,0 +1,19 @@ +#!/bin/bash + +if [ "$(uname)" == "Darwin" ] +then + # Mac OSX + sed -i '' "s@map\: \.@map\: $PWD@g" Homestead.yaml +elif [ "$(expr substr $(uname -s) 1 5)" == "Linux" ] +then + sed -i "s@map\: \.@map\: $PWD@g" Homestead.yaml +elif [ -n "$COMSPEC" -a -x "$COMSPEC" ] +then + var=$PWD + sub=${var:0:1} + workdir=${var/$sub/""}; + + sub=${workdir:1:1} + workdir=${workdir/$sub/":/"} + sed -i "s@map\: \.@map\: $workdir@g" Homestead.yaml +fi diff --git a/bin/sulu/vendorfix.sh b/bin/sulu/vendorfix.sh new file mode 100644 index 0000000..a8273cd --- /dev/null +++ b/bin/sulu/vendorfix.sh @@ -0,0 +1,47 @@ +#!/bin/bash + +# Figure out name of Sulu app, save into variable +NAME=$(grep -oP -m 1 '\K(.+)(?=<\/name>)' app/Resources/webspaces/sulu.io.xml) + +# Figure out new vendor folder name +VENDORPATH="/home/vagrant/vendors/sulu-$NAME/" + +# Create new vendor folder +mkdir -p $VENDORPATH + +# Change vendor in 'composer.json' unless 'vendor-dir' already exists +if [[ -z $(grep "vendor-dir" composer.json) ]]; then + sed -i "s@\"config\": {@\"config\": {\n\t\"vendor-dir\": \"$VENDORPATH\",@g" composer.json + sed -i "s@\"bin-dir\": \"bin\"@\"bin-dir\": \"vendor/bin\"@g" composer.json +else + echo "[Safety block] config.vendor-dir value in composer.json already defined. Remove line and try running the script again. Other commands will still execute." +fi + +# Change app/autoload.php's assumption of where the vendor folder is +LOADER="\$loader = require __DIR__.'/../vendor/autoload.php';" +NEWLOADER="/*\n\[app/autoload.php fix\] Commented out by bin/sulu/vendorfix.sh\n\$loader = require __DIR__ . '/../vendor/autoload.php';\n*/\n\$loader = require \"$VENDORPATH/autoload.php\";" + +if [[ -z $(grep '\[app/autoload.php fix\]' app/autoload.php) ]]; then + sed -i "s@$LOADER@$NEWLOADER@g" app/autoload.php +else + echo "[Safety block] app/autoload.php file already modified for custom vendor location. Not changing it." +fi + +# Add new vendor location to sulu.yml +YMLFILE='app/config/sulu.yml'; +if [[ -z $(grep "\[app/config/sulu.yml fix\]" app/config/sulu.yml) ]]; then + sed -i "s@%kernel.root_dir%/../vendor/@$VENDORPATH@g" $YMLFILE + echo "#[app/config/sulu.yml fix] Vendor location changed by bin/sulu/vendorfix.sh - not doing any more changes." >> $YMLFILE +else + echo "[Safety block] app/config/sulu.yml already modified for custom vendor location. Not changing it." +fi + +# Remove current vendor folder +echo "Removing current vendor folder.\n" +rm -rf vendor + +# Install dependencies in newly configured location +echo "Starting Composer installation.\n" +composer install +composer update +app/console cache:clear diff --git a/composer.json b/composer.json new file mode 100644 index 0000000..72adcc4 --- /dev/null +++ b/composer.json @@ -0,0 +1,29 @@ +{ + "name": "Homestead Improved", + "description": "See here: http://www.sitepoint.com/quick-tip-get-homestead-vagrant-vm-running/", + "require": { + "php": ">=7", + "symfony/console": "~2.0", + "symfony/process": "~2.0", + "symfony/yaml": "^3.3" + }, + "license": "MIT", + "authors": [ + { + "name": "Taylor Otwell", + "email": "taylorotwell@gmail.com" + }, + { + "name": "Bruno Skvorc", + "email": "bruno.skvorc@sitepoint.com" + } + ], + "autoload": { + "psr-4": { + "Laravel\\Homestead\\": "src/" + } + }, + "bin": [ + "homestead" + ] +} diff --git a/composer.lock b/composer.lock new file mode 100644 index 0000000..cb64d38 --- /dev/null +++ b/composer.lock @@ -0,0 +1,179 @@ +{ + "_readme": [ + "This file locks the dependencies of your project to a known state", + "Read more about it at https://getcomposer.org/doc/01-basic-usage.md#composer-lock-the-lock-file", + "This file is @generated automatically" + ], + "content-hash": "8c0e784cc156bfd7da46c535ee5cc78e", + "packages": [ + { + "name": "symfony/console", + "version": "v2.6.4", + "target-dir": "Symfony/Component/Console", + "source": { + "type": "git", + "url": "https://github.com/symfony/console.git", + "reference": "e44154bfe3e41e8267d7a3794cd9da9a51cfac34" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/symfony/console/zipball/e44154bfe3e41e8267d7a3794cd9da9a51cfac34", + "reference": "e44154bfe3e41e8267d7a3794cd9da9a51cfac34", + "shasum": "" + }, + "require": { + "php": ">=5.3.3" + }, + "require-dev": { + "psr/log": "~1.0", + "symfony/event-dispatcher": "~2.1", + "symfony/process": "~2.1" + }, + "suggest": { + "psr/log": "For using the console logger", + "symfony/event-dispatcher": "", + "symfony/process": "" + }, + "type": "library", + "extra": { + "branch-alias": { + "dev-master": "2.6-dev" + } + }, + "autoload": { + "psr-0": { + "Symfony\\Component\\Console\\": "" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Symfony Community", + "homepage": "http://symfony.com/contributors" + }, + { + "name": "Fabien Potencier", + "email": "fabien@symfony.com" + } + ], + "description": "Symfony Console Component", + "homepage": "http://symfony.com", + "time": "2015-01-25T04:39:26+00:00" + }, + { + "name": "symfony/process", + "version": "v2.6.4", + "target-dir": "Symfony/Component/Process", + "source": { + "type": "git", + "url": "https://github.com/symfony/Process.git", + "reference": "ecfc23e89d9967999fa5f60a1e9af7384396e9ae" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/symfony/Process/zipball/ecfc23e89d9967999fa5f60a1e9af7384396e9ae", + "reference": "ecfc23e89d9967999fa5f60a1e9af7384396e9ae", + "shasum": "" + }, + "require": { + "php": ">=5.3.3" + }, + "type": "library", + "extra": { + "branch-alias": { + "dev-master": "2.6-dev" + } + }, + "autoload": { + "psr-0": { + "Symfony\\Component\\Process\\": "" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Symfony Community", + "homepage": "http://symfony.com/contributors" + }, + { + "name": "Fabien Potencier", + "email": "fabien@symfony.com" + } + ], + "description": "Symfony Process Component", + "homepage": "http://symfony.com", + "time": "2015-01-25T04:39:26+00:00" + }, + { + "name": "symfony/yaml", + "version": "v3.3.10", + "source": { + "type": "git", + "url": "https://github.com/symfony/yaml.git", + "reference": "8c7bf1e7d5d6b05a690b715729cb4cd0c0a99c46" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/symfony/yaml/zipball/8c7bf1e7d5d6b05a690b715729cb4cd0c0a99c46", + "reference": "8c7bf1e7d5d6b05a690b715729cb4cd0c0a99c46", + "shasum": "" + }, + "require": { + "php": "^5.5.9|>=7.0.8" + }, + "require-dev": { + "symfony/console": "~2.8|~3.0" + }, + "suggest": { + "symfony/console": "For validating YAML files using the lint command" + }, + "type": "library", + "extra": { + "branch-alias": { + "dev-master": "3.3-dev" + } + }, + "autoload": { + "psr-4": { + "Symfony\\Component\\Yaml\\": "" + }, + "exclude-from-classmap": [ + "/Tests/" + ] + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Fabien Potencier", + "email": "fabien@symfony.com" + }, + { + "name": "Symfony Community", + "homepage": "https://symfony.com/contributors" + } + ], + "description": "Symfony Yaml Component", + "homepage": "https://symfony.com", + "time": "2017-10-05T14:43:42+00:00" + } + ], + "packages-dev": [], + "aliases": [], + "minimum-stability": "stable", + "stability-flags": [], + "prefer-stable": false, + "prefer-lowest": false, + "platform": { + "php": ">=7" + }, + "platform-dev": [] +} diff --git a/homestead b/homestead new file mode 100644 index 0000000..bdc34d0 --- /dev/null +++ b/homestead @@ -0,0 +1,41 @@ +#!/usr/bin/env php +add(new Laravel\Homestead\DestroyCommand); +$app->add(new Laravel\Homestead\EditCommand); +$app->add(new Laravel\Homestead\HaltCommand); +$app->add(new Laravel\Homestead\InitCommand); +$app->add(new Laravel\Homestead\MakeCommand); +$app->add(new Laravel\Homestead\ProvisionCommand); +$app->add(new Laravel\Homestead\ResumeCommand); +$app->add(new Laravel\Homestead\RunCommand); +$app->add(new Laravel\Homestead\UpCommand); +$app->add(new Laravel\Homestead\UpdateCommand); +$app->add(new Laravel\Homestead\SshCommand); +$app->add(new Laravel\Homestead\SshConfigCommand); +$app->add(new Laravel\Homestead\StatusCommand); +$app->add(new Laravel\Homestead\SuspendCommand); +$app->add(new Laravel\Homestead\AddSiteCommand); +$app->add(new Laravel\Homestead\AddDatabaseCommand); + +$app->run(); diff --git a/readme.md b/readme.md new file mode 100644 index 0000000..337dd94 --- /dev/null +++ b/readme.md @@ -0,0 +1,4 @@ +# Homestead Improved + +A fork of the original Laravel Homestead, this improved version aims to make things even simpler. +See full explanation with quickstart tutorial [here](http://www.sitepoint.com/quick-tip-get-homestead-vagrant-vm-running/). diff --git a/scripts/blackfire.sh b/scripts/blackfire.sh new file mode 100644 index 0000000..189992c --- /dev/null +++ b/scripts/blackfire.sh @@ -0,0 +1,28 @@ + +#!/usr/bin/env bash + +agent="[blackfire] +ca-cert= +collector=https://blackfire.io +log-file=stderr +log-level=1 +server-id="$1" +server-token="$2" +socket=unix:///var/run/blackfire/agent.sock +spec= +" + +client="[blackfire] +ca-cert= +client-id="$3" +client-token="$4" +endpoint=https://blackfire.io +timeout=15s +" + +echo "$agent" > "/etc/blackfire/agent" +echo "$client" > "/home/vagrant/.blackfire.ini" + +service hhvm restart +service php7.2-fpm restart +service blackfire-agent restart diff --git a/scripts/clear-nginx.sh b/scripts/clear-nginx.sh new file mode 100644 index 0000000..bc09f5d --- /dev/null +++ b/scripts/clear-nginx.sh @@ -0,0 +1,4 @@ +# Clear The Old Nginx Sites + +rm -f /etc/nginx/sites-enabled/* +rm -f /etc/nginx/sites-available/* diff --git a/scripts/clear-variables.sh b/scripts/clear-variables.sh new file mode 100644 index 0000000..9a63d29 --- /dev/null +++ b/scripts/clear-variables.sh @@ -0,0 +1,4 @@ +# Clear The Old Environment Variables + +sed -i '/# Set Homestead Environment Variable/,+1d' /home/vagrant/.profile +sed -i '/env\[.*/,+1d' /etc/php/7.2/fpm/php-fpm.conf diff --git a/scripts/create-mysql.sh b/scripts/create-mysql.sh new file mode 100644 index 0000000..0412040 --- /dev/null +++ b/scripts/create-mysql.sh @@ -0,0 +1,5 @@ +#!/usr/bin/env bash + +DB=$1; + +mysql -uhomestead -psecret -e "CREATE DATABASE IF NOT EXISTS \`$DB\` DEFAULT CHARACTER SET utf8 DEFAULT COLLATE utf8_unicode_ci"; diff --git a/scripts/create-postgres.sh b/scripts/create-postgres.sh new file mode 100644 index 0000000..0300f4a --- /dev/null +++ b/scripts/create-postgres.sh @@ -0,0 +1,5 @@ +#!/usr/bin/env bash + +DB=$1; +# su postgres -c "dropdb $DB --if-exists" +su postgres -c "createdb -O homestead '$DB' || true" diff --git a/scripts/cron-schedule.sh b/scripts/cron-schedule.sh new file mode 100644 index 0000000..9628b08 --- /dev/null +++ b/scripts/cron-schedule.sh @@ -0,0 +1,8 @@ +#!/usr/bin/env bash + +mkdir /etc/cron.d 2>/dev/null + +cron="* * * * * vagrant /usr/bin/php $2/../artisan schedule:run >> /dev/null 2>&1" + +echo "$cron" > "/etc/cron.d/$1" +service cron restart diff --git a/scripts/homestead.rb b/scripts/homestead.rb new file mode 100644 index 0000000..bde0fe7 --- /dev/null +++ b/scripts/homestead.rb @@ -0,0 +1,278 @@ +class Homestead + def Homestead.configure(config, settings) + # Set The VM Provider + ENV['VAGRANT_DEFAULT_PROVIDER'] = settings["provider"] ||= "virtualbox" + + # Configure Local Variable To Access Scripts From Remote Location + scriptDir = File.dirname(__FILE__) + + # Prevent TTY Errors + config.ssh.shell = "bash -c 'BASH_ENV=/etc/profile exec bash'" + + # Allow SSH Agent Forward from The Box + config.ssh.forward_agent = true + + # Configure The Box + config.vm.box = settings["box"] ||= "status-im/nimbox" + config.vm.box_version = settings["version"] ||= ">= 0.0.1" + config.vm.hostname = settings["hostname"] ||= "homestead" + + # Configure A Private Network IP + config.vm.network :private_network, ip: settings["ip"] ||= "192.168.10.10" + + # Configure Additional Networks + if settings.has_key?("networks") + settings["networks"].each do |network| + config.vm.network network["type"], ip: network["ip"], bridge: network["bridge"] ||= nil + end + end + + # Configure A Few VirtualBox Settings + config.vm.provider "virtualbox" do |vb| + vb.customize ["modifyvm", :id, "--memory", settings["memory"] ||= "2048"] + vb.customize ["modifyvm", :id, "--cpus", settings["cpus"] ||= "1"] + vb.customize ["modifyvm", :id, "--natdnsproxy1", "on"] + vb.customize ["modifyvm", :id, "--natdnshostresolver1", settings["natdnshostresolver"] ||= "on"] + vb.customize ["modifyvm", :id, "--ostype", "Ubuntu_64"] + vb.customize ['modifyvm', :id, '--cableconnected1', 'on'] + if settings.has_key?("gui") && settings["gui"] + vb.gui = true + end + end + + # Configure A Few VMware Settings + ["vmware_fusion", "vmware_workstation"].each do |vmware| + config.vm.provider vmware do |v| + v.vmx["memsize"] = settings["memory"] ||= 2048 + v.vmx["numvcpus"] = settings["cpus"] ||= 1 + v.vmx["guestOS"] = "ubuntu-64" + if settings.has_key?("gui") && settings["gui"] + v.gui = true + end + end + end + + # Configure A Few Parallels Settings + config.vm.provider "parallels" do |v| + v.name = settings["name"] ||= "homestead-7" + v.update_guest_tools = true + v.memory = settings["memory"] ||= 2048 + v.cpus = settings["cpus"] ||= 1 + end + + # Standardize Ports Naming Schema + if (settings.has_key?("ports")) + settings["ports"].each do |port| + port["guest"] ||= port["to"] + port["host"] ||= port["send"] + port["protocol"] ||= "tcp" + end + else + settings["ports"] = [] + end + + # Default Port Forwarding + default_ports = { + 80 => 8000, + 443 => 44300, + 3306 => 33060, + 5432 => 54320 + } + + # Use Default Port Forwarding Unless Overridden + unless settings.has_key?("default_ports") && settings["default_ports"] == false + default_ports.each do |guest, host| + unless settings["ports"].any? { |mapping| mapping["guest"] == guest } + config.vm.network "forwarded_port", guest: guest, host: host, auto_correct: true + end + end + end + + # Add Custom Ports From Configuration + if settings.has_key?("ports") + settings["ports"].each do |port| + config.vm.network "forwarded_port", guest: port["guest"], host: port["host"], protocol: port["protocol"], auto_correct: true + end + end + + # Configure The Public Key For SSH Access + if settings.include? 'authorize' + if File.exists? File.expand_path(settings["authorize"]) + config.vm.provision "shell" do |s| + s.inline = "echo $1 | grep -xq \"$1\" /home/vagrant/.ssh/authorized_keys || echo \"\n$1\" | tee -a /home/vagrant/.ssh/authorized_keys" + s.args = [File.read(File.expand_path(settings["authorize"]))] + end + end + end + + # Copy The SSH Private Keys To The Box + if settings.include? 'keys' + settings["keys"].each do |key| + config.vm.provision "shell" do |s| + s.privileged = false + s.inline = "echo \"$1\" > /home/vagrant/.ssh/$2 && chmod 600 /home/vagrant/.ssh/$2" + s.args = [File.read(File.expand_path(key)), key.split('/').last] + end + end + end + + # Copy User Files Over to VM + if settings.include? 'copy' + settings["copy"].each do |file| + config.vm.provision "file" do |f| + f.source = File.expand_path(file["from"]) + f.destination = file["to"].chomp('/') + "/" + file["from"].split('/').last + end + end + end + + # Register All Of The Configured Shared Folders + if settings.include? 'folders' + settings["folders"].each do |folder| + mount_opts = [] + + if (folder["type"] == "nfs") + mount_opts = folder["mount_options"] ? folder["mount_options"] : ['actimeo=1', 'nolock'] + elsif (folder["type"] == "smb") + mount_opts = folder["mount_options"] ? folder["mount_options"] : ['vers=3.02', 'mfsymlinks'] + elsif (folder["type"] == "sshfs") + mount_opts = folder["mount_options"] ? folder["mount_options"] : ['nonempty'] + end + + # For b/w compatibility keep separate 'mount_opts', but merge with options + options = (folder["options"] || {}).merge({ mount_options: mount_opts }) + + # Double-splat (**) operator only works with symbol keys, so convert + options.keys.each{|k| options[k.to_sym] = options.delete(k) } + + config.vm.synced_folder folder["map"], folder["to"], type: folder["type"] ||= nil, **options + + # Bindfs support to fix shared folder (NFS) permission issue on Mac + if (folder["type"] == "nfs" && Vagrant.has_plugin?("vagrant-bindfs")) + config.vm.synced_folder folder["map"], "/mnt/vagrant", id: "vagrant", type: 'nfs' + config.bindfs.bind_folder "/mnt/vagrant", folder["to"], owner: "vagrant", group: "vagrant", perms: "u=rwX:g=rwX:o=rD", 'create-as-user': true, 'create-with-perms': "u=rwX:g=rwX:o=rD", 'chown-ignore': true, 'chgrp-ignore': true, 'chmod-ignore': true, 'o': "nonempty" + end + end + end + + # Install All The Configured Nginx Sites + config.vm.provision "shell" do |s| + s.path = scriptDir + "/clear-nginx.sh" + end + + + if settings.include? 'sites' + settings["sites"].each do |site| + type = site["type"] ||= "laravel" + + if (site.has_key?("hhvm") && site["hhvm"]) + type = "hhvm" + end + + if (type == "symfony") + type = "symfony2" + end + + if (type == "symfony-sulu") + type = "sulu" + end + + config.vm.provision "shell" do |s| + s.name = "Creating Site: " + site["map"] + s.path = scriptDir + "/serve-#{type}.sh" + s.args = [site["map"], site["to"], site["port"] ||= "80", site["ssl"] ||= "443"] + end + + # Configure The Cron Schedule + if (site.has_key?("schedule")) + config.vm.provision "shell" do |s| + s.name = "Creating Schedule" + + if (site["schedule"]) + s.path = scriptDir + "/cron-schedule.sh" + s.args = [site["map"].tr('^A-Za-z0-9', ''), site["to"]] + else + s.inline = "rm -f /etc/cron.d/$1" + s.args = [site["map"].tr('^A-Za-z0-9', '')] + end + end + end + + end + end + + config.vm.provision "shell" do |s| + s.name = "Restarting Nginx" + s.inline = "sudo service nginx restart; sudo service php7.2-fpm restart" + end + + # Install MariaDB If Necessary + if settings.has_key?("mariadb") && settings["mariadb"] + config.vm.provision "shell" do |s| + s.path = scriptDir + "/install-maria.sh" + end + end + + + # Configure All Of The Configured Databases + if settings.has_key?("databases") + settings["databases"].each do |db| + config.vm.provision "shell" do |s| + s.name = "Creating MySQL Database: " + db + s.path = scriptDir + "/create-mysql.sh" + s.args = [db] + end + + config.vm.provision "shell" do |s| + s.name = "Creating Postgres Database: " + db + s.path = scriptDir + "/create-postgres.sh" + s.args = [db] + end + end + end + + # Configure All Of The Server Environment Variables + config.vm.provision "shell" do |s| + s.name = "Clear Variables" + s.path = scriptDir + "/clear-variables.sh" + end + + if settings.has_key?("variables") + settings["variables"].each do |var| + config.vm.provision "shell" do |s| + s.inline = "echo \"\nenv[$1] = '$2'\" >> /etc/php/7.2/fpm/php-fpm.conf" + s.args = [var["key"], var["value"]] + end + + config.vm.provision "shell" do |s| + s.inline = "echo \"\n# Set Homestead Environment Variable\nexport $1=$2\" >> /home/vagrant/.profile" + s.args = [var["key"], var["value"]] + end + end + + config.vm.provision "shell" do |s| + s.inline = "service php7.2-fpm restart" + end + end + + # Update Composer On Every Provision + config.vm.provision "shell" do |s| + s.name = "Update Composer" + s.inline = "sudo /usr/local/bin/composer self-update && sudo chown -R vagrant:vagrant /home/vagrant/.composer/" + s.privileged = false + end + + # Configure Blackfire.io + if settings.has_key?("blackfire") + config.vm.provision "shell" do |s| + s.path = scriptDir + "/blackfire.sh" + s.args = [ + settings["blackfire"][0]["id"], + settings["blackfire"][0]["token"], + settings["blackfire"][0]["client-id"], + settings["blackfire"][0]["client-token"] + ] + end + end + end +end diff --git a/scripts/install-maria.sh b/scripts/install-maria.sh new file mode 100644 index 0000000..53a03a3 --- /dev/null +++ b/scripts/install-maria.sh @@ -0,0 +1,55 @@ + +# Check If Maria Has Been Installed + +if [ -f /home/vagrant/.maria ] +then + echo "MariaDB already installed." + exit 0 +fi + +touch /home/vagrant/.maria + +# Remove MySQL + +apt-get remove -y --purge mysql-server mysql-client mysql-common +apt-get autoremove -y +apt-get autoclean + +rm -rf /var/lib/mysql +rm -rf /var/log/mysql +rm -rf /etc/mysql + +# Add Maria PPA + +apt-key adv --recv-keys --keyserver hkp://keyserver.ubuntu.com:80 0xF1656F24C74CD1D8 +add-apt-repository 'deb [arch=amd64,i386,ppc64el] http://ftp.osuosl.org/pub/mariadb/repo/10.1/ubuntu xenial main' +apt-get update + +# Set The Automated Root Password + +export DEBIAN_FRONTEND=noninteractive + +debconf-set-selections <<< "mariadb-server-10.1 mysql-server/data-dir select ''" +debconf-set-selections <<< "mariadb-server-10.1 mysql-server/root_password password secret" +debconf-set-selections <<< "mariadb-server-10.1 mysql-server/root_password_again password secret" + +# Install MariaDB + +apt-get install -y mariadb-server + +# Configure Password Expiration + +echo "default_password_lifetime = 0" >> /etc/mysql/my.cnf + +# Configure Maria Remote Access + +sed -i '/^bind-address/s/bind-address.*=.*/bind-address = 0.0.0.0/' /etc/mysql/my.cnf + +mysql --user="root" --password="secret" -e "GRANT ALL ON *.* TO root@'0.0.0.0' IDENTIFIED BY 'secret' WITH GRANT OPTION;" +service mysql restart + +mysql --user="root" --password="secret" -e "CREATE USER 'homestead'@'0.0.0.0' IDENTIFIED BY 'secret';" +mysql --user="root" --password="secret" -e "GRANT ALL ON *.* TO 'homestead'@'0.0.0.0' IDENTIFIED BY 'secret' WITH GRANT OPTION;" +mysql --user="root" --password="secret" -e "GRANT ALL ON *.* TO 'homestead'@'%' IDENTIFIED BY 'secret' WITH GRANT OPTION;" +mysql --user="root" --password="secret" -e "FLUSH PRIVILEGES;" +service mysql restart diff --git a/scripts/serve-hhvm.sh b/scripts/serve-hhvm.sh new file mode 100644 index 0000000..8ecee76 --- /dev/null +++ b/scripts/serve-hhvm.sh @@ -0,0 +1,51 @@ +#!/usr/bin/env bash + +mkdir /etc/nginx/ssl 2>/dev/null +openssl genrsa -out "/etc/nginx/ssl/$1.key" 1024 2>/dev/null +openssl req -new -key /etc/nginx/ssl/$1.key -out /etc/nginx/ssl/$1.csr -subj "/CN=$1/O=Vagrant/C=UK" 2>/dev/null +openssl x509 -req -days 365 -in /etc/nginx/ssl/$1.csr -signkey /etc/nginx/ssl/$1.key -out /etc/nginx/ssl/$1.crt 2>/dev/null + +block="server { + listen ${3:-80}; + listen ${4:-443} ssl; + server_name $1; + root \"$2\"; + + index index.html index.htm index.php; + + charset utf-8; + + location / { + try_files \$uri \$uri/ /index.php?\$query_string; + } + + location = /favicon.ico { access_log off; log_not_found off; } + location = /robots.txt { access_log off; log_not_found off; } + + access_log off; + error_log /var/log/nginx/$1-error.log error; + + sendfile off; + + location ~ \.php$ { + fastcgi_split_path_info ^(.+\.php)(/.+)$; + fastcgi_pass 127.0.0.1:9000; + fastcgi_index index.php; + fastcgi_param SCRIPT_FILENAME \$document_root\$fastcgi_script_name; + include fastcgi_params; + } + + location ~ /\.ht { + deny all; + } + + ssl_certificate /etc/nginx/ssl/$1.crt; + ssl_certificate_key /etc/nginx/ssl/$1.key; +} +" + +echo "$block" > "/etc/nginx/sites-available/$1" +ln -fs "/etc/nginx/sites-available/$1" "/etc/nginx/sites-enabled/$1" +service nginx restart +service php7.2-fpm restart +service hhvm restart diff --git a/scripts/serve-laravel.sh b/scripts/serve-laravel.sh new file mode 100644 index 0000000..a84ee0b --- /dev/null +++ b/scripts/serve-laravel.sh @@ -0,0 +1,66 @@ +#!/usr/bin/env bash + +mkdir /etc/nginx/ssl 2>/dev/null + +PATH_SSL="/etc/nginx/ssl" +PATH_KEY="${PATH_SSL}/${1}.key" +PATH_CSR="${PATH_SSL}/${1}.csr" +PATH_CRT="${PATH_SSL}/${1}.crt" + +if [ ! -f $PATH_KEY ] || [ ! -f $PATH_CSR ] || [ ! -f $PATH_CRT ] +then + openssl genrsa -out "$PATH_KEY" 2048 2>/dev/null + openssl req -new -key "$PATH_KEY" -out "$PATH_CSR" -subj "/CN=$1/O=Vagrant/C=UK" 2>/dev/null + openssl x509 -req -days 365 -in "$PATH_CSR" -signkey "$PATH_KEY" -out "$PATH_CRT" 2>/dev/null +fi + +block="server { + listen ${3:-80}; + listen ${4:-443} ssl http2; + server_name $1; + root \"$2\"; + + index index.html index.htm index.php; + + charset utf-8; + + location / { + try_files \$uri \$uri/ /index.php?\$query_string; + } + + location = /favicon.ico { access_log off; log_not_found off; } + location = /robots.txt { access_log off; log_not_found off; } + + access_log off; + error_log /var/log/nginx/$1-error.log error; + + sendfile off; + + client_max_body_size 100m; + + location ~ \.php$ { + fastcgi_split_path_info ^(.+\.php)(/.+)$; + fastcgi_pass unix:/var/run/php/php7.2-fpm.sock; + fastcgi_index index.php; + include fastcgi_params; + fastcgi_param SCRIPT_FILENAME \$document_root\$fastcgi_script_name; + + fastcgi_intercept_errors off; + fastcgi_buffer_size 16k; + fastcgi_buffers 4 16k; + fastcgi_connect_timeout 300; + fastcgi_send_timeout 300; + fastcgi_read_timeout 300; + } + + location ~ /\.ht { + deny all; + } + + ssl_certificate /etc/nginx/ssl/$1.crt; + ssl_certificate_key /etc/nginx/ssl/$1.key; +} +" + +echo "$block" > "/etc/nginx/sites-available/$1" +ln -fs "/etc/nginx/sites-available/$1" "/etc/nginx/sites-enabled/$1" diff --git a/scripts/serve-sulu.sh b/scripts/serve-sulu.sh new file mode 100644 index 0000000..24091b2 --- /dev/null +++ b/scripts/serve-sulu.sh @@ -0,0 +1,86 @@ +#!/usr/bin/env bash + +mkdir /etc/nginx/ssl 2>/dev/null +openssl genrsa -out "/etc/nginx/ssl/$1.key" 1024 2>/dev/null +openssl req -new -key /etc/nginx/ssl/$1.key -out /etc/nginx/ssl/$1.csr -subj "/CN=$1/O=Vagrant/C=UK" 2>/dev/null +openssl x509 -req -days 365 -in /etc/nginx/ssl/$1.csr -signkey /etc/nginx/ssl/$1.key -out /etc/nginx/ssl/$1.crt 2>/dev/null + +block="server { + listen ${3:-80}; + listen ${4:-443} ssl; + server_name $1; + root \"$2\"; + + charset utf-8; + + location = /favicon.ico { access_log off; log_not_found off; } + location = /robots.txt { access_log off; log_not_found off; } + + access_log off; + error_log /var/log/nginx/$1-ssl-error.log error; + + sendfile off; + + client_max_body_size 100m; + + # DEV + location ~ ^/(website|admin|app)\.php(/|$) { + fastcgi_split_path_info ^(.+\.php)(/.+)$; + fastcgi_pass unix:/var/run/php/php7.2-fpm.sock; + include fastcgi_params; + fastcgi_param SCRIPT_FILENAME \$document_root\$fastcgi_script_name; + fastcgi_intercept_errors off; + fastcgi_buffer_size 32; + fastcgi_buffers 16 16k; + fastcgi_param SYMFONY_ENV dev; + fastcgi_param SYMFONY_DEBUG 1; + # Prevents URIs that include the front controller. This will 404: + # http://domain.tld/app.php/some-path + # Remove the internal directive to allow URIs like this + internal; + } + + # strip app.php/ prefix if it is present + rewrite ^/app\.php/?(.*)\$ /$1 permanent; + + location /admin { + index admin.php; + try_files \$uri @rewriteadmin; + } + + location @rewriteadmin { + rewrite ^(.*)\$ /admin.php/$1 last; + } + + location / { + index website.php; + try_files \$uri @rewritewebsite; + } + + # expire + location ~* \.(?:ico|css|js|gif|jpe?g|png)\$ { + try_files \$uri /website.php/$1; + access_log off; + expires 30d; + add_header Pragma public; + add_header Cache-Control "public"; + } + + location @rewritewebsite { + rewrite ^(.*)\$ /website.php/$1 last; + } + + + location ~ /\.ht { + deny all; + } + + ssl_certificate /etc/nginx/ssl/$1.crt; + ssl_certificate_key /etc/nginx/ssl/$1.key; +} +" + +echo "$block" > "/etc/nginx/sites-available/$1" +ln -fs "/etc/nginx/sites-available/$1" "/etc/nginx/sites-enabled/$1" +service nginx restart +service php7.2-fpm restart diff --git a/scripts/serve-symfony2.sh b/scripts/serve-symfony2.sh new file mode 100644 index 0000000..8812922 --- /dev/null +++ b/scripts/serve-symfony2.sh @@ -0,0 +1,70 @@ +#!/usr/bin/env bash + +mkdir /etc/nginx/ssl 2>/dev/null +openssl genrsa -out "/etc/nginx/ssl/$1.key" 1024 2>/dev/null +openssl req -new -key /etc/nginx/ssl/$1.key -out /etc/nginx/ssl/$1.csr -subj "/CN=$1/O=Vagrant/C=UK" 2>/dev/null +openssl x509 -req -days 365 -in /etc/nginx/ssl/$1.csr -signkey /etc/nginx/ssl/$1.key -out /etc/nginx/ssl/$1.crt 2>/dev/null + +block="server { + listen ${3:-80}; + listen ${4:-443} ssl; + server_name $1; + root \"$2\"; + + index index.html index.htm index.php app.php; + + charset utf-8; + + location / { + try_files \$uri \$uri/ /app.php?\$query_string; + } + + location = /favicon.ico { access_log off; log_not_found off; } + location = /robots.txt { access_log off; log_not_found off; } + + access_log off; + error_log /var/log/nginx/$1-ssl-error.log error; + + sendfile off; + + client_max_body_size 100m; + + # DEV + location ~ ^/(app_dev|config)\.php(/|\$) { + fastcgi_split_path_info ^(.+\.php)(/.+)\$; + fastcgi_pass unix:/var/run/php/php7.2-fpm.sock; + include fastcgi_params; + fastcgi_param SCRIPT_FILENAME \$document_root\$fastcgi_script_name; + fastcgi_intercept_errors off; + fastcgi_buffer_size 16k; + fastcgi_buffers 4 16k; + } + + # PROD + location ~ ^/app\.php(/|$) { + fastcgi_split_path_info ^(.+\.php)(/.+)$; + fastcgi_pass unix:/var/run/php/php7.2-fpm.sock; + include fastcgi_params; + fastcgi_param SCRIPT_FILENAME \$document_root\$fastcgi_script_name; + fastcgi_intercept_errors off; + fastcgi_buffer_size 16k; + fastcgi_buffers 4 16k; + # Prevents URIs that include the front controller. This will 404: + # http://domain.tld/app.php/some-path + # Remove the internal directive to allow URIs like this + internal; + } + + location ~ /\.ht { + deny all; + } + + ssl_certificate /etc/nginx/ssl/$1.crt; + ssl_certificate_key /etc/nginx/ssl/$1.key; +} +" + +echo "$block" > "/etc/nginx/sites-available/$1" +ln -fs "/etc/nginx/sites-available/$1" "/etc/nginx/sites-enabled/$1" +service nginx restart +service php7.2-fpm restart diff --git a/scripts/serve-symfony4.sh b/scripts/serve-symfony4.sh new file mode 100644 index 0000000..38a39ff --- /dev/null +++ b/scripts/serve-symfony4.sh @@ -0,0 +1,49 @@ +#!/usr/bin/env bash + +block="server { + listen ${3:-80}; + listen ${4:-443} ssl http2; + server_name $1; + root \"$2\"; + + index index.html index.htm index.php; + + charset utf-8; + + location / { + try_files \$uri \$uri/ /index.php?\$query_string; + } + + location = /favicon.ico { access_log off; log_not_found off; } + location = /robots.txt { access_log off; log_not_found off; } + + access_log off; + error_log /var/log/nginx/$1-ssl-error.log error; + + sendfile off; + + client_max_body_size 100m; + + # DEV + location ~ ^/index\.php(/|\$) { + fastcgi_split_path_info ^(.+\.php)(/.*)\$; + fastcgi_pass unix:/var/run/php/php7.2-fpm.sock; + include fastcgi_params; + fastcgi_param SCRIPT_FILENAME \$document_root\$fastcgi_script_name; + + fastcgi_intercept_errors off; + fastcgi_buffer_size 16k; + fastcgi_buffers 4 16k; + } + + location ~ /\.ht { + deny all; + } + + ssl_certificate /etc/nginx/ssl/$1.crt; + ssl_certificate_key /etc/nginx/ssl/$1.key; +} +" + +echo "$block" > "/etc/nginx/sites-available/$1" +ln -fs "/etc/nginx/sites-available/$1" "/etc/nginx/sites-enabled/$1" diff --git a/scripts/serve.sh b/scripts/serve.sh new file mode 100644 index 0000000..4410cbc --- /dev/null +++ b/scripts/serve.sh @@ -0,0 +1,58 @@ +#!/usr/bin/env bash + +mkdir /etc/nginx/ssl 2>/dev/null +openssl genrsa -out "/etc/nginx/ssl/$1.key" 1024 2>/dev/null +openssl req -new -key /etc/nginx/ssl/$1.key -out /etc/nginx/ssl/$1.csr -subj "/CN=$1/O=Vagrant/C=UK" 2>/dev/null +openssl x509 -req -days 365 -in /etc/nginx/ssl/$1.csr -signkey /etc/nginx/ssl/$1.key -out /etc/nginx/ssl/$1.crt 2>/dev/null + +block="server { + listen ${3:-80}; + listen ${4:-443} ssl; + server_name $1; + root \"$2\"; + + index index.html index.htm index.php; + + charset utf-8; + + location / { + try_files \$uri \$uri/ /index.php?\$query_string; + } + + location = /favicon.ico { access_log off; log_not_found off; } + location = /robots.txt { access_log off; log_not_found off; } + + access_log off; + error_log /var/log/nginx/$1-error.log error; + + sendfile off; + + client_max_body_size 100m; + + location ~ \.php$ { + fastcgi_split_path_info ^(.+\.php)(/.+)$; + fastcgi_pass unix:/var/run/php/php7.2-fpm.sock; + fastcgi_index index.php; + include fastcgi_params; + fastcgi_param SCRIPT_FILENAME \$document_root\$fastcgi_script_name; + fastcgi_intercept_errors off; + fastcgi_buffer_size 16k; + fastcgi_buffers 4 16k; + fastcgi_connect_timeout 300; + fastcgi_send_timeout 300; + fastcgi_read_timeout 300; + } + + location ~ /\.ht { + deny all; + } + + ssl_certificate /etc/nginx/ssl/$1.crt; + ssl_certificate_key /etc/nginx/ssl/$1.key; +} +" + +echo "$block" > "/etc/nginx/sites-available/$1" +ln -fs "/etc/nginx/sites-available/$1" "/etc/nginx/sites-enabled/$1" +service nginx restart +service php7.2-fpm restart diff --git a/src/AddDatabaseCommand.php b/src/AddDatabaseCommand.php new file mode 100644 index 0000000..95bc040 --- /dev/null +++ b/src/AddDatabaseCommand.php @@ -0,0 +1,89 @@ +setName('add-db') + ->setDescription('Add a new database to the Homestead.yaml file') + ->addArgument('name', InputArgument::REQUIRED, 'the database name to be added'); + } + + /** + * Execute the command. + * + * @param \Symfony\Component\Console\Input\InputInterface $input + * @param \Symfony\Component\Console\Output\OutputInterface $output + * + * @return void + */ + public function execute(InputInterface $input, OutputInterface $output) + { + $this->homesteadYamlContents = Yaml::parse(file_get_contents('./Homestead.yaml')); + $this->output = $output; + + $name = $input->getArgument('name'); + + $canAddItem = $this->canItemBeAdded($name); + + if($canAddItem) { + $this->addItemAndSaveToYamlFile($name); + } + } + + /** + * @param $name + * + * @return bool + */ + private function canItemBeAdded($name) + { + $canAddItem = true; + foreach($this->homesteadYamlContents['databases'] as $database) { + if($database === $name) { + $this->output->writeln(sprintf('Database %s already defined.', $name)); + $canAddItem = false; + break; + } + } + + return $canAddItem; + } + + /** + * @param $name + */ + private function addItemAndSaveToYamlFile($name) + { + $this->homesteadYamlContents['databases'][] = $name; + + file_put_contents('./Homestead.yaml', Yaml::dump($this->homesteadYamlContents)); + + $this->output->writeln('New database successfully added.'); + $this->output->write('Don\'t forget to re-provision your VM.'); + } +} diff --git a/src/AddSiteCommand.php b/src/AddSiteCommand.php new file mode 100644 index 0000000..2d80f8f --- /dev/null +++ b/src/AddSiteCommand.php @@ -0,0 +1,99 @@ +setName('add-site') + ->setDescription('Add a new site to the Homestead.yaml file') + ->addArgument('hostname', InputArgument::REQUIRED, 'the hostname to add') + ->addArgument('path', InputArgument::REQUIRED, 'the path for the given hostname'); + } + + /** + * Execute the command. + * + * @param \Symfony\Component\Console\Input\InputInterface $input + * @param \Symfony\Component\Console\Output\OutputInterface $output + * @return void + */ + public function execute(InputInterface $input, OutputInterface $output) + { + $this->homesteadYamlContents = Yaml::parse(file_get_contents('./Homestead.yaml')); + $this->output = $output; + + $hostname = $input->getArgument('hostname'); + $path = $input->getArgument('path'); + + $canAddItem = $this->canItemBeAdded($hostname, $path); + + if($canAddItem) { + $this->addItemAndSaveToYamlFile($hostname, $path); + } + } + + /** + * @param $currentSites + * @param $hostname + * @param $path + * @param OutputInterface $output + * + * @return bool + */ + private function canItemBeAdded($hostname, $path) + { + $canAddItem = true; + foreach($this->homesteadYamlContents['sites'] as $site) { + if($site['map'] === $hostname) { + $this->output->writeln(sprintf('Hostname %s already used.', $hostname)); + $canAddItem = false; + break; + } + + if($site['to'] === $path) { + $this->output->writeln(sprintf('Path %s already mapped to %s', $path, $site['to'])); + $canAddItem = false; + break; + } + } + + return $canAddItem; + } + + private function addItemAndSaveToYamlFile($hostname, $path) + { + $this->homesteadYamlContents['sites'][] = [ + 'map' => $hostname, + 'to' => $path + ]; + + file_put_contents('./Homestead.yaml', Yaml::dump($this->homesteadYamlContents)); + + $this->output->writeln('New site successfully added.'); + $this->output->write('Don\'t forget to re-provision your VM.'); + } +} diff --git a/src/DestroyCommand.php b/src/DestroyCommand.php new file mode 100644 index 0000000..ce03859 --- /dev/null +++ b/src/DestroyCommand.php @@ -0,0 +1,37 @@ +setName('destroy')->setDescription('Destroy the Homestead machine'); + } + + /** + * Execute the command. + * + * @param \Symfony\Component\Console\Input\InputInterface $input + * @param \Symfony\Component\Console\Output\OutputInterface $output + * @return void + */ + public function execute(InputInterface $input, OutputInterface $output) + { + $process = new Process('vagrant destroy --force', realpath(__DIR__.'/../'), array_merge($_SERVER, $_ENV), null, null); + + $process->run(function ($type, $line) use ($output) { + $output->write($line); + }); + } +} diff --git a/src/EditCommand.php b/src/EditCommand.php new file mode 100644 index 0000000..701256b --- /dev/null +++ b/src/EditCommand.php @@ -0,0 +1,65 @@ +setName('edit') + ->setDescription('Edit a Homestead file') + ->addArgument('file', InputArgument::OPTIONAL, 'The file you wish to edit.'); + } + + /** + * Execute the command. + * + * @param \Symfony\Component\Console\Input\InputInterface $input + * @param \Symfony\Component\Console\Output\OutputInterface $output + * @return void + */ + public function execute(InputInterface $input, OutputInterface $output) + { + $file = 'Homestead.yaml'; + + if ($input->getArgument('file') === 'aliases') { + $file = 'aliases'; + } + + $command = $this->executable().' '.homestead_path().'/'.$file; + + $process = new Process($command, realpath(__DIR__.'/../'), array_merge($_SERVER, $_ENV), null, null); + + $process->run(function ($type, $line) use ($output) { + $output->write($line); + }); + } + + /** + * Find the correct executable to run depending on the OS. + * + * @return string + */ + protected function executable() + { + if (strpos(strtoupper(PHP_OS), 'WIN') === 0) { + return 'start'; + } elseif (strpos(strtoupper(PHP_OS), 'DARWIN') === 0) { + return 'open'; + } + + return 'xdg-open'; + } +} diff --git a/src/HaltCommand.php b/src/HaltCommand.php new file mode 100644 index 0000000..9048638 --- /dev/null +++ b/src/HaltCommand.php @@ -0,0 +1,37 @@ +setName('halt')->setDescription('Halt the Homestead machine'); + } + + /** + * Execute the command. + * + * @param \Symfony\Component\Console\Input\InputInterface $input + * @param \Symfony\Component\Console\Output\OutputInterface $output + * @return void + */ + public function execute(InputInterface $input, OutputInterface $output) + { + $process = new Process('vagrant halt', realpath(__DIR__.'/../'), array_merge($_SERVER, $_ENV), null, null); + + $process->run(function ($type, $line) use ($output) { + $output->write($line); + }); + } +} diff --git a/src/InitCommand.php b/src/InitCommand.php new file mode 100644 index 0000000..e9c3abd --- /dev/null +++ b/src/InitCommand.php @@ -0,0 +1,44 @@ +setName('init')->setDescription('Create a stub Homestead.yaml file'); + } + + /** + * Execute the command. + * + * @param \Symfony\Component\Console\Input\InputInterface $input + * @param \Symfony\Component\Console\Output\OutputInterface $output + * @return void + */ + public function execute(InputInterface $input, OutputInterface $output) + { + if (is_dir(homestead_path())) { + throw new InvalidArgumentException('Homestead has already been initialized.'); + } + + mkdir(homestead_path()); + + copy(__DIR__.'/stubs/Homestead.yaml', homestead_path().'/Homestead.yaml'); + copy(__DIR__.'/stubs/after.sh', homestead_path().'/after.sh'); + copy(__DIR__.'/stubs/aliases', homestead_path().'/aliases'); + + $output->writeln('Creating Homestead.yaml file... '); + $output->writeln('Homestead.yaml file created at: '.homestead_path().'/Homestead.yaml'); + } +} diff --git a/src/MakeCommand.php b/src/MakeCommand.php new file mode 100644 index 0000000..f25ac3d --- /dev/null +++ b/src/MakeCommand.php @@ -0,0 +1,153 @@ +basePath = getcwd(); + $this->projectName = basename(getcwd()); + $this->defaultName = strtolower(trim(preg_replace('/[^A-Za-z0-9-]+/', '-', $this->projectName))); + + $this + ->setName('make') + ->setDescription('Install Homestead into the current project') + ->addOption('name', null, InputOption::VALUE_OPTIONAL, 'The name the virtual machine.', $this->defaultName) + ->addOption('hostname', null, InputOption::VALUE_OPTIONAL, 'The hostname the virtual machine.', $this->defaultName) + ->addOption('after', null, InputOption::VALUE_NONE, 'Determines if the after.sh file is created.') + ->addOption('aliases', null, InputOption::VALUE_NONE, 'Determines if the aliases file is created.'); + } + + /** + * Execute the command. + * + * @param \Symfony\Component\Console\Input\InputInterface $input + * @param \Symfony\Component\Console\Output\OutputInterface $output + * @return void + */ + public function execute(InputInterface $input, OutputInterface $output) + { + copy(__DIR__.'/stubs/LocalizedVagrantfile', $this->basePath.'/Vagrantfile'); + + if (! file_exists($this->basePath.'/Homestead.yaml')) { + copy(__DIR__.'/stubs/Homestead.yaml', $this->basePath.'/Homestead.yaml'); + + if ($input->getOption('name')) { + $this->updateName($input->getOption('name')); + } + + if ($input->getOption('hostname')) { + $this->updateHostName($input->getOption('hostname')); + } + } + + if ($input->getOption('after')) { + if (! file_exists($this->basePath.'/after.sh')) { + copy(__DIR__.'/stubs/after.sh', $this->basePath.'/after.sh'); + } + } + + if ($input->getOption('aliases')) { + if (! file_exists($this->basePath.'/aliases')) { + copy(__DIR__.'/stubs/aliases', $this->basePath.'/aliases'); + } + } + + $this->configurePaths(); + + $output->writeln('Homestead Installed!'); + } + + /** + * Update paths in Homestead.yaml. + * + * @return void + */ + protected function configurePaths() + { + $yaml = str_replace( + '- map: ~/Code', '- map: "'.str_replace('\\', '/', $this->basePath).'"', $this->getHomesteadFile() + ); + + $yaml = str_replace( + 'to: /home/vagrant/Code', 'to: "/home/vagrant/'.$this->defaultName.'"', $yaml + ); + + // Fix path to the public folder (sites: to:) + $yaml = str_replace( + $this->defaultName.'"/Laravel/public', $this->defaultName.'/public"', $yaml + ); + + file_put_contents($this->basePath.'/Homestead.yaml', $yaml); + } + + /** + * Update the "name" variable of the Homestead.yaml file. + * + * VirtualBox requires a unique name for each virtual machine. + * + * @param string $name + * @return void + */ + protected function updateName($name) + { + file_put_contents($this->basePath.'/Homestead.yaml', str_replace( + 'cpus: 1', 'cpus: 1'.PHP_EOL.'name: '.$name, $this->getHomesteadFile() + )); + } + + /** + * Set the virtual machine's hostname setting in the Homestead.yaml file. + * + * @param string $hostname + * @return void + */ + protected function updateHostName($hostname) + { + file_put_contents($this->basePath.'/Homestead.yaml', str_replace( + 'cpus: 1', 'cpus: 1'.PHP_EOL.'hostname: '.$hostname, $this->getHomesteadFile() + )); + } + + /** + * Get the contents of the Homestead.yaml file. + * + * @return string + */ + protected function getHomesteadFile() + { + return file_get_contents($this->basePath.'/Homestead.yaml'); + } +} diff --git a/src/ProvisionCommand.php b/src/ProvisionCommand.php new file mode 100644 index 0000000..ae76d90 --- /dev/null +++ b/src/ProvisionCommand.php @@ -0,0 +1,37 @@ +setName('provision')->setDescription('Re-provisions the Homestead machine'); + } + + /** + * Execute the command. + * + * @param \Symfony\Component\Console\Input\InputInterface $input + * @param \Symfony\Component\Console\Output\OutputInterface $output + * @return void + */ + public function execute(InputInterface $input, OutputInterface $output) + { + $process = new Process('vagrant provision', realpath(__DIR__.'/../'), array_merge($_SERVER, $_ENV), null, null); + + $process->run(function ($type, $line) use ($output) { + $output->write($line); + }); + } +} diff --git a/src/ResumeCommand.php b/src/ResumeCommand.php new file mode 100644 index 0000000..ebfb3b2 --- /dev/null +++ b/src/ResumeCommand.php @@ -0,0 +1,37 @@ +setName('resume')->setDescription('Resume the suspended Homestead machine'); + } + + /** + * Execute the command. + * + * @param \Symfony\Component\Console\Input\InputInterface $input + * @param \Symfony\Component\Console\Output\OutputInterface $output + * @return void + */ + public function execute(InputInterface $input, OutputInterface $output) + { + $process = new Process('vagrant resume', realpath(__DIR__.'/../'), array_merge($_SERVER, $_ENV), null, null); + + $process->run(function ($type, $line) use ($output) { + $output->write($line); + }); + } +} diff --git a/src/RunCommand.php b/src/RunCommand.php new file mode 100644 index 0000000..c4f3a61 --- /dev/null +++ b/src/RunCommand.php @@ -0,0 +1,54 @@ +setName('run') + ->setDescription('Run commands through the Homestead machine via SSH') + ->addArgument('ssh-command', InputArgument::REQUIRED, 'The command to pass through to the virtual machine.'); + } + + /** + * Execute the command. + * + * @param \Symfony\Component\Console\Input\InputInterface $input + * @param \Symfony\Component\Console\Output\OutputInterface $output + * @return void + */ + public function execute(InputInterface $input, OutputInterface $output) + { + chdir(__DIR__.'/../'); + + $command = $input->getArgument('ssh-command'); + + passthru($this->setEnvironmentCommand().' vagrant ssh -c "'.$command.'"'); + } + + protected function setEnvironmentCommand() + { + if ($this->isWindows()) { + return 'SET VAGRANT_DOTFILE_PATH='.$_ENV['VAGRANT_DOTFILE_PATH'].' &&'; + } + + return 'VAGRANT_DOTFILE_PATH="'.$_ENV['VAGRANT_DOTFILE_PATH'].'"'; + } + + protected function isWindows() + { + return strpos(strtoupper(PHP_OS), 'WIN') === 0; + } +} diff --git a/src/SshCommand.php b/src/SshCommand.php new file mode 100644 index 0000000..87726b4 --- /dev/null +++ b/src/SshCommand.php @@ -0,0 +1,48 @@ +setName('ssh')->setDescription('Login to the Homestead machine via SSH'); + } + + /** + * Execute the command. + * + * @param \Symfony\Component\Console\Input\InputInterface $input + * @param \Symfony\Component\Console\Output\OutputInterface $output + * @return void + */ + public function execute(InputInterface $input, OutputInterface $output) + { + chdir(__DIR__.'/../'); + + passthru($this->setEnvironmentCommand().' vagrant ssh'); + } + + protected function setEnvironmentCommand() + { + if ($this->isWindows()) { + return 'SET VAGRANT_DOTFILE_PATH='.$_ENV['VAGRANT_DOTFILE_PATH'].' &&'; + } + + return 'VAGRANT_DOTFILE_PATH="'.$_ENV['VAGRANT_DOTFILE_PATH'].'"'; + } + + protected function isWindows() + { + return strpos(strtoupper(PHP_OS), 'WIN') === 0; + } +} diff --git a/src/SshConfigCommand.php b/src/SshConfigCommand.php new file mode 100644 index 0000000..38500fa --- /dev/null +++ b/src/SshConfigCommand.php @@ -0,0 +1,58 @@ +setName('ssh-config')->setDescription('Outputs OpenSSH valid configuration to connect to Homestead'); + } + + /** + * Execute the command. + * + * @param \Symfony\Component\Console\Input\InputInterface $input + * @param \Symfony\Component\Console\Output\OutputInterface $output + * @return void + */ + public function execute(InputInterface $input, OutputInterface $output) + { + chdir(__DIR__.'/../'); + + passthru($this->setDotFileInEnvironment().' vagrant ssh-config'); + } + + /** + * Set the dot file path in the environment. + * + * @return void + */ + protected function setDotFileInEnvironment() + { + if ($this->isWindows()) { + return 'SET VAGRANT_DOTFILE_PATH='.$_ENV['VAGRANT_DOTFILE_PATH'].' &&'; + } + + return 'VAGRANT_DOTFILE_PATH="'.$_ENV['VAGRANT_DOTFILE_PATH'].'"'; + } + + /** + * Determine if the machine is running the Windows operating system. + * + * @return bool + */ + protected function isWindows() + { + return strpos(strtoupper(PHP_OS), 'WIN') === 0; + } +} diff --git a/src/StatusCommand.php b/src/StatusCommand.php new file mode 100644 index 0000000..5dd773a --- /dev/null +++ b/src/StatusCommand.php @@ -0,0 +1,37 @@ +setName('status')->setDescription('Get the status of the Homestead machine'); + } + + /** + * Execute the command. + * + * @param \Symfony\Component\Console\Input\InputInterface $input + * @param \Symfony\Component\Console\Output\OutputInterface $output + * @return void + */ + public function execute(InputInterface $input, OutputInterface $output) + { + $process = new Process('vagrant status', realpath(__DIR__.'/../'), array_merge($_SERVER, $_ENV), null, null); + + $process->run(function ($type, $line) use ($output) { + $output->write($line); + }); + } +} diff --git a/src/SuspendCommand.php b/src/SuspendCommand.php new file mode 100644 index 0000000..2d065a6 --- /dev/null +++ b/src/SuspendCommand.php @@ -0,0 +1,37 @@ +setName('suspend')->setDescription('Suspend the Homestead machine'); + } + + /** + * Execute the command. + * + * @param \Symfony\Component\Console\Input\InputInterface $input + * @param \Symfony\Component\Console\Output\OutputInterface $output + * @return void + */ + public function execute(InputInterface $input, OutputInterface $output) + { + $process = new Process('vagrant suspend', realpath(__DIR__.'/../'), array_merge($_SERVER, $_ENV), null, null); + + $process->run(function ($type, $line) use ($output) { + $output->write($line); + }); + } +} diff --git a/src/UpCommand.php b/src/UpCommand.php new file mode 100644 index 0000000..e48a4a0 --- /dev/null +++ b/src/UpCommand.php @@ -0,0 +1,47 @@ +setName('up') + ->setDescription('Start the Homestead machine') + ->addOption('provision', null, InputOption::VALUE_NONE, 'Run the provisioners on the box.'); + } + + /** + * Execute the command. + * + * @param \Symfony\Component\Console\Input\InputInterface $input + * @param \Symfony\Component\Console\Output\OutputInterface $output + * @return void + */ + public function execute(InputInterface $input, OutputInterface $output) + { + $command = 'vagrant up'; + + if ($input->getOption('provision')) { + $command .= ' --provision'; + } + + $process = new Process($command, realpath(__DIR__.'/../'), array_merge($_SERVER, $_ENV), null, null); + + $process->run(function ($type, $line) use ($output) { + $output->write($line); + }); + } +} diff --git a/src/UpdateCommand.php b/src/UpdateCommand.php new file mode 100644 index 0000000..99a6f16 --- /dev/null +++ b/src/UpdateCommand.php @@ -0,0 +1,37 @@ +setName('update')->setDescription('Update the Homestead machine image'); + } + + /** + * Execute the command. + * + * @param \Symfony\Component\Console\Input\InputInterface $input + * @param \Symfony\Component\Console\Output\OutputInterface $output + * @return void + */ + public function execute(InputInterface $input, OutputInterface $output) + { + $process = new Process('vagrant box update', realpath(__DIR__.'/../'), array_merge($_SERVER, $_ENV), null, null); + + $process->run(function ($type, $line) use ($output) { + $output->write($line); + }); + } +}