umount-many 0.1.4 → 0.2.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/README.md ADDED
@@ -0,0 +1,10 @@
1
+ umount-many
2
+ ===========
3
+
4
+ `umount-many` is a little tool which allows you to unmount several file systems
5
+ at once by using filters. For example, if you want to unmount every VFAT
6
+ file system in reversed order, simply enter this at the command line:
7
+
8
+ umount-many -t vfat -R
9
+
10
+ For a complete list, call `umount-many` with the `-h` option.
data/Rakefile CHANGED
@@ -2,10 +2,9 @@ begin
2
2
  require 'jeweler'
3
3
  Jeweler::Tasks.new do |gem|
4
4
  gem.name = "umount-many"
5
- gem.executables = "umount-many"
6
5
  gem.summary = "Unmount several devices based on filters"
7
6
  gem.email = "sin3141592@gmail.com"
8
- gem.homepage = "http://github.com/sin3141592/umount-many"
7
+ gem.homepage = "https://github.com/sin3141592/umount-many"
9
8
  gem.description = gem.summary
10
9
  gem.authors = ["Hagbard Celine"]
11
10
  end
data/TODO CHANGED
@@ -1,2 +1 @@
1
- - Write a bit of documentation
2
- - Of course fix the TODO's placed in the code
1
+ - Of course fix the TODOs placed in the code
data/VERSION CHANGED
@@ -1 +1 @@
1
- 0.1.4
1
+ 0.2.0
data/bin/umount-many CHANGED
@@ -1,8 +1,8 @@
1
1
  #!/usr/bin/env ruby
2
2
  # coding: utf-8
3
3
 
4
- require 'optparse'
5
- require File.join(File.dirname(__FILE__), "..", "lib", "umount-many")
4
+ require "optparse"
5
+ require File.expand_path("../../lib/umount-many", __FILE__)
6
6
 
7
7
  def main
8
8
  opts = Hash.new
@@ -54,7 +54,7 @@ def main
54
54
  opts[:reverse] = true
55
55
  end
56
56
  end.parse!
57
- unmount_many_fs(opts)
57
+ UmountMany.unmount_many_fs(opts)
58
58
  end
59
59
 
60
- main
60
+ main if $0 == __FILE__
@@ -0,0 +1,16 @@
1
+ #!/usr/bin/env ruby
2
+ # coding: utf-8
3
+
4
+ module HashValuesAt
5
+ # Works similiar to the +values_at+ method but return
6
+ # instead of just values an appropriate hash
7
+ def hash_at(*keys)
8
+ hash = Hash.new
9
+ keys.zip(self.values_at(*keys)).each {|k, v| hash[k] = v}
10
+ hash
11
+ end
12
+ end
13
+
14
+ class Hash
15
+ include HashValuesAt
16
+ end
data/lib/umount-many.rb CHANGED
@@ -4,124 +4,163 @@
4
4
  # == umount-many
5
5
  # umount-many allows you to unmount several file systems at once
6
6
  # You can specify several filter types to select the desired file systems
7
- # For example:
7
+ # For example:
8
8
  # +umount-many -t ext4+
9
9
  # This command unmounts every file system that has ext4 as file system type
10
10
  # For a list of all filters use the +-h+ or +--help+ command line option
11
11
 
12
12
  require 'optparse'
13
13
  require 'set'
14
+ require File.expand_path("../core_ext/hash.rb", __FILE__)
14
15
 
15
- class Hash
16
- # Works similiar to the +values_at+ method but return
17
- # instead of just values an appropriate hash
18
- def hash_at(*keys)
19
- hash = Hash.new
20
- keys.zip(self.values_at(*keys)).each {|k, v| hash[k] = v}
21
- hash
22
- end
23
- end
16
+ module UmountMany
17
+ # Retrieve a list of all mounted file system. Return an array with hashes
18
+ # of the following form_
19
+ # * +:device+: The device file (in +/dev+) from which the file system is
20
+ # mounted.
21
+ # * +:mount_point+: The directory to which the file system is mounted
22
+ # * +:type+: The file system type (e.g. +ext4+).
23
+ # * +:options+: An array of options such as +rw+ and +nosuid+.
24
+ def self.parse_file_systems
25
+ # TODO: Currently calls +mount+ and parses stdout. Not such a good
26
+ # approach, is it?
27
+ # TODO: I just can the regex gurantee to work for my box (which is a linux
28
+ # 2.6.31 with +mount+ from util-linux-ng 2.16)
24
29
 
