ghost 0.3.0 → 1.0.0.pre

Sign up to get free protection for your applications and to get access to all the features.
Files changed (46) hide show
  1. data/LICENSE +1 -1
  2. data/bin/ghost +2 -130
  3. data/lib/ghost.rb +3 -16
  4. data/lib/ghost/cli.rb +60 -0
  5. data/lib/ghost/cli/task.rb +71 -0
  6. data/lib/ghost/cli/task/add.rb +25 -0
  7. data/lib/ghost/cli/task/delete.rb +30 -0
  8. data/lib/ghost/cli/task/empty.rb +18 -0
  9. data/lib/ghost/cli/task/export.rb +19 -0
  10. data/lib/ghost/cli/task/help.rb +41 -0
  11. data/lib/ghost/cli/task/import.rb +25 -0
  12. data/lib/ghost/cli/task/list.rb +40 -0
  13. data/lib/ghost/host.rb +34 -0
  14. data/lib/ghost/store.rb +12 -0
  15. data/lib/ghost/store/dscl_store.rb +71 -0
  16. data/lib/ghost/store/hosts_file_store.rb +123 -0
  17. data/lib/ghost/tokenized_file.rb +65 -0
  18. data/lib/ghost/version.rb +3 -0
  19. data/spec/ghost/cli/task/add_spec.rb +80 -0
  20. data/spec/ghost/cli/task/delete_spec.rb +20 -0
  21. data/spec/ghost/cli/task/empty_spec.rb +19 -0
  22. data/spec/ghost/cli/task/export_spec.rb +16 -0
  23. data/spec/ghost/cli/task/help_spec.rb +36 -0
  24. data/spec/ghost/cli/task/import_spec.rb +56 -0
  25. data/spec/ghost/cli/task/list_spec.rb +50 -0
  26. data/spec/ghost/cli_spec.rb +22 -0
  27. data/spec/ghost/host_spec.rb +36 -0
  28. data/spec/ghost/store/dscl_store_spec.rb +153 -0
  29. data/spec/ghost/store/hosts_file_store_spec.rb +316 -0
  30. data/spec/ghost/store_spec.rb +2 -0
  31. data/spec/ghost/tokenized_file_spec.rb +131 -0
  32. data/spec/spec_helper.rb +4 -2
  33. data/spec/support/cli.rb +29 -0
  34. data/spec/support/resolv.rb +15 -0
  35. metadata +91 -27
  36. data/Rakefile +0 -28
  37. data/TODO +0 -0
  38. data/bin/ghost-ssh +0 -132
  39. data/lib/ghost/linux-host.rb +0 -158
  40. data/lib/ghost/mac-host.rb +0 -116
  41. data/lib/ghost/ssh_config.rb +0 -110
  42. data/spec/etc_hosts_spec.rb +0 -190
  43. data/spec/ghost_spec.rb +0 -151
  44. data/spec/spec.opts +0 -1
  45. data/spec/ssh_config_spec.rb +0 -80
  46. data/spec/ssh_config_template +0 -11
