Full Code of flogic/whiskey_disk for AI

master 2df0d502013f cached
178 files
336.4 KB
95.9k tokens
214 symbols
1 requests
Download .txt
Showing preview only (379K chars total). Download the full file or copy to clipboard to get everything.
Repository: flogic/whiskey_disk
Branch: master
Commit: 2df0d502013f
Files: 178
Total size: 336.4 KB

Directory structure:
gitextract_l5xymha1/

├── .gitignore
├── CHANGELOG
├── Gemfile
├── MIT-LICENSE
├── README.integration_specs
├── README.markdown
├── Rakefile
├── VERSION
├── WHY.txt
├── bin/
│   ├── wd
│   └── wd_role
├── examples/
│   ├── deploy-configs.yml
│   ├── deploy-local.yml
│   ├── deploy-multiple-remotes.yml
│   ├── deploy-staging.yml
│   ├── deploy.rake
│   └── deploy.yml
├── init.rb
├── install.rb
├── lib/
│   ├── whiskey_disk/
│   │   ├── config/
│   │   │   ├── abstract_filter.rb
│   │   │   ├── filter.rb
│   │   │   └── filters/
│   │   │       ├── add_environment_name_filter.rb
│   │   │       ├── add_project_name_filter.rb
│   │   │       ├── check_for_duplicate_domains_filter.rb
│   │   │       ├── convert_role_strings_to_list_filter.rb
│   │   │       ├── default_config_target_filter.rb
│   │   │       ├── default_domain_filter.rb
│   │   │       ├── drop_empty_domain_roles_filter.rb
│   │   │       ├── environment_scope_filter.rb
│   │   │       ├── hashify_domain_entries_filter.rb
│   │   │       ├── localize_domains_filter.rb
│   │   │       ├── modules/
│   │   │       │   └── scope_helper.rb
│   │   │       ├── normalize_ssh_options_filter.rb
│   │   │       ├── project_scope_filter.rb
│   │   │       ├── select_project_and_environment_filter.rb
│   │   │       └── stringify_hash_keys_filter.rb
│   │   ├── config.rb
│   │   ├── helpers.rb
│   │   └── rake.rb
│   └── whiskey_disk.rb
├── scenarios/
│   ├── git_repositories/
│   │   ├── config.git/
│   │   │   ├── HEAD
│   │   │   ├── config
│   │   │   ├── description
│   │   │   ├── git-daemon-export-ok
│   │   │   ├── hooks/
│   │   │   │   ├── applypatch-msg.sample
│   │   │   │   ├── commit-msg.sample
│   │   │   │   ├── post-commit.sample
│   │   │   │   ├── post-receive.sample
│   │   │   │   ├── post-update.sample
│   │   │   │   ├── pre-applypatch.sample
│   │   │   │   ├── pre-commit.sample
│   │   │   │   ├── pre-rebase.sample
│   │   │   │   ├── prepare-commit-msg.sample
│   │   │   │   └── update.sample
│   │   │   ├── info/
│   │   │   │   └── exclude
│   │   │   ├── objects/
│   │   │   │   ├── 0d/
│   │   │   │   │   └── b14dd6ddc54017c0a11960dcda82ed802cde69
│   │   │   │   ├── 0e/
│   │   │   │   │   └── e781f5ce80d64db32a74a7aae7b5248dafe112
│   │   │   │   ├── 17/
│   │   │   │   │   └── 6bf54cf17d1d1c24556dc059c4144a5df230e8
│   │   │   │   ├── 20/
│   │   │   │   │   └── e9ff3feaa8ede30f707e5f1b4356e3c02bb7ec
│   │   │   │   ├── 45/
│   │   │   │   │   └── 117b1c775f0de415478dbf08ed9d667ab17d13
│   │   │   │   ├── 51/
│   │   │   │   │   └── 3954c9aca090e6ce40359f0e9fde30ea78eb8c
│   │   │   │   ├── 66/
│   │   │   │   │   └── 947a7a11a6f5d3d561fe95de284ced3010819a
│   │   │   │   ├── 6b/
│   │   │   │   │   └── bc79311bfac47d3ed724aa82a4814e0dda4c67
│   │   │   │   ├── 71/
│   │   │   │   │   └── eb5df52676e8e6efba471050b46978173af110
│   │   │   │   ├── 84/
│   │   │   │   │   └── 17d2fe3e8fcc0825249c517b29b0f9ea8b8b31
│   │   │   │   ├── 8b/
│   │   │   │   │   └── 384fcfcf7c0dee7c3c1d5636bee9e645d9cf38
│   │   │   │   ├── bb/
│   │   │   │   │   └── 59da633ba74296b0c2f9ff70784ac155ddb599
│   │   │   │   ├── cc/
│   │   │   │   │   └── b86b26189afbf45d8eb9165812ab86dbdfca63
│   │   │   │   ├── d1/
│   │   │   │   │   └── 0bcd51fec41f854001e4d61f99d9e282a695d3
│   │   │   │   ├── d8/
│   │   │   │   │   └── a8b0f5b1fd66844efb141d9544965ea0065f2d
│   │   │   │   ├── e6/
│   │   │   │   │   └── b02c66ad632e6b8535c4630cb8fe07732a72fc
│   │   │   │   ├── e8/
│   │   │   │   │   └── b8bfeeba735c0a1a873082554cb4d7256ac125
│   │   │   │   └── f9/
│   │   │   │       ├── 0181466a1a60b793ca9cc9abd584c18d4e3887
│   │   │   │       └── 49d5d8a4f12c91471e34d4e277239c35ebd10d
│   │   │   └── refs/
│   │   │       └── heads/
│   │   │           └── master
│   │   └── project.git/
│   │       ├── HEAD
│   │       ├── config
│   │       ├── description
│   │       ├── git-daemon-export-ok
│   │       ├── hooks/
│   │       │   ├── applypatch-msg.sample
│   │       │   ├── commit-msg.sample
│   │       │   ├── post-commit.sample
│   │       │   ├── post-receive.sample
│   │       │   ├── post-update.sample
│   │       │   ├── pre-applypatch.sample
│   │       │   ├── pre-commit.sample
│   │       │   ├── pre-rebase.sample
│   │       │   ├── prepare-commit-msg.sample
│   │       │   └── update.sample
│   │       ├── info/
│   │       │   └── exclude
│   │       ├── objects/
│   │       │   ├── 04/
│   │       │   │   ├── 26e152e66c8cd42974279bdcae09be9839c172
│   │       │   │   └── f4de85eaf72ef1631dc6d7424045c0a749b757
│   │       │   ├── 06/
│   │       │   │   ├── 13fe277280cbcdb2856e1eefc70bdaff011b20
│   │       │   │   └── 7aca89b86265eee211387434c3e50f37ccf009
│   │       │   ├── 09/
│   │       │   │   └── 445dacc4822722612d60833c9948219ecdd8f5
│   │       │   ├── 11/
│   │       │   │   └── c4ec64326de35462f4e79d0f4229bf8e26e0c5
│   │       │   ├── 20/
│   │       │   │   └── 1c7641c2e42b0b904e5c1f793489d8b858e4da
│   │       │   ├── 23/
│   │       │   │   └── 979639da60d2d31e9744468df1c1221b101e64
│   │       │   ├── 27/
│   │       │   │   └── a3fff2c4c45ab5513a405f694c0a042cb5d417
│   │       │   ├── 2c/
│   │       │   │   └── 0c33cfba8e1af15df88522c0db2b10a6a94138
│   │       │   ├── 38/
│   │       │   │   └── b574660305ecb5fec6b2daa7ee1e0dbf1b6003
│   │       │   ├── 4a/
│   │       │   │   └── 57abb5e4e426cfc9101b3af22ac83ccbd8e2ad
│   │       │   ├── 4c/
│   │       │   │   └── 77ebdd985e57afe7988480720c5dc77ec525c9
│   │       │   ├── 51/
│   │       │   │   └── c94da6f1b8aa9d2346088d3d362475b60c7f32
│   │       │   ├── 5b/
│   │       │   │   └── a96acf9cc9b87babe37c032676f53bf1ba9ae7
│   │       │   ├── 5d/
│   │       │   │   └── f555601d60f1c2a84d2364af0ad640612c3ba5
│   │       │   ├── 71/
│   │       │   │   └── 03b5ac94940d596c2160a5cfcd55ca4ccac41f
│   │       │   ├── 73/
│   │       │   │   └── 3fc331098b03523f414f3509b9ae6e637c6866
│   │       │   ├── 80/
│   │       │   │   └── 26076649ceccbe96a6292f2432652f08483035
│   │       │   ├── 86/
│   │       │   │   └── d1ef0976be4567de562224e1b51fbf9820c53a
│   │       │   ├── 87/
│   │       │   │   └── a9d8b09b3401d21b23d90253332d6b28b47db2
│   │       │   ├── 8b/
│   │       │   │   └── 030ba688255c917d189ae3f87d7c5ccd226bc2
│   │       │   ├── 95/
│   │       │   │   ├── c9d5ad9b1c90e4c805516783105fc2037dedeb
│   │       │   │   └── d82d043af35a80eabfd56c0d705abfa3488787
│   │       │   ├── 96/
│   │       │   │   └── 0bf34bb0b46d0aeb0be87f688f4ef06a4b35e1
│   │       │   ├── a3/
│   │       │   │   └── 860106dc1d148c7831cd45ae38829b4ed47702
│   │       │   ├── a8/
│   │       │   │   └── 506d6439b71784a72ac72d284b2ad53088f573
│   │       │   ├── ad/
│   │       │   │   └── 22ea6c7563777936ecfbe50d8e2cf8120fd525
│   │       │   ├── ae/
│   │       │   │   └── 3900de54aff557c61c81146d00f9d38e55a265
│   │       │   ├── bf/
│   │       │   │   ├── 5e3740d52b80abb0378b3f85f93a53b1294521
│   │       │   │   └── b59811cdbc069418dee14b171e6e7e979784b7
│   │       │   ├── cc/
│   │       │   │   └── 5ac0afb24e727d5de344cc26a425f4fb7fd17d
│   │       │   ├── d1/
│   │       │   │   └── 091aa2dd76885108461110c639e6b33a297fce
│   │       │   ├── d8/
│   │       │   │   └── 913f6650eb2b7bf2a633732d8452008ca23dcb
│   │       │   ├── db/
│   │       │   │   └── d1b9667f1b26b13331ac0c321dced8be1aeab0
│   │       │   ├── e4/
│   │       │   │   └── 3b9107e9b1908ce415025e64eb83a493d329b7
│   │       │   ├── ef/
│   │       │   │   └── 2a88894d5421920b9dfe67a9a4d8043830e62e
│   │       │   ├── f4/
│   │       │   │   └── 0123a1ff20c65d8dc15a38a83222647908e6f7
│   │       │   ├── f5/
│   │       │   │   └── 0af315b75ca0b12c720dec6d916b76b968c319
│   │       │   └── f6/
│   │       │       └── 0215709b7b23f3738e9cbaf634b1c86bbd376a
│   │       └── refs/
│   │           └── heads/
│   │               ├── bad_rakefile
│   │               ├── hook_with_changed
│   │               ├── master
│   │               ├── no_rake_hooks
│   │               └── post_rake_tasks
│   ├── invalid/
│   │   └── deploy.yml
│   ├── local/
│   │   └── deploy.yml.erb
│   ├── remote/
│   │   └── deploy.yml
│   └── setup/
│       └── vagrant/
│           ├── .gitignore
│           ├── Vagrantfile
│           ├── manifests/
│           │   └── integration.pp
│           └── pids/
│               └── .gitignore
├── spec/
│   ├── .bacon
│   ├── init_spec.rb
│   ├── install_spec.rb
│   ├── integration/
│   │   ├── branch_switching_spec.rb
│   │   ├── deployment_failures_spec.rb
│   │   ├── helper_spec.rb
│   │   ├── invalid_configuration_spec.rb
│   │   ├── local_deployments_spec.rb
│   │   ├── post_rake_tasks_spec.rb
│   │   ├── post_scripts_spec.rb
│   │   ├── remote_deployments_spec.rb
│   │   └── staleness_checks_spec.rb
│   ├── spec_helper.rb
│   ├── wd_command_spec.rb
│   ├── wd_role_command_spec.rb
│   ├── whiskey_disk/
│   │   ├── config/
│   │   │   ├── filter_spec.rb
│   │   │   └── filters/
│   │   │       ├── add_environment_name_filter_spec.rb
│   │   │       ├── add_project_name_filter_spec.rb
│   │   │       ├── check_for_duplicate_domains_filter_spec.rb
│   │   │       ├── convert_role_strings_to_list_filter_spec.rb
│   │   │       ├── default_config_target_filter_spec.rb
│   │   │       ├── default_domain_filter_spec.rb
│   │   │       ├── drop_empty_domain_roles_filter_spec.rb
│   │   │       ├── environment_scope_filter_spec.rb
│   │   │       ├── hashify_domain_entries_filter_spec.rb
│   │   │       ├── localize_domains_filter_spec.rb
│   │   │       ├── normalize_ssh_options_filter_spec.rb
│   │   │       ├── project_scope_filter_spec.rb
│   │   │       ├── select_project_and_environment_filter_spec.rb
│   │   │       └── stringify_hash_keys_filter_spec.rb
│   │   ├── config_spec.rb
│   │   ├── helpers_spec.rb
│   │   └── rake_spec.rb
│   └── whiskey_disk_spec.rb
├── tasks/
│   └── deploy.rake
└── whiskey_disk.gemspec

================================================
FILE CONTENTS
================================================

================================================
FILE: .gitignore
================================================
pkg/


================================================
FILE: CHANGELOG
================================================

