hosts-cli 0.1.0

Sign up to get free protection for your applications and to get access to all the features.
checksums.yaml ADDED
@@ -0,0 +1,7 @@
1
+ ---
2
+ SHA1:
3
+ metadata.gz: 85b4ffe43ac4d76a38fca773d29bf8c754c4ccc6
4
+ data.tar.gz: 3164d63d30eebb53eaaafec6364dd854237c054e
5
+ SHA512:
6
+ metadata.gz: 80ba5915bcfd43f204627d14c04c541eca372544803018467a24bc051028509636bdaef2f24e713d53102a700ecdf34c1c3111db67b694a98fc81a10955b162e
7
+ data.tar.gz: cdfb89302a6e8139e9eb767dffd117ccde75097d48c7339b7c67bcdabe584ceb46d7e320187ff5697e9275464fe602d45536a77ed494a01b4286b7b4b8802a57
data/bin/hosts ADDED
@@ -0,0 +1,10 @@
1
+ #!/usr/bin/env ruby
2
+
3
+ # Ad lib to include path
4
+ $:.unshift File.dirname(File.expand_path(File.dirname(__FILE__))) + '/lib'
5
+
6
+ # Require sub commands
7
+ require 'Hosts/Lib/autoload.rb'
8
+ require 'hosts.rb'
9
+
10
+ Hosts.main
@@ -0,0 +1,28 @@
1
+ include Hosts::Lib::Core
2
+ include Hosts::Lib
3
+
4
+ module Hosts::Lib::Commands
5
+ options_obj = Slop::Options.new suppress_errors: true
6
+ options_obj.banner = "Usage: hosts add [dest] [hostname [hostname [...]]]"
7
+
8
+ Add = SubCommand.new(
9
+ 'add', # Name of the sub command
10
+ 'Add a hosts entry. requires \'sudo\'',
11
+ options_obj
12
+ ) { |options, args|
13
+ unless (args.length >= 2)
14
+ puts options_obj.banner
15
+ next
16
+ end
17
+
18
+ hosts_file = HostsFile.new Hosts.hosts_file
19
+
20
+ hosts_file.add_entry(args[0], args[1])
21
+
22
+ puts "Added entry: #{args[0]} => #{args[1]}"
23
+
24
+ # Write changes to hosts file
25
+ hosts_file.flush
26
+ }
27
+ @Add
28
+ end
@@ -0,0 +1,17 @@
1
+ include Hosts::Lib::Core
2
+
3
+ module Hosts::Lib::Commands
4
+ options_obj = Slop::Options.new
5
+
6
+ Help = SubCommand.new(
7
+ 'help', # Name of the command
8
+ 'Print the help message', # Description
9
+ options_obj, # Has no options
10
+ false
11
+ ) do |_options, _args|
12
+ Hosts.sub_commands.each do |_key, cmd|
13
+ cmd.print_help_message
14
+ end
15
+ end
16
+ @Help
17
+ end
@@ -0,0 +1,32 @@
1
+ require 'JSON'
2
+
3
+ module Hosts::Lib::Commands
4
+ options_obj = Slop::Options.new
5
+
6
+ List = SubCommand.new(
7
+ 'list', # Name of the sub command
8
+ 'List all host entries',
9
+ options_obj,
10
+ false
11
+ ) { |options, args|
12
+ hosts_file = HostsFile.new Hosts.hosts_file
13
+ hosts_entries = hosts_file.get_all_entries
14
+
15
+ longest_dest_name = 0
16
+
17
+ hosts_entries.each do |dest, hostnames|
18
+ if (dest.length > longest_dest_name)
19
+ longest_dest_name = dest.length
20
+ end
21
+ end
22
+
23
+ hosts_entries.each do |dest, hostnames|
24
+ hostname_f = hostnames * ", "
25
+
26
+ print "%-#{longest_dest_name}.#{longest_dest_name}s" % dest
27
+ print " "
28
+ puts "=> #{hostname_f}"
29
+ end
30
+ }
31
+ @List
32
+ end
@@ -0,0 +1,34 @@
1
+ include Hosts::Lib::Core
2
+
3
+ module Hosts::Lib::Commands
4
+ options_obj = Slop::Options.new
5
+ options_obj.banner = "Usage: hosts dest [alias]"
6
+
7
+ Rm = SubCommand.new(
8
+ 'rm', # Name of the sub command
9
+ "Remove entry. Removes all entries to a 'dest' if no alias is defined. Requires 'sudo'",
10
+ options_obj
11
+ ) { |options, args|
12
+ # Must be right number of arguments
13
+ unless (args.length > 0 && args.length <= 2)
14
+ puts options_obj
15
+ next
16
+ end
17
+
18
+ hosts_file = HostsFile.new Hosts.hosts_file
19
+
20
+ if (args[1] != nil)
21
+ # rm alias
22
+ hosts_file.rm_alias(args[0], args[1])
23
+ else
24
+ # Remove all entries
25
+ # to 'dest' if alias
26
+ # is not defined
27
+ hosts_file.rm_dest_entries(args[0])
28
+ end
29
+
30
+ # Write changes to hosts file
31
+ hosts_file.flush()
32
+ }
33
+ @Rm
34
+ end
@@ -0,0 +1,15 @@
1
+ include Hosts::Lib::Core
2
+
3
+ module Hosts::Lib::Commands
4
+ options_obj = Slop::Options.new
5
+
6
+ Version = SubCommand.new(
7
+ 'version', # Name of the sub command
8
+ 'Print the version',
9
+ options_obj,
10
+ false
11
+ ) { |options, args|
12
+ puts Hosts::VERSION
13
+ }
14
+ @Version
15
+ end
@@ -0,0 +1,161 @@
1
+ require 'JSON'
2
+ require 'etc'
3
+
4
+ module Hosts::Lib::Core
5
+ class HostsFile
6
+ @hosts_file_path = nil
7
+
8
+ def initialize(file_path)
9
+ @entries = {}
10
+ @hosts_file_path = file_path
11
+ parse_file(file_path)
12
+ end
13
+
14
+ def parse_file(file_path)
15
+ newline_count = 0
16
+ comment_count = 0
17
+
18
+ File.readlines(file_path).each do |line|
19
+ # Add comments to @entries, to preserve them
20
+ if (/^[\s\t]*?#/ =~ line)
21
+ # Add comment to entries, minus the newline
22
+ @entries["__comment__#{comment_count}"] = { "comment" => line[0..-2] }
23
+ comment_count += 1
24
+ next
25
+ end
26
+
27
+ # Add empty lines to @entries, to preserve them
28
+ if (/^[\s\t]*?$/ =~ line)
29
+ @entries["__newline__#{newline_count}"] = { "newline" => "newline" }
30
+ newline_count += 1
31
+ next
32
+ end
33
+
34
+ # Remove comment, if there is one
35
+ line_and_comment = line.split("#")
36
+ line = line_and_comment[0]
37
+ comment = line_and_comment[1]
38
+
39
+ # Remove newline from comment
40
+ comment = comment[0..-2] if (comment != nil)
41
+
42
+ parts = line.split(/[\s\t]+/)
43
+
44
+ dest = parts[0]
45
+ hostnames = parts[1..-1]
46
+
47
+ # Remove last item if empty
48
+ hostnames.pop if (hostnames.length == 0)
49
+
50
+ hostnames = [hostnames] if (!hostnames.is_a?(Array))
51
+
52
+ if (hostnames == nil)
53
+ fail InvalidHostsFileException.new "Missing hostsname from entry declaration \n #{line}\n"
54
+ end
55
+ if (dest == nil)
56
+ fail InvalidHostsFileException.new "Missing destination from entry declaration \n #{line}\n"
57
+ end
58
+
59
+ add_entry(dest, hostnames, comment)
60
+ end
61
+ end
62
+
63
+ # Return false if the hostname
64
+ # was not an alias for 'dest'
65
+ def rm_alias(dest, hostname)
66
+ return false if (!@entries.has_key?(dest))
67
+
68
+ # remove hostname from dest, and return
69
+ # bool to indicate if it existed in the
70
+ # first place
71
+ was_deleted = @entries[dest]["hostnames"].delete(hostname) != nil;
72
+
73
+ # remove dest from @entries
74
+ # if it is now empty
75
+ if (@entries[dest]["hostnames"].length == 0)
76
+ @entries.delete(dest)
77
+ end
78
+
79
+ return was_deleted
80
+ end
81
+
82
+ def rm_dest_entries(dest)
83
+ if (@entries.has_key?(dest))
84
+ @entries.delete(dest)
85
+ end
86
+ end
87
+
88
+ # Add an entry.
89
+ # Expects to strings
90
+ def add_entry(dest, hostnames, comment = nil)
91
+ comment = "" if comment == nil
92
+
93
+ hostnames = [hostnames] if (!hostnames.is_a?(Array))
94
+
95
+ if (@entries.has_key?(dest))
96
+ # Add hostnames to entries, except duplicates, dont add them
97
+ @entries[dest]["hostnames"] = @entries[dest]["hostnames"] | hostnames
98
+ else
99
+ @entries[dest] = {"hostnames" => hostnames, "comment" => comment}
100
+ end
101
+ end
102
+
103
+ def get_all_entries()
104
+ _entries = {}
105
+ @entries.each do |dest, obj|
106
+ next if (!obj.has_key?("hostnames"))
107
+ _entries[dest] = obj["hostnames"]
108
+ end
109
+ return _entries
110
+ end
111
+
112
+ # Flush changes made to
113
+ # hosts file
114
+ def flush()
115
+ new_hosts_file_content = ''
116
+ longest_dest_name = 0
117
+
118
+ @entries.each do |dest, obj|
119
+ next unless (obj.has_key?("hostnames"))
120
+ if (dest.length > longest_dest_name)
121
+ longest_dest_name = dest.length
122
+ end
123
+ end
124
+
125
+ longest_dest_name += 1
126
+
127
+ @entries.each do |dest, obj|
128
+ if (obj.has_key?('comment') && !obj.has_key?('hostnames'))
129
+ new_hosts_file_content << obj['comment'] << "\n"
130
+ elsif (obj.has_key?('newline'))
131
+ new_hosts_file_content << "\n"
132
+ else
133
+ new_hosts_file_content << ("%-#{longest_dest_name}.#{longest_dest_name}s" % dest)
134
+ new_hosts_file_content << (obj['hostnames'] * ' ')
135
+
136
+ if (obj['comment'].length > 0)
137
+ comment = obj['comment']
138
+ # If it for some reason is not formated
139
+ # as a comment
140
+ unless (/^[\s\t]*?#/ =~ comment)
141
+ comment = '#' + comment
142
+ end
143
+ new_hosts_file_content += ("\s" + comment)
144
+ end
145
+
146
+ new_hosts_file_content << "\n"
147
+ end
148
+ end
149
+
150
+ puts
151
+ puts "new content of hosts file:"
152
+ puts new_hosts_file_content
153
+ puts
154
+
155
+ File.open(@hosts_file_path, "w+").write(new_hosts_file_content)
156
+ end
157
+ end
158
+
159
+ class InvalidHostsFileException < Exception
160
+ end
161
+ end
@@ -0,0 +1,61 @@
1
+ module Hosts::Lib::Core
2
+ class SubCommand
3
+ attr_reader :name
4
+ attr_reader :description
5
+ attr_reader :options
6
+
7
+ # If true, print help message on empty args
8
+ attr_reader :assume_help
9
+
10
+ def initialize(name, description, options, assume_help = true, &block)
11
+ @name = name
12
+ @description = description
13
+ @options = options
14
+ @block = block
15
+ @assume_help = assume_help
16
+ end
17
+
18
+ def run(args)
19
+ begin
20
+ # If no option spesified, assume --help
21
+ # The underscore is a hack, see rescue block
22
+ if (assume_help)
23
+ fail Slop::UnknownOption.new "Unknown option --help", "--help" if (args.length == 0)
24
+ end
25
+
26
+ @options.parse(args); # Dryrun to check for argument errors
27
+ @block.call(@options, args)
28
+ rescue Slop::UnknownOption => e
29
+ # Hack to get around the lack of e.getUnknownOption()
30
+ # TODO Fix once avaiable
31
+ if (e.flag == '--help')
32
+ print_help_message
33
+ else
34
+ puts "#{e.message}. Try 'hosts #{@name} help'"
35
+ end
36
+ end
37
+ end
38
+
39
+ def self.is_flag(str)
40
+ return str.start_with?("--") || (str.start_with?("-") && str.length == 2)
41
+ end
42
+
43
+ def print_help_message
44
+ puts 'hosts ' + @name
45
+ if (@description != '')
46
+ puts "\tDescription:"
47
+ puts "\t" + @description
48
+ end
49
+ if @options.options.length > 0
50
+ puts
51
+ puts "\tArguments:"
52
+ @options.each do |a|
53
+ print "\t" + '%-16.16s' % (a.flags * ', ')
54
+ print "\t"
55
+ print a.desc + "\n"
56
+ end
57
+ end
58
+ puts
59
+ end
60
+ end
61
+ end
@@ -0,0 +1,20 @@
1
+ require 'slop'
2
+
3
+ module Hosts
4
+ LIB_PATH = File.dirname(File.dirname(File.expand_path("../", __FILE__)))
5
+ end
6
+
7
+ module Hosts::Lib end
8
+
9
+ module Hosts::Lib::Core
10
+ autoload :HostsFile, File.dirname(__FILE__) + "/Core/HostsFile.rb"
11
+ autoload :SubCommand, File.dirname(__FILE__) + "/Core/SubCommand.rb"
12
+ end
13
+
14
+ module Hosts::Lib::Commands
15
+ autoload :Add, File.dirname(__FILE__) + "/Commands/Add.rb"
16
+ autoload :Rm, File.dirname(__FILE__) + "/Commands/Rm.rb"
17
+ autoload :List, File.dirname(__FILE__) + "/Commands/List.rb"
18
+ autoload :Version, File.dirname(__FILE__) + "/Commands/Version.rb"
19
+ autoload :Help, File.dirname(__FILE__) + "/Commands/Help.rb"
20
+ end
data/lib/hosts.rb ADDED
@@ -0,0 +1,37 @@
1
+ require_relative 'Hosts/Lib/autoload.rb'
2
+
3
+ module Hosts
4
+ VERSION = "0.1.0"
5
+
6
+ def self.main
7
+ @sub_commands = {}
8
+ @sub_commands['add'] = Hosts::Lib::Commands::Add
9
+ @sub_commands['help'] = Hosts::Lib::Commands::Help
10
+ @sub_commands['list'] = Hosts::Lib::Commands::List
11
+ @sub_commands['rm'] = Hosts::Lib::Commands::Rm
12
+ @sub_commands['version'] = Hosts::Lib::Commands::Version
13
+
14
+ if ARGV[0] == nil
15
+ Hosts::Lib::Commands::Help.run([]);
16
+ elsif @sub_commands[ARGV[0]].nil?
17
+ puts "'#{ARGV[0]}' is not a sub command. See 'hosts help'"
18
+ else
19
+ sub_cmd_obj = @sub_commands[ARGV[0].downcase]
20
+ ARGV.shift; # Remove subcommand from ARGV, rest is options
21
+ sub_cmd_obj.run(ARGV)
22
+ end
23
+ end
24
+
25
+ def self.dir
26
+ File.dirname(File.expand_path(__FILE__))
27
+ end
28
+
29
+ def self.hosts_file
30
+ return "/etc/hosts"
31
+ end
32
+
33
+ #attr_reader :sub_commands
34
+ def self.sub_commands
35
+ return @sub_commands
36
+ end
37
+ end
metadata ADDED
@@ -0,0 +1,54 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: hosts-cli
3
+ version: !ruby/object:Gem::Version
4
+ version: 0.1.0
5
+ platform: ruby
6
+ authors:
7
+ - Sigurd Berg Svela
8
+ autorequire:
9
+ bindir: bin
10
+ cert_chain: []
11
+ date: 2015-05-20 00:00:00.000000000 Z
12
+ dependencies: []
13
+ description: An easy CLI to edit the hosts file on unix systems
14
+ email: sigurdbergsvela@gmail.com
15
+ executables:
16
+ - hosts
17
+ extensions: []
18
+ extra_rdoc_files: []
19
+ files:
20
+ - lib/Hosts/Lib/Commands/Add.rb
21
+ - lib/Hosts/Lib/Commands/Help.rb
22
+ - lib/Hosts/Lib/Commands/List.rb
23
+ - lib/Hosts/Lib/Commands/Rm.rb
24
+ - lib/Hosts/Lib/Commands/Version.rb
25
+ - lib/Hosts/Lib/Core/HostsFile.rb
26
+ - lib/Hosts/Lib/Core/SubCommand.rb
27
+ - lib/Hosts/Lib/autoload.rb
28
+ - lib/hosts.rb
29
+ - bin/hosts
30
+ homepage: https://github.com/sigurdsvela/hosts
31
+ licenses:
32
+ - licenses
33
+ metadata: {}
34
+ post_install_message:
35
+ rdoc_options: []
36
+ require_paths:
37
+ - lib
38
+ required_ruby_version: !ruby/object:Gem::Requirement
39
+ requirements:
40
+ - - '>='
41
+ - !ruby/object:Gem::Version
42
+ version: 2.0.0
43
+ required_rubygems_version: !ruby/object:Gem::Requirement
44
+ requirements:
45
+ - - '>='
46
+ - !ruby/object:Gem::Version
47
+ version: '0'
48
+ requirements: []
49
+ rubyforge_project:
50
+ rubygems_version: 2.0.14
51
+ signing_key:
52
+ specification_version: 4
53
+ summary: Edit host file on unix system
54
+ test_files: []