@@ -0,0 +1,2 @@
1
+ require File.expand_path("#{File.dirname(__FILE__)}/../spec_helper.rb")
2
+ require 'ghost/store'
@@ -0,0 +1,131 @@
1
+ require File.expand_path("#{File.dirname(__FILE__)}/../spec_helper.rb")
2
+ require 'ghost/tokenized_file'
3
+
4
+ require 'tmpdir'
5
+ require 'fileutils'
6
+
7
+ describe Ghost::TokenizedFile do
8
+ let(:file) { File.open(file_path, 'r+') }
9
+ let(:file_path) { File.join(Dir.tmpdir, "tokenized_file.#{Process.pid}.#{rand(9999999)}") }
10
+ let(:tokenized_file) { Ghost::TokenizedFile.new(file_path, start_token, end_token) }
11
+ let(:start_token) { "# start" }
12
+ let(:end_token) { "# end" }
13
+
14
+ before { FileUtils.touch(file_path) }
15
+
16
+ describe "#read" do
17
+ context "with empty file" do
18
+ it "returns empty string" do
19
+ tokenized_file.read.should == ""
20
+ end
21
+ end
22
+
23
+ context "with a non-empty file with no tokens" do
24
+ before do
25
+ file.write "hi there"
26
+ file.close
27
+ end
28
+
29
+ it "returns empty string" do
30
+ tokenized_file.read.should == ""
31
+ end
32
+ end
33
+
34
+ context 'with a non-empty file with content between tokens' do
35
+ before do
36
+ file.write "#{start_token}\nline 1\nline 2\n#{end_token}"
37
+ file.close
38
+ end
39
+
40
+ it "returns empty string" do
41
+ tokenized_file.read.should == "line 1\nline 2\n"
42
+ end
43
+ end
44
+
45
+ context 'with a non-empty file with empty tokens' do
46
+ before do
47
+ file.write "#{start_token}\n#{end_token}"
48
+ file.flush
49
+ file.rewind
50
+ end
51
+
52
+ it "returns empty string" do
53
+ tokenized_file.read.should == ""
54
+ end
55
+ end
56
+ end
57
+
58
+ describe "#write" do
59
+ context 'writing to a file with existing content' do
60
+ context "with no tokens" do
61
+ before do
62
+ file.write "xyz"
63
+ file.flush
64
+ file.rewind
65
+ end
66
+
67
+ it "doesn't change file contents when writing nothing" do
68
+ tokenized_file.write ""
69
+ file.read.should == "xyz\n"
70
+ end
71
+
72
+ it "inserts appends new content to file between tokens" do
73
+ tokenized_file.write "abc"
74
+ file.read.should == "xyz\n#{start_token}\nabc\n#{end_token}\n"
75
+ end
76
+ end
77
+
78
+ context "with empty tokens" do
79
+ before do
80
+ file.write "#{start_token}\n#{end_token}\nxyz"
81
+ file.flush
82
+ file.rewind
83
+ end
84
+
85
+ it "removes the token when writing an nothing" do
86
+ tokenized_file.write ""
87
+ file.read.should == "xyz\n"
88
+ end
89
+
90
+ it "adds content between the tokens when writing content" do
91
+ tokenized_file.write "foo"
92
+ file.read.should == "xyz\n#{start_token}\nfoo\n#{end_token}\n"
93
+ end
94
+ end
95
+
96
+ context "with non-empty tokens" do
97
+ before do
98
+ file.write "#{start_token}\nfoo\n#{end_token}\nxyz"
99
+ file.flush
100
+ file.rewind
101
+ end
102
+
103
+ it "removes the token when writing an nothing" do
104
+ tokenized_file.write ""
105
+ file.read.should == "xyz\n"
106
+ end
107
+
108
+ it "replaces the content between the tokens when writing new content" do
109
+ tokenized_file.write "bar"
110
+ file.read.should == "xyz\n#{start_token}\nbar\n#{end_token}\n"
111
+ end
112
+ end
113
+ end
114
+
115
+ context "writing to an empty file" do
116
+ context "when writing nothing" do
117
+ it "writes nothing to the file" do
118
+ tokenized_file.write ""
119
+ file.read.should == ""
120
+ end
121
+ end
122
+
123
+ context "when writing something" do
124
+ it "writes content to the file between tokens" do
125
+ tokenized_file.write "a"
126
+ file.read.should == "#{start_token}\na\n#{end_token}\n"
127
+ end
128
+ end
129
+ end
130
+ end
131
+ end
@@ -1,4 +1,6 @@
1
- $TESTING=true
2
1
  $:.unshift File.join(File.dirname(__FILE__), '..', 'lib')
2
+
3
3
  require 'rubygems'