25
- def parse_file_systems
26
- # TODO: Currently calls +mount+ and parses stdout. Not such a good
27
- # approach, is it?
28
- # TODO: I just can the regex gurantee to work for my box (which is a linux
29
- # 2.6.31 with +mount+ from util-linux-ng 2.16)
30
-
31
- filesystems = []
32
- IO.popen("mount") do |pipe|
33
- pipe.each_line do |line|
34
- if line =~ /([^\s]+) on ([^\s]+) type ([^\s]+) \((.*)\)/
35
- filesystems.push({:device => $1, :mount_point => $2, :type => $3,
36
- :options => $4.split(",")})
37
- else
38
- STDERR.puts("Couldn't parse output from mount. " +
39
- "Skipping current line")
30
+ filesystems = []
31
+ IO.popen("mount") do |pipe|
32
+ pipe.each_line do |line|
33
+ if line =~ /([^\s]+) on ([^\s]+) type ([^\s]+) \((.*)\)/
34
+ filesystems.push({:device => $1, :mount_point => $2, :type => $3,
35
+ :options => $4.split(",")})
36
+ else
37
+ STDERR.puts("Couldn't parse output from mount. " +
38
+ "Skipping current line")
39
+ end
40
40
  end
41
41
  end
42
+ filesystems
42
43
  end
43
- filesystems
44
- end
45
-
46
- def filter_by_device(filesystems, device)
47
- filesystems.select {|e| e[:device] == device}
48
- end
49
-
50
- def filter_by_mount_point(filesystems, mp)
51
- filesystems.select {|e| e[:mount_point] == mp}
52
- end
53
44
 
54
- def filter_by_type(filesystems, type)
55
- filesystems.select {|e| e[:type].downcase == type.downcase}
56
- end
45
+ # Check if a file system is mounted from +device+.
46
+ def self.filter_by_device(filesystems, device)
47
+ filesystems.select {|e| e[:device] == device}
48
+ end
57
49
 
58
- def filter_by_options(filesystems, option)
59
- filesystems.select {|e| e[:options].include?(option)}
60
- end
50
+ # Check if a file system is mounted on +mp+.
51
+ def self.filter_by_mount_point(filesystems, mp)
52
+ filesystems.select {|e| e[:mount_point] == mp}
53
+ end
61
54
 
62
- def collect_filters(opts)
63
- filters = []
64
- opts.hash_at(:mount_point, :device, :type, :options).each do |filter, v|
65
- filters.push filter if v && !v.empty?
55
+ # Check if a file system is of the given +type+.
56
+ def self.filter_by_type(filesystems, type)
57
+ filesystems.select {|e| e[:type].downcase == type.downcase}
66
58
  end
67
- filters.map{|e| [method("filter_by_" + e.to_s), e]}
68
- end
69
59
 
70
- def report_results(to_unmount, format)
71
- unless ["yaml", "json", "xml"].include?(format)
72
- puts "Not a supported format for reporting: #{format}"
73
- puts "See the help (-h) for a list"
74
- exit 2
60
+ # Check if all given +options+ are set on a file system
61
+ def self.filter_by_options(filesystems, option)
62
+ # TODO: Check whether e[:options] contains *all* set options
63
+ # (e[:options] & options == options)
64
+ # Rename option to options
65
+ filesystems.select {|e| e[:options].include?(option)}
75
66
  end
76
- if format.downcase == "xml"
77
- STDERR.puts "WARNING: XML format is experimental."
78
- require 'xmlsimple'
79
- puts XmlSimple.xml_out(to_unmount)
80
- else
81
- require format
82
- meth = to_unmount.method("to_" + format)
83
- puts meth.call
67
+
68
+ # See which filters are set in +opts+ and return an array of the form
69
+ # <tt>[[filter_by_foo, foo], ...]</tt>. +filter_by_foo+ is a method object
70
+ # representing the according methods defined in this module. +foo+ is string
71
+ # naming the filter.
72
+ def self.collect_filters(opts)
73
+ filters = []
74
+ opts.hash_at(:mount_point, :device, :type, :options).each do |filter, v|
75
+ filters.push filter if v && !v.empty?
76
+ end
77
+ filters.map{|e| [method("filter_by_" + e.to_s), e]}
84
78
  end
85
- end
86
79
 
87
- def unmount_devices(devices, verbose)
88
- devices.each do |device|
89
- if verbose
90
- print ("Unmounting #{device[:device]} mounted on " +
91
- "#{device[:mount_point]}... ")
80
+ # Serialize the matched file system in the given +format+. Available
81
+ # are YAML, JSON and XML (this requires the +xmlsimple+ library). YAML and
82
+ # JSON use stdlib libraries.
83
+ def self.report_results(to_unmount, format)
84
+ unless ["yaml", "json", "xml"].include?(format)
85
+ puts "Not a supported format for reporting: #{format}"
86
+ puts "See the help (-h) for a list"
87
+ exit 2
88
+ end
89
+ if format.downcase == "xml"
90
+ STDERR.puts "WARNING: XML format is experimental."
91
+ require 'xmlsimple'
92
+ puts XmlSimple.xml_out(to_unmount)
93
+ else
94
+ require format
95
+ meth = to_unmount.method("to_" + format)
96
+ puts meth.call
92
97
  end
