Skip to content

Commit

Permalink
Merge pull request #6660 from rolandwalker/installer_stanza
Browse files Browse the repository at this point in the history
DSL: add `installer` stanza
  • Loading branch information
rolandwalker committed Oct 16, 2014
2 parents c021c67 + 4277051 commit 633a2ef
Show file tree
Hide file tree
Showing 19 changed files with 216 additions and 99 deletions.
70 changes: 54 additions & 16 deletions doc/CASK_LANGUAGE_REFERENCE.md
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,7 @@ Cask Domain-Specific Language (DSL) which are not needed in most cases.
* [App Stanza Details](#app-stanza-details)
* [Suite Stanza Details](#suite-stanza-details)
* [Pkg Stanza Details](#pkg-stanza-details)
* [Installer Stanza Details](#installer-stanza-details)
* [Depends_on Stanza Details](#depends_on-stanza-details)
* [Uninstall Stanza Details](#uninstall-stanza-details)
* [Zap Stanza Details](#zap-stanza-details)
Expand Down Expand Up @@ -96,6 +97,7 @@ Each Cask must declare one or more *artifacts* (i.e. something to install)
| `widget` | yes | relative path to a widget that should be linked into the `~/Library/Widgets` folder on installation (ALPHA: DOES NOT WORK YET)
| `suite` | yes | relative path to a containing directory that should be linked into the `~/Applications` folder on installation (see also [Suite Stanza Details](#suite-stanza-details))
| `artifact` | yes | relative path to an arbitrary path that should be symlinked on installation. This is only for unusual cases. The `app` stanza is strongly preferred when linking `.app` bundles.
| `installer` | yes | describes an executable which must be run to complete the installation. (see [Installer Stanza Details](#installer-stanza-details))

## Optional Stanzas

Expand All @@ -119,27 +121,28 @@ Each Cask must declare one or more *artifacts* (i.e. something to install)

The following stanzas are no longer in use.

| name | multiple occurrences allowed? | meaning |
| -------------------- |------------------------------ | ----------- |
| `after_install` | yes | an obsolete alternative to `postflight`
| `after_uninstall` | yes | an obsolete alternative to `uninstall_postflight`
| `before_install` | yes | an obsolete alternative to `preflight`
| `before_uninstall` | yes | an obsolete alternative to `uninstall_preflight`
| `container_type` | yes | an obsolete alternative to `container :type =>`
| `depends_on_formula` | yes | an obsolete alternative to `depends_on :formula =>`
| `install` | yes | an obsolete alternative to `pkg`
| `link` | yes | an obsolete alternative to `artifact`
| `no_checksum` | no | an obsolete alternative to `sha256 :no_check`
| name | meaning |
| ------------------------- | ----------- |
| `after_install` | an obsolete alternative to `postflight`
| `after_uninstall` | an obsolete alternative to `uninstall_postflight`
| `before_install` | an obsolete alternative to `preflight`
| `before_uninstall` | an obsolete alternative to `uninstall_preflight`
| `container_type` | an obsolete alternative to `container :type =>`
| `depends_on_formula` | an obsolete alternative to `depends_on :formula =>`
| `install` | an obsolete alternative to `pkg`
| `link` | an obsolete alternative to `artifact`
| `no_checksum` | an obsolete alternative to `sha256 :no_check`


## Legacy Forms

The following forms are no longer in use.

| name | meaning |
| -------------------- | ----------- |
| `uninstall :files` | an obsolete alternative to `uninstall :delete`
| `version 'latest'` | an obsolete alternative to `version :latest`
| name | meaning |
| ------------------------- | ----------- |
| `uninstall :files` | an obsolete alternative to `uninstall :delete`
| `version 'latest'` | an obsolete alternative to `version :latest`
| `manual_installer(path)` | when occurring within `caveats`, an obsolete alternative to `installer :script`


## Conditional Statements
Expand Down Expand Up @@ -225,7 +228,6 @@ The following methods may be called to generate standard warning messages:

| method | description |
| --------------------------------- | ----------- |
| `manual_installer(path)` | The user should execute an installer to complete the installation. `path` may be absolute, or relative to the Cask.
| `path_environment_variable(path)` | The user should make sure `path` is in their `$PATH` environment variable
| `zsh_path_helper(path)` | Zsh users must take additional steps to make sure `path` is in their `$PATH` environment variable
| `logout` | The user should log out and log back in to complete installation
Expand Down Expand Up @@ -480,6 +482,42 @@ Example:
pkg 'Soundflower.pkg', :allow_untrusted => true
```


## Installer Stanza Details

The `installer` stanza takes a series of key-value pairs, the first key of
which must be `:manual` or `:script`.

### Installer :manual

`installer :manual` takes a single string value, describing a GUI installer
which must be run by the user at a later time. The path may be absolute,
or relative to the Cask. Example:

```ruby
installer :manual => 'Little Snitch Installer.app'
```
### Installer :script

`installer :script` introduces a series of key-value pairs describing
a command which will automate completion of the install. The form is
similar to `uninstall :script`:

| key | value
| ----------------|------------------------------
| `:script` | path to an install script to be run via `sudo`. (Required first key.)
| `:args` | array of arguments to the install script
| `:input` | array of lines of input to be sent to `stdin` of the script
| `:must_succeed` | set to `false` if the script is allowed to fail
| `:sudo` | set to `false` if the script does not need `sudo`

The path may be absolute, or relative to the Cask. Example:

```ruby
installer :script => 'Adobe AIR Installer.app/Contents/MacOS/Adobe AIR Installer',
:args => %w[-silent]
```

## Depends_on Stanza Details

`depends_on` is used to declare dependencies required to install a Cask
Expand Down
28 changes: 15 additions & 13 deletions doc/cask_language_deltas.md
Original file line number Diff line number Diff line change
Expand Up @@ -43,6 +43,7 @@ This notice will be removed for the final form.**
* *stub* - not yet functional
* `depends_on :java`
* *stub* - not yet functional
* `installer :script`
* `license`
* `suite`
* `tags`
Expand All @@ -54,19 +55,20 @@ This notice will be removed for the final form.**

## Renames (1.0)

| old form | new form
| --------------------- |----------------
| `after_install` | `postflight`
| `after_uninstall` | `uninstall_postflight`
| `before_install` | `preflight`
| `before_uninstall` | `uninstall_preflight`
| `container_type` | `container :type`
| `depends_on_formula` | `depends_on :formula`
| `install` | `pkg`
| `link` | `app` (or sometimes `suite` or `artifact`)
| `nested_container` | `container :nested =>`
| `uninstall :files` | `uninstall :delete`
| `version 'latest'` | `version :latest`
| old form | new form
| ------------------------------------------- |----------------
| `after_install` | `postflight`
| `after_uninstall` | `uninstall_postflight`
| `before_install` | `preflight`
| `before_uninstall` | `uninstall_preflight`
| `container_type` | `container :type`
| `depends_on_formula` | `depends_on :formula`
| `install` | `pkg`
| `link` | `app` (or sometimes `suite` or `artifact`)
| `nested_container` | `container :nested =>`
| `uninstall :files` | `uninstall :delete`
| `version 'latest'` | `version :latest`
| `manual_installer(path)` (within `caveats`) | `installer :manual`


## All Supported Stanzas (1.0)
Expand Down
1 change: 1 addition & 0 deletions lib/cask.rb
Original file line number Diff line number Diff line change
Expand Up @@ -30,6 +30,7 @@ class Cask; end
require 'cask/qualified_cask_name'
require 'cask/scopes'
require 'cask/source'
require 'cask/staged'
require 'cask/system_command'
require 'cask/underscore_supporting_uri'
require 'cask/url'
Expand Down
4 changes: 2 additions & 2 deletions lib/cask/artifact.rb
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,7 @@ module Cask::Artifact; end
require 'cask/artifact/before_block'
require 'cask/artifact/colorpicker'
require 'cask/artifact/font'
require 'cask/artifact/install_script'
require 'cask/artifact/installer'
require 'cask/artifact/nested_container'
require 'cask/artifact/pkg'
require 'cask/artifact/prefpane'
Expand All @@ -35,7 +35,7 @@ def self.artifacts
[
Cask::Artifact::BeforeBlock,
Cask::Artifact::NestedContainer,
Cask::Artifact::InstallScript,
Cask::Artifact::Installer,
Cask::Artifact::App,
Cask::Artifact::Artifact, # generic 'artifact' stanza
Cask::Artifact::Colorpicker,
Expand Down
30 changes: 0 additions & 30 deletions lib/cask/artifact/install_script.rb

This file was deleted.

40 changes: 40 additions & 0 deletions lib/cask/artifact/installer.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,40 @@
class Cask::Artifact::Installer < Cask::Artifact::Base

# todo: for backward compatibility, removeme
def install
install_phase
end

# todo: for backward compatibility, removeme
def uninstall
uninstall_phase
end

def install_phase
@cask.artifacts[self.class.artifact_dsl_key].each do |artifact|
if artifact.manual then
puts <<-EOS.undent
To complete the installation of Cask #{@cask}, you must also
run the installer at
'#{@cask.destination_path.join(artifact.manual)}'
EOS
else
executable, script_arguments = self.class.read_script_arguments(
artifact.script,
"#{self.class.artifact_dsl_key}",
{:must_succeed => true, :sudo => true},
{:print_stdout => true}
)
ohai "Running #{self.class.artifact_dsl_key} script #{executable}"
raise CaskInvalidError.new(@cask, "#{self.class.artifact_dsl_key} missing executable") if executable.nil?
@command.run(@cask.destination_path.join(executable), script_arguments)
end
end
end

def uninstall_phase
odebug "Nothing to do. The #{self.class.artifact_dsl_key} artifact has no uninstall phase."
end
end
2 changes: 2 additions & 0 deletions lib/cask/caveats.rb
Original file line number Diff line number Diff line change
Expand Up @@ -43,6 +43,8 @@ def destination_path
# ( The return value of the last method in the block is also sent
# to the output by the caller, but that feature is only for the
# convenience of Cask authors. )

# todo: remove this method after DSL 1.0 transition
def manual_installer(path)
puts <<-EOS.undent
To complete the installation of Cask #{@cask}, you must also
Expand Down
19 changes: 8 additions & 11 deletions lib/cask/dsl.rb
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@
module Cask::DSL; end

require 'cask/dsl/base'
require 'cask/dsl/installed'
require 'cask/dsl/installer'
require 'cask/dsl/after_install'
require 'cask/dsl/after_uninstall'
require 'cask/dsl/before_install'
Expand Down Expand Up @@ -282,18 +282,15 @@ def self.ordinary_artifact_types
end
end

def install_script(*args)
unless args.length > 0
raise CaskInvalidError.new(self.title, "'install_script' stanza requires an argument")
def installer(*args)
if args.empty?
return artifacts[:installer]
end
executable = args.shift if args[0].kind_of? String
if args.length > 0
args = Hash.new().merge(*args)
else
args = Hash.new()
begin
artifacts[:installer] << Cask::DSL::Installer.new(*args)
rescue StandardError => e
raise CaskInvalidError.new(self.title, e)
end
args.merge!({ :executable => executable }) if executable
artifacts[:install_script] << args
end

attr_reader :sums
Expand Down
4 changes: 3 additions & 1 deletion lib/cask/dsl/after_install.rb
Original file line number Diff line number Diff line change
@@ -1,5 +1,7 @@
require 'cask/staged'

class Cask::DSL::AfterInstall < Cask::DSL::Base
include Cask::DSL::Installed
include Cask::Staged

def suppress_move_to_applications
system_command("/usr/bin/defaults", :args => ["write", bundle_identifier, "moveToApplicationsFolderAlertSuppress", "-bool", "true"])
Expand Down
4 changes: 3 additions & 1 deletion lib/cask/dsl/before_uninstall.rb
Original file line number Diff line number Diff line change
@@ -1,5 +1,7 @@
require 'cask/staged'

class Cask::DSL::BeforeUninstall < Cask::DSL::Base
include Cask::DSL::Installed
include Cask::Staged

def remove_accessibility_access
if MacOS.version >= :mavericks
Expand Down
39 changes: 39 additions & 0 deletions lib/cask/dsl/installer.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,39 @@
class Cask::DSL::Installer

VALID_KEYS = Set.new [
:manual,
:script,
]

attr_accessor *VALID_KEYS

def initialize(*parameters)
unless parameters.length > 0
raise CaskInvalidError.new(self.title, "'installer' stanza requires an argument")
end
parameters = Hash.new().merge(*parameters)
if parameters.key?(:script) and ! parameters[:script].respond_to?(:key?)
if parameters.key?(:executable)
raise CaskInvalidError.new(self.title, "'installer' stanza gave arguments for both :script and :executable")
end
parameters[:executable] = parameters[:script]
parameters.delete(:script)
parameters = { :script => parameters }
end
unless parameters.keys.length == 1
raise "invalid 'installer' stanza: only one of #{VALID_KEYS.inspect} is permitted"
end
key = parameters.keys.first
raise "invalid 'installer' stanza key: '#{key.inspect}'" unless VALID_KEYS.include?(key)
writer_method = "#{key}=".to_sym
send(writer_method, parameters[key])
end

def to_yaml
@pairs.to_yaml
end

def to_s
@pairs.inspect
end
end
3 changes: 2 additions & 1 deletion lib/cask/dsl/installed.rb → lib/cask/staged.rb
Original file line number Diff line number Diff line change
@@ -1,9 +1,10 @@
module Cask::DSL::Installed
module Cask::Staged
def info_plist
"#{destination_path}/#{@cask.artifacts[:link].first.first}/Contents/Info.plist"
end

def plist_exec(cmd)
# todo: don't use external interface system_command
system_command("/usr/libexec/PlistBuddy", :args => ["-c", cmd, info_plist])
end

Expand Down
6 changes: 3 additions & 3 deletions test/cask/cli/info_test.rb
Original file line number Diff line number Diff line change
Expand Up @@ -61,10 +61,10 @@
Cask title: with-caveats
Custom text via puts followed by DSL-generated text:
To complete the installation of Cask with-caveats, you must also
run the installer at
To use with-caveats, you may need to add the /custom/path/bin directory
to your PATH environment variable, eg (for bash shell):
'#{Cask.caskroom}/with-caveats/1.2.3/Installer.app'
export PATH=/custom/path/bin:"$PATH"
CLIOUTPUT
end
Expand Down
Loading

0 comments on commit 633a2ef

Please sign in to comment.