4
- require 'spec'
4
+ require 'rspec'
5
+
6
+ Dir[File.join(File.dirname(__FILE__), "support", "*")].each { |f| require(f) }
@@ -0,0 +1,29 @@
1
+ require 'fileutils'
2
+ require 'tempfile'
3
+ require 'tmpdir'
4
+
5
+ module CliSpecs
6
+ def self.included(klass)
7
+ klass.before do
8
+ FileUtils.touch(store_path)
9
+ Ghost.store = store
10
+ end
11
+
12
+ klass.let(:store_path) { File.join(Dir.tmpdir, "etc_hosts.#{Process.pid}.#{rand(9999)}") }
13
+ klass.let(:store) { Ghost::Store::HostsFileStore.new(store_path) }
14
+ end
15
+
16
+ def ghost(args)
17
+ out = StringIO.new
18
+ Ghost::Cli.new(out).parse(args.split(/\s+/))
19
+ out.rewind
20
+ out.read
21
+ rescue SystemExit
22
+ out.rewind
23
+ out.read
24
+ end
25
+ end
26
+
27
+ RSpec.configure do |c|
28
+ c.include CliSpecs, :type => :cli
29
+ end
@@ -0,0 +1,15 @@
1
+ require 'ipaddr'
2
+
3
+ RSpec.configure do |c|
4
+ IP_ADDRESS_REGEX = /\b(?:(?:25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?)\.){3}(?:25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?)\b/
5
+
6
+ c.before do
7
+ Ghost::Host.any_instance.stub(:resolve_ip) do |ip_or_hostname|
8
+ if ip_or_hostname =~ IP_ADDRESS_REGEX
9
+ ip_or_hostname
10
+ else
11
+ raise "Don't resolve in tests!"
12
+ end
13
+ end
14
+ end
15
+ end
metadata CHANGED
@@ -1,48 +1,96 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: ghost
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.3.0
5
- prerelease:
4
+ version: 1.0.0.pre
5
+ prerelease: 6
6
6
  platform: ruby
7
7
  authors:
8
8
  - Bodaniel Jeanes
9
- autorequire: ghost
9
+ autorequire:
10
10
  bindir: bin
11
11
  cert_chain: []
12
- date: 2012-04-18 00:00:00.000000000Z
13
- dependencies: []
14
- description: Allows you to create, list, and modify local hostnames
12
+ date: 2012-09-05 00:00:00.000000000Z
13
+ dependencies:
14
+ - !ruby/object:Gem::Dependency
15
+ name: unindent
16
+ requirement: &70100277448360 !ruby/object:Gem::Requirement
17
+ none: false
18
+ requirements:
19
+ - - =
20
+ - !ruby/object:Gem::Version
21
+ version: '1.0'
22
+ type: :runtime
23
+ prerelease: false
24
+ version_requirements: *70100277448360
25
+ - !ruby/object:Gem::Dependency
26
+ name: rspec
27
+ requirement: &70100277447880 !ruby/object:Gem::Requirement
28
+ none: false
29
+ requirements:
30
+ - - =
31
+ - !ruby/object:Gem::Version
32
+ version: 2.9.0
33
+ type: :development
34
+ prerelease: false
35
+ version_requirements: *70100277447880
36
+ - !ruby/object:Gem::Dependency
37
+ name: rake
38
+ requirement: &70100277447400 !ruby/object:Gem::Requirement
39
+ none: false
40
+ requirements:
41
+ - - =
42
+ - !ruby/object:Gem::Version
43
+ version: 0.9.2.2
44
+ type: :development
45
+ prerelease: false
46
+ version_requirements: *70100277447400
47
+ description: Allows you to create, list, and modify local hostnames on POSIX systems
48
+ (e.g. Mac OS X and Linux) and Windows
15
49
  email: me@bjeanes.com
16
50
  executables:
17
51
  - ghost
18
- - ghost-ssh
19
52
  extensions: []
20
- extra_rdoc_files:
21
- - README.md
22
- - LICENSE
23
- - TODO
53
+ extra_rdoc_files: []
24
54
  files:
25
55
  - LICENSE
26
56
  - README.md
27
- - Rakefile
28
- - TODO
29
57
  - bin/ghost
30
- - bin/ghost-ssh
31
- - lib/ghost/linux-host.rb
32
- - lib/ghost/mac-host.rb
33
- - lib/ghost/ssh_config.rb
58
+ - lib/ghost/cli/task/add.rb
59
+ - lib/ghost/cli/task/delete.rb
60
+ - lib/ghost/cli/task/empty.rb
61
+ - lib/ghost/cli/task/export.rb
62
+ - lib/ghost/cli/task/help.rb
63
+ - lib/ghost/cli/task/import.rb
64
+ - lib/ghost/cli/task/list.rb
65
+ - lib/ghost/cli/task.rb
66
+ - lib/ghost/cli.rb
67
+ - lib/ghost/host.rb
68
+ - lib/ghost/store/dscl_store.rb
69
+ - lib/ghost/store/hosts_file_store.rb
70
+ - lib/ghost/store.rb
71
+ - lib/ghost/tokenized_file.rb
72
+ - lib/ghost/version.rb
34
73
  - lib/ghost.rb
