hardhat 0.0.1
Sign up to get free protection for your applications and to get access to all the features.
- data/.gitignore +17 -0
- data/.rspec +1 -0
- data/Gemfile +4 -0
- data/LICENSE.txt +22 -0
- data/README.md +152 -0
- data/Rakefile +8 -0
- data/bin/bootstrap +50 -0
- data/bin/hardhat +50 -0
- data/example/blueprint.rb +52 -0
- data/hardhat.gemspec +24 -0
- data/lib/hardhat.rb +33 -0
- data/lib/hardhat/dependency.rb +38 -0
- data/lib/hardhat/ext.rb +1 -0
- data/lib/hardhat/ext/string.rb +16 -0
- data/lib/hardhat/installer.rb +53 -0
- data/lib/hardhat/repository.rb +18 -0
- data/lib/hardhat/repository/git.rb +11 -0
- data/lib/hardhat/repository/svn.rb +11 -0
- data/lib/hardhat/system.rb +19 -0
- data/lib/hardhat/version.rb +3 -0
- data/spec/dependency_spec.rb +55 -0
- data/spec/installer_spec.rb +178 -0
- data/spec/repository/git_spec.rb +9 -0
- data/spec/repository/svn_spec.rb +9 -0
- data/spec/spec_helper.rb +5 -0
- data/spec/support/shared_examples_for_repository.rb +29 -0
- data/spec/system_spec.rb +32 -0
- data/spec/version_spec.rb +22 -0
- metadata +130 -0
data/.gitignore
ADDED
data/.rspec
ADDED
@@ -0,0 +1 @@
|
|
1
|
+
--color --order rand
|
data/Gemfile
ADDED
data/LICENSE.txt
ADDED
@@ -0,0 +1,22 @@
|
|
1
|
+
Copyright (c) 2013 Nathan Lilienthal
|
2
|
+
|
3
|
+
MIT License
|
4
|
+
|
5
|
+
Permission is hereby granted, free of charge, to any person obtaining
|
6
|
+
a copy of this software and associated documentation files (the
|
7
|
+
"Software"), to deal in the Software without restriction, including
|
8
|
+
without limitation the rights to use, copy, modify, merge, publish,
|
9
|
+
distribute, sublicense, and/or sell copies of the Software, and to
|
10
|
+
permit persons to whom the Software is furnished to do so, subject to
|
11
|
+
the following conditions:
|
12
|
+
|
13
|
+
The above copyright notice and this permission notice shall be
|
14
|
+
included in all copies or substantial portions of the Software.
|
15
|
+
|
16
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
|
17
|
+
EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
|
18
|
+
MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
|
19
|
+
NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
|
20
|
+
LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
|
21
|
+
OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
|
22
|
+
WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
data/README.md
ADDED
@@ -0,0 +1,152 @@
|
|
1
|
+
# Hardhat
|
2
|
+
|
3
|
+
...
|
4
|
+
|
5
|
+
## Installation
|
6
|
+
|
7
|
+
...
|
8
|
+
|
9
|
+
## CLI
|
10
|
+
|
11
|
+
...
|
12
|
+
|
13
|
+
# Documentation
|
14
|
+
|
15
|
+
Hardhat is essentially a collection of helper classes and modules for
|
16
|
+
performing actions common to a build. Things like installing dependencies,
|
17
|
+
downloading code from version control, moving files into place, patching
|
18
|
+
files, running daemons, and even making images.
|
19
|
+
|
20
|
+
|
21
|
+
## Installing Dependencies
|
22
|
+
|
23
|
+
Projects have a collection of dependencies, some are for a single purpose,
|
24
|
+
and some a required for many purposes. By grouping these dependencies up by
|
25
|
+
what they are required for it make managing them easier.
|
26
|
+
|
27
|
+
Dependency lists should look like this:
|
28
|
+
|
29
|
+
```ruby
|
30
|
+
breakfast_deps = [
|
31
|
+
Dependency.new "milk",
|
32
|
+
Dependency.new "cereal",
|
33
|
+
Dependency.new "bowl",
|
34
|
+
Dependency.new "spoon",
|
35
|
+
]
|
36
|
+
```
|
37
|
+
|
38
|
+
Then to install the dependencies:
|
39
|
+
|
40
|
+
```ruby
|
41
|
+
meal_installer = Installer.new "mealer"
|
42
|
+
meal_installer.install breakfast_deps
|
43
|
+
```
|
44
|
+
|
45
|
+
By default this translates to:
|
46
|
+
|
47
|
+
```
|
48
|
+
mealer install milk
|
49
|
+
mealer install cereal
|
50
|
+
mealer install bowl
|
51
|
+
mealer install spoon
|
52
|
+
```
|
53
|
+
|
54
|
+
#### Hardhat::Dependency
|
55
|
+
|
56
|
+
Class for defining dependencies for the project. The first argument is the
|
57
|
+
name of the dependency, and is used to tell the package manager how to install.
|
58
|
+
The second argument is an optional hash, where you can define `:installer` to
|
59
|
+
limit what installers can deal with this dependency, `:sudo` to define if
|
60
|
+
this needs to be run as sudo to install, and `:flags` to pass command line
|
61
|
+
flags to the package manager.
|
62
|
+
|
63
|
+
Examples:
|
64
|
+
|
65
|
+
```ruby
|
66
|
+
# must install with gem
|
67
|
+
@rails = Dependency.new("rails", :installer => "gem")
|
68
|
+
@highline = Dependency.new("highline", :sudo => false, :installer => "gem")
|
69
|
+
@bundler = Dependency.new("bundler", :sudo => true, :installer => "gem")
|
70
|
+
|
71
|
+
# doesn't care what you install with
|
72
|
+
@foo = Dependency.new('foo', :flags => "-noop")
|
73
|
+
@bar = Dependency.new('bar', :sudo => false, :flags => "--verbose -q")
|
74
|
+
@baz = Dependency.new('baz', :sudo => true, :flags => "-qweF=1")
|
75
|
+
|
76
|
+
# can install with array of installer names
|
77
|
+
@git = Dependency.new("git", :installer => ["apt-get", "yum"])
|
78
|
+
@ack = Dependency.new("ack", :sudo => false, :installer => ["apt-get", "yum"])
|
79
|
+
@curl = Dependency.new("curl", :sudo => true, :installer => ["apt-get", "yum"])
|
80
|
+
```
|
81
|
+
|
82
|
+
#### Hardhat::Installer
|
83
|
+
|
84
|
+
Class for defining system programs to install dependencies. The first argument
|
85
|
+
is the name of the program to run, `apt-get` for example. The second argument
|
86
|
+
is an optional hash much like for `Dependency`. You can specify `:sudo` to
|
87
|
+
make all dependencies handled by this installer done so as root. `:flags` to
|
88
|
+
pass command line flags to the program for all dependencies.
|
89
|
+
|
90
|
+
Installers have 3 main methods, `install`, `uninstall` and `remove`. By
|
91
|
+
default `Installer.new('gem').install ...` will call `gem install ...`.
|
92
|
+
|
93
|
+
__Custom commands__
|
94
|
+
|
95
|
+
```ruby
|
96
|
+
Installer.new('apt-get', :uninstall => :remove).uninstall ...
|
97
|
+
apt-get remove ...
|
98
|
+
|
99
|
+
Installer.new('foo', :update => :bar).update ...
|
100
|
+
foo bar ...
|
101
|
+
```
|
102
|
+
|
103
|
+
|
104
|
+
## Getting Code from Version Control
|
105
|
+
|
106
|
+
When building on a new system often times the code will not be there yet,
|
107
|
+
`Hardhat::Repository` defines the how to pull code down from VC. It is a
|
108
|
+
module currently with 2 classes the include it, `Hardhat::Repository::Git`
|
109
|
+
and `Hardhat::Repository::Svn`.
|
110
|
+
|
111
|
+
Classes that include `Hardhat::Repository` must define a `get` and a `branch`
|
112
|
+
method.
|
113
|
+
|
114
|
+
#### Hardhat::Repository::Git
|
115
|
+
|
116
|
+
```ruby
|
117
|
+
repo = Repository::Git.new "https://gist.github.com/4772101.git", "/tmp/hh"
|
118
|
+
repo.get # downloads the repo to /tmp/hh
|
119
|
+
```
|
120
|
+
|
121
|
+
#### Hardhat::Repository::Svn
|
122
|
+
|
123
|
+
```ruby
|
124
|
+
repo = Repository::Svn.new "http://svn.apache.org/repos/asf/spamassassin/trunk", "/tmp/hh"
|
125
|
+
repo.get # downloads the repo to /tmp/hh
|
126
|
+
```
|
127
|
+
|
128
|
+
|
129
|
+
## Other Useful Code
|
130
|
+
|
131
|
+
Miscellaneous helper methods and classes.
|
132
|
+
|
133
|
+
#### main
|
134
|
+
|
135
|
+
How to print to the user from Hardhat:
|
136
|
+
|
137
|
+
```ruby
|
138
|
+
inform "something to tell the user"
|
139
|
+
warn "a thing to be weary of"
|
140
|
+
error "oh god something broke"
|
141
|
+
```
|
142
|
+
|
143
|
+
#### Hardhat::System
|
144
|
+
|
145
|
+
Helper module for interacting with the operating system.
|
146
|
+
|
147
|
+
__::has? -> boolean__
|
148
|
+
|
149
|
+
```ruby
|
150
|
+
Hardhat::System.has?('git') => true
|
151
|
+
Hardhat::System.has?(['git', 'svn']) => false
|
152
|
+
```
|
data/Rakefile
ADDED
data/bin/bootstrap
ADDED
@@ -0,0 +1,50 @@
|
|
1
|
+
#!/bin/bash
|
2
|
+
# __ ____ __ __
|
3
|
+
# _/ / _/_/ /_ ____ ____ / /______/ /__________ _____
|
4
|
+
# / __/ _/_// __ \/ __ \/ __ \/ __/ ___/ __/ ___/ __ `/ __ \
|
5
|
+
# (_ ) _ _/_/ / /_/ / /_/ / /_/ / /_(__ ) /_/ / / /_/ / /_/ /
|
6
|
+
# / _/ (_)_/ /_.___/\____/\____/\__/____/\__/_/ \__,_/ .___/
|
7
|
+
# /_/ /_/
|
8
|
+
#
|
9
|
+
# Installs what is required to have a sane system for building
|
10
|
+
# our application.
|
11
|
+
#
|
12
|
+
# Sane requires:
|
13
|
+
# * Git
|
14
|
+
# * Ruby interpreter with
|
15
|
+
# * rubygems (included in 1.9.3)
|
16
|
+
# * bundler
|
17
|
+
# * Hardhat
|
18
|
+
#
|
19
|
+
|
20
|
+
# Whitelist platforms we've tested this script on, and plan
|
21
|
+
# to support. This is the output of `uname -mrs`
|
22
|
+
SUPPORTED_PLATFORMS=(
|
23
|
+
"Linux 2.6.32-33-generic-pae i686"
|
24
|
+
)
|
25
|
+
is_supported_platform() {
|
26
|
+
for s in "${SUPPORTED_PLATFORMS[@]}"; do
|
27
|
+
if [ "$s" == "$(uname -mrs)" ]; then
|
28
|
+
return 0
|
29
|
+
fi
|
30
|
+
done
|
31
|
+
echo unsupported platform please use one of:
|
32
|
+
echo ${SUPPORTED_PLATFORMS[@]}
|
33
|
+
return 1
|
34
|
+
}
|
35
|
+
# exit if the user is on unsupported platform.
|
36
|
+
if ! is_supported_platform; then
|
37
|
+
exit 1
|
38
|
+
fi
|
39
|
+
|
40
|
+
# We'll need this for building anything (ruby in this case).
|
41
|
+
echo "installing build-essential..."
|
42
|
+
sudo apt-get install -qqy build-essential zlib1g zlib1g-dev
|
43
|
+
|
44
|
+
# Install Git
|
45
|
+
echo "installing git-core..."
|
46
|
+
sudo apt-get install -qqy git-core
|
47
|
+
|
48
|
+
# Install RVM & ruby (might not use rvm in the future)
|
49
|
+
sudo apt-get install -qqy curl # needed for RVM
|
50
|
+
\curl -L https://get.rvm.io | bash -s stable --ruby
|
data/bin/hardhat
ADDED
@@ -0,0 +1,50 @@
|
|
1
|
+
#!/usr/bin/env ruby
|
2
|
+
$LOAD_PATH.unshift File.expand_path("../../lib", __FILE__)
|
3
|
+
require 'hardhat'
|
4
|
+
require 'trollop'
|
5
|
+
|
6
|
+
class Hardhat::Runner
|
7
|
+
instance_methods.each do |m|
|
8
|
+
undef_method(m) unless %w(__send__ __id__ send class inspect instance_eval instance_variables object_id).include?(m.to_s)
|
9
|
+
end
|
10
|
+
|
11
|
+
include Hardhat
|
12
|
+
# Given a file path, open the file, and eval within the context of
|
13
|
+
# this module.
|
14
|
+
#
|
15
|
+
def self.eval(file, options = {})
|
16
|
+
new.instance_eval(File.read(file), file)
|
17
|
+
end
|
18
|
+
end
|
19
|
+
|
20
|
+
SUB_COMMANDS = %w(build)
|
21
|
+
global_options = Trollop::options do
|
22
|
+
banner <<-EOF
|
23
|
+
d:) hardhat
|
24
|
+
|
25
|
+
Usage:
|
26
|
+
hardhat [options] [subcommand]
|
27
|
+
|
28
|
+
where [subcommand]s are
|
29
|
+
build
|
30
|
+
|
31
|
+
where [options] are:
|
32
|
+
EOF
|
33
|
+
stop_on SUB_COMMANDS
|
34
|
+
end
|
35
|
+
|
36
|
+
command = ARGV.shift
|
37
|
+
case command
|
38
|
+
|
39
|
+
when "build"
|
40
|
+
options = Trollop::options do
|
41
|
+
opt :blueprint, "Specify a file path for a blueprint", :short => "-b",
|
42
|
+
:default => 'blueprint.rb'
|
43
|
+
end
|
44
|
+
Trollop::die "blueprint must exist" unless File.exist?(options[:blueprint]) if options[:blueprint]
|
45
|
+
Hardhat::Runner.eval(options[:blueprint])
|
46
|
+
|
47
|
+
|
48
|
+
else
|
49
|
+
Trollop::die "unknown subcommand #{command.inspect}"
|
50
|
+
end
|
@@ -0,0 +1,52 @@
|
|
1
|
+
# if we want to chroot
|
2
|
+
|
3
|
+
# Prompt for password here to get it out of the way.
|
4
|
+
System.prompt_sudo("Starting build")
|
5
|
+
|
6
|
+
deps = [
|
7
|
+
"cryptsetup","ssh","subversion","nfs-common","libssl-dev","tftpd-hpa",
|
8
|
+
"tftp-hpa","libipc-shareable-perl","libgd-graph-perl",
|
9
|
+
"libshell-posix-select-perl","unzip","traceroute",
|
10
|
+
"libbusiness-onlinepayment-authorizenet-perl",
|
11
|
+
"speedy-cgi-perl","djbdns","libxml2-dev","apache2-threaded-dev","apache2",
|
12
|
+
"ethtool","g++","libxmlrpc-c3","libxmlrpc-c3-dev","libpopt-dev","smbfs",
|
13
|
+
"acpid","libboost-dev","watchdog","curl","libcurl4-openssl-dev","snmpd",
|
14
|
+
"snmp","imagemagick","beanstalkd","build-essential","bison","openssl",
|
15
|
+
"libreadline6","libreadline6-dev","curl","git-core","zlib1g","zlib1g-dev",
|
16
|
+
"libssl-dev","libyaml-dev","libsqlite3-0","libsqlite3-dev","sqlite3",
|
17
|
+
"libxml2-dev","libxslt-dev","autoconf","libc6-dev","libqt4-dev","postgresql",
|
18
|
+
"postgresql-server-dev-8.4","postgresql-client-common","libtool",
|
19
|
+
].map { |e| Dependency.new(e, :installer => 'apt-get') }
|
20
|
+
|
21
|
+
inform "Installing system dependencies"
|
22
|
+
apt_get = Installer.new("apt-get", :sudo => true, :flags => "-qqy")
|
23
|
+
apt_get.update
|
24
|
+
apt_get.install deps
|
25
|
+
|
26
|
+
inform "Installing perl dependencies"
|
27
|
+
# add env setting to installer
|
28
|
+
`PERL_MM_USE_DEFAULT=1 cpan DBI Convert:ASN1 Digest:MD5 Digest:SHA1 Digest:HMAC IO Storable Cache:Mmap NetAddr:IP Text:CSV_XS Time:HiRes XML:Parser Crypt:DES Net:SNMP NetPacket Net_SSLeay IO:Socket:SSL Digest:MD4 Crypt:CBC perl:ldap Apache:AuthenNTLM Crypt:SSLeay Frontier:RPC HTML:Tagset HTML:Parser MIME:Base64 URI libwww:perl Bit:Vector Date:Calc TimeDate File:Tail GD GDTextUtil perlipq Authen:Krb5:Simple Filter XML:Dumper Config:Properties Text:Balanced Compress:Zlib Business:OnlinePayment Business:OnlinePayment:AuthorizeNet Class:Accessor HTML:Tree JSON JSON:Syck Module:Build HTML:Prototype Mail:Sender Mail:Sender:Easy IO:Tty Expect Business:OnlinePayment:CyberSource Switch Proc:Reliable Business:CreditCard Business:CreditCard:Object`
|
29
|
+
`PERL_MM_USE_DEFAULT=1 cpan Archive::Zip Test::Warn SOAP:Lite Class:C3:XS JSON:XS XML:LibXML:Common XML:NamespaceSupport XML:SAX XML:LibXML Data:Dumper:Simple Tie:IxHash XML:Simple YAML SQL:Abstract SQL:Abstract:Limit Algorithm:C3 Class:C3 Class:Inspector Class:C3:Componentised Module:Find MRO:Compat Carp:Clan Scope:Guard Class:Accessor:Grouped Class:Accessor:Chained Data:Page DBIx:Class Class:Data:Inheritable Devel:StackTrace Exception:Class Tree JSON:RPC Email:Public Authen::SASL XML::SAX::Writer XML::Filter::BufferText Net::LDAP CGI Text::Autoformat Data::Dump List::MoreUtils Mail::POP3Client`
|
30
|
+
`PERL_MM_USE_DEFAULT=1 cpan Sort::Versions File::chdir`
|
31
|
+
`PERL_MM_USE_DEFAULT=1 cpan DBD::Pg Beanstalk::Client Redis`
|
32
|
+
|
33
|
+
inform "Creating user - blueserver"
|
34
|
+
# System.add_user('blueserver')
|
35
|
+
useradd -m blueserver
|
36
|
+
su - blueserver
|
37
|
+
|
38
|
+
# get fresh vcommon from svn
|
39
|
+
petri = Repository::Svn.new "https://trac.eng.bluesocket.com/repos/petri/branches/vwlan-2_3", "~/petri"
|
40
|
+
petri.get
|
41
|
+
|
42
|
+
# run vmware-install.pl
|
43
|
+
|
44
|
+
# copy rootfs
|
45
|
+
|
46
|
+
|
47
|
+
# copy/append files with headers
|
48
|
+
|
49
|
+
# make C from build blue
|
50
|
+
|
51
|
+
# migrate and seed database
|
52
|
+
|
data/hardhat.gemspec
ADDED
@@ -0,0 +1,24 @@
|
|
1
|
+
# -*- encoding: utf-8 -*-
|
2
|
+
lib = File.expand_path('../lib', __FILE__)
|
3
|
+
$LOAD_PATH.unshift(lib) unless $LOAD_PATH.include?(lib)
|
4
|
+
require 'hardhat/version'
|
5
|
+
|
6
|
+
Gem::Specification.new do |gem|
|
7
|
+
gem.name = "hardhat"
|
8
|
+
gem.version = Hardhat::VERSION
|
9
|
+
gem.authors = ["Nathan Lilienthal"]
|
10
|
+
gem.email = ["nathanl@ccs.neu.edu"]
|
11
|
+
gem.description = %q{Elegant DSL for managing build dependencies and project builds.}
|
12
|
+
gem.summary = %q{Construction for your project.}
|
13
|
+
gem.homepage = "https://github.com/nathan/hardhat"
|
14
|
+
|
15
|
+
gem.files = `git ls-files`.split($/)
|
16
|
+
gem.executables << 'hardhat'
|
17
|
+
gem.test_files = gem.files.grep(%r{^(test|spec|features)/})
|
18
|
+
gem.require_paths = ["lib"]
|
19
|
+
|
20
|
+
gem.add_dependency('trollop')
|
21
|
+
|
22
|
+
gem.add_development_dependency('rake')
|
23
|
+
gem.add_development_dependency('rspec')
|
24
|
+
end
|
data/lib/hardhat.rb
ADDED
@@ -0,0 +1,33 @@
|
|
1
|
+
module Hardhat
|
2
|
+
|
3
|
+
# Prefix to be printed before every message.
|
4
|
+
PREFIX = "d:) ->"
|
5
|
+
|
6
|
+
# Printing methods:
|
7
|
+
# * inform : info about the build.
|
8
|
+
# * warn : non critical errors.
|
9
|
+
# * error : blocking errors.
|
10
|
+
#
|
11
|
+
# Use these methods for interacting with STDOUT exclusively,
|
12
|
+
# to help keep the build process feel uniform.
|
13
|
+
#
|
14
|
+
def inform(string)
|
15
|
+
puts "#{PREFIX.magenta} #{string}"
|
16
|
+
end
|
17
|
+
|
18
|
+
def warn(string)
|
19
|
+
puts "#{PREFIX.magenta} #{"WARNING:".yellow} #{string}".yellow
|
20
|
+
end
|
21
|
+
|
22
|
+
def error(string)
|
23
|
+
puts "#{PREFIX.magenta} #{"ERROR:".red} #{string}".red
|
24
|
+
end
|
25
|
+
|
26
|
+
end
|
27
|
+
|
28
|
+
require "hardhat/dependency"
|
29
|
+
require "hardhat/ext"
|
30
|
+
require "hardhat/installer"
|
31
|
+
require "hardhat/repository"
|
32
|
+
require "hardhat/system"
|
33
|
+
require "hardhat/version"
|
@@ -0,0 +1,38 @@
|
|
1
|
+
class Hardhat::Dependency
|
2
|
+
|
3
|
+
attr_reader :name, :installers, :flags
|
4
|
+
|
5
|
+
def initialize(name, options={})
|
6
|
+
unless options.is_a? Hash
|
7
|
+
raise ArgumentError.new "options should be a hash"
|
8
|
+
end
|
9
|
+
@name = name
|
10
|
+
@installers = ([] << options[:installer]).flatten.compact
|
11
|
+
@sudo = options[:sudo]
|
12
|
+
@flags = options[:flags]
|
13
|
+
end
|
14
|
+
|
15
|
+
# sudo? -> Boolean
|
16
|
+
# Returns a boolean indicating if this dependency needs to
|
17
|
+
# be handled as root. This will overide installer defaults.
|
18
|
+
#
|
19
|
+
def sudo?
|
20
|
+
!!@sudo
|
21
|
+
end
|
22
|
+
|
23
|
+
# to_s -> String
|
24
|
+
# Returns the name of this dependency.
|
25
|
+
# This is used when formatting the system call
|
26
|
+
#
|
27
|
+
def to_s
|
28
|
+
name
|
29
|
+
end
|
30
|
+
|
31
|
+
# inspect -> String
|
32
|
+
# Debugging output for this dependency
|
33
|
+
#
|
34
|
+
def inspect
|
35
|
+
"#<#{self.class}: #{self.name}>"
|
36
|
+
end
|
37
|
+
|
38
|
+
end
|
data/lib/hardhat/ext.rb
ADDED
@@ -0,0 +1 @@
|
|
1
|
+
require "hardhat/ext/string"
|
@@ -0,0 +1,16 @@
|
|
1
|
+
class String
|
2
|
+
|
3
|
+
def colorize(color_code)
|
4
|
+
"\e[#{color_code}m#{self}\e[0m"
|
5
|
+
end
|
6
|
+
|
7
|
+
def black; self.colorize(30); end
|
8
|
+
def red; self.colorize(31); end
|
9
|
+
def green; self.colorize(32); end
|
10
|
+
def yellow; self.colorize(33); end
|
11
|
+
def blue; self.colorize(34); end
|
12
|
+
def magenta; self.colorize(35); end
|
13
|
+
def cyan; self.colorize(36); end
|
14
|
+
def white; self.colorize(37); end
|
15
|
+
|
16
|
+
end
|
@@ -0,0 +1,53 @@
|
|
1
|
+
class Hardhat::Installer
|
2
|
+
COMMANDS = [:install, :uninstall, :update]
|
3
|
+
|
4
|
+
attr_reader :program, :flags
|
5
|
+
|
6
|
+
def initialize(program, options={})
|
7
|
+
unless options.is_a? Hash
|
8
|
+
raise ArgumentError.new "options should be a hash"
|
9
|
+
end
|
10
|
+
unless Hardhat::System.has? program
|
11
|
+
raise ArgumentError.new "program not found: #{program}"
|
12
|
+
end
|
13
|
+
@program = program
|
14
|
+
@sudo = options[:sudo]
|
15
|
+
@flags = options[:flags]
|
16
|
+
|
17
|
+
# dynamicly create a method for each COMMAND.
|
18
|
+
metaclass = class << self; self; end
|
19
|
+
COMMANDS.each do |cmd|
|
20
|
+
if options.key? cmd
|
21
|
+
instance_variable_set("@#{cmd}", options[cmd])
|
22
|
+
else
|
23
|
+
instance_variable_set("@#{cmd}", cmd)
|
24
|
+
end
|
25
|
+
metaclass.send(:define_method, cmd) do |dependency = nil, options = {}|
|
26
|
+
if cmd != :update && dependency.nil?
|
27
|
+
raise ArgumentError.new("requires a dependency")
|
28
|
+
end
|
29
|
+
run instance_variable_get("@#{cmd}"), dependency, options
|
30
|
+
end
|
31
|
+
end
|
32
|
+
end
|
33
|
+
|
34
|
+
# Always returns a valid bolean
|
35
|
+
def sudo?
|
36
|
+
!!@sudo
|
37
|
+
end
|
38
|
+
|
39
|
+
private
|
40
|
+
|
41
|
+
# HACK: This code below really needs to be cleaned up,
|
42
|
+
# and broken into helper function.
|
43
|
+
def run(command, dependency, options={})
|
44
|
+
[dependency].flatten.each do |d|
|
45
|
+
unless !d || d.installers.empty? || d.installers.include?(program)
|
46
|
+
raise "bad installer"
|
47
|
+
end
|
48
|
+
s = options[:sudo].nil? ? sudo? || (d.sudo? if d) : options[:sudo]
|
49
|
+
f = options[:flags].nil? ? "#{flags+' ' if flags}#{d.flags if d}" : options[:flags]
|
50
|
+
system "#{'sudo ' if s}#{program} #{command} #{f+' ' unless f.to_s == ''}#{d}"
|
51
|
+
end
|
52
|
+
end
|
53
|
+
end
|
@@ -0,0 +1,18 @@
|
|
1
|
+
module Hardhat::Repository
|
2
|
+
attr_accessor :url, :path
|
3
|
+
|
4
|
+
def initialize(url, path, options={})
|
5
|
+
@url = url
|
6
|
+
@path = File.expand_path(path)
|
7
|
+
end
|
8
|
+
|
9
|
+
# Implementations of a repository (Classes that include this module)
|
10
|
+
# MUST define the following methods.
|
11
|
+
# * get : Downloads the latest code from @url to @path
|
12
|
+
# * branch : Switches the active branch of this repo.
|
13
|
+
#
|
14
|
+
|
15
|
+
end
|
16
|
+
|
17
|
+
require 'hardhat/repository/git'
|
18
|
+
require 'hardhat/repository/svn'
|
@@ -0,0 +1,19 @@
|
|
1
|
+
module Hardhat::System
|
2
|
+
extend Hardhat
|
3
|
+
|
4
|
+
def self.has?(command)
|
5
|
+
[*command].map do |cmd|
|
6
|
+
system "command -v #{cmd} > /dev/null 2>&1"
|
7
|
+
end.all?
|
8
|
+
end
|
9
|
+
|
10
|
+
def self.prompt_sudo(string)
|
11
|
+
if system "sudo -k true"
|
12
|
+
inform string
|
13
|
+
else
|
14
|
+
error "couldn't execute sudo"
|
15
|
+
exit 1
|
16
|
+
end
|
17
|
+
end
|
18
|
+
|
19
|
+
end
|
@@ -0,0 +1,55 @@
|
|
1
|
+
require "spec_helper"
|
2
|
+
|
3
|
+
describe Dependency do
|
4
|
+
|
5
|
+
before :each do
|
6
|
+
# must install with gem
|
7
|
+
@rails = Dependency.new("rails", :installer => "gem")
|
8
|
+
@highline = Dependency.new("highline", :sudo => false, :installer => "gem")
|
9
|
+
@bundler = Dependency.new("bundler", :sudo => true, :installer => "gem")
|
10
|
+
|
11
|
+
# doesn't care what you install with
|
12
|
+
@foo = Dependency.new('foo', :flags => "-noop")
|
13
|
+
@bar = Dependency.new('bar', :sudo => false, :flags => "--verbose -q")
|
14
|
+
@baz = Dependency.new('baz', :sudo => true, :flags => "-qweF=1")
|
15
|
+
|
16
|
+
# can install with array of installer names
|
17
|
+
@git = Dependency.new("git", :installer => ["apt-get", "yum"])
|
18
|
+
@ack = Dependency.new("ack", :sudo => false, :installer => ["apt-get", "yum"])
|
19
|
+
@curl = Dependency.new("curl", :sudo => true, :installer => ["apt-get", "yum"])
|
20
|
+
|
21
|
+
@deps = [@rails, @highline, @bundler, @foo, @bar, @baz, @git, @ack, @curl]
|
22
|
+
end
|
23
|
+
|
24
|
+
it "requires a hash as the 2nd argument" do
|
25
|
+
expect { Dependency.new("gem", "string") }.to raise_error(ArgumentError)
|
26
|
+
end
|
27
|
+
|
28
|
+
it "has a name" do
|
29
|
+
names = ["rails", "highline", "bundler", "foo", "bar", "baz", "git", "ack", "curl"]
|
30
|
+
@deps.zip(names).each do |dep, name|
|
31
|
+
dep.name.should == name
|
32
|
+
end
|
33
|
+
end
|
34
|
+
|
35
|
+
it "has an array of installers" do
|
36
|
+
@deps.each do |dep|
|
37
|
+
dep.installers.should be_an Array
|
38
|
+
end
|
39
|
+
end
|
40
|
+
|
41
|
+
it "has a sudo? method" do
|
42
|
+
@deps.each do |dep|
|
43
|
+
bool = dep.sudo?
|
44
|
+
bool.should == !!bool # is_a Boolean
|
45
|
+
end
|
46
|
+
end
|
47
|
+
|
48
|
+
it "support flags" do
|
49
|
+
@rails.flags.should be_nil
|
50
|
+
@foo.flags.should == "-noop"
|
51
|
+
@bar.flags.should == "--verbose -q"
|
52
|
+
@baz.flags.should == "-qweF=1"
|
53
|
+
end
|
54
|
+
|
55
|
+
end
|
@@ -0,0 +1,178 @@
|
|
1
|
+
require "spec_helper"
|
2
|
+
|
3
|
+
describe Installer do
|
4
|
+
|
5
|
+
# Stub out System.has? to allow us to use fake installers.
|
6
|
+
# Installer.new checks to see if the OS has that program.
|
7
|
+
#
|
8
|
+
before :all do
|
9
|
+
module Hardhat::System
|
10
|
+
class << self
|
11
|
+
alias _has? has?
|
12
|
+
def has?(program)
|
13
|
+
true
|
14
|
+
end
|
15
|
+
end
|
16
|
+
end
|
17
|
+
end
|
18
|
+
|
19
|
+
after :all do
|
20
|
+
module Hardhat::System
|
21
|
+
class << self
|
22
|
+
alias has? _has?
|
23
|
+
end
|
24
|
+
end
|
25
|
+
end
|
26
|
+
|
27
|
+
before :each do
|
28
|
+
@gem_i = Installer.new('gem')
|
29
|
+
@apt_i = Installer.new('apt-get', :uninstall => :remove)
|
30
|
+
@flag_i = Installer.new('fman', :flags => '-qqy')
|
31
|
+
@sudo_i = Installer.new('sman', :sudo => true)
|
32
|
+
|
33
|
+
# must install with gem
|
34
|
+
@rails = Dependency.new("rails", :installer => "gem")
|
35
|
+
@highline = Dependency.new("highline", :sudo => false, :installer => "gem")
|
36
|
+
@bundler = Dependency.new("bundler", :sudo => true, :installer => "gem")
|
37
|
+
@gems = [@rails, @highline, @bundler]
|
38
|
+
|
39
|
+
# doesn't care what you install with
|
40
|
+
@foo = Dependency.new('foo')
|
41
|
+
@bar = Dependency.new('bar', :sudo => false, :flags => "--verbose -q")
|
42
|
+
@baz = Dependency.new('baz', :sudo => true, :flags => "-qweF=1")
|
43
|
+
@random = [@foo, @bar, @baz]
|
44
|
+
|
45
|
+
# can install with array of installer names
|
46
|
+
@git = Dependency.new("git", :installer => ["apt-get", "yum"])
|
47
|
+
@ack = Dependency.new("ack", :sudo => false, :installer => ["apt-get", "yum"])
|
48
|
+
@curl = Dependency.new("curl", :sudo => true, :installer => ["apt-get", "yum"])
|
49
|
+
end
|
50
|
+
|
51
|
+
it "should have a program to run" do
|
52
|
+
@gem_i.program.should be_a String
|
53
|
+
@gem_i.program.should == "gem"
|
54
|
+
@apt_i.program.should == "apt-get"
|
55
|
+
end
|
56
|
+
|
57
|
+
it "should allow custom command mappings" do
|
58
|
+
@apt_i.should_receive(:system).with(/remove/).once
|
59
|
+
@apt_i.uninstall(@foo)
|
60
|
+
end
|
61
|
+
|
62
|
+
it "should have a method for each in COMMANDS, that calls system" do
|
63
|
+
Installer::COMMANDS.each do |cmd|
|
64
|
+
@gem_i.should_receive(:system).with("gem #{cmd} foo").once
|
65
|
+
@gem_i.public_send(cmd, @foo)
|
66
|
+
end
|
67
|
+
end
|
68
|
+
|
69
|
+
# update should be able to be called without args
|
70
|
+
|
71
|
+
it "should handle noarg update" do
|
72
|
+
@gem_i.should_receive(:system).with(/gem update/).once
|
73
|
+
@gem_i.update
|
74
|
+
end
|
75
|
+
|
76
|
+
it "should still require dependencies for other commands" do
|
77
|
+
expect { @gem_i.install }.to raise_error(ArgumentError)
|
78
|
+
end
|
79
|
+
|
80
|
+
# dep array
|
81
|
+
|
82
|
+
it "should handle an array of dependencies" do
|
83
|
+
Installer::COMMANDS.each do |cmd|
|
84
|
+
@gem_i.should_receive(:system).with(/gem #{cmd}/).exactly(3).times
|
85
|
+
@gem_i.public_send(cmd, @gems)
|
86
|
+
end
|
87
|
+
end
|
88
|
+
|
89
|
+
# sudo
|
90
|
+
|
91
|
+
it "should support sudo in installer" do
|
92
|
+
Installer::COMMANDS.each do |cmd|
|
93
|
+
@sudo_i.should_receive(:system).with(/sudo/).once
|
94
|
+
@sudo_i.public_send(cmd, @foo)
|
95
|
+
end
|
96
|
+
end
|
97
|
+
|
98
|
+
it "should support sudo from dependencies" do
|
99
|
+
Installer::COMMANDS.each do |cmd|
|
100
|
+
@gem_i.should_receive(:system).with(/sudo/).once
|
101
|
+
@gem_i.public_send(cmd, @bundler)
|
102
|
+
end
|
103
|
+
end
|
104
|
+
|
105
|
+
it "should support sudo when calling commands" do
|
106
|
+
Installer::COMMANDS.each do |cmd|
|
107
|
+
@gem_i.should_receive(:system).with(/sudo/).once
|
108
|
+
@gem_i.public_send(cmd, @foo, :sudo => true)
|
109
|
+
end
|
110
|
+
end
|
111
|
+
|
112
|
+
it "should respect flags of command arguments over installer" do
|
113
|
+
Installer::COMMANDS.each do |cmd|
|
114
|
+
@sudo_i.should_not_receive(:system).with(/sudo/)
|
115
|
+
@sudo_i.public_send(cmd, @foo, :sudo => false)
|
116
|
+
end
|
117
|
+
end
|
118
|
+
|
119
|
+
it "should respect flags of command arguments over dependency" do
|
120
|
+
Installer::COMMANDS.each do |cmd|
|
121
|
+
@gem_i.should_receive(:system).with(/sudo/)
|
122
|
+
@gem_i.public_send(cmd, @bar, :sudo => true)
|
123
|
+
end
|
124
|
+
end
|
125
|
+
|
126
|
+
# flags
|
127
|
+
|
128
|
+
it "should support flags in installer" do
|
129
|
+
Installer::COMMANDS.each do |cmd|
|
130
|
+
@flag_i.should_receive(:system).with(/-qqy/).once
|
131
|
+
@flag_i.public_send(cmd, @foo)
|
132
|
+
end
|
133
|
+
end
|
134
|
+
|
135
|
+
it "should support flags from dependencies" do
|
136
|
+
Installer::COMMANDS.each do |cmd|
|
137
|
+
@gem_i.should_receive(:system).with(/--verbose -q/).once
|
138
|
+
@gem_i.public_send(cmd, @bar)
|
139
|
+
end
|
140
|
+
end
|
141
|
+
|
142
|
+
it "should support flags arguments when calling commands" do
|
143
|
+
Installer::COMMANDS.each do |cmd|
|
144
|
+
@gem_i.should_receive(:system).with(/--quite/).once
|
145
|
+
@gem_i.public_send(cmd, @foo, :flags => '--quite')
|
146
|
+
end
|
147
|
+
end
|
148
|
+
|
149
|
+
it "should respect flags of command arguments over installer" do
|
150
|
+
Installer::COMMANDS.each do |cmd|
|
151
|
+
@flag_i.should_not_receive(:system).with(/-qqy/)
|
152
|
+
@flag_i.public_send(cmd, @foo, :flags => '-lol')
|
153
|
+
end
|
154
|
+
end
|
155
|
+
|
156
|
+
it "should respect flags of command arguments over dependency" do
|
157
|
+
Installer::COMMANDS.each do |cmd|
|
158
|
+
@flag_i.should_not_receive(:system).with(/--verbose -q/)
|
159
|
+
@flag_i.public_send(cmd, @bar, :flags => '-lol')
|
160
|
+
end
|
161
|
+
end
|
162
|
+
|
163
|
+
# allowable installer
|
164
|
+
|
165
|
+
it "should not install a dependency without itself in array of installers" do
|
166
|
+
Installer::COMMANDS.each do |cmd|
|
167
|
+
@gem_i.should_not_receive(:system) # no sys calls in tests
|
168
|
+
expect { @gem_i.public_send(cmd, @git) }.to raise_error
|
169
|
+
end
|
170
|
+
end
|
171
|
+
|
172
|
+
it "should not install a dependency without itself as the installer" do
|
173
|
+
Installer::COMMANDS.each do |cmd|
|
174
|
+
expect { @flag_i.public_send(cmd, @rails) }.to raise_error
|
175
|
+
end
|
176
|
+
end
|
177
|
+
|
178
|
+
end
|
data/spec/spec_helper.rb
ADDED
@@ -0,0 +1,29 @@
|
|
1
|
+
require "spec_helper"
|
2
|
+
require "fileutils"
|
3
|
+
|
4
|
+
include Hardhat
|
5
|
+
shared_examples_for Repository do
|
6
|
+
|
7
|
+
after :each do
|
8
|
+
FileUtils.rm_rf host.path
|
9
|
+
end
|
10
|
+
|
11
|
+
it "should have a url" do
|
12
|
+
host.should respond_to(:url)
|
13
|
+
end
|
14
|
+
|
15
|
+
it "should have a path" do
|
16
|
+
host.should respond_to(:path)
|
17
|
+
end
|
18
|
+
|
19
|
+
it "should redefine the get method" do
|
20
|
+
host.should respond_to(:get)
|
21
|
+
end
|
22
|
+
|
23
|
+
it "should download a project with `get`" do
|
24
|
+
raise "#{host.path} already exists" if Dir.exists? host.path
|
25
|
+
host.get
|
26
|
+
Dir.exists?(host.path).should be_true
|
27
|
+
end
|
28
|
+
|
29
|
+
end
|
data/spec/system_spec.rb
ADDED
@@ -0,0 +1,32 @@
|
|
1
|
+
require "spec_helper"
|
2
|
+
|
3
|
+
describe System do
|
4
|
+
|
5
|
+
describe "::has?" do
|
6
|
+
it "should check for installed programs" do
|
7
|
+
System.has?(:ls).should be_true
|
8
|
+
System.has?([:ls, :cd, :rm]).should be_true
|
9
|
+
System.has?(:foobarbaz).should be_false
|
10
|
+
end
|
11
|
+
end
|
12
|
+
|
13
|
+
describe "::prompt_sudo" do
|
14
|
+
context "with correct password" do
|
15
|
+
it "prompts user for sudo password and informs given string" do
|
16
|
+
string = "hello friend"
|
17
|
+
System.should_receive(:system).with(/sudo -k/).and_return(true)
|
18
|
+
$stdout.should_receive(:puts).with(/#{string}/)
|
19
|
+
System.prompt_sudo(string)
|
20
|
+
end
|
21
|
+
end
|
22
|
+
|
23
|
+
context "with incorrect password" do
|
24
|
+
it "prompts user for sudo then errors and exits" do
|
25
|
+
System.should_receive(:system).with(/sudo -k/).and_return(false)
|
26
|
+
$stdout.should_receive(:puts).with(/couldn't execute sudo/)
|
27
|
+
expect { System.prompt_sudo("hello") }.to raise_error(SystemExit)
|
28
|
+
end
|
29
|
+
end
|
30
|
+
end
|
31
|
+
|
32
|
+
end
|
@@ -0,0 +1,22 @@
|
|
1
|
+
require "spec_helper"
|
2
|
+
|
3
|
+
describe Hardhat do
|
4
|
+
describe "::VERSION" do
|
5
|
+
|
6
|
+
it "should be a String" do
|
7
|
+
Hardhat::VERSION.should be_a(String)
|
8
|
+
end
|
9
|
+
|
10
|
+
it "should have valid version numbers" do
|
11
|
+
version = Hardhat::VERSION.split('.')
|
12
|
+
version.each do |part|
|
13
|
+
expect { Integer(part) }.to_not raise_error
|
14
|
+
end
|
15
|
+
end
|
16
|
+
|
17
|
+
it "should only have 3 parts" do
|
18
|
+
Hardhat::VERSION.split('.').should have(3).items
|
19
|
+
end
|
20
|
+
|
21
|
+
end
|
22
|
+
end
|
metadata
ADDED
@@ -0,0 +1,130 @@
|
|
1
|
+
--- !ruby/object:Gem::Specification
|
2
|
+
name: hardhat
|
3
|
+
version: !ruby/object:Gem::Version
|
4
|
+
version: 0.0.1
|
5
|
+
prerelease:
|
6
|
+
platform: ruby
|
7
|
+
authors:
|
8
|
+
- Nathan Lilienthal
|
9
|
+
autorequire:
|
10
|
+
bindir: bin
|
11
|
+
cert_chain: []
|
12
|
+
date: 2013-02-21 00:00:00.000000000 Z
|
13
|
+
dependencies:
|
14
|
+
- !ruby/object:Gem::Dependency
|
15
|
+
name: trollop
|
16
|
+
requirement: !ruby/object:Gem::Requirement
|
17
|
+
none: false
|
18
|
+
requirements:
|
19
|
+
- - ! '>='
|
20
|
+
- !ruby/object:Gem::Version
|
21
|
+
version: '0'
|
22
|
+
type: :runtime
|
23
|
+
prerelease: false
|
24
|
+
version_requirements: !ruby/object:Gem::Requirement
|
25
|
+
none: false
|
26
|
+
requirements:
|
27
|
+
- - ! '>='
|
28
|
+
- !ruby/object:Gem::Version
|
29
|
+
version: '0'
|
30
|
+
- !ruby/object:Gem::Dependency
|
31
|
+
name: rake
|
32
|
+
requirement: !ruby/object:Gem::Requirement
|
33
|
+
none: false
|
34
|
+
requirements:
|
35
|
+
- - ! '>='
|
36
|
+
- !ruby/object:Gem::Version
|
37
|
+
version: '0'
|
38
|
+
type: :development
|
39
|
+
prerelease: false
|
40
|
+
version_requirements: !ruby/object:Gem::Requirement
|
41
|
+
none: false
|
42
|
+
requirements:
|
43
|
+
- - ! '>='
|
44
|
+
- !ruby/object:Gem::Version
|
45
|
+
version: '0'
|
46
|
+
- !ruby/object:Gem::Dependency
|
47
|
+
name: rspec
|
48
|
+
requirement: !ruby/object:Gem::Requirement
|
49
|
+
none: false
|
50
|
+
requirements:
|
51
|
+
- - ! '>='
|
52
|
+
- !ruby/object:Gem::Version
|
53
|
+
version: '0'
|
54
|
+
type: :development
|
55
|
+
prerelease: false
|
56
|
+
version_requirements: !ruby/object:Gem::Requirement
|
57
|
+
none: false
|
58
|
+
requirements:
|
59
|
+
- - ! '>='
|
60
|
+
- !ruby/object:Gem::Version
|
61
|
+
version: '0'
|
62
|
+
description: Elegant DSL for managing build dependencies and project builds.
|
63
|
+
email:
|
64
|
+
- nathanl@ccs.neu.edu
|
65
|
+
executables:
|
66
|
+
- hardhat
|
67
|
+
extensions: []
|
68
|
+
extra_rdoc_files: []
|
69
|
+
files:
|
70
|
+
- .gitignore
|
71
|
+
- .rspec
|
72
|
+
- Gemfile
|
73
|
+
- LICENSE.txt
|
74
|
+
- README.md
|
75
|
+
- Rakefile
|
76
|
+
- bin/bootstrap
|
77
|
+
- bin/hardhat
|
78
|
+
- example/blueprint.rb
|
79
|
+
- hardhat.gemspec
|
80
|
+
- lib/hardhat.rb
|
81
|
+
- lib/hardhat/dependency.rb
|
82
|
+
- lib/hardhat/ext.rb
|
83
|
+
- lib/hardhat/ext/string.rb
|
84
|
+
- lib/hardhat/installer.rb
|
85
|
+
- lib/hardhat/repository.rb
|
86
|
+
- lib/hardhat/repository/git.rb
|
87
|
+
- lib/hardhat/repository/svn.rb
|
88
|
+
- lib/hardhat/system.rb
|
89
|
+
- lib/hardhat/version.rb
|
90
|
+
- spec/dependency_spec.rb
|
91
|
+
- spec/installer_spec.rb
|
92
|
+
- spec/repository/git_spec.rb
|
93
|
+
- spec/repository/svn_spec.rb
|
94
|
+
- spec/spec_helper.rb
|
95
|
+
- spec/support/shared_examples_for_repository.rb
|
96
|
+
- spec/system_spec.rb
|
97
|
+
- spec/version_spec.rb
|
98
|
+
homepage: https://github.com/nathan/hardhat
|
99
|
+
licenses: []
|
100
|
+
post_install_message:
|
101
|
+
rdoc_options: []
|
102
|
+
require_paths:
|
103
|
+
- lib
|
104
|
+
required_ruby_version: !ruby/object:Gem::Requirement
|
105
|
+
none: false
|
106
|
+
requirements:
|
107
|
+
- - ! '>='
|
108
|
+
- !ruby/object:Gem::Version
|
109
|
+
version: '0'
|
110
|
+
required_rubygems_version: !ruby/object:Gem::Requirement
|
111
|
+
none: false
|
112
|
+
requirements:
|
113
|
+
- - ! '>='
|
114
|
+
- !ruby/object:Gem::Version
|
115
|
+
version: '0'
|
116
|
+
requirements: []
|
117
|
+
rubyforge_project:
|
118
|
+
rubygems_version: 1.8.23
|
119
|
+
signing_key:
|
120
|
+
specification_version: 3
|
121
|
+
summary: Construction for your project.
|
122
|
+
test_files:
|
123
|
+
- spec/dependency_spec.rb
|
124
|
+
- spec/installer_spec.rb
|
125
|
+
- spec/repository/git_spec.rb
|
126
|
+
- spec/repository/svn_spec.rb
|
127
|
+
- spec/spec_helper.rb
|
128
|
+
- spec/support/shared_examples_for_repository.rb
|
129
|
+
- spec/system_spec.rb
|
130
|
+
- spec/version_spec.rb
|