93
- system "umount \"#{device[:device]}\""
94
- # Needed because umount takes a bit of time
95
- sleep 0.2
96
- puts "DONE" if verbose
97
98
  end
98
- end
99
99
 
100
- def matched_devices(opts)
101
- filesystems = parse_file_systems
102
- filters = collect_filters(opts)
103
- to_unmount = Set.new
104
- results = filters.map {|meth, name| meth.call(filesystems, opts[name])}
105
- results.each {|devices| to_unmount += Set.new(devices)}
106
- to_unmount = to_unmount.to_a
107
- to_unmount.reverse! if opts[:reverse]
108
- to_unmount
109
- end
100
+ # Actually unmount all the given devices. If +verbose+ is +true+, print every
101
+ # file system before it is unmounted.
102
+ def self.unmount_devices(devices, verbose)
103
+ devices.each do |device|
104
+ if verbose
105
+ print ("Unmounting #{device[:device]} mounted on " +
106
+ "#{device[:mount_point]}... ")
107
+ end
108
+ system "umount \"#{device[:device]}\""
109
+ # Needed because umount takes a bit of time
110
+ sleep 0.2
111
+ puts "DONE" if verbose
112
+ end
113
+ end
110
114
 
111
- def unmount_many_fs(opts)
112
- if opts[:all]
113
- to_unmount = parse_file_systems
114
- else
115
- to_unmount = matched_devices(opts)
115
+ # Collect the mounted file systems and apply the given filters. Return an
116
+ # array of hashes. For a description of this data structure see
117
+ # +parse_file_systems+.
118
+ def self.matched_devices(opts)
119
+ filesystems = parse_file_systems
120
+ filters = collect_filters(opts)
121
+ to_unmount = Set.new
122
+ results = filters.map {|meth, name| meth.call(filesystems, opts[name])}
123
+ results.each {|devices| to_unmount += Set.new(devices)}
124
+ to_unmount = to_unmount.to_a
125
+ to_unmount.reverse! if opts[:reverse]
126
+ to_unmount
116
127
  end
117
- if opts[:simulate]
118
- to_unmount.each do |device|
119
- puts ("#{device[:device]} mounted on #{device[:mount_point]} as " +
120
- "#{device[:type]}")
128
+
129
+ # Main interface to +umount-many+.
130
+ # +opts+ is a Hash which may consist of the
131
+ # following keys (+nil+ is the default for all keys)
132
+ # * +:mount_point+: A path which points to the mounted directory.
133
+ # * +:device+: A path to the device file (in +/dev+).
134
+ # * +:type+: The file system (e.g. +ext4+).
135
+ # * +:options+: An array of set options (e.g. +rw+ or +nosuid+). If all of
136
+ # these options are set (additional may be set as well), unmount it.
137
+ # * +:all+: Unmount all of them (merely because we can).
138
+ # * +:simulate+: If true, do not unmount a single file system, but print
139
+ # the collected ones to the screen (see +:reporting as well). This is
140
+ # recommended to check whether the used filters match the correct
141
+ # file systems.
142
+ # * +:reporting+: Similar to +:simulate+, but instead of printing in a human
143
+ # readable format, print in a standardized and easy parsable format.
144
+ # Currently available are YAML, JSON and XML.
145
+ # * +:verbose+: If true, print every file system as it is unmount to the
146
+ # screen
147
+ # * +:reverse+: Reverse the file systems collection before unmounting. This is
148
+ # kind of pointless for there is no guarantee for the order of file systems.
149
+ def self.unmount_many_fs(opts)
150
+ if opts[:all]
151
+ to_unmount = parse_file_systems
152
+ else
153
+ to_unmount = matched_devices(opts)
154
+ end
155
+ if opts[:simulate]
156
+ to_unmount.each do |device|
157
+ puts ("#{device[:device]} mounted on #{device[:mount_point]} as " +
158
+ "#{device[:type]}")
159
+ end
160
+ elsif opts[:reporting]
161
+ report_results(to_unmount, opts[:reporting])
162
+ else
163
+ unmount_devices(to_unmount, opts[:verbose])
121
164
  end
122
- elsif opts[:reporting]
123
- report_results(to_unmount, opts[:reporting])
124
- else
125
- unmount_devices(to_unmount, opts[:verbose])
126
165
  end
