rhosts 0.0.1

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: 044fbb1e205d8759c29fa0381afa740ad7352d99
4
+ data.tar.gz: 2154e8b6d3f7a40365cd381321cf6cc4685e90fc
5
+ SHA512:
6
+ metadata.gz: b99163fd4aa43d5dd534844858092a7cee61825abff17c87a258014508e247c1b7fec709333ddd5757f645c18269b205641ec7fb695bd650ba37ff76a573ec5d
7
+ data.tar.gz: 46b2de6da8141d881deab5e82cff345026a8e3ab8ad0c97e1f5a43872f811941efac12937505cb11b0ab0ec08a1813b4d2c82057b9dd6a7c1d13a156d4e5edce
data/License.txt ADDED
@@ -0,0 +1,20 @@
1
+ Copyright 2013 Takeshi Takizawa
2
+
3
+ Permission is hereby granted, free of charge, to any person obtaining
4
+ a copy of this software and associated documentation files (the
5
+ "Software"), to deal in the Software without restriction, including
6
+ without limitation the rights to use, copy, modify, merge, publish,
7
+ distribute, sublicense, and/or sell copies of the Software, and to
8
+ permit persons to whom the Software is furnished to do so, subject to
9
+ the following conditions:
10
+
11
+ The above copyright notice and this permission notice shall be
12
+ included in all copies or substantial portions of the Software.
13
+
14
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
15
+ EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
16
+ MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
17
+ NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
18
+ LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
19
+ OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
20
+ WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
data/README.md ADDED
@@ -0,0 +1,97 @@
1
+ RHosts
2
+ ====
3
+
4
+ hosts file manager
5
+
6
+ # Description
7
+
8
+ rhosts is a command that facilitates the management of the host file.
9
+
10
+ # Usage
11
+ ## show all hosts
12
+ ```
13
+ $ rhosts
14
+ rhosts> all
15
+ ### actives
16
+ 127.0.0.1
17
+ localhost
18
+ dev-www.example.com
19
+
20
+ 127.0.0.2
21
+ stg-www.example.com
22
+
23
+ ### inactives
24
+ 127.0.0.1
25
+ stg-www.example.com
26
+
27
+ ```
28
+
29
+ ## show active hosts
30
+ ```
31
+ rhosts> actives
32
+ ### actives
33
+ 127.0.0.1
34
+ localhost
35
+ dev-www.example.com
36
+
37
+ 127.0.0.2
38
+ stg-www.example.com
39
+
40
+ ```
41
+
42
+ ## show inactive hosts
43
+ ```
44
+ rhosts> inactives
45
+ ### inactives
46
+ 127.0.0.1
47
+ stg-www.example.com
48
+
49
+ ```
50
+
51
+ ## map specific host
52
+ ```
53
+ $ rhosts
54
+ rhosts> actives
55
+ ### actives
56
+ 127.0.0.1
57
+ localhost
58
+ dev-www.example.com
59
+
60
+ 127.0.0.2
61
+ stg-www.example.com
62
+
63
+ rhosts> map "dev-www.example.co.jp" => "127.0.0.1"
64
+ rhosts> actives
65
+ ### actives
66
+ 127.0.0.1
67
+ localhost
68
+ dev-www.example.com
69
+ dev-www.example.co.jp
70
+
71
+ 127.0.0.2
72
+ stg-www.example.com
73
+
74
+ ```
75
+
76
+ ## unmap specific host
77
+ ```
78
+ $ rhosts
79
+ rhosts> actives
80
+ ### actives
81
+ 127.0.0.1
82
+ localhost
83
+ dev-www.example.com
84
+
85
+ 127.0.0.2
86
+ stg-www.example.com
87
+
88
+ rhosts> unmap "dev-www.example.com" => "127.0.0.1"
89
+ rhosts> actives
90
+ ### actives
91
+ 127.0.0.1
92
+ localhost
93
+
94
+ 127.0.0.2
95
+ stg-www.example.com
96
+
97
+ ```
data/bin/rhosts ADDED
@@ -0,0 +1,6 @@
1
+ #!/usr/bin/env ruby
2
+
3
+ lib_path = File.expand_path('../../lib', __FILE__)
4
+ $:.unshift(lib_path) unless $:.include?(lib_path)
5
+
6
+ require "rhosts/cli"
@@ -0,0 +1,41 @@
1
+ module RHosts
2
+ module Alias
3
+ def self.included(base)
4
+ base.extend ClassMethods
5
+ end
6
+
7
+ def alias_ips
8
+ self.class.alias_ips
9
+ end
10
+
11
+ def alias_ip(new_name, old_name)
12
+ self.class.alias_ips[new_name] = old_name
13
+ end
14
+
15
+ def alias_hosts
16
+ self.class.alias_hosts
17
+ end
18
+
19
+ def alias_host(new_name, old_name)
20
+ self.class.alias_hosts[new_name] = old_name
21
+ end
22
+
23
+ module ClassMethods
24
+ def alias_ips
25
+ @alias_ips ||= {}
26
+ end
27
+
28
+ def alias_ip(new_name, old_name)
29
+ alias_ips[new_name] = old_name
30
+ end
31
+
32
+ def alias_hosts
33
+ @alias_hosts ||= {}
34
+ end
35
+
36
+ def alias_host(new_name, old_name)
37
+ alias_hosts[new_name] = old_name
38
+ end
39
+ end
40
+ end
41
+ end
data/lib/rhosts/cli.rb ADDED
@@ -0,0 +1,8 @@
1
+ Signal.trap("INT") { puts; exit(1) }
2
+
3
+ require 'rhosts'
4
+
5
+ # TODO: Runnable not only console but also exec from file, string and so on.
6
+ require 'rhosts/commands/console'
7
+
8
+ RHosts::Console.start
@@ -0,0 +1,57 @@
1
+ require 'readline'
2
+ require 'rhosts/filer'
3
+ require 'rhosts/console/app'
4
+ require 'rhosts/rulable'
5
+ require 'rhosts/alias'
6
+
7
+ module RHosts
8
+ class Console
9
+ include RHosts::ConsoleMethods
10
+ include RHosts::Rulable
11
+ include RHosts::Alias
12
+
13
+ alias_host 'exp', 'www.example.com'
14
+ alias_ip 'localhost', '127.0.0.1'
15
+
16
+ class << self
17
+ def start
18
+ @console = new
19
+
20
+ load_default_rules
21
+ load_run_command
22
+
23
+ unless File.writable?(RHosts.config.hosts_file_path)
24
+ STDERR.puts "Hosts file is not writable. Please check permission"
25
+ exit 1
26
+ end
27
+
28
+ @console.start
29
+ end
30
+
31
+ private
32
+ def load_default_rules
33
+ default_rules = File.read(RHosts.root + '/rhosts/console/default_rules.rb')
34
+ @console.instance_eval(default_rules)
35
+ end
36
+
37
+ def load_run_command
38
+ rhostsrc = File.join(File.expand_path("~"), ".rhostsrc")
39
+ if File.exist?(rhostsrc)
40
+ puts "load: #{rhostsrc}"
41
+ @console.instance_eval(File.read(rhostsrc))
42
+ end
43
+ end
44
+ end
45
+
46
+ def initialize
47
+ @actives, @inactives = RHosts::Filer.load
48
+ end
49
+
50
+ def start
51
+ while command = Readline.readline('rhosts> ', true)
52
+ # call matched rule with captures
53
+ rules.each{ |rule, action| action.call($~.captures) if rule.match command.chomp }
54
+ end
55
+ end
56
+ end
57
+ end
@@ -0,0 +1,9 @@
1
+ module RHosts
2
+ class Configuration
3
+ attr_accessor :hosts_file_path, :backup_dir, :make_backup
4
+
5
+ def make_backup?
6
+ make_backup
7
+ end
8
+ end
9
+ end
@@ -0,0 +1,74 @@
1
+ require 'ipaddress'
2
+
3
+ module RHosts
4
+ module ConsoleMethods
5
+ def actives
6
+ @actives ||= Hash.new{ |h, k| h[k] = Set.new }
7
+ end
8
+
9
+ def inactives
10
+ @inactives ||= Hash.new{ |h, k| h[k] = Set.new }
11
+ end
12
+
13
+ def map(target)
14
+ process(target) do |host, ip|
15
+ unless inactives[ip].empty?
16
+ inactives[ip].delete_if{ |h| h == host }
17
+ inactives.delete(ip) if inactives[ip].empty?
18
+ end
19
+
20
+ actives[ip] << host
21
+ puts "map #{host} to #{ip}"
22
+ end
23
+ end
24
+
25
+ def unmap(target)
26
+ process(target) do |host, ip|
27
+ unless actives[ip].empty?
28
+ actives[ip].delete_if{ |h| h == host }
29
+ actives.delete(ip) if actives[ip].empty?
30
+ end
31
+
32
+ inactives[ip] << host
33
+ puts "unmap #{host} from #{ip}"
34
+ end
35
+ end
36
+
37
+ # print mappings
38
+ def display(title, mappings)
39
+ puts "### #{title}"
40
+ mappings.each do |ip, hosts|
41
+ puts ip
42
+ hosts.each{ |host| puts " #{host}" }
43
+ puts ''
44
+ end
45
+ end
46
+
47
+ private
48
+ def process(target, &block)
49
+ raise ArgumentsError.new('mapping target must be Hash') unless target.instance_of? Hash
50
+
51
+ # TODO
52
+ # before_actions.each{ |action| action.call }
53
+
54
+ target.each do |host, ip|
55
+ host = alias_hosts[host] || host
56
+ ip = alias_ips[ip] || ip
57
+
58
+ ip_without_zone_index = ip.split('%')[0]
59
+ unless IPAddress.valid?(ip_without_zone_index)
60
+ STDERR.puts "#{ip} is invalid IP Address!"
61
+ next
62
+ end
63
+
64
+ block.call(host, ip)
65
+ end
66
+
67
+ RHosts::Filer.backup if RHosts.config.make_backup?
68
+ RHosts::Filer.save(actives, inactives)
69
+
70
+ # TODO
71
+ # after_actions.each{ |action| action.call }
72
+ end
73
+ end
74
+ end
@@ -0,0 +1,46 @@
1
+ # print all mappings
2
+ rule /^(A|all)$/ do
3
+ display 'actives', actives
4
+ display 'inactives', inactives
5
+ end
6
+
7
+ # print only active mappings
8
+ rule /^(a|actives)$/ do
9
+ display 'actives', actives
10
+ end
11
+
12
+ # print only inactive mappings
13
+ rule /^(i|inactives)$/ do
14
+ display 'inactives', inactives
15
+ end
16
+
17
+ # add mapping
18
+ rule /^(m|map) +(.*?) +(.*?)$/ do |command, host, ip|
19
+ map host => ip
20
+ end
21
+
22
+ # add unmapping
23
+ rule /^(u|unmap) +(.*?) +(.*?)$/ do |command, host, ip|
24
+ unmap host => ip
25
+ end
26
+
27
+ # print command history
28
+ rule /^(hist|history)$/ do
29
+ puts Readline::HISTORY.to_a.join("\n")
30
+ end
31
+
32
+ # print registored rules
33
+ rule /^rules$/ do
34
+ puts rules.keys.join("\n")
35
+ end
36
+
37
+ # print help
38
+ rule /^(h|help)$/ do
39
+ # TODO: help message
40
+ #help
41
+ end
42
+
43
+ # quit rhosts
44
+ rule /^(q|quit|exit)$/ do
45
+ exit
46
+ end
@@ -0,0 +1,91 @@
1
+ require 'ipaddress'
2
+
3
+ module RHosts
4
+ module Filer
5
+ class << self
6
+ def load
7
+ actives = Hash.new{ |h, k| h[k] = Set.new }
8
+ inactives = Hash.new{ |h, k| h[k] = Set.new }
9
+
10
+ File.open(RHosts.config.hosts_file_path, 'r') do |file|
11
+ file.each do |line|
12
+ storage = Mapping.active?(line) ? actives : inactives
13
+
14
+ Mapping.parse(line) do |ip, hosts|
15
+ next if ip.nil? or hosts.empty?
16
+
17
+ # IPAddress gem can't parse IP with zone index
18
+ #
19
+ # for example
20
+ # fe80::1%lo0
21
+ ip_without_zone_index = ip.split('%')[0]
22
+ next unless IPAddress.valid?(ip_without_zone_index)
23
+
24
+ storage[ip] ||= []
25
+ storage[ip] += hosts
26
+ end
27
+ end
28
+ end
29
+
30
+ [actives, inactives]
31
+ end
32
+
33
+ def backup
34
+ bk_file_path = backup_file_path
35
+ hosts_file_path = RHosts.config.hosts_file_path
36
+
37
+ if File.writable?(RHosts.config.backup_dir)
38
+ FileUtils.cp(hosts_file_path, bk_file_path)
39
+ puts "backup: #{bk_file_path}"
40
+ else
41
+ STDERR.puts "backup file is not writable. #{bk_file_path}"
42
+ STDERR.puts 'So we will backup to tmp dir'
43
+ tmp = tmp_file_path
44
+ FileUtils.cp(hosts_file_path, tmp)
45
+ STDERR.puts "backup: #{tmp}"
46
+ end
47
+ end
48
+
49
+ def save(actives, inactives)
50
+ # TODO: reload hosts file if chnaged after load
51
+ hosts_file_path = RHosts.config.hosts_file_path
52
+ unless File.writable?(hosts_file_path)
53
+ STDERR.puts "Hosts file is not writable. Please check permission"
54
+ exit 1
55
+ end
56
+
57
+ File.open(RHosts.config.hosts_file_path, 'w') do |file|
58
+ actives.each{ |ip, hosts| file.write("#{ip} #{hosts.to_a.join(' ')}\n") }
59
+ inactives.each{ |ip, hosts| file.write("##{ip} #{hosts.to_a.join(' ')}\n") }
60
+ end
61
+ puts "save: #{hosts_file_path}"
62
+ end
63
+
64
+ private
65
+ def backup_file_path
66
+ hosts_file_path = RHosts.config.hosts_file_path
67
+ basename = File.basename(hosts_file_path)
68
+ File.join(RHosts.config.backup_dir, "#{basename}.#{Time.now.to_i}")
69
+ end
70
+
71
+ def tmp_file_path
72
+ hosts_file_path = RHosts.config.hosts_file_path
73
+ basename = File.basename(hosts_file_path)
74
+ File.join('/tmp', "#{basename}.#{Time.now.to_i}")
75
+ end
76
+ end
77
+
78
+ class Mapping
79
+ class << self
80
+ def active?(line)
81
+ line !~ /^#/
82
+ end
83
+
84
+ def parse(line, &block)
85
+ ip, *hosts = line.chomp.sub(/^#+\s*/, '').split(/\s+/)
86
+ block.call(ip, hosts)
87
+ end
88
+ end
89
+ end
90
+ end
91
+ end
@@ -0,0 +1,11 @@
1
+ module RHosts
2
+ module Rulable
3
+ def rules
4
+ @rules ||= {}
5
+ end
6
+
7
+ def rule(pattern, &block)
8
+ rules[pattern] = block
9
+ end
10
+ end
11
+ end
@@ -0,0 +1,5 @@
1
+ module RHosts # :nodoc:
2
+ module Version # :nodoc:
3
+ STRING = '0.0.1'
4
+ end
5
+ end
data/lib/rhosts.rb ADDED
@@ -0,0 +1,28 @@
1
+ require 'rubygems'
2
+ require 'bundler/setup'
3
+
4
+ lib_path = File.dirname(__FILE__)
5
+ $:.unshift(lib_path) unless $:.include?(lib_path)
6
+
7
+ require 'rhosts/configuration'
8
+
9
+ module RHosts
10
+ def self.root
11
+ @root ||= File.dirname(__FILE__)
12
+ end
13
+
14
+ def self.config
15
+ @config ||= RHosts::Configuration.new
16
+ end
17
+
18
+ def self.configure
19
+ yield config if block_given?
20
+ end
21
+ end
22
+
23
+ # default setting
24
+ RHosts.configure do |c|
25
+ c.hosts_file_path = '/etc/hosts'
26
+ c.backup_dir = '/etc'
27
+ c.make_backup = true
28
+ end
@@ -0,0 +1,22 @@
1
+ require 'spec_helper'
2
+ require 'rhosts/console/app'
3
+
4
+ describe 'ConsoleMethods' do
5
+ include RHosts::ConsoleMethods
6
+
7
+ describe '#map' do
8
+ before do
9
+ map 'example.com' => '127.0.0.1'
10
+ end
11
+
12
+ after do
13
+ @actives.clear
14
+ @inactives.clear
15
+ end
16
+
17
+ it 'map example.com to 127.0.0.1' do
18
+ expect(actives).to eq('127.0.0.1' => ['example.com'])
19
+ expect(inactives).to eq({ })
20
+ end
21
+ end
22
+ end
@@ -0,0 +1,19 @@
1
+ require File.expand_path('../../lib/rhosts', __FILE__)
2
+
3
+ # This file was generated by the `rspec --init` command. Conventionally, all
4
+ # specs live under a `spec` directory, which RSpec adds to the `$LOAD_PATH`.
5
+ # Require this file using `require "spec_helper"` to ensure that it is only
6
+ # loaded once.
7
+ #
8
+ # See http://rubydoc.info/gems/rspec-core/RSpec/Core/Configuration
9
+ RSpec.configure do |config|
10
+ config.treat_symbols_as_metadata_keys_with_true_values = true
11
+ config.run_all_when_everything_filtered = true
12
+ config.filter_run :focus
13
+
14
+ # Run specs in random order to surface order dependencies. If you find an
15
+ # order dependency and want to debug it, you can fix the order by providing
16
+ # the seed, which is printed after each run.
17
+ # --seed 1234
18
+ config.order = 'random'
19
+ end
metadata ADDED
@@ -0,0 +1,77 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: rhosts
3
+ version: !ruby/object:Gem::Version
4
+ version: 0.0.1
5
+ platform: ruby
6
+ authors:
7
+ - Takeshi Takizawa
8
+ autorequire:
9
+ bindir: bin
10
+ cert_chain: []
11
+ date: 2013-06-23 00:00:00.000000000 Z
12
+ dependencies:
13
+ - !ruby/object:Gem::Dependency
14
+ name: ipaddress
15
+ requirement: !ruby/object:Gem::Requirement
16
+ requirements:
17
+ - - ~>
18
+ - !ruby/object:Gem::Version
19
+ version: 0.8.0
20
+ type: :runtime
21
+ prerelease: false
22
+ version_requirements: !ruby/object:Gem::Requirement
23
+ requirements:
24
+ - - ~>
25
+ - !ruby/object:Gem::Version
26
+ version: 0.8.0
27
+ description: hosts file manager
28
+ email: TakiTake.create@gmail.com
29
+ executables:
30
+ - rhosts
31
+ extensions: []
32
+ extra_rdoc_files:
33
+ - README.md
34
+ files:
35
+ - lib/rhosts.rb
36
+ - lib/rhosts/alias.rb
37
+ - lib/rhosts/cli.rb
38
+ - lib/rhosts/commands/console.rb
39
+ - lib/rhosts/configuration.rb
40
+ - lib/rhosts/console/app.rb
41
+ - lib/rhosts/console/default_rules.rb
42
+ - lib/rhosts/filer.rb
43
+ - lib/rhosts/rulable.rb
44
+ - lib/rhosts/version.rb
45
+ - License.txt
46
+ - README.md
47
+ - spec/console/app_spec.rb
48
+ - spec/spec_helper.rb
49
+ - bin/rhosts
50
+ homepage: http://github.com/TakiTake/rhosts
51
+ licenses:
52
+ - MIT
53
+ metadata: {}
54
+ post_install_message:
55
+ rdoc_options:
56
+ - --charset=UTF-8
57
+ require_paths:
58
+ - lib
59
+ required_ruby_version: !ruby/object:Gem::Requirement
60
+ requirements:
61
+ - - '>='
62
+ - !ruby/object:Gem::Version
63
+ version: '0'
64
+ required_rubygems_version: !ruby/object:Gem::Requirement
65
+ requirements:
66
+ - - '>='
67
+ - !ruby/object:Gem::Version
68
+ version: '0'
69
+ requirements: []
70
+ rubyforge_project: rhosts
71
+ rubygems_version: 2.0.3
72
+ signing_key:
73
+ specification_version: 4
74
+ summary: rhosts-0.0.1
75
+ test_files:
76
+ - spec/console/app_spec.rb
77
+ - spec/spec_helper.rb