jisota 0.0.1
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +7 -0
- data/.gitignore +19 -0
- data/.rspec +2 -0
- data/Gemfile +4 -0
- data/Guardfile +7 -0
- data/LICENSE.txt +22 -0
- data/README.md +254 -0
- data/Rakefile +1 -0
- data/jisota.gemspec +30 -0
- data/lib/jisota/collection.rb +52 -0
- data/lib/jisota/command_script.rb +17 -0
- data/lib/jisota/composite_script.rb +23 -0
- data/lib/jisota/configuration.rb +60 -0
- data/lib/jisota/errors.rb +3 -0
- data/lib/jisota/file_script.rb +21 -0
- data/lib/jisota/logger.rb +74 -0
- data/lib/jisota/package.rb +35 -0
- data/lib/jisota/package_script.rb +54 -0
- data/lib/jisota/packages/apt.rb +17 -0
- data/lib/jisota/packages/ruby.rb +29 -0
- data/lib/jisota/param.rb +34 -0
- data/lib/jisota/param_parser.rb +70 -0
- data/lib/jisota/provisioner.rb +24 -0
- data/lib/jisota/role.rb +13 -0
- data/lib/jisota/script_block.rb +66 -0
- data/lib/jisota/server.rb +12 -0
- data/lib/jisota/ssh_engine.rb +11 -0
- data/lib/jisota/ssh_session.rb +48 -0
- data/lib/jisota/upload_file.rb +3 -0
- data/lib/jisota/version.rb +3 -0
- data/lib/jisota.rb +63 -0
- data/spec/acceptance/simple_script_spec.rb +56 -0
- data/spec/lib/jisota/collection_spec.rb +44 -0
- data/spec/lib/jisota/command_script_spec.rb +22 -0
- data/spec/lib/jisota/composite_script_spec.rb +37 -0
- data/spec/lib/jisota/configuration_spec.rb +82 -0
- data/spec/lib/jisota/file_script_spec.rb +22 -0
- data/spec/lib/jisota/logger_spec.rb +34 -0
- data/spec/lib/jisota/package_script_spec.rb +43 -0
- data/spec/lib/jisota/package_spec.rb +74 -0
- data/spec/lib/jisota/packages/apt_spec.rb +15 -0
- data/spec/lib/jisota/packages/ruby_spec.rb +14 -0
- data/spec/lib/jisota/role_spec.rb +31 -0
- data/spec/lib/jisota/script_block_spec.rb +51 -0
- data/spec/lib/jisota/server_spec.rb +37 -0
- data/spec/lib/jisota_spec.rb +34 -0
- data/spec/spec_helper.rb +21 -0
- data/spec/test_files/foo +1 -0
- metadata +221 -0
checksums.yaml
ADDED
@@ -0,0 +1,7 @@
|
|
1
|
+
---
|
2
|
+
SHA1:
|
3
|
+
metadata.gz: 868630ce53b3e30dee642175d2e3f9269c40749c
|
4
|
+
data.tar.gz: 692a72ec3e1df5c55e7c679837548584096c3bb0
|
5
|
+
SHA512:
|
6
|
+
metadata.gz: e48e212a2175b404f1cfd1d2b122841051902f3f868509b1321096a9e1315440da686113cf8f7b209b872028ed068d50af947dbf3d8e2c97746f80987dea3b73
|
7
|
+
data.tar.gz: 71963bcbed7a13a30aadd4bc17a2bace65ea8ff694924999213c0a63cdf9e2b72b727d41d515dd69e535212e1fe042d0be28f6a5e26d022a8e3d6fba2398657c
|
data/.gitignore
ADDED
data/.rspec
ADDED
data/Gemfile
ADDED
data/Guardfile
ADDED
data/LICENSE.txt
ADDED
@@ -0,0 +1,22 @@
|
|
1
|
+
Copyright (c) 2014 Lasse Skindstad Ebert
|
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,254 @@
|
|
1
|
+
# Jisota
|
2
|
+
|
3
|
+
Jisota is a simple provisioning tool meant for smaller projects.
|
4
|
+
|
5
|
+
Provisioning, in this context, is the act of turning an empty server
|
6
|
+
into a working machine tailored to your needs.
|
7
|
+
|
8
|
+
## Installation
|
9
|
+
|
10
|
+
Add this line to your application's Gemfile:
|
11
|
+
|
12
|
+
gem 'jisota', require: false
|
13
|
+
|
14
|
+
And then execute:
|
15
|
+
|
16
|
+
$ bundle
|
17
|
+
|
18
|
+
Or install it yourself as:
|
19
|
+
|
20
|
+
$ gem install jisota
|
21
|
+
|
22
|
+
## Introduction
|
23
|
+
|
24
|
+
A simple example of a Jisota script:
|
25
|
+
|
26
|
+
# config/provision.rb (Or whatever you want to call this file)
|
27
|
+
require 'jisota'
|
28
|
+
|
29
|
+
config = Jisota.config do
|
30
|
+
role :app do
|
31
|
+
ruby version: "2.1.1"
|
32
|
+
nginx config_file: "path/to/nginx.conf"
|
33
|
+
end
|
34
|
+
|
35
|
+
server "mydomain.com", user: "john_doe", roles: :app
|
36
|
+
end
|
37
|
+
|
38
|
+
Jisota.run(config)
|
39
|
+
|
40
|
+
Run the script with the ruby executable:
|
41
|
+
|
42
|
+
$ ruby config/provision.rb
|
43
|
+
|
44
|
+
## Defining a package
|
45
|
+
|
46
|
+
Inside a `Jisota.config` block, use the `package` method to define a package.
|
47
|
+
|
48
|
+
Example:
|
49
|
+
|
50
|
+
Jisota.config do
|
51
|
+
package :essentials do
|
52
|
+
description "Installs important stuff"
|
53
|
+
run do
|
54
|
+
apt :curl, :vim, :git
|
55
|
+
end
|
56
|
+
end
|
57
|
+
end
|
58
|
+
|
59
|
+
In this simple example we define a package with the name `:essentials`. It has
|
60
|
+
a description and runs another package, `:apt`, that it calls with the arguments
|
61
|
+
`:curl, :vim, :git`
|
62
|
+
|
63
|
+
The DSL you can use inside a package include:
|
64
|
+
|
65
|
+
* `description`: Will provide a description for the package.
|
66
|
+
* `param`: Specify one or more named parameters for the package. See more in
|
67
|
+
the params section below.
|
68
|
+
* `run(&block)`: This block will be called when the package is executed.
|
69
|
+
* `verify(&block)`: If this block exits with code 0, the run block will not be executed
|
70
|
+
|
71
|
+
Inside a run-block, packages can be called by their name, somewhat like a Ruby
|
72
|
+
method. See the `apt` example above.
|
73
|
+
|
74
|
+
### Defining packages to be used in more than one project
|
75
|
+
|
76
|
+
Defining packages with `Jisota.config` as above will only add the package to
|
77
|
+
the current configuration. To make packages global they need to be in the
|
78
|
+
global package manager. Simply use the `Jisota.global_config` instead:
|
79
|
+
|
80
|
+
|
81
|
+
Jisota.global_config do
|
82
|
+
package :ruby do
|
83
|
+
description "Installs ruby from source"
|
84
|
+
...
|
85
|
+
end
|
86
|
+
end
|
87
|
+
|
88
|
+
This will make the package accessable from all configurations. If a local
|
89
|
+
package has the same name, the local package is used.
|
90
|
+
|
91
|
+
All build-in packages are defined this way.
|
92
|
+
|
93
|
+
## Defining params for a package
|
94
|
+
|
95
|
+
Params for a package are defined with the `param` DSL method inside a
|
96
|
+
`package`-block. Params are named:
|
97
|
+
|
98
|
+
package :my_package do
|
99
|
+
param :foo
|
100
|
+
param :bar
|
101
|
+
...
|
102
|
+
end
|
103
|
+
|
104
|
+
This package can be called either with named parameters or with sorted parameters.
|
105
|
+
The following calls are all equivalent:
|
106
|
+
|
107
|
+
my_package 42, "Baz"
|
108
|
+
my_package 42, bar: "Baz"
|
109
|
+
my_package foo: 42, bar: "Baz"
|
110
|
+
my_package bar: "Baz", foo: 42
|
111
|
+
|
112
|
+
### Param options
|
113
|
+
|
114
|
+
Params can have the following options:
|
115
|
+
|
116
|
+
* `default`: Sets a default value, if no value is passed to that parameter
|
117
|
+
* `required`: Validates that the parameter will have a value
|
118
|
+
* `splat`: Will assign all the following unnamed arguments to this parameter as an array
|
119
|
+
|
120
|
+
Example:
|
121
|
+
|
122
|
+
package :apt do
|
123
|
+
param :packages, splat: true
|
124
|
+
param :command, default: "sudo apt-get install :package"
|
125
|
+
run do
|
126
|
+
cmd command.gsub(/:package/, packages.join(' '))
|
127
|
+
end
|
128
|
+
end
|
129
|
+
|
130
|
+
# And then call params inside another script block:
|
131
|
+
run do
|
132
|
+
apt :vim, :git
|
133
|
+
apt :vim, :git, command: "sudo apt-get install -y :package"
|
134
|
+
end
|
135
|
+
|
136
|
+
|
137
|
+
## Atomic script operations
|
138
|
+
|
139
|
+
All packages will eventually boil down to these few atomic operations, which
|
140
|
+
can be called inside a script block:
|
141
|
+
|
142
|
+
### cmd
|
143
|
+
|
144
|
+
Will run a script on the server. Example:
|
145
|
+
|
146
|
+
cmd "apt-get install foo"
|
147
|
+
|
148
|
+
### upload
|
149
|
+
|
150
|
+
Uploads the file to the server. Example:
|
151
|
+
|
152
|
+
upload from: "path/to/nginx.conf", to: "/etc/nginx.conf"
|
153
|
+
|
154
|
+
## Complete list of build-in packages
|
155
|
+
|
156
|
+
### ruby
|
157
|
+
|
158
|
+
description "Installs ruby from source"
|
159
|
+
param :version, required: true
|
160
|
+
param :tmp_dir, default: "~/tmp"
|
161
|
+
|
162
|
+
### apt
|
163
|
+
|
164
|
+
description "Installs packages with apt-get"
|
165
|
+
param :packages, required: true, splat: true
|
166
|
+
|
167
|
+
### More packages?
|
168
|
+
|
169
|
+
Jisota is a young gem. Please contribute with any packages that you think
|
170
|
+
others could benifit from.
|
171
|
+
|
172
|
+
## To DSL or not to DSL
|
173
|
+
|
174
|
+
The DSL provided by Jisota is just a layer of abstraction. The entire library
|
175
|
+
can easily be used without the DSL. This could be useful if you need to e.g.
|
176
|
+
dynamically build a configuration.
|
177
|
+
|
178
|
+
Example:
|
179
|
+
|
180
|
+
my_package = Jisota::Package.new(:stuff)
|
181
|
+
my_package.params << Jisota::Param.new(:foo, default: 42)
|
182
|
+
|
183
|
+
config = Jisota::Configuration.new
|
184
|
+
config.packages << my_package
|
185
|
+
|
186
|
+
is equivalent to:
|
187
|
+
|
188
|
+
config = Jisota.config do
|
189
|
+
package :stuff do
|
190
|
+
param :foo, default: 42
|
191
|
+
end
|
192
|
+
end
|
193
|
+
|
194
|
+
## Full example
|
195
|
+
|
196
|
+
An example using most of the features of Jisota:
|
197
|
+
|
198
|
+
require 'jisota'
|
199
|
+
|
200
|
+
config = Jisota.config do
|
201
|
+
package :essentials do
|
202
|
+
description "Install essentials"
|
203
|
+
param :extra_packages, splat: true
|
204
|
+
run do
|
205
|
+
packages = %w[git vim curl]
|
206
|
+
packages += extra_packages
|
207
|
+
cmd "sudo apt-get install #{packages.join(" ")}"
|
208
|
+
end
|
209
|
+
end
|
210
|
+
|
211
|
+
package :postgres do
|
212
|
+
description "Installs postgres"
|
213
|
+
run do
|
214
|
+
cmd "some command sequence to install postgres"
|
215
|
+
end
|
216
|
+
end
|
217
|
+
|
218
|
+
package :nginx do
|
219
|
+
description "Install nginx"
|
220
|
+
param :config_file, required: true
|
221
|
+
run do
|
222
|
+
cmd "sudo apt get install nginx"
|
223
|
+
upload from: config_file, to: /etc/nginx.conf
|
224
|
+
end
|
225
|
+
end
|
226
|
+
|
227
|
+
role :app do
|
228
|
+
essentials "libfoo"
|
229
|
+
ruby version: "2.1.1"
|
230
|
+
nginx
|
231
|
+
end
|
232
|
+
|
233
|
+
role :db do
|
234
|
+
essentials
|
235
|
+
postgres
|
236
|
+
end
|
237
|
+
|
238
|
+
server "myapp.com", user: "deploy", roles: :app
|
239
|
+
server "staging.myapp.com", user: "deploy", roles: :app
|
240
|
+
server "db.myapp.com", user: "deploy", roles: :db
|
241
|
+
server "standby.myapp.com", user: "deploy", roles: [:app, :db]
|
242
|
+
end
|
243
|
+
|
244
|
+
Jisota.run(config)
|
245
|
+
|
246
|
+
## Contributing
|
247
|
+
|
248
|
+
Any pull requests, suggestions, bug reports and feedback are most welcome :)
|
249
|
+
|
250
|
+
1. Fork it ( http://github.com/lasseebert/jisota/fork )
|
251
|
+
2. Create your feature branch (`git checkout -b my-new-feature`)
|
252
|
+
3. Commit your changes (`git commit -am 'Add some feature'`)
|
253
|
+
4. Push to the branch (`git push origin my-new-feature`)
|
254
|
+
5. Create new Pull Request
|
data/Rakefile
ADDED
@@ -0,0 +1 @@
|
|
1
|
+
require "bundler/gem_tasks"
|
data/jisota.gemspec
ADDED
@@ -0,0 +1,30 @@
|
|
1
|
+
# coding: utf-8
|
2
|
+
lib = File.expand_path('../lib', __FILE__)
|
3
|
+
$LOAD_PATH.unshift(lib) unless $LOAD_PATH.include?(lib)
|
4
|
+
require 'jisota/version'
|
5
|
+
|
6
|
+
Gem::Specification.new do |spec|
|
7
|
+
spec.name = "jisota"
|
8
|
+
spec.version = Jisota::VERSION
|
9
|
+
spec.authors = ["Lasse Skindstad Ebert"]
|
10
|
+
spec.email = ["lasseebert@gmail.com"]
|
11
|
+
spec.summary = %q{Easily provision servers}
|
12
|
+
spec.description = %q{Easily provision servers using ruby, existing packages, your own packages and a nice DSL}
|
13
|
+
spec.homepage = "https://github.com/lasseebert/jisota"
|
14
|
+
spec.license = "MIT"
|
15
|
+
|
16
|
+
spec.files = `git ls-files -z`.split("\x0")
|
17
|
+
spec.executables = spec.files.grep(%r{^bin/}) { |f| File.basename(f) }
|
18
|
+
spec.test_files = spec.files.grep(%r{^(test|spec|features)/})
|
19
|
+
spec.require_paths = ["lib"]
|
20
|
+
|
21
|
+
spec.add_dependency "net-ssh", "~> 2.8.0"
|
22
|
+
spec.add_dependency "net-scp", "~> 1.1.2"
|
23
|
+
|
24
|
+
spec.add_development_dependency "bundler", "~> 1.5"
|
25
|
+
spec.add_development_dependency "rake"
|
26
|
+
spec.add_development_dependency "simplecov"
|
27
|
+
spec.add_development_dependency "byebug"
|
28
|
+
spec.add_development_dependency "rspec", "~> 3.0.0.beta2"
|
29
|
+
spec.add_development_dependency "guard-rspec", "~> 4.2.8"
|
30
|
+
end
|
@@ -0,0 +1,52 @@
|
|
1
|
+
module Jisota
|
2
|
+
|
3
|
+
##
|
4
|
+
# Stores items with a `:key` attribute
|
5
|
+
# In Jisota, this is used for collections of `Package`, `Role` and `Server`
|
6
|
+
#
|
7
|
+
# Unlike most ruby enumerables, errors are raised when adding duplicate item
|
8
|
+
# or getting non-existent item.
|
9
|
+
class Collection
|
10
|
+
extend Forwardable
|
11
|
+
include Enumerable
|
12
|
+
|
13
|
+
class KeyNotFoundError < StandardError; end
|
14
|
+
class DuplicateKeyError < StandardError; end
|
15
|
+
|
16
|
+
attr_reader :items
|
17
|
+
|
18
|
+
def_delegators :items, :size, :each, :has_key?
|
19
|
+
|
20
|
+
def initialize(items = {})
|
21
|
+
@items = items
|
22
|
+
end
|
23
|
+
|
24
|
+
def add(item_with_key)
|
25
|
+
key = item_with_key.key
|
26
|
+
raise DuplicateKeyError, "Collection already contains an item with key #{key.inspect}" if items.has_key?(key)
|
27
|
+
items[key] = item_with_key
|
28
|
+
end
|
29
|
+
alias_method :<<, :add
|
30
|
+
|
31
|
+
def [](key)
|
32
|
+
items.fetch(key) { raise KeyNotFoundError, "The key #{key.inspect} was not found in the collection" }
|
33
|
+
end
|
34
|
+
|
35
|
+
def first
|
36
|
+
@items.first[1]
|
37
|
+
end
|
38
|
+
|
39
|
+
def last
|
40
|
+
@items.last[1]
|
41
|
+
end
|
42
|
+
|
43
|
+
def each(&block)
|
44
|
+
@items.values.each(&block)
|
45
|
+
end
|
46
|
+
|
47
|
+
def merge(other, &block)
|
48
|
+
Collection.new(items.merge(other.items, &block))
|
49
|
+
end
|
50
|
+
|
51
|
+
end
|
52
|
+
end
|
@@ -0,0 +1,17 @@
|
|
1
|
+
module Jisota
|
2
|
+
##
|
3
|
+
# Part of the Script duck type
|
4
|
+
#
|
5
|
+
# Stores a single shell command that can be executed
|
6
|
+
class CommandScript
|
7
|
+
attr_accessor :command
|
8
|
+
|
9
|
+
def initialize(command)
|
10
|
+
@command = command
|
11
|
+
end
|
12
|
+
|
13
|
+
def execute(ssh_session, logger = nil)
|
14
|
+
ssh_session.command(command, logger)
|
15
|
+
end
|
16
|
+
end
|
17
|
+
end
|
@@ -0,0 +1,23 @@
|
|
1
|
+
module Jisota
|
2
|
+
##
|
3
|
+
# Part of the Script duck type
|
4
|
+
#
|
5
|
+
# Contains a list of Scripts and can execute them consectutive.
|
6
|
+
# If one script fails, the following will not be executed and the combined
|
7
|
+
# result of this script will also be failed (`false`)
|
8
|
+
class CompositeScript
|
9
|
+
attr_accessor :scripts
|
10
|
+
|
11
|
+
def initialize
|
12
|
+
@scripts = []
|
13
|
+
end
|
14
|
+
|
15
|
+
def execute(ssh_session, logger = nil)
|
16
|
+
scripts.each do |inner|
|
17
|
+
result = inner.execute(ssh_session, logger)
|
18
|
+
return false unless result
|
19
|
+
end
|
20
|
+
true
|
21
|
+
end
|
22
|
+
end
|
23
|
+
end
|
@@ -0,0 +1,60 @@
|
|
1
|
+
module Jisota
|
2
|
+
##
|
3
|
+
# Stores all information required to run a provision against one or multiple
|
4
|
+
# servers (Except for the global package manager, which is stored in the Jisota module).
|
5
|
+
#
|
6
|
+
# Uses DSL methods in the initializer for convenient definition of packages, roles and servers
|
7
|
+
class Configuration
|
8
|
+
attr_accessor :packages, :roles, :servers, :ssh_engine
|
9
|
+
|
10
|
+
def initialize(options = {}, &block)
|
11
|
+
@packages = options.fetch(:packages) { Collection.new }
|
12
|
+
@roles = options.fetch(:role) { Collection.new }
|
13
|
+
@servers = options.fetch(:servers) { [] }
|
14
|
+
@ssh_engine = options.fetch(:ssh_engine) { SSHEngine }
|
15
|
+
DSL.new(self).instance_eval(&block) if block_given?
|
16
|
+
end
|
17
|
+
|
18
|
+
def add_package(package)
|
19
|
+
packages.add(package)
|
20
|
+
end
|
21
|
+
|
22
|
+
def get_package(name)
|
23
|
+
packages[name]
|
24
|
+
end
|
25
|
+
|
26
|
+
def add_role(role)
|
27
|
+
roles.add(role)
|
28
|
+
end
|
29
|
+
|
30
|
+
def get_role(name)
|
31
|
+
roles[name]
|
32
|
+
end
|
33
|
+
|
34
|
+
def add_server(server)
|
35
|
+
servers << server
|
36
|
+
end
|
37
|
+
|
38
|
+
def each_server(&block)
|
39
|
+
servers.each(&block)
|
40
|
+
end
|
41
|
+
|
42
|
+
class DSL
|
43
|
+
def initialize(target)
|
44
|
+
@target = target
|
45
|
+
end
|
46
|
+
|
47
|
+
def package(name, &block)
|
48
|
+
@target.packages << Package.new(name, &block)
|
49
|
+
end
|
50
|
+
|
51
|
+
def role(name, &block)
|
52
|
+
@target.roles << Role.new(name, &block)
|
53
|
+
end
|
54
|
+
|
55
|
+
def server(host, options = {})
|
56
|
+
@target.servers << Server.new(host, options)
|
57
|
+
end
|
58
|
+
end
|
59
|
+
end
|
60
|
+
end
|
@@ -0,0 +1,21 @@
|
|
1
|
+
module Jisota
|
2
|
+
##
|
3
|
+
# Part of the Script duck type
|
4
|
+
#
|
5
|
+
# Uploads a file on execution
|
6
|
+
class FileScript
|
7
|
+
attr_accessor :file
|
8
|
+
|
9
|
+
def initialize(file)
|
10
|
+
@file = file
|
11
|
+
end
|
12
|
+
|
13
|
+
def execute(ssh_session, logger = nil)
|
14
|
+
logger.prefixed_message("File #{file.from} -> #{file.to}") if logger
|
15
|
+
logger.indent if logger
|
16
|
+
result = ssh_session.upload(file, logger)
|
17
|
+
logger.outdent if logger
|
18
|
+
result
|
19
|
+
end
|
20
|
+
end
|
21
|
+
end
|
@@ -0,0 +1,74 @@
|
|
1
|
+
module Jisota
|
2
|
+
##
|
3
|
+
# Responsible for outputting to the user / log file / whatever
|
4
|
+
#
|
5
|
+
# Will default to use STDOUT and STDERR, but that can be overwritten in the
|
6
|
+
# initializer
|
7
|
+
class Logger
|
8
|
+
attr_accessor :stdout, :stderr, :verbose, :prefix, :indent_level
|
9
|
+
|
10
|
+
def initialize(options = {})
|
11
|
+
@stdout = options.fetch(:stdout) { $stdout }
|
12
|
+
@stderr = options.fetch(:stderr) { $stderr }
|
13
|
+
@verbose = options.fetch(:verbose) { false }
|
14
|
+
@prefix = options.fetch(:prefix) { "-----> " }
|
15
|
+
@indent_level = 0
|
16
|
+
end
|
17
|
+
|
18
|
+
def command(command)
|
19
|
+
prefixed_message "Executing #{command}"
|
20
|
+
end
|
21
|
+
|
22
|
+
def upload(from: , to: )
|
23
|
+
prefixed_message "Uploading #{from} -> #{to}"
|
24
|
+
end
|
25
|
+
|
26
|
+
def package(package_script)
|
27
|
+
prefixed_message "Package #{package_script}"
|
28
|
+
end
|
29
|
+
|
30
|
+
def package_cancelled_by_verify(package_script)
|
31
|
+
prefixed_message "Package #{package_script} already installed"
|
32
|
+
end
|
33
|
+
|
34
|
+
def prefixed_message(message)
|
35
|
+
stdout.write(create_message(message, true, true))
|
36
|
+
end
|
37
|
+
|
38
|
+
def info(message)
|
39
|
+
stdout.write(message) if verbose
|
40
|
+
end
|
41
|
+
|
42
|
+
def warn(message)
|
43
|
+
stderr.write(message) if verbose
|
44
|
+
end
|
45
|
+
|
46
|
+
def error(message)
|
47
|
+
stderr.write(message)
|
48
|
+
end
|
49
|
+
|
50
|
+
def indent
|
51
|
+
self.indent_level += 1
|
52
|
+
end
|
53
|
+
|
54
|
+
def outdent
|
55
|
+
self.indent_level -= 1
|
56
|
+
end
|
57
|
+
|
58
|
+
private
|
59
|
+
|
60
|
+
def create_message(message, newline, use_prefix)
|
61
|
+
result = ""
|
62
|
+
if use_prefix
|
63
|
+
result << prefix
|
64
|
+
else
|
65
|
+
result << " " * prefix.size
|
66
|
+
end
|
67
|
+
result << " " * indent_level
|
68
|
+
result << message
|
69
|
+
result << "\n" if newline
|
70
|
+
result
|
71
|
+
end
|
72
|
+
|
73
|
+
end
|
74
|
+
end
|
@@ -0,0 +1,35 @@
|
|
1
|
+
module Jisota
|
2
|
+
class Package
|
3
|
+
attr_accessor :name, :description, :params, :run_block, :verify_block
|
4
|
+
|
5
|
+
def initialize(name = nil, &block)
|
6
|
+
@params = []
|
7
|
+
@name = name
|
8
|
+
DSL.new(self).instance_eval(&block) if block_given?
|
9
|
+
end
|
10
|
+
|
11
|
+
alias_method :key, :name
|
12
|
+
|
13
|
+
class DSL
|
14
|
+
def initialize(target)
|
15
|
+
@target = target
|
16
|
+
end
|
17
|
+
|
18
|
+
def description(value)
|
19
|
+
@target.description = value
|
20
|
+
end
|
21
|
+
|
22
|
+
def param(name, options = {})
|
23
|
+
@target.params << Param.new(name, options)
|
24
|
+
end
|
25
|
+
|
26
|
+
def run(&block)
|
27
|
+
@target.run_block = ScriptBlock.new(&block)
|
28
|
+
end
|
29
|
+
|
30
|
+
def verify(&block)
|
31
|
+
@target.verify_block = ScriptBlock.new(&block)
|
32
|
+
end
|
33
|
+
end
|
34
|
+
end
|
35
|
+
end
|