0.6.24 / 2011-10-05
==================

  * fix hashify_domain_filter for ruby 1.9.2 (closes issue #29)

0.6.23 / 2011-09-29
==================

  * Fix incompatibility with latest jeweler (Rakefile error messages) [James Cox (imajes)]
  * We now use vagrant for integration specs.
  * Make rsync_changes more robust
  * Add ERB support to YAML files used in integration specs
  * add per-domain ssh_options support to config files
  * Big refactoring of config handling into a filter stream architecture

0.6.22 / 2011-04-10
==================

  * support branch-switching on deployments
  * added integration spec for "branch switching" behavior

0.6.21 / 2011-04-06
==================

  * change rsync changes capturing mechanism to be more portable
  * upgrade integration spec to test rsync/#changed?/config repo
  * helpers spec now tests root path rsync changes
  * deploy.yml to test rsync changes w/ config repo
  * integration spec project and config changes to stored git repos

0.6.20 / 2011-04-06
==================

  * Output the entire command before running it when debugging.
  * more anal git checkouts on clones to support older gits
  * abort instead of raising in wd
  * Neuter commandline output in wd command spec
  * Make #changes work on setup
  * Allow enabling debugger in specs w/ non-empty ENV['debug']
  * Fix setup #changed? integration specs
  * Improve example text for deployment #changed? integration specs
  * Factor out snapshotting of git revision from WD.initialize_git_changes
  * Fix the direction of the setup #changed? integration spec test
  * Fixing jump_to_initial_commit spec helper
  * Helper integration spec should use the correct branch when setting up.
  * adjust env testing in integration specs
  * update some specs to work with updated checkout/setup helpers
  * use branches in integration checks so full checkouts will work
  * when initializing git changes data, work from deployment path
  * allow integration spec checkouts to switch to a specific branch
  * record git changes for later use by #changed?
  * capture rsync changes for later #changed? analysis
  * capture initial git HEAD ref for later #changes comparisons
  * clean out any prior git/rsync changes data before refreshing repos
  * Add specs for version command-line argument
  * Change spec helper run_command method set pwd to bin/
  * integration spec for #changed? in post_setup tasks
  * adding #changed? helper (and friends) to whiskey_disk/helpers
  * spec_helper method to rewind a git repo to the beginning
  * git project scenario changes to support integration testing of #changes helper
  * refactor:  splitting up WD.summarize method
  * README updates for #changed? helper functionality


0.6.17 / 2011-03-25
==================

  * updating contributor info in README
  * updating specs to pass under new --debug regime
  * deployment status message shouldn't appear in spec run output
  * Refactoring WhiskeyDisk.reset in whiskey_disk_spec.rb
  * spec helper should keep debugging on for test runs
  * Make deployment status message more readable
  * Only run post deploy|setup script with -x in debug mode
  * Only rake --trace in debug mode
  * Suppressing git output unless debug mode
  * Adding log mesage for rsync configuration
  * Only show rsync verbose and progress if debug enabled
  * Print out a log message to indicate which host is currently being deployed
  * Only run set -x in debug mode, also don't use bash -c
  * Refactor a spec to use build_command directly
  * Fix spec description for ENV['debug']
  * Only run ssh with -v if in debug mode
  * Refactor run to use a #ssh command
  * Add WhiskeyDisk::Config.debug?
  * Add -d, --debug to bin/wd
  * change raise to abort for cleaner help output when doing `wd -h`
  * change raise to abort for cleaner help output
  * add --version option to wd
  * Add support section to README


0.6.16 / 2011-03-08
==================

  * Turning off shallow clones for 'wd setup'
  * minor refactoring of new checkout functionality
  * check out the specified branch on setup
  * adding integration specs to test setup + deploy at once
  * tweaking a couple of old path specs

0.6.15 / 2011-03-07
==================

  * integration specs for "git checkout #{branch}" functionality
  * adding scenario to test git checkout on non-master branches
  * Adding current_branch integration spec helper method
  * Ensure specified branch is checked out before applying the refresh

0.6.14 / 2011-02-23
==================

  * forcing bash as the execution shell

0.6.13 / 2011-02-20
==================

  * pass rake_env settings to post_* scripts
  * Finish basic integration specs for post_* scripts
  * should fail when post_* scripts are specified but missing
  * basic integration specs for post_* scripts
  * updating integration spec git repo data

0.6.12 / 2011-02-20
==================

  * bad Rakefile should cause deployment to fail
  * post_* rake task specs
  * new scenarios to use when testing post_* rake hooks
  * adding a dump_log helper to use when developing integration specs

0.6.11 / 2011-02-18
==================

  * Generate an error message when we can't find --to proj/env in a config
  * Fixing typo in an integration spec's example text

0.6.10 / 2011-02-08
==================

  * reorganizing integration specs
  * adding a quick README on how to run integration specs
  * adding a remote deployment integration spec
  * working around permissioning issues to support "remote" integration specs
  * integration specs for non-matching --only deployment
  * make sure the integration test is actually testing the local library
  * fixing 'unit@' --only local deployment WD.remote? bug
  * Adding initial integration spec suite
  * save +x chmod state to bin/wd
  * adding --only support to wd binary
  * an ENV['only'] domain should deploy locally
  * adding support for ENV['none'] to WhiskeyDisk, ::Config
  * WD.fetch now iterates over all domains, local or remote
  * reorganizing specs
  * make it an error for a domain to appear more than once in a given project/target
  * changing internal :domain representation
  * WhiskeyDisk.remote? now takes a domain argument
  * can now specify path to deploy.yml info using an URL

0.6.4 / 2011-01-26
==================

  * bugfix: cd to deploy_to path before running post_{setup,deploy}_script

0.6.3 / 2011-01-13
==================

  * adding support for config_target in deploy.yml

0.6.2 / 2010-12-23
==================

  * update multiple deployment example to use roles
  * new wd_role command for checking membership in a role from shell scripts
  * adding #role? method in whiskey_disk/helpers for role-based rake tasks
  * pass domain roles along as env variables when running ssh commands
  * domain data now includes role information when available
  * internal representation of 'domain' is now a list of hashes
  * refactoring of config domain normalization code
  * adding domain examples for config specs
  * removing unnecessary describe blocks from config spec
  * reordering domain config spec setup data structure for readability


0.6.0 / 2010-12-22
==================

  * adding a set of multi-domain examples
  * adding a local deployment example
  * updating output summary to be more readable
  * rake exit statuses reflect overall deployment/setup success
  * adding WhiskeyDisk.success? method
  * We now summarize runs, both local and remote.
  * record results for local runs as well as remote ones
  * now run SSH commands on multiple domains, serially, synchronously
  * propagating changes allowed by normalizing 'domain' in config data
  * normalize 'domain' values pulled from config files
  * refactor config file writing in config spec
  * WD.remote? now understands arrays of 'domain' entries in the config

0.5.4
==================

  * Removing Jeweler warning from Rakefile
  * eliminating more stubbing specs from config_spec
  * Removing more stub! calls from config specs
  * removing YAML.load exception stub
  * replacing some configuration_data stubs in config spec
  * Remove CURRENT_FILE from config specs
  * Removing CURRENT from config specs
  * Removing more File.exists? stubs from config spec.
  * Removing File.exists? stubs in config specs
  * spec refactorings
  * Removing has_config_repo? stubs from rake specs
  * Using non-stubbed configuration in rake specs
  * removing useless stub of :register_configuration
  * And removing unneeded spec helper
  * removing whiskey_disk config stubbing
  * introducing use_config() spec helper

0.5.3
==================

  * Cosmetic and naming change in new config method
  * fixing spec example description
  * Reworking the config to append project name overrides to the env, since everything else is dependent thereupon
  * tidying up the spec
  * Allowing a manually specified project name in the bare config hash to be used as the parent project in the absence of one specified from the 'to' env setting

0.5.2
==================

  * Adding --check flag to wd command-line script
  * Making shallow clones on initial setup

0.5.0
==================

  * Make the rake test task do right by bacon
  * Adding post_setup_script support
  * Adding post_deploy_script support
  * Reordering specs for post-setup/deployment tasks

0.4.5
==================

  * ENV settings now available to rake when searching for tasks
  * refactoring common code for rake tasks
  * further refactoring of clone_repository
  * refactoring update checkout methods
  * renaming conditional_clone
  * Refactoring rake task code

0.4.4
==================

  * README updates

0.4.3
==================

  * Smarter setups

0.4.2
==================

  * Taking a different approach to rake task detection

0.4.1
==================

  * Fixing post_* hook edge case

0.4.0
==================

  * Make the staleness check actually work with bash.
  * Adding "else" block to provide feedback when not stale
  * More complete implementation of staleness checks
  * Removing earlier abortive implementation of staleness checking
  * Support for staleness checks
  * Adding first pass at conditional staleness checks

0.3.1
==================

  * No longer require a Rakefile when --path isn't used
  * We no longer do per-target config file overrides
  * Don't run post_{setup,deploy} rake tasks without a deployed Rakefile
  * encoding < and >
  * adding a check flag for use with staleness checks


================================================
FILE: Gemfile
================================================
source "https://rubygems.org"

group :test do
  gem "rake", "~> 12.3"
  gem "extensions"
  gem "facon", "~> 0.5.0"
  gem "bacon", "~> 1.1.0"
end


================================================
FILE: MIT-LICENSE
================================================
Copyright (c) 2009, Flawed Logic, OG Consulting, Rick Bradley.


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.


================================================
FILE: README.integration_specs
================================================
Running Integration Specs
-------------------------

To run the integration spec suite you need to be able to run a Vagrant virtual machine (see: http://vagrantup.com/), which means you will have to have VirtualBox installed.  The Vagrant/VirtualBox setup is currently out of the scope of this document.  By default, I have been using the lucid32 box as my "base" box.

Once you are set up to be able to run Vagrant, you can create and start up an integration environment by running the following rake task:

% rake integration:up

This will create a vagrant VM, and so may take a few minutes to complete.


To run the integration specs once the integration environment is up:

    % export INTEGRATION=true
    % rake

To shut down the integration VM and the integration git-daemon server:

    % rake integration:down

To completely remove the integration spec VM (which can take up a good bit of space on disk), do:

    % rake integration:destroy


================================================
FILE: README.markdown
================================================
## Whiskey Disk -- embarrassingly fast deployments. ##


A very opinionated deployment tool, designed to be as fast as technologically possible.  (For more background, read the [WHY.txt](http://github.com/flogic/whiskey_disk/raw/master/WHY.txt) file)  Should work with any project which is git hosted, not just Ruby / Ruby on Rails projects.  Allows for local deploys as well as remote.

You can right-arrow through a talk on the design process of whiskey_disk, given at the 2011 Madison Ruby Conference (as well as the Ruby Hoedown), entitled "Free Whiskey" by going to [http://madisonruby.rickbradley.com](http://madisonruby.rickbradley.com) (slide source available [here](http://github.com/rick/madison_free_whiskey)).

Or... right-arrow through a short whiskey_disk presentation at [http://wd2010.rickbradley.com/](http://wd2010.rickbradley.com) (slide source available [here](http://github.com/rick/whiskey_disk_presentation).), covering the 0.2.*-era functionality.

You can also right-arrow through a shorter but more up-to-date whiskey_disk "lightning talk" presentation (from the 2010 Ruby Hoedown) at [http://wdlightning.rickbradley.com/](http://wdlightning.rickbradley.com) (slide source available [here](http://github.com/rick/whiskey_disk_presentation/tree/lightning).), covering the 0.4.*-era functionality.

### tl;dr ###

First:

    % gem install whiskey_disk


Then make a deploy.yml file (in config/ if you're doing a Rails project):

    staging:
      domain: "deployment_user@staging.mydomain.com"
      deploy_to: "/path/to/where/i/deploy/staging.mydomain.com"
      repository: "https://github.com/username/project.git"
      branch: "staging"
      rake_env:
        RAILS_ENV: 'production'

then:

    % wd setup --to=staging

then:

    % wd deploy --to=staging


### Selling points ###

  - If you share the same opinions as we do there's almost no code involved, almost no
    dependencies, and it uses stock *nix tools (ssh, bash, rsync) to get
everything done.

  - Written completely spec-first for 100% coverage.  We even did that for the
    rake tasks, the init.rb and the plugin install.rb (if you swing that way).

  - 1 ssh connection per run -- so everything needed to do a full setup
    is done in one shot.  Everything needed to do a full deployment is done in
one shot.  (Having 8 minute deploys failing because I was on CDMA wireless on a
train in India where the connection won't stay up for more than 2-3 minutes is
not where I want to be any more.)

  - Deployment configuration is specified as YAML data, not as code.
    Operations to perform after setup or deployment are specified as rake
tasks.

  - You can do *local* deployments, by this I mean you can use whiskey\_disk to
    deploy fully running instances of your application to the same machine
you're developing on.  This turns out to be surprisingly handy (well, I was
surprised).  *NOTE*:  be sure to set your deploy_to to a place other than the
current local checkout.

  - You can do multi-project deployments, specifying deployment data in a single
    deploy.yml config file, or keep an entire directory of project deployment config files.

  - You can separate per-deployment application configuration information (e.g., passwords,
    database configs, hoptoad/AWS/email config data, etc.) in separate repositories from
    the application, and whiskey\_disk will merge the correct data onto the deployed
    application at deployment time.  You can even share sets of configuration files among
    deployment targets that behave alike.

  - You can have per-developer configurations for targets (especially
    useful for "local" or "development" targets).  Use .gitignore, or
    specify a config_branch and everyone can have their own local setup that just
    works.

  - There's no before\_after\_before_after hooks.  You can use a well-defined rake hook and/or a
    bash script to run additional tasks.

  - You can enable "staleness checks" so that deployments only happen if
    either the main repo, or the config repo (if you're using one) has
    changes that are newer than what is currently deployed.

  - Put whiskey\_disk in a cron, with staleness checks enabled, and you can
    do hands-free automated deployments whenever code is pushed to your
    deployment branch of choice!

  - You can deploy to multiple remote targets at once.  Currently this is limited
    to one-after-the-other synchronous deployments, but we're thinking about
    doing them in parallel once we're happy with the stability of this feature.

  - Assign hosts to roles (e.g., "web", "db", "app") and vary the shell or rake
    post-setup/post-deploy actions you run based on those roles.

  - Limit the actions you run after deployment based on whether files of interest
    *actually changed*.

### Assumptions ###

 - your project is managed via git
 - you are deploying over ssh, or deploying locally and have a bash-compatible shell
 - you are comfortable defining (optional) post-setup and post-deployment actions with rake
 - you have an optional second git repository for per-application/per-target configuration files
 - you have an optional Rakefile in the top directory of your project's checkout

### Dependencies ###

On the server from which the whiskey_disk process will be kicked off:

 - ruby
 - rake
 - whiskey\_disk
 - ssh (if doing a remote deployment).

On the deployment target server (which may be the same as the first server):

 - a bash-compatible shell
 - rsync (only if using a configuration repository)
 - ruby, rake, whiskey\_disk (only if running post\_setup or post\_deploy hooks)

If you're running on OS X or Linux you probably have all of these installed already.  Note that the deployment target system doesn't even have to have ruby installed unless post\_* rake hooks are being run.

### Installation ###

As a gem:

    % gem install whiskey_disk

As a rails plugin:

    % script/plugin install git://github.com/flogic/whiskey_disk.git

### Configuration ###

 - look in the examples/ directory for sample configuration files
 - main configuration is in &lt;app_root&gt;/config/deploy.yml
 - config files are YAML, with a section for each target.

Known config file settings (if you're familiar with capistrano and vlad these should seem eerily familiar):

    domain:              host or list of hosts on which to deploy (these are ssh connect strings)
                         can also optionally include role information for each host
    deploy_to:           path to which to deploy main application
    repository:          git repo path for main application
    branch:              git branch to deploy from main application git repo (default: master)
    deploy_config_to:    where to deploy the configuration repository
    config_repository:   git repository for configuration files
    config_branch:       git branch to deploy from configuration git repo (default: master)
    config_target:       configuration repository target path to use
    project:             project name (used to compute path in configuration checkout)
    post_deploy_script:  path to a shell script to run after deployment
    post_setup_script:   path to a shell script to run after setup
    rake_env:            hash of environment variables to set when running post_setup and post_deploy rake tasks


A simple config/deploy.yml might look like:

    qa:
      domain: "ogc@qa.ogtastic.com"
      deploy_to: "/var/www/www.ogtastic.com"
      repository: "git@ogtastic.com:www.ogtastic.com.git"
      branch: "stable"
      rake_env:
        RAILS_ENV: 'production'

 - defining a deploy:&lt;target&gt;:post_setup rake task (e.g., in lib/tasks/
   or in your project's Rakefile) will cause that task to be run at the end
of deploy:setup

 - defining a deploy:&lt;target&gt;:post_deploy rake task (e.g., in
   lib/tasks/ or in your project's Rakefile) will cause that task to be run
at the end of deploy:now

It's easy to specify a local deployment.  The simplest way is to just not specify a "domain":

    local:
      deploy_to: "/var/www/www.ogtastic.com"
      repository: "git@ogtastic.com:www.ogtastic.com.git"
      branch: "stable"
      rake_env:
        RAILS_ENV: 'production'


Or, just specify the string 'local' as the domain:

    local:
      domain: "local"
      deploy_to: "/var/www/www.ogtastic.com"
      repository: "git@ogtastic.com:www.ogtastic.com.git"
      branch: "stable"
      rake_env:
        RAILS_ENV: 'production'


For deploying to multiple hosts, the config/deploy.yml might look like:

    qa:
      domain:
      - "ogc@qa1.ogtastic.com"
      - "ogc@qa2.ogtastic.com""
      deploy_to: "/var/www/www.ogtastic.com"
      repository: "git@ogtastic.com:www.ogtastic.com.git"
      branch: "stable"
      rake_env:
        RAILS_ENV: 'production'


You can even include a local deployment along with remote deployments, simply use the 'local' name:

    qa:
      domain:
      - "local"
      - "ogc@qa2.ogtastic.com""
      deploy_to: "/var/www/www.ogtastic.com"
      repository: "git@ogtastic.com:www.ogtastic.com.git"
      branch: "stable"
      rake_env:
        RAILS_ENV: 'production'


If you need special flags passed to ssh for a given domain, specify an array of `ssh_options` flags:

    qa:
      domain:
      - name: "ogc@qa.ogtastic.com"
        ssh_options:
        - "-t"
        - "-vv"
        - "-p 443"
      deploy_to: "/var/www/www.ogtastic.com"
      repository: "git@ogtastic.com:www.ogtastic.com.git"

### Specifying domains, with or without roles ###

There are a number of ways to specify domains (the ssh connection strings denoting the hosts
where your code will be deployed).  Here are just a few examples:

Just a single domain:

    staging:
      domain: "foo@staging.example.com"

Just a single domain, but specified as a one-item list:

    qa:
      domain:
      - "foo@qa.example.com"

A list of multiple domains:

    production:
      domain:
      - "foo@appserver1.example.com"
      - "foo@appserver2.example.com"
      - "foo@www.example.com"

Using the "name" label for the domain names (if using roles, as described below, the "name" label is required,
otherwise it's optional and superfluous):

    ci:
      domain:
      - name: "build@ci.example.com"

It's also possible to assign various "roles" to the domains to which you deploy.  Some common usages would be
"www", which might need a post\_deploy task which notifies some web server software (apache, nginx, passenger,
unicorn, etc.) that it should refresh the contents being served; or perhaps "db", which might need some set of
post-deployment database migrations run (and which shouldn't be run from multiple servers).

The role names are simply strings and you can create whichever roles you wish.  See the section below entitled
"Taking actions based on roles" to see how to use roles to control actions when setting up or deploying to a
target.

Roles are described in the domain: section of the configuration file.  There are, of course, a few different
valid ways to specify roles.  Note that the domain name must now be labeled when roles are being specified
for the domain.

A single role for a domain can be specified inline:

    production:
      domain:
      - name: "foo@appserver1.example.com"
        roles: "web"

While multiple roles for a domain must be specified as a list:

    production:
      domain:
      - name: "foo@appserver1.example.com"
        roles:
        - "web"
        - "app"
        - "db"

But domains with roles can be specified alongside simple domains as well:

    production:
      domain:
      - name: "bar@demo.example.com"
      - "user@otherhost.domain.com"
      - name: "foo@appserver1.example.com"
        roles:
        - "web"
        - "app"
        - "db"


And, if you need to assign roles for a local deployment, you can do that as well:

    local:
      domain:
      - name: "local"
        roles:
        - "web"
        - "app"
        - "db"


All that said, it's often simpler to refrain from carving up hosts into roles.  But who's going to listen to reason?



### post\_deploy\_script and post\_setup\_script ###

Whiskey\_disk provides rake task hooks (deploy:post\_setup and deploy:post\_deploy) to allow running custom
code after setup or deployment.  There are situations where it is desirable to run some commands prior to
running those rake tasks (e.g., if using bundler and needing to do a 'bundle install' before running rake).
It may also be the case that the target system doesn't have rake (and/or ruby) installed, but some post-setup
or post-deploy operations need to happen.  For these reasons, whiskey\_disk allows specifying a (bash-compatible)
shell script to run after setup and/or deployment via the post\_deploy\_script and post\_setup\_script settings
in the configuration file.  These scripts, when specified, are run immediately before running the deploy:post\_setup
or deploy:post\_deploy rake tasks, if they are present.

The paths provided to post\_deploy\_script and post\_setup\_script can be either absolute or relative.  A path
starting with a '/' is an absolute path, and the script specified should be at that exact location on the
target filesystem.  A path which does not start with a '/' is a relative path, and the script specified should
be located at the specified path under the deployed application path.  This implies that it's possible to
manage post\_setup and post\_deploy scripts out of a configuration repository.

A config/deploy.yml using post\_deploy\_script and post\_setup\_script might look like this:

    production:
      domain: "ogc@www.ogtastic.com"
      deploy_to: "/var/www/www.ogtastic.com"
      repository: "git@ogtastic.com:www.ogtastic.com.git"
      branch: "stable"
      post_setup_script: "/home/ogc/horrible_place_for_this/prod-setup.sh"
      post_deploy_script: "bin/post-deploy.sh"
      rake_env:
        RAILS_ENV: 'production'

The post\_deploy\_script will be run from /var/www/www.ogtastic.com/bin/post-deploy.sh on the
target system.


### Taking actions based on roles ###

#### When running rake tasks or other ruby scripts ####

Whiskey\_disk includes a helper library for use in rake tasks and other ruby scripts.  In that library you'll
find a ruby function 'role?' which returns true if you're currently being deployed to a domain with the given
role.  For example:

    require 'whiskey_disk/helpers'

    namespace :deploy do
      task :create_rails_directories do
        if role? :www
          puts "creating log/ and tmp/ directories"
          Dir.chdir(RAILS_ROOT)
          system("mkdir -p log tmp")
        end
      end

      task :db_migrate_if_necessary do
        Rake::Task['db:migrate'] if role? :db
      end

      # whytf is this even necessary?  Come on.  This should be built into ts:restart.
      task :thinking_sphinx_restart => [:environment] do
        if role? :app
          Rake::Task['ts:stop'].invoke rescue nil
          Rake::Task['ts:index'].invoke
          Rake::Task['ts:start'].invoke
        end
      end

      task :bounce_passenger do
        if role? :www
          puts "restarting Passenger web server"
          Dir.chdir(RAILS_ROOT)
          system("touch tmp/restart.txt")
        end
      end

      # etc...

      task :post_setup  => [ :create_rails_directories ]
      task :post_deploy => [ :db_migrate_if_necessary, :thinking_sphinx_restart, :bounce_passenger ]
    end


#### When working with the shell ####

Installing the whiskey\_disk gem also installs another binary, called wd_role.  It's job is really simple,
given a role, determine if we're currently in a deployment that matches that role.  If so, exit with a success
exit status, otherwise, exit with an error exit status.  This allows programs running in the shell to conditionally
execute code based on domain roles.  This is particularly applicable to post\_setup\_script and post\_deploy\_script
code.

Here's an off-the-cuff example of how one might use wd\_role.  We have the rockhands gem installed (obviously), and
are in an environment where the 'app' role is active but the 'web' role is not:


    $ wd_role web && rock || shocker
         .-.
       .-.U|
       |U| | .-.
       | | |_|U|
       | | | | |
      /|     ` |
     | |       |
     |         |
      \        /
      |       |
      |       |

    $ wd_role app && rock || shocker
       .-.
       |U|
       | |   .-.
       | |-._|U|
       | | | | |
      /|     ` |
     | |       |
     |         |
              /
      |       |
      |       |




### Running whiskey\_disk from the command-line ###

    % wd setup --to=<target>
    % wd setup --to=<project>:<target>
    % wd setup --to=foo:qa --path=/etc/whiskey_disk/deploy.yml
    % wd setup --to=foo:qa --path=https://github.com/username/project/raw/master/path/to/configs/deploy.yml
    % wd setup --to=foo:qa --only=myhost.example.com

    % wd deploy --to=<target>
    % wd deploy --to=<project>:<target>
    % wd deploy --to=foo:qa --path=/etc/whiskey_disk/deploy.yml
    % wd deploy --to=foo:qa --path=https://github.com/username/project/raw/master/path/to/configs/deploy.yml
    % wd deploy --to=foo:qa --only=myhost.example.com

    % wd --help
    % wd --version



Also, `--debug` can be used to enable verbose output when running `wd setup` or `wd deploy`.

Note that the wd command (unlike rake, which requires a Rakefile in the current directory) can be run from anywhere, so you can deploy any project, working from any path, and can even specify where to find the deployment YAML configuration file.

The --path argument can take either a file or a directory.  When given a file it will use that file as the configuration file.  When given a directory it will look in that directory for deploy/&lt;project&gt;/&lt;target&gt;.yml, then deploy/&lt;project&gt;.yml, then deploy/&lt;target&gt;.yml, then &lt;target&gt;.yml, and finally, deploy.yml.

To make things even better, you can provide an URL as the --path argument and have a central location from which to pull deployment YAML data.  This means that you can centrally administer the definitive deployment information for the various projects and targets you manage.  This could be as simple as keeping them in a text file hosted on a web server, checking them into git and using github or gitweb to serve up the file contents on HEAD, or it could be a programmatically managed configuration management system returning dynamically-generated results.

All this means you can manage a large number of project deployments (local or remote) and have a single scripted deployment manager that keeps them up to date.  Configurations can live in a centralized location, and developers don't have to be actively involved in ensuring code gets shipped up to a server.  Win.

When doing scripted deployments for a group of nodes who appear in the same 'domain' list, it's possible to specify the --only setting so that you can identify which domain entries belong to a specific node.  For example, given this configuration:


    production:
      domain:
      - foo.example.com
      - bar.example.com
      repository: git@github.com:foo.git


We would like to be able to set up the following scripted runs on foo.example.com and bar.example.com:


    foo% wd deploy --to=app:production --path=http://automation.example.com/wd/deploy.yml
    bar% wd deploy --to=app:production --path=http://automation.example.com/wd/deploy.yml


But without specifying --only we end up with undesired results.  When foo.example.com runs it will see that it needs to make sure deployment happens on 'foo.example.com' and 'bar.example.com'.  So, wd will ssh from foo.example.com to foo.example.com (less than ideal), deploy, and then ... it will ssh from foo.example.com to bar.example.com and do a deployment.  When bar.example.com runs, however, it will also ssh to bar.example.com, and also to foo.example.com.  So each host will be deployed twice.

The --only setting is used to tell a node what its name is, and to tell it not to bother trying to deploy other nodes that it finds in the target's "domain" listing.  In other words, deployment is being managed from afar, and it's best to just manage ourselves and forego managing other nodes.


### A note about post\_{setup,deploy} Rake tasks

If you want actions to run on the deployment target after you do a whiskey\_disk setup or whiskey\_disk deploy,
you will need to make sure that whiskey\_disk is available on the target system (either by gem installation,
as a rails plugin in the Rails application to be deployed, or as a vendored library in the application to be
deployed).  Whiskey\_disk provides the basic deploy:post\_setup and deploy:post\_deploy hooks which get called.
You can also define these tasks yourself if you want to eliminate the dependency on whiskey\_disk on the
deployment target system.


### Doing things when files of interest change ###

Do you want to run database migrations when no migrations have been added?  Why bother compressing front-end assets when none of them have changed?  Why restart your application server if only the project README changed?  Whiskey\_disk provides a `changed?` ruby helper method to allow you to decide whether to run expensive post deployment tasks, based on what files changed in the deployment.  Typically this would happen in your rake tasks, but it could happen from regular ruby code as well.


    require 'whiskey_disk/helpers'

    namespace :deploy do

      task :run_migrations do
        if role?(:db) and changed?('db/migrate')
          puts "Running database migrations..."
          Rake::Task['db:migrate'].invoke
        end
      end

      task :compress_assets do
        if changed?('public/stylesheets') or changed?('public/javascripts')
          puts "Getting my asset munge on..."
          # do some expensive asset compression stuff
        end
      end

      task :post_deploy => [ :run_migrations, :compress_assets ]
    end



### Running via rake ###

You can use rake tasks to do everything possible with whiskey\_disk (the `wd` command is just a front-end to the whiskey\_disk rake tasks).  In your Rakefile:

    require 'whiskey_disk/rake'

  Then, from the command-line:

    % rake deploy:setup to=<target>   (e.g., "qa", "staging", "production", etc.)
    % rake deploy:now   to=<target>

  or, specifying the project name:

    % rake deploy:setup to=<project>:<target>   (e.g., "foo:qa", "bar:production", etc.)
    % rake deploy:now   to=<project>:<target>

  enabling staleness checking (see below):

    % rake deploy:setup to=<project>:<target> check=yes
    % rake deploy:now   to=<project>:<target> check=yes

  maybe even specifying the path to the configuration file:

    % rake deploy:setup to=<project>:<target> path=/etc/deploy.yml
    % rake deploy:now   to=<project>:<target> path=/etc/deploy.yml

  how about specifying the configuration file via URL:

    % rake deploy:setup to=<project>:<target> path=https://github.com/username/project/raw/master/path/to/configs/deploy.yml
    % rake deploy:now   to=<project>:<target> path=https://github.com/username/project/raw/master/path/to/configs/deploy.yml

  Finally, it's also possible to specify the 'only' variable to limit 'domain' entries of interest:

    % rake deploy:setup to=<project>:<target> only=myhost.example.com
    % rake deploy:now to=<project>:<target> only=myhost.example.com

  (see the discussion of --only above in "Running whiskey\_disk from the command-line" for more information)


### Staleness checks ###

Enabling staleness checking will cause whiskey\_disk to check whether the deployed checkout of the repository
is out of date ("stale") with respect to the upstream version in git.  If there is a configuration repository
in use, whiskey\_disk will check the deployed checkout of the configuration repository for staleness as well.
If the checkouts are already up-to-date the deployment process will print an up-to-date message and stop rather
than proceeding with any of the deployment actions.  This makes it easy to simply run whiskey\_disk out of cron
so that it will automatically perform a deployment whenever changes are pushed to the upstream git repositories.

To turn on staleness checking, simply specify the '--check' flag when deploying (or the shorter '-c')

    wd deploy --check --to=foobar:production

If running whiskey\_disk purely via rake, you can also enable staleness checking.  This works by setting the 'check'
environment variable to the string 'true' or 'yes':

    % check='true' to='whiskey_disk:testing' rake deploy:now


### Configuration Repository ###

#### What's all this about a second repository for configuration stuff? ####

This is completely optional, but we really are digging this, so maybe
you should try it.  Basically it goes like this...

We have a number of web applications that we manage.  Usually there's a
customer, there might be third-party developers, or the customer might have
access to the git repo, or their designer might, etc.  We also tend to run a
few instances of any given app, for any given customer.  So, we'll run a
"production" site, which is the public- facing, world-accessible main site.
We'll usually also run a "staging" site, which is roughly the same code, maybe
the same data, running on a different URL, which the customer can look at to
see if the functionality there is suitable for deploying out to production.  We
sometimes run a "development" site which is even less likely to be the same
code as production, etc., but gives visibility into what might end up in
production one day soon.

So we'll store the code for all of these versions of a site in the same git
repo, typically using a different remote branch for each target
("qa", "production", "staging", "development").

One thing that comes up pretty quickly is that there are various files
associated with the application which have more to do with configuration of a
running instance than they have to do with the application in general.  In the
rails world these files are probably in config, or config/initializers/.  Think
database connection information, search engine settings, exception notification
plugin data, email configuration, Amazon S3 credentials, e-commerce back-end
configuration, etc.

We don't want the production site using the same database as the
development site.  We don't want staging using (and re-indexing, re-starting,
etc.) production's search engine server.  We don't want any site other than
production to send account reset emails, or to push orders out to fulfillment,
etc.

For some reason, the answer to this with cap and/or vlad has been to have
recipes which reference various files up in a shared area on the server, do
copying or symlinking, etc.  Where did those files come from?  How did they get
there?  How are they managed over time?  If they got there via a configuration
tool, why (a) are they not in the right place, or (b) do we have to do work to
get them into the right place?

So, we decided that we'd change how we deal with the issue.  Instead of
moving files around or symlinking every time we deploy, we will manage the
configuration data just like we manage other files required by our projects --
with git.

So, each project we deploy is associated with a config repo in our git
repository.  Usually many projects are in the same repo, because we're the only
people to see the data and there's no confidentiality issue.  But, if a
customer has access to their git information then we'll make a separate config
repo for all that customers' projects.  (This is easier to manage than it
sounds if you're using gitosis, btw.)

Anyway, a config repo is just a git repo.  In it are directories for every
project whose configuration information is managed in that repo.  For example,
there's a "larry" directory in our main config repo, because we're deploying
the [larry project](http://github.com/flogic/larry) to manage our high-level
configuration data.

Note, if you set the 'project' setting in deploy.yml, that determines the
name of the top-level project directory whiskey\_disk will hunt for in your
config repo.  If you don't it uses the 'repository' setting (i.e., the git URL)
to try to guess what the project name might be.  So if the URL ends in
foo/bar.git, or foo:bar.git, or /bar, or :bar, whiskey\_disk is going to guess
"bar".  If it's all bitched up, just set 'project' manually in deploy.yml.

Inside the project directory is a directory named for each target we
might deploy to.  Frankly, we've been using "production", "staging",
"development", and "local" on just about everything.

Inside the target directory is a tree of files.  So, e.g., there's
config/, which has initializers/ and database.yml in it.

Long story short, load up whatever configuration files you're using into
the repo as described, and come deployment time exactly those files will be
overlaid on top of the most recent checkout of the project.  Snap.

    project-config/
      |
      +---larry/
            |
            +---production/
            |     |
            |     +---config/
            |           |
            |           +---initializers/
            |           |
            |           +---database.yml
            |
            +---staging/
            |     |
            |     |
            |     +---config/
            |           |
            |           ....
            |
            +---development/
            |     |
            |     +---config/
            |           |
            |           ....
            |
            +---local/
                  |
                  +---config/
                        |
                        ....


#### Sharing a set of configuration files among multiple targets ####

Developers on applications with many deployment targets can find that configuration repositories can become a burden to maintain, especially when a number of environments share essentially the same configurations.  For example, for an application where deployments for user acceptance testing, QA, staging, and feature branch demoing are all essentially the same (though differing from production configurations and developer configurations), it's probably easiest to store a configuration for development, a configuration for production, a configuration for staging and then use the staging configuration for all the other environments: user acceptance testing, QA, staging, demo1, demo2, etc.  Using the config\_target setting, a deploy.yml might look like this:


    production:
      domain: "www.ogtastic.com"
      deploy_to: "/var/www/www.ogtastic.com"
      repository: "git@ogtastic.com:www.ogtastic.com.git"
      branch: "production"
      config_repository: "git@ogtastic.com:ogc-production-config.git"
    development:
      deploy_to: '/var/www/devel.ogtastic.com'
      repository: "git@ogtastic.com:www.ogtastic.com.git"
      branch: "develop"
      config_repository: "git@ogtastic.com:ogc-config.git"
    staging:
      [...]
      config_repository: "git@ogtastic.com:ogc-config.git"
    uat:
      [....]
      config_repository: "git@ogtastic.com:ogc-config.git"
      config_target: "staging"
    qa:
      [....]
      config_repository: "git@ogtastic.com:ogc-config.git"
      config_target: "staging"


So here we have the 'staging', 'uat', and 'qa' deployment targets all sharing the 'staging' configuration repo information.  The non-production configuration repo can then look like:


    project-config/
      |
      +---ogtastic/
            |
            +---staging/
            |     |
            |     |
            |     +---config/
            |           |
            |           ....
            |
            +---development/
                  |
                  +---config/
                        |
                        ....


Notice that there are no separate trees for 'uat' and 'qa' targets.

### More Examples: ###

 - We are using whiskey\_disk to manage larry.  See [https://github.com/flogic/larry/blob/master/config/deploy-local.yml.example](https://github.com/flogic/larry/blob/master/config/deploy-local.yml.example) and [http://github.com/flogic/larry/blob/master/lib/tasks/deploy.rake](http://github.com/flogic/larry/blob/master/lib/tasks/deploy.rake)

 - Here is a sample of a lib/tasks/deploy.rake from a Rails application we deployed once upon a time:



        RAILS_ENV=ENV['RAILS_ENV'] if ENV['RAILS_ENV'] and '' != ENV['RAILS_ENV']
        Rake::Task['environment'].invoke

        require 'asset_cache_sweeper'

        namespace :deploy do
          task :create_rails_directories do
            puts "creating log/ and tmp/ directories"
            Dir.chdir(RAILS_ROOT)
            system("mkdir -p log tmp")
          end

          # note that the plpgsql language needs to be installed by the db admin at initial database creation :-/
          task :setup_postgres_for_thinking_sphinx => [ :environment ] do
            ThinkingSphinx::PostgreSQLAdapter.new(Product).setup
          end

          # whytf is this even necessary?  Come on.  This should be built into ts:restart.
          task :thinking_sphinx_restart => [:environment] do
            Rake::Task['ts:stop'].invoke rescue nil
            Rake::Task['ts:index'].invoke
            Rake::Task['ts:start'].invoke
          end

          task :bounce_passenger do
            puts "restarting Passenger web server"
            Dir.chdir(RAILS_ROOT)
            system("touch tmp/restart.txt")
          end

          task :clear_asset_cache => [:environment] do
            STDERR.puts "Expiring cached Assets for domains [#{AssetCacheSweeper.domains.join(", ")}]"
            AssetCacheSweeper.expire
          end

          task :post_setup => [ :create_rails_directories, :setup_postgres_for_thinking_sphinx ]
          task :post_deploy => [ 'db:migrate', 'ts:config', :thinking_sphinx_restart, :bounce_passenger, :clear_asset_cache ]
        end

### Future Directions ###

Check out the [Pivotal Tracker project](https://www.pivotaltracker.com/projects/202125)
to see what we have in mind for the near future.

### Resources ###

 - [http://github.com/blog/470-deployment-script-spring-cleaning](http://github.com/blog/470-deployment-script-spring-cleaning)
 - [http://github.com/mislav/git-deploy](http://github.com/mislav/git-deploy)
 - [http://toroid.org/ams/git-website-howto](http://toroid.org/ams/git-website-howto)

### Support ###

The [bug tracker](https://github.com/flogic/whiskey_disk/issues)
is available here:

  -  [https://github.com/flogic/whiskey_disk/issues](https://github.com/flogic/whiskey_disk/issues)

The IRC channel is #whiskey_disk on freenode.

### Contributors ###

 - [Rick Bradley](https://github.com/rick): author
 - [James Cox](https://github.com/imajes): bugfixes, prototyping, design help, code, feedback
 - [Rein Henrichs](https://github.com/reinh): design help, code
 - [Jeremy Holland](https://github.com/awebneck): code
 - [Kevin Barnes](https://github.com/vinbarnes): design help, code
 - [Alex Sharp](https://github.com/ajsharp): issues, real-world usage cases, design help
 - [Yossef Mendelssohn](https://github.com/ymendel): design help, proofreading
 - [Aaron Kalin](https://github.com/martinisoft) - bug hunting
 - [Brandon Valentine](https://github.com/brandonvalentine) - help with bug fixing
 - [Josh Moore](https://github.com/joshsmoore): bug hunting

 - Documentation/feedback: [Cristi Balan](https://github.com/evilchelu), [Hedgehog](http://github.com/hedgehog)


================================================
FILE: Rakefile
================================================
require 'rake'
require 'rake/testtask'

desc 'Default: run unit tests.'
task :default => :test

desc 'Test whiskey_disk'
task :test do
  files = Dir['spec/**/*_spec.rb'].join(" ")
  system("bacon #{files}")
end

namespace :integration do
  def say(mesg)
    STDERR.puts mesg
  end

  def vagrant_path
    File.expand_path(File.join(File.dirname(__FILE__), 'scenarios', 'setup', 'vagrant'))
  end

  def root_path
    File.expand_path(File.dirname(__FILE__))
  end

  def pidfile
    File.join(vagrant_path, 'pids', 'git-daemon.pid')
  end

  def start_git_daemon
    stop_git_daemon
    say "Starting git daemon..."
    run(root_path, "git daemon --base-path=#{root_path}/scenarios/git_repositories/ --reuseaddr --verbose --detach --pid-file=#{pidfile}")
  end

  def stop_git_daemon
    return unless File.exists?(pidfile)
    pid = File.read(pidfile).chomp
    return if pid == ''
    say "Stopping git daemon..."
    run(root_path, "kill #{pid}")
  end

  def start_vm
    say "Bringing up vagrant vm..."
    run(vagrant_path, 'vagrant up')
    copy_ssh_config
  end

  def stop_vm
    say "Shutting down vagrant vm..."
    run(vagrant_path, 'vagrant halt')
  end

  def copy_ssh_config
    say "Capturing vagrant ssh_config data..."
    run(vagrant_path, "vagrant ssh_config > #{vagrant_path}/ssh_config")
  end

  def run(path, cmd)
    Dir.chdir(path)
    say "running: #{cmd} [cwd: #{Dir.pwd}]"
    system(cmd)
  end

  desc 'Start a vagrant VM and git-daemon server to support running integration specs'
  task :up do
    start_vm
    start_git_daemon
  end

  desc 'Shut down integration vagrant VM and git-daemon server'
  task :down do
    stop_git_daemon
    stop_vm
  end

  desc 'Completely remove the vagrant VM files used by the integration spec suite'
  task :destroy do
    stop_git_daemon
    stop_vm
    run(vagrant_path, 'vagrant destroy')
  end
end

begin
  require 'jeweler'
  Jeweler::Tasks.new do |gemspec|
    gemspec.name = "whiskey_disk"
    gemspec.summary = "embarrassingly fast deployments."
    gemspec.description = "Opinionated gem for doing fast git-based server deployments."
    gemspec.email = "rick@rickbradley.com"
    gemspec.homepage = "http://github.com/flogic/whiskey_disk"
    gemspec.authors = ["Rick Bradley"]
    gemspec.add_dependency('rake')

    # I've decided that the integration spec shizzle shouldn't go into the gem
    rejected = %w(scenarios spec/integration)
    gemspec.files.reject {|f| rejected.include?(f) }
    gemspec.test_files.reject {|f| rejected.include?(f) }
  end
  Jeweler::GemcutterTasks.new
rescue LoadError
  # if you get here, you need Jeweler installed to do packaging and gem installation, yo.
end



================================================
FILE: VERSION
================================================
0.6.24


================================================
FILE: WHY.txt
================================================

Why?
----

The idea here is inspired by github's cleaned up deployment scripts, and mislav's git-deploy project.  Only, we gave up on capistrano a long time ago, and after a few years of doing deployments on a few dozen projects, we realized that we really have very little variation on how we do things.  That is, we can afford to have a very opinionated tool to do our deployments.

Here are the features/constraints we're envisioning:

 - We need some sort of very basic "run this on a remote server" functionality.  We've been using vlad for years now and this would suffice:  it does what we're looking for and is much much smaller than capistrano.  If we don't load the included recipes it's basically a fancy ruby ssh wrapper.
 
 - Setup should mostly just do a very fast remote git checkout in the right place.  Deployment should very quickly update that checkout.
 
 - We have been considering a move towards tracking configuration data across our projects as a separate concern.  So, if we can have a private repo that stores per-project and per-environment (here I mean staging vs. production, etc.) configuration files, and have our deployments overlay those files quickly, that would be ideal.  I'm talking about hoptoad configs, database.yml files, AWS cert files, GeoKit API keys, etc., etc., etc.

 - We should be able to use the same "setup == clone" + "deploy == reset" technique to manage the per-project/per-environment config files.
 
 - Using rsync on the remote to those overlay config files on the deployed project would be a fast way to get them in place.
 
 - Get rid of a bunch of annoying symlinks and symlink-hoops-to-jump-through.
 
 - Get rid of a bunch of space (yeah yeah disk is cheap, but copying isn't) on the disk devoted to umpteen "releases".
 
 - Obviously reduce deployment time by doing less, ssh-ing less, and taking less time to do whatever.
 
 - should be rake based, and should provide a bare minimum of tasks -- like deploy:setup, deploy:now, and maybe a deploy:refresh_config_files.
 
 - While a very basic task or few would run after setup or after deployment (e.g., rake db:migrate if migrations were changed, or touch tmp/restart.txt if the web server needs a restart; see git-deploy for more examples), we should be able to declare optional rake tasks (e.g., "deploy:staging:post_deploy") and have them run on this project if they are declared.
 
 - Should work with projects that aren't remotely ruby.
 
 - Should be loadable as a gem, meaning that it doesn't need to live in your project's space.  (see also non-ruby projects)
 
 - Should be able to use a non-ruby config, preferably yaml, for information for all environments.  That could be stored in <project>/config/deploy.yml and saved with the project.  Even if this is just shoved into vlad 'set' commands, it's still an improvement:  we don't need ruby in the config file because we're opinionated.
 
 - should be able to override settings for an environment locally by declaring a <project>/config/deploy-<environment>.yml.  Ideal for testing out deployments to different servers (or deploying locally).  This also makes it possible to .gitignore your local settings, so everyone can have their config repos in different places.
 
 - should make it easier to do local development (e.g., on a laptop) by being able to overlay config files using the same rake tasks as used for remote deployments, just not running the functionality remotely.
 
 - dropping in a project Rakefile can add post-deploy / post-setup hooks transparently.
 
 - actually have meaningful error messages, unlike anything that ever seems to happen with cap or vlad.  :-/

 - build this spec-first (whenever possible) so that there's a useful test suite.
 
 - M$ windows hasn't been a priority for me for over a decade, not starting now.


================================================
FILE: bin/wd
================================================
#!/usr/bin/env ruby 

require 'optparse'
require 'whiskey_disk/rake'

$0 = "#{$0} setup|deploy"  # jesus, this is a hack.

options = {}
op = OptionParser.new do |opts|
  opts.on('-t=TARGET', '--to=TARGET', "deployment target") do |target| 
    options[:target] = target
  end
  
  opts.on('-p=TARGET', '--path=TARGET', "configuration path") do |path|
    options[:path] = path
  end
    
  opts.on('-o=DOMAIN', '--only=DOMAIN', "limit deployment to this domain") do |domain|
    options[:only] = domain
  end
    
  opts.on('-c', '--check', "do a staleness check before deploying") do |path|
    options[:check] = 'true'
  end

  opts.on('-d', '--debug', "turn on debug mode (ssh -v and rake --trace)") do
    options[:debug] = 'true'
  end
    
  opts.on('--version', 'show current version') do
    puts File.read(File.expand_path(File.join(File.dirname(__FILE__), '..', 'VERSION')))
    exit 0
  end
  
  opts.on_tail('-h', '--help', 'show this message') do
    abort opts.to_s
  end
end

begin
  rest = op.parse(ARGV) 
rescue 
  abort op.to_s 
end

abort op.to_s unless options[:target]
abort op.to_s unless rest and rest.size == 1
command = rest.first
abort op.to_s unless ['deploy', 'setup'].include?(command)

ENV['to'] = options[:target]
ENV['path'] = options[:path]
ENV['only'] = options[:only]
ENV['check'] = options[:check]
ENV['debug'] = options[:debug]

if command == 'deploy'
  Rake::Task['deploy:now'].invoke
else
  Rake::Task['deploy:setup'].invoke
end


================================================
FILE: bin/wd_role
================================================
#!/usr/bin/env ruby 
require 'whiskey_disk/helpers'

# simple command-line script to detect whether this deployment target
# is in a specified whiskey_disk role.  sets exit status appropriately
#
# useful for conditionalizing shell scripting based on roles.

role = ARGV.shift
exit(1) unless role?(role)

__END__

( this example session presumes you `gem install rockhands` first... )

$ export WD_ROLES='app:db'
$ wd_role web && rock || shocker
     .-.     
   .-.U|     
   |U| | .-. 
   | | |_|U| 
   | | | | | 
  /|     ` |
 | |       | 
 |         | 
  \        / 
  |       |  
  |       |  
             
$ wd_role app && rock || shocker
   .-.       
   |U|       
   | |   .-. 
   | |-._|U| 
   | | | | | 
  /|     ` | 
 | |       | 
 |         | 
          / 
  |       |  
  |       |  



================================================
FILE: examples/deploy-configs.yml
================================================
production:
  domain: "ogc@hoenir.websages.com"
  deploy_to: "/tmp/test-deployment"
  deploy_config_to: "/tmp/test-config"
  repository: "git@git.ogtastic.com:whiskey_disk.git"
  config_repository: "git@git.ogtastic.com:ogc-config.git"
staging:
  domain: "ogc@hoenir.websages.com"
  deploy_to: "/tmp/test-deployment"
  deploy_config_to: "/tmp/test-config"
  repository: "git@git.ogtastic.com:whiskey_disk.git"
  config_repository: "git@git.ogtastic.com:ogc-config.git"
  config_target: "local"


================================================
FILE: examples/deploy-local.yml
================================================
local:
  deploy_to: "/Users/rick/deploy/whiskey_disk/local"
  repository: "/Users/rick/git/whiskey_disk"
  branch: "develop"


================================================
FILE: examples/deploy-multiple-remotes.yml
================================================
multi:
  domain:
  - "ogc@hoenir.websages.com"
  - "ogc@nerthus.websages.com"
  deploy_to: "/tmp/test-deployment/"
  repository: "git@git.ogtastic.com:whiskey_disk.git"
  branch: "develop"
roles:
  domain:
  - name: "ogc@hoenir.websages.com"
    roles:
    - web
    - app
  - name: "ogc@nerthus.websages.com"
    roles: db 
  deploy_to: "/tmp/test-deployment/"
  repository: "git@git.ogtastic.com:whiskey_disk.git"
  branch: "feature/support-domain-roles"
  post_deploy_script: "/tmp/role-checker.sh"
badmulti:
  domain:
  - "ogc@hoenir.websages.com"
  - "ogc@bogus.example.com"
  deploy_to: "/tmp/test-deployment/"
  repository: "git@git.ogtastic.com:whiskey_disk.git"
  branch: "develop"


================================================
FILE: examples/deploy-staging.yml
================================================
staging:
  domain: "user@www.example.com"
  deploy_to: "/var/www/suparsite.com/"
  repository: "git://github.com/clarkkent/suparsite.git"
  config_repository: "git@github.com:clarkkent/suparconfig.git"
  deploy_config_to: "/var/cache/git/suparconfig"
  rake_env:
    RAILS_ENV: 'development'


================================================
FILE: examples/deploy.rake
================================================
namespace :deploy do
  namespace :staging do
    task :post_setup do
      puts "This is my local post_setup hook."
    end

    task :post_deploy do
      puts "This is my local post_deploy hook."
    end
  end
end


================================================
FILE: examples/deploy.yml
================================================
staging:
  domain: "user@www.example.com"
  deploy_to: "/var/www/suparsite.com/"
  repository: "git://github.com/clarkkent/suparsite.git"
  config_repository: "git@github.com:clarkkent/suparconfig.git"
  deploy_config_to: "/var/cache/git/suparconfig"
  branch: "production"
  rake_env:
    RAILS_ENV: "production"
local:
  repository: "git://github.com/clarkkent/suparsite.git"
  config_repository: "git@github.com:clarkkent/suparconfig.git"
  deploy_to: "/Users/clark/git/suparsite"
  deploy_config_to: "/Users/clark/git/suparconfig"
  rake_env:
    RAILS_ENV: "production"


================================================
FILE: init.rb
================================================
require File.expand_path(File.join(File.dirname(__FILE__), 'lib', 'whiskey_disk'))


================================================
FILE: install.rb
================================================
def readme_contents
  IO.read(File.expand_path(File.join(File.dirname(__FILE__), 'README.markdown')))
end

puts readme_contents


================================================
FILE: lib/whiskey_disk/config/abstract_filter.rb
================================================
class WhiskeyDisk
  class Config
    class AbstractFilter
      attr_reader :config
  
      def initialize(config)
        @config = config
      end
  
      def project_name
        config.project_name
      end
  
      def environment_name
        config.environment_name
      end
    end
  end
end

================================================
FILE: lib/whiskey_disk/config/filter.rb
================================================
require 'whiskey_disk/config/filters/stringify_hash_keys_filter'
require 'whiskey_disk/config/filters/environment_scope_filter'
require 'whiskey_disk/config/filters/project_scope_filter'
require 'whiskey_disk/config/filters/select_project_and_environment_filter'
require 'whiskey_disk/config/filters/add_environment_name_filter'
require 'whiskey_disk/config/filters/add_project_name_filter'
require 'whiskey_disk/config/filters/default_config_target_filter'
require 'whiskey_disk/config/filters/default_domain_filter'
require 'whiskey_disk/config/filters/hashify_domain_entries_filter'
require 'whiskey_disk/config/filters/localize_domains_filter'
require 'whiskey_disk/config/filters/check_for_duplicate_domains_filter'
require 'whiskey_disk/config/filters/convert_role_strings_to_list_filter'
require 'whiskey_disk/config/filters/drop_empty_domain_roles_filter'
require 'whiskey_disk/config/filters/normalize_ssh_options_filter'

class WhiskeyDisk
  class Config
    class Filter
      attr_reader :config, :filters
  
      def initialize(config)
        @config = config
        @filters = [
          StringifyHashKeysFilter,
          EnvironmentScopeFilter,
          ProjectScopeFilter,
          SelectProjectAndEnvironmentFilter,
          AddEnvironmentNameFilter,
          AddProjectNameFilter,
          DefaultConfigTargetFilter,
          DefaultDomainFilter,
          HashifyDomainEntriesFilter,
          LocalizeDomainsFilter,
          CheckForDuplicateDomainsFilter,
          ConvertRoleStringsToListFilter,
          DropEmptyDomainRolesFilter,
          NormalizeSshOptionsFilter
        ]
      end
  
      def filter_data(data)
        filters.inject(data.clone) do |result, filter|
          result = filter.new(config).filter(result)
        end
      end
    end
  end
end


================================================
FILE: lib/whiskey_disk/config/filters/add_environment_name_filter.rb
================================================
require 'whiskey_disk/config/abstract_filter'

class WhiskeyDisk
  class Config
    class AddEnvironmentNameFilter < AbstractFilter
      def filter(data)
        data.merge( { 'environment' => environment_name } )
      end
    end
  end
end


================================================
FILE: lib/whiskey_disk/config/filters/add_project_name_filter.rb
================================================
require 'whiskey_disk/config/abstract_filter'

class WhiskeyDisk
  class Config
    class AddProjectNameFilter < AbstractFilter
      def filter(data)
        data.merge( { 'project' => project_name } )
      end
    end
  end
end


================================================
FILE: lib/whiskey_disk/config/filters/check_for_duplicate_domains_filter.rb
================================================
require 'whiskey_disk/config/abstract_filter'

class WhiskeyDisk
  class Config
    class CheckForDuplicateDomainsFilter < AbstractFilter
      def check_domains(domain_list)
        seen = {}
        domain_list.each do |domain|
          raise "duplicate domain [#{domain['name']}] in configuration file for project [#{environment_name}], target [#{environment_name}]" if seen[domain['name']]
          seen[domain['name']] = true
        end
      end
      
      def filter(data)
        check_domains(data['domain'])
        data
      end
    end
  end
end



================================================
FILE: lib/whiskey_disk/config/filters/convert_role_strings_to_list_filter.rb
================================================
require 'whiskey_disk/config/abstract_filter'

class WhiskeyDisk
  class Config
    class ConvertRoleStringsToListFilter < AbstractFilter
      def convert_roles_for_domain(domain)
        return domain unless domain['roles']
        domain.merge('roles' => [ domain['roles'] ].flatten)
      end
      
      def convert_all_roles(domains_list)
        domains_list.collect {|domain| convert_roles_for_domain(domain) }
      end
      
      def filter(data)
        data.merge('domain' => convert_all_roles(data['domain']))
      end
    end
  end
end


================================================
FILE: lib/whiskey_disk/config/filters/default_config_target_filter.rb
================================================
require 'whiskey_disk/config/abstract_filter'

class WhiskeyDisk
  class Config
    class DefaultConfigTargetFilter < AbstractFilter
      def filter(data)
        return data if data['config_target']
        data.merge( { 'config_target' => environment_name })
      end
    end
  end
end

================================================
FILE: lib/whiskey_disk/config/filters/default_domain_filter.rb
================================================
require 'whiskey_disk/config/abstract_filter'

class WhiskeyDisk
  class Config
    class DefaultDomainFilter < AbstractFilter
      def filter(data)
        data.has_key?('domain') ? data : data.merge('domain' => [ { 'name' => 'local' } ] )
      end
    end
  end
end



================================================
FILE: lib/whiskey_disk/config/filters/drop_empty_domain_roles_filter.rb
================================================
require 'whiskey_disk/config/abstract_filter'

class WhiskeyDisk
  class Config
    class DropEmptyDomainRolesFilter < AbstractFilter
      def has_empty_role?(domain)
        return true unless domain.has_key?('roles')
        return true if domain['roles'].nil?

        roles = domain['roles'].uniq.compact
        return true if roles == [ '' ]
        return true if roles == []
        
        false
      end
      
      def drop_empty_roles_for_domain(domain)
        return domain unless has_empty_role?(domain)
        domain.reject {|key, value| key == 'roles' }
      end
      
      def drop_empty_domain_roles(domains_list)
        domains_list.collect { |domain| drop_empty_roles_for_domain(domain) }
      end
      
      def filter(data)
        data.merge('domain' => drop_empty_domain_roles(data['domain']))
      end
    end
  end
end



================================================
FILE: lib/whiskey_disk/config/filters/environment_scope_filter.rb
================================================
require 'whiskey_disk/config/abstract_filter'
require 'whiskey_disk/config/filters/modules/scope_helper'

class WhiskeyDisk
  class Config
    class EnvironmentScopeFilter < AbstractFilter      
      include ScopeHelper

      # is this data hash a bottom-level data hash without an environment name?
      def needs_environment_scoping?(data)
        repository_depth(data) == 0
      end
  
      def filter(data)
        return data unless needs_environment_scoping?(data)
        { environment_name => data }
      end
    end
  end
end

================================================
FILE: lib/whiskey_disk/config/filters/hashify_domain_entries_filter.rb
================================================
require 'whiskey_disk/config/abstract_filter'

class WhiskeyDisk
  class Config
    class HashifyDomainEntriesFilter < AbstractFilter
      def needs_hashing?(domain)
        ! domain.respond_to?(:keys)
      end

      def hashify_domain(domain)
        needs_hashing?(domain) ? { 'name' => domain } : domain
      end

      def new_domain
        { 'name' => '' }
      end

      def hashify_domains(domain_list)
        return new_domain unless domain_list
        [ domain_list ].flatten.collect {|domain| hashify_domain(domain) }
      end

      def filter(data)
        data.merge('domain' => hashify_domains(data['domain']))
      end
    end
  end
end



================================================
FILE: lib/whiskey_disk/config/filters/localize_domains_filter.rb
================================================
require 'whiskey_disk/config/abstract_filter'

class WhiskeyDisk
  class Config
    class LocalizeDomainsFilter < AbstractFilter
      def is_local?(name)
        name.nil? or name == ''
      end
      
      def localize(name)
        is_local?(name) ? 'local' : name
      end
      
      def localize_domains(domain_list)
        domain_list.collect {|domain| domain.merge('name' => localize(domain['name'])) }
      end

      def filter(data)
        data.merge('domain' => localize_domains(data['domain']))
      end
    end
  end
end



================================================
FILE: lib/whiskey_disk/config/filters/modules/scope_helper.rb
================================================
class WhiskeyDisk
  class Config
    module ScopeHelper
      def repository_depth(data, depth = 0)
        raise 'no repository found' unless data.respond_to?(:has_key?)
        return depth if data.has_key?('repository')
        repository_depth(data.values.first, depth + 1)
      end
    end
  end
end

================================================
FILE: lib/whiskey_disk/config/filters/normalize_ssh_options_filter.rb
================================================
require 'whiskey_disk/config/abstract_filter'

class WhiskeyDisk
  class Config
    class NormalizeSshOptionsFilter < AbstractFilter
      def drop_empties(options_list)
        options_list.select {|option| option and option != '' }
      end
      
      def drop_empty_ssh_options_for_domain(domain)
        result = drop_empties([ domain['ssh_options'] ].flatten)
        if result and result != []
          domain.merge('ssh_options' => result)
        else
          domain.reject {|k,v| k == 'ssh_options' }
        end
      end
      
      def normalize_ssh_options(domains_list)
        domains_list.collect { |domain| drop_empty_ssh_options_for_domain(domain) }
      end
      
      def filter(data)
        data.merge('domain' => normalize_ssh_options(data['domain']))
      end
    end
  end
end



================================================
FILE: lib/whiskey_disk/config/filters/project_scope_filter.rb
================================================
require 'whiskey_disk/config/abstract_filter'
require 'whiskey_disk/config/filters/modules/scope_helper'

class WhiskeyDisk
  class Config
    class ProjectScopeFilter < AbstractFilter
      include ScopeHelper

      def repository_depth(data, depth = 0)
        raise 'no repository found' unless data.respond_to?(:has_key?)
        return depth if data.has_key?('repository')
        repository_depth(data.values.first, depth + 1)
      end
  
      # is this data hash an environment data hash without a project name?
      def needs_project_scoping?(data)
        repository_depth(data) == 1
      end

      # TODO: why do we continue to need override_project_name! ?
      # TODO: this is invasive into Config's implementation
      def override_project_name!(data)
        return if ENV['to'] && ENV['to'] =~ /:/
        ENV['to'] = data[environment_name]['project'] + ':' + ENV['to'] if data[environment_name]['project']
      end

      def filter(data)
        return data unless needs_project_scoping?(data)
        override_project_name!(data)
        { project_name => data }
      end
    end
  end
end

================================================
FILE: lib/whiskey_disk/config/filters/select_project_and_environment_filter.rb
================================================
require 'whiskey_disk/config/abstract_filter'

class WhiskeyDisk
  class Config
    class SelectProjectAndEnvironmentFilter < AbstractFilter
      def filter(data)
        raise "No configuration file defined data for project `#{project_name}`, environment `#{environment_name}`" unless data and data[project_name] and data[project_name][environment_name]
        data[project_name][environment_name]
      end
    end
  end
end

================================================
FILE: lib/whiskey_disk/config/filters/stringify_hash_keys_filter.rb
================================================
require 'whiskey_disk/config/abstract_filter'

class WhiskeyDisk
  class Config
    class StringifyHashKeysFilter < AbstractFilter
      def stringify_hash(data)
        result = {}
        data.each_pair do |key, value|
          result[key.to_s] = stringify(value)
        end
        result
      end

      def stringify(structure)
        return structure.clone unless structure.respond_to? :keys
        stringify_hash(structure)
      end
      
      def filter(data)
        stringify(data)
      end
    end
  end
end



================================================
FILE: lib/whiskey_disk/config.rb
================================================
require 'yaml'
require 'uri'
require 'open-uri'
require 'whiskey_disk/config/filter'

class WhiskeyDisk
  class Config
    def fetch
      raise "Cannot determine current environment -- try rake ... to=staging, for example." unless environment_name
      filter_data(load_data)
    end

    def debug?
      env_flag_is_true?('debug')
    end
    
    def domain_limit
      env_key_or_false?('only')
    end
    
    def check_staleness?
      env_flag_is_true?('check')
    end
    
    def configuration_file
      return path if valid_path?(path)
      
      files = []

      files += [
        File.join(base_path, 'deploy', specified_project_name, "#{environment_name}.yml"),  # /deploy/foo/staging.yml
        File.join(base_path, 'deploy', "#{specified_project_name}.yml") # /deploy/foo.yml
      ] if specified_project_name

      files += [
        File.join(base_path, 'deploy', "#{environment_name}.yml"),  # /deploy/staging.yml
        File.join(base_path, "#{environment_name}.yml"), # /staging.yml
        File.join(base_path, 'deploy.yml') # /deploy.yml
      ]

      files.each { |file|  return file if File.exists?(file) }

      raise "Could not locate configuration file in path [#{base_path}]"
    end

    def environment_name
      return false unless env_has_key?('to')
      return ENV['to'] unless ENV['to'] =~ /:/
      ENV['to'].split(/:/)[1]
    end

    def specified_project_name
      return false unless env_has_key?('to')
      return false unless ENV['to'] =~ /:/
      ENV['to'].split(/:/).first
    end
    
    def contains_rakefile?(path)
      File.exists?(File.expand_path(File.join(path, 'Rakefile')))
    end

    def find_rakefile_from_current_path
      original_path = Dir.pwd
      while (!contains_rakefile?(Dir.pwd))
        return File.join(original_path, 'config') if Dir.pwd == '/'
        Dir.chdir('..')
      end
      File.join(Dir.pwd, 'config')
    ensure
      Dir.chdir(original_path)
    end

    def base_path
      path || find_rakefile_from_current_path
    end

    def valid_path?(path)
      return false unless path
      uri = URI.parse(path)
      return path if uri.scheme
      return path if File.file?(path)
    end

    def project_name
      specified_project_name || 'unnamed_project'
    end

    # called only by #load_data
    def configuration_data
      open(configuration_file) {|f| f.read }
    end

    # called only by #fetch
    def load_data
      YAML.load(configuration_data)
    rescue Exception => e
      raise %Q{Error reading configuration file [#{configuration_file}]: "#{e}"}
    end
    
    def filter
      @filter ||= WhiskeyDisk::Config::Filter.new(self)
    end
    
    # called only by #fetch
    def filter_data(data)
      filter.filter_data(data)
    end

  private

    def path
      env_key_or_false?('path')
    end

    def env_has_key?(key)
      ENV[key] && ENV[key] != ''
    end

    def env_flag_is_true?(key)
      !!(env_has_key?(key) && ENV[key] =~ /^(?:t(?:rue)?|y(?:es)?|1)$/)
    end

    def env_key_or_false?(key)
      env_has_key?(key) ? ENV[key] : false
    end  
  end
end


================================================
FILE: lib/whiskey_disk/helpers.rb
================================================

# is the current deployment domain in the specified role?
def role?(role)
  return false unless ENV['WD_ROLES'] and ENV['WD_ROLES'] != ''
  ENV['WD_ROLES'].split(':').include?(role.to_s)
end

# have files of interest changed on this deployment?
def changed?(path)
  return true unless gc = git_changes
  cleaned = Regexp.escape(path.sub(%r{/+$}, ''))
  [ gc, rsync_changes ].flatten.compact.any? { |p| p =~ %r<^#{cleaned}(?:$|/)> }
end

# list of changed paths, according to git
def git_changes
  changes = read_git_changes_file.split("\n").uniq
rescue Exception
  nil
end

def rsync_changes
  changes = read_rsync_changes_file.split("\n")
  changes.map {|c| c.sub(/^[^ ]* [^ ]* [^ ]* /, '') }.
          grep(/^[^ ]{9,} /).map {|c| c.sub(/^[^ ]{9,} /, '') }.
          map {|s| s.sub(%r{/$}, '') } - ['.']
rescue Exception
  nil
end

def read_git_changes_file
  File.read(git_changes_path)
end

def read_rsync_changes_file
  File.read(rsync_changes_path)
end

def changes_file_root
  path = IO.popen("git rev-parse --show-toplevel").read
  path == '' ? Dir.pwd : path.chomp
end

def git_changes_path
  File.join(changes_file_root, '.whiskey_disk_git_changes')
end

def rsync_changes_path
  File.join(changes_file_root, '.whiskey_disk_rsync_changes')
end

================================================
FILE: lib/whiskey_disk/rake.rb
================================================
require 'rake'
require File.expand_path(File.join(File.dirname(__FILE__), '..', 'whiskey_disk'))

namespace :deploy do
  desc "Perform initial setup for deployment"
  task :setup do
    @whiskey_disk = WhiskeyDisk.new
    @whiskey_disk.ensure_main_parent_path_is_present
    @whiskey_disk.ensure_config_parent_path_is_present      if @whiskey_disk.has_config_repo?
    @whiskey_disk.checkout_main_repository
    @whiskey_disk.checkout_configuration_repository         if @whiskey_disk.has_config_repo?
    @whiskey_disk.update_main_repository_checkout
    @whiskey_disk.update_configuration_repository_checkout  if @whiskey_disk.has_config_repo?
    @whiskey_disk.refresh_configuration                     if @whiskey_disk.has_config_repo?
    @whiskey_disk.initialize_all_changes
    @whiskey_disk.run_post_setup_hooks
    @whiskey_disk.flush
    @whiskey_disk.summarize

    exit(1) unless @whiskey_disk.success?
  end
  
  desc "Deploy now."
  task :now do
    @whiskey_disk = WhiskeyDisk.new(:staleness_checks => true)
    @whiskey_disk.update_main_repository_checkout
    @whiskey_disk.update_configuration_repository_checkout  if @whiskey_disk.has_config_repo?
    @whiskey_disk.refresh_configuration                     if @whiskey_disk.has_config_repo?
    @whiskey_disk.run_post_deploy_hooks
    @whiskey_disk.flush
    @whiskey_disk.summarize

    exit(1) unless @whiskey_disk.success?
  end
  
  task :post_setup do
    @whiskey_disk = WhiskeyDisk.new
    env = @whiskey_disk.setting(:environment)
    Rake::Task["deploy:#{env}:post_setup"].invoke if Rake::Task.task_defined? "deploy:#{env}:post_setup"      
  end

  task :post_deploy do
    @whiskey_disk = WhiskeyDisk.new
    env = @whiskey_disk.setting(:environment)
    Rake::Task["deploy:#{env}:post_deploy"].invoke if Rake::Task.task_defined? "deploy:#{env}:post_deploy"      
  end
end


================================================
FILE: lib/whiskey_disk.rb
================================================
require File.expand_path(File.join(File.dirname(__FILE__), 'whiskey_disk', 'config'))

class WhiskeyDisk
  attr_writer :configuration, :config
  attr_reader :results
  
  def initialize(options = {})
    @staleness_checks = true if options[:staleness_checks]
  end
  
  def buffer
    @buffer ||= []
  end
  
  def config
    @config ||= WhiskeyDisk::Config.new
  end
  
  def configuration
    @configuration ||= config.fetch
  end
  
  def debugging?
    config.debug?
  end
  
  def setting(key)
    configuration[key.to_s]
  end
  
  def check_staleness?
    config.check_staleness?
  end
  
  def staleness_checks_enabled?
    !!@staleness_checks
  end    

  def enqueue(command)
    buffer << command
  end
  
  def remote?(domain)
    return false unless domain
    return false if domain == 'local'
    limit = config.domain_limit 
    return false if limit and domain_limit_match?(domain, limit)

    true
  end
  
  def has_config_repo?
    ! (setting(:config_repository).nil? or setting(:config_repository) == '')
  end
  
  def project_name_specified?
    setting(:project) != 'unnamed_project'
  end

  def branch
    (setting(:branch) and setting(:branch) != '') ? setting(:branch) : 'master'
  end
  
  def config_branch
    (setting(:config_branch) and setting(:config_branch) != '') ? setting(:config_branch) : 'master'
  end
  
  def env_vars
    return '' unless setting(:rake_env)
    setting(:rake_env).keys.inject('') do |buffer,k| 
      buffer += "#{k}='#{setting(:rake_env)[k]}' "
      buffer
    end
  end
  
  def parent_path(path)
    File.split(path).first
  end
  
  def tail_path(path)
    File.split(path).last
  end
  
  def needs(*keys)
    keys.each do |key|
      raise "No value for '#{key}' declared in configuration files [#{config.configuration_file}]" unless setting(key)
    end
  end

  def apply_staleness_check(commands)
    needs(:deploy_to, :repository)
    
    check = "cd #{setting(:deploy_to)}; " +
            "ml=\`git log -1 --pretty=format:%H\`; " +
            "mr=\`git ls-remote #{setting(:repository)} refs/heads/#{branch}\`; "
    
    if setting(:deploy_config_to)
      check += "cd #{setting(:deploy_config_to)}; " +
               "cl=\`git log -1 --pretty=format:%H\`; " +
               "cr=\`git ls-remote #{setting(:config_repository)} refs/heads/#{config_branch}\`; "
    end
    
    check += "if [[ $ml != ${mr%%\t*} ]] " +
             (setting(:deploy_config_to) ? "|| [[ $cl != ${cr%%\t*} ]]" : '') +
             "; then #{commands}; else echo \"No changes to deploy.\"; fi"
  end
  
  def join_commands
    buffer.collect {|c| "{ #{c} ; }"}.join(' && ')
  end
  
  def bundle
    return '' if buffer.empty?
    (staleness_checks_enabled? and check_staleness?) ? apply_staleness_check(join_commands) : join_commands
  end

  def domain_limit_match?(domain, limit)
    domain.sub(%r{^.*@}, '') == limit
  end
  
  def domain_of_interest?(domain)
    return true unless limit = config.domain_limit
    domain_limit_match?(domain, limit)
  end
  
  def encode_roles(roles)
    return '' unless roles and !roles.empty?
    "export WD_ROLES='#{roles.join(':')}'; "
  end

  def build_command(domain, cmd)
    "#{'set -x; ' if debugging?}" + encode_roles(domain['roles']) + cmd
  end
  
  def run(domain, cmd)
    ssh(domain, cmd)
  end

  def ssh(domain, cmd)
    args = []
    args << domain['name']
    args << '-v' if debugging?
    args += domain['ssh_options'] if domain['ssh_options']
    args << build_command(domain, cmd)

    puts "Running: ssh #{args.join(' ')}" if debugging?
    system('ssh', *args)
  end
  
  def shell(domain, cmd)
    puts "Running command locally: [#{cmd}]" if debugging?
    system('bash', '-c', build_command(domain, cmd))
  end
  
  def flush
    needs(:domain)
    setting(:domain).each do |domain|
      next unless domain_of_interest?(domain['name'])
      puts "Deploying #{domain['name']}..."
      status = remote?(domain['name']) ? run(domain, bundle) : shell(domain, bundle)
      record_result(domain['name'], status)
    end
  end
  
  def record_result(domain, status)
    @results ||= []
    @results << { 'domain' => domain, 'status' => status }
  end

  def summarize_results(results)
    successes = failures = 0
    results.each do |result|
      puts "#{result['domain']} => #{result['status'] ? 'succeeded' : 'failed'}."
      if result['status']
        successes += 1 
      else
        failures += 1
      end
    end
    [successes + failures, successes, failures]
  end
  
  def summarize
    puts "\nResults:"
    if results and not results.empty?
      total, successes, failures = summarize_results(results)
      puts "Total: #{total} deployment#{total == 1 ? '' : 's'}, " +
        "#{successes} success#{successes == 1 ? '' : 'es'}, " +
        "#{failures} failure#{failures == 1 ? '' : 's'}."
    else
      puts "No deployments to report."
    end       
  end
  
  def success?
    return true if !results or results.empty?
    results.all? {|result| result['status'] }
  end
  
  def if_file_present(path, cmd)
    "if [ -e #{path} ]; then #{cmd}; fi"
  end
  
  def if_task_defined(task, cmd)
    %Q(rakep=`#{env_vars} rake -P` && if [[ `echo "${rakep}" | grep #{task}` != "" ]]; then #{cmd}; fi )
  end
  
  def safe_branch_checkout(path, my_branch)
    %Q(cd #{path} && git checkout -b #{my_branch} origin/#{my_branch} || git checkout #{my_branch} origin/#{my_branch} || git checkout #{my_branch})
  end
  
  def clone_repository(repo, path, my_branch)
    enqueue "cd #{parent_path(path)}"
    enqueue("if [ -e #{path} ]; then echo 'Repository already cloned to [#{path}].  Skipping.'; " +
            "else git clone #{repo} #{tail_path(path)} && #{safe_branch_checkout(path, my_branch)}; fi")
  end
 
  def refresh_checkout(path, repo_branch)
    enqueue "cd #{path}"
    enqueue "git fetch origin +refs/heads/#{repo_branch}:refs/remotes/origin/#{repo_branch} #{'&>/dev/null' unless debugging?}"
    enqueue "git checkout #{repo_branch} #{'&>/dev/null' unless debugging?}"
    enqueue "git reset --hard origin/#{repo_branch} #{'&>/dev/null' unless debugging?}"
  end

  def run_rake_task(path, task_name)
    enqueue "echo Running rake #{task_name}..."
    enqueue "cd #{path}"
    enqueue(if_file_present("#{setting(:deploy_to)}/Rakefile", 
      if_task_defined(task_name, "#{env_vars} rake #{'--trace' if debugging?} #{task_name} to=#{setting(:environment)}")))
  end
  
  def build_path(path)
    return path if path =~ %r{^/}
    File.join(setting(:deploy_to), path)
  end

  def run_script(script)
    return unless script
    enqueue(%Q<cd #{setting(:deploy_to)}; echo "Running post script..."; #{env_vars} bash #{'-x' if debugging?} #{build_path(script)}>)
  end

  def ensure_main_parent_path_is_present
    needs(:deploy_to)
    enqueue "mkdir -p #{parent_path(setting(:deploy_to))}"
  end
  
  def ensure_config_parent_path_is_present
    needs(:deploy_config_to)
    enqueue "mkdir -p #{parent_path(setting(:deploy_config_to))}"
  end

  def checkout_main_repository
    needs(:deploy_to, :repository)
    clone_repository(setting(:repository), setting(:deploy_to), branch)
  end
  
  def checkout_configuration_repository
    needs(:deploy_config_to, :config_repository)
    clone_repository(setting(:config_repository), setting(:deploy_config_to), config_branch)
  end
  
  def snapshot_git_revision
    needs(:deploy_to)
    enqueue "cd #{setting(:deploy_to)}"
    enqueue %Q{ml=\`git log -1 --pretty=format:%H\`}
  end
  
  def initialize_git_changes
    needs(:deploy_to)
    enqueue "rm -f #{setting(:deploy_to)}/.whiskey_disk_git_changes"
    snapshot_git_revision
  end
  
  def initialize_rsync_changes
    needs(:deploy_to)
    enqueue "rm -f #{setting(:deploy_to)}/.whiskey_disk_rsync_changes"
  end
  
  def initialize_all_changes
    needs(:deploy_to)
    initialize_git_changes
    initialize_rsync_changes
  end
  
  def capture_git_changes
    needs(:deploy_to)
    enqueue "git diff --name-only ${ml}..HEAD > #{setting(:deploy_to)}/.whiskey_disk_git_changes"
  end
  
  def update_main_repository_checkout
    needs(:deploy_to)
    initialize_git_changes
    refresh_checkout(setting(:deploy_to), branch)
    capture_git_changes
  end
  
  def update_configuration_repository_checkout
    needs(:deploy_config_to)
    initialize_rsync_changes
    refresh_checkout(setting(:deploy_config_to), config_branch)
  end
  
  def refresh_configuration
    needs(:deploy_to, :deploy_config_to)
    raise "Must specify project name when using a configuration repository." unless project_name_specified?
    enqueue "echo Rsyncing configuration..."
    enqueue("rsync -a#{'v --progress' if debugging?} " + '--log-format="%t [%p] %i %n" ' +
            "#{setting(:deploy_config_to)}/#{setting(:project)}/#{setting(:config_target)}/ #{setting(:deploy_to)}/ " + 
            "> #{setting(:deploy_to)}/.whiskey_disk_rsync_changes")
  end
  
  def run_post_setup_hooks
    needs(:deploy_to)
    run_script(setting(:post_setup_script))
    run_rake_task(setting(:deploy_to), "deploy:post_setup")
  end
  
  def run_post_deploy_hooks
    needs(:deploy_to)
    run_script(setting(:post_deploy_script))
    run_rake_task(setting(:deploy_to), "deploy:post_deploy")
  end
end


================================================
FILE: scenarios/git_repositories/config.git/HEAD
================================================
ref: refs/heads/master


================================================
FILE: scenarios/git_repositories/config.git/config
================================================
[core]
	repositoryformatversion = 0
	filemode = true
	bare = true
	ignorecase = true


================================================
FILE: scenarios/git_repositories/config.git/description
================================================
Unnamed repository; edit this file 'description' to name the repository.


================================================
FILE: scenarios/git_repositories/config.git/git-daemon-export-ok
================================================


================================================
FILE: scenarios/git_repositories/config.git/hooks/applypatch-msg.sample
================================================
#!/bin/sh
#
# An example hook script to check the commit log message taken by
# applypatch from an e-mail message.
#
# The hook should exit with non-zero status after issuing an
# appropriate message if it wants to stop the commit.  The hook is
# allowed to edit the commit message file.
#
# To enable this hook, rename this file to "applypatch-msg".

. git-sh-setup
test -x "$GIT_DIR/hooks/commit-msg" &&
	exec "$GIT_DIR/hooks/commit-msg" ${1+"$@"}
:


================================================
FILE: scenarios/git_repositories/config.git/hooks/commit-msg.sample
================================================
#!/bin/sh
#
# An example hook script to check the commit log message.
# Called by git-commit with one argument, the name of the file
# that has the commit message.  The hook should exit with non-zero
# status after issuing an appropriate message if it wants to stop the
# commit.  The hook is allowed to edit the commit message file.
#
# To enable this hook, rename this file to "commit-msg".

# Uncomment the below to add a Signed-off-by line to the message.
# Doing this in a hook is a bad idea in general, but the prepare-commit-msg
# hook is more suited to it.
#
# SOB=$(git var GIT_AUTHOR_IDENT | sed -n 's/^\(.*>\).*$/Signed-off-by: \1/p')
# grep -qs "^$SOB" "$1" || echo "$SOB" >> "$1"

# This example catches duplicate Signed-off-by lines.

test "" = "$(grep '^Signed-off-by: ' "$1" |
	 sort | uniq -c | sed -e '/^[ 	]*1[ 	]/d')" || {
	echo >&2 Duplicate Signed-off-by lines.
	exit 1
}


================================================
FILE: scenarios/git_repositories/config.git/hooks/post-commit.sample
================================================
#!/bin/sh
#
# An example hook script that is called after a successful
# commit is made.
#
# To enable this hook, rename this file to "post-commit".

: Nothing


================================================
FILE: scenarios/git_repositories/config.git/hooks/post-receive.sample
================================================
#!/bin/sh
#
# An example hook script for the "post-receive" event.
#
# The "post-receive" script is run after receive-pack has accepted a pack
# and the repository has been updated.  It is passed arguments in through
# stdin in the form
#  <oldrev> <newrev> <refname>
# For example:
#  aa453216d1b3e49e7f6f98441fa56946ddcd6a20 68f7abf4e6f922807889f52bc043ecd31b79f814 refs/heads/master
#
# see contrib/hooks/ for a sample, or uncomment the next line and
# rename the file to "post-receive".

#. /usr/share/doc/git-core/contrib/hooks/post-receive-email


================================================
FILE: scenarios/git_repositories/config.git/hooks/post-update.sample
================================================
#!/bin/sh
#
# An example hook script to prepare a packed repository for use over
# dumb transports.
#
# To enable this hook, rename this file to "post-update".

exec git-update-server-info


================================================
FILE: scenarios/git_repositories/config.git/hooks/pre-applypatch.sample
================================================
#!/bin/sh
#
# An example hook script to verify what is about to be committed
# by applypatch from an e-mail message.
#
# The hook should exit with non-zero status after issuing an
# appropriate message if it wants to stop the commit.
#
# To enable this hook, rename this file to "pre-applypatch".

. git-sh-setup
test -x "$GIT_DIR/hooks/pre-commit" &&
	exec "$GIT_DIR/hooks/pre-commit" ${1+"$@"}
:


================================================
FILE: scenarios/git_repositories/config.git/hooks/pre-commit.sample
================================================
#!/bin/sh
#
# An example hook script to verify what is about to be committed.
# Called by git-commit with no arguments.  The hook should
# exit with non-zero status after issuing an appropriate message if
# it wants to stop the commit.
#
# To enable this hook, rename this file to "pre-commit".

if git-rev-parse --verify HEAD >/dev/null 2>&1
then
	against=HEAD
else
	# Initial commit: diff against an empty tree object
	against=4b825dc642cb6eb9a060e54bf8d69288fbee4904
fi

# If you want to allow non-ascii filenames set this variable to true.
allownonascii=$(git config hooks.allownonascii)

# Cross platform projects tend to avoid non-ascii filenames; prevent
# them from being added to the repository. We exploit the fact that the
# printable range starts at the space character and ends with tilde.
if [ "$allownonascii" != "true" ] &&
	# Note that the use of brackets around a tr range is ok here, (it's
	# even required, for portability to Solaris 10's /usr/bin/tr), since
	# the square bracket bytes happen to fall in the designated range.
	test "$(git diff --cached --name-only --diff-filter=A -z $against |
	  LC_ALL=C tr -d '[ -~]\0')"
then
	echo "Error: Attempt to add a non-ascii file name."
	echo
	echo "This can cause problems if you want to work"
	echo "with people on other platforms."
	echo
	echo "To be portable it is advisable to rename the file ..."
	echo
	echo "If you know what you are doing you can disable this"
	echo "check using:"
	echo
	echo "  git config hooks.allownonascii true"
	echo
	exit 1
fi

exec git diff-index --check --cached $against --


================================================
FILE: scenarios/git_repositories/config.git/hooks/pre-rebase.sample
================================================
#!/bin/sh
#
# Copyright (c) 2006, 2008 Junio C Hamano
#
# The "pre-rebase" hook is run just before "git-rebase" starts doing
# its job, and can prevent the command from running by exiting with
# non-zero status.
#
# The hook is called with the following parameters:
#
# $1 -- the upstream the series was forked from.
# $2 -- the branch being rebased (or empty when rebasing the current branch).
#
# This sample shows how to prevent topic branches that are already
# merged to 'next' branch from getting rebased, because allowing it
# would result in rebasing already published history.

publish=next
basebranch="$1"
if test "$#" = 2
then
	topic="refs/heads/$2"
else
	topic=`git symbolic-ref HEAD` ||
	exit 0 ;# we do not interrupt rebasing detached HEAD
fi

case "$topic" in
refs/heads/??/*)
	;;
*)
	exit 0 ;# we do not interrupt others.
	;;
esac

# Now we are dealing with a topic branch being rebased
# on top of master.  Is it OK to rebase it?

# Does the topic really exist?
git show-ref -q "$topic" || {
	echo >&2 "No such branch $topic"
	exit 1
}

# Is topic fully merged to master?
not_in_master=`git-rev-list --pretty=oneline ^master "$topic"`
if test -z "$not_in_master"
then
	echo >&2 "$topic is fully merged to master; better remove it."
	exit 1 ;# we could allow it, but there is no point.
fi

# Is topic ever merged to next?  If so you should not be rebasing it.
only_next_1=`git-rev-list ^master "^$topic" ${publish} | sort`
only_next_2=`git-rev-list ^master           ${publish} | sort`
if test "$only_next_1" = "$only_next_2"
then
	not_in_topic=`git-rev-list "^$topic" master`
	if test -z "$not_in_topic"
	then
		echo >&2 "$topic is already up-to-date with master"
		exit 1 ;# we could allow it, but there is no point.
	else
		exit 0
	fi
else
	not_in_next=`git-rev-list --pretty=oneline ^${publish} "$topic"`
	perl -e '
		my $topic = $ARGV[0];
		my $msg = "* $topic has commits already merged to public branch:\n";
		my (%not_in_next) = map {
			/^([0-9a-f]+) /;
			($1 => 1);
		} split(/\n/, $ARGV[1]);
		for my $elem (map {
				/^([0-9a-f]+) (.*)$/;
				[$1 => $2];
			} split(/\n/, $ARGV[2])) {
			if (!exists $not_in_next{$elem->[0]}) {
				if ($msg) {
					print STDERR $msg;
					undef $msg;
				}
				print STDERR " $elem->[1]\n";
			}
		}
	' "$topic" "$not_in_next" "$not_in_master"
	exit 1
fi

exit 0

################################################################

This sample hook safeguards topic branches that have been
published from being rewound.

The workflow assumed here is:

 * Once a topic branch forks from "master", "master" is never
   merged into it again (either directly or indirectly).

 * Once a topic branch is fully cooked and merged into "master",
   it is deleted.  If you need to build on top of it to correct
   earlier mistakes, a new topic branch is created by forking at
   the tip of the "master".  This is not strictly necessary, but
   it makes it easier to keep your history simple.

 * Whenever you need to test or publish your changes to topic
   branches, merge them into "next" branch.

The script, being an example, hardcodes the publish branch name
to be "next", but it is trivial to make it configurable via
$GIT_DIR/config mechanism.

With this workflow, you would want to know:

(1) ... if a topic branch has ever been merged to "next".  Young
    topic branches can have stupid mistakes you would rather
    clean up before publishing, and things that have not been
    merged into other branches can be easily rebased without
    affecting other people.  But once it is published, you would
    not want to rewind it.

(2) ... if a topic branch has been fully merged to "master".
    Then you can delete it.  More importantly, you should not
    build on top of it -- other people may already want to
    change things related to the topic as patches against your
    "master", so if you need further changes, it is better to
    fork the topic (perhaps with the same name) afresh from the
    tip of "master".

Let's look at this example:

		   o---o---o---o---o---o---o---o---o---o "next"
		  /       /           /           /
		 /   a---a---b A     /           /
		/   /               /           /
	       /   /   c---c---c---c B         /
	      /   /   /             \         /
	     /   /   /   b---b C     \       /
	    /   /   /   /             \     /
    ---o---o---o---o---o---o---o---o---o---o---o "master"


A, B and C are topic branches.

 * A has one fix since it was merged up to "next".

 * B has finished.  It has been fully merged up to "master" and "next",
   and is ready to be deleted.

 * C has not merged to "next" at all.

We would want to allow C to be rebased, refuse A, and encourage
B to be deleted.

To compute (1):

	git-rev-list ^master ^topic next
	git-rev-list ^master        next

	if these match, topic has not merged in next at all.

To compute (2):

	git-rev-list master..topic

	if this is empty, it is fully merged to "master".


================================================
FILE: scenarios/git_repositories/config.git/hooks/prepare-commit-msg.sample
================================================
#!/bin/sh
#
# An example hook script to prepare the commit log message.
# Called by git-commit with the name of the file that has the
# commit message, followed by the description of the commit
# message's source.  The hook's purpose is to edit the commit
# message file.  If the hook fails with a non-zero status,
# the commit is aborted.
#
# To enable this hook, rename this file to "prepare-commit-msg".

# This hook includes three examples.  The first comments out the
# "Conflicts:" part of a merge commit.
#
# The second includes the output of "git diff --name-status -r"
# into the message, just before the "git status" output.  It is
# commented because it doesn't cope with --amend or with squashed
# commits.
#
# The third example adds a Signed-off-by line to the message, that can
# still be edited.  This is rarely a good idea.

case "$2,$3" in
  merge,)
    perl -i.bak -ne 's/^/# /, s/^# #/#/ if /^Conflicts/ .. /#/; print' "$1" ;;

# ,|template,)
#   perl -i.bak -pe '
#      print "\n" . `git diff --cached --name-status -r`
#	 if /^#/ && $first++ == 0' "$1" ;;

  *) ;;
esac

# SOB=$(git var GIT_AUTHOR_IDENT | sed -n 's/^\(.*>\).*$/Signed-off-by: \1/p')
# grep -qs "^$SOB" "$1" || echo "$SOB" >> "$1"


================================================
FILE: scenarios/git_repositories/config.git/hooks/update.sample
================================================
#!/bin/sh
#
# An example hook script to blocks unannotated tags from entering.
# Called by git-receive-pack with arguments: refname sha1-old sha1-new
#
# To enable this hook, rename this file to "update".
#
# Config
# ------
# hooks.allowunannotated
#   This boolean sets whether unannotated tags will be allowed into the
#   repository.  By default they won't be.
# hooks.allowdeletetag
#   This boolean sets whether deleting tags will be allowed in the
#   repository.  By default they won't be.
# hooks.allowmodifytag
#   This boolean sets whether a tag may be modified after creation. By default
#   it won't be.
# hooks.allowdeletebranch
#   This boolean sets whether deleting branches will be allowed in the
#   repository.  By default they won't be.
# hooks.denycreatebranch
#   This boolean sets whether remotely creating branches will be denied
#   in the repository.  By default this is allowed.
#

# --- Command line
refname="$1"
oldrev="$2"
newrev="$3"

# --- Safety check
if [ -z "$GIT_DIR" ]; then
	echo "Don't run this script from the command line." >&2
	echo " (if you want, you could supply GIT_DIR then run" >&2
	echo "  $0 <ref> <oldrev> <newrev>)" >&2
	exit 1
fi

if [ -z "$refname" -o -z "$oldrev" -o -z "$newrev" ]; then
	echo "Usage: $0 <ref> <oldrev> <newrev>" >&2
	exit 1
fi

# --- Config
allowunannotated=$(git config --bool hooks.allowunannotated)
allowdeletebranch=$(git config --bool hooks.allowdeletebranch)
denycreatebranch=$(git config --bool hooks.denycreatebranch)
allowdeletetag=$(git config --bool hooks.allowdeletetag)
allowmodifytag=$(git config --bool hooks.allowmodifytag)

# check for no description
projectdesc=$(sed -e '1q' "$GIT_DIR/description")
case "$projectdesc" in
"Unnamed repository"* | "")
	echo "*** Project description file hasn't been set" >&2
	exit 1
	;;
esac

# --- Check types
# if $newrev is 0000...0000, it's a commit to delete a ref.
zero="0000000000000000000000000000000000000000"
if [ "$newrev" = "$zero" ]; then
	newrev_type=delete
else
	newrev_type=$(git-cat-file -t $newrev)
fi

case "$refname","$newrev_type" in
	refs/tags/*,commit)
		# un-annotated tag
		short_refname=${refname##refs/tags/}
		if [ "$allowunannotated" != "true" ]; then
			echo "*** The un-annotated tag, $short_refname, is not allowed in this repository" >&2
			echo "*** Use 'git tag [ -a | -s ]' for tags you want to propagate." >&2
			exit 1
		fi
		;;
	refs/tags/*,delete)
		# delete tag
		if [ "$allowdeletetag" != "true" ]; then
			echo "*** Deleting a tag is not allowed in this repository" >&2
			exit 1
		fi
		;;
	refs/tags/*,tag)
		# annotated tag
		if [ "$allowmodifytag" != "true" ] && git rev-parse $refname > /dev/null 2>&1
		then
			echo "*** Tag '$refname' already exists." >&2
			echo "*** Modifying a tag is not allowed in this repository." >&2
			exit 1
		fi
		;;
	refs/heads/*,commit)
		# branch
		if [ "$oldrev" = "$zero" -a "$denycreatebranch" = "true" ]; then
			echo "*** Creating a branch is not allowed in this repository" >&2
			exit 1
		fi
		;;
	refs/heads/*,delete)
		# delete branch
		if [ "$allowdeletebranch" != "true" ]; then
			echo "*** Deleting a branch is not allowed in this repository" >&2
			exit 1
		fi
		;;
	refs/remotes/*,commit)
		# tracking branch
		;;
	refs/remotes/*,delete)
		# delete tracking branch
		if [ "$allowdeletebranch" != "true" ]; then
			echo "*** Deleting a tracking branch is not allowed in this repository" >&2
			exit 1
		fi
		;;
	*)
		# Anything else (is there anything else?)
		echo "*** Update hook: unknown type of update to ref $refname of type $newrev_type" >&2
		exit 1
		;;
esac

# --- Finished
exit 0


================================================
FILE: scenarios/git_repositories/config.git/info/exclude
================================================
# git-ls-files --others --exclude-from=.git/info/exclude
# Lines that start with '#' are comments.
# For a project mostly in C, the following would be a good set of
# exclude patterns (uncomment them if you want to use them):
# *.[oa]
# *~


================================================
FILE: scenarios/git_repositories/config.git/objects/0e/e781f5ce80d64db32a74a7aae7b5248dafe112
================================================
x[
0D*<nD%<n&%ݽw́&eH-A4x)Ah549ddc7RKAKw,9`ݞ}
/Ug\{~)Bq٥5~џuikP=O!M3ZJuQ

================================================
FILE: scenarios/git_repositories/config.git/objects/71/eb5df52676e8e6efba471050b46978173af110
================================================
x	1DNۀ%An`r?u<x3RK'$&I8(mͳyɜutʿ6xdy\h_,;9I-W@3[äQ;ՠ?uܳ_aQ_&<

================================================
FILE: scenarios/git_repositories/config.git/objects/84/17d2fe3e8fcc0825249c517b29b0f9ea8b8b31
================================================
xQJ0})J6ID#xoM$Ez{#cqlgW5藅CrL9Q9z(^]a}dH~E	}@u~l%vfA#}[^:ɮ<^%'n3m
Ls>H7 XˮހBY[ѮQ
UyF+Y

================================================
FILE: scenarios/git_repositories/config.git/refs/heads/master
================================================
bb59da633ba74296b0c2f9ff70784ac155ddb599


================================================
FILE: scenarios/git_repositories/project.git/HEAD
================================================
ref: refs/heads/master


================================================
FILE: scenarios/git_repositories/project.git/config
================================================
[core]
	repositoryformatversion = 0
	filemode = true
	bare = true
	ignorecase = true


================================================
FILE: scenarios/git_repositories/project.git/description
================================================
Unnamed repository; edit this file 'description' to name the repository.


================================================
FILE: scenarios/git_repositories/project.git/git-daemon-export-ok
================================================


================================================
FILE: scenarios/git_repositories/project.git/hooks/applypatch-msg.sample
================================================
#!/bin/sh
#
# An example hook script to check the commit log message taken by
# applypatch from an e-mail message.
#
# The hook should exit with non-zero status after issuing an
# appropriate message if it wants to stop the commit.  The hook is
# allowed to edit the commit message file.
#
# To enable this hook, rename this file to "applypatch-msg".

. git-sh-setup
test -x "$GIT_DIR/hooks/commit-msg" &&
	exec "$GIT_DIR/hooks/commit-msg" ${1+"$@"}
:


================================================
FILE: scenarios/git_repositories/project.git/hooks/commit-msg.sample
================================================
#!/bin/sh
#
# An example hook script to check the commit log message.
# Called by git-commit with one argument, the name of the file
# that has the commit message.  The hook should exit with non-zero
# status after issuing an appropriate message if it wants to stop the
# commit.  The hook is allowed to edit the commit message file.
#
# To enable this hook, rename this file to "commit-msg".

# Uncomment the below to add a Signed-off-by line to the message.
# Doing this in a hook is a bad idea in general, but the prepare-commit-msg
# hook is more suited to it.
#
# SOB=$(git var GIT_AUTHOR_IDENT | sed -n 's/^\(.*>\).*$/Signed-off-by: \1/p')
# grep -qs "^$SOB" "$1" || echo "$SOB" >> "$1"

# This example catches duplicate Signed-off-by lines.

test "" = "$(grep '^Signed-off-by: ' "$1" |
	 sort | uniq -c | sed -e '/^[ 	]*1[ 	]/d')" || {
	echo >&2 Duplicate Signed-off-by lines.
	exit 1
}


================================================
FILE: scenarios/git_repositories/project.git/hooks/post-commit.sample
================================================
#!/bin/sh
#
# An example hook script that is called after a successful
# commit is made.
#
# To enable this hook, rename this file to "post-commit".

: Nothing


================================================
FILE: scenarios/git_repositories/project.git/hooks/post-receive.sample
================================================
#!/bin/sh
#
# An example hook script for the "post-receive" event.
#
# The "post-receive" script is run after receive-pack has accepted a pack
# and the repository has been updated.  It is passed arguments in through
# stdin in the form
#  <oldrev> <newrev> <refname>
# For example:
#  aa453216d1b3e49e7f6f98441fa56946ddcd6a20 68f7abf4e6f922807889f52bc043ecd31b79f814 refs/heads/master
#
# see contrib/hooks/ for a sample, or uncomment the next line and
# rename the file to "post-receive".

#. /usr/share/doc/git-core/contrib/hooks/post-receive-email


================================================
FILE: scenarios/git_repositories/project.git/hooks/post-update.sample
================================================
#!/bin/sh
#
# An example hook script to prepare a packed repository for use over
# dumb transports.
#
# To enable this hook, rename this file to "post-update".

exec git-update-server-info


================================================
FILE: scenarios/git_repositories/project.git/hooks/pre-applypatch.sample
================================================
#!/bin/sh
#
# An example hook script to verify what is about to be committed
# by applypatch from an e-mail message.
#
# The hook should exit with non-zero status after issuing an
# appropriate message if it wants to stop the commit.
#
# To enable this hook, rename this file to "pre-applypatch".

. git-sh-setup
test -x "$GIT_DIR/hooks/pre-commit" &&
	exec "$GIT_DIR/hooks/pre-commit" ${1+"$@"}
:


================================================
FILE: scenarios/git_repositories/project.git/hooks/pre-commit.sample
================================================
#!/bin/sh
#
# An example hook script to verify what is about to be committed.
# Called by git-commit with no arguments.  The hook should
# exit with non-zero status after issuing an appropriate message if
# it wants to stop the commit.
#
# To enable this hook, rename this file to "pre-commit".

if git-rev-parse --verify HEAD >/dev/null 2>&1
then
	against=HEAD
else
	# Initial commit: diff against an empty tree object
	against=4b825dc642cb6eb9a060e54bf8d69288fbee4904
fi

# If you want to allow non-ascii filenames set this variable to true.
allownonascii=$(git config hooks.allownonascii)

# Cross platform projects tend to avoid non-ascii filenames; prevent
# them from being added to the repository. We exploit the fact that the
# printable range starts at the space character and ends with tilde.
if [ "$allownonascii" != "true" ] &&
	# Note that the use of brackets around a tr range is ok here, (it's
	# even required, for portability to Solaris 10's /usr/bin/tr), since
	# the square bracket bytes happen to fall in the designated range.
	test "$(git diff --cached --name-only --diff-filter=A -z $against |
	  LC_ALL=C tr -d '[ -~]\0')"
then
	echo "Error: Attempt to add a non-ascii file name."
	echo
	echo "This can cause problems if you want to work"
	echo "with people on other platforms."
	echo
	echo "To be portable it is advisable to rename the file ..."
	echo
	echo "If you know what you are doing you can disable this"
	echo "check using:"
	echo
	echo "  git config hooks.allownonascii true"
	echo
	exit 1
fi

exec git diff-index --check --cached $against --


================================================
FILE: scenarios/git_repositories/project.git/hooks/pre-rebase.sample
================================================
#!/bin/sh
#
# Copyright (c) 2006, 2008 Junio C Hamano
#
# The "pre-rebase" hook is run just before "git-rebase" starts doing
# its job, and can prevent the command from running by exiting with
# non-zero status.
#
# The hook is called with the following parameters:
#
# $1 -- the upstream the series was forked from.
# $2 -- the branch being rebased (or empty when rebasing the current branch).
#
# This sample shows how to prevent topic branches that are already
# merged to 'next' branch from getting rebased, because allowing it
# would result in rebasing already published history.

publish=next
basebranch="$1"
if test "$#" = 2
then
	topic="refs/heads/$2"
else
	topic=`git symbolic-ref HEAD` ||
	exit 0 ;# we do not interrupt rebasing detached HEAD
fi

case "$topic" in
refs/heads/??/*)
	;;
*)
	exit 0 ;# we do not interrupt others.
	;;
esac

# Now we are dealing with a topic branch being rebased
# on top of master.  Is it OK to rebase it?

# Does the topic really exist?
git show-ref -q "$topic" || {
	echo >&2 "No such branch $topic"
	exit 1
}

# Is topic fully merged to master?
not_in_master=`git-rev-list --pretty=oneline ^master "$topic"`
if test -z "$not_in_master"
then
	echo >&2 "$topic is fully merged to master; better remove it."
	exit 1 ;# we could allow it, but there is no point.
fi

# Is topic ever merged to next?  If so you should not be rebasing it.
only_next_1=`git-rev-list ^master "^$topic" ${publish} | sort`
only_next_2=`git-rev-list ^master           ${publish} | sort`
if test "$only_next_1" = "$only_next_2"
then
	not_in_topic=`git-rev-list "^$topic" master`
	if test -z "$not_in_topic"
	then
		echo >&2 "$topic is already up-to-date with master"
		exit 1 ;# we could allow it, but there is no point.
	else
		exit 0
	fi
else
	not_in_next=`git-rev-list --pretty=oneline ^${publish} "$topic"`
	perl -e '
		my $topic = $ARGV[0];
		my $msg = "* $topic has commits already merged to public branch:\n";
		my (%not_in_next) = map {
			/^([0-9a-f]+) /;
			($1 => 1);
		} split(/\n/, $ARGV[1]);
		for my $elem (map {
				/^([0-9a-f]+) (.*)$/;
				[$1 => $2];
			} split(/\n/, $ARGV[2])) {
			if (!exists $not_in_next{$elem->[0]}) {
				if ($msg) {
					print STDERR $msg;
					undef $msg;
				}
				print STDERR " $elem->[1]\n";
			}
		}
	' "$topic" "$not_in_next" "$not_in_master"
	exit 1
fi

exit 0

################################################################

This sample hook safeguards topic branches that have been
published from being rewound.

The workflow assumed here is:

 * Once a topic branch forks from "master", "master" is never
   merged into it again (either directly or indirectly).

 * Once a topic branch is fully cooked and merged into "master",
   it is deleted.  If you need to build on top of it to correct
   earlier mistakes, a new topic branch is created by forking at
   the tip of the "master".  This is not strictly necessary, but
   it makes it easier to keep your history simple.

 * Whenever you need to test or publish your changes to topic
   branches, merge them into "next" branch.

The script, being an example, hardcodes the publish branch name
to be "next", but it is trivial to make it configurable via
$GIT_DIR/config mechanism.

With this workflow, you would want to know:

(1) ... if a topic branch has ever been merged to "next".  Young
    topic branches can have stupid mistakes you would rather
    clean up before publishing, and things that have not been
    merged into other branches can be easily rebased without
    affecting other people.  But once it is published, you would
    not want to rewind it.

(2) ... if a topic branch has been fully merged to "master".
    Then you can delete it.  More importantly, you should not
    build on top of it -- other people may already want to
    change things related to the topic as patches against your
    "master", so if you need further changes, it is better to
    fork the topic (perhaps with the same name) afresh from the
    tip of "master".

Let's look at this example:

		   o---o---o---o---o---o---o---o---o---o "next"
		  /       /           /           /
		 /   a---a---b A     /           /
		/   /               /           /
	       /   /   c---c---c---c B         /
	      /   /   /             \         /
	     /   /   /   b---b C     \       /
	    /   /   /   /             \     /
    ---o---o---o---o---o---o---o---o---o---o---o "master"


A, B and C are topic branches.

 * A has one fix since it was merged up to "next".

 * B has finished.  It has been fully merged up to "master" and "next",
   and is ready to be deleted.

 * C has not merged to "next" at all.

We would want to allow C to be rebased, refuse A, and encourage
B to be deleted.

To compute (1):

	git-rev-list ^master ^topic next
	git-rev-list ^master        next

	if these match, topic has not merged in next at all.

To compute (2):

	git-rev-list master..topic

	if this is empty, it is fully merged to "master".


================================================
FILE: scenarios/git_repositories/project.git/hooks/prepare-commit-msg.sample
================================================
#!/bin/sh
#
# An example hook script to prepare the commit log message.
# Called by git-commit with the name of the file that has the
# commit message, followed by the description of the commit
# message's source.  The hook's purpose is to edit the commit
# message file.  If the hook fails with a non-zero status,
# the commit is aborted.
#
# To enable this hook, rename this file to "prepare-commit-msg".

# This hook includes three examples.  The first comments out the
# "Conflicts:" part of a merge commit.
#
# The second includes the output of "git diff --name-status -r"
# into the message, just before the "git status" output.  It is
# commented because it doesn't cope with --amend or with squashed
# commits.
#
# The third example adds a Signed-off-by line to the message, that can
# still be edited.  This is rarely a good idea.

case "$2,$3" in
  merge,)
    perl -i.bak -ne 's/^/# /, s/^# #/#/ if /^Conflicts/ .. /#/; print' "$1" ;;

# ,|template,)
#   perl -i.bak -pe '
#      print "\n" . `git diff --cached --name-status -r`
#	 if /^#/ && $first++ == 0' "$1" ;;

  *) ;;
esac

# SOB=$(git var GIT_AUTHOR_IDENT | sed -n 's/^\(.*>\).*$/Signed-off-by: \1/p')
# grep -qs "^$SOB" "$1" || echo "$SOB" >> "$1"


================================================
FILE: scenarios/git_repositories/project.git/hooks/update.sample
================================================
#!/bin/sh
#
# An example hook script to blocks unannotated tags from entering.
# Called by git-receive-pack with arguments: refname sha1-old sha1-new
#
# To enable this hook, rename this file to "update".
#
# Config
# ------
# hooks.allowunannotated
#   This boolean sets whether unannotated tags will be allowed into the
#   repository.  By default they won't be.
# hooks.allowdeletetag
#   This boolean sets whether deleting tags will be allowed in the
#   repository.  By default they won't be.
# hooks.allowmodifytag
#   This boolean sets whether a tag may be modified after creation. By default
#   it won't be.
# hooks.allowdeletebranch
#   This boolean sets whether deleting branches will be allowed in the
#   repository.  By default they won't be.
# hooks.denycreatebranch
#   This boolean sets whether remotely creating branches will be denied
#   in the repository.  By default this is allowed.
#

# --- Command line
refname="$1"
oldrev="$2"
newrev="$3"

# --- Safety check
if [ -z "$GIT_DIR" ]; then
	echo "Don't run this script from the command line." >&2
	echo " (if you want, you could supply GIT_DIR then run" >&2
	echo "  $0 <ref> <oldrev> <newrev>)" >&2
	exit 1
fi

if [ -z "$refname" -o -z "$oldrev" -o -z "$newrev" ]; then
	echo "Usage: $0 <ref> <oldrev> <newrev>" >&2
	exit 1
fi

# --- Config
allowunannotated=$(git config --bool hooks.allowunannotated)
allowdeletebranch=$(git config --bool hooks.allowdeletebranch)
denycreatebranch=$(git config --bool hooks.denycreatebranch)
allowdeletetag=$(git config --bool hooks.allowdeletetag)
allowmodifytag=$(git config --bool hooks.allowmodifytag)

# check for no description
projectdesc=$(sed -e '1q' "$GIT_DIR/description")
case "$projectdesc" in
"Unnamed repository"* | "")
	echo "*** Project description file hasn't been set" >&2
	exit 1
	;;
esac

# --- Check types
# if $newrev is 0000...0000, it's a commit to delete a ref.
zero="0000000000000000000000000000000000000000"
if [ "$newrev" = "$zero" ]; then
	newrev_type=delete
else
	newrev_type=$(git-cat-file -t $newrev)
fi

case "$refname","$newrev_type" in
	refs/tags/*,commit)
		# un-annotated tag
		short_refname=${refname##refs/tags/}
		if [ "$allowunannotated" != "true" ]; then
			echo "*** The un-annotated tag, $short_refname, is not allowed in this repository" >&2
			echo "*** Use 'git tag [ -a | -s ]' for tags you want to propagate." >&2
			exit 1
		fi
		;;
	refs/tags/*,delete)
		# delete tag
		if [ "$allowdeletetag" != "true" ]; then
			echo "*** Deleting a tag is not allowed in this repository" >&2
			exit 1
		fi
		;;
	refs/tags/*,tag)
		# annotated tag
		if [ "$allowmodifytag" != "true" ] && git rev-parse $refname > /dev/null 2>&1
		then
			echo "*** Tag '$refname' already exists." >&2
			echo "*** Modifying a tag is not allowed in this repository." >&2
			exit 1
		fi
		;;
	refs/heads/*,commit)
		# branch
		if [ "$oldrev" = "$zero" -a "$denycreatebranch" = "true" ]; then
			echo "*** Creating a branch is not allowed in this repository" >&2
			exit 1
		fi
		;;
	refs/heads/*,delete)
		# delete branch
		if [ "$allowdeletebranch" != "true" ]; then
			echo "*** Deleting a branch is not allowed in this repository" >&2
			exit 1
		fi
		;;
	refs/remotes/*,commit)
		# tracking branch
		;;
	refs/remotes/*,delete)
		# delete tracking branch
		if [ "$allowdeletebranch" != "true" ]; then
			echo "*** Deleting a tracking branch is not allowed in this repository" >&2
			exit 1
		fi
		;;
	*)
		# Anything else (is there anything else?)
		echo "*** Update hook: unknown type of update to ref $refname of type $newrev_type" >&2
		exit 1
		;;
esac

# --- Finished
exit 0


================================================
FILE: scenarios/git_repositories/project.git/info/exclude
================================================
# git-ls-files --others --exclude-from=.git/info/exclude
# Lines that start with '#' are comments.
# For a project mostly in C, the following would be a good set of
# exclude patterns (uncomment them if you want to use them):
# *.[oa]
# *~


================================================
FILE: scenarios/git_repositories/project.git/objects/04/f4de85eaf72ef1631dc6d7424045c0a749b757
================================================
xIjC1D)zH<@!G#:>27Uԃ5
D@RaH"pQåA1yuPEɐ;"lBm+hRHFT<Y>G,7=҃}2or]'	Y,}IWy&u턗y?*W

================================================
FILE: scenarios/git_repositories/project.git/objects/20/1c7641c2e42b0b904e5c1f793489d8b858e4da
================================================
x	1DNۀ%qD ar?u<x3;hrD@mrh68sZğD7»?kG/VvżS
ڰ7nbpDBT.*o¾<t

================================================
FILE: scenarios/git_repositories/project.git/objects/27/a3fff2c4c45ab5513a405f694c0a042cb5d417
================================================
xNAj1ٯsevg!'abl:A/BR\4 GoBq +C΄ѻ)N,["c`R`J8Z	9'#s#s`.kc3voYdxGhO6gHJ
G5³׭vd7P

================================================
FILE: scenarios/git_repositories/project.git/objects/2c/0c33cfba8e1af15df88522c0db2b10a6a94138
================================================
xKj1D)	R3#I|jC2"zmYfLMŁJ$`≳xG\(HdUȑsTsqm.
w6NUC7n
N3w+ގu o-0gLC
^m8nmW:ط+wn(V}

================================================
FILE: scenarios/git_repositories/project.git/objects/5b/a96acf9cc9b87babe37c032676f53bf1ba9ae7
================================================
xaj QRz@	b4ޠx<t g/@Wmf&Dɧ3N8ɜOlu&82m`l(&&+zj19F|Zzwh'D
U'~n[vy)%86p?b)'w'
U6

================================================
FILE: scenarios/git_repositories/project.git/objects/86/d1ef0976be4567de562224e1b51fbf9820c53a
================================================
xAJ1E]PJ:^@J4Ifx7뾗a40Iт.bF7BiN4[u&Ցa¤S$Ͷ|>yrT>>k7xk17<^''vZIg*\+tnS!GS\T

================================================
FILE: scenarios/git_repositories/project.git/objects/95/c9d5ad9b1c90e4c805516783105fc2037dedeb
================================================
xKn U# TUUw
x8	jrB`;ۭ}̈́6VˡP NڪiBh٦cSQ;-pHa
AP4gj%&v+JYT&rV#7qΊZLQ:\"H4(c0gW>2X\C$T>S-7_?a*2',*hq:\PA|D[x֣lR
MŐ|&z

================================================
FILE: scenarios/git_repositories/project.git/objects/95/d82d043af35a80eabfd56c0d705abfa3488787
================================================
xQn1DSEvd	UGI@.B73yғ&oZ;XG$:+iy)ZJ=6
)ώ)[e0dg*sイDekp
e?8^d<3|C4]M3D(.vW-uQ(RRR

================================================
FILE: scenarios/git_repositories/project.git/objects/a3/860106dc1d148c7831cd45ae38829b4ed47702
================================================
x]
0})6ɚD#xlh"ۛ
|o`bTkt4CJ񙍳V[4#m$):sјH>T-e<0HI¿ۣT	ӋW8.[92aP(H~g֥/!H

================================================
FILE: scenarios/git_repositories/project.git/objects/ae/3900de54aff557c61c81146d00f9d38e55a265
================================================
xAj!EH(R[BI!7{৶u4zJ"d
\bAˎ|rs&=_RLV8 +yuԴ{ypN3/Mq>hxF{p5eck[,wP

================================================
FILE: scenarios/git_repositories/project.git/objects/bf/5e3740d52b80abb0378b3f85f93a53b1294521
================================================
xQj0SvX #*"߾*A~evB&ls}a8{"B.Oαc5t8'%qPBC.=]d!{grv_|Uyq~˜d>Z1GMos
X>37]2u'S9

================================================
FILE: scenarios/git_repositories/project.git/objects/cc/5ac0afb24e727d5de344cc26a425f4fb7fd17d
================================================
xA
0D]CBBAWzNJIG6?𓅷$Y7oyf])g&on֒
F^hBDt htt.e%yCΪVfS~?Zvwΰҭl:l?k]

================================================
FILE: scenarios/git_repositories/project.git/objects/db/d1b9667f1b26b13331ac0c321dced8be1aeab0
================================================
xKj0)	-Y$@hZc3cbn nԛT&RpL`0OgtT5هh*l%D]2Ze+Q.mI
yv:Zgj基
G=W^z;Wrv7dTfݺV

================================================
FILE: scenarios/git_repositories/project.git/refs/heads/bad_rakefile
================================================
95d82d043af35a80eabfd56c0d705abfa3488787


================================================
FILE: scenarios/git_repositories/project.git/refs/heads/hook_with_changed
================================================
5ba96acf9cc9b87babe37c032676f53bf1ba9ae7


================================================
FILE: scenarios/git_repositories/project.git/refs/heads/master
================================================
04f4de85eaf72ef1631dc6d7424045c0a749b757


================================================
FILE: scenarios/git_repositories/project.git/refs/heads/no_rake_hooks
================================================
ae3900de54aff557c61c81146d00f9d38e55a265


================================================
FILE: scenarios/git_repositories/project.git/refs/heads/post_rake_tasks
================================================
27a3fff2c4c45ab5513a405f694c0a042cb5d417


================================================
FILE: scenarios/invalid/deploy.yml
================================================
}


================================================
FILE: scenarios/local/deploy.yml.erb
================================================
<% root = File.expand_path(File.join(File.dirname(__FILE__), 'scenarios', 'setup', 'vagrant', 'deployed', 'target')) %>
project:
  "local-default":
    deploy_to: "<%= root %>/project"
    repository: "git://localhost/project.git"
  "local-keyword":
    domain: "local"
    deploy_to: "<%= root %>/project"
    repository: "git://localhost/project.git"
  "local-user-domain":
    domain: "user@localhost"
    deploy_to: "<%= root %>/project"
    repository: "git://localhost/project.git"
  "local-domain":
    domain: "localhost"
    deploy_to: "<%= root %>/project"
    repository: "git://localhost/project.git"


================================================
FILE: scenarios/remote/deploy.yml
================================================
project:
  "remote":
    domain:
    - name: "vagrant@vagrant"
      ssh_options:
      - "-F"
      - "scenarios/setup/vagrant/ssh_config"
    deploy_to: "/opt/deploy/target/project"
    repository: "git://wd-git.example.com/project.git"
  "remote-on-other-branch":
    domain:
    - name: "vagrant@vagrant"
      ssh_options:
      - "-F"
      - "scenarios/setup/vagrant/ssh_config"
    deploy_to: "/opt/deploy/target/project"
    repository: "git://wd-git.example.com/project.git"
    branch: "no_rake_hooks"
  "no_rakefile":
    domain:
    - name: "vagrant@vagrant"
      ssh_options:
      - "-F"
      - "scenarios/setup/vagrant/ssh_config"
    deploy_to: "/opt/deploy/target/project"
    repository: "git://wd-git.example.com/project.git"
  "bad_rakefile":
    domain:
    - name: "vagrant@vagrant"
      ssh_options:
      - "-F"
      - "scenarios/setup/vagrant/ssh_config"
    deploy_to: "/opt/deploy/target/project"
    repository: "git://wd-git.example.com/project.git"
    branch: "bad_rakefile"
  "no_rake_hooks":
    domain:
    - name: "vagrant@vagrant"
      ssh_options:
      - "-F"
      - "scenarios/setup/vagrant/ssh_config"
    deploy_to: "/opt/deploy/target/project"
    repository: "git://wd-git.example.com/project.git"
    branch: "no_rake_hooks"
  "with_rake_hooks":
    domain:
    - name: "vagrant@vagrant"
      ssh_options:
      - "-F"
      - "scenarios/setup/vagrant/ssh_config"
    deploy_to: "/opt/deploy/target/project"
    repository: "git://wd-git.example.com/project.git"
    branch: "post_rake_tasks"
  "no_post_scripts":
    domain:
    - name: "vagrant@vagrant"
      ssh_options:
      - "-F"
      - "scenarios/setup/vagrant/ssh_config"
    deploy_to: "/opt/deploy/target/project"
    repository: "git://wd-git.example.com/project.git"
  "missing_post_scripts":
    domain:
    - name: "vagrant@vagrant"
      ssh_options:
      - "-F"
      - "scenarios/setup/vagrant/ssh_config"
    deploy_to: "/opt/deploy/target/project"
    repository: "git://wd-git.example.com/project.git"
    post_setup_script: "bin/missing.sh"
    post_deploy_script: "bin/missing.sh"
    rake_env:
      FOO: "BAR"
  "with_post_scripts":
    domain:
    - name: "vagrant@vagrant"
      ssh_options:
      - "-F"
      - "scenarios/setup/vagrant/ssh_config"
    deploy_to: "/opt/deploy/target/project"
    repository: "git://wd-git.example.com/project.git"
    post_setup_script: "bin/post_setup_script.sh"
    post_deploy_script: "bin/post_deploy_script.sh"
    rake_env:
      FOO: "BAR"
  "with_failing_post_scripts":
    domain:
    - name: "vagrant@vagrant"
      ssh_options:
      - "-F"
      - "scenarios/setup/vagrant/ssh_config"
    deploy_to: "/opt/deploy/target/project"
    repository: "git://wd-git.example.com/project.git"
    post_setup_script: "bin/failing_post_setup_script.sh"
    post_deploy_script: "bin/failing_post_deploy_script.sh"
    rake_env:
      FOO: "BAR"
  "hook_with_changed":
    domain:
    - name: "vagrant@vagrant"
      ssh_options:
      - "-F"
      - "scenarios/setup/vagrant/ssh_config"
    deploy_to: "/opt/deploy/target/project"
    repository: "git://wd-git.example.com/project.git"
    deploy_config_to: "/opt/deploy/target/config"
    config_repository: "git://wd-git.example.com/config.git"
    branch: "hook_with_changed"
  "with_ssh_options":
    domain:
    - name: "vagrant@vagrant"
      ssh_options:
      - "-F"
      - "scenarios/setup/vagrant/ssh_config"
      - "-t"
      - "-v"
    deploy_to: "/tmp/wd-integration-target/destination/project"
    repository: "git://wd-git.example.com/project.git"



================================================
FILE: scenarios/setup/vagrant/.gitignore
================================================
ssh_config
.vagrant
deployed


================================================
FILE: scenarios/setup/vagrant/Vagrantfile
================================================
Vagrant::Config.run do |config|
  config.vm.box = "base"
  config.vm.share_folder "deployment", "/opt/deploy", "deployed"
  config.vm.share_folder "wd_lib", "/opt/lib", "../../../lib"

  config.vm.provision :puppet do |puppet|
    puppet.manifests_path = "manifests"
    puppet.manifest_file = "integration.pp"
  end
end


================================================
FILE: scenarios/setup/vagrant/manifests/integration.pp
================================================
file { '/etc/motd':
  content => "Welcome to your Vagrant-built virtual machine! Managed by Puppet.\n"
}

file { '/opt/deploy/target':
  ensure => directory,
  owner => 'vagrant',
  group => 'vagrant',
  mode => '775'
}

file { '/home/vagrant/.bashrc':
  ensure => 'present',
  owner => 'vagrant',
  group => 'vagrant',
  mode => '755',
  content => 'RUBYLIB="/opt/lib"; export RUBYLIB'
}

host {'host':
  ensure       => 'present',
  host_aliases => 'wd-git.example.com',
  ip           => '10.0.2.2',
}

package {'git-core':
  ensure       => 'latest'
}

package {'rake':
  ensure       => 'latest'
}


================================================
FILE: scenarios/setup/vagrant/pids/.gitignore
================================================
*.pid


================================================
FILE: spec/.bacon
================================================


================================================
FILE: spec/init_spec.rb
================================================
require File.expand_path(File.join(File.dirname(__FILE__), 'spec_helper.rb'))
require 'rake'

describe 'when the init.rb plugin loader has been included' do
  it 'loads the main library' do
    require(File.expand_path(File.join(File.dirname(__FILE__), '..', 'init')))
    $".should.include(File.expand_path(File.join(File.dirname(__FILE__), '..', 'lib', 'whiskey_disk.rb')))
  end
end


================================================
FILE: spec/install_spec.rb
================================================
require File.expand_path(File.join(File.dirname(__FILE__), 'spec_helper'))

def do_install
  eval File.read(File.join(File.dirname(__FILE__), *%w[.. install.rb ]))
end

describe 'the plugin install.rb script' do
  before do
    self.stub!(:puts).and_return(true)
  end
  
  it 'displays the content of the plugin README file' do
    self.stub!(:readme_contents).and_return('README CONTENTS')
    self.should.receive(:puts).with('README CONTENTS')
    do_install
  end
  
  describe 'readme_contents' do
    it 'works without arguments' do
      do_install
      lambda { readme_contents }.should.not.raise(ArgumentError)
    end
    
    it 'accepts no arguments' do
      do_install
      lambda { readme_contents(:foo) }.should.raise(ArgumentError)
    end
    
    it 'reads the plugin README file' do
      do_install
      File.stub!(:join).and_return('/path/to/README')
      IO.should.receive(:read).with('/path/to/README')
      readme_contents
    end
    
    it 'returns the contents of the plugin README file' do
      do_install
      File.stub!(:join).and_return('/path/to/README')
      IO.stub!(:read).with('/path/to/README').and_return('README CONTENTS')
      readme_contents.should == 'README CONTENTS'
    end
  end
end

================================================
FILE: spec/integration/branch_switching_spec.rb
================================================
require File.expand_path(File.join(File.dirname(__FILE__), '..', 'spec_helper.rb'))
require File.expand_path(File.join(File.dirname(__FILE__), '..', '..', 'lib', 'whiskey_disk'))

integration_spec do
  describe 'when configured for a remote deployment' do
    before do
      setup_deployment_area
    end
  
    describe 'and deploying on a different branch than originally deployed' do
      before do
        @config = scenario_config('remote/deploy.yml')
        @args = "--path=#{@config} --to=project:remote"
        run_setup(@args)
        run_deploy(@args)

        @args = "--path=#{@config} --to=project:remote-on-other-branch"
        File.unlink(deployed_file('project/README'))  # modify the deployed checkout
      end
      
      it 'updates the checkout of the repository on the target path' do
        run_deploy(@args)
        File.exists?(deployed_file('project/README')).should == true
      end    

      it 'has the working copy set to the new branch' do
        run_deploy(@args)
        current_branch('project').should == 'no_rake_hooks'
      end

      it 'reports the remote deployment as successful' do
        run_deploy(@args)
        File.read(integration_log).should =~ /vagrant => succeeded/
      end

      it 'exits with a true status' do
        run_deploy(@args).should == true
      end
    end
  end
end

================================================
FILE: spec/integration/deployment_failures_spec.rb
================================================
require File.expand_path(File.join(File.dirname(__FILE__), '..', 'spec_helper.rb'))
require File.expand_path(File.join(File.dirname(__FILE__), '..', '..', 'lib', 'whiskey_disk'))

integration_spec do  
  describe 'when specified project cannot be found in the configuration' do
    before do
      setup_deployment_area
      
      @config = scenario_config('remote/deploy.yml')
      @args = "--path=#{@config} --to=bogus:remote"
    end

    describe 'and performing a setup' do
      it 'does not checkout a repository for the project to the target path' do
        run_setup(@args)
        File.exists?(deployed_file('bogus')).should == false
      end
      
      it 'does not checkout a repository for any project in the configuration file to the target path' do
        run_setup(@args)
        File.exists?(deployed_file('project')).should == false
      end
      
      it 'includes a helpful error message' do
        run_setup(@args)
        File.read(integration_log).should =~ /No configuration file defined data for project `bogus`/
      end
      
      it 'exits with a false status' do
        run_setup(@args).should == false
      end
    end

    describe 'and performing a deployment' do
      before do
        checkout_repo('project')
        File.unlink(deployed_file('project/README'))  # modify the deployed checkout
      end        

      it 'does not checkout a repository for the project to the target path' do
        run_deploy(@args)
        File.exists?(deployed_file('bogus')).should == false
      end
      
      it 'does not update the repository for any project in the configuration file to the target path' do
        run_deploy(@args)
        File.exists?(deployed_file('project/README')).should == false
      end
      
      it 'includes a helpful error message' do
        run_deploy(@args)
        File.read(integration_log).should =~ /No configuration file defined data for project `bogus`/
      end
      
      it 'exits with a false status' do
        run_deploy(@args).should == false
      end
    end
  end
  
  describe 'when specified environment cannot be found in the configuration' do
    before do
      setup_deployment_area
      
      @config = scenario_config('remote/deploy.yml')
      @args = "--path=#{@config} --to=project:bogus"
    end

    describe 'and performing a setup' do
      it 'does not checkout a repository for the project to the target path' do
        run_setup(@args)
        File.exists?(deployed_file('project')).should == false
      end
      
      it 'includes a helpful error message' do
        run_setup(@args)
        File.read(integration_log).should =~ /No configuration file defined data for project `project`, environment `bogus`/
      end
      
      it 'exits with a false status' do
        run_setup(@args).should == false
      end
    end

    describe 'and performing a deployment' do
      before do
        checkout_repo('project')
        File.unlink(deployed_file('project/README'))  # modify the deployed checkout
      end        

      it 'does not update the repository for the project to the target path' do
        run_deploy(@args)
        File.exists?(deployed_file('project/README')).should == false
      end
      
      it 'includes a helpful error message' do
        run_deploy(@args)
        File.read(integration_log).should =~ /No configuration file defined data for project `project`, environment `bogus`/
      end
      
      it 'exits with a false status' do
        run_deploy(@args).should == false
      end
    end
  end
end

================================================
FILE: spec/integration/helper_spec.rb
================================================
require File.expand_path(File.join(File.dirname(__FILE__), '..', 'spec_helper.rb'))
require File.expand_path(File.join(File.dirname(__FILE__), '..', '..', 'lib', 'whiskey_disk'))

integration_spec do
  describe 'when a post_deploy hook uses the changed? method' do
    before do
      setup_deployment_area
      @config = scenario_config('remote/deploy.yml')
      @args = "--path=#{@config} --to=project:hook_with_changed"
    end

    describe 'and performing a setup' do
      it 'performs a checkout of the repository to the target path' do
        run_setup(@args)
        File.exists?(deployed_file('project/README')).should == true
      end

      it 'considers all files changed, running any actions guarded by #changed?' do
        run_setup(@args)
        File.read(integration_log).should =~ /changed\? was true/
      end

      it 'considers all files changed, including by rsync, running any actions guarded by #changed?' do
        run_setup(@args)
        File.read(integration_log).should =~ /changed\? by rsync was true/
      end

      it 'considers all files changed, not running any actions guarded by ! #changed?' do
        run_setup(@args)
        File.read(integration_log).should.not =~ /changed\? was false/
      end

      it 'considers all files changed, including by rsync not running any actions guarded by ! #changed?' do
        run_setup(@args)
        File.read(integration_log).should.not =~ /changed\? by rsync was false/
      end

      it 'reports the remote setup as successful' do
        run_setup(@args)
        File.read(integration_log).should =~ /vagrant => succeeded/
      end

      it 'exits with a true status' do
        run_setup(@args).should == true
      end
    end

    describe 'and performing a deployment' do
      before do
        checkout_repo('project', 'hook_with_changed')
        checkout_repo('config')
        jump_to_initial_commit('project') # reset the deployed checkout
      end

      it 'updates the repo checkout' do
        run_deploy(@args)
        File.exists?(deployed_file('project/README')).should == true
      end

      it 'runs actions contingent on file changes' do
        run_deploy(@args)
        File.read(integration_log).should =~ /changed\? was true/
      end

      it 'runs actions contingent on rsync file changes' do
        run_deploy(@args)
        File.read(integration_log).should =~ /changed\? by rsync was true/
      end

      it 'does not run actions contingent upon files not changing' do
        run_deploy(@args)
        File.read(integration_log).should =~ /changed\? was false/
      end

      it 'does not run actions contingent upon rsync files not changing' do
        run_deploy(@args)
        File.read(integration_log).should =~ /changed\? by rsync was false/
      end

      it 'exits with a true status' do
        run_deploy(@args).should == true
      end

      it 'reports the deployment as successful' do
        run_deploy(@args)
        File.read(integration_log).should =~ /vagrant => succeeded/
      end
    end
  end
end

================================================
FILE: spec/integration/invalid_configuration_spec.rb
================================================
require File.expand_path(File.join(File.dirname(__FILE__), '..', 'spec_helper.rb'))
require File.expand_path(File.join(File.dirname(__FILE__), '..', '..', 'lib', 'whiskey_disk'))

integration_spec do
  describe 'when an invalid configuration file is specified' do
    before do
      setup_deployment_area
      @config = scenario_config('invalid/deploy.yml')
      @args = "--path=#{@config} --to=project:invalid"
    end
    
    describe 'performing a setup' do
      it 'exits with a false status' do
        run_setup(@args).should == false
      end
      
      it 'does not create a repo checkout' do
        run_setup(@args)
        File.exists?(deployed_file('project')).should == false
      end
    end
  
    describe 'performing a deployment' do
      before do
        checkout_repo('project')
        File.unlink(deployed_file('project/README'))  # modify the deployed checkout
      end

      it 'exits with a false status' do
        run_deploy(@args).should == false
      end      
    
      it 'does not update a repo checkout' do
        run_deploy(@args)
        File.exists?(deployed_file('project/README')).should == false
      end
    end
  end
end

================================================
FILE: spec/integration/local_deployments_spec.rb
================================================
require File.expand_path(File.join(File.dirname(__FILE__), '..', 'spec_helper.rb'))
require File.expand_path(File.join(File.dirname(__FILE__), '..', '..', 'lib', 'whiskey_disk'))

integration_spec do
  describe 'when configured for a local deployment' do
    before do
      setup_deployment_area
    end

    describe 'when the configuration specifies no domain' do
      before do
        @config = scenario_config('local/deploy.yml.erb')
        @args = "--path=#{@config} --to=project:local-default"
      end

      describe 'performing a setup' do
        it 'performs a checkout of the repository to the target path' do
          run_setup(@args)
          File.exists?(deployed_file('project/README')).should == true
        end

        it 'reports the local setup as successful' do
          run_setup(@args)
          File.read(integration_log).should =~ /local => succeeded/
        end

        it 'exits with a true status' do
          run_setup(@args).should == true
        end
      end

      describe 'performing a deployment' do
        before do
          checkout_repo('project')
          File.unlink(deployed_file('project/README'))  # modify the deployed checkout
        end

        it 'updates the checkout of the repository on the target path' do
          run_deploy(@args)
          File.exists?(deployed_file('project/README')).should == true
        end

        it 'reports the local deployment as successful' do
          run_deploy(@args)
          File.read(integration_log).should =~ /local => succeeded/
        end

        it 'exits with a true status' do
          run_deploy(@args).should == true
        end
      end
    end

    describe 'when the configuration specifies a single domain via the "local" keyword' do
      before do
        @config = scenario_config('local/deploy.yml.erb')
        @args = "--path=#{@config} --to=project:local-keyword"
      end

      describe 'performing a setup' do
        it 'performs a checkout of the repository to the target path' do
          run_setup(@args)
          File.exists?(deployed_file('project/README')).should == true
        end

        it 'reports the local setup as successful' do
          run_setup(@args)
          File.read(integration_log).should =~ /local => succeeded/
        end

        it 'exits with a true status' do
          run_setup(@args).should == true
        end
      end

      describe 'performing a deployment' do
        before do
          checkout_repo('project')
          File.unlink(deployed_file('project/README'))  # modify the deployed checkout
        end

        it 'updates the checkout of the repository on the target path' do
          run_deploy(@args)
          File.exists?(deployed_file('project/README')).should == true
        end

        it 'reports the local deployment as successful' do
          run_deploy(@args)
          File.read(integration_log).should =~ /local => succeeded/
        end

        it 'exits with a true status' do
          run_deploy(@args).should == true
        end
      end
    end

    describe 'when the configuration specifies a single domain specified as user@domain, using --only=domain' do
      before do
        @config = scenario_config('local/deploy.yml.erb')
        @args = "--path=#{@config} --to=project:local-user-domain --only=localhost"
      end

      describe 'performing a setup' do
        it 'performs a checkout of the repository to the target path' do
          run_setup(@args)
          File.exists?(deployed_file('project/README')).should == true
        end

        it 'reports the named domain setup as successful' do
          run_setup(@args)
          File.read(integration_log).should =~ /localhost => succeeded/
        end

        it 'exits with a true status' do
          run_setup(@args).should == true
        end
      end

      describe 'performing a deployment' do
        before do
          checkout_repo('project')
          File.unlink(deployed_file('project/README'))  # modify the deployed checkout
        end

        it 'updates the checkout of the repository on the target path' do
          run_deploy(@args)
          File.exists?(deployed_file('project/README')).should == true
        end

        it 'reports the named domain deployment as successful' do
          run_deploy(@args)
          File.read(integration_log).should =~ /localhost => succeeded/
        end

        it 'exits with a true status' do
          run_deploy(@args).should == true
        end
      end
    end

    describe 'when the configuration specifies a single domain without username, using --only=domain' do
      before do
        @config = scenario_config('local/deploy.yml.erb')
        @args = "--path=#{@config} --to=project:local-domain --only=localhost"
      end

      describe 'performing a setup' do
        it 'performs a checkout of the repository to the target path' do
          run_setup(@args)
          File.exists?(deployed_file('project/README')).should == true
        end

        it 'reports the named domain setup as successful' do
          run_setup(@args)
          File.read(integration_log).should =~ /localhost => succeeded/
        end

        it 'exits with a true status' do
          run_setup(@args).should == true
        end
      end

      describe 'performing a deployment' do
        before do
          checkout_repo('project')
          File.unlink(deployed_file('project/README'))  # modify the deployed checkout
        end

        it 'updates the checkout of the repository on the target path' do
          run_deploy(@args)
          File.exists?(deployed_file('project/README')).should == true
        end

        it 'reports the named domain deployment as successful' do
          run_deploy(@args)
          File.read(integration_log).should =~ /localhost => succeeded/
        end

        it 'exits with a true status' do
          run_deploy(@args).should == true
        end
      end
    end

    describe 'when the configuration specifies a single domain which does not match the --only domain' do
      before do
        @config = scenario_config('local/deploy.yml.erb')
        @args = "--path=#{@config} --to=project:local-domain --only=vagrant2"
      end

      describe 'performing a setup' do
        it 'does not perform a checkout of the repository to the target path' do
          run_setup(@args)
          File.exists?(deployed_file('project/README')).should == false
        end

        it 'reports that there were no deployments' do
          run_setup(@args)
          File.read(integration_log).should =~ /No deployments/
        end

        it 'exits with a true status' do
          run_setup(@args).should == true
        end
      end

      describe 'performing a deployment' do
        before do
          checkout_repo('project')
          File.unlink(deployed_file('project/README'))  # modify the deployed checkout
        end

        it 'does not update the checkout of the repository on the target path' do
          run_deploy(@args)
          File.exists?(deployed_file('project/README')).should == false
        end

        it 'reports that there were no deployments' do
          run_deploy(@args)
          File.read(integration_log).should =~ /No deployments/
        end

        it 'exits with a true status' do
          run_deploy(@args).should == true
        end
      end
    end
  end
end

================================================
FILE: spec/integration/post_rake_tasks_spec.rb
================================================
require File.expand_path(File.join(File.dirname(__FILE__), '..', 'spec_helper.rb'))
require File.expand_path(File.join(File.dirname(__FILE__), '..', '..', 'lib', 'whiskey_disk'))

integration_spec do
  describe 'when configured for a remote deployment' do
    before do
      setup_deployment_area
    end
  
    describe 'with no Rakefile in the project' do
      before do
        @config = scenario_config('remote/deploy.yml')
        @args = "--path=#{@config} --to=project:no_rakefile"
      end
      
      describe 'performing a setup' do
        it 'performs a checkout of the repository to the target path' do
          run_setup(@args)
          File.exists?(deployed_file('project/README')).should == true
        end
        
        it 'does not run a deploy:post_setup rake task' do
          run_setup(@args)
          File.read(integration_log).should.not =~ /Running a post_setup task/
        end
            
        it 'reports the remote setup as successful' do
          run_setup(@args)
          File.read(integration_log).should =~ /vagrant => succeeded/
        end

        it 'exits with a true status' do
          run_setup(@args).should == true
        end
      end
      
      describe 'performing a deployment' do
        before do
          checkout_repo('project')
          File.unlink(deployed_file('project/README'))  # modify the deployed checkout
        end
        
        it 'updates the checkout of the repository on the target path' do
          run_deploy(@args)
          File.exists?(deployed_file('project/README')).should == true
        end    

        it 'does not run a deploy:post_deploy rake task' do
          run_deploy(@args)
          File.read(integration_log).should.not =~ /Running a post_deploy task/
        end
            
        it 'reports the remote deployment as successful' do
          run_deploy(@args)
          File.read(integration_log).should =~ /vagrant => succeeded/
        end

        it 'exits with a true status' do
          run_deploy(@args).should == true
        end
      end
    end
    
    describe 'with an unparseable Rakefile in the project' do
      before do
        @config = scenario_config('remote/deploy.yml')
        @args = "--path=#{@config} --to=project:bad_rakefile"
      end
      
      describe 'performing a setup' do
        it 'performs a checkout of the repository to the target path' do
          run_setup(@args)
          File.exists?(deployed_file('project/README')).should == true
        end
        
        it 'does not run a deploy:post_setup rake task' do
          run_setup(@args)
          File.read(integration_log).should.not =~ /Running a post_setup task/
        end
            
        it 'reports the remote setup as a failure' do
          run_setup(@args)
          File.read(integration_log).should =~ /vagrant => failed/
        end

        it 'exits with a false status' do
          run_setup(@args).should == false
        end
      end
      
      describe 'performing a deployment' do
        before do
          checkout_repo('project', 'bad_rakefile')
          File.unlink(deployed_file('project/README'))  # modify the deployed checkout
        end
        
        it 'updates the checkout of the repository on the target path' do
          run_deploy(@args)
          File.exists?(deployed_file('project/README')).should == true
        end    

        it 'does not run a deploy:post_deploy rake task' do
          run_deploy(@args)
          File.read(integration_log).should.not =~ /Running a post_deploy task/
        end
            
        it 'reports the remote deployment as a failure' do
          run_deploy(@args)
          File.read(integration_log).should =~ /vagrant => failed/
        end

        it 'exits with a false status' do
          run_deploy(@args).should == false
        end
      end      
    end
    
    describe 'with a valid Rakefile in the project with no post_setup or post_deploy hooks' do
      before do
        @config = scenario_config('remote/deploy.yml')
        @args = "--path=#{@config} --to=project:no_rake_hooks"
      end
      
      describe 'and doing a setup' do
        it 'performs a checkout of the repository to the target path' do
          run_setup(@args)
          File.exists?(deployed_file('project/README')).should == true
        end
        
        it 'does not run a deploy:post_setup rake task' do
          run_setup(@args)
          File.read(integration_log).should.not =~ /Running a post_setup task/
        end
            
        it 'reports the remote setup as successful' do
          run_setup(@args)
          File.read(integration_log).should =~ /vagrant => succeeded/
        end

        it 'exits with a true status' do
          run_setup(@args).should == true
        end
      end

      describe 'and doing a deploy' do
        before do
          checkout_repo('project', 'no_rake_hooks')
          File.unlink(deployed_file('project/README'))  # modify the deployed checkout
        end
        
        it 'updates the checkout of the repository on the target path' do
          run_deploy(@args)
          File.exists?(deployed_file('project/README')).should == true
        end    

        it 'does not run a deploy:post_deploy rake task' do
          run_deploy(@args)
          File.read(integration_log).should.not =~ /Running a post_deploy task/
        end
            
        it 'reports the remote deployment as successful' do
          run_deploy(@args)
          File.read(integration_log).should =~ /vagrant => succeeded/
        end

        it 'exits with a true status' do
          run_deploy(@args).should == true
        end
      end
    end
    
    describe 'with a valid Rakefile in the project with post_setup and post_deploy hooks' do
      before do
        @config = scenario_config('remote/deploy.yml')
        @args = "--path=#{@config} --to=project:with_rake_hooks"
      end
      
      describe 'and doing a setup' do
        it 'performs a checkout of the repository to the target path' do
          run_setup(@args)
          File.exists?(deployed_file('project/README')).should == true
        end
        
        it 'runs a deploy:post_setup rake task' do
          run_setup(@args)
          File.read(integration_log).should =~ /Running a post_setup task/
        end
            
        it 'reports the remote setup as successful' do
          run_setup(@args)
          File.read(integration_log).should =~ /vagrant => succeeded/
        end

        it 'exits with a true status' do
          run_setup(@args).should == true
        end
      end

      describe 'and doing a deploy' do
        before do
          checkout_repo('project', 'post_rake_tasks')
          File.unlink(deployed_file('project/README'))  # modify the deployed checkout
        end
        
        it 'updates the checkout of the repository on the target path' do
          run_deploy(@args)
          File.exists?(deployed_file('project/README')).should == true
        end    

        it 'runs a deploy:post_deploy rake task' do
          run_deploy(@args)
          File.read(integration_log).should =~ /Running a post_deploy task/
        end
            
        it 'reports the remote deployment as successful' do
          run_deploy(@args)
          File.read(integration_log).should =~ /vagrant => succeeded/
        end

        it 'exits with a true status' do
          run_deploy(@args).should == true
        end
      end
    end
  end
end

================================================
FILE: spec/integration/post_scripts_spec.rb
================================================
require File.expand_path(File.join(File.dirname(__FILE__), '..', 'spec_helper.rb'))
require File.expand_path(File.join(File.dirname(__FILE__), '..', '..', 'lib', 'whiskey_disk'))

integration_spec do
  describe 'when configured for a remote deployment' do
    before do
      setup_deployment_area
    end
  
    describe 'with no post_* scripts defined' do
      before do
        @config = scenario_config('remote/deploy.yml')
        @args = "--path=#{@config} --to=project:no_post_scripts"
      end
      
      describe 'performing a setup' do
        it 'performs a checkout of the repository to the target path' do
          run_setup(@args)
          File.exists?(deployed_file('project/README')).should == true
        end
        
        it 'does not run a post_setup script' do
          run_setup(@args)
          File.read(integration_log).should.not =~ /^Running post script/
        end
            
        it 'reports the remote setup as successful' do
          run_setup(@args)
          File.read(integration_log).should =~ /vagrant => succeeded/
        end

        it 'exits with a true status' do
          run_setup(@args).should == true
        end
      end
      
      describe 'performing a deployment' do
        before do
          checkout_repo('project')
          File.unlink(deployed_file('project/README'))  # modify the deployed checkout
        end
        
        it 'updates the checkout of the repository on the target path' do
          run_deploy(@args)
          File.exists?(deployed_file('project/README')).should == true
        end    

        it 'does not run a post_deploy script' do
          run_deploy(@args)
          File.read(integration_log).should.not =~ /^Running post script/
        end
            
        it 'reports the remote deployment as successful' do
          run_deploy(@args)
          File.read(integration_log).should =~ /vagrant => succeeded/
        end

        it 'exits with a true status' do
          run_deploy(@args).should == true
        end
      end
    end
    
    describe 'with missing post_* scripts defined' do
      before do
        @config = scenario_config('remote/deploy.yml')
        @args = "--path=#{@config} --to=project:missing_post_scripts"
      end
      
      describe 'performing a setup' do
        it 'performs a checkout of the repository to the target path' do
          run_setup(@args)
          File.exists?(deployed_file('project/README')).should == true
        end
        
        it 'attempts to run a post_setup script' do
          run_setup(@args)
          File.read(integration_log).should =~ /^Running post script/
        end
        
        it 'passes environment variable settings to the post_setup script' do
          run_setup(@args)
          File.read(integration_log).should =~ /FOO=BAR/
        end
            
        it 'reports the remote setup as a failure' do
          run_setup(@args)
          File.read(integration_log).should =~ /vagrant => failed/
        end

        it 'exits with a false status' do
          run_setup(@args).should == false
        end
      end
      
      describe 'performing a deployment' do
        before do
          checkout_repo('project')
          File.unlink(deployed_file('project/README'))  # modify the deployed checkout
        end
        
        it 'updates the checkout of the repository on the target path' do
          run_deploy(@args)
          File.exists?(deployed_file('project/README')).should == true
        end    

        it 'attempts to run a post_deploy script' do
          run_deploy(@args)
          File.read(integration_log).should =~ /^Running post script/
        end
            
        it 'passes environment variable settings to the post_deploy script' do
          run_deploy(@args)
          File.read(integration_log).should =~ /FOO='BAR'/
        end
            
        it 'reports the remote deployment as a failure' do
          run_deploy(@args)
          File.read(integration_log).should =~ /vagrant => failed/
        end

        it 'exits with a false status' do
          run_deploy(@args).should == false
        end
      end      
    end
    
    describe 'with post_* scripts specified and present' do
      before do
        @config = scenario_config('remote/deploy.yml')
        @args = "--path=#{@config} --to=project:with_post_scripts"
      end
      
      describe 'and doing a setup' do
        it 'performs a checkout of the repository to the target path' do
          run_setup(@args)
          File.exists?(deployed_file('project/README')).should == true
        end
        
        describe 'and the post_setup script is successful' do
          it 'runs the post_setup script' do
            run_setup(@args)
            File.read(integration_log).should =~ /^Running the post_setup script/
          end

          it 'passes environment variable settings to the post_setup script' do
            run_setup(@args)
            File.read(integration_log).should =~ /FOO=BAR/
          end

          it 'reports the remote setup as successful' do
            run_setup(@args)
            File.read(integration_log).should =~ /vagrant => succeeded/
          end

          it 'exits with a true status' do
            run_setup(@args).should == true
          end          
        end
        
        describe 'and the post_setup script fails' do
          before do
            @args = "--path=#{@config} --to=project:with_failing_post_scripts"
          end
          
          it 'runs the post_setup script' do
            run_setup(@args)
            File.read(integration_log).should =~ /^Running the post_setup script/
          end

          it 'passes environment variable settings to the post_setup script' do
            run_setup(@args)
            File.read(integration_log).should =~ /FOO=BAR/
          end

          it 'reports the remote setup as a failure' do
            run_setup(@args)
            File.read(integration_log).should =~ /vagrant => failed/
          end

          it 'exits with a false status' do
            run_setup(@args).should == false
          end          
        end
      end

      describe 'and doing a deploy' do
        before do
          checkout_repo('project')
          File.unlink(deployed_file('project/README'))  # modify the deployed checkout
        end
        
        it 'updates the checkout of the repository on the target path' do
          run_deploy(@args)
          File.exists?(deployed_file('project/README')).should == true
        end    

        describe 'and the post_deploy script is successful' do
          it 'runs the post_deploy script' do
            run_deploy(@args)
            File.read(integration_log).should =~ /^Running the post_deploy script/
          end

          it 'passes environment variable settings to the post_deploy script' do
            run_deploy(@args)
            File.read(integration_log).should =~ /FOO='BAR'/
          end

          it 'reports the remote deployment as successful' do
            run_deploy(@args)
            File.read(integration_log).should =~ /vagrant => succeeded/
          end

          it 'exits with a true status' do
            run_deploy(@args).should == true
          end          
        end
        
        describe 'and the post_deploy script fails' do
          before do
            @args = "--path=#{@config} --to=project:with_failing_post_scripts"
          end
          
          it 'runs the post_deploy script' do
            run_deploy(@args)
            File.read(integration_log).should =~ /^Running the post_deploy script/
          end

          it 'passes environment variable settings to the post_deploy script' do
            run_deploy(@args)
            File.read(integration_log).should =~ /FOO='BAR'/
          end

          it 'reports the remote deployment as a failure' do
            run_deploy(@args)
            File.read(integration_log).should =~ /vagrant => failed/
          end

          it 'exits with a false status' do
            run_deploy(@args).should == false
          end          
        end
      end
    end
  end
end

================================================
FILE: spec/integration/remote_deployments_spec.rb
================================================
require File.expand_path(File.join(File.dirname(__FILE__), '..', 'spec_helper.rb'))
require File.expand_path(File.join(File.dirname(__FILE__), '..', '..', 'lib', 'whiskey_disk'))

integration_spec do
  describe 'when configured for a remote deployment' do
    before do
      setup_deployment_area
    end

    describe 'with a single remote domain' do
      before do
        @config = scenario_config('remote/deploy.yml')
        @args = "--path=#{@config} --to=project:remote"
      end

      describe 'performing a setup' do
        it 'performs a checkout of the repository to the target path' do
          run_setup(@args)
          File.exists?(deployed_file('project/README')).should == true
        end

        it 'has the working copy set to the master branch' do
          run_setup(@args)
          current_branch('project').should == 'master'
        end

        it 'has the working copy set to the specified branch when one is available' do
          @args = "--path=#{@config} --to=project:remote-on-other-branch"
          run_setup(@args)
          current_branch('project').should == 'no_rake_hooks'
        end

        it 'reports the remote setup as successful' do
          run_setup(@args)
          File.read(integration_log).should =~ /vagrant => succeeded/
        end

        it 'exits with a true status' do
          run_setup(@args).should == true
        end
      end

      describe 'performing a deployment' do
        before do
          checkout_repo('project')
          File.unlink(deployed_file('project/README'))  # modify the deployed checkout
        end

        it 'updates the checkout of the repository on the target path' do
          run_deploy(@args)
          File.exists?(deployed_file('project/README')).should == true
        end

        it 'has the working copy set to the master branch' do
          run_deploy(@args)
          current_branch('project').should == 'master'
        end

        it 'has the working copy set to the specified branch when one is available' do
          @args = "--path=#{@config} --to=project:remote-on-other-branch"
          checkout_branch('project', 'no_rake_hooks')
          run_deploy(@args)
          current_branch('project').should == 'no_rake_hooks'
        end

        it 'reports the remote deployment as successful' do
          run_deploy(@args)
          File.read(integration_log).should =~ /vagrant => succeeded/
        end

        it 'exits with a true status' do
          run_deploy(@args).should == true
        end
      end

      describe 'performing a deploy after a setup' do
        describe 'and using the master branch' do
          before do
            run_setup(@args)
            File.unlink(deployed_file('project/README'))  # modify the deployed checkout
          end

          it 'updates the checkout of the repository on the target path' do
            run_deploy(@args)
            File.exists?(deployed_file('project/README')).should == true
          end

          it 'has the working copy set to the master branch' do
            run_deploy(@args)
            current_branch('project').should == 'master'
          end

          it 'has the working copy set to the specified branch when one is available' do
            setup_deployment_area

            @args = "--path=#{@config} --to=project:remote-on-other-branch"
            run_setup(@args)

            File.unlink(deployed_file('project/README'))

            run_deploy(@args)
            current_branch('project').should == 'no_rake_hooks'
          end

          it 'reports the remote deployment as successful' do
            run_deploy(@args)
            File.read(integration_log).should =~ /vagrant => succeeded/
          end

          it 'exits with a true status' do
            run_deploy(@args).should == true
          end
        end
      end
    end

    describe 'with ssh options specified' do
      before do
        @config = scenario_config('remote/deploy.yml')
        @args = "--path=#{@config} --to=project:with_ssh_options"
      end

      describe 'performing a setup' do
        # TODO FIXME -- this spec fails due to interplay between STDOUT and file buffering in ruby system() (*WTF*)
        #
        # it 'uses specified ssh options when performing the setup' do
        #   run_setup(@args)
        #   dump_log
        #   File.read(integration_log).should =~ /ssh.* -t /
        # end

        it 'reports the remote setup as successful' do
          run_setup(@args)
          File.read(integration_log).should =~ /vagrant => succeeded/
        end

        it 'exits with a true status' do
          run_setup(@args).should == true
        end
      end

      describe 'performing a deployment' do
        before do
          checkout_repo('project')
          File.unlink(deployed_file('project/README'))  # modify the deployed checkout
        end

        # TODO FIXME -- this spec fails due to interplay between STDOUT and file buffering in ruby system() (*WTF*)
        #
        # it 'uses specified ssh options when performing the setup' do
        #   run_deploy(@args, true)
        #   File.read(integration_log).should =~ /ssh.* -t /
        # end

        it 'reports the remote deployment as successful' do
          run_deploy(@args)
          File.read(integration_log).should =~ /vagrant => succeeded/
        end

        it 'exits with a true status' do
          run_deploy(@args).should == true
        end
      end
    end
  end
end

================================================
FILE: spec/integration/staleness_checks_spec.rb
================================================
require File.expand_path(File.join(File.dirname(__FILE__), '..', 'spec_helper.rb'))
require File.expand_path(File.join(File.dirname(__FILE__), '..', '..', 'lib', 'whiskey_disk'))

integration_spec do
  describe 'when configured for a local deployment' do
    before do
      setup_deployment_area
      @config = scenario_config('local/deploy.yml.erb')
    end

    describe 'when staleness checkes are enabled' do
      before do
        @args = "--path=#{@config} --to=project:local-default --check"
      end

      describe 'performing a deployment' do
        before do
          checkout_repo('project')
          File.unlink(deployed_file('project/README'))  # modify the deployed checkout
        end

        it 'does not update the checkout of the repository on the target path' do
          run_deploy(@args)
          File.exists?(deployed_file('project/README')).should == false
        end

        it 'reports the local deployment as successful' do
          run_deploy(@args)
          File.read(integration_log).should =~ /local => succeeded/
        end

        it 'exits with a true status' do
          run_deploy(@args).should == true
        end
      end
    end
  end

  describe 'when configured for a remote deployment' do
    before do
      setup_deployment_area
      @config = scenario_config('remote/deploy.yml')
    end

    describe 'when staleness checkes are enabled' do
      before do
        @args = "--path=#{@config} --to=project:remote --check"
      end

      describe 'performing a deployment' do
        before do
          checkout_repo('project')
          File.unlink(deployed_file('project/README'))  # modify the deployed checkout
        end

        it 'does not update the checkout of the repository on the target path' do
          run_deploy(@args)
          File.exists?(deployed_file('project/README')).should == false
        end

        it 'reports the local deployment as successful' do
          run_deploy(@args)
          File.read(integration_log).should =~ /vagrant => succeeded/
        end

        it 'exits with a true status' do
          run_deploy(@args).should == true
        end
      end
    end
  end
end

================================================
FILE: spec/spec_helper.rb
================================================
require 'rubygems'
require 'bacon'
require 'facon'
require 'fileutils'
require 'tempfile'
require 'erb'

if ENV['DEBUG'] and ENV['DEBUG'] != ''
  STDERR.puts "Enabling debugger for spec runs..."
  require 'rubygems'
  require 'ruby-debug'
  Debugger.start
end

$:.unshift(File.expand_path(File.join(File.dirname(__FILE__), '..', 'lib')))

# local target directory, integration spec workspace
def deployment_root
  File.expand_path(File.join(File.dirname(__FILE__), '..', 'scenarios', 'setup', 'vagrant', 'deployed', 'target'))
end

# allow defining an integration spec block
def integration_spec(&block)
  yield if ENV['INTEGRATION'] and ENV['INTEGRATION'] != ''
end

# reset the deployment directory for integration specs
def setup_deployment_area
  FileUtils.rm_rf(deployment_root)
  File.umask(0)
  Dir.mkdir(deployment_root, 0777)
  Dir.mkdir(deployed_file('log'), 0777)
end

# run a wd setup using the provided arguments string
def run_setup(arguments, debugging = true)
  wd_path  = File.join(File.dirname(__FILE__), '..', 'bin', 'wd')
  lib_path = File.join(File.dirname(__FILE__), '..', 'lib')
  debug = debugging ? '--debug' : ''
  system("/usr/bin/env ruby -I #{lib_path} -r whiskey_disk -rubygems #{wd_path} setup #{debug} #{arguments} > #{integration_log} 2> #{integration_log}")
end

def integration_log
  deployed_file('log/out.txt')
end

# run a wd setup using the provided arguments string
def run_deploy(arguments, debugging = true)
  wd_path  = File.join(File.dirname(__FILE__), '..', 'bin', 'wd')
  lib_path = File.join(File.dirname(__FILE__), '..', 'lib')
  debug = debugging ? '--debug' : ''
  status = system("/usr/bin/env ruby -I #{lib_path} -r whiskey_disk -rubygems #{wd_path} deploy #{debug} #{arguments} > #{integration_log} 2> #{integration_log}")
  status
end

# build the correct local path to the deployment configuration for a given scenario
def scenario_config(path)
  return erb_scenario_config(path) if path =~ /\.erb$/
  scenario_config_path(path)
end

def scenario_config_path(path)
  File.join(File.dirname(__FILE__), '..', 'scenarios', path)
end

def erb_scenario_config(path)
  data = File.read(scenario_config_path(path))
  converted = erb_eval(data)
  write_tempfile(converted)
end

def erb_eval(data)
  ERB.new(data).result
end

def write_tempfile(data)
  tmp_file = Tempfile.new('whiskey_disk_integration_spec_scenario')
  tmp_file.puts(data)
  tmp_file.close
  tmp_file.path
end

# clone a git repository locally (as if a "wd setup" had been deployed)
def checkout_repo(repo_name, branch = nil)
  repo_path = File.expand_path(File.join(File.dirname(__FILE__), '..', 'scenarios', 'git_repositories', "#{repo_name}.git"))
  system("cd #{deployment_root} && git clone #{repo_path} >/dev/null 2>/dev/null && cd #{repo_name} && git remote set-url origin #{remote_url(repo_name)}")
  checkout_branch(repo_name, branch)
end

def remote_url(repo)
  "git://wd-git.example.com/#{repo}.git"
end

def checkout_branch(repo_name, branch = nil)
  return unless branch
  system("cd #{deployment_root}/#{repo_name} && git checkout #{branch} >/dev/null 2>/dev/null")
end

def jump_to_initial_commit(path)
  system(%Q(cd #{File.join(deployment_root, path)} && git reset --hard `git log --oneline | tail -1 | awk '{print $1}'` >/dev/null 2>/dev/null))
end

def run_log
  File.readlines(integration_log)
end

def deployed_file(path)
  File.join(deployment_root, path)
end

def dump_log
  STDERR.puts("\n\n\n" + File.read(integration_log) + "\n\n\n")
end

def current_branch(path)
  `cd #{deployed_file(path)} && git branch`.split("\n").grep(/^\*/).first.sub(/^\* /, '')
end

================================================
FILE: spec/wd_command_spec.rb
================================================
require_relative('spec_helper.rb')
require 'rake'

def run_command
  cmd_path = File.expand_path(File.join(File.dirname(__FILE__), *%w[.. bin wd]))
  path = File.expand_path(File.dirname(cmd_path))
  file = File.read(cmd_path)

  Dir.chdir(path) do |path|
    eval(file)
  end
end

describe 'wd command' do
  before do
    @stderr, @stdout, $stderr, $stdout = $stderr, $stdout, StringIO.new, StringIO.new
    ENV['to'] = ENV['path'] = nil
  end

  after do
    @stderr, @stdout, $stderr, $stdout = $stderr, $stdout, @stderr, @stdout
  end
  
  describe 'when no command-line arguments are specified' do
    before do
      Object.send(:remove_const, :ARGV)
      ARGV = []
    end  
    
    it 'does not run rake tasks' do
      Rake::Application.should.receive(:new).never
      lambda { run_command }
    end
  
    it 'exits' do
      lambda { run_command }.should.raise(SystemExit)
    end
    
    it 'exits with a failure status' do
      begin
        run_command
      rescue Exception => e
        e.success?.should == false
      end
    end
  end

  it 'outputs usage without a backtrace when --help is specified' do
    Object.send(:remove_const, :ARGV)
    ARGV = ['--help']
    lambda { run_command }.should.raise(SystemExit)
  end
  
  it 'outputs usage without a backtrace when garbage options are specified' do
    Object.send(:remove_const, :ARGV)
    ARGV = ['--slkjfsdflkj']
    lambda { run_command }.should.raise(SystemExit)
  end
  
  describe 'when --version argument is specified' do
    before do
      Object.send(:remove_const, :ARGV)
      ARGV = ['--version']
    end
  
    # it 'outputs the version stored in the VERSION file' do
    #   version = File.read(File.expand_path(File.join(File.dirname(__FILE__), '..', 'VERSION'))).chomp
    #   # TODO: capture version output
    #   lambda{ run_command }
    # end
  
    it 'exits' do
      lambda { run_command }.should.raise(SystemExit)
    end
  
    it 'exits successfully' do
      begin
        run_command
      rescue SystemExit => e
        e.success?.should == true
      end
    end
  end

  describe "when the 'setup' command is specified" do
    before do
      Object.send(:remove_const, :ARGV)
      ARGV = ['setup']
    end  

    describe 'and no target is specified' do    
      it 'does not run rake tasks' do
        Rake::Application.should.receive(:new).never
        lambda { run_command }
      end

      it 'exits when a target is specified' do
        lambda { run_command }.should.raise(SystemExit)
      end

      it 'exits with a failing status when a target is specified' do
        begin
          run_command
        rescue SystemExit => e
          e.success?.should == false
        end
      end
    end

    
    describe 'and a --to argument is specified' do
      before do
        ARGV.push '--to=foo'
        @rake = Rake::Task['deploy:setup']
        @rake.stub!(:invoke)
      end
      
      it 'does not fail' do
        lambda { run_command }.should.not.raise
      end
      
      it 'runs the deploy:setup rake task' do
        @rake.should.receive(:invoke)
        run_command
      end
      
      it 'makes the specified target available as a "to" argument to the rake task' do
        run_command
        ENV['to'].should == 'foo'
      end
      
      describe 'and a --path argument is specified' do
        before do
          ARGV.push '--path=/path/to/foo'
        end
        
        it 'makes the specified path available as a "path" argument to the rake task' do
          run_command
          ENV['path'].should == '/path/to/foo'
        end
      
        it 'fails if the rake task fails' do
          @rake.stub!(:invoke).and_raise(RuntimeError)
          lambda { run_command }.should.raise
        end
      
        it 'does not fail if the rake task succeeds' do
          @rake.stub!(:invoke).and_return(true)
          lambda { run_command }.should.not.raise
        end
      end
      
      describe 'and a -p argument is specified' do
        before do
          ARGV.push '-p'
          ARGV.push '/path/to/foo'
        end
        
        it 'makes the specified path available as a "path" argument to the rake task' do
          run_command
          ENV['path'].should == '/path/to/foo'
        end
      
        it 'fails if the rake task fails' do
          @rake.stub!(:invoke).and_raise(RuntimeError)
          lambda { run_command }.should.raise
        end
      
        it 'does not fail if the rake task succeeds' do
          @rake.stub!(:invoke).and_return(true)
          lambda { run_command }.should.not.raise
        end
      end
      
      describe 'and no --path or -p argument is specified' do
        it 'does not make a "path" argument available to the rake task' do
          ENV['path'].should.be.nil
        end
      
        it 'fails if the rake task fails' do
          @rake.stub!(:invoke).and_raise(RuntimeError)
          lambda { run_command }.should.raise
        end
      
        it 'does not fail if the rake task succeeds' do
          @rake.stub!(:invoke).and_return(true)
          lambda { run_command }.should.not.raise
        end
      end

      describe 'and a --only argument is specified' do
        before do
          @domain = 'smeghost'
          ARGV.push "--only=#{@domain}"
        end

        it 'makes the specified domain available as an "only" argument to the rake task' do
          run_command
          ENV['only'].should == @domain
        end

        it 'fails if the rake task fails' do
          @rake.stub!(:invoke).and_raise(RuntimeError)
          lambda { run_command }.should.raise
        end

        it 'does not fail if the rake task succeeds' do
          @rake.stub!(:invoke).and_return(true)
          lambda { run_command }.should.not.raise
        end
      end

      describe 'and a -o argument is specified' do
        before do
          @domain = 'smeghost'
          ARGV.push '-o'
          ARGV.push @domain
        end

        it 'makes the specified domain available as an "only" argument to the rake task' do
          run_command
          ENV['only'].should == @domain
        end

        it 'fails if the rake task fails' do
          @rake.stub!(:invoke).and_raise(RuntimeError)
          lambda { run_command }.should.raise
        end

        it 'does not fail if the rake task succeeds' do
          @rake.stub!(:invoke).and_return(true)
          lambda { run_command }.should.not.raise
        end
      end

      describe 'and no --only or -o argument is specified' do
        it 'does not make an "only" argument available to the rake task' do
          run_command
          ENV['only'].should.be.nil
        end

        it 'fails if the rake task fails' do
          @rake.stub!(:invoke).and_raise(RuntimeError)
          lambda { run_command }.should.raise
        end

        it 'does not fail if the rake task succeeds' do
          @rake.stub!(:invoke).and_return(true)
          lambda { run_command }.should.not.raise
        end
      end

      describe 'and a --debug argument is specified' do
        before do
          ARGV.push '--debug'
        end

        it 'runs the deploy:now rake task' do
          @rake.should.receive(:invoke)
          run_command
        end

        it 'makes the specified target available as a "debug" argument to the rake task' do
          run_command
          ENV['debug'].should == 'true'
        end

        it 'fails if the rake task fails' do
          @rake.stub!(:invoke).and_raise(RuntimeError)
          lambda { run_command }.should.raise
        end

        it 'does not fail if the rake task succeeds' do
          @rake.stub!(:invoke).and_return(true)
          lambda { run_command }.should.not.raise
        end
      end
      
      describe 'and a -d argument is specified' do
        before do
          ARGV.push '-d'
        end

        it 'runs the deploy:now rake task' do
          @rake.should.receive(:invoke)
          run_command
        end

        it 'makes the specified target available as a "debug" argument to the rake task' do
          run_command
          ENV['debug'].should == 'true'
        end

        it 'fails if the rake task fails' do
          @rake.stub!(:invoke).and_raise(RuntimeError)
          lambda { run_command }.should.raise
        end

        it 'does not fail if the rake task succeeds' do
          @rake.stub!(:invoke).and_return(true)
          lambda { run_command }.should.not.raise
        end
      end

      describe 'and no --debug or -d argument is specified' do
        it 'does not make a "debug" argument available to the rake task' do
          run_command
          ENV['debug'].should.be.nil
        end

        it 'runs the deploy:now rake task' do
          @rake.should.receive(:invoke)
          run_command
        end

        it 'fails if the rake task fails' do
          @rake.stub!(:invoke).and_raise(RuntimeError)
          lambda { run_command }.should.raise
        end

        it 'does not fail if the rake task succeeds' do
          @rake.stub!(:invoke).and_return(true)
          lambda { run_command }.should.not.raise
        end
      end
    end

    describe 'and a -t argument is specified' do
      before do
        ARGV.push '-t'
        ARGV.push 'foo'
        @rake = Rake::Task['deploy:setup']
        @rake.stub!(:invoke)
      end

      it 'does not fail' do
        lambda { run_command }.should.not.raise
      end

      it 'runs the deploy:setup rake task' do
        @rake.should.receive(:invoke)
        run_command
      end

      it 'makes the specified target available as a "to" argument to the rake task' do
        run_command
        ENV['to'].should == 'foo'
      end

      describe 'and a --path argument is specified' do
        before do
          ARGV.push '--path=/path/to/foo'
        end
        
        it 'makes the specified path available as a "path" argument to the rake task' do
          run_command
          ENV['path'].should == '/path/to/foo'
        end
      
        it 'fails if the rake task fails' do
          @rake.stub!(:invoke).and_raise(RuntimeError)
          lambda { run_command }.should.raise
        end
      
        it 'does not fail if the rake task succeeds' do
          @rake.stub!(:invoke).and_return(true)
          lambda { run_command }.should.not.raise
        end
      end
      
      describe 'and a -p argument is specified' do
        before do
          ARGV.push '-p'
          ARGV.push '/path/to/foo'
        end
        
        it 'makes the specified path available as a "path" argument to the rake task' do
          run_command
          ENV['path'].should == '/path/to/foo'
        end
      
        it 'fails if the rake task fails' do
          @rake.stub!(:invoke).and_raise(RuntimeError)
          lambda { run_command }.should.raise
        end
      
        it 'does not fail if the rake task succeeds' do
          @rake.stub!(:invoke).and_return(true)
          lambda { run_command }.should.not.raise
        end
      end
      
      describe 'and no --path or -p argument is specified' do
        it 'does not make a "path" argument available to the rake task' do
          ENV['path'].should.be.nil
        end
      
        it 'fails if the rake task fails' do
          @rake.stub!(:invoke).and_raise(RuntimeError)
          lambda { run_command }.should.raise
        end
      
        it 'does not fail if the rake task succeeds' do
          @rake.stub!(:invoke).and_return(true)
          lambda { run_command }.should.not.raise
        end
      end

      describe 'and a --only argument is specified' do
        before do
          @domain = 'smeghost'
          ARGV.push "--only=#{@domain}"
        end

        it 'makes the specified domain available as an "only" argument to the rake task' do
          run_command
          ENV['only'].should == @domain
        end

        it 'fails if the rake task fails' do
          @rake.stub!(:invoke).and_raise(RuntimeError)
          lambda { run_command }.should.raise
        end

        it 'does not fail if the rake task succeeds' do
          @rake.stub!(:invoke).and_return(true)
          lambda { run_command }.should.not.raise
        end
      end

      describe 'and a -o argument is specified' do
        before do
          @domain = 'smeghost'
          ARGV.push '-o'
          ARGV.push @domain
        end

        it 'makes the specified domain available as an "only" argument to the rake task' do
          run_command
          ENV['only'].should == @domain
        end

        it 'fails if the rake task fails' do
          @rake.stub!(:invoke).and_raise(RuntimeError)
          lambda { run_command }.should.raise
        end

        it 'does not fail if the rake task succeeds' do
          @rake.stub!(:invoke).and_return(true)
          lambda { run_command }.should.not.raise
        end
      end

      describe 'and no --only or -o argument is specified' do
        it 'does not make an "only" argument available to the rake task' do
          run_command
          ENV['only'].should.be.nil
        end

        it 'fails if the rake task fails' do
          @rake.stub!(:invoke).and_raise(RuntimeError)
          lambda { run_command }.should.raise
        end

        it 'does not fail if the rake task succeeds' do
          @rake.stub!(:invoke).and_return(true)
          lambda { run_command }.should.not.raise
        end
      end
    end
  end
  
  describe "when the 'deploy' command is specified" do
    before do
      Object.send(:remove_const, :ARGV)
      ARGV = ['deploy']
    end  

    describe 'but no target is specified' do
      it 'does not run rake tasks' do
        Rake::Application.should.receive(:new).never
        lambda { run_command }
      end
  
      it 'exits when a target is specified' do
        lambda { run_command }.should.raise(SystemExit)
      end

      it 'exits with a failing status when a target is specified' do
        begin
          run_command
        rescue SystemExit => e
          e.success?.should == false
        end
      end
    end
    
    describe 'and a --to argument is specified' do
      before do
        ARGV.push '--to=foo'
        @rake = Rake::Task['deploy:now']
        @rake.stub!(:invoke)
      end
      
      it 'does not fail' do
        lambda { run_command }.should.not.raise
      end
      
      it 'runs the deploy:now rake task' do
        @rake.should.receive(:invoke)
        run_command
      end
      
      it 'makes the specified target available as a "to" argument to the rake task' do
        run_command
        ENV['to'].should == 'foo'
      end
    
      describe 'and a --check argument is specified' do
        before do
          ARGV.push '--check'
          @rake = Rake::Task['deploy:now']
          @rake.stub!(:invoke)
        end
           
        it 'does not fail' do
          lambda { run_command }.should.not.raise
        end
      
        it 'runs the deploy:now rake task' do
          @rake.should.receive(:invoke)
          run_command
        end
      
        it 'makes the specified target available as a "check" argument to the rake task' do
          run_command
          ENV['check'].should == 'true'
        end
      end

      describe 'and a -c argument is specified' do
        before do
          ARGV.push '-c'
          @rake = Rake::Task['deploy:now']
          @rake.stub!(:invoke)
        end
           
        it 'does not fail' do
          lambda { run_command }.should.not.raise
        end
      
        it 'runs the deploy:now rake task' do
          @rake.should.receive(:invoke)
          run_command
        end
      
        it 'makes the specified target available as a "check" argument to the rake task' do
          run_command
          ENV['check'].should == 'true'
        end
      end

      describe 'and no --check or -c argument is specified' do        
        it 'does not make a "check" argument available to the rake task' do          
          run_command
          ENV['check'].should.be.nil
        end
      
        it 'fails if the rake task fails' do
          @ra
Download .txt
gitextract_l5xymha1/

├── .gitignore
├── CHANGELOG
├── Gemfile
├── MIT-LICENSE
├── README.integration_specs
├── README.markdown
├── Rakefile
├── VERSION
├── WHY.txt
├── bin/
│   ├── wd
│   └── wd_role
├── examples/
│   ├── deploy-configs.yml
│   ├── deploy-local.yml
│   ├── deploy-multiple-remotes.yml
│   ├── deploy-staging.yml
│   ├── deploy.rake
│   └── deploy.yml
├── init.rb
├── install.rb
├── lib/
│   ├── whiskey_disk/
│   │   ├── config/
│   │   │   ├── abstract_filter.rb
│   │   │   ├── filter.rb
│   │   │   └── filters/
│   │   │       ├── add_environment_name_filter.rb
│   │   │       ├── add_project_name_filter.rb
│   │   │       ├── check_for_duplicate_domains_filter.rb
│   │   │       ├── convert_role_strings_to_list_filter.rb
│   │   │       ├── default_config_target_filter.rb
│   │   │       ├── default_domain_filter.rb
│   │   │       ├── drop_empty_domain_roles_filter.rb
│   │   │       ├── environment_scope_filter.rb
│   │   │       ├── hashify_domain_entries_filter.rb
│   │   │       ├── localize_domains_filter.rb
│   │   │       ├── modules/
│   │   │       │   └── scope_helper.rb
│   │   │       ├── normalize_ssh_options_filter.rb
│   │   │       ├── project_scope_filter.rb
│   │   │       ├── select_project_and_environment_filter.rb
│   │   │       └── stringify_hash_keys_filter.rb
│   │   ├── config.rb
│   │   ├── helpers.rb
│   │   └── rake.rb
│   └── whiskey_disk.rb
├── scenarios/
│   ├── git_repositories/
│   │   ├── config.git/
│   │   │   ├── HEAD
│   │   │   ├── config
│   │   │   ├── description
│   │   │   ├── git-daemon-export-ok
│   │   │   ├── hooks/
│   │   │   │   ├── applypatch-msg.sample
│   │   │   │   ├── commit-msg.sample
│   │   │   │   ├── post-commit.sample
│   │   │   │   ├── post-receive.sample
│   │   │   │   ├── post-update.sample
│   │   │   │   ├── pre-applypatch.sample
│   │   │   │   ├── pre-commit.sample
│   │   │   │   ├── pre-rebase.sample
│   │   │   │   ├── prepare-commit-msg.sample
│   │   │   │   └── update.sample
│   │   │   ├── info/
│   │   │   │   └── exclude
│   │   │   ├── objects/
│   │   │   │   ├── 0d/
│   │   │   │   │   └── b14dd6ddc54017c0a11960dcda82ed802cde69
│   │   │   │   ├── 0e/
│   │   │   │   │   └── e781f5ce80d64db32a74a7aae7b5248dafe112
│   │   │   │   ├── 17/
│   │   │   │   │   └── 6bf54cf17d1d1c24556dc059c4144a5df230e8
│   │   │   │   ├── 20/
│   │   │   │   │   └── e9ff3feaa8ede30f707e5f1b4356e3c02bb7ec
│   │   │   │   ├── 45/
│   │   │   │   │   └── 117b1c775f0de415478dbf08ed9d667ab17d13
│   │   │   │   ├── 51/
│   │   │   │   │   └── 3954c9aca090e6ce40359f0e9fde30ea78eb8c
│   │   │   │   ├── 66/
│   │   │   │   │   └── 947a7a11a6f5d3d561fe95de284ced3010819a
│   │   │   │   ├── 6b/
│   │   │   │   │   └── bc79311bfac47d3ed724aa82a4814e0dda4c67
│   │   │   │   ├── 71/
│   │   │   │   │   └── eb5df52676e8e6efba471050b46978173af110
│   │   │   │   ├── 84/
│   │   │   │   │   └── 17d2fe3e8fcc0825249c517b29b0f9ea8b8b31
│   │   │   │   ├── 8b/
│   │   │   │   │   └── 384fcfcf7c0dee7c3c1d5636bee9e645d9cf38
│   │   │   │   ├── bb/
│   │   │   │   │   └── 59da633ba74296b0c2f9ff70784ac155ddb599
│   │   │   │   ├── cc/
│   │   │   │   │   └── b86b26189afbf45d8eb9165812ab86dbdfca63
│   │   │   │   ├── d1/
│   │   │   │   │   └── 0bcd51fec41f854001e4d61f99d9e282a695d3
│   │   │   │   ├── d8/
│   │   │   │   │   └── a8b0f5b1fd66844efb141d9544965ea0065f2d
│   │   │   │   ├── e6/
│   │   │   │   │   └── b02c66ad632e6b8535c4630cb8fe07732a72fc
│   │   │   │   ├── e8/
│   │   │   │   │   └── b8bfeeba735c0a1a873082554cb4d7256ac125
│   │   │   │   └── f9/
│   │   │   │       ├── 0181466a1a60b793ca9cc9abd584c18d4e3887
│   │   │   │       └── 49d5d8a4f12c91471e34d4e277239c35ebd10d
│   │   │   └── refs/
│   │   │       └── heads/
│   │   │           └── master
│   │   └── project.git/
│   │       ├── HEAD
│   │       ├── config
│   │       ├── description
│   │       ├── git-daemon-export-ok
│   │       ├── hooks/
│   │       │   ├── applypatch-msg.sample
│   │       │   ├── commit-msg.sample
│   │       │   ├── post-commit.sample
│   │       │   ├── post-receive.sample
│   │       │   ├── post-update.sample
│   │       │   ├── pre-applypatch.sample
│   │       │   ├── pre-commit.sample
│   │       │   ├── pre-rebase.sample
│   │       │   ├── prepare-commit-msg.sample
│   │       │   └── update.sample
│   │       ├── info/
│   │       │   └── exclude
│   │       ├── objects/
│   │       │   ├── 04/
│   │       │   │   ├── 26e152e66c8cd42974279bdcae09be9839c172
│   │       │   │   └── f4de85eaf72ef1631dc6d7424045c0a749b757
│   │       │   ├── 06/
│   │       │   │   ├── 13fe277280cbcdb2856e1eefc70bdaff011b20
│   │       │   │   └── 7aca89b86265eee211387434c3e50f37ccf009
│   │       │   ├── 09/
│   │       │   │   └── 445dacc4822722612d60833c9948219ecdd8f5
│   │       │   ├── 11/
│   │       │   │   └── c4ec64326de35462f4e79d0f4229bf8e26e0c5
│   │       │   ├── 20/
│   │       │   │   └── 1c7641c2e42b0b904e5c1f793489d8b858e4da
│   │       │   ├── 23/
│   │       │   │   └── 979639da60d2d31e9744468df1c1221b101e64
│   │       │   ├── 27/
│   │       │   │   └── a3fff2c4c45ab5513a405f694c0a042cb5d417
│   │       │   ├── 2c/
│   │       │   │   └── 0c33cfba8e1af15df88522c0db2b10a6a94138
│   │       │   ├── 38/
│   │       │   │   └── b574660305ecb5fec6b2daa7ee1e0dbf1b6003
│   │       │   ├── 4a/
│   │       │   │   └── 57abb5e4e426cfc9101b3af22ac83ccbd8e2ad
│   │       │   ├── 4c/
│   │       │   │   └── 77ebdd985e57afe7988480720c5dc77ec525c9
│   │       │   ├── 51/
│   │       │   │   └── c94da6f1b8aa9d2346088d3d362475b60c7f32
│   │       │   ├── 5b/
│   │       │   │   └── a96acf9cc9b87babe37c032676f53bf1ba9ae7
│   │       │   ├── 5d/
│   │       │   │   └── f555601d60f1c2a84d2364af0ad640612c3ba5
│   │       │   ├── 71/
│   │       │   │   └── 03b5ac94940d596c2160a5cfcd55ca4ccac41f
│   │       │   ├── 73/
│   │       │   │   └── 3fc331098b03523f414f3509b9ae6e637c6866
│   │       │   ├── 80/
│   │       │   │   └── 26076649ceccbe96a6292f2432652f08483035
│   │       │   ├── 86/
│   │       │   │   └── d1ef0976be4567de562224e1b51fbf9820c53a
│   │       │   ├── 87/
│   │       │   │   └── a9d8b09b3401d21b23d90253332d6b28b47db2
│   │       │   ├── 8b/
│   │       │   │   └── 030ba688255c917d189ae3f87d7c5ccd226bc2
│   │       │   ├── 95/
│   │       │   │   ├── c9d5ad9b1c90e4c805516783105fc2037dedeb
│   │       │   │   └── d82d043af35a80eabfd56c0d705abfa3488787
│   │       │   ├── 96/
│   │       │   │   └── 0bf34bb0b46d0aeb0be87f688f4ef06a4b35e1
│   │       │   ├── a3/
│   │       │   │   └── 860106dc1d148c7831cd45ae38829b4ed47702
│   │       │   ├── a8/
│   │       │   │   └── 506d6439b71784a72ac72d284b2ad53088f573
│   │       │   ├── ad/
│   │       │   │   └── 22ea6c7563777936ecfbe50d8e2cf8120fd525
│   │       │   ├── ae/
│   │       │   │   └── 3900de54aff557c61c81146d00f9d38e55a265
│   │       │   ├── bf/
│   │       │   │   ├── 5e3740d52b80abb0378b3f85f93a53b1294521
│   │       │   │   └── b59811cdbc069418dee14b171e6e7e979784b7
│   │       │   ├── cc/
│   │       │   │   └── 5ac0afb24e727d5de344cc26a425f4fb7fd17d
│   │       │   ├── d1/
│   │       │   │   └── 091aa2dd76885108461110c639e6b33a297fce
│   │       │   ├── d8/
│   │       │   │   └── 913f6650eb2b7bf2a633732d8452008ca23dcb
│   │       │   ├── db/
│   │       │   │   └── d1b9667f1b26b13331ac0c321dced8be1aeab0
│   │       │   ├── e4/
│   │       │   │   └── 3b9107e9b1908ce415025e64eb83a493d329b7
│   │       │   ├── ef/
│   │       │   │   └── 2a88894d5421920b9dfe67a9a4d8043830e62e
│   │       │   ├── f4/
│   │       │   │   └── 0123a1ff20c65d8dc15a38a83222647908e6f7
│   │       │   ├── f5/
│   │       │   │   └── 0af315b75ca0b12c720dec6d916b76b968c319
│   │       │   └── f6/
│   │       │       └── 0215709b7b23f3738e9cbaf634b1c86bbd376a
│   │       └── refs/
│   │           └── heads/
│   │               ├── bad_rakefile
│   │               ├── hook_with_changed
│   │               ├── master
│   │               ├── no_rake_hooks
│   │               └── post_rake_tasks
│   ├── invalid/
│   │   └── deploy.yml
│   ├── local/
│   │   └── deploy.yml.erb
│   ├── remote/
│   │   └── deploy.yml
│   └── setup/
│       └── vagrant/
│           ├── .gitignore
│           ├── Vagrantfile
│           ├── manifests/
│           │   └── integration.pp
│           └── pids/
│               └── .gitignore
├── spec/
│   ├── .bacon
│   ├── init_spec.rb
│   ├── install_spec.rb
│   ├── integration/
│   │   ├── branch_switching_spec.rb
│   │   ├── deployment_failures_spec.rb
│   │   ├── helper_spec.rb
│   │   ├── invalid_configuration_spec.rb
│   │   ├── local_deployments_spec.rb
│   │   ├── post_rake_tasks_spec.rb
│   │   ├── post_scripts_spec.rb
│   │   ├── remote_deployments_spec.rb
│   │   └── staleness_checks_spec.rb
│   ├── spec_helper.rb
│   ├── wd_command_spec.rb
│   ├── wd_role_command_spec.rb
│   ├── whiskey_disk/
│   │   ├── config/
│   │   │   ├── filter_spec.rb
│   │   │   └── filters/
│   │   │       ├── add_environment_name_filter_spec.rb
│   │   │       ├── add_project_name_filter_spec.rb
│   │   │       ├── check_for_duplicate_domains_filter_spec.rb
│   │   │       ├── convert_role_strings_to_list_filter_spec.rb
│   │   │       ├── default_config_target_filter_spec.rb
│   │   │       ├── default_domain_filter_spec.rb
│   │   │       ├── drop_empty_domain_roles_filter_spec.rb
│   │   │       ├── environment_scope_filter_spec.rb
│   │   │       ├── hashify_domain_entries_filter_spec.rb
│   │   │       ├── localize_domains_filter_spec.rb
│   │   │       ├── normalize_ssh_options_filter_spec.rb
│   │   │       ├── project_scope_filter_spec.rb
│   │   │       ├── select_project_and_environment_filter_spec.rb
│   │   │       └── stringify_hash_keys_filter_spec.rb
│   │   ├── config_spec.rb
│   │   ├── helpers_spec.rb
│   │   └── rake_spec.rb
│   └── whiskey_disk_spec.rb
├── tasks/
│   └── deploy.rake
└── whiskey_disk.gemspec
Download .txt
SYMBOL INDEX (214 symbols across 28 files)

FILE: install.rb
  function readme_contents (line 1) | def readme_contents

FILE: lib/whiskey_disk.rb
  class WhiskeyDisk (line 3) | class WhiskeyDisk
    method initialize (line 7) | def initialize(options = {})
    method buffer (line 11) | def buffer
    method config (line 15) | def config
    method configuration (line 19) | def configuration
    method debugging? (line 23) | def debugging?
    method setting (line 27) | def setting(key)
    method check_staleness? (line 31) | def check_staleness?
    method staleness_checks_enabled? (line 35) | def staleness_checks_enabled?
    method enqueue (line 39) | def enqueue(command)
    method remote? (line 43) | def remote?(domain)
    method has_config_repo? (line 52) | def has_config_repo?
    method project_name_specified? (line 56) | def project_name_specified?
    method branch (line 60) | def branch
    method config_branch (line 64) | def config_branch
    method env_vars (line 68) | def env_vars
    method parent_path (line 76) | def parent_path(path)
    method tail_path (line 80) | def tail_path(path)
    method needs (line 84) | def needs(*keys)
    method apply_staleness_check (line 90) | def apply_staleness_check(commands)
    method join_commands (line 108) | def join_commands
    method bundle (line 112) | def bundle
    method domain_limit_match? (line 117) | def domain_limit_match?(domain, limit)
    method domain_of_interest? (line 121) | def domain_of_interest?(domain)
    method encode_roles (line 126) | def encode_roles(roles)
    method build_command (line 131) | def build_command(domain, cmd)
    method run (line 135) | def run(domain, cmd)
    method ssh (line 139) | def ssh(domain, cmd)
    method shell (line 150) | def shell(domain, cmd)
    method flush (line 155) | def flush
    method record_result (line 165) | def record_result(domain, status)
    method summarize_results (line 170) | def summarize_results(results)
    method summarize (line 183) | def summarize
    method success? (line 195) | def success?
    method if_file_present (line 200) | def if_file_present(path, cmd)
    method if_task_defined (line 204) | def if_task_defined(task, cmd)
    method safe_branch_checkout (line 208) | def safe_branch_checkout(path, my_branch)
    method clone_repository (line 212) | def clone_repository(repo, path, my_branch)
    method refresh_checkout (line 218) | def refresh_checkout(path, repo_branch)
    method run_rake_task (line 225) | def run_rake_task(path, task_name)
    method build_path (line 232) | def build_path(path)
    method run_script (line 237) | def run_script(script)
    method ensure_main_parent_path_is_present (line 242) | def ensure_main_parent_path_is_present
    method ensure_config_parent_path_is_present (line 247) | def ensure_config_parent_path_is_present
    method checkout_main_repository (line 252) | def checkout_main_repository
    method checkout_configuration_repository (line 257) | def checkout_configuration_repository
    method snapshot_git_revision (line 262) | def snapshot_git_revision
    method initialize_git_changes (line 268) | def initialize_git_changes
    method initialize_rsync_changes (line 274) | def initialize_rsync_changes
    method initialize_all_changes (line 279) | def initialize_all_changes
    method capture_git_changes (line 285) | def capture_git_changes
    method update_main_repository_checkout (line 290) | def update_main_repository_checkout
    method update_configuration_repository_checkout (line 297) | def update_configuration_repository_checkout
    method refresh_configuration (line 303) | def refresh_configuration
    method run_post_setup_hooks (line 312) | def run_post_setup_hooks
    method run_post_deploy_hooks (line 318) | def run_post_deploy_hooks

FILE: lib/whiskey_disk/config.rb
  class WhiskeyDisk (line 6) | class WhiskeyDisk
    class Config (line 7) | class Config
      method fetch (line 8) | def fetch
      method debug? (line 13) | def debug?
      method domain_limit (line 17) | def domain_limit
      method check_staleness? (line 21) | def check_staleness?
      method configuration_file (line 25) | def configuration_file
      method environment_name (line 46) | def environment_name
      method specified_project_name (line 52) | def specified_project_name
      method contains_rakefile? (line 58) | def contains_rakefile?(path)
      method find_rakefile_from_current_path (line 62) | def find_rakefile_from_current_path
      method base_path (line 73) | def base_path
      method valid_path? (line 77) | def valid_path?(path)
      method project_name (line 84) | def project_name
      method configuration_data (line 89) | def configuration_data
      method load_data (line 94) | def load_data
      method filter (line 100) | def filter
      method filter_data (line 105) | def filter_data(data)
      method path (line 111) | def path
      method env_has_key? (line 115) | def env_has_key?(key)
      method env_flag_is_true? (line 119) | def env_flag_is_true?(key)
      method env_key_or_false? (line 123) | def env_key_or_false?(key)

FILE: lib/whiskey_disk/config/abstract_filter.rb
  class WhiskeyDisk (line 1) | class WhiskeyDisk
    class Config (line 2) | class Config
      class AbstractFilter (line 3) | class AbstractFilter
        method initialize (line 6) | def initialize(config)
        method project_name (line 10) | def project_name
        method environment_name (line 14) | def environment_name

FILE: lib/whiskey_disk/config/filter.rb
  class WhiskeyDisk (line 16) | class WhiskeyDisk
    class Config (line 17) | class Config
      class Filter (line 18) | class Filter
        method initialize (line 21) | def initialize(config)
        method filter_data (line 41) | def filter_data(data)

FILE: lib/whiskey_disk/config/filters/add_environment_name_filter.rb
  class WhiskeyDisk (line 3) | class WhiskeyDisk
    class Config (line 4) | class Config
      class AddEnvironmentNameFilter (line 5) | class AddEnvironmentNameFilter < AbstractFilter
        method filter (line 6) | def filter(data)

FILE: lib/whiskey_disk/config/filters/add_project_name_filter.rb
  class WhiskeyDisk (line 3) | class WhiskeyDisk
    class Config (line 4) | class Config
      class AddProjectNameFilter (line 5) | class AddProjectNameFilter < AbstractFilter
        method filter (line 6) | def filter(data)

FILE: lib/whiskey_disk/config/filters/check_for_duplicate_domains_filter.rb
  class WhiskeyDisk (line 3) | class WhiskeyDisk
    class Config (line 4) | class Config
      class CheckForDuplicateDomainsFilter (line 5) | class CheckForDuplicateDomainsFilter < AbstractFilter
        method check_domains (line 6) | def check_domains(domain_list)
        method filter (line 14) | def filter(data)

FILE: lib/whiskey_disk/config/filters/convert_role_strings_to_list_filter.rb
  class WhiskeyDisk (line 3) | class WhiskeyDisk
    class Config (line 4) | class Config
      class ConvertRoleStringsToListFilter (line 5) | class ConvertRoleStringsToListFilter < AbstractFilter
        method convert_roles_for_domain (line 6) | def convert_roles_for_domain(domain)
        method convert_all_roles (line 11) | def convert_all_roles(domains_list)
        method filter (line 15) | def filter(data)

FILE: lib/whiskey_disk/config/filters/default_config_target_filter.rb
  class WhiskeyDisk (line 3) | class WhiskeyDisk
    class Config (line 4) | class Config
      class DefaultConfigTargetFilter (line 5) | class DefaultConfigTargetFilter < AbstractFilter
        method filter (line 6) | def filter(data)

FILE: lib/whiskey_disk/config/filters/default_domain_filter.rb
  class WhiskeyDisk (line 3) | class WhiskeyDisk
    class Config (line 4) | class Config
      class DefaultDomainFilter (line 5) | class DefaultDomainFilter < AbstractFilter
        method filter (line 6) | def filter(data)

FILE: lib/whiskey_disk/config/filters/drop_empty_domain_roles_filter.rb
  class WhiskeyDisk (line 3) | class WhiskeyDisk
    class Config (line 4) | class Config
      class DropEmptyDomainRolesFilter (line 5) | class DropEmptyDomainRolesFilter < AbstractFilter
        method has_empty_role? (line 6) | def has_empty_role?(domain)
        method drop_empty_roles_for_domain (line 17) | def drop_empty_roles_for_domain(domain)
        method drop_empty_domain_roles (line 22) | def drop_empty_domain_roles(domains_list)
        method filter (line 26) | def filter(data)

FILE: lib/whiskey_disk/config/filters/environment_scope_filter.rb
  class WhiskeyDisk (line 4) | class WhiskeyDisk
    class Config (line 5) | class Config
      class EnvironmentScopeFilter (line 6) | class EnvironmentScopeFilter < AbstractFilter
        method needs_environment_scoping? (line 10) | def needs_environment_scoping?(data)
        method filter (line 14) | def filter(data)

FILE: lib/whiskey_disk/config/filters/hashify_domain_entries_filter.rb
  class WhiskeyDisk (line 3) | class WhiskeyDisk
    class Config (line 4) | class Config
      class HashifyDomainEntriesFilter (line 5) | class HashifyDomainEntriesFilter < AbstractFilter
        method needs_hashing? (line 6) | def needs_hashing?(domain)
        method hashify_domain (line 10) | def hashify_domain(domain)
        method new_domain (line 14) | def new_domain
        method hashify_domains (line 18) | def hashify_domains(domain_list)
        method filter (line 23) | def filter(data)

FILE: lib/whiskey_disk/config/filters/localize_domains_filter.rb
  class WhiskeyDisk (line 3) | class WhiskeyDisk
    class Config (line 4) | class Config
      class LocalizeDomainsFilter (line 5) | class LocalizeDomainsFilter < AbstractFilter
        method is_local? (line 6) | def is_local?(name)
        method localize (line 10) | def localize(name)
        method localize_domains (line 14) | def localize_domains(domain_list)
        method filter (line 18) | def filter(data)

FILE: lib/whiskey_disk/config/filters/modules/scope_helper.rb
  class WhiskeyDisk (line 1) | class WhiskeyDisk
    class Config (line 2) | class Config
      type ScopeHelper (line 3) | module ScopeHelper
        function repository_depth (line 4) | def repository_depth(data, depth = 0)

FILE: lib/whiskey_disk/config/filters/normalize_ssh_options_filter.rb
  class WhiskeyDisk (line 3) | class WhiskeyDisk
    class Config (line 4) | class Config
      class NormalizeSshOptionsFilter (line 5) | class NormalizeSshOptionsFilter < AbstractFilter
        method drop_empties (line 6) | def drop_empties(options_list)
        method drop_empty_ssh_options_for_domain (line 10) | def drop_empty_ssh_options_for_domain(domain)
        method normalize_ssh_options (line 19) | def normalize_ssh_options(domains_list)
        method filter (line 23) | def filter(data)

FILE: lib/whiskey_disk/config/filters/project_scope_filter.rb
  class WhiskeyDisk (line 4) | class WhiskeyDisk
    class Config (line 5) | class Config
      class ProjectScopeFilter (line 6) | class ProjectScopeFilter < AbstractFilter
        method repository_depth (line 9) | def repository_depth(data, depth = 0)
        method needs_project_scoping? (line 16) | def needs_project_scoping?(data)
        method override_project_name! (line 22) | def override_project_name!(data)
        method filter (line 27) | def filter(data)

FILE: lib/whiskey_disk/config/filters/select_project_and_environment_filter.rb
  class WhiskeyDisk (line 3) | class WhiskeyDisk
    class Config (line 4) | class Config
      class SelectProjectAndEnvironmentFilter (line 5) | class SelectProjectAndEnvironmentFilter < AbstractFilter
        method filter (line 6) | def filter(data)

FILE: lib/whiskey_disk/config/filters/stringify_hash_keys_filter.rb
  class WhiskeyDisk (line 3) | class WhiskeyDisk
    class Config (line 4) | class Config
      class StringifyHashKeysFilter (line 5) | class StringifyHashKeysFilter < AbstractFilter
        method stringify_hash (line 6) | def stringify_hash(data)
        method stringify (line 14) | def stringify(structure)
        method filter (line 19) | def filter(data)

FILE: lib/whiskey_disk/helpers.rb
  function role? (line 3) | def role?(role)
  function changed? (line 9) | def changed?(path)
  function git_changes (line 16) | def git_changes
  function rsync_changes (line 22) | def rsync_changes
  function read_git_changes_file (line 31) | def read_git_changes_file
  function read_rsync_changes_file (line 35) | def read_rsync_changes_file
  function changes_file_root (line 39) | def changes_file_root
  function git_changes_path (line 44) | def git_changes_path
  function rsync_changes_path (line 48) | def rsync_changes_path

FILE: spec/install_spec.rb
  function do_install (line 3) | def do_install

FILE: spec/spec_helper.rb
  function deployment_root (line 18) | def deployment_root
  function integration_spec (line 23) | def integration_spec(&block)
  function setup_deployment_area (line 28) | def setup_deployment_area
  function run_setup (line 36) | def run_setup(arguments, debugging = true)
  function integration_log (line 43) | def integration_log
  function run_deploy (line 48) | def run_deploy(arguments, debugging = true)
  function scenario_config (line 57) | def scenario_config(path)
  function scenario_config_path (line 62) | def scenario_config_path(path)
  function erb_scenario_config (line 66) | def erb_scenario_config(path)
  function erb_eval (line 72) | def erb_eval(data)
  function write_tempfile (line 76) | def write_tempfile(data)
  function checkout_repo (line 84) | def checkout_repo(repo_name, branch = nil)
  function remote_url (line 90) | def remote_url(repo)
  function checkout_branch (line 94) | def checkout_branch(repo_name, branch = nil)
  function jump_to_initial_commit (line 99) | def jump_to_initial_commit(path)
  function run_log (line 103) | def run_log
  function deployed_file (line 107) | def deployed_file(path)
  function dump_log (line 111) | def dump_log
  function current_branch (line 115) | def current_branch(path)

FILE: spec/wd_command_spec.rb
  function run_command (line 4) | def run_command

FILE: spec/wd_role_command_spec.rb
  function run_command (line 3) | def run_command

FILE: spec/whiskey_disk/config_spec.rb
  function make (line 8) | def make(path)
  function build_temp_dir (line 13) | def build_temp_dir
  function write_config_file (line 18) | def write_config_file(data)
  class TestURLConfig (line 23) | class TestURLConfig < WhiskeyDisk::Config
    method set_response (line 24) | def set_response(data)
    method open (line 28) | def open(path)

FILE: spec/whiskey_disk/helpers_spec.rb
  function set_git_changes (line 44) | def set_git_changes(changes)
  function set_rsync_changes (line 48) | def set_rsync_changes(changes)

FILE: spec/whiskey_disk_spec.rb
  class TestOrderedExecution (line 7) | class TestOrderedExecution < WhiskeyDisk
    method commands (line 9) | def commands
    method system (line 15) | def system(*args)
Condensed preview — 178 files, each showing path, character count, and a content snippet. Download the .json file or copy for the full structured content (370K chars).
[
  {
    "path": ".gitignore",
    "chars": 5,
    "preview": "pkg/\n"
  },
  {
    "path": "CHANGELOG",
    "chars": 10459,
    "preview": "\n0.6.24 / 2011-10-05\n==================\n\n  * fix hashify_domain_filter for ruby 1.9.2 (closes issue #29)\n\n0.6.23 / 2011-"
  },
  {
    "path": "Gemfile",
    "chars": 145,
    "preview": "source \"https://rubygems.org\"\n\ngroup :test do\n  gem \"rake\", \"~> 12.3\"\n  gem \"extensions\"\n  gem \"facon\", \"~> 0.5.0\"\n  gem"
  },
  {
    "path": "MIT-LICENSE",
    "chars": 1088,
    "preview": "Copyright (c) 2009, Flawed Logic, OG Consulting, Rick Bradley.\n\n\nPermission is hereby granted, free of charge, to any pe"
  },
  {
    "path": "README.integration_specs",
    "chars": 951,
    "preview": "Running Integration Specs\n-------------------------\n\nTo run the integration spec suite you need to be able to run a Vagr"
  },
  {
    "path": "README.markdown",
    "chars": 35618,
    "preview": "## Whiskey Disk -- embarrassingly fast deployments. ##\n\n\nA very opinionated deployment tool, designed to be as fast as t"
  },
  {
    "path": "Rakefile",
    "chars": 2677,
    "preview": "require 'rake'\nrequire 'rake/testtask'\n\ndesc 'Default: run unit tests.'\ntask :default => :test\n\ndesc 'Test whiskey_disk'"
  },
  {
    "path": "VERSION",
    "chars": 7,
    "preview": "0.6.24\n"
  },
  {
    "path": "WHY.txt",
    "chars": 3822,
    "preview": "\nWhy?\n----\n\nThe idea here is inspired by github's cleaned up deployment scripts, and mislav's git-deploy project.  Only,"
  },
  {
    "path": "bin/wd",
    "chars": 1468,
    "preview": "#!/usr/bin/env ruby \n\nrequire 'optparse'\nrequire 'whiskey_disk/rake'\n\n$0 = \"#{$0} setup|deploy\"  # jesus, this is a hack"
  },
  {
    "path": "bin/wd_role",
    "chars": 800,
    "preview": "#!/usr/bin/env ruby \nrequire 'whiskey_disk/helpers'\n\n# simple command-line script to detect whether this deployment targ"
  },
  {
    "path": "examples/deploy-configs.yml",
    "chars": 494,
    "preview": "production:\n  domain: \"ogc@hoenir.websages.com\"\n  deploy_to: \"/tmp/test-deployment\"\n  deploy_config_to: \"/tmp/test-confi"
  },
  {
    "path": "examples/deploy-local.yml",
    "chars": 125,
    "preview": "local:\n  deploy_to: \"/Users/rick/deploy/whiskey_disk/local\"\n  repository: \"/Users/rick/git/whiskey_disk\"\n  branch: \"deve"
  },
  {
    "path": "examples/deploy-multiple-remotes.yml",
    "chars": 691,
    "preview": "multi:\n  domain:\n  - \"ogc@hoenir.websages.com\"\n  - \"ogc@nerthus.websages.com\"\n  deploy_to: \"/tmp/test-deployment/\"\n  rep"
  },
  {
    "path": "examples/deploy-staging.yml",
    "chars": 292,
    "preview": "staging:\n  domain: \"user@www.example.com\"\n  deploy_to: \"/var/www/suparsite.com/\"\n  repository: \"git://github.com/clarkke"
  },
  {
    "path": "examples/deploy.rake",
    "chars": 216,
    "preview": "namespace :deploy do\n  namespace :staging do\n    task :post_setup do\n      puts \"This is my local post_setup hook.\"\n    "
  },
  {
    "path": "examples/deploy.yml",
    "chars": 575,
    "preview": "staging:\n  domain: \"user@www.example.com\"\n  deploy_to: \"/var/www/suparsite.com/\"\n  repository: \"git://github.com/clarkke"
  },
  {
    "path": "init.rb",
    "chars": 83,
    "preview": "require File.expand_path(File.join(File.dirname(__FILE__), 'lib', 'whiskey_disk'))\n"
  },
  {
    "path": "install.rb",
    "chars": 128,
    "preview": "def readme_contents\n  IO.read(File.expand_path(File.join(File.dirname(__FILE__), 'README.markdown')))\nend\n\nputs readme_c"
  },
  {
    "path": "lib/whiskey_disk/config/abstract_filter.rb",
    "chars": 304,
    "preview": "class WhiskeyDisk\n  class Config\n    class AbstractFilter\n      attr_reader :config\n  \n      def initialize(config)\n    "
  },
  {
    "path": "lib/whiskey_disk/config/filter.rb",
    "chars": 1804,
    "preview": "require 'whiskey_disk/config/filters/stringify_hash_keys_filter'\nrequire 'whiskey_disk/config/filters/environment_scope_"
  },
  {
    "path": "lib/whiskey_disk/config/filters/add_environment_name_filter.rb",
    "chars": 243,
    "preview": "require 'whiskey_disk/config/abstract_filter'\n\nclass WhiskeyDisk\n  class Config\n    class AddEnvironmentNameFilter < Abs"
  },
  {
    "path": "lib/whiskey_disk/config/filters/add_project_name_filter.rb",
    "chars": 231,
    "preview": "require 'whiskey_disk/config/abstract_filter'\n\nclass WhiskeyDisk\n  class Config\n    class AddProjectNameFilter < Abstrac"
  },
  {
    "path": "lib/whiskey_disk/config/filters/check_for_duplicate_domains_filter.rb",
    "chars": 565,
    "preview": "require 'whiskey_disk/config/abstract_filter'\n\nclass WhiskeyDisk\n  class Config\n    class CheckForDuplicateDomainsFilter"
  },
  {
    "path": "lib/whiskey_disk/config/filters/convert_role_strings_to_list_filter.rb",
    "chars": 554,
    "preview": "require 'whiskey_disk/config/abstract_filter'\n\nclass WhiskeyDisk\n  class Config\n    class ConvertRoleStringsToListFilter"
  },
  {
    "path": "lib/whiskey_disk/config/filters/default_config_target_filter.rb",
    "chars": 289,
    "preview": "require 'whiskey_disk/config/abstract_filter'\n\nclass WhiskeyDisk\n  class Config\n    class DefaultConfigTargetFilter < Ab"
  },
  {
    "path": "lib/whiskey_disk/config/filters/default_domain_filter.rb",
    "chars": 271,
    "preview": "require 'whiskey_disk/config/abstract_filter'\n\nclass WhiskeyDisk\n  class Config\n    class DefaultDomainFilter < Abstract"
  },
  {
    "path": "lib/whiskey_disk/config/filters/drop_empty_domain_roles_filter.rb",
    "chars": 860,
    "preview": "require 'whiskey_disk/config/abstract_filter'\n\nclass WhiskeyDisk\n  class Config\n    class DropEmptyDomainRolesFilter < A"
  },
  {
    "path": "lib/whiskey_disk/config/filters/environment_scope_filter.rb",
    "chars": 541,
    "preview": "require 'whiskey_disk/config/abstract_filter'\nrequire 'whiskey_disk/config/filters/modules/scope_helper'\n\nclass WhiskeyD"
  },
  {
    "path": "lib/whiskey_disk/config/filters/hashify_domain_entries_filter.rb",
    "chars": 664,
    "preview": "require 'whiskey_disk/config/abstract_filter'\n\nclass WhiskeyDisk\n  class Config\n    class HashifyDomainEntriesFilter < A"
  },
  {
    "path": "lib/whiskey_disk/config/filters/localize_domains_filter.rb",
    "chars": 544,
    "preview": "require 'whiskey_disk/config/abstract_filter'\n\nclass WhiskeyDisk\n  class Config\n    class LocalizeDomainsFilter < Abstra"
  },
  {
    "path": "lib/whiskey_disk/config/filters/modules/scope_helper.rb",
    "chars": 305,
    "preview": "class WhiskeyDisk\n  class Config\n    module ScopeHelper\n      def repository_depth(data, depth = 0)\n        raise 'no re"
  },
  {
    "path": "lib/whiskey_disk/config/filters/normalize_ssh_options_filter.rb",
    "chars": 814,
    "preview": "require 'whiskey_disk/config/abstract_filter'\n\nclass WhiskeyDisk\n  class Config\n    class NormalizeSshOptionsFilter < Ab"
  },
  {
    "path": "lib/whiskey_disk/config/filters/project_scope_filter.rb",
    "chars": 1117,
    "preview": "require 'whiskey_disk/config/abstract_filter'\nrequire 'whiskey_disk/config/filters/modules/scope_helper'\n\nclass WhiskeyD"
  },
  {
    "path": "lib/whiskey_disk/config/filters/select_project_and_environment_filter.rb",
    "chars": 428,
    "preview": "require 'whiskey_disk/config/abstract_filter'\n\nclass WhiskeyDisk\n  class Config\n    class SelectProjectAndEnvironmentFil"
  },
  {
    "path": "lib/whiskey_disk/config/filters/stringify_hash_keys_filter.rb",
    "chars": 529,
    "preview": "require 'whiskey_disk/config/abstract_filter'\n\nclass WhiskeyDisk\n  class Config\n    class StringifyHashKeysFilter < Abst"
  },
  {
    "path": "lib/whiskey_disk/config.rb",
    "chars": 3106,
    "preview": "require 'yaml'\nrequire 'uri'\nrequire 'open-uri'\nrequire 'whiskey_disk/config/filter'\n\nclass WhiskeyDisk\n  class Config\n "
  },
  {
    "path": "lib/whiskey_disk/helpers.rb",
    "chars": 1255,
    "preview": "\n# is the current deployment domain in the specified role?\ndef role?(role)\n  return false unless ENV['WD_ROLES'] and ENV"
  },
  {
    "path": "lib/whiskey_disk/rake.rb",
    "chars": 1855,
    "preview": "require 'rake'\nrequire File.expand_path(File.join(File.dirname(__FILE__), '..', 'whiskey_disk'))\n\nnamespace :deploy do\n "
  },
  {
    "path": "lib/whiskey_disk.rb",
    "chars": 9233,
    "preview": "require File.expand_path(File.join(File.dirname(__FILE__), 'whiskey_disk', 'config'))\n\nclass WhiskeyDisk\n  attr_writer :"
  },
  {
    "path": "scenarios/git_repositories/config.git/HEAD",
    "chars": 23,
    "preview": "ref: refs/heads/master\n"
  },
  {
    "path": "scenarios/git_repositories/config.git/config",
    "chars": 85,
    "preview": "[core]\n\trepositoryformatversion = 0\n\tfilemode = true\n\tbare = true\n\tignorecase = true\n"
  },
  {
    "path": "scenarios/git_repositories/config.git/description",
    "chars": 73,
    "preview": "Unnamed repository; edit this file 'description' to name the repository.\n"
  },
  {
    "path": "scenarios/git_repositories/config.git/git-daemon-export-ok",
    "chars": 0,
    "preview": ""
  },
  {
    "path": "scenarios/git_repositories/config.git/hooks/applypatch-msg.sample",
    "chars": 452,
    "preview": "#!/bin/sh\n#\n# An example hook script to check the commit log message taken by\n# applypatch from an e-mail message.\n#\n# T"
  },
  {
    "path": "scenarios/git_repositories/config.git/hooks/commit-msg.sample",
    "chars": 894,
    "preview": "#!/bin/sh\n#\n# An example hook script to check the commit log message.\n# Called by git-commit with one argument, the name"
  },
  {
    "path": "scenarios/git_repositories/config.git/hooks/post-commit.sample",
    "chars": 160,
    "preview": "#!/bin/sh\n#\n# An example hook script that is called after a successful\n# commit is made.\n#\n# To enable this hook, rename"
  },
  {
    "path": "scenarios/git_repositories/config.git/hooks/post-receive.sample",
    "chars": 552,
    "preview": "#!/bin/sh\n#\n# An example hook script for the \"post-receive\" event.\n#\n# The \"post-receive\" script is run after receive-pa"
  },
  {
    "path": "scenarios/git_repositories/config.git/hooks/post-update.sample",
    "chars": 189,
    "preview": "#!/bin/sh\n#\n# An example hook script to prepare a packed repository for use over\n# dumb transports.\n#\n# To enable this h"
  },
  {
    "path": "scenarios/git_repositories/config.git/hooks/pre-applypatch.sample",
    "chars": 398,
    "preview": "#!/bin/sh\n#\n# An example hook script to verify what is about to be committed\n# by applypatch from an e-mail message.\n#\n#"
  },
  {
    "path": "scenarios/git_repositories/config.git/hooks/pre-commit.sample",
    "chars": 1576,
    "preview": "#!/bin/sh\n#\n# An example hook script to verify what is about to be committed.\n# Called by git-commit with no arguments. "
  },
  {
    "path": "scenarios/git_repositories/config.git/hooks/pre-rebase.sample",
    "chars": 4942,
    "preview": "#!/bin/sh\n#\n# Copyright (c) 2006, 2008 Junio C Hamano\n#\n# The \"pre-rebase\" hook is run just before \"git-rebase\" starts d"
  },
  {
    "path": "scenarios/git_repositories/config.git/hooks/prepare-commit-msg.sample",
    "chars": 1219,
    "preview": "#!/bin/sh\n#\n# An example hook script to prepare the commit log message.\n# Called by git-commit with the name of the file"
  },
  {
    "path": "scenarios/git_repositories/config.git/hooks/update.sample",
    "chars": 3609,
    "preview": "#!/bin/sh\n#\n# An example hook script to blocks unannotated tags from entering.\n# Called by git-receive-pack with argumen"
  },
  {
    "path": "scenarios/git_repositories/config.git/info/exclude",
    "chars": 240,
    "preview": "# git-ls-files --others --exclude-from=.git/info/exclude\n# Lines that start with '#' are comments.\n# For a project mostl"
  },
  {
    "path": "scenarios/git_repositories/config.git/objects/0e/e781f5ce80d64db32a74a7aae7b5248dafe112",
    "chars": 102,
    "preview": "x\u0001[\n0\u0014D*\u0006<n\u0004D%<n&%\u001fݽ\u0011w\f́\u0019&e\u001aH-\u000e\u0012A4x\u0017)\u000eA\u0005h5\u001d49\u0007dd\u001b\u0018\u0014c\u0014\u0014\u00027RKAKw,9`ݞ}\n/U\u0017g\\{~)\u0002Bq٥\u00105~џuikP=\u0007\bO\u001f\u0014!M3ZJu\u0007Q\u0001"
  },
  {
    "path": "scenarios/git_repositories/config.git/objects/71/eb5df52676e8e6efba471050b46978173af110",
    "chars": 76,
    "preview": "x\u0001\t\u00021\u0010DN\u0015ۀ\u001c%An`r\u0010?u<x3RK\u001d\u0018\u0001'$&I8\u0005\f(m\u0010ͳ\u0010\u0012y\u000eɜutʿ6xdy\u000f\\h_,;9I-W@3[äQ;ՠ?uܳ_aQ_&<"
  },
  {
    "path": "scenarios/git_repositories/config.git/objects/84/17d2fe3e8fcc0825249c517b29b0f9ea8b8b31",
    "chars": 112,
    "preview": "x\u0001QJ0\u0010})\u0002J6I\u0004D#xoM$Ez{#\u0019c\u0006q\u0013l\u000fgW5\u0019藅\u0016CrL9Q9z(^]a\u001c}dH~E\t}@u~l\b%vfA#\u0013}[^\u0003:ɮ\u0017<^%'n\u000b3\u0016m\n\u0001Ls>H7 Xˮ\u0015ހB\u0005Y[\u0017Ѯ\u0002Q\r\u0017Uy\u0001F+Y"
  },
  {
    "path": "scenarios/git_repositories/config.git/refs/heads/master",
    "chars": 41,
    "preview": "bb59da633ba74296b0c2f9ff70784ac155ddb599\n"
  },
  {
    "path": "scenarios/git_repositories/project.git/HEAD",
    "chars": 23,
    "preview": "ref: refs/heads/master\n"
  },
  {
    "path": "scenarios/git_repositories/project.git/config",
    "chars": 85,
    "preview": "[core]\n\trepositoryformatversion = 0\n\tfilemode = true\n\tbare = true\n\tignorecase = true\n"
  },
  {
    "path": "scenarios/git_repositories/project.git/description",
    "chars": 73,
    "preview": "Unnamed repository; edit this file 'description' to name the repository.\n"
  },
  {
    "path": "scenarios/git_repositories/project.git/git-daemon-export-ok",
    "chars": 0,
    "preview": ""
  },
  {
    "path": "scenarios/git_repositories/project.git/hooks/applypatch-msg.sample",
    "chars": 452,
    "preview": "#!/bin/sh\n#\n# An example hook script to check the commit log message taken by\n# applypatch from an e-mail message.\n#\n# T"
  },
  {
    "path": "scenarios/git_repositories/project.git/hooks/commit-msg.sample",
    "chars": 894,
    "preview": "#!/bin/sh\n#\n# An example hook script to check the commit log message.\n# Called by git-commit with one argument, the name"
  },
  {
    "path": "scenarios/git_repositories/project.git/hooks/post-commit.sample",
    "chars": 160,
    "preview": "#!/bin/sh\n#\n# An example hook script that is called after a successful\n# commit is made.\n#\n# To enable this hook, rename"
  },
  {
    "path": "scenarios/git_repositories/project.git/hooks/post-receive.sample",
    "chars": 552,
    "preview": "#!/bin/sh\n#\n# An example hook script for the \"post-receive\" event.\n#\n# The \"post-receive\" script is run after receive-pa"
  },
  {
    "path": "scenarios/git_repositories/project.git/hooks/post-update.sample",
    "chars": 189,
    "preview": "#!/bin/sh\n#\n# An example hook script to prepare a packed repository for use over\n# dumb transports.\n#\n# To enable this h"
  },
  {
    "path": "scenarios/git_repositories/project.git/hooks/pre-applypatch.sample",
    "chars": 398,
    "preview": "#!/bin/sh\n#\n# An example hook script to verify what is about to be committed\n# by applypatch from an e-mail message.\n#\n#"
  },
  {
    "path": "scenarios/git_repositories/project.git/hooks/pre-commit.sample",
    "chars": 1576,
    "preview": "#!/bin/sh\n#\n# An example hook script to verify what is about to be committed.\n# Called by git-commit with no arguments. "
  },
  {
    "path": "scenarios/git_repositories/project.git/hooks/pre-rebase.sample",
    "chars": 4942,
    "preview": "#!/bin/sh\n#\n# Copyright (c) 2006, 2008 Junio C Hamano\n#\n# The \"pre-rebase\" hook is run just before \"git-rebase\" starts d"
  },
  {
    "path": "scenarios/git_repositories/project.git/hooks/prepare-commit-msg.sample",
    "chars": 1219,
    "preview": "#!/bin/sh\n#\n# An example hook script to prepare the commit log message.\n# Called by git-commit with the name of the file"
  },
  {
    "path": "scenarios/git_repositories/project.git/hooks/update.sample",
    "chars": 3609,
    "preview": "#!/bin/sh\n#\n# An example hook script to blocks unannotated tags from entering.\n# Called by git-receive-pack with argumen"
  },
  {
    "path": "scenarios/git_repositories/project.git/info/exclude",
    "chars": 240,
    "preview": "# git-ls-files --others --exclude-from=.git/info/exclude\n# Lines that start with '#' are comments.\n# For a project mostl"
  },
  {
    "path": "scenarios/git_repositories/project.git/objects/04/f4de85eaf72ef1631dc6d7424045c0a749b757",
    "chars": 99,
    "preview": "x\u0001IjC1\u0010D)z\u001dH<@\b!G\u0005#:>27Uԃ\u00075\u0002\u000b\rD@R\u0010aH\"pQ\u000båA1y\u0015uPEɐ\u001c;\"lBm+hRHFT<\u001b\u0015Y>\u0015G,7=҃}2\u000b\u0003or\u0016]'\tY,\u0017}IWy&u턗\u0011\u001dy?*W"
  },
  {
    "path": "scenarios/git_repositories/project.git/objects/20/1c7641c2e42b0b904e5c1f793489d8b858e4da",
    "chars": 71,
    "preview": "x\u0001\t\u00021\u0010DN\u0015ۀ%q\u0017D\u0012 ar\u0010?u<x3;hrD@\u0016\u0013mrh68sZğ\u0003\u0007\bD\u00137»?kG/VvżS\nڰ7nbpDBT.*o¾\u001c<t"
  },
  {
    "path": "scenarios/git_repositories/project.git/objects/27/a3fff2c4c45ab5513a405f694c0a042cb5d417",
    "chars": 95,
    "preview": "x\u0001NAj\u00031\u0010ٯsevg!'\u0003ab\u001bl:\u000eA/B\u0012\u0012R\\4 GoB\u001eq +C΄ѻ)\u000eN,\u000b[\"c`R`\u0011J8Z\t9'#s#s`.kc3\u001cv\u0011\u0013\u0006oYdxGhO6gHJ\rG5³\u000b׭vd7\u000bP"
  },
  {
    "path": "scenarios/git_repositories/project.git/objects/2c/0c33cfba8e1af15df88522c0db2b10a6a94138",
    "chars": 104,
    "preview": "x\u0001Kj\u00031\u0010D)\u0002\tR3#\bI\u0011|\u0001jC2\u001f\"\u0018zmYf\u0005LM\u0004\u0002ŁJ\u0012$`≳x\u0010G\\(HdUȑsTsq\u0004\u001em.\rw6N\u000fU\u0014C7n\rN3w+ގu o-\u001f0gLC\n\u001e^m\u001c8nmW:\u0017ط\u0007+\u0017wn\u0001(V}"
  },
  {
    "path": "scenarios/git_repositories/project.git/objects/5b/a96acf9cc9b87babe37c032676f53bf1ba9ae7",
    "chars": 96,
    "preview": "x\u0001aj \u0010\u000bQ\u0017Rz@\t\u001bb\f4ޠx<t g/@\u000eWmf&Dɧ3\u001bN\u00188ɜOlu&82m`\u001fl(&\u0004&+z\u000fj1\u00179F|Zzw\u0007h'D\rU'~n\f[v\u0019y)\u0002\u001e%\u000f86p?b)'w\u0007'\nU6"
  },
  {
    "path": "scenarios/git_repositories/project.git/objects/86/d1ef0976be4567de562224e1b51fbf9820c53a",
    "chars": 103,
    "preview": "x\u0001AJ\u00041\u0010E]\u0014\u001ePJ:\u0001\u0011\b^@J\u00184Ifx\u00037\u001f\u0007뾗\u0001a4\u00110Iт.bF7B\fiN4[u&\u0014Ցa\u0014¤S$Ͷ|>yrT>>k7xk17<^''\u000b\u0018\f\u001e\u001avZIg*\\+\u000btn\u001c\u001dS!\u0016G\u0007S\u001f\\T"
  },
  {
    "path": "scenarios/git_repositories/project.git/objects/95/c9d5ad9b1c90e4c805516783105fc2037dedeb",
    "chars": 151,
    "preview": "x\u0001Kn \f\u0014U\u001a# TUUw\rx8\tj\brB\u0006`\u0007;ۭ}\b\u0013̈́6VˡP NڪiBh٦\u0012\u0006\u0002cSQ;-\u0011pHa\rAP4gj%&v\u0007+\u001eJY\u000fT&\u000f\u0010r\u001cV#7qΊZL\u0012Q:\\\"H\u00154(c0gW\u0018\u0016>\u00122X\\\u0011C$T>S-\u001a7_?a*2\u001d'"
  },
  {
    "path": "scenarios/git_repositories/project.git/objects/95/d82d043af35a80eabfd56c0d705abfa3488787",
    "chars": 102,
    "preview": "x\u0001Qn\u00021\fDS\u0002Evd\u0013\tU\u0015G\u0006I@.B7\u001b3yғ&oZ;XG\u001f\u001c\u0014$:\u0014+\u0013iy)ZJ=6\r\u0011)ώ)[e0\u0005dg*s\u0007イD\u0013ekp\n\u0016e?8^d\u000b\u0006<3|C4]M\u00143D(.vW-uQ(R\u0007RR"
  },
  {
    "path": "scenarios/git_repositories/project.git/objects/a3/860106dc1d148c7831cd45ae38829b4ed47702",
    "chars": 82,
    "preview": "x\u0001]\n0\u0010})\u00026ɚ\u0004D#xlh\u0012\"ۛ\r|\u0019o`bTk\u0019t4CJ\u0012񙍳V[4\u0012#m$):sјH\u0006>\u0004T\u0006-e<0HI\u000e¿ۣT\tӋW8.[\u001f92aP(\u000eH~g֥/!H"
  },
  {
    "path": "scenarios/git_repositories/project.git/objects/ae/3900de54aff557c61c81146d00f9d38e55a265",
    "chars": 84,
    "preview": "x\u0001Aj\u0004!\u0010E\u0014\u001eH(R[\u0018B\u0011\u0002\u001e\u0007I!7{৶u4zJ\"\u0018d\r\u0015\\bAˎ|rs&=_\u000bRLV\u0016\u00178 \u0014+yuԴ{yp\u0007N3/Mq>hxF\u000e{\u001cp5eck[\u0013,w\u0003P"
  },
  {
    "path": "scenarios/git_repositories/project.git/objects/bf/5e3740d52b80abb0378b3f85f93a53b1294521",
    "chars": 100,
    "preview": "x\u0001Qj0\u0010\u0005S\u0005\u0012vX #\u0006*\u0011\"\u0005߾*A~\u001ee\u0006vB&ls\u001e}\b\u0003a8{\"B.Oαc\u00115t8'%qPBC.=]d\u0013!{grv_\u001a|Uyq~\u000e˜d>\u001cZ1\u0004G\u001c\u0010Mos\rX\u001b>37]2u\u0001'S9"
  },
  {
    "path": "scenarios/git_repositories/project.git/objects/cc/5ac0afb24e727d5de344cc26a425f4fb7fd17d",
    "chars": 80,
    "preview": "x\u0001A\n0\u0014D]\u0014C\u000fB\u0017BAWzNJIG6?𓅷$\bY7o\u0018yf])g&\u0012on֒\u001f\r\n\bF^hBDt\u0012\u0001 htt.e\u0006%y\u0017CΪVfS~?Zvwΰҭl:l?k]"
  },
  {
    "path": "scenarios/git_repositories/project.git/objects/db/d1b9667f1b26b13331ac0c321dced8be1aeab0",
    "chars": 96,
    "preview": "x\u0001Kj0\u0010\u0005)\u0002\t-Y\u001f\u000b$\b@hZc3cbn\u001f \u0007nԛ\b\u0014T&RpL`0\u000b\u001cOgtT\u00075ه\u0018h*\u0018l\u001d%D\u0016]2\u0012Ze\u0006+Q\u0003.mI\nyv:Zgj\u0011基\nG=W^\u001fz;Wrv7dTf\u0003ݺV"
  },
  {
    "path": "scenarios/git_repositories/project.git/refs/heads/bad_rakefile",
    "chars": 41,
    "preview": "95d82d043af35a80eabfd56c0d705abfa3488787\n"
  },
  {
    "path": "scenarios/git_repositories/project.git/refs/heads/hook_with_changed",
    "chars": 41,
    "preview": "5ba96acf9cc9b87babe37c032676f53bf1ba9ae7\n"
  },
  {
    "path": "scenarios/git_repositories/project.git/refs/heads/master",
    "chars": 41,
    "preview": "04f4de85eaf72ef1631dc6d7424045c0a749b757\n"
  },
  {
    "path": "scenarios/git_repositories/project.git/refs/heads/no_rake_hooks",
    "chars": 41,
    "preview": "ae3900de54aff557c61c81146d00f9d38e55a265\n"
  },
  {
    "path": "scenarios/git_repositories/project.git/refs/heads/post_rake_tasks",
    "chars": 41,
    "preview": "27a3fff2c4c45ab5513a405f694c0a042cb5d417\n"
  },
  {
    "path": "scenarios/invalid/deploy.yml",
    "chars": 2,
    "preview": "}\n"
  },
  {
    "path": "scenarios/local/deploy.yml.erb",
    "chars": 613,
    "preview": "<% root = File.expand_path(File.join(File.dirname(__FILE__), 'scenarios', 'setup', 'vagrant', 'deployed', 'target')) %>\n"
  },
  {
    "path": "scenarios/remote/deploy.yml",
    "chars": 3583,
    "preview": "project:\n  \"remote\":\n    domain:\n    - name: \"vagrant@vagrant\"\n      ssh_options:\n      - \"-F\"\n      - \"scenarios/setup/"
  },
  {
    "path": "scenarios/setup/vagrant/.gitignore",
    "chars": 29,
    "preview": "ssh_config\n.vagrant\ndeployed\n"
  },
  {
    "path": "scenarios/setup/vagrant/Vagrantfile",
    "chars": 321,
    "preview": "Vagrant::Config.run do |config|\n  config.vm.box = \"base\"\n  config.vm.share_folder \"deployment\", \"/opt/deploy\", \"deployed"
  },
  {
    "path": "scenarios/setup/vagrant/manifests/integration.pp",
    "chars": 603,
    "preview": "file { '/etc/motd':\n  content => \"Welcome to your Vagrant-built virtual machine! Managed by Puppet.\\n\"\n}\n\nfile { '/opt/d"
  },
  {
    "path": "scenarios/setup/vagrant/pids/.gitignore",
    "chars": 6,
    "preview": "*.pid\n"
  },
  {
    "path": "spec/.bacon",
    "chars": 0,
    "preview": ""
  },
  {
    "path": "spec/init_spec.rb",
    "chars": 386,
    "preview": "require File.expand_path(File.join(File.dirname(__FILE__), 'spec_helper.rb'))\nrequire 'rake'\n\ndescribe 'when the init.rb"
  },
  {
    "path": "spec/install_spec.rb",
    "chars": 1239,
    "preview": "require File.expand_path(File.join(File.dirname(__FILE__), 'spec_helper'))\n\ndef do_install\n  eval File.read(File.join(Fi"
  },
  {
    "path": "spec/integration/branch_switching_spec.rb",
    "chars": 1347,
    "preview": "require File.expand_path(File.join(File.dirname(__FILE__), '..', 'spec_helper.rb'))\nrequire File.expand_path(File.join(F"
  },
  {
    "path": "spec/integration/deployment_failures_spec.rb",
    "chars": 3570,
    "preview": "require File.expand_path(File.join(File.dirname(__FILE__), '..', 'spec_helper.rb'))\nrequire File.expand_path(File.join(F"
  },
  {
    "path": "spec/integration/helper_spec.rb",
    "chars": 3061,
    "preview": "require File.expand_path(File.join(File.dirname(__FILE__), '..', 'spec_helper.rb'))\nrequire File.expand_path(File.join(F"
  },
  {
    "path": "spec/integration/invalid_configuration_spec.rb",
    "chars": 1177,
    "preview": "require File.expand_path(File.join(File.dirname(__FILE__), '..', 'spec_helper.rb'))\nrequire File.expand_path(File.join(F"
  },
  {
    "path": "spec/integration/local_deployments_spec.rb",
    "chars": 7418,
    "preview": "require File.expand_path(File.join(File.dirname(__FILE__), '..', 'spec_helper.rb'))\nrequire File.expand_path(File.join(F"
  },
  {
    "path": "spec/integration/post_rake_tasks_spec.rb",
    "chars": 7526,
    "preview": "require File.expand_path(File.join(File.dirname(__FILE__), '..', 'spec_helper.rb'))\nrequire File.expand_path(File.join(F"
  },
  {
    "path": "spec/integration/post_scripts_spec.rb",
    "chars": 8184,
    "preview": "require File.expand_path(File.join(File.dirname(__FILE__), '..', 'spec_helper.rb'))\nrequire File.expand_path(File.join(F"
  },
  {
    "path": "spec/integration/remote_deployments_spec.rb",
    "chars": 5494,
    "preview": "require File.expand_path(File.join(File.dirname(__FILE__), '..', 'spec_helper.rb'))\nrequire File.expand_path(File.join(F"
  },
  {
    "path": "spec/integration/staleness_checks_spec.rb",
    "chars": 2183,
    "preview": "require File.expand_path(File.join(File.dirname(__FILE__), '..', 'spec_helper.rb'))\nrequire File.expand_path(File.join(F"
  },
  {
    "path": "spec/spec_helper.rb",
    "chars": 3597,
    "preview": "require 'rubygems'\nrequire 'bacon'\nrequire 'facon'\nrequire 'fileutils'\nrequire 'tempfile'\nrequire 'erb'\n\nif ENV['DEBUG']"
  },
  {
    "path": "spec/wd_command_spec.rb",
    "chars": 28393,
    "preview": "require_relative('spec_helper.rb')\nrequire 'rake'\n\ndef run_command\n  cmd_path = File.expand_path(File.join(File.dirname("
  },
  {
    "path": "spec/wd_role_command_spec.rb",
    "chars": 1288,
    "preview": "require_relative 'spec_helper.rb'\n\ndef run_command\n  eval File.read(File.join(File.dirname(__FILE__), *%w[.. bin wd_role"
  },
  {
    "path": "spec/whiskey_disk/config/filter_spec.rb",
    "chars": 5083,
    "preview": "require File.expand_path(File.join(File.dirname(__FILE__), '..', '..', 'spec_helper.rb'))\nrequire File.expand_path(File."
  },
  {
    "path": "spec/whiskey_disk/config/filters/add_environment_name_filter_spec.rb",
    "chars": 982,
    "preview": "require File.expand_path(File.join(File.dirname(__FILE__), '..', '..', '..', 'spec_helper.rb'))\nrequire File.expand_path"
  },
  {
    "path": "spec/whiskey_disk/config/filters/add_project_name_filter_spec.rb",
    "chars": 946,
    "preview": "require File.expand_path(File.join(File.dirname(__FILE__), '..', '..', '..', 'spec_helper.rb'))\nrequire File.expand_path"
  },
  {
    "path": "spec/whiskey_disk/config/filters/check_for_duplicate_domains_filter_spec.rb",
    "chars": 1364,
    "preview": "require File.expand_path(File.join(File.dirname(__FILE__), '..', '..', '..', 'spec_helper.rb'))\nrequire File.expand_path"
  },
  {
    "path": "spec/whiskey_disk/config/filters/convert_role_strings_to_list_filter_spec.rb",
    "chars": 1417,
    "preview": "require File.expand_path(File.join(File.dirname(__FILE__), '..', '..', '..', 'spec_helper.rb'))\nrequire File.expand_path"
  },
  {
    "path": "spec/whiskey_disk/config/filters/default_config_target_filter_spec.rb",
    "chars": 1016,
    "preview": "require File.expand_path(File.join(File.dirname(__FILE__), '..', '..', '..', 'spec_helper.rb'))\nrequire File.expand_path"
  },
  {
    "path": "spec/whiskey_disk/config/filters/default_domain_filter_spec.rb",
    "chars": 836,
    "preview": "require File.expand_path(File.join(File.dirname(__FILE__), '..', '..', '..', 'spec_helper.rb'))\nrequire File.expand_path"
  },
  {
    "path": "spec/whiskey_disk/config/filters/drop_empty_domain_roles_filter_spec.rb",
    "chars": 1644,
    "preview": "require File.expand_path(File.join(File.dirname(__FILE__), '..', '..', '..', 'spec_helper.rb'))\nrequire File.expand_path"
  },
  {
    "path": "spec/whiskey_disk/config/filters/environment_scope_filter_spec.rb",
    "chars": 1349,
    "preview": "require File.expand_path(File.join(File.dirname(__FILE__), '..', '..', '..', 'spec_helper.rb'))\nrequire File.expand_path"
  },
  {
    "path": "spec/whiskey_disk/config/filters/hashify_domain_entries_filter_spec.rb",
    "chars": 1368,
    "preview": "require File.expand_path(File.join(File.dirname(__FILE__), '..', '..', '..', 'spec_helper.rb'))\nrequire File.expand_path"
  },
  {
    "path": "spec/whiskey_disk/config/filters/localize_domains_filter_spec.rb",
    "chars": 998,
    "preview": "require File.expand_path(File.join(File.dirname(__FILE__), '..', '..', '..', 'spec_helper.rb'))\nrequire File.expand_path"
  },
  {
    "path": "spec/whiskey_disk/config/filters/normalize_ssh_options_filter_spec.rb",
    "chars": 2003,
    "preview": "require File.expand_path(File.join(File.dirname(__FILE__), '..', '..', '..', 'spec_helper.rb'))\nrequire File.expand_path"
  },
  {
    "path": "spec/whiskey_disk/config/filters/project_scope_filter_spec.rb",
    "chars": 2974,
    "preview": "require File.expand_path(File.join(File.dirname(__FILE__), '..', '..', '..', 'spec_helper.rb'))\nrequire File.expand_path"
  },
  {
    "path": "spec/whiskey_disk/config/filters/select_project_and_environment_filter_spec.rb",
    "chars": 1303,
    "preview": "require File.expand_path(File.join(File.dirname(__FILE__), '..', '..', '..', 'spec_helper.rb'))\nrequire File.expand_path"
  },
  {
    "path": "spec/whiskey_disk/config/filters/stringify_hash_keys_filter_spec.rb",
    "chars": 1245,
    "preview": "require File.expand_path(File.join(File.dirname(__FILE__), '..', '..', '..', 'spec_helper.rb'))\nrequire File.expand_path"
  },
  {
    "path": "spec/whiskey_disk/config_spec.rb",
    "chars": 29634,
    "preview": "require File.expand_path(File.join(File.dirname(__FILE__), '..', 'spec_helper.rb'))\nrequire File.expand_path(File.join(F"
  },
  {
    "path": "spec/whiskey_disk/helpers_spec.rb",
    "chars": 20777,
    "preview": "require File.expand_path(File.join(File.dirname(__FILE__), '..', 'spec_helper.rb'))\nrequire File.expand_path(File.join(F"
  },
  {
    "path": "spec/whiskey_disk/rake_spec.rb",
    "chars": 8991,
    "preview": "require File.expand_path(File.join(File.dirname(__FILE__), '..', 'spec_helper.rb'))\nrequire 'rake'\n\ndescribe 'rake tasks"
  },
  {
    "path": "spec/whiskey_disk_spec.rb",
    "chars": 51609,
    "preview": "require File.expand_path(File.join(File.dirname(__FILE__), 'spec_helper.rb'))\nrequire File.expand_path(File.join(File.di"
  },
  {
    "path": "tasks/deploy.rake",
    "chars": 98,
    "preview": "require File.expand_path(File.join(File.dirname(__FILE__), '..', 'lib', 'whiskey_disk', 'rake'))\n\n"
  },
  {
    "path": "whiskey_disk.gemspec",
    "chars": 13081,
    "preview": "# Generated by jeweler\n# DO NOT EDIT THIS FILE DIRECTLY\n# Instead, edit Jeweler::Tasks in Rakefile, and run 'rake gemspe"
  }
]

// ... and 43 more files (download for full content)

About this extraction

This page contains the full source code of the flogic/whiskey_disk GitHub repository, extracted and formatted as plain text for AI agents and large language models (LLMs). The extraction includes 178 files (336.4 KB), approximately 95.9k tokens, and a symbol index with 214 extracted functions, classes, methods, constants, and types. Use this with OpenClaw, Claude, ChatGPT, Cursor, Windsurf, or any other AI tool that accepts text input. You can copy the full output to your clipboard or download it as a .txt file.

Extracted by GitExtract — free GitHub repo to text converter for AI. Built by Nikandr Surkov.

Copied to clipboard!