35
- - spec/etc_hosts_spec.rb
36
- - spec/ghost_spec.rb
37
- - spec/spec.opts
74
+ - spec/ghost/cli/task/add_spec.rb
75
+ - spec/ghost/cli/task/delete_spec.rb
76
+ - spec/ghost/cli/task/empty_spec.rb
77
+ - spec/ghost/cli/task/export_spec.rb
78
+ - spec/ghost/cli/task/help_spec.rb
79
+ - spec/ghost/cli/task/import_spec.rb
80
+ - spec/ghost/cli/task/list_spec.rb
81
+ - spec/ghost/cli_spec.rb
82
+ - spec/ghost/host_spec.rb
83
+ - spec/ghost/store/dscl_store_spec.rb
84
+ - spec/ghost/store/hosts_file_store_spec.rb
85
+ - spec/ghost/store_spec.rb
86
+ - spec/ghost/tokenized_file_spec.rb
38
87
  - spec/spec_helper.rb
39
- - spec/ssh_config_spec.rb
40
- - spec/ssh_config_template
88
+ - spec/support/cli.rb
89
+ - spec/support/resolv.rb
41
90
  homepage: http://github.com/bjeanes/ghost
42
91
  licenses: []
43
92
  post_install_message:
44
- rdoc_options:
45
- - --line-numbers
93
+ rdoc_options: []
46
94
  require_paths:
47
95
  - lib
48
96
  required_ruby_version: !ruby/object:Gem::Requirement
@@ -54,13 +102,29 @@ required_ruby_version: !ruby/object:Gem::Requirement
54
102
  required_rubygems_version: !ruby/object:Gem::Requirement
55
103
  none: false
56
104
  requirements:
57
- - - ! '>='
105
+ - - ! '>'
58
106
  - !ruby/object:Gem::Version
59
- version: '0'
107
+ version: 1.3.1
60
108
  requirements: []
61
109
  rubyforge_project: ghost
62
110
  rubygems_version: 1.8.10
63
111
  signing_key:
64
112
  specification_version: 3
65
113
  summary: Allows you to create, list, and modify local hostnames
