server_remote 0.2.0
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/LICENSE +20 -0
- data/README.textile +37 -0
- data/VERSION.yml +4 -0
- data/bin/server_remotify +9 -0
- data/config/defaults.yml +4 -0
- data/config/server_remote.yml.sample +39 -0
- data/lib/hash_ext.rb +8 -0
- data/lib/server_remote/install_tools.rb +28 -0
- data/lib/server_remote/server_remote.rb +230 -0
- data/lib/server_remote.rb +7 -0
- data/script/remote +7 -0
- data/test/config/config_no_override.yml +2 -0
- data/test/config/config_override.yml +3 -0
- data/test/config/defaults.yml +3 -0
- data/test/server_remote_test.rb +43 -0
- data/test/server_remote_util_test.rb +75 -0
- data/test/test_helper.rb +13 -0
- metadata +83 -0
data/LICENSE
ADDED
@@ -0,0 +1,20 @@
|
|
1
|
+
Copyright (c) 2009 Tobias Crawley
|
2
|
+
|
3
|
+
Permission is hereby granted, free of charge, to any person obtaining
|
4
|
+
a copy of this software and associated documentation files (the
|
5
|
+
"Software"), to deal in the Software without restriction, including
|
6
|
+
without limitation the rights to use, copy, modify, merge, publish,
|
7
|
+
distribute, sublicense, and/or sell copies of the Software, and to
|
8
|
+
permit persons to whom the Software is furnished to do so, subject to
|
9
|
+
the following conditions:
|
10
|
+
|
11
|
+
The above copyright notice and this permission notice shall be
|
12
|
+
included in all copies or substantial portions of the Software.
|
13
|
+
|
14
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
|
15
|
+
EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
|
16
|
+
MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
|
17
|
+
NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
|
18
|
+
LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
|
19
|
+
OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
|
20
|
+
WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
data/README.textile
ADDED
@@ -0,0 +1,37 @@
|
|
1
|
+
h2. Server Remote
|
2
|
+
|
3
|
+
Server Remote is a gem that provides common application server commands over ssh via a script in @script/@ called @remote@.
|
4
|
+
|
5
|
+
Currently, it provides the following commands:
|
6
|
+
|
7
|
+
* @remote shell@ - same as ssh'ing to the server (this is the default command, so it can be called with just @remote@)
|
8
|
+
* @remote console@ - executes a @script/console@ on the server
|
9
|
+
* @remote logtail@ - executes @tail -f log/<environment>.log@ on the server
|
10
|
+
* @remote cmd <some command>@ executes command on the server, displaying the result. It @cd@'s to the remote app root first.
|
11
|
+
* @remote scp <local_file> :<remote_file>@ provides scp. Prefix remote files with ':'
|
12
|
+
|
13
|
+
h3. Configuration
|
14
|
+
|
15
|
+
Configuration is stored in @config/server_remote.yml@. On installation, a sample file is copied to @APP_ROOT/config/@ (along with @APP_ROOT/script/remote@).
|
16
|
+
|
17
|
+
The configuration file groups configurations into _profiles_. A profile defines the info needed to connect to a server, along with the path to the app and the environment it is running under.
|
18
|
+
|
19
|
+
The default profile is _app_. This can be changed with the @default_profile:@ setting in the config file, and overridden on any call with the @-p profile@ switch. This switch must be the first argument. Example:
|
20
|
+
|
21
|
+
@script/remote -p admin console@
|
22
|
+
|
23
|
+
h3. Installation
|
24
|
+
|
25
|
+
First, install the gem:
|
26
|
+
|
27
|
+
@gem install tobias-server_remote --source http://gems.github.com@
|
28
|
+
|
29
|
+
Second, use @server_remotify@ command to create the config and script file in your project:
|
30
|
+
|
31
|
+
@server_remotify path_to_app@
|
32
|
+
|
33
|
+
If either of the @config/@ or @script/@ dirs do not exist, they will be created for you.
|
34
|
+
|
35
|
+
*Note:* this plugin uses the ssh and scp binaries, which must be in your path. I have absolutely no idea if it will work on Windows.
|
36
|
+
|
37
|
+
Copyright (c) 2009 Tobias Crawley, released under the MIT license
|
data/VERSION.yml
ADDED
data/bin/server_remotify
ADDED
data/config/defaults.yml
ADDED
@@ -0,0 +1,39 @@
|
|
1
|
+
# Config file for server_remote plugin (http://github.com/tobias/server_remote)
|
2
|
+
# Options are grouped into named profiles.
|
3
|
+
|
4
|
+
# The default profile is 'app'. This can be changed here (this is the only
|
5
|
+
# top-level configuration option - the rest are within profiles).
|
6
|
+
#default_profile: app
|
7
|
+
|
8
|
+
# The only required option in a profile is host:. The rest can be pulled from
|
9
|
+
# the defaults or inferred by ssh.
|
10
|
+
|
11
|
+
# user: Specifies the user to log in as. No default; ssh will assume the
|
12
|
+
# current user.
|
13
|
+
|
14
|
+
# keyfile: specifies the path (relative to RAILS_ROOT) to the ssh keyfile. No
|
15
|
+
# default; ssh will ask for a password.
|
16
|
+
|
17
|
+
# environment: specifies the rails environment for the app on the server. Applies
|
18
|
+
# to the 'console' and 'logtail' commands. Default is 'production'.
|
19
|
+
|
20
|
+
# app_path: specifies the path to the app on the server relative to user:'s home
|
21
|
+
# or absolute. Default is '/mnt/app/current/'.
|
22
|
+
|
23
|
+
# tail_initial_lines: specifies how many lines the 'logtail' command should show
|
24
|
+
# initially. Default is 500.
|
25
|
+
|
26
|
+
common: &common
|
27
|
+
keyfile: config/server-key.pem
|
28
|
+
host: server.example.com
|
29
|
+
|
30
|
+
# Profiles:
|
31
|
+
|
32
|
+
app:
|
33
|
+
<<: *common
|
34
|
+
user: app
|
35
|
+
|
36
|
+
admin:
|
37
|
+
<<: *common
|
38
|
+
user: admin
|
39
|
+
|
data/lib/hash_ext.rb
ADDED
@@ -0,0 +1,28 @@
|
|
1
|
+
module ServerRemote
|
2
|
+
class InstallTools
|
3
|
+
|
4
|
+
def self.install(app_root)
|
5
|
+
app_cfg_dir = File.join(app_root, 'config')
|
6
|
+
|
7
|
+
FileUtils.mkdir(app_cfg_dir) unless File.exists?(app_cfg_dir)
|
8
|
+
|
9
|
+
cp File.join(GEM_ROOT, 'config', 'server_remote.yml.sample'), File.join(app_cfg_dir, 'server_remote.yml')
|
10
|
+
|
11
|
+
app_script_dir = File.join(app_root, 'script')
|
12
|
+
|
13
|
+
FileUtils.mkdir(app_script_dir) unless File.exists?(app_script_dir)
|
14
|
+
|
15
|
+
cp File.join(GEM_ROOT, 'script', 'remote'), File.join(app_script_dir, 'remote')
|
16
|
+
end
|
17
|
+
|
18
|
+
private
|
19
|
+
def self.cp(src, dest)
|
20
|
+
if File.exists?(dest)
|
21
|
+
puts "File '#{dest}' exists; skipping\n"
|
22
|
+
else
|
23
|
+
FileUtils.cp src, dest
|
24
|
+
end
|
25
|
+
end
|
26
|
+
|
27
|
+
end
|
28
|
+
end
|
@@ -0,0 +1,230 @@
|
|
1
|
+
require 'rubygems'
|
2
|
+
require 'yaml'
|
3
|
+
require 'simplecli'
|
4
|
+
require 'hash_ext'
|
5
|
+
|
6
|
+
module ServerRemote
|
7
|
+
GEM_ROOT = File.join(File.dirname(__FILE__), '..', '..')
|
8
|
+
|
9
|
+
module Util
|
10
|
+
|
11
|
+
DEFAULT_PROFILE = 'app'
|
12
|
+
|
13
|
+
|
14
|
+
def default_options_path
|
15
|
+
File.join(*([GEM_ROOT] + %w{config defaults.yml}))
|
16
|
+
end
|
17
|
+
|
18
|
+
def execute(cmd)
|
19
|
+
print "--> calling '#{cmd}'\n"
|
20
|
+
Kernel.system(cmd)
|
21
|
+
end
|
22
|
+
|
23
|
+
def user_and_host
|
24
|
+
user = "#{config[:user]}@" if config[:user]
|
25
|
+
"#{user}#{config[:host]}"
|
26
|
+
end
|
27
|
+
|
28
|
+
def keyfile_option
|
29
|
+
"-i #{File.join(app_root, config[:keyfile])} " if config[:keyfile]
|
30
|
+
end
|
31
|
+
|
32
|
+
def ssh_command
|
33
|
+
"ssh -t #{keyfile_option}#{user_and_host}"
|
34
|
+
end
|
35
|
+
|
36
|
+
def scp_command
|
37
|
+
"scp #{keyfile_option}"
|
38
|
+
end
|
39
|
+
|
40
|
+
def scp_file_argument(arg)
|
41
|
+
if arg and arg[0..0] == ':'
|
42
|
+
user_and_host + arg
|
43
|
+
else
|
44
|
+
arg
|
45
|
+
end
|
46
|
+
end
|
47
|
+
|
48
|
+
def console_action
|
49
|
+
"./script/console #{config[:environment]}"
|
50
|
+
end
|
51
|
+
|
52
|
+
def cd_to_app_action
|
53
|
+
"cd #{config[:app_path]}"
|
54
|
+
end
|
55
|
+
|
56
|
+
def tail_action
|
57
|
+
"tail -n #{config[:tail_initial_lines]} -f log/#{config[:environment]}.log"
|
58
|
+
end
|
59
|
+
|
60
|
+
def remote_command(args)
|
61
|
+
args = args.join(' ') if args.respond_to?(:join)
|
62
|
+
"#{ssh_command} '#{args}'"
|
63
|
+
end
|
64
|
+
|
65
|
+
def remote_command_in_app(args)
|
66
|
+
args = args.join(' ') if args.respond_to?(:join)
|
67
|
+
remote_command("#{cd_to_app_action};#{args}")
|
68
|
+
end
|
69
|
+
|
70
|
+
def app_root=(app_root)
|
71
|
+
@app_root = app_root
|
72
|
+
end
|
73
|
+
|
74
|
+
def app_root
|
75
|
+
raise 'app_root not set!' unless @app_root
|
76
|
+
@app_root
|
77
|
+
end
|
78
|
+
|
79
|
+
def config=(cfg)
|
80
|
+
@config = cfg
|
81
|
+
end
|
82
|
+
|
83
|
+
def config
|
84
|
+
@config ||= {}
|
85
|
+
end
|
86
|
+
|
87
|
+
def config_path
|
88
|
+
options[:config_path] ? options[:config_path] : File.join(app_root, 'config', 'server_remote.yml')
|
89
|
+
end
|
90
|
+
|
91
|
+
def load_config
|
92
|
+
load_default_config
|
93
|
+
load_app_config(config_path)
|
94
|
+
end
|
95
|
+
|
96
|
+
def parse_common_args
|
97
|
+
if args.first == '-p'
|
98
|
+
args.shift
|
99
|
+
p = args.shift
|
100
|
+
if p
|
101
|
+
config[:profile] = p
|
102
|
+
else
|
103
|
+
raise "Missing profile argument for -p"
|
104
|
+
end
|
105
|
+
end
|
106
|
+
|
107
|
+
# get around simplecli's usage call when there are no arguments
|
108
|
+
# instead of calling the default action
|
109
|
+
args << '--nullarg' if args.empty?
|
110
|
+
end
|
111
|
+
|
112
|
+
protected
|
113
|
+
|
114
|
+
def load_app_config(config_path)
|
115
|
+
cfg = YAML.load_file(config_path)
|
116
|
+
self.config[:profile] ||= cfg['default_profile'] || DEFAULT_PROFILE
|
117
|
+
if cfg[config[:profile]]
|
118
|
+
self.config.merge!(cfg[config[:profile]].symbolize_keys)
|
119
|
+
else
|
120
|
+
raise "No profile '#{config[:profile]}' exists in #{config_path}"
|
121
|
+
end
|
122
|
+
end
|
123
|
+
|
124
|
+
def load_default_config
|
125
|
+
self.config.merge!(YAML.load_file(default_options_path).symbolize_keys)
|
126
|
+
end
|
127
|
+
|
128
|
+
|
129
|
+
end
|
130
|
+
|
131
|
+
class Command
|
132
|
+
include SimpleCLI
|
133
|
+
include Util
|
134
|
+
|
135
|
+
def usage_help
|
136
|
+
"Summary: prints usage message"
|
137
|
+
end
|
138
|
+
|
139
|
+
def usage
|
140
|
+
puts <<EOH
|
141
|
+
Executes commands on a remote server over ssh. Configuration is in:
|
142
|
+
#{File.join(app_root, 'config', 'server_remote.yml')}
|
143
|
+
|
144
|
+
You can override the profile used with -p profile. The default profile is: #{config[:profile]}
|
145
|
+
|
146
|
+
Learn more in the readme:
|
147
|
+
#{File.join(GEM_ROOT, 'README.textile')}
|
148
|
+
|
149
|
+
EOH
|
150
|
+
|
151
|
+
commands
|
152
|
+
end
|
153
|
+
|
154
|
+
def shell_help
|
155
|
+
"Summary: executes remote shell"
|
156
|
+
end
|
157
|
+
|
158
|
+
def shell(*args)
|
159
|
+
execute ssh_command
|
160
|
+
end
|
161
|
+
|
162
|
+
def console_help
|
163
|
+
'Summary: executes remote console'
|
164
|
+
end
|
165
|
+
|
166
|
+
def console(*args)
|
167
|
+
execute remote_command_in_app(console_action)
|
168
|
+
end
|
169
|
+
|
170
|
+
def logtail_help
|
171
|
+
'Summary: executes remote tail -f on the log'
|
172
|
+
end
|
173
|
+
|
174
|
+
def logtail(*args)
|
175
|
+
execute remote_command_in_app(tail_action)
|
176
|
+
end
|
177
|
+
|
178
|
+
def cmd_help
|
179
|
+
%{
|
180
|
+
Summary: executes an arbitrary command on the server after a cd to the app path
|
181
|
+
|
182
|
+
usage: #{script_name} cmd <command>
|
183
|
+
}
|
184
|
+
end
|
185
|
+
|
186
|
+
def cmd(*args)
|
187
|
+
if args.empty?
|
188
|
+
cmd_help
|
189
|
+
else
|
190
|
+
execute remote_command_in_app(args)
|
191
|
+
end
|
192
|
+
end
|
193
|
+
|
194
|
+
def scp_help
|
195
|
+
%{
|
196
|
+
Summary: copies files over scp (prefix remote files with ':')
|
197
|
+
|
198
|
+
usage: #{script_name} scp <file1> <file2>
|
199
|
+
|
200
|
+
Example:
|
201
|
+
|
202
|
+
#{script_name} scp /local/file :/remote/file executes:
|
203
|
+
scp /local/file user@host:/remote/file
|
204
|
+
|
205
|
+
Any non colon prefixed arguments will be passed to scp.
|
206
|
+
}
|
207
|
+
end
|
208
|
+
|
209
|
+
def scp(*args)
|
210
|
+
if args.empty?
|
211
|
+
scp_help
|
212
|
+
else
|
213
|
+
execute scp_command + args.collect { |f| scp_file_argument(f) }.join(' ')
|
214
|
+
end
|
215
|
+
end
|
216
|
+
|
217
|
+
|
218
|
+
def self.start(app_root, args, options = {})
|
219
|
+
remote = new(args, options.merge(:default => 'shell'))
|
220
|
+
remote.app_root = app_root
|
221
|
+
remote.parse_common_args
|
222
|
+
remote.load_config
|
223
|
+
remote.parse!
|
224
|
+
remote.run
|
225
|
+
end
|
226
|
+
|
227
|
+
end
|
228
|
+
|
229
|
+
end
|
230
|
+
|
@@ -0,0 +1,7 @@
|
|
1
|
+
$:.unshift(File.dirname(__FILE__)) unless
|
2
|
+
$:.include?(File.dirname(__FILE__)) || $:.include?(File.expand_path(File.dirname(__FILE__)))
|
3
|
+
|
4
|
+
require File.join(File.dirname(__FILE__), 'server_remote', 'server_remote')
|
5
|
+
require File.join(File.dirname(__FILE__), 'server_remote', 'install_tools')
|
6
|
+
|
7
|
+
|
data/script/remote
ADDED
@@ -0,0 +1,43 @@
|
|
1
|
+
require 'test_helper'
|
2
|
+
|
3
|
+
class ServerRemoteTest < Test::Unit::TestCase
|
4
|
+
module ServerRemote::Util
|
5
|
+
def execute(cmd)
|
6
|
+
cmd
|
7
|
+
end
|
8
|
+
|
9
|
+
end
|
10
|
+
|
11
|
+
|
12
|
+
def run_cmd(args = [])
|
13
|
+
ServerRemote::Command.start(TEST_ROOT, args, :config_path => TEST_ROOT + '/config/config_no_override.yml')
|
14
|
+
end
|
15
|
+
|
16
|
+
|
17
|
+
def test_shell_action
|
18
|
+
assert_equal 'ssh -t test', run_cmd
|
19
|
+
assert_equal 'ssh -t test', run_cmd(%w{-p app})
|
20
|
+
end
|
21
|
+
|
22
|
+
def test_console_action
|
23
|
+
assert_equal "ssh -t test 'cd /mnt/app/current;./script/console production'", run_cmd(%w{console})
|
24
|
+
end
|
25
|
+
|
26
|
+
def test_logtail_action
|
27
|
+
assert_equal "ssh -t test 'cd /mnt/app/current;tail -n 500 -f log/production.log'", run_cmd(%w{logtail})
|
28
|
+
end
|
29
|
+
|
30
|
+
def test_cmd_action
|
31
|
+
assert_match /^Summary:/, run_cmd(%w{cmd})
|
32
|
+
assert_equal "ssh -t test 'cd /mnt/app/current;ls'", run_cmd(%w{cmd ls})
|
33
|
+
assert_equal "ssh -t test 'cd /mnt/app/current;ls -p'", run_cmd(%w{cmd ls -p})
|
34
|
+
assert_equal "ssh -t test 'cd /mnt/app/current;ls'", run_cmd(%w{-p app cmd ls})
|
35
|
+
end
|
36
|
+
|
37
|
+
def test_scp_action
|
38
|
+
assert_match /^Summary:/, run_cmd(%w{scp})
|
39
|
+
assert_equal "scp test:/remote/file /local/file", run_cmd(%w{scp :/remote/file /local/file})
|
40
|
+
assert_equal "scp test:/remote/file test:/local/file", run_cmd(%w{scp :/remote/file :/local/file})
|
41
|
+
end
|
42
|
+
|
43
|
+
end
|
@@ -0,0 +1,75 @@
|
|
1
|
+
require 'test_helper'
|
2
|
+
|
3
|
+
require 'pp'
|
4
|
+
|
5
|
+
class ServerRemoteUtilTest < Test::Unit::TestCase
|
6
|
+
include ServerRemote::Util
|
7
|
+
attr_accessor :args
|
8
|
+
attr_accessor :options
|
9
|
+
|
10
|
+
def setup
|
11
|
+
self.options = {}
|
12
|
+
self.app_root = TEST_ROOT
|
13
|
+
end
|
14
|
+
|
15
|
+
def test_load_config_should_load_defaults
|
16
|
+
options[:config_path] = TEST_ROOT + '/config/config_no_override.yml'
|
17
|
+
load_config
|
18
|
+
assert_equal 'app', config[:profile]
|
19
|
+
assert_equal 'production', config[:environment]
|
20
|
+
end
|
21
|
+
|
22
|
+
def test_load_config_should_override_defaults
|
23
|
+
options[:config_path] = TEST_ROOT + '/config/config_override.yml'
|
24
|
+
load_config
|
25
|
+
assert_equal 'test', config[:environment]
|
26
|
+
end
|
27
|
+
|
28
|
+
def test_parse_common_args_should_set_profile
|
29
|
+
self.config = {}
|
30
|
+
self.args = %w{-p profile}
|
31
|
+
parse_common_args
|
32
|
+
assert_equal 'profile', config[:profile]
|
33
|
+
end
|
34
|
+
|
35
|
+
|
36
|
+
def test_user_and_host
|
37
|
+
self.config = {:host => 'host'}
|
38
|
+
assert_equal 'host', user_and_host
|
39
|
+
|
40
|
+
self.config[:user] = 'user'
|
41
|
+
assert_equal 'user@host', user_and_host
|
42
|
+
end
|
43
|
+
|
44
|
+
def test_keyfile_option
|
45
|
+
self.config = {}
|
46
|
+
assert_nil keyfile_option
|
47
|
+
|
48
|
+
self.config[:keyfile] = 'kf'
|
49
|
+
assert_equal "-i #{File.join(TEST_ROOT, 'kf')} ", keyfile_option
|
50
|
+
end
|
51
|
+
|
52
|
+
def test_remote_command
|
53
|
+
self.config = {:host => 'host'}
|
54
|
+
assert_equal "ssh -t host 'cmd'", remote_command(%w{cmd})
|
55
|
+
end
|
56
|
+
|
57
|
+
def test_remote_command_in_app
|
58
|
+
self.config = {:host => 'host', :app_path => 'path'}
|
59
|
+
assert_equal "ssh -t host 'cd path;cmd'", remote_command_in_app(%w{cmd})
|
60
|
+
end
|
61
|
+
|
62
|
+
def test_scp_command
|
63
|
+
self.config = {}
|
64
|
+
assert_equal 'scp ', scp_command
|
65
|
+
self.config[:keyfile] = 'kf'
|
66
|
+
assert_equal "scp -i #{File.join(TEST_ROOT, 'kf')} ", scp_command
|
67
|
+
end
|
68
|
+
|
69
|
+
def test_scp_file_argument
|
70
|
+
self.config = {:host => 'host'}
|
71
|
+
assert_equal 'test', scp_file_argument('test')
|
72
|
+
assert_equal 'host:test', scp_file_argument(':test')
|
73
|
+
end
|
74
|
+
|
75
|
+
end
|
data/test/test_helper.rb
ADDED
@@ -0,0 +1,13 @@
|
|
1
|
+
require 'rubygems'
|
2
|
+
require 'test/unit'
|
3
|
+
require 'shoulda'
|
4
|
+
|
5
|
+
TEST_ROOT = File.dirname(__FILE__)
|
6
|
+
|
7
|
+
$LOAD_PATH.unshift(File.join(File.dirname(__FILE__), '..', 'lib'))
|
8
|
+
$LOAD_PATH.unshift(File.dirname(__FILE__))
|
9
|
+
require 'server_remote'
|
10
|
+
|
11
|
+
class Test::Unit::TestCase
|
12
|
+
|
13
|
+
end
|
metadata
ADDED
@@ -0,0 +1,83 @@
|
|
1
|
+
--- !ruby/object:Gem::Specification
|
2
|
+
name: server_remote
|
3
|
+
version: !ruby/object:Gem::Version
|
4
|
+
version: 0.2.0
|
5
|
+
platform: ruby
|
6
|
+
authors:
|
7
|
+
- Tobias Crawley
|
8
|
+
autorequire:
|
9
|
+
bindir: bin
|
10
|
+
cert_chain: []
|
11
|
+
|
12
|
+
date: 2009-10-01 00:00:00 -04:00
|
13
|
+
default_executable: server_remotify
|
14
|
+
dependencies:
|
15
|
+
- !ruby/object:Gem::Dependency
|
16
|
+
name: remi-simplecli
|
17
|
+
type: :runtime
|
18
|
+
version_requirement:
|
19
|
+
version_requirements: !ruby/object:Gem::Requirement
|
20
|
+
requirements:
|
21
|
+
- - ">="
|
22
|
+
- !ruby/object:Gem::Version
|
23
|
+
version: 0.1.5
|
24
|
+
version:
|
25
|
+
description:
|
26
|
+
email: tcrawley@gmail.com
|
27
|
+
executables:
|
28
|
+
- server_remotify
|
29
|
+
extensions: []
|
30
|
+
|
31
|
+
extra_rdoc_files:
|
32
|
+
- LICENSE
|
33
|
+
- README.textile
|
34
|
+
files:
|
35
|
+
- README.textile
|
36
|
+
- VERSION.yml
|
37
|
+
- bin/server_remotify
|
38
|
+
- config/defaults.yml
|
39
|
+
- config/server_remote.yml.sample
|
40
|
+
- lib/hash_ext.rb
|
41
|
+
- lib/server_remote.rb
|
42
|
+
- lib/server_remote/install_tools.rb
|
43
|
+
- lib/server_remote/server_remote.rb
|
44
|
+
- script/remote
|
45
|
+
- test/config/config_no_override.yml
|
46
|
+
- test/config/config_override.yml
|
47
|
+
- test/config/defaults.yml
|
48
|
+
- test/server_remote_test.rb
|
49
|
+
- test/server_remote_util_test.rb
|
50
|
+
- test/test_helper.rb
|
51
|
+
- LICENSE
|
52
|
+
has_rdoc: true
|
53
|
+
homepage: http://github.com/tobias/server_remote
|
54
|
+
licenses: []
|
55
|
+
|
56
|
+
post_install_message:
|
57
|
+
rdoc_options:
|
58
|
+
- --charset=UTF-8
|
59
|
+
require_paths:
|
60
|
+
- lib
|
61
|
+
required_ruby_version: !ruby/object:Gem::Requirement
|
62
|
+
requirements:
|
63
|
+
- - ">="
|
64
|
+
- !ruby/object:Gem::Version
|
65
|
+
version: "0"
|
66
|
+
version:
|
67
|
+
required_rubygems_version: !ruby/object:Gem::Requirement
|
68
|
+
requirements:
|
69
|
+
- - ">="
|
70
|
+
- !ruby/object:Gem::Version
|
71
|
+
version: "0"
|
72
|
+
version:
|
73
|
+
requirements: []
|
74
|
+
|
75
|
+
rubyforge_project:
|
76
|
+
rubygems_version: 1.3.5
|
77
|
+
signing_key:
|
78
|
+
specification_version: 3
|
79
|
+
summary: A gem that provides script/remote to a project for executing remote commands.
|
80
|
+
test_files:
|
81
|
+
- test/server_remote_test.rb
|
82
|
+
- test/server_remote_util_test.rb
|
83
|
+
- test/test_helper.rb
|