jorp 1.0.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.
- data/.gitignore +1 -0
- data/Gemfile +7 -0
- data/Gemfile.lock +19 -0
- data/README.md +4 -0
- data/bin/jorp +5 -0
- data/jorp.gemspec +14 -0
- data/lib/jorp.rb +69 -0
- data/lib/jorp/basic_adaptor.rb +23 -0
- data/lib/jorp/listener.rb +9 -0
- data/lib/jorp/remote_adaptor.rb +64 -0
- data/lib/jorp/sudo.rb +47 -0
- data/lib/jorp/sudo_adaptor.rb +47 -0
- metadata +73 -0
data/.gitignore
ADDED
@@ -0,0 +1 @@
|
|
1
|
+
.DS_Store
|
data/Gemfile
ADDED
data/Gemfile.lock
ADDED
@@ -0,0 +1,19 @@
|
|
1
|
+
GEM
|
2
|
+
remote: https://rubygems.org/
|
3
|
+
specs:
|
4
|
+
highline (1.6.15)
|
5
|
+
jruby-pageant (1.1.1)
|
6
|
+
listen (0.5.3)
|
7
|
+
net-scp (1.0.4)
|
8
|
+
net-ssh (>= 1.99.1)
|
9
|
+
net-ssh (2.6.0)
|
10
|
+
jruby-pageant (>= 1.1.1)
|
11
|
+
|
12
|
+
PLATFORMS
|
13
|
+
ruby
|
14
|
+
|
15
|
+
DEPENDENCIES
|
16
|
+
highline
|
17
|
+
listen
|
18
|
+
net-scp
|
19
|
+
net-ssh
|
data/README.md
ADDED
data/bin/jorp
ADDED
data/jorp.gemspec
ADDED
@@ -0,0 +1,14 @@
|
|
1
|
+
|
2
|
+
Gem::Specification.new do |s|
|
3
|
+
s.name = 'jorp'
|
4
|
+
s.version = '1.0.0'
|
5
|
+
s.date = '2012-10-16'
|
6
|
+
s.summary = 'A SSH wrapper for local text editors'
|
7
|
+
s.description = 'Jorp lets you edit remote files using local editors'
|
8
|
+
s.authors = [ 'Stewart Ulm' ]
|
9
|
+
s.email = 'stewart.ulm@gmail.com'
|
10
|
+
s.homepage = 'http://github.com/stewartspeak/jorp'
|
11
|
+
s.files = `git ls-files`.split("\n")
|
12
|
+
s.executables = [ 'jorp' ]
|
13
|
+
s.require_paths = [ 'lib' ]
|
14
|
+
end
|
data/lib/jorp.rb
ADDED
@@ -0,0 +1,69 @@
|
|
1
|
+
# encoding: utf-8
|
2
|
+
|
3
|
+
require 'bundler/setup'
|
4
|
+
require 'optparse'
|
5
|
+
require 'jorp/sudo_adaptor'
|
6
|
+
require 'jorp/basic_adaptor'
|
7
|
+
require 'jorp/remote_adaptor'
|
8
|
+
|
9
|
+
module Jorp
|
10
|
+
|
11
|
+
DEFAULT_OPTIONS = {
|
12
|
+
:username => (ENV['USER']),
|
13
|
+
:editor => (ENV['JORP_EDITOR'] || ENV['EDITOR'] || 'subl -w'),
|
14
|
+
:hostname => ENV['JORP_HOST'],
|
15
|
+
:sudo => false,
|
16
|
+
}
|
17
|
+
|
18
|
+
class App
|
19
|
+
|
20
|
+
def initialize(args, bin_path)
|
21
|
+
@original_args = args.clone
|
22
|
+
@bin_path = bin_path
|
23
|
+
process_args(args)
|
24
|
+
end
|
25
|
+
|
26
|
+
def process_args(args)
|
27
|
+
@options = DEFAULT_OPTIONS.clone
|
28
|
+
parser = OptionParser.new(args) do |opts|
|
29
|
+
opts.banner = 'jorp [options] [file]'
|
30
|
+
opts.program_name = 'Jorp'
|
31
|
+
opts.version = '0.1'
|
32
|
+
opts.on('-s', '--sudo') { @options[:sudo] = true }
|
33
|
+
opts.on('-e', '--editor [command]') {|e| @options[:editor] = e }
|
34
|
+
opts.on('-u', '--username [username]') {|u| @options[:username] = u }
|
35
|
+
opts.on('-h', '--host [hostname]') {|h| @options[:hostname] = h }
|
36
|
+
end
|
37
|
+
parser.load(File.expand_path('~/.jorp'))
|
38
|
+
parser.parse!
|
39
|
+
if ARGV.length != 1
|
40
|
+
puts parser
|
41
|
+
exit -1
|
42
|
+
end
|
43
|
+
@options[:path] = args[0]
|
44
|
+
end
|
45
|
+
|
46
|
+
def run
|
47
|
+
if @options[:hostname].nil?
|
48
|
+
if @options[:sudo]
|
49
|
+
@adaptor = SudoAdaptor.new(@options[:path])
|
50
|
+
else
|
51
|
+
@adaptor = BasicAdaptor.new(@options[:path])
|
52
|
+
end
|
53
|
+
else
|
54
|
+
puts "Using remote host: \"#{@options[:hostname]}\""
|
55
|
+
if @options[:sudo]
|
56
|
+
@adaptor = RemoteAdaptor.new(@options[:hostname], @options[:path], @options[:username])
|
57
|
+
else
|
58
|
+
@adaptor = RemoteAdaptor.new(@options[:hostname], @options[:path], @options[:username])
|
59
|
+
end
|
60
|
+
end
|
61
|
+
@adaptor.connect
|
62
|
+
system("#{@options[:editor]} \"#{@adaptor.proxy_path}\"")
|
63
|
+
@adaptor.disconnect
|
64
|
+
end
|
65
|
+
|
66
|
+
end
|
67
|
+
|
68
|
+
end
|
69
|
+
|
@@ -0,0 +1,64 @@
|
|
1
|
+
# encoding: utf-8
|
2
|
+
|
3
|
+
require 'tmpdir'
|
4
|
+
require 'pty'
|
5
|
+
require 'expect'
|
6
|
+
require 'listen'
|
7
|
+
require 'net/ssh'
|
8
|
+
require 'net/scp'
|
9
|
+
|
10
|
+
module Jorp
|
11
|
+
|
12
|
+
class RemoteAdaptor
|
13
|
+
|
14
|
+
def initialize(hostname, path, username)
|
15
|
+
@hostname = hostname
|
16
|
+
@path = path
|
17
|
+
@username = username
|
18
|
+
@proxy_directory = Dir.mktmpdir('jorp')
|
19
|
+
@proxy_path = File.join(@proxy_directory, File.basename(@path))
|
20
|
+
end
|
21
|
+
|
22
|
+
def upload(connection)
|
23
|
+
begin
|
24
|
+
copier = Net::SCP.new(connection)
|
25
|
+
copier.upload!(@proxy_path, @path)
|
26
|
+
rescue Exception => e
|
27
|
+
puts "ERROR: " + e
|
28
|
+
end
|
29
|
+
end
|
30
|
+
|
31
|
+
def download(connection)
|
32
|
+
begin
|
33
|
+
copier = Net::SCP.new(connection)
|
34
|
+
copier.download!(@path, @proxy_path)
|
35
|
+
rescue Exception => e
|
36
|
+
puts "ERROR: " + e
|
37
|
+
end
|
38
|
+
end
|
39
|
+
|
40
|
+
def connect
|
41
|
+
connection = Net::SSH.start(@hostname, @username)
|
42
|
+
download(connection)
|
43
|
+
Thread.new do
|
44
|
+
begin
|
45
|
+
Listen.to(@proxy_directory, :filter => /^#{Regexp.escape(File.basename(@proxy_path))}$/) do
|
46
|
+
upload(connection)
|
47
|
+
end
|
48
|
+
rescue Exception => e
|
49
|
+
puts "An error occurred: " + e.inspect
|
50
|
+
end
|
51
|
+
end
|
52
|
+
end
|
53
|
+
|
54
|
+
def disconnect
|
55
|
+
FileUtils.remove_entry_secure(@proxy_directory)
|
56
|
+
end
|
57
|
+
|
58
|
+
def proxy_path
|
59
|
+
@proxy_path
|
60
|
+
end
|
61
|
+
|
62
|
+
end
|
63
|
+
|
64
|
+
end
|
data/lib/jorp/sudo.rb
ADDED
@@ -0,0 +1,47 @@
|
|
1
|
+
# encoding: utf-8
|
2
|
+
|
3
|
+
module Jorp
|
4
|
+
|
5
|
+
class Sudo
|
6
|
+
|
7
|
+
def initialize()
|
8
|
+
end
|
9
|
+
|
10
|
+
def prompt
|
11
|
+
password = nil
|
12
|
+
begin
|
13
|
+
PTY.spawn("sudo -k -p ENTER_PASSWORD whoami") do |input, output, pid|
|
14
|
+
loop do
|
15
|
+
response = input.expect(/^ENTER_PASSWORD/)
|
16
|
+
if response.nil? || response.length == 0
|
17
|
+
raise IOError.new
|
18
|
+
end
|
19
|
+
output.puts(password = HighLine.ask("Enter password: ") {|q| q.echo = false })
|
20
|
+
input.expect(/^(Sorry, try again|root$)/) do |matches|
|
21
|
+
if (matches[1] =~ /^Sorry, try again/)
|
22
|
+
password = nil
|
23
|
+
puts("Sorry, try again.")
|
24
|
+
end
|
25
|
+
end
|
26
|
+
break unless password.nil?
|
27
|
+
end
|
28
|
+
end
|
29
|
+
rescue
|
30
|
+
@password = nil
|
31
|
+
end
|
32
|
+
@password = password
|
33
|
+
end
|
34
|
+
|
35
|
+
def exec(command)
|
36
|
+
PTY.spawn("sudo -k -p ENTER_PASSWORD #{command}") do |input, output, pid|
|
37
|
+
input.expect(/^ENTER_PASSWORD/)
|
38
|
+
output.puts(@password)
|
39
|
+
while (response = input.gets)
|
40
|
+
# no-op
|
41
|
+
end
|
42
|
+
end
|
43
|
+
end
|
44
|
+
|
45
|
+
end
|
46
|
+
|
47
|
+
end
|
@@ -0,0 +1,47 @@
|
|
1
|
+
# encoding: utf-8
|
2
|
+
|
3
|
+
require 'tmpdir'
|
4
|
+
require 'pty'
|
5
|
+
require 'expect'
|
6
|
+
require 'highline/import'
|
7
|
+
require 'listen'
|
8
|
+
require 'jorp/sudo'
|
9
|
+
|
10
|
+
module Jorp
|
11
|
+
|
12
|
+
class SudoAdaptor
|
13
|
+
|
14
|
+
def initialize(path)
|
15
|
+
@source_path = path
|
16
|
+
@proxy_directory = Dir.mktmpdir('jorp')
|
17
|
+
@proxy_path = File.join(@proxy_directory, File.basename(@source_path))
|
18
|
+
FileUtils.touch(@proxy_path)
|
19
|
+
end
|
20
|
+
|
21
|
+
def connect
|
22
|
+
sudo = Sudo.new
|
23
|
+
if sudo.prompt
|
24
|
+
sudo.exec("cp \"#{@source_path}\" \"#{@proxy_path}\"")
|
25
|
+
Thread.new do
|
26
|
+
begin
|
27
|
+
Listen.to(@proxy_directory, :filter => /^#{Regexp.escape(File.basename(@proxy_path))}$/) do
|
28
|
+
sudo.exec("cp -p \"#{proxy_path}\" \"#{@source_path}\"")
|
29
|
+
end
|
30
|
+
rescue Exception => e
|
31
|
+
# log this error
|
32
|
+
end
|
33
|
+
end
|
34
|
+
end
|
35
|
+
end
|
36
|
+
|
37
|
+
def disconnect
|
38
|
+
FileUtils.remove_entry_secure(@proxy_directory)
|
39
|
+
end
|
40
|
+
|
41
|
+
def proxy_path
|
42
|
+
@proxy_path
|
43
|
+
end
|
44
|
+
|
45
|
+
end
|
46
|
+
|
47
|
+
end
|
metadata
ADDED
@@ -0,0 +1,73 @@
|
|
1
|
+
--- !ruby/object:Gem::Specification
|
2
|
+
name: jorp
|
3
|
+
version: !ruby/object:Gem::Version
|
4
|
+
prerelease: false
|
5
|
+
segments:
|
6
|
+
- 1
|
7
|
+
- 0
|
8
|
+
- 0
|
9
|
+
version: 1.0.0
|
10
|
+
platform: ruby
|
11
|
+
authors:
|
12
|
+
- Stewart Ulm
|
13
|
+
autorequire:
|
14
|
+
bindir: bin
|
15
|
+
cert_chain: []
|
16
|
+
|
17
|
+
date: 2012-10-16 00:00:00 -04:00
|
18
|
+
default_executable:
|
19
|
+
dependencies: []
|
20
|
+
|
21
|
+
description: Jorp lets you edit remote files using local editors
|
22
|
+
email: stewart.ulm@gmail.com
|
23
|
+
executables:
|
24
|
+
- jorp
|
25
|
+
extensions: []
|
26
|
+
|
27
|
+
extra_rdoc_files: []
|
28
|
+
|
29
|
+
files:
|
30
|
+
- .gitignore
|
31
|
+
- Gemfile
|
32
|
+
- Gemfile.lock
|
33
|
+
- README.md
|
34
|
+
- bin/jorp
|
35
|
+
- jorp.gemspec
|
36
|
+
- lib/jorp.rb
|
37
|
+
- lib/jorp/basic_adaptor.rb
|
38
|
+
- lib/jorp/listener.rb
|
39
|
+
- lib/jorp/remote_adaptor.rb
|
40
|
+
- lib/jorp/sudo.rb
|
41
|
+
- lib/jorp/sudo_adaptor.rb
|
42
|
+
has_rdoc: true
|
43
|
+
homepage: http://github.com/stewartspeak/jorp
|
44
|
+
licenses: []
|
45
|
+
|
46
|
+
post_install_message:
|
47
|
+
rdoc_options: []
|
48
|
+
|
49
|
+
require_paths:
|
50
|
+
- lib
|
51
|
+
required_ruby_version: !ruby/object:Gem::Requirement
|
52
|
+
requirements:
|
53
|
+
- - ">="
|
54
|
+
- !ruby/object:Gem::Version
|
55
|
+
segments:
|
56
|
+
- 0
|
57
|
+
version: "0"
|
58
|
+
required_rubygems_version: !ruby/object:Gem::Requirement
|
59
|
+
requirements:
|
60
|
+
- - ">="
|
61
|
+
- !ruby/object:Gem::Version
|
62
|
+
segments:
|
63
|
+
- 0
|
64
|
+
version: "0"
|
65
|
+
requirements: []
|
66
|
+
|
67
|
+
rubyforge_project:
|
68
|
+
rubygems_version: 1.3.6
|
69
|
+
signing_key:
|
70
|
+
specification_version: 3
|
71
|
+
summary: A SSH wrapper for local text editors
|
72
|
+
test_files: []
|
73
|
+
|