jisota 0.0.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- 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
|