rhc 0.92.11 → 0.93.18
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.
- data/README.md +1 -9
- data/Rakefile +1 -55
- data/bin/rhc +31 -1
- data/bin/rhc-app +62 -127
- data/bin/rhc-chk +6 -7
- data/bin/rhc-create-app +8 -8
- data/bin/rhc-create-domain +6 -86
- data/bin/rhc-ctl-app +3 -3
- data/bin/rhc-ctl-domain +4 -4
- data/bin/rhc-domain +16 -18
- data/bin/rhc-domain-info +3 -3
- data/bin/rhc-port-forward +127 -24
- data/bin/rhc-snapshot +7 -46
- data/bin/rhc-sshkey +13 -79
- data/bin/rhc-tail-files +16 -8
- data/lib/rhc-common.rb +406 -230
- data/lib/rhc-rest.rb +3 -3
- data/lib/rhc-rest/client.rb +1 -1
- data/lib/rhc-rest/domain.rb +1 -1
- data/lib/rhc.rb +20 -0
- data/lib/rhc/cli.rb +38 -0
- data/lib/rhc/client.rb +15 -0
- data/lib/rhc/commands.rb +32 -0
- data/lib/rhc/commands/base.rb +67 -0
- data/lib/rhc/commands/server.rb +24 -0
- data/lib/rhc/config.rb +141 -0
- data/lib/rhc/core_ext.rb +15 -0
- data/lib/rhc/helpers.rb +142 -0
- data/lib/rhc/json.rb +52 -0
- data/lib/rhc/targz.rb +46 -0
- data/lib/rhc/vendor/okjson.rb +600 -0
- data/lib/rhc/vendor/zliby.rb +628 -0
- data/lib/rhc/wizard.rb +579 -0
- data/spec/rhc/assets/foo.txt +1 -0
- data/spec/rhc/assets/targz_corrupted.tar.gz +1 -0
- data/spec/rhc/assets/targz_sample.tar.gz +0 -0
- data/spec/rhc/cli_spec.rb +24 -0
- data/spec/rhc/command_spec.rb +88 -0
- data/spec/rhc/commands/server_spec.rb +39 -0
- data/spec/rhc/helpers_spec.rb +171 -0
- data/spec/rhc/json_spec.rb +30 -0
- data/spec/rhc/targz_spec.rb +42 -0
- data/spec/rhc/wizard_spec.rb +426 -0
- data/spec/spec_helper.rb +192 -0
- data/test/functional/application_test.rb +71 -0
- data/test/functional/domain_test.rb +123 -0
- data/test/functional/test_credentials.rb +5 -0
- data/test/sample-usage.rb +122 -0
- data/test/support/server.rb +14 -0
- data/test/support/testcase.rb +3 -0
- data/test/test_helper.rb +4 -0
- data/test/unit/command_test.rb +19 -0
- metadata +181 -29
- data/ext/mkrf_conf.rb +0 -58
- data/lib/rhc +0 -115
data/lib/rhc-rest.rb
CHANGED
@@ -1,7 +1,6 @@
|
|
1
1
|
require 'rubygems'
|
2
2
|
require 'rest-client'
|
3
3
|
require 'logger'
|
4
|
-
require 'json'
|
5
4
|
require 'rhc-rest/exceptions/exceptions'
|
6
5
|
require 'rhc-rest/application'
|
7
6
|
require 'rhc-rest/cartridge'
|
@@ -9,6 +8,7 @@ require 'rhc-rest/client'
|
|
9
8
|
require 'rhc-rest/domain'
|
10
9
|
require 'rhc-rest/key'
|
11
10
|
require 'rhc-rest/user'
|
11
|
+
require 'rhc/helpers'
|
12
12
|
|
13
13
|
@@end_point = ""
|
14
14
|
@@headers = {:accept => :json}
|
@@ -24,7 +24,7 @@ module Rhc
|
|
24
24
|
end
|
25
25
|
|
26
26
|
def parse_response(response)
|
27
|
-
result =
|
27
|
+
result = RHC::Json.decode(response)
|
28
28
|
type = result['type']
|
29
29
|
data = result['data']
|
30
30
|
case type
|
@@ -92,7 +92,7 @@ module Rhc
|
|
92
92
|
def process_error_response(response)
|
93
93
|
messages = Array.new
|
94
94
|
begin
|
95
|
-
result =
|
95
|
+
result = RHC::Json.decode(response)
|
96
96
|
messages = result['messages']
|
97
97
|
rescue Exception => e
|
98
98
|
logger.debug "Response did not include a message from server" if @mydebug
|
data/lib/rhc-rest/client.rb
CHANGED
@@ -13,7 +13,7 @@ module Rhc
|
|
13
13
|
request = RestClient::Request.new(:url => end_point, :method => :get, :headers => @@headers)
|
14
14
|
begin
|
15
15
|
response = request.execute
|
16
|
-
result =
|
16
|
+
result = RHC::Json.decode(response)
|
17
17
|
@links = send(request)
|
18
18
|
rescue RestClient::ExceptionWithResponse => e
|
19
19
|
logger.error "Failed to get API #{e.response}"
|
data/lib/rhc-rest/domain.rb
CHANGED
@@ -24,7 +24,7 @@ module Rhc
|
|
24
24
|
end
|
25
25
|
timeout = nil
|
26
26
|
if options[:scale]
|
27
|
-
timeout =
|
27
|
+
timeout = 300 # 5 minute timeout for scalable app
|
28
28
|
end
|
29
29
|
request = RestClient::Request.new(:url => url, :method => method, :headers => @@headers, :payload => payload, :timeout => timeout)
|
30
30
|
return send(request)
|
data/lib/rhc.rb
ADDED
@@ -0,0 +1,20 @@
|
|
1
|
+
# require 'rhc/version' #FIXME gem should know version
|
2
|
+
# FIXME Remove rubygems from requirements, ensure library is correct
|
3
|
+
|
4
|
+
# Only require external gem dependencies here
|
5
|
+
require 'rest_client'
|
6
|
+
require 'logger'
|
7
|
+
|
8
|
+
# Extend core methods
|
9
|
+
require 'rhc/core_ext'
|
10
|
+
|
11
|
+
module RHC
|
12
|
+
module Commands; end
|
13
|
+
|
14
|
+
autoload :Helpers, 'rhc/helpers'
|
15
|
+
end
|
16
|
+
|
17
|
+
# Replace me with proper autoloads on the module RHC
|
18
|
+
require 'rhc-common'
|
19
|
+
require 'rhc-rest'
|
20
|
+
|
data/lib/rhc/cli.rb
ADDED
@@ -0,0 +1,38 @@
|
|
1
|
+
require 'rhc'
|
2
|
+
require 'commander'
|
3
|
+
require 'commander/runner'
|
4
|
+
require 'commander/delegates'
|
5
|
+
require 'rhc/commands'
|
6
|
+
|
7
|
+
include Commander::UI
|
8
|
+
include Commander::UI::AskForClass
|
9
|
+
|
10
|
+
module RHC
|
11
|
+
#
|
12
|
+
# Run and execute a command line session with the RHC tools.
|
13
|
+
#
|
14
|
+
# You can invoke the CLI with:
|
15
|
+
# bundle exec ruby -e 'require "rhc/cli"; RHC::CLI.start(ARGV);' -- <arguments>
|
16
|
+
#
|
17
|
+
# from the gem directory.
|
18
|
+
#
|
19
|
+
module CLI
|
20
|
+
|
21
|
+
extend Commander::Delegates
|
22
|
+
|
23
|
+
def self.set_terminal
|
24
|
+
$terminal.wrap_at = HighLine::SystemExtensions.terminal_size.first - 5 rescue 80 if $stdin.tty?
|
25
|
+
end
|
26
|
+
|
27
|
+
def self.start(args)
|
28
|
+
Commander::Runner.instance_variable_set :@singleton, Commander::Runner.new(args)
|
29
|
+
|
30
|
+
program :name, 'rhc'
|
31
|
+
program :version, '0.0.0' #FIXME pull from versions.rb
|
32
|
+
program :description, 'Command line interface for OpenShift.'
|
33
|
+
|
34
|
+
RHC::Commands.load.to_commander
|
35
|
+
exit(run! || 0)
|
36
|
+
end
|
37
|
+
end
|
38
|
+
end
|
data/lib/rhc/client.rb
ADDED
@@ -0,0 +1,15 @@
|
|
1
|
+
class RHC::Client
|
2
|
+
def initialize() #auth info
|
3
|
+
end
|
4
|
+
|
5
|
+
include RHC::Helpers
|
6
|
+
|
7
|
+
def get(uri, headers={})
|
8
|
+
# absolute uris are called directly, relative uris are called with
|
9
|
+
# the rest api root, and server relative uris are called against the
|
10
|
+
# host. Allow simple templatization via t()
|
11
|
+
end
|
12
|
+
def t(uri, opts)
|
13
|
+
# templatize uri using AddressableTemplate and opts
|
14
|
+
end
|
15
|
+
end
|
data/lib/rhc/commands.rb
ADDED
@@ -0,0 +1,32 @@
|
|
1
|
+
require 'rhc/config'
|
2
|
+
|
3
|
+
module RHC
|
4
|
+
module Commands
|
5
|
+
def self.load
|
6
|
+
Dir[File.join(File.dirname(__FILE__), "commands", "*.rb")].each do |file|
|
7
|
+
require file
|
8
|
+
end
|
9
|
+
self
|
10
|
+
end
|
11
|
+
def self.add(opts)
|
12
|
+
commands[opts[:name]] = opts
|
13
|
+
end
|
14
|
+
def self.to_commander(instance=Commander::Runner.instance)
|
15
|
+
commands.each_pair do |name, opts|
|
16
|
+
instance.command name do |c|
|
17
|
+
c.option '--config PATH', String, 'Path of alternate config'
|
18
|
+
c.when_called do |args, options|
|
19
|
+
RHC::Config.set_opts_config(options.config) if options.config
|
20
|
+
opts[:class].new(args, options).send(opts[:method])
|
21
|
+
end
|
22
|
+
end
|
23
|
+
end
|
24
|
+
self
|
25
|
+
end
|
26
|
+
|
27
|
+
protected
|
28
|
+
def self.commands
|
29
|
+
@commands ||= {}
|
30
|
+
end
|
31
|
+
end
|
32
|
+
end
|
@@ -0,0 +1,67 @@
|
|
1
|
+
require 'commander'
|
2
|
+
require 'commander/delegates'
|
3
|
+
require 'rhc/helpers'
|
4
|
+
|
5
|
+
class RHC::Commands::Base
|
6
|
+
|
7
|
+
attr_reader :args, :options
|
8
|
+
|
9
|
+
def initialize(args=[], options={})
|
10
|
+
@args, @options = args, options
|
11
|
+
end
|
12
|
+
|
13
|
+
protected
|
14
|
+
include RHC::Helpers
|
15
|
+
|
16
|
+
def application
|
17
|
+
#@application ||= ... identify current application or throw,
|
18
|
+
# indicating one is needed. Should check
|
19
|
+
# options (commands which have it as an ARG
|
20
|
+
# should set it onto options), then check
|
21
|
+
# current git repo for remote, fail.
|
22
|
+
end
|
23
|
+
|
24
|
+
def client
|
25
|
+
#@client ||= ... Return a client object capable of making calls
|
26
|
+
# to the OpenShift API that transforms intent
|
27
|
+
# and options, to remote calls, and then handle
|
28
|
+
# the output (or failures) into exceptions and
|
29
|
+
# formatted object output. Most interactions
|
30
|
+
# should be through this call pattern.
|
31
|
+
#
|
32
|
+
# Initialize with auth (a separate responsibility
|
33
|
+
# object).
|
34
|
+
end
|
35
|
+
|
36
|
+
class InvalidCommand < StandardError ; end
|
37
|
+
|
38
|
+
def self.inherited(klass)
|
39
|
+
unless klass == RHC::Commands::Base
|
40
|
+
end
|
41
|
+
end
|
42
|
+
|
43
|
+
def self.method_added(method)
|
44
|
+
return if self == RHC::Commands::Base
|
45
|
+
return if private_method_defined? method
|
46
|
+
return if protected_method_defined? method
|
47
|
+
|
48
|
+
method_name = method.to_s == 'run' ? nil : method.to_s
|
49
|
+
name = [method_name]
|
50
|
+
name.unshift(self.object_name).compact!
|
51
|
+
raise InvalidCommand, "Either object_name must be set or a non default method defined" if name.empty?
|
52
|
+
RHC::Commands.add({
|
53
|
+
:name => name.join(' '),
|
54
|
+
:class => self,
|
55
|
+
:method => method,
|
56
|
+
});
|
57
|
+
end
|
58
|
+
|
59
|
+
def self.object_name(value=nil)
|
60
|
+
@object_name ||= begin
|
61
|
+
value ||= if self.name && !self.name.empty?
|
62
|
+
self.name.split('::').last
|
63
|
+
end
|
64
|
+
value.to_s.downcase if value
|
65
|
+
end
|
66
|
+
end
|
67
|
+
end
|
@@ -0,0 +1,24 @@
|
|
1
|
+
require 'rhc/commands/base'
|
2
|
+
|
3
|
+
module RHC::Commands
|
4
|
+
class Server < Base
|
5
|
+
def run
|
6
|
+
status = decode_json(RestClient.get("https://#{openshift_server}/app/status/status.json").body)
|
7
|
+
open = status['open']
|
8
|
+
|
9
|
+
(success 'All systems running fine' and return 0) if open.blank?
|
10
|
+
|
11
|
+
open.each do |i|
|
12
|
+
i = i['issue']
|
13
|
+
say color("%-3s %s" % ["##{i['id']}", i['title']], :bold)
|
14
|
+
items = i['updates'].map{ |u| [u['description'], date(u['created_at'])] }
|
15
|
+
items.unshift ['Opened', date(i['created_at'])]
|
16
|
+
table(items, :align => [nil,:right], :join => ' ').each{ |s| say " #{s}" }
|
17
|
+
end
|
18
|
+
say "\n"
|
19
|
+
warn pluralize(open.length, "open issue")
|
20
|
+
|
21
|
+
open.length #exit with the count of open items
|
22
|
+
end
|
23
|
+
end
|
24
|
+
end
|
data/lib/rhc/config.rb
ADDED
@@ -0,0 +1,141 @@
|
|
1
|
+
require 'parseconfig'
|
2
|
+
|
3
|
+
module RHC
|
4
|
+
module Config
|
5
|
+
def self.initialize
|
6
|
+
@@defaults = ParseConfig.new()
|
7
|
+
@@global_config = nil
|
8
|
+
@@local_config = nil
|
9
|
+
@@opts_config = nil
|
10
|
+
@@default_proxy = nil
|
11
|
+
@@env_config = ParseConfig.new()
|
12
|
+
|
13
|
+
@@defaults.add('libra_server', 'openshift.redhat.com')
|
14
|
+
@@env_config.add('libra_server', ENV['LIBRA_SERVER']) if ENV['LIBRA_SERVER']
|
15
|
+
|
16
|
+
#
|
17
|
+
# Config paths... /etc/openshift/express.conf or $GEM/conf/express.conf -> ~/.openshift/express.conf
|
18
|
+
#
|
19
|
+
|
20
|
+
@@conf_name = 'express.conf'
|
21
|
+
_linux_cfg = '/etc/openshift/' + @@conf_name
|
22
|
+
_gem_cfg = File.join(File.expand_path(File.dirname(__FILE__) + "/../../conf"), @@conf_name)
|
23
|
+
|
24
|
+
config_path = File.exists?(_linux_cfg) ? _linux_cfg : _gem_cfg
|
25
|
+
@@home_dir = File.expand_path("~")
|
26
|
+
@@home_conf_path = File.join(@@home_dir, '.openshift')
|
27
|
+
@@local_config_path = File.join(@@home_conf_path, @@conf_name)
|
28
|
+
|
29
|
+
begin
|
30
|
+
@@global_config = ParseConfig.new(config_path)
|
31
|
+
@@local_config = ParseConfig.new(File.expand_path(@@local_config_path)) if File.exists?(@@local_config_path)
|
32
|
+
rescue Errno::EACCES => e
|
33
|
+
puts "Could not open config file: #{e.message}"
|
34
|
+
exit 253
|
35
|
+
end
|
36
|
+
end
|
37
|
+
|
38
|
+
self.initialize
|
39
|
+
|
40
|
+
# used for tests
|
41
|
+
def self.home_dir=(home_dir)
|
42
|
+
@@home_dir=home_dir
|
43
|
+
@@home_conf_path = File.join(@@home_dir, '.openshift')
|
44
|
+
@@local_config_path = File.join(@@home_conf_path, @@conf_name)
|
45
|
+
end
|
46
|
+
|
47
|
+
def self.get_value(key)
|
48
|
+
# evaluate in cascading order
|
49
|
+
configs = [@@opts_config, @@env_config, @@local_config, @@global_config, @@defaults]
|
50
|
+
result = nil
|
51
|
+
configs.each do |conf|
|
52
|
+
result = conf.get_value(key) if !conf.nil?
|
53
|
+
break if !result.nil?
|
54
|
+
end
|
55
|
+
|
56
|
+
result
|
57
|
+
end
|
58
|
+
|
59
|
+
# Public: configures the default user for this session
|
60
|
+
def self.config_user(username)
|
61
|
+
@@defaults.add('default_rhlogin', username)
|
62
|
+
end
|
63
|
+
|
64
|
+
def self.set_local_config(confpath)
|
65
|
+
begin
|
66
|
+
@@local_config = ParseConfig.new(File.expand_path(confpath))
|
67
|
+
rescue Errno::EACCES => e
|
68
|
+
puts "Could not open config file: #{e.message}"
|
69
|
+
exit 253
|
70
|
+
end
|
71
|
+
end
|
72
|
+
|
73
|
+
def self.set_opts_config(confpath)
|
74
|
+
begin
|
75
|
+
@@opts_config = ParseConfig.new(File.expand_path(confpath))
|
76
|
+
rescue Errno::EACCES => e
|
77
|
+
puts "Could not open config file: #{e.message}"
|
78
|
+
exit 253
|
79
|
+
end
|
80
|
+
end
|
81
|
+
|
82
|
+
def self.check_cpath(opts)
|
83
|
+
unless opts["config"].nil?
|
84
|
+
opts_config_path = File.expand_path(opts["config"])
|
85
|
+
if !File.readable?(opts_config_path)
|
86
|
+
puts "Could not open config file: #{@opts_config_path}"
|
87
|
+
exit 253
|
88
|
+
else
|
89
|
+
set_opts_config(opts_config_path)
|
90
|
+
end
|
91
|
+
end
|
92
|
+
end
|
93
|
+
|
94
|
+
def self.has_global_config?
|
95
|
+
!@@global_config.nil?
|
96
|
+
end
|
97
|
+
|
98
|
+
def self.has_local_config?
|
99
|
+
!@@local_config.nil?
|
100
|
+
end
|
101
|
+
|
102
|
+
def self.has_opts_config?
|
103
|
+
!@@opts_config.nil?
|
104
|
+
end
|
105
|
+
|
106
|
+
# Public: convinience function to see if we should run the wizard
|
107
|
+
def self.should_run_wizard?
|
108
|
+
not (has_local_config? or has_opts_config?)
|
109
|
+
end
|
110
|
+
|
111
|
+
def self.local_config_path
|
112
|
+
@@local_config_path
|
113
|
+
end
|
114
|
+
|
115
|
+
def self.home_conf_path
|
116
|
+
@@home_conf_path
|
117
|
+
end
|
118
|
+
|
119
|
+
def self.home_dir
|
120
|
+
@@home_dir
|
121
|
+
end
|
122
|
+
|
123
|
+
def self.default_proxy
|
124
|
+
#
|
125
|
+
# Check for proxy environment
|
126
|
+
#
|
127
|
+
if @@default_proxy.nil?
|
128
|
+
if ENV['http_proxy']
|
129
|
+
if ENV['http_proxy']!~/^(\w+):\/\// then
|
130
|
+
ENV['http_proxy']="http://" + ENV['http_proxy']
|
131
|
+
end
|
132
|
+
proxy_uri=URI.parse(ENV['http_proxy'])
|
133
|
+
@@default_proxy = Net::HTTP::Proxy(proxy_uri.host, proxy_uri.port, proxy_uri.user, proxy_uri.password)
|
134
|
+
else
|
135
|
+
@@default_proxy = Net::HTTP
|
136
|
+
end
|
137
|
+
end
|
138
|
+
@@default_proxy
|
139
|
+
end
|
140
|
+
end
|
141
|
+
end
|
data/lib/rhc/core_ext.rb
ADDED
data/lib/rhc/helpers.rb
ADDED
@@ -0,0 +1,142 @@
|
|
1
|
+
require 'commander/user_interaction'
|
2
|
+
require 'rhc/config'
|
3
|
+
|
4
|
+
module RHC
|
5
|
+
module Helpers
|
6
|
+
|
7
|
+
# helpers always have Commander UI available
|
8
|
+
include Commander::UI
|
9
|
+
include Commander::UI::AskForClass
|
10
|
+
|
11
|
+
extend self
|
12
|
+
|
13
|
+
def decode_json(s)
|
14
|
+
RHC::Vendor::OkJson.decode(s)
|
15
|
+
end
|
16
|
+
|
17
|
+
def date(s)
|
18
|
+
now = Time.now
|
19
|
+
d = datetime_rfc3339(s)
|
20
|
+
if now.year == d.year
|
21
|
+
return d.strftime('%l:%M %p').strip if now.yday == d.yday
|
22
|
+
end
|
23
|
+
d.strftime('%b %d %l:%M %p')
|
24
|
+
end
|
25
|
+
|
26
|
+
def datetime_rfc3339(s)
|
27
|
+
DateTime.strptime(s, '%Y-%m-%dT%H:%M:%S%z')
|
28
|
+
# Replace with d = DateTime.rfc3339(s)
|
29
|
+
end
|
30
|
+
|
31
|
+
def openshift_server
|
32
|
+
RHC::Config.get_value('libra_server')
|
33
|
+
end
|
34
|
+
|
35
|
+
def success(*args)
|
36
|
+
args.each{ |a| say color(a, :green) }
|
37
|
+
end
|
38
|
+
def warn(*args)
|
39
|
+
args.each{ |a| say color(a, :yellow) }
|
40
|
+
end
|
41
|
+
|
42
|
+
def color(s, color)
|
43
|
+
$terminal.color(s, color)
|
44
|
+
end
|
45
|
+
|
46
|
+
def pluralize(count, s)
|
47
|
+
count == 1 ? "#{count} #{s}" : "#{count} #{s}s"
|
48
|
+
end
|
49
|
+
|
50
|
+
def table(items, opts={}, &block)
|
51
|
+
items = items.map &block if block_given?
|
52
|
+
columns = []
|
53
|
+
max = items.each do |item|
|
54
|
+
item.each_with_index do |s, i|
|
55
|
+
item[i] = s.to_s
|
56
|
+
columns[i] = [columns[i] || 0, s.length].max if s.respond_to?(:length)
|
57
|
+
end
|
58
|
+
end
|
59
|
+
align = opts[:align] || []
|
60
|
+
join = opts[:join] || ' '
|
61
|
+
items.map do |item|
|
62
|
+
item.each_with_index.map{ |s,i| s.send((align[i] == :right ? :rjust : :ljust), columns[i], ' ') }.join(join).strip
|
63
|
+
end
|
64
|
+
end
|
65
|
+
|
66
|
+
##
|
67
|
+
# section
|
68
|
+
#
|
69
|
+
# highline helper mixin which correctly formats block of say and ask
|
70
|
+
# output to have correct margins. section remembers the last margin
|
71
|
+
# used and calculates the relitive margin from the previous section.
|
72
|
+
# For example:
|
73
|
+
#
|
74
|
+
# section(bottom=1) do
|
75
|
+
# say "Hello"
|
76
|
+
# end
|
77
|
+
#
|
78
|
+
# section(top=1) do
|
79
|
+
# say "World"
|
80
|
+
# end
|
81
|
+
#
|
82
|
+
# Will output:
|
83
|
+
#
|
84
|
+
# > Hello
|
85
|
+
# >
|
86
|
+
# > World
|
87
|
+
#
|
88
|
+
# with only one newline between the two. Biggest margin wins.
|
89
|
+
#
|
90
|
+
# params:
|
91
|
+
# top - top margin specified in lines
|
92
|
+
# bottom - bottom margin specified in line
|
93
|
+
#
|
94
|
+
@@section_bottom_last = 0
|
95
|
+
def section(params={}, &block)
|
96
|
+
top = params[:top]
|
97
|
+
top = 0 if top.nil?
|
98
|
+
bottom = params[:bottom]
|
99
|
+
bottom = 0 if bottom.nil?
|
100
|
+
|
101
|
+
# add more newlines if top is greater than the last section's bottom margin
|
102
|
+
top_margin = @@section_bottom_last
|
103
|
+
|
104
|
+
# negitive previous bottoms indicate that an untracked newline was
|
105
|
+
# printed and so we do our best to negate it since we can't remove it
|
106
|
+
if top_margin < 0
|
107
|
+
top += top_margin
|
108
|
+
top_margin = 0
|
109
|
+
end
|
110
|
+
|
111
|
+
until top_margin >= top
|
112
|
+
say "\n"
|
113
|
+
top_margin += 1
|
114
|
+
end
|
115
|
+
|
116
|
+
block.call
|
117
|
+
|
118
|
+
bottom_margin = 0
|
119
|
+
until bottom_margin >= bottom
|
120
|
+
say "\n"
|
121
|
+
bottom_margin += 1
|
122
|
+
end
|
123
|
+
|
124
|
+
@@section_bottom_last = bottom
|
125
|
+
end
|
126
|
+
|
127
|
+
##
|
128
|
+
# paragraph
|
129
|
+
#
|
130
|
+
# highline helper which creates a section with margins of 1, 1
|
131
|
+
#
|
132
|
+
def paragraph(&block)
|
133
|
+
section(:top => 1, :bottom => 1, &block)
|
134
|
+
end
|
135
|
+
|
136
|
+
# Platform helpers
|
137
|
+
def jruby? ; RUBY_PLATFORM =~ /java/i end
|
138
|
+
def windows? ; RUBY_PLATFORM =~ /win(32|dows|ce)|djgpp|(ms|cyg|bcc)win|mingw32/i end
|
139
|
+
def unix? ; !jruby? && !windows? end
|
140
|
+
|
141
|
+
end
|
142
|
+
end
|