Merge pull request #9504 from zachflower/feature/vagrant-aliases

Vagrant aliases
This commit is contained in:
Chris Roberts 2018-04-06 15:39:18 -07:00 committed by GitHub
commit f3c5e86f28
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
10 changed files with 229 additions and 0 deletions

View File

@ -84,6 +84,7 @@ require "vagrant/registry"
module Vagrant
autoload :Action, 'vagrant/action'
autoload :Alias, 'vagrant/alias'
autoload :BatchAction, 'vagrant/batch_action'
autoload :Box, 'vagrant/box'
autoload :BoxCollection, 'vagrant/box_collection'

56
lib/vagrant/alias.rb Normal file
View File

@ -0,0 +1,56 @@
require "vagrant/registry"
module Vagrant
# This class imports and processes CLI aliases stored in ~/.vagrant.d/aliases
class Alias
def initialize(env)
@aliases = Registry.new
@env = env
if env.aliases_path.file?
env.aliases_path.readlines.each do |line|
# separate keyword-command pairs
keyword, command = interpret(line)
if keyword && command
register(keyword, command)
end
end
end
end
# This returns all the registered alias commands.
def commands
@aliases
end
# This interprets a raw line from the aliases file.
def interpret(line)
# is it a comment?
return nil if line.strip.start_with?("#")
keyword, command = line.split("=", 2).collect(&:strip)
# validate the keyword
if keyword.match(/\s/i)
raise Errors::AliasInvalidError, alias: line, message: "Alias keywords must not contain any whitespace."
end
[keyword, command]
end
# This registers an alias.
def register(keyword, command)
@aliases.register(keyword.to_sym) do
lambda do |args|
# directly execute shell commands
if command.start_with?("!")
return Util::SafeExec.exec "#{command[1..-1]} #{args.join(" ")}".strip
end
return CLI.new(command.split.concat(args), @env).execute
end
end
end
end
end

View File

@ -28,6 +28,14 @@ module Vagrant
command_plugin = nil
if @sub_command
command_plugin = Vagrant.plugin("2").manager.commands[@sub_command.to_sym]
if !command_plugin
alias_command = Alias.new(@env).commands[@sub_command.to_sym]
if alias_command
return alias_command.call(@sub_args)
end
end
end
if !command_plugin || !@sub_command

View File

@ -56,6 +56,9 @@ module Vagrant
# The directory where temporary files for Vagrant go.
attr_reader :tmp_path
# File where command line aliases go.
attr_reader :aliases_path
# The directory where boxes are stored.
attr_reader :boxes_path
@ -124,6 +127,9 @@ module Vagrant
@tmp_path = @home_path.join("tmp")
@machine_index_dir = @data_dir.join("machine-index")
@aliases_path = Pathname.new(ENV["VAGRANT_ALIAS_FILE"]).expand_path if ENV.key?("VAGRANT_ALIAS_FILE")
@aliases_path ||= @home_path.join("aliases")
# Prepare the directories
setup_home_path

View File

@ -108,6 +108,10 @@ module Vagrant
error_key(:active_machine_with_different_provider)
end
class AliasInvalidError < VagrantError
error_key(:alias_invalid_error)
end
class BatchMultiError < VagrantError
error_key(:batch_multi_error)
end

View File

@ -402,6 +402,12 @@ en:
Machine name: %{name}
Active provider: %{active_provider}
Requested provider: %{requested_provider}
alias_invalid_error: |-
The defined alias is not valid. Please review the information below
to help resolve the issue:
Alias: %{alias}
Message: %{message}
batch_multi_error: |-
An error occurred while executing multiple actions in parallel.
Any errors that occurred are shown below.

View File

