ssh_bookmarker 0.0.1

Sign up to get free protection for your applications and to get access to all the features.
data/.gitignore ADDED
@@ -0,0 +1,17 @@
1
+ *.gem
2
+ *.rbc
3
+ .bundle
4
+ .config
5
+ .yardoc
6
+ Gemfile.lock
7
+ InstalledFiles
8
+ _yardoc
9
+ coverage
10
+ doc/
11
+ lib/bundler/man
12
+ pkg
13
+ rdoc
14
+ spec/reports
15
+ test/tmp
16
+ test/version_tmp
17
+ tmp
data/Gemfile ADDED
@@ -0,0 +1,4 @@
1
+ source 'https://rubygems.org'
2
+
3
+ # Specify your gem's dependencies in ssh_bookmarker.gemspec
4
+ gemspec
data/LICENSE.txt ADDED
@@ -0,0 +1,22 @@
1
+ Copyright (c) 2013 Andreas Fuchs
2
+
3
+ MIT License
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining
6
+ a copy of this software and associated documentation files (the
7
+ "Software"), to deal in the Software without restriction, including
8
+ without limitation the rights to use, copy, modify, merge, publish,
9
+ distribute, sublicense, and/or sell copies of the Software, and to
10
+ permit persons to whom the Software is furnished to do so, subject to
11
+ the following conditions:
12
+
13
+ The above copyright notice and this permission notice shall be
14
+ included in all copies or substantial portions of the Software.
15
+
16
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
17
+ EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
18
+ MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
19
+ NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
20
+ LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
21
+ OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
22
+ WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
data/README.md ADDED
@@ -0,0 +1,29 @@
1
+ # Automatically create OS X bookmark files (.webloc) from your SSH config
2
+
3
+ This set of scripts allows you to automatically create bookmarks for
4
+ all hosts that your SSH knows about. The really cool part is that it
5
+ also includes a LaunchAgent script that re-runs this every time your
6
+ SSH config changes. Include the output dir in your LaunchBar /
7
+ QuickSilver / Alfred config, and you can SSH into hosts without even
8
+ opening Terminal (to type SSH)!
9
+
10
+ ## Installation
11
+
12
+ You have to install it under the system ruby, so run:
13
+
14
+ $ sudo env RBENV_VERSION=system RVM_VERSION=system gem install ssh_bookmarker
15
+
16
+ ## Usage
17
+
18
+ You can either use `create-ssh-bookmarks` as a one-off script to
19
+ generate SSH bookmarks in a specific directory, or, if you have found
20
+ a set of command line args that works for you, use those same args
21
+ with `generate-ssh-bookmark-launchagent`.
22
+
23
+ ## Contributing
24
+
25
+ 1. Fork it
26
+ 2. Create your feature branch (`git checkout -b my-new-feature`)
27
+ 3. Commit your changes (`git commit -am 'Add some feature'`)
28
+ 4. Push to the branch (`git push origin my-new-feature`)
29
+ 5. Create new Pull Request
data/Rakefile ADDED
@@ -0,0 +1 @@
1
+ require "bundler/gem_tasks"
@@ -0,0 +1,8 @@
1
+ #!/usr/bin/env ruby
2
+
3
+ require 'rubygems'
4
+ require 'ssh_bookmarker'
5
+
6
+ cli = SSHBookmarker::CLI.new
7
+ cli.parse_options
8
+ cli.run
@@ -0,0 +1,84 @@
1
+ #!/usr/bin/env ruby
2
+
3
+ require 'rubygems'
4
+ require 'optparse'
5
+ require 'ssh_bookmarker'
6
+
7
+ class LaunchAgentCreator
8
+ def run(args)
9
+ cli = SSHBookmarker::CLI.new
10
+ cli.banner = <<-USAGE
11
+ Usage: #{$0} [options] output_dir
12
+
13
+ This script writes a LaunchAgent configuration file that will run
14
+ create-ssh-bookmarks with all the options you pass it, whenever any of
15
+ the SSH known_hosts or config files changes.
16
+
17
+ When create-ssh-bookmarks is run, the resulting files will be written
18
+ to output_dir.
19
+ USAGE
20
+ cli.parse_options(args.dup)
21
+
22
+ sanity_checks
23
+
24
+ filename = File.expand_path("~/Library/LaunchAgents/net.boinkor.ssh-bookmarker.plist")
25
+ File.open(filename, 'w') do |f|
26
+ f.write <<-PLIST
27
+ <?xml version="1.0" encoding="UTF-8"?>
28
+ <!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
29
+ <plist version="1.0">
30
+ <dict>
31
+ <key>Label</key>
32
+ <string>net.boinkor.ssh-bookmarker</string>
33
+ <key>ProgramArguments</key>
34
+ <array>#{program_arguments(args)}</array>
35
+ <key>QueueDirectories</key>
36
+ <array/>
37
+ <key>RunAtLoad</key>
38
+ <true/>
39
+ <key>StartCalendarInterval</key>
40
+ <dict>
41
+ <key>Hour</key>
42
+ <integer>0</integer>
43
+ <key>Minute</key>
44
+ <integer>0</integer>
45
+ </dict>
46
+ <key>WatchPaths</key>
47
+ <array>#{watch_paths(cli)}</array>
48
+ </dict>
49
+ </plist>
50
+ PLIST
51
+ end
52
+ puts <<-STATUS
53
+ Wrote #{filename}
54
+
55
+ Now run:
56
+
57
+ launchctl unload #{filename}
58
+ launchctl load #{filename}
59
+ STATUS
60
+ end
61
+
62
+ def sanity_checks
63
+ if (ENV['RBENV_VERSION'] && ENV['RBENV_VERSION'] != 'system') ||
64
+ (ENV['RVM_VERSION'] && ENV['RVM_VERSION'] != 'system')
65
+ $stderr.puts "#{$0} must be run under the 'system' ruby, sorry."
66
+ exit(1)
67
+ end
68
+ end
69
+
70
+ def make_string_array(elements)
71
+ '<string>' + elements.join("</string>\n<string>") + '</string>'
72
+ end
73
+
74
+ def program_arguments(args)
75
+ script_path = File.expand_path('../create-ssh-bookmarks', __FILE__)
76
+ make_string_array([script_path] + args)
77
+ end
78
+
79
+ def watch_paths(cli)
80
+ make_string_array(cli.hosts_files + cli.config_files)
81
+ end
82
+ end
83
+
84
+ LaunchAgentCreator.new.run(ARGV)# if $0 == __FILE__
@@ -0,0 +1,125 @@
1
+ require "ssh_bookmarker/version"
2
+ require "ssh_bookmarker/cli"
3
+ require 'logger'
4
+ require 'fileutils'
5
+
6
+ module SSHBookmarker
7
+ class Parser
8
+ def initialize(locations_dir)
9
+ @locations_dir = locations_dir
10
+ end
11
+
12
+ def logger=(logger)
13
+ @logger = logger
14
+ end
15
+
16
+ def logger
17
+ @logger ||= begin
18
+ Logger.new(STDERR)
19
+ end
20
+ end
21
+
22
+ def protocol_override=(block)
23
+ @protocol_override = block
24
+ end
25
+
26
+ DEFAULT_CONFIG_FILES=['/etc/ssh/ssh_config', File.expand_path('~/.ssh/config')]
27
+ DEFAULT_KNOWN_HOSTS_FILES=['/etc/ssh/known_hosts', File.expand_path('~/.ssh/known_hosts')]
28
+
29
+ def process_files(ssh_config_files=DEFAULT_CONFIG_FILES, known_host_files=DEFAULT_KNOWN_HOSTS_FILES)
30
+ ssh_config_files.each do |path|
31
+ if File.exists?(path)
32
+ logger.info("Parsing SSH config file #{path}")
33
+ else
34
+ logger.info("Skipping missing SSH config file #{path}")
35
+ next
36
+ end
37
+ parse_ssh_config(path) do |hostname, url_scheme|
38
+ if @protocol_override
39
+ (@protocol_override.call(hostname, url_scheme) || [url_scheme]).each do |scheme|
40
+ make_webloc(hostname, nil, scheme)
41
+ end
42
+ else
43
+ make_webloc(hostname, nil, url_scheme)
44
+ end
45
+ end
46
+ end
47
+
48
+ known_host_files.each do |path|
49
+ if File.exists?(path)
50
+ logger.info("Parsing known_hosts file #{path}")
51
+ else
52
+ logger.info("Skipping missing known_hosts file #{path}")
53
+ next
54
+ end
55
+ parse_known_hosts_file(path) do |hostname, port|
56
+ make_webloc(hostname, port)
57
+ end
58
+ end
59
+ end
60
+
61
+ def parse_known_hosts_file(path)
62
+ File.open(path).each_line do |line|
63
+ line = line.split(' ')[0]
64
+ hostname = line.split(',').each do |hostname|
65
+ if ported_host_match = hostname.match(/\[(\S*[a-zA-Z]+\S*)\]:([0-9]+)/)
66
+ host = ported_host_match[1]
67
+ port = ported_host_match[2]
68
+ yield(host, port)
69
+ else
70
+ yield(hostname) unless hostname.match(/ /) || hostname.match(/^[\[]/) || hostname.match(/^[0-9\.]+$/) || hostname.match(/^[a-f0-9\:]+(%.*)?$/)
71
+ end
72
+ end
73
+ end
74
+ rescue Errno::ENOENT => e
75
+ puts "Can't open #{path}: #{e}" if $debug
76
+ end
77
+
78
+ def parse_ssh_config(path)
79
+ File.open(path).each do |line|
80
+ if line.match /^\s*Host\s+([^#]+)\s*(#.+)?$/i
81
+ host_spec = $1
82
+ url_schemes = extract_url_scheme($2)
83
+ hosts = host_spec.split(/\s+/)
84
+ logger.debug("Got hosts #{hosts.inspect}")
85
+ hosts.each do |host|
86
+ url_schemes.each do |url_scheme|
87
+ yield(host, nil, url_scheme) unless host.match /\*/
88
+ end
89
+ end
90
+ end
91
+ end
92
+ rescue Errno::ENOENT => e
93
+ end
94
+
95
+ def make_webloc(hostname, port, url_scheme=nil)
96
+ url_scheme ||= 'ssh'
97
+ logger.debug "Making host entry for #{url_scheme}://#{hostname}:#{port}"
98
+ loc_filename = File.join(@locations_dir, "#{hostname} (#{url_scheme}).webloc")
99
+ begin
100
+ File.open(loc_filename, 'w') do |file|
101
+ file.write <<-XML
102
+ <?xml version="1.0" encoding="UTF-8"?>
103
+ <!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
104
+ <plist version="1.0">
105
+ <dict>
106
+ <key>URL</key>
107
+ <string>#{url_scheme || 'ssh'}://#{hostname}#{port && ":#{port}"}</string>
108
+ </dict>
109
+ </plist>
110
+ XML
111
+ end
112
+ rescue Exception => e
113
+ logger.error "Can't write webloc file #{loc_filename} for host #{hostname}: #{e}"
114
+ end
115
+ end
116
+
117
+ def extract_url_scheme(scheme_comment)
118
+ if scheme_comment && scheme_comment =~ /^#:(.*)$/
119
+ $1.split(',')
120
+ else
121
+ ["ssh"]
122
+ end
123
+ end
124
+ end
125
+ end
@@ -0,0 +1,96 @@
1
+ require 'logger'
2
+ require 'optparse'
3
+
4
+ module SSHBookmarker
5
+ class CLI
6
+ attr_accessor :hosts_files
7
+ attr_accessor :config_files
8
+ attr_accessor :dir
9
+
10
+ def initialize
11
+ @hosts_files = SSHBookmarker::Parser::DEFAULT_KNOWN_HOSTS_FILES
12
+ @config_files = SSHBookmarker::Parser::DEFAULT_CONFIG_FILES
13
+
14
+ @mosh_positive_domain_patterns = []
15
+ @mosh_negative_domain_patterns = []
16
+
17
+ @debug_level = Logger::WARN
18
+ end
19
+
20
+ attr_writer :banner
21
+ def banner
22
+ @banner || <<-USAGE
23
+ Usage: #{$0} [options] output_dir
24
+
25
+ This script generates SSH (and, optionally, mosh) bookmarks in
26
+ output_dir.
27
+
28
+ (Note that patterns can be either substring matches or regexes, if wrapped in //)
29
+ USAGE
30
+ end
31
+
32
+ def parse_options(args=ARGV)
33
+ optparse = OptionParser.new do |opts|
34
+ opts.banner = banner
35
+ opts.on('-k', '--known_hosts=FILE', 'Add file to list of known hosts') do |file|
36
+ @hosts_files << file
37
+ end
38
+
39
+ opts.on('-c', '--ssh_config=FILE', 'Add file to list of ssh config files') do |file|
40
+ @config_files << file
41
+ end
42
+
43
+ opts.on('-m PATTERN', '--mosh=PATTERN', 'Emit a mosh bookmark for host names matching PATTERN') do |pattern|
44
+ @mosh_positive_domain_patterns << to_match_expr(pattern)
45
+ end
46
+
47
+ opts.on('-M PATTERN', '--prevent-mosh=PATTERN', 'Prevent emitting a mosh bookmark for host names matching PATTERN') do |pattern|
48
+ @mosh_negative_domain_patterns << to_match_expr(pattern)
49
+ end
50
+ opts.on('-v', '--verbose', 'More debug chunder') do
51
+ @debug_level -= 1
52
+ end
53
+ end
54
+ optparse.parse!(args)
55
+ if args.length != 1
56
+ $stderr.puts optparse
57
+ exit 1
58
+ end
59
+ @dir = args.first
60
+ self
61
+ end
62
+
63
+ def to_match_expr(str)
64
+ if str.match(%r{\A/(.*)/\z})
65
+ Regexp.new($1)
66
+ else
67
+ str
68
+ end
69
+ end
70
+
71
+ def parser
72
+ parser = SSHBookmarker::Parser.new(@dir)
73
+
74
+ logger = Logger.new(STDERR)
75
+ logger.level = @debug_level
76
+ parser.logger = logger
77
+
78
+ if @mosh_positive_domain_patterns.length > 0
79
+ parser.protocol_override = proc do |hostname, url_scheme|
80
+ if @mosh_positive_domain_patterns.find {|pattern| hostname.match(pattern)} &&
81
+ !@mosh_negative_domain_patterns.find {|pattern| hostname.match(pattern)}
82
+ ['mosh']
83
+ end
84
+ end
85
+ end
86
+
87
+ parser
88
+ end
89
+
90
+ def run
91
+ Dir[File.join(@dir, '*.webloc')].each {|f| File.unlink(f)}
92
+ FileUtils.mkdir_p(@dir)
93
+ parser.process_files(@config_files, @hosts_files)
94
+ end
95
+ end
96
+ end
@@ -0,0 +1,3 @@
1
+ module SSHBookmarker
2
+ VERSION = "0.0.1"
3
+ end
@@ -0,0 +1,23 @@
1
+ # coding: utf-8
2
+ lib = File.expand_path('../lib', __FILE__)
3
+ $LOAD_PATH.unshift(lib) unless $LOAD_PATH.include?(lib)
4
+ require 'ssh_bookmarker/version'
5
+
6
+ Gem::Specification.new do |spec|
7
+ spec.name = "ssh_bookmarker"
8
+ spec.version = SSHBookmarker::VERSION
9
+ spec.authors = ["Andreas Fuchs"]
10
+ spec.email = ["asf@boinkor.net"]
11
+ spec.description = %q{A tool that lets you automatically generate SSH bookmarks}
12
+ spec.summary = %q{This gem installs a script that lets you generate SSH bookmarks from the (non-wildcard) entries in your SSH config and known_hosts files. It supports Mosh, too!}
13
+ spec.homepage = ""
14
+ spec.license = "MIT"
15
+
16
+ spec.files = `git ls-files`.split($/)
17
+ spec.executables = spec.files.grep(%r{^bin/}) { |f| File.basename(f) }
18
+ spec.test_files = spec.files.grep(%r{^(test|spec|features)/})
19
+ spec.require_paths = ["lib"]
20
+
21
+ spec.add_development_dependency "bundler", "~> 1.3"
22
+ spec.add_development_dependency "rake"
23
+ end
metadata ADDED
@@ -0,0 +1,94 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: ssh_bookmarker
3
+ version: !ruby/object:Gem::Version
4
+ version: 0.0.1
5
+ prerelease:
6
+ platform: ruby
7
+ authors:
8
+ - Andreas Fuchs
9
+ autorequire:
10
+ bindir: bin
11
+ cert_chain: []
12
+ date: 2013-07-19 00:00:00.000000000 Z
13
+ dependencies:
14
+ - !ruby/object:Gem::Dependency
15
+ name: bundler
16
+ requirement: !ruby/object:Gem::Requirement
17
+ none: false
18
+ requirements:
19
+ - - ~>
20
+ - !ruby/object:Gem::Version
21
+ version: '1.3'
22
+ type: :development
23
+ prerelease: false
24
+ version_requirements: !ruby/object:Gem::Requirement
25
+ none: false
26
+ requirements:
27
+ - - ~>
28
+ - !ruby/object:Gem::Version
29
+ version: '1.3'
30
+ - !ruby/object:Gem::Dependency
31
+ name: rake
32
+ requirement: !ruby/object:Gem::Requirement
33
+ none: false
34
+ requirements:
35
+ - - ! '>='
36
+ - !ruby/object:Gem::Version
37
+ version: '0'
38
+ type: :development
39
+ prerelease: false
40
+ version_requirements: !ruby/object:Gem::Requirement
41
+ none: false
42
+ requirements:
43
+ - - ! '>='
44
+ - !ruby/object:Gem::Version
45
+ version: '0'
46
+ description: A tool that lets you automatically generate SSH bookmarks
47
+ email:
48
+ - asf@boinkor.net
49
+ executables:
50
+ - create-ssh-bookmarks
51
+ - generate-ssh-bookmark-launchagent
52
+ extensions: []
53
+ extra_rdoc_files: []
54
+ files:
55
+ - .gitignore
56
+ - Gemfile
57
+ - LICENSE.txt
58
+ - README.md
59
+ - Rakefile
60
+ - bin/create-ssh-bookmarks
61
+ - bin/generate-ssh-bookmark-launchagent
62
+ - lib/ssh_bookmarker.rb
63
+ - lib/ssh_bookmarker/cli.rb
64
+ - lib/ssh_bookmarker/version.rb
65
+ - ssh_bookmarker.gemspec
66
+ homepage: ''
67
+ licenses:
68
+ - MIT
69
+ post_install_message:
70
+ rdoc_options: []
71
+ require_paths:
72
+ - lib
73
+ required_ruby_version: !ruby/object:Gem::Requirement
74
+ none: false
75
+ requirements:
76
+ - - ! '>='
77
+ - !ruby/object:Gem::Version
78
+ version: '0'
79
+ required_rubygems_version: !ruby/object:Gem::Requirement
80
+ none: false
81
+ requirements:
82
+ - - ! '>='
83
+ - !ruby/object:Gem::Version
84
+ version: '0'
85
+ requirements: []
86
+ rubyforge_project:
87
+ rubygems_version: 1.8.23
88
+ signing_key:
89
+ specification_version: 3
90
+ summary: This gem installs a script that lets you generate SSH bookmarks from the
91
+ (non-wildcard) entries in your SSH config and known_hosts files. It supports Mosh,
92
+ too!
93
+ test_files: []
94
+ has_rdoc: