hosts-cli 0.1.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.
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: []