@ -0,0 +1,68 @@
require_relative "../base"
require "vagrant/alias"
describe Vagrant::Alias do
include_context "unit"
include_context "command plugin helpers"
let(:iso_env) { isolated_environment }
let(:env) { iso_env.create_vagrant_env }
describe "#interpret" do
let(:interpreter) { described_class.new(env) }
it "returns nil for comments" do
comments = [
"# this is a comment",
"# so is this ",
" # and this",
" # this too "
]
comments.each do |comment|
expect(interpreter.interpret(comment)).to be_nil
end
end
it "raises an error on invalid keywords" do
keywords = [
"keyword with a space = command",
"keyword\twith a tab = command",
"keyword\nwith a newline = command",
]
keywords.each do |keyword|
expect { interpreter.interpret(keyword) }.to raise_error(Vagrant::Errors::AliasInvalidError)
end
end
it "properly interprets a simple alias" do
keyword, command = interpreter.interpret("keyword=command")
expect(keyword).to eq("keyword")
expect(command).to eq("command")
end
it "properly interprets an alias with excess whitespace" do
keyword, command = interpreter.interpret(" keyword = command ")
expect(keyword).to eq("keyword")
expect(command).to eq("command")
end
it "properly interprets an alias with an equals sign in the command" do
keyword, command = interpreter.interpret(" keyword = command = command ")
expect(keyword).to eq("keyword")
expect(command).to eq("command = command")
end
it "allows keywords with non-alpha-numeric characters" do
keyword, command = interpreter.interpret("keyword! = command")
expect(keyword).to eq("keyword!")
expect(command).to eq("command")
end
end
end

View File

@ -0,0 +1,74 @@
---
layout: "docs"
page_title: "Aliases - Command-Line Interface"
sidebar_current: "cli-aliases"
description: |-
Custom Vagrant commands can be defined using aliases, allowing for a simpler,
easier, and more familiar command line interface.
---
# Aliases
Inspired in part by Git's own
[alias functionality](https://git-scm.com/book/en/v2/Git-Basics-Git-Aliases),
aliases make your Vagrant experience simpler, easier, and more familiar by
allowing you to create your own custom Vagrant commands.
Aliases can be defined within `VAGRANT_HOME/aliases` file, or in a custom file
defined using the `VAGRANT_ALIAS_FILE` environment variable, in the following
format:
```
# basic command-level aliases
start = up
stop = halt
# advanced command-line aliases
eradicate = !vagrant destroy && rm -rf .vagrant
```
In a nutshell, aliases are defined using a standard `key = value` format, where
the `key` is the new Vagrant command, and the `value` is the aliased command.
Using this format, there are two types of aliases that can be defined: internal
and external aliases.
## Internal Aliases
Internal command aliases call the CLI class directly, allowing you to alias
one Vagrant command to another Vagrant command. This technique can be very
useful for creating commands that you think _should_ exist. For example,
if `vagrant stop` feels more intuitive than `vagrant halt`, the following alias
definitions would make that change possible:
```
stop = halt
```
This makes the following commands equivalent:
```
vagrant stop
vagrant halt
```
## External Aliases
While internal aliases can be used to define more intuitive Vagrant commands,
external command aliases are used to define Vagrant commands with brand new
functionality. These aliases are prefixed with the `!` character, which
indicates to the interpreter that the alias should be executed as a shell
command. For example, let's say that you want to be able to view the processor
and memory utilization of the active project's virtual machine. To do this, you
could define a `vagrant metrics` command that returns the required information
in an easy-to-read format, like so:
```
metrics = !ps aux | grep "[V]BoxHeadless" | grep $(cat .vagrant/machines/default/virtualbox/id) | awk '{ printf("CPU: %.02f%%, Memory: %.02f%%", $3, $4) }'
```
The above alias, from within the context of an active Vagrant project, would
print the CPU and memory utilization directly to the console:
```
CPU: 4.20%, Memory: 11.00%
```

View File

@ -14,6 +14,11 @@ Vagrant has a set of environmental variables that can be used to
configure and control it in a global way. This page lists those environmental
variables.
## `VAGRANT_ALIAS_FILE`
`VAGRANT_ALIAS_FILE` can be set to change the file where Vagrant aliases are
defined. By default, this is set to `~/.vagrant.d/aliases`.
## `VAGRANT_DEBUG_LAUNCHER`
For performance reasons, especially for Windows users, Vagrant uses a static

View File

@ -44,6 +44,7 @@
<li<%= sidebar_current("cli-validate") %>><a href="/docs/cli/validate.html">validate</a></li>
<li<%= sidebar_current("cli-version") %>><a href="/docs/cli/version.html">version</a></li>
<li<%= sidebar_current("cli-nonprimary") %>><a href="/docs/cli/non-primary.html">More Commands</a></li>
<li<%= sidebar_current("cli-aliases") %>><a href="/docs/cli/aliases.html">Aliases</a></li>
<li<%= sidebar_current("cli-machinereadable") %>><a href="/docs/cli/machine-readable.html">Machine Readable Output</a></li>
</ul>
</li>