sshfsmount 0.1.0 → 0.1.2

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 CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA1:
3
- metadata.gz: 15c81068a30c8ed5a61b3fcc19d7a6503036762d
4
- data.tar.gz: '0943c0fbd855d60f5c349c29cba4fd209ab89e03'
3
+ metadata.gz: 0f9330ebd590ac3a49fb68f3166a18f1e8666ca5
4
+ data.tar.gz: 6ad40fe249ba8b6a82f365fae9518e9b351972d3
5
5
  SHA512:
6
- metadata.gz: fdc671ab26209081bd02081aba7515a56c7fecbc6ea6e4162cc5866678e9323abe8db71d0d208f7dc6c426e72c329632c7652a989d58f3157db31a5c0e644fc2
7
- data.tar.gz: a2a64b1d2500f7889fd46646f7e0e46c7a1c529a059fb8fcca7a456d987504766e5209c0d4c032ff169906c4615ea9ef9542a90aefb4d60922fcb038fbda03ec
6
+ metadata.gz: 31eac3dbd23722dbacb13dc2d15e0e5495870d758c0a87eaab7e2eadba5b382b83b336f248f6eb04afa5582120e55da270e217eb90193cc9ea15dcfb65c834a9
7
+ data.tar.gz: d42f434f5a1d99b9099b9e9ec6a97737c5cd83089381fe2ca40429d6ea6fa4678fea67e66c72b517463a6558da83444ffca9dfd5dc3ca3db86d8bafe0b8a00d2
data/README.md CHANGED
@@ -3,6 +3,7 @@
3
3
  [![Build Status](https://travis-ci.org/nomoon/sshfsmount.svg?branch=master)](https://travis-ci.org/nomoon/sshfsmount)
4
4
  [![Coverage Status](https://coveralls.io/repos/github/nomoon/sshfsmount/badge.svg?branch=master)](https://coveralls.io/github/nomoon/sshfsmount?branch=master)
5
5
  [![Dependency Status](https://gemnasium.com/badges/github.com/nomoon/sshfsmount.svg)](https://gemnasium.com/github.com/nomoon/sshfsmount)
6
+ [![Gem Version](https://badge.fury.io/rb/sshfsmount.svg)](https://badge.fury.io/rb/sshfsmount)
6
7
 
7
8
  A simple front-end CLI to SSHFS.
8
9
 
@@ -1,156 +1,8 @@
1
1
  #!/usr/bin/env ruby
2
2
  # frozen_string_literal: true
3
3
 
4
- require "gli"
5
- require "json"
6
- require "shellwords"
7
- require "fileutils"
8
-
9
4
  require "sshfsmount"
10
-
11
- #
12
- # Basic SSHFS flags
13
- #
14
- SSHFS_FLAGS = [
15
- "-o local",
16
- "-o workaround=nonodelaysrv",
17
- "-o transform_symlinks",
18
- "-o idmap=user",
19
- "-C",
20
- ].freeze
21
-
22
- #
23
- # Locate config file.
24
- #
25
- CONFIG_FILE = [
26
- File.join(Dir.home, ".sshfsmount.json"),
27
- File.join(Dir.home, ".config", "sshfsmount.json"),
28
- File.join(Dir.home, ".config", "sshfsmount", "sshfsmount.json"),
29
- ].select { |f| File.exist?(f) }.first.freeze
30
-
31
- #
32
- # Parse config file
33
- #
34
- CONFIG = (begin
35
- if CONFIG_FILE.nil?
36
- STDERR.puts "No config file found"
37
- {}
38
- else
39
- JSON.parse(File.read(CONFIG_FILE), symbolize_names: true)
40
- end
41
- rescue JSON::ParserError => e
42
- STDERR.puts "Parse error in config file `#{CONFIG_FILE}`: #{e}"
43
- {}
44
- end).freeze
45
-
46
- #
47
- # Create Mount-point Directory
48
- #
49
- def mkmountpoint(name)
50
- local = File.expand_path(name)
51
- if !Dir.exist?(local)
52
- STDERR.puts "Creating mount-point directory #{local}"
53
- FileUtils.mkdir_p(local)
54
- elsif !Dir.empty?(local)
55
- raise "Mount point #{local} already exists and is not empty"
56
- elsif VERBOSE
57
- STDERR.puts "Mount-point directory #{local} already exists and is empty"
58
- end
59
- local
60
- end
61
-
62
- #
63
- # Delete mount-point directory
64
- #
65
- def rmmountpoint(name)
66
- local = File.expand_path(name)
67
- if !Dir.exist?(local)
68
- STDERR.puts "Mount-point directory not found" if VERBOSE
69
- elsif !Dir.empty?(local)
70
- raise "Mount-point directory #{local} is not empty"
71
- else
72
- STDERR.puts "Deleting mount-point directory #{local}"
73
- FileUtils.rmdir(local)
74
- end
75
- local
76
- end
77
-
78
- #
79
- # Mount an SSHFS volume
80
- #
81
- def mount(mount_name, params)
82
- local = mkmountpoint(params[:local])
83
- volname = params[:volname] || mount_name
84
- p_remote = Shellwords.escape(params[:remote])
85
- p_local = Shellwords.escape(local)
86
- p_volname = Shellwords.escape(volname)
87
- port = (params[:port] || 22).to_i
88
- cmd = "/usr/local/bin/sshfs #{p_remote} #{p_local} " \
89
- "-o volname=\"#{p_volname}\" #{SSHFS_FLAGS.join(' ')} -p #{port}"
90
- pgrep = `pgrep -f \"#{cmd}\"`
91
- unless pgrep.empty?
92
- raise "SSHFS process for #{mount_name} running already (PID: #{pgrep.strip}, " \
93
- "Mount-point: #{p_local})"
94
- end
95
- puts "Mounting #{params[:remote]} to #{params[:local]} as \"#{volname}\""
96
- STDERR.puts "> #{cmd}" if VERBOSE
97
- system(cmd)
98
- end
99
-
100
- #
101
- # Unmount an SSHFS volume
102
- #
103
- def unmount(mount_name, params)
104
- local = File.expand_path(params[:local])
105
- p_local = Shellwords.escape(local)
106
- cmd = "diskutil unmount #{p_local}"
107
- pgrep = `pgrep -f \"#{p_local}\"`
108
- if pgrep.empty?
109
- raise "No SSHFS process found with the mount-point for #{mount_name} (#{p_local})"
110
- end
111
- puts "Unmounting #{local}"
112
- STDERR.puts "> #{cmd}" if VERBOSE
113
- system(cmd)
114
- rmmountpoint(local)
115
- end
116
-
117
- #
118
- # GLI command-line app definition
119
- #
120
- include GLI::App
121
-
122
- program_desc "A simple front-end CLI to SSHFS"
123
- version Sshfsmount::VERSION
124
-
125
- switch %i[u unmount], desc: "Unmount the volume", negatable: false
126
- switch %i[v verbose], desc: "Show verbose output", negatable: false
127
-
128
- desc "List active SSHFS processes"
129
- command :active do |c|
130
- c.action do
131
- system("pgrep -fl sshfs")
132
- end
133
- end
134
-
135
- #
136
- # Define commands from data-file
137
- #
138
- extant_commands = commands.keys
139
- CONFIG.reject { |name, _| extant_commands.include?(name) }.each do |mount_name, params|
140
- desc "mount #{params[:remote]} to #{params[:local]}"
141
- command mount_name do |c|
142
- c.switch %i[u unmount], desc: "Unmount the volume", negatable: false
143
- c.switch %i[v verbose], desc: "Show verbose output", negatable: false
144
- c.action do |global_options, cmd_options|
145
- VERBOSE = global_options[:v] || cmd_options[:v]
146
- if global_options[:u] || cmd_options[:u]
147
- unmount(mount_name, params)
148
- else
149
- mount(mount_name, params)
150
- end
151
- end
152
- end
153
- end
5
+ require "sshfsmount/cli"
154
6
 
155
7
  # Run the GLI app
156
- exit run(ARGV)
8
+ exit Sshfsmount::CLI.run(ARGV)
@@ -1,7 +1,164 @@
1
1
  # frozen_string_literal: true
2
2
 
3
+ require "json"
4
+ require "shellwords"
5
+ require "pathname"
6
+
3
7
  require "sshfsmount/version"
4
8
 
5
9
  module Sshfsmount
6
- # Your code goes here...
10
+ #
11
+ # Basic SSHFS flags
12
+ #
13
+ SSHFS_FLAGS = [
14
+ "-o local",
15
+ "-o workaround=nonodelaysrv",
16
+ "-o transform_symlinks",
17
+ "-o idmap=user",
18
+ "-C",
19
+ ].freeze
20
+
21
+ module_function
22
+
23
+ def verbose
24
+ @verbose
25
+ end
26
+
27
+ def verbose=(val)
28
+ @verbose = val ? true : false
29
+ end
30
+
31
+ def sshfs_cmd
32
+ sshfs_cmd = `command -v sshfs`.strip
33
+ raise "sshfs command not found in path" if sshfs_cmd.empty?
34
+ sshfs_cmd
35
+ end
36
+
37
+ #
38
+ # Locate config file.
39
+ #
40
+ def find_config_file
41
+ @config_file ||= begin
42
+ [
43
+ Pathname.new(File.join(Dir.home, ".sshfsmount.json")),
44
+ Pathname.new(File.join(Dir.home, ".config", "sshfsmount.json")),
45
+ Pathname.new(File.join(Dir.home, ".config", "sshfsmount", "sshfsmount.json")),
46
+ ].select(&:file?).first
47
+ end
48
+ end
49
+
50
+ #
51
+ # Parse config file
52
+ #
53
+ def config
54
+ @config ||= begin
55
+ config_file = find_config_file
56
+ if config_file.nil?
57
+ STDERR.puts "No config file found"
58
+ {}
59
+ else
60
+ JSON.parse(config_file.read, symbolize_names: true)
61
+ end
62
+ rescue JSON::ParserError => e
63
+ STDERR.puts "Parse error in config file `#{config_file}`: #{e}"
64
+ {}
65
+ end
66
+ end
67
+
68
+ def active_mounts
69
+ @active_mounts ||= begin
70
+ `mount`.lines.each_with_object({}) do |line, mounts|
71
+ regex = %r{^(?<remote>.+@[^:]+\:/.*?) on (?<local>/.*?) (?<options>\(\b(?:fuse|osxfuse)\b.*?\))$}
72
+ info = line.match(regex)
73
+ next if info.nil?
74
+ pid = `pgrep -f "/sshfs #{Shellwords.escape(info[:remote])} #{Shellwords.escape(info[:local])} "`.strip
75
+ pid = "None found" if pid.empty?
76
+ mounts[Pathname.new(info[:local]).expand_path] = {
77
+ local: info[:local],
78
+ remote: info[:remote],
79
+ options: info[:options],
80
+ pid: pid,
81
+ str: "#{info[:remote]} on #{info[:local]} (PID: #{pid})",
82
+ }
83
+ end
84
+ end
85
+ end
86
+
87
+ # Fails if the mount-path is already in use.
88
+ def dupe_check!(mount_name, params)
89
+ local = Pathname.new(params[:local]).expand_path
90
+ dupe = active_mounts[local]
91
+ return if dupe.nil?
92
+ raise "\"#{mount_name}\" already mounted?\n* #{dupe[:str]}"
93
+ end
94
+
95
+ #
96
+ # Create Mount-point Directory
97
+ #
98
+ def mkmountpoint(name)
99
+ local = Pathname.new(name).expand_path
100
+ if !local.exist?
101
+ STDERR.puts "Creating mount-point directory #{local}"
102
+ local.mkpath
103
+ elsif !local.directory
104
+ raise "Mount point #{local} exists and is not a directory"
105
+ elsif !local.empty?
106
+ raise "Mount point #{local} already exists and is not empty"
107
+ elsif @verbose
108
+ STDERR.puts "Mount-point directory #{local} already exists and is empty"
109
+ end
110
+ local
111
+ end
112
+
113
+ #
114
+ # Delete mount-point directory
115
+ #
116
+ def rmmountpoint(name)
117
+ local = Pathname.new(name).expand_path
118
+ if !local.exist?
119
+ STDERR.puts "Mount-point directory not found" if @verbose
120
+ elsif !local.directory?
121
+ raise "Mount point #{local} is not a directory"
122
+ elsif !local.empty?
123
+ raise "Mount-point directory #{local} is not empty"
124
+ else
125
+ STDERR.puts "Deleting mount-point directory #{local}"
126
+ local.rmdir
127
+ return true
128
+ end
129
+ end
130
+
131
+ #
132
+ # Mount an SSHFS volume
133
+ #
134
+ def mount(mount_name, params)
135
+ dupe_check!(mount_name, params)
136
+ local = mkmountpoint(params[:local])
137
+ volname = params[:volname] || mount_name
138
+ cmd = "#{sshfs_cmd} " \
139
+ "#{Shellwords.escape(params[:remote])} " \
140
+ "#{Shellwords.escape(local)} " \
141
+ "-o volname=\"#{Shellwords.escape(volname)}\" " \
142
+ "#{SSHFS_FLAGS.join(' ')} " \
143
+ "-p #{(params[:port] || 22).to_i}"
144
+ puts "Mounting \"#{mount_name}\"\n" \
145
+ " * #{params[:remote]} on #{local} as \"#{volname}\""
146
+ STDERR.puts "> #{cmd}" if @verbose
147
+ system(cmd)
148
+ end
149
+
150
+ #
151
+ # Unmount an SSHFS volume
152
+ #
153
+ def unmount(mount_name, params)
154
+ local = Pathname.new(params[:local]).expand_path
155
+ info = active_mounts[local]
156
+ raise "No active mount-point found for #{local}" if info.nil?
157
+ STDERR.puts "No active SSHFS process found for #{local}" if info[:pid] == "None found"
158
+ cmd = "umount #{Shellwords.escape(local)}"
159
+ puts "Unmounting \"#{mount_name}\" (#{local})"
160
+ STDERR.puts "> #{cmd}" if @verbose
161
+ raise "Unmount error, skipping removal of mount-point." unless system(cmd)
162
+ rmmountpoint(local)
163
+ end
7
164
  end
@@ -0,0 +1,48 @@
1
+ # frozen_string_literal: true
2
+
3
+ require "gli"
4
+
5
+ module Sshfsmount
6
+ module CLI
7
+ extend GLI::App
8
+ #
9
+ # GLI command-line app definition
10
+ #
11
+ program_desc "A simple front-end CLI to SSHFS"
12
+ version Sshfsmount::VERSION
13
+
14
+ switch %i[u unmount], desc: "Unmount the volume", negatable: false
15
+ switch %i[v verbose], desc: "Show verbose output", negatable: false
16
+
17
+ desc "List active SSHFS processes"
18
+ command :active do |c|
19
+ c.action do
20
+ Sshfsmount.active_mounts.each_value do |data|
21
+ puts "* #{data[:str]}"
22
+ end
23
+ end
24
+ end
25
+
26
+ config = Sshfsmount.config
27
+
28
+ #
29
+ # Define commands from data-file
30
+ #
31
+ extant_commands = commands.keys
32
+ config.reject { |name, _| extant_commands.include?(name) }.each do |mount_name, params|
33
+ desc "mount #{params[:remote]} to #{params[:local]}"
34
+ command mount_name do |c|
35
+ c.switch %i[u unmount], desc: "Unmount the volume", negatable: false
36
+ c.switch %i[v verbose], desc: "Show verbose output", negatable: false
37
+ c.action do |global_options, cmd_options|
38
+ Sshfsmount.verbose = global_options[:v] || cmd_options[:v]
39
+ if global_options[:u] || cmd_options[:u]
40
+ Sshfsmount.unmount(mount_name, params)
41
+ else
42
+ Sshfsmount.mount(mount_name, params)
43
+ end
44
+ end
45
+ end
46
+ end
47
+ end
48
+ end
@@ -1,5 +1,5 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  module Sshfsmount
4
- VERSION = "0.1.0".freeze
4
+ VERSION = "0.1.2".freeze
5
5
  end
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: sshfsmount
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.1.0
4
+ version: 0.1.2
5
5
  platform: ruby
6
6
  authors:
7
7
  - Tim Bellefleur
8
8
  autorequire:
9
9
  bindir: exe
10
10
  cert_chain: []
11
- date: 2017-07-25 00:00:00.000000000 Z
11
+ date: 2017-07-26 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: bundler
@@ -128,6 +128,7 @@ files:
128
128
  - bin/setup
129
129
  - exe/sshfsmount
130
130
  - lib/sshfsmount.rb
131
+ - lib/sshfsmount/cli.rb
131
132
  - lib/sshfsmount/version.rb
132
133
  - sshfsmount.gemspec
133
134
  homepage: https://github.com/nomoon/sshfsmount