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 +7 -0
- data/bin/hosts +10 -0
- data/lib/Hosts/Lib/Commands/Add.rb +28 -0
- data/lib/Hosts/Lib/Commands/Help.rb +17 -0
- data/lib/Hosts/Lib/Commands/List.rb +32 -0
- data/lib/Hosts/Lib/Commands/Rm.rb +34 -0
- data/lib/Hosts/Lib/Commands/Version.rb +15 -0
- data/lib/Hosts/Lib/Core/HostsFile.rb +161 -0
- data/lib/Hosts/Lib/Core/SubCommand.rb +61 -0
- data/lib/Hosts/Lib/autoload.rb +20 -0
- data/lib/hosts.rb +37 -0
- metadata +54 -0
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,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: []
|