127
166
  end
Binary file
Binary file
Binary file
data/umount-many.gemspec CHANGED
@@ -1,34 +1,39 @@
1
1
  # Generated by jeweler
2
2
  # DO NOT EDIT THIS FILE DIRECTLY
3
- # Instead, edit Jeweler::Tasks in Rakefile, and run the gemspec command
3
+ # Instead, edit Jeweler::Tasks in Rakefile, and run 'rake gemspec'
4
4
  # -*- encoding: utf-8 -*-
5
5
 
6
6
  Gem::Specification.new do |s|
7
7
  s.name = %q{umount-many}
8
- s.version = "0.1.4"
8
+ s.version = "0.2.0"
9
9
 
10
10
  s.required_rubygems_version = Gem::Requirement.new(">= 0") if s.respond_to? :required_rubygems_version=
11
11
  s.authors = ["Hagbard Celine"]
12
- s.date = %q{2010-10-05}
12
+ s.date = %q{2011-01-23}
13
13
  s.default_executable = %q{umount-many}
14
14
  s.description = %q{Unmount several devices based on filters}
15
15
  s.email = %q{sin3141592@gmail.com}
16
16
  s.executables = ["umount-many"]
17
17
  s.extra_rdoc_files = [
18
+ "README.md",
18
19
  "TODO"
19
20
  ]
20
21
  s.files = [
22
+ "README.md",
21
23
  "Rakefile",
22
- "TODO",
23
- "VERSION",
24
- "bin/umount-many",
25
- "lib/umount-many.rb",
26
- "pkg/umount-many-0.1.0.gem",
27
- "pkg/umount-many-0.1.1.gem",
28
- "umount-many.gemspec"
24
+ "TODO",
25
+ "VERSION",
26
+ "bin/umount-many",
27
+ "lib/core_ext/hash.rb",
28
+ "lib/umount-many.rb",
29
+ "pkg/umount-many-0.1.0.gem",
30
+ "pkg/umount-many-0.1.1.gem",
31
+ "pkg/umount-many-0.1.3.gem",
32
+ "pkg/umount-many-0.1.4.gem",
33
+ "umount-many-0.1.4.gem",
34
+ "umount-many.gemspec"
29
35
  ]
30
- s.homepage = %q{http://github.com/sin3141592/umount-many}
31
- s.rdoc_options = ["--charset=UTF-8"]
36
+ s.homepage = %q{https://github.com/sin3141592/umount-many}
32
37
  s.require_paths = ["lib"]
33
38
  s.rubygems_version = %q{1.3.7}
34
39
  s.summary = %q{Unmount several devices based on filters}
metadata CHANGED
@@ -4,9 +4,9 @@ version: !ruby/object:Gem::Version
4
4
  prerelease: false
5
5
  segments:
6
6
  - 0
7
- - 1
8
- - 4
9
- version: 0.1.4
7
+ - 2
8
+ - 0
9
+ version: 0.2.0
10
10
  platform: ruby
11
11
  authors:
12
12
  - Hagbard Celine
@@ -14,7 +14,7 @@ autorequire:
14
14
  bindir: bin
15
15
  cert_chain: []
16
16
 
17
- date: 2010-10-05 00:00:00 +02:00
17
+ date: 2011-01-23 00:00:00 +01:00
18
18
  default_executable: umount-many
19
19
  dependencies: []
20
20
 
@@ -25,23 +25,29 @@ executables:
25
25
  extensions: []
26
26
 
27
27
  extra_rdoc_files:
28
+ - README.md
28
29
  - TODO
29
30
  files:
31
+ - README.md
30
32
  - Rakefile
31
33
  - TODO
32
34
  - VERSION
33
35
  - bin/umount-many
36
+ - lib/core_ext/hash.rb
34
37
  - lib/umount-many.rb
35
38
  - pkg/umount-many-0.1.0.gem
36
39
  - pkg/umount-many-0.1.1.gem
40
+ - pkg/umount-many-0.1.3.gem
41
+ - pkg/umount-many-0.1.4.gem
42
+ - umount-many-0.1.4.gem
37
43
  - umount-many.gemspec
38
44
  has_rdoc: true
39
- homepage: http://github.com/sin3141592/umount-many
45
+ homepage: https://github.com/sin3141592/umount-many
40
46
  licenses: []
41
47
 
42
48
  post_install_message:
43
- rdoc_options:
44
- - --charset=UTF-8
49
+ rdoc_options: []
50
+
45
51
  require_paths:
46
52
  - lib
47
53
  required_ruby_version: !ruby/object:Gem::Requirement