poet 0.4 → 0.5
Sign up to get free protection for your applications and to get access to all the features.
- data/.travis.yml +7 -1
- data/History.txt +18 -0
- data/README.md +15 -5
- data/bin/poet +1 -33
- data/features/bootstrapping.feature +4 -4
- data/features/editing_files.feature +32 -0
- data/features/step_definitions/editor_steps.rb +3 -0
- data/features/verbose.feature +29 -0
- data/lib/poet.rb +65 -49
- data/lib/poet/version.rb +1 -1
- data/poet.gemspec +1 -0
- metadata +27 -10
data/.travis.yml
CHANGED
data/History.txt
CHANGED
@@ -1,5 +1,23 @@
|
|
1
1
|
master
|
2
2
|
|
3
|
+
0.5
|
4
|
+
|
5
|
+
- drop support for Ruby 1.8
|
6
|
+
|
7
|
+
- edit files under ~/.ssh/config.d/ directly with `poet edit some_ssh_config_file`
|
8
|
+
|
9
|
+
- use Thor internally for CLI
|
10
|
+
|
11
|
+
- 'bootstrap' is now a subcommand (use `poet bootstrap` instead of `poet --bootstrap`)
|
12
|
+
|
13
|
+
- also test against JRuby, Rubinius, and 1.9.2
|
14
|
+
|
15
|
+
- running verbosely works again
|
16
|
+
|
17
|
+
- extended help
|
18
|
+
|
19
|
+
0.4
|
20
|
+
|
3
21
|
- let users organize their config files in directories
|
4
22
|
|
5
23
|
0.3.1
|
data/README.md
CHANGED
@@ -1,16 +1,26 @@
|
|
1
1
|
[![Build Status](https://secure.travis-ci.org/awendt/poet.png)](http://travis-ci.org/awendt/poet)
|
2
2
|
|
3
|
-
#
|
3
|
+
# Split your `ssh_config` into separate files!
|
4
4
|
|
5
|
-
|
6
|
-
|
7
|
-
|
5
|
+
## Getting started
|
6
|
+
|
7
|
+
$ gem install poet
|
8
|
+
$ poet bootstrap
|
9
|
+
|
10
|
+
This will move your `~/.ssh/config` into `~/.ssh/config.d/` and create an identical `~/.ssh/config`.
|
11
|
+
Organize files in `~/.ssh/config.d/` any way you want (just remember to re-run `poet` afterwards).
|
12
|
+
|
13
|
+
To edit `~/.ssh/config.d/some_file`, run `poet edit some_file`.
|
14
|
+
Poet will open your favorite $EDITOR and automatically create a new `~/.ssh/config`
|
15
|
+
when you quit the editor.
|
16
|
+
|
17
|
+
## Advanced usage
|
8
18
|
|
9
19
|
Poet won't touch your existing ssh_config.
|
10
20
|
If you want to play with it, pass a different filename to the "-o" option.
|
11
21
|
Or move your existing config out of the way.
|
12
22
|
|
13
|
-
Stanzas under `~/.ssh/config.d/` with an extension of .disabled are ignored by
|
23
|
+
Stanzas under `~/.ssh/config.d/` with an extension of .disabled are ignored by default.
|
14
24
|
Every now and then, when you do need it, run `poet --with CONFIG` to explicitly include
|
15
25
|
`CONFIG.disabled` in your generated ssh_config. You can even include several by running several
|
16
26
|
`--with` options or using `--with CONFIG1,CONFIG2`.
|
data/bin/poet
CHANGED
@@ -1,37 +1,5 @@
|
|
1
1
|
#!/usr/bin/env ruby
|
2
2
|
|
3
|
-
require 'optparse'
|
4
3
|
require 'poet'
|
5
4
|
|
6
|
-
|
7
|
-
:ssh_config => ENV['POET_OUTPUT'] || File.expand_path('~/.ssh/config'),
|
8
|
-
:verbose => false,
|
9
|
-
:with => [],
|
10
|
-
:dir => ENV['POET_GLOBDIR'] || File.expand_path('~/.ssh/config.d')
|
11
|
-
}
|
12
|
-
|
13
|
-
optparse = OptionParser.new do|opts|
|
14
|
-
opts.on('-h', '--help', 'Display this screen') do
|
15
|
-
puts opts
|
16
|
-
exit
|
17
|
-
end
|
18
|
-
opts.on('-d', '--dir DIR', '') do |dir|
|
19
|
-
options[:dir] = File.expand_path(dir)
|
20
|
-
end
|
21
|
-
opts.on('-o', '--output FILE', '') do |file|
|
22
|
-
options[:ssh_config] = file
|
23
|
-
end
|
24
|
-
opts.on('-v', '--verbose', 'Be verbose') do
|
25
|
-
options[:verbose] = true
|
26
|
-
end
|
27
|
-
opts.on('--bootstrap [FILE]', '') do |file|
|
28
|
-
options[:bootstrap] = File.expand_path(file || options[:ssh_config])
|
29
|
-
end
|
30
|
-
opts.on('-w', '--with CONFIG', 'Include an otherwise disabled config file') do |file|
|
31
|
-
options[:with] += file.split(',')
|
32
|
-
options[:with].each{|file| puts "Including #{file} even if disabled..."}
|
33
|
-
end
|
34
|
-
end
|
35
|
-
optparse.parse!
|
36
|
-
|
37
|
-
Poet.application(options).run
|
5
|
+
PoetCLI.start(ARGV)
|
@@ -8,7 +8,7 @@ Feature: Bootstrapping
|
|
8
8
|
Host *.amazonaws.com
|
9
9
|
StrictHostKeyChecking no
|
10
10
|
"""
|
11
|
-
When I run `poet
|
11
|
+
When I run `poet bootstrap --dir ./config.d`
|
12
12
|
Then the exit status should be 0
|
13
13
|
And a directory named "config.d" should exist
|
14
14
|
And a file named "config.d/ssh_config" should exist
|
@@ -24,8 +24,8 @@ Feature: Bootstrapping
|
|
24
24
|
Host *.amazonaws.com
|
25
25
|
StrictHostKeyChecking no
|
26
26
|
"""
|
27
|
-
When I run `poet
|
27
|
+
When I run `poet bootstrap --dir ./config.d`
|
28
28
|
Then the exit status should be 0
|
29
|
-
When I run `poet
|
30
|
-
Then the output from "poet
|
29
|
+
When I run `poet bootstrap --dir ./config.d`
|
30
|
+
Then the output from "poet bootstrap --dir ./config.d" should contain "You're already good to go"
|
31
31
|
And the exit status should not be 0
|
@@ -0,0 +1,32 @@
|
|
1
|
+
Feature: Editing files
|
2
|
+
Scenario: User wants to edit files quickly
|
3
|
+
Given a file named "favorite_editor" with:
|
4
|
+
"""
|
5
|
+
Host vim
|
6
|
+
User me
|
7
|
+
"""
|
8
|
+
When I set env variable "EDITOR" to "/bin/cat"
|
9
|
+
And I run `poet edit favorite_editor`
|
10
|
+
Then the output from "poet edit favorite_editor" should contain "Host vim"
|
11
|
+
And the file "ssh_config" should contain "Host vim"
|
12
|
+
|
13
|
+
Scenario: Show warning when user does not have EDITOR set
|
14
|
+
Given a file named "no_editor" with:
|
15
|
+
"""
|
16
|
+
Host none
|
17
|
+
User me
|
18
|
+
"""
|
19
|
+
When I set env variable "EDITOR" to ""
|
20
|
+
And I run `poet edit no_editor`
|
21
|
+
Then the output from "poet edit no_editor" should contain "$EDITOR is empty. Could not determine your favorite editor."
|
22
|
+
And the exit status should not be 0
|
23
|
+
|
24
|
+
Scenario: Do not re-create ssh_config when no file was created
|
25
|
+
Given a file named "important" with:
|
26
|
+
"""
|
27
|
+
This is absolutely vital information
|
28
|
+
"""
|
29
|
+
When I set env variable "EDITOR" to "/bin/cat"
|
30
|
+
And I run `poet edit missing -o important`
|
31
|
+
Then the output from "poet edit missing -o important" should not contain "Found hand-crafted ssh_config"
|
32
|
+
And the exit status should be 0
|
@@ -0,0 +1,29 @@
|
|
1
|
+
Feature: Seeing more output when running verbosely
|
2
|
+
Scenario: Silent by default
|
3
|
+
Given a file named "test" with:
|
4
|
+
"""
|
5
|
+
Host te.st
|
6
|
+
User me
|
7
|
+
"""
|
8
|
+
When I run `poet`
|
9
|
+
Then the output should not contain "Using test"
|
10
|
+
|
11
|
+
Scenario: User sees which files are included
|
12
|
+
Given a directory named "customers"
|
13
|
+
And a file named "customers/first" with:
|
14
|
+
"""
|
15
|
+
Host customer1
|
16
|
+
User me
|
17
|
+
"""
|
18
|
+
And a file named "customers/second" with:
|
19
|
+
"""
|
20
|
+
Host customer2
|
21
|
+
User me
|
22
|
+
"""
|
23
|
+
When I run `poet -v`
|
24
|
+
Then the output should contain exactly:
|
25
|
+
"""
|
26
|
+
Using customers/first
|
27
|
+
Using customers/second
|
28
|
+
|
29
|
+
"""
|
data/lib/poet.rb
CHANGED
@@ -1,71 +1,87 @@
|
|
1
1
|
require "poet/version"
|
2
|
+
require "thor"
|
2
3
|
require "fileutils"
|
3
4
|
|
4
|
-
|
5
|
+
class PoetCLI < Thor
|
5
6
|
|
6
7
|
MAGIC_LINE = "# Generated by #{File.basename(__FILE__, '.rb')}"
|
7
8
|
|
8
|
-
|
9
|
-
|
10
|
-
|
11
|
-
|
9
|
+
default_task :create
|
10
|
+
class_option :dir,
|
11
|
+
desc: 'Use specified directory to collect conf files',
|
12
|
+
default: ENV['POET_GLOBDIR'] || File.expand_path('~/.ssh/config.d')
|
13
|
+
class_option :output,
|
14
|
+
desc: 'Generate output in specified file',
|
15
|
+
aliases: '-o',
|
16
|
+
default: ENV['POET_OUTPUT'] || File.expand_path('~/.ssh/config')
|
17
|
+
class_option :with,
|
18
|
+
desc: 'Include an otherwise disabled config file',
|
19
|
+
aliases: '-w',
|
20
|
+
default: ""
|
21
|
+
class_option :verbose,
|
22
|
+
desc: 'Be verbose',
|
23
|
+
aliases: '-v',
|
24
|
+
type: :boolean
|
25
|
+
|
26
|
+
desc "bootstrap [FILE]",
|
27
|
+
"Move ~/.ssh/config (or whatever you specified) to ~/.ssh/config.d/ to help you get started"
|
28
|
+
def bootstrap(file=nil)
|
29
|
+
file ||= File.expand_path(file || options[:output])
|
30
|
+
if File.directory?(options[:dir])
|
31
|
+
$stderr.puts "You're already good to go."
|
32
|
+
Process.exit!(3)
|
12
33
|
end
|
13
|
-
|
34
|
+
FileUtils.mkdir_p(options[:dir])
|
35
|
+
FileUtils.mv(file, options[:dir])
|
36
|
+
create
|
14
37
|
end
|
15
38
|
|
16
|
-
|
17
|
-
|
18
|
-
|
19
|
-
|
20
|
-
|
21
|
-
@options = options
|
39
|
+
desc "", "Concatenate all host stanzas under ~/.ssh/config.d/ into a single ~/.ssh/config"
|
40
|
+
def create
|
41
|
+
if !File.directory?(options[:dir])
|
42
|
+
$stderr.puts "#{options[:dir]} does not exist or is not a directory"
|
43
|
+
Process.exit!(1)
|
22
44
|
end
|
23
45
|
|
24
|
-
|
25
|
-
|
26
|
-
|
27
|
-
|
28
|
-
|
29
|
-
FileUtils.mkdir_p(options[:dir])
|
30
|
-
FileUtils.mv(options[:bootstrap], options[:dir])
|
46
|
+
if File.exists?(options[:output]) && File.new(options[:output]).gets == "#{MAGIC_LINE}\n"
|
47
|
+
puts "Found generated ssh_config under #{options[:output]}. Overwriting..."
|
48
|
+
elsif File.exists?(options[:output])
|
49
|
+
$stderr.puts "Found hand-crafted ssh_config under #{options[:output]}. Please move it out of the way or specify a different output file with the -o option."
|
50
|
+
Process.exit!(2)
|
31
51
|
end
|
32
52
|
|
33
|
-
|
34
|
-
|
35
|
-
|
36
|
-
|
37
|
-
|
38
|
-
Process.exit!(1)
|
39
|
-
end
|
40
|
-
|
41
|
-
if File.exists?(options[:ssh_config]) && File.new(options[:ssh_config]).gets == "#{MAGIC_LINE}\n"
|
42
|
-
puts "Found generated ssh_config under #{options[:ssh_config]}. Overwriting..."
|
43
|
-
elsif File.exists?(options[:ssh_config])
|
44
|
-
$stderr.puts "Found hand-crafted ssh_config under #{options[:ssh_config]}. Please move it out of the way or specify a different output file with the -o option."
|
45
|
-
Process.exit!(2)
|
46
|
-
end
|
53
|
+
whitelist = options[:with].split(',')
|
54
|
+
files = Dir["#{options[:dir]}/**/*"].reject do |file|
|
55
|
+
File.directory?(file) || \
|
56
|
+
file =~ /\.disabled$/ && !whitelist.include?("#{File.basename(file, '.disabled')}")
|
57
|
+
end
|
47
58
|
|
48
|
-
|
49
|
-
File.directory?(file) || \
|
50
|
-
file =~ /\.disabled$/ && !options[:with].include?("#{File.basename(file, '.disabled')}")
|
51
|
-
end
|
59
|
+
files -= [options[:output]]
|
52
60
|
|
53
|
-
|
61
|
+
entries = []
|
54
62
|
|
55
|
-
|
63
|
+
files.sort.each do |file|
|
64
|
+
entries << File.read(file)
|
65
|
+
$stdout.puts "Using #{file.gsub(/^\.\//, '')}" if options[:verbose]
|
66
|
+
end
|
56
67
|
|
57
|
-
|
58
|
-
|
59
|
-
|
68
|
+
File.open(options[:output], 'w', 0600) do |ssh_config|
|
69
|
+
ssh_config.puts(MAGIC_LINE)
|
70
|
+
ssh_config.puts("# DO NOT EDIT THIS FILE")
|
71
|
+
ssh_config.puts("# Create or modify files under #{options[:dir]} instead")
|
72
|
+
ssh_config.puts(entries.join("\n"))
|
73
|
+
end
|
74
|
+
end
|
60
75
|
|
61
|
-
|
62
|
-
|
63
|
-
|
64
|
-
|
65
|
-
|
66
|
-
end
|
76
|
+
desc "edit FILE", "Open FILE under ~/.ssh/config.d/ in your favorite $EDITOR"
|
77
|
+
def edit(file)
|
78
|
+
if ENV['EDITOR'].to_s.empty?
|
79
|
+
$stderr.puts "$EDITOR is empty. Could not determine your favorite editor."
|
80
|
+
Process.exit!(4)
|
67
81
|
end
|
68
|
-
|
82
|
+
filepath = File.join(options[:dir], file)
|
83
|
+
system("#{ENV['EDITOR']} #{filepath}")
|
84
|
+
create if File.exists?(filepath)
|
69
85
|
end
|
70
86
|
|
71
87
|
end
|
data/lib/poet/version.rb
CHANGED
data/poet.gemspec
CHANGED
metadata
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: poet
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: '0.
|
4
|
+
version: '0.5'
|
5
5
|
prerelease:
|
6
6
|
platform: ruby
|
7
7
|
authors:
|
@@ -9,11 +9,11 @@ authors:
|
|
9
9
|
autorequire:
|
10
10
|
bindir: bin
|
11
11
|
cert_chain: []
|
12
|
-
date:
|
12
|
+
date: 2013-02-05 00:00:00.000000000 Z
|
13
13
|
dependencies:
|
14
14
|
- !ruby/object:Gem::Dependency
|
15
15
|
name: cucumber
|
16
|
-
requirement: &
|
16
|
+
requirement: &70099056296460 !ruby/object:Gem::Requirement
|
17
17
|
none: false
|
18
18
|
requirements:
|
19
19
|
- - ! '>='
|
@@ -21,10 +21,10 @@ dependencies:
|
|
21
21
|
version: '0'
|
22
22
|
type: :development
|
23
23
|
prerelease: false
|
24
|
-
version_requirements: *
|
24
|
+
version_requirements: *70099056296460
|
25
25
|
- !ruby/object:Gem::Dependency
|
26
26
|
name: aruba
|
27
|
-
requirement: &
|
27
|
+
requirement: &70099056296020 !ruby/object:Gem::Requirement
|
28
28
|
none: false
|
29
29
|
requirements:
|
30
30
|
- - ! '>='
|
@@ -32,10 +32,10 @@ dependencies:
|
|
32
32
|
version: '0'
|
33
33
|
type: :development
|
34
34
|
prerelease: false
|
35
|
-
version_requirements: *
|
35
|
+
version_requirements: *70099056296020
|
36
36
|
- !ruby/object:Gem::Dependency
|
37
37
|
name: rake
|
38
|
-
requirement: &
|
38
|
+
requirement: &70099056295560 !ruby/object:Gem::Requirement
|
39
39
|
none: false
|
40
40
|
requirements:
|
41
41
|
- - ! '>='
|
@@ -43,7 +43,18 @@ dependencies:
|
|
43
43
|
version: '0'
|
44
44
|
type: :development
|
45
45
|
prerelease: false
|
46
|
-
version_requirements: *
|
46
|
+
version_requirements: *70099056295560
|
47
|
+
- !ruby/object:Gem::Dependency
|
48
|
+
name: thor
|
49
|
+
requirement: &70099056311480 !ruby/object:Gem::Requirement
|
50
|
+
none: false
|
51
|
+
requirements:
|
52
|
+
- - ! '>='
|
53
|
+
- !ruby/object:Gem::Version
|
54
|
+
version: '0'
|
55
|
+
type: :runtime
|
56
|
+
prerelease: false
|
57
|
+
version_requirements: *70099056311480
|
47
58
|
description: Split your longish ~/.ssh/config into files in ~/.ssh/config.d/ and let
|
48
59
|
poet join them for you.
|
49
60
|
email:
|
@@ -62,11 +73,14 @@ files:
|
|
62
73
|
- Rakefile
|
63
74
|
- bin/poet
|
64
75
|
- features/bootstrapping.feature
|
76
|
+
- features/editing_files.feature
|
65
77
|
- features/permissions.feature
|
66
78
|
- features/running.feature
|
67
79
|
- features/selective_files.feature
|
80
|
+
- features/step_definitions/editor_steps.rb
|
68
81
|
- features/step_definitions/permissions_steps.rb
|
69
82
|
- features/support/env.rb
|
83
|
+
- features/verbose.feature
|
70
84
|
- lib/poet.rb
|
71
85
|
- lib/poet/version.rb
|
72
86
|
- poet.gemspec
|
@@ -84,7 +98,7 @@ required_ruby_version: !ruby/object:Gem::Requirement
|
|
84
98
|
version: '0'
|
85
99
|
segments:
|
86
100
|
- 0
|
87
|
-
hash: -
|
101
|
+
hash: -3487840776745573411
|
88
102
|
required_rubygems_version: !ruby/object:Gem::Requirement
|
89
103
|
none: false
|
90
104
|
requirements:
|
@@ -93,7 +107,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
|
|
93
107
|
version: '0'
|
94
108
|
segments:
|
95
109
|
- 0
|
96
|
-
hash: -
|
110
|
+
hash: -3487840776745573411
|
97
111
|
requirements: []
|
98
112
|
rubyforge_project: poet
|
99
113
|
rubygems_version: 1.8.11
|
@@ -102,8 +116,11 @@ specification_version: 3
|
|
102
116
|
summary: Poet concatenates stanzas
|
103
117
|
test_files:
|
104
118
|
- features/bootstrapping.feature
|
119
|
+
- features/editing_files.feature
|
105
120
|
- features/permissions.feature
|
106
121
|
- features/running.feature
|
107
122
|
- features/selective_files.feature
|
123
|
+
- features/step_definitions/editor_steps.rb
|
108
124
|
- features/step_definitions/permissions_steps.rb
|
109
125
|
- features/support/env.rb
|
126
|
+
- features/verbose.feature
|