vagrant/website/docs/source/v2/plugins/commands.html.md

133 lines
4.2 KiB
Markdown
Raw Normal View History

---
page_title: "Command Plugins - Plugin Development"
sidebar_current: "plugins-commands"
---
# Plugin Development: Commands
This page documents how to add new commands to Vagrant, invokable
via `vagrant YOUR-COMMAND`. Prior to reading this, you should be familiar
with the [plugin development basics](/v2/plugins/development-basics.html).
<div class="alert alert-warn">
<p>
<strong>Warning: Advanced Topic!</strong> Developing plugins is an
advanced topic that only experienced Vagrant users who are reasonably
comfortable with Ruby should approach.
</p>
</div>
## Definition Component
Within the context of a plugin definition, new commands can be defined
like so:
```ruby
command "foo" do
require_relative "command"
Command
end
```
Commands are defined with the `command` method, which takes as an argument
the name of the command, in this case "foo." This means the command will be
invokable via `vagrant foo`. Then the block argument returns a class that
implements the `Vagrant.plugin(2, "command")` interface.
You can also define _non-primary commands_. These commands do not show
up in the `vagrant -h` output. They only show up if the user explicitly
2014-01-11 17:15:14 +00:00
does a `vagrant list-commands` which shows the full listing of available
commands. This is useful for highly specific commands or plugins that a
beginner to Vagrant would not be using anyways. Vagrant itself uses non-primary
commands to expose some internal functions, as well.
To define a non-primary command:
```ruby
command("foo", primary: false) do
require_relative "command"
Command
end
```
## Implementation
Implementations of commands should subclass `Vagrant.plugin(2, :command)`,
which is a Vagrant method that will return the proper superclass for
a version 2 command. The implementation itself is quite simple, since the
class needs to only implement a single method: `execute`. Example:
```ruby
class Command < Vagrant.plugin(2, :command)
def execute
puts "Hello!"
0
end
end
```
The `execute` method is called when the command is invoked, and it should
return the exit status (0 for success, anything else for error).
This is a command at its simplest form. Of course, the command superclass
gives you access to the Vagrant environment and provides some helpers to
do common tasks such as command line parsing.
## Parsing Command-Line Options
The `parse_options` method is available which will parse the command line
for you. It takes an [OptionParser](http://ruby-doc.org/stdlib-1.9.3/libdoc/optparse/rdoc/OptionParser.html)
as an argument, and adds some common elements to it such as the `--help` flag,
automatically showing help if requested. View the API docs directly for more
information.
This is recommended over raw parsing/manipulation of command line flags.
The following is an example of parsing command line flags pulled directly
from the built-in Vagrant `destroy` command:
```ruby
options = {}
options[:force] = false
opts = OptionParser.new do |o|
o.banner = "Usage: vagrant destroy [vm-name]"
o.separator ""
o.on("-f", "--force", "Destroy without confirmation.") do |f|
options[:force] = f
end
end
# Parse the options
argv = parse_options(opts)
```
## Using Vagrant Machines
The `with_target_vms` method is a helper that helps you interact with
the machines that Vagrant manages in a standard Vagrant way. This method
automatically does the right thing in the case of multi-machine environments,
handling target machines on the command line (`vagrant foo my-vm`), etc.
If you need to do any manipulation of a Vagrant machine, including SSH
access, this helper should be used.
An example of using the helper, again pulled directly from the built-in
`destroy` command:
```ruby
with_target_vms(argv, :reverse => true) do |machine|
machine.action(:destroy)
end
```
In this case, it asks for the machines in reverse order and calls the
destroy action on each of them. If a user says `vagrant destroy foo`, then
the helper automatically only yields the `foo` machine. If no parameter
is given and it is a multi-machine environment, every machine in the environment
is yielded, and so on. It just does the right thing.
## Using the Raw Vagrant Environment
The raw loaded `Vagrant::Environment` object is available with the
'@env' instance variable.