66
- test_files: []
114
+ test_files:
115
+ - spec/ghost/cli/task/add_spec.rb
116
+ - spec/ghost/cli/task/delete_spec.rb
117
+ - spec/ghost/cli/task/empty_spec.rb
118
+ - spec/ghost/cli/task/export_spec.rb
119
+ - spec/ghost/cli/task/help_spec.rb
120
+ - spec/ghost/cli/task/import_spec.rb
121
+ - spec/ghost/cli/task/list_spec.rb
122
+ - spec/ghost/cli_spec.rb
123
+ - spec/ghost/host_spec.rb
124
+ - spec/ghost/store/dscl_store_spec.rb
125
+ - spec/ghost/store/hosts_file_store_spec.rb
126
+ - spec/ghost/store_spec.rb
127
+ - spec/ghost/tokenized_file_spec.rb
128
+ - spec/spec_helper.rb
129
+ - spec/support/cli.rb
130
+ - spec/support/resolv.rb
data/Rakefile DELETED
@@ -1,28 +0,0 @@
1
- require 'rubygems'
2
- require 'rake/gempackagetask'
3
- require 'rubygems/specification'
4
- require 'date'
5
-
6
- Dir['tasks/**/*.rake'].each { |rake| load rake }
7
-
8
-
9
- #### MISC TASKS ####
10
-
11
- desc "list tasks"
12
- task :default do
13
- puts `rake -T`
14
- end
15
-
16
- desc "Outstanding TODO's"
17
- task :todo do
18
- files = ["**/*.{rb,rake}" "bin/*", "README.mkdn"]
19
-
20
- File.open('TODO','w') do |f|
21
- FileList[*files].egrep(/TODO|FIXME/) do |file, line, text|
22
- output = "#{file}:#{line} - #{text.chomp.gsub(/^\s+|\s+$/ , "")}"
23
-
24
- puts output
25
- f.puts output
26
- end
27
- end
28
- end
data/TODO DELETED
File without changes
@@ -1,132 +0,0 @@
1
- #!/usr/bin/env ruby
2
-
3
- require File.expand_path(File.dirname(__FILE__) + '/../lib/ghost')
4
-
5
- def help_text(exit_code = 0)
6
- script_name = File.basename $0
7
- puts """USAGE: #{script_name} add <host> <hostname> [--user=<user>] [--port=<port>]
8
- #{script_name} modify <host> <hostname> [--user=<user>] [--port=<port>]
9
- #{script_name} delete <host>
10
- #{script_name} list
11
- #{script_name} empty
12
- #{script_name} export
13
- #{script_name} import <file>
14
- """
15
- exit(exit_code)
16
- end
17
-
18
- def parse(argv)
19
- argv.shift
20
-
21
- new_config = {
22
- :host => argv.shift,
23
- :hostname => argv.shift
24
- }
25
-
26
- if argv.size > 0
27
- argv.each do |arg|
28
- if arg =~ /--([a-z]+)=(.*)/
29
- new_config[$1.to_sym] = $2
30
- end
31
- end
32
- end
33
-
34
- new_config
35
- end
36
-
37
- if ARGV.size.zero? || ['-h', '--help', 'help'].include?(ARGV.first)
38
- help_text
39
- else
40
- case ARGV[0]
41
- when 'add'
42
- if [3,4,5].include?(ARGV.size)
43
- begin
44
- new_config = parse(ARGV)
45
-
46
- config = Ghost::SshConfig.add(new_config)
47
- puts " [Adding] #{config.host} -> #{config.hostname}"
48
- exit 0
49
- rescue Ghost::SshConfigDuplicateError
50
- $stderr.puts $!
51
- exit 3
52
- end
53
- else
54
- $stderr.puts "The add subcommand requires at least a host and a hostname.\n\n"
55
- help_text 2
56
- end
57
- when 'modify'
58
- if [3,4,5].include?(ARGV.size)
59
- new_config = parse(ARGV)
60
- new_config[:force] = true
61
- config = Ghost::SshConfig.add(new_config)
62
- puts " [Modifying] #{config.host} -> #{config.hostname}"
63
- exit 0
64
- else
65
- $stderr.puts "The modify subcommand requires at least a host and a hostname.\n\n"
66
- help_text 4
67
- end
68
- when 'delete', 'del', 'remove', 'rm'
69
- if ARGV.size == 2
70
- Ghost::SshConfig.delete(ARGV[1])
71
- puts " [Deleting] #{ARGV[1]}"
72
- exit 0
73
- else
74
- $stderr.puts "The delete subcommand requires a hostname.\n\n"
75
- help_text 2
76
- end
77
-
78
- when 'list'
79
- configs = Ghost::SshConfig.list
80
- pad = configs.max{|a,b| a.to_s.length <=> b.to_s.length }.to_s.length
81
-
82
- puts "Listing #{configs.size} configs(s):"
83
-
84
- configs.each do |c|
85
- user = c.user ? "#{c.user}@" : ""
86
- puts "#{c.host.rjust(pad+2)} -> #{user}#{c.hostname}:#{c.port||22}"
87
- end
88
- exit 0
89
- when 'empty'
90
- print " [Emptying] "
91
- Ghost::SshConfig.empty!
92
- puts "Done."
93
- exit 0
94
- when 'export'
95
- configs = Ghost::SshConfig.list
96
- configs.each do |c|
97
- puts "#{c.host},#{c.hostname},#{c.user},#{c.port}"
98
- end
99
- exit 0
100
- when 'import'
101
- if ARGV.size == 2
102
- begin
103
- File.foreach(ARGV[1]) do |line|
104
- cfg_infos = line.strip.split(',')
105
- hash = {
106
- :host => cfg_infos[0],
107
- :hostname => cfg_infos[1]
108
- }
109
-
110
- hash[:user] = cfg_infos[2] if cfg_infos.size > 2
111
- hash[:port] = cfg_infos[3] if cfg_infos.size > 3
112
- hash[:force] = true
113
-
114
- config = Ghost::SshConfig.add(hash)
115
-
116
- puts " [Adding] #{config.host} -> #{config.hostname}"
117
- end
118
- exit 0
119
- rescue
120
- $stderr.puts "Cannot import. A problem occured while opening the import file (#{$!.message})."
121
- exit 5
122
- end
123
- else
124
- $stderr.puts "The import command requires an input file.\n\n"
125
- help_text 6
126
- end
127
- else
128
- $stderr.puts "Invalid option: #{ARGV[0]}"
129
- help_text 1
130
- end
131
- end
132
-