durb 0.1

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.
@@ -0,0 +1,4 @@
1
+ === 0.1 / 2009-02-11
2
+
3
+ * First release
4
+
@@ -0,0 +1,11 @@
1
+ History.txt
2
+ Manifest.txt
3
+ README.txt
4
+ Rakefile
5
+ bin/durb
6
+ lib/directory_inspector.rb
7
+ lib/directory_node.rb
8
+ lib/durb.rb
9
+ lib/human_readable.rb
10
+ lib/reducer.rb
11
+ lib/text_output.rb
@@ -0,0 +1,40 @@
1
+ = durb
2
+
3
+ * http://durb.rubyforge.org
4
+
5
+ == DESCRIPTION:
6
+
7
+ durb is a smarter du. It's a CLI ruby utility which intelligently displays disk usage under a directory or filesystem. durb hides unimportant directories to make it easier to find out where all your disk-space has gone.
8
+
9
+ == FEATURES/PROBLEMS:
10
+
11
+ * Slow
12
+
13
+ == SYNOPSIS:
14
+
15
+ durb [-s size] [directory]
16
+
17
+ == REQUIREMENTS:
18
+
19
+ * None
20
+
21
+ == INSTALL:
22
+
23
+ * sudo gem install
24
+
25
+ == LICENSE:
26
+
27
+ Copyright (c) 2009 Matteo Sasso
28
+
29
+ This program is free software: you can redistribute it and/or modify
30
+ it under the terms of the GNU General Public License as published by
31
+ the Free Software Foundation, either version 3 of the License, or
32
+ (at your option) any later version.
33
+
34
+ This program is distributed in the hope that it will be useful,
35
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
36
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
37
+ GNU General Public License for more details.
38
+
39
+ You should have received a copy of the GNU General Public License
40
+ along with this program. If not, see <http://www.gnu.org/licenses/>.
@@ -0,0 +1,11 @@
1
+ # -*- ruby -*-
2
+
3
+ require 'rubygems'
4
+ require 'hoe'
5
+ require './lib/durb.rb'
6
+
7
+ Hoe.new('durb', Durb::VERSION) do |p|
8
+ p.developer('Matteo Sasso', 'matteo.sasso@gmail.com')
9
+ end
10
+
11
+ # vim: syntax=Ruby
@@ -0,0 +1,39 @@
1
+ #!/usr/bin/env ruby
2
+
3
+ require 'getoptlong'
4
+
5
+ require 'human_readable'
6
+ require 'text_output'
7
+ require 'directory_node'
8
+ require 'directory_inspector'
9
+ require 'reducer'
10
+
11
+ include HumanReadable
12
+
13
+ DEFAULT_SIZE = "100m"
14
+
15
+ opts = GetoptLong.new(
16
+ ["--size", "-s", GetoptLong::REQUIRED_ARGUMENT],
17
+ ["--width", "-w", GetoptLong::REQUIRED_ARGUMENT],
18
+ ["--verbose", "-v", GetoptLong::NO_ARGUMENT],
19
+ ["--one-filesystem", "-x", GetoptLong::NO_ARGUMENT])
20
+
21
+ opts.each do |opt, arg|
22
+ case opt
23
+ when "--size"
24
+ $size = arg
25
+ when "--width"
26
+ $width = arg.to_i
27
+ when "--verbose"
28
+ $verbose = true
29
+ when "--one-filesystem"
30
+ $one_filesystem = true
31
+ end
32
+ end
33
+
34
+ $path = ARGV[0] ? File.expand_path(ARGV[0]) : File.expand_path(".")
35
+ $size = DEFAULT_SIZE if not $size or $size == 0
36
+
37
+ tree = DirectoryInspector.new($path, {:one_filesystem => $one_filesystem}).run
38
+ reduced_tree = Reducer.run(tree, text_to_size($size))
39
+ TextOutput.new(reduced_tree, $stdout, {:width => $width, :verbose => $verbose}).print_all(text_to_size($size))
@@ -0,0 +1,58 @@
1
+ class DirectoryInspector
2
+ def initialize(path, options = {})
3
+ @path = DirectoryNode.string_to_path(path)
4
+ @filesystem = options[:one_filesystem] ? File.stat(path).dev : nil
5
+ end
6
+
7
+ def run
8
+ make_node(@path)
9
+ end
10
+
11
+ protected
12
+ def make_node(path)
13
+ size, files, subdirectories = inspect(path)
14
+
15
+ dir = DirectoryNode.new(path, size, files)
16
+ subdirectories.map{|p| make_node(p)}.select{|n| not n.nil?}.each do |n|
17
+ dir.add_subdirectory(n)
18
+ end
19
+
20
+ return dir
21
+ end
22
+
23
+ def inspect(path)
24
+ path_string = DirectoryNode.path_to_string(path)
25
+ size = files = 0
26
+ subdirectories = []
27
+
28
+ begin
29
+ dir = Dir.new(path_string)
30
+ rescue Errno::EACCES
31
+ raise $!
32
+ rescue Errno::ENOENT
33
+ return nil
34
+ end
35
+ dir.each do |f|
36
+ next if [".", ".."].include?(f)
37
+ fname = path_string + f
38
+ begin
39
+ st = File.lstat(fname)
40
+ rescue Errno::EACCES
41
+ raise $!
42
+ rescue Errno::ENOENT, Errno::ELOOP
43
+ next
44
+ end
45
+ next if st.symlink?
46
+ next if @filesystem and st.dev != @filesystem
47
+ if st.file?
48
+ size += (512 * st.blocks)
49
+ files += 1
50
+ elsif st.directory?
51
+ # Need to add directory size?
52
+ subdirectories << path + [f]
53
+ end
54
+ end
55
+
56
+ return size, files, subdirectories
57
+ end
58
+ end
@@ -0,0 +1,41 @@
1
+ class DirectoryNode
2
+ attr_reader :path, :subdirectories
3
+ attr_accessor :size, :files, :subsize, :subfiles, :significant
4
+
5
+ def initialize(path, size, files, significant = true)
6
+ @path = path
7
+ @size = size
8
+ @files = files
9
+ @subsize = @subfiles = 0
10
+ @significant = significant
11
+ @subdirectories = []
12
+ end
13
+
14
+ def add_subdirectory(d)
15
+ @subdirectories << d
16
+ if d.significant
17
+ @subsize += d.size + d.subsize
18
+ @subfiles += d.files + d.subfiles
19
+ end
20
+ end
21
+
22
+ def significant_subdirectories
23
+ @subdirectories.select{|n| n.significant}
24
+ end
25
+
26
+ def insignificant_subdirectories
27
+ @subdirectories.select{|n| not n.significant}
28
+ end
29
+
30
+ def path_string
31
+ self.class.path_to_string(@path)
32
+ end
33
+
34
+ def self.path_to_string(path)
35
+ path.length == 0 ? '/' : ('/' + path.join('/') + '/')
36
+ end
37
+
38
+ def self.string_to_path(path_string)
39
+ path_string == '/' ? [] : path_string.split('/').reject{|component| component.empty?}
40
+ end
41
+ end
@@ -0,0 +1,3 @@
1
+ class Durb
2
+ VERSION = '0.1'
3
+ end
@@ -0,0 +1,27 @@
1
+ module HumanReadable
2
+ SUFFIXES = [' ', 'k', 'm', 'g', 't', 'p']
3
+
4
+ def text_to_size(text)
5
+ number, multiplier = text.match(/^(\d+)(\D)?$/)[1..-1]
6
+ exp = multiplier ? SUFFIXES.index(multiplier) : 0
7
+ raise ArgumentError, "Unknown suffix: %s" % multiplier if not exp
8
+
9
+ return number.to_i * 1024**exp
10
+ end
11
+
12
+ def size_to_text(size)
13
+ exp = 0
14
+ while size > 999
15
+ size /= 1024.0
16
+ exp += 1
17
+ end
18
+
19
+ if size >= 100 or exp == 0
20
+ "%d%s" % [size.round, SUFFIXES[exp]]
21
+ elsif size >= 10
22
+ "%.1f%s" % [size, SUFFIXES[exp]]
23
+ else
24
+ "%.2f%s" % [size, SUFFIXES[exp]]
25
+ end
26
+ end
27
+ end
@@ -0,0 +1,14 @@
1
+ module Reducer
2
+ def self.run(tree, threshold)
3
+ rtree = DirectoryNode.new(tree.path, tree.size, tree.files)
4
+
5
+ tree.subdirectories.each{|n| rtree.add_subdirectory(run(n, threshold))}
6
+ rtree.insignificant_subdirectories.each do |n|
7
+ rtree.size += n.size
8
+ rtree.files += n.files
9
+ end
10
+ rtree.significant = (rtree.size >= threshold or not rtree.significant_subdirectories.empty?)
11
+
12
+ return rtree
13
+ end
14
+ end
@@ -0,0 +1,76 @@
1
+ class TextOutput
2
+ def initialize(tree, output, options = {})
3
+ @width = calc_width(tree) + (options[:verbose] ? 23 : 11)
4
+ @output = output
5
+ if output.tty?
6
+ begin
7
+ tput = open("|tput cols")
8
+ max_width = tput.gets.to_i
9
+ rescue
10
+ max_width = 80
11
+ end
12
+ @width = [max_width, @width].min
13
+ end
14
+ @tree = tree
15
+ @options = options
16
+ end
17
+
18
+ def print_all(size)
19
+ if @options[:verbose]
20
+ heading = "SELF SUBS/# "
21
+ puts((" " * (@width - heading.size - 2)) + heading)
22
+ end
23
+ print_tree(@tree, size)
24
+ end
25
+
26
+ def print_tree(tree, size, indentation = 0)
27
+ print_node(tree, size, indentation)
28
+ tree.significant_subdirectories.each do |n|
29
+ print_tree(n, size, indentation + 2)
30
+ end
31
+ end
32
+
33
+ def print_node(node, size, indentation)
34
+ if $verbose
35
+ subsize_text = size_to_text(node.subsize)
36
+ if node.subsize == 0 and node.size == 0
37
+ size_text = nil; raise "can this happen?"
38
+ elsif node.subsize == 0
39
+ size_text = "%5s " % size_to_text(node.size)
40
+ elsif node.size == 0
41
+ size_text = " %5s/%-4d" % [size_to_text(node.subsize), node.subdirectories.size]
42
+ else
43
+ size_text = "%5s + %5s/%-4d" % [size_to_text(node.size), size_to_text(node.subsize), node.subdirectories.size]
44
+ end
45
+ else
46
+ total_size = node.size #+ node.subsize
47
+ size_text = total_size < size ? nil : size_to_text(total_size)
48
+ end
49
+ align((' ' * indentation) + node.path_string, size_text)
50
+ end
51
+
52
+ def calc_width(tree, indentation = 0)
53
+ (tree.significant_subdirectories.map{|n| calc_width(n, indentation + 2)} +
54
+ [tree.path_string.size + indentation]).max
55
+ end
56
+
57
+ def align(left, right)
58
+ right = "" if not right
59
+ size = @width - (left.size + right.size + 4)
60
+ if size <= 0
61
+ left = left[0..(size-4)] + '...'
62
+ size = 0
63
+ end
64
+ @output.print left, ' '
65
+ if not right.empty?
66
+ y = 0
67
+ while size > 0
68
+ @output.print(((y + left.size) % 2 == 0) ? '.' : ' ')
69
+ size -= 1
70
+ y += 1
71
+ end
72
+ @output.print ' ', right
73
+ end
74
+ @output.print "\n"
75
+ end
76
+ end
File without changes
metadata ADDED
@@ -0,0 +1,76 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: durb
3
+ version: !ruby/object:Gem::Version
4
+ version: "0.1"
5
+ platform: ruby
6
+ authors:
7
+ - Matteo Sasso
8
+ autorequire:
9
+ bindir: bin
10
+ cert_chain: []
11
+
12
+ date: 2009-02-11 00:00:00 +01:00
13
+ default_executable:
14
+ dependencies:
15
+ - !ruby/object:Gem::Dependency
16
+ name: hoe
17
+ type: :development
18
+ version_requirement:
19
+ version_requirements: !ruby/object:Gem::Requirement
20
+ requirements:
21
+ - - ">="
22
+ - !ruby/object:Gem::Version
23
+ version: 1.8.3
24
+ version:
25
+ description: durb is a smarter du. It's a CLI ruby utility which intelligently displays disk usage under a directory or filesystem. durb hides unimportant directories to make it easier to find out where all your disk-space has gone.
26
+ email:
27
+ - matteo.sasso@gmail.com
28
+ executables:
29
+ - durb
30
+ extensions: []
31
+
32
+ extra_rdoc_files:
33
+ - History.txt
34
+ - Manifest.txt
35
+ - README.txt
36
+ files:
37
+ - History.txt
38
+ - Manifest.txt
39
+ - README.txt
40
+ - Rakefile
41
+ - bin/durb
42
+ - lib/directory_inspector.rb
43
+ - lib/directory_node.rb
44
+ - lib/durb.rb
45
+ - lib/human_readable.rb
46
+ - lib/reducer.rb
47
+ - lib/text_output.rb
48
+ has_rdoc: true
49
+ homepage: http://durb.rubyforge.org
50
+ post_install_message:
51
+ rdoc_options:
52
+ - --main
53
+ - README.txt
54
+ require_paths:
55
+ - lib
56
+ required_ruby_version: !ruby/object:Gem::Requirement
57
+ requirements:
58
+ - - ">="
59
+ - !ruby/object:Gem::Version
60
+ version: "0"
61
+ version:
62
+ required_rubygems_version: !ruby/object:Gem::Requirement
63
+ requirements:
64
+ - - ">="
65
+ - !ruby/object:Gem::Version
66
+ version: "0"
67
+ version:
68
+ requirements: []
69
+
70
+ rubyforge_project: durb
71
+ rubygems_version: 1.3.1
72
+ signing_key:
73
+ specification_version: 2
74
+ summary: durb is a smarter du
75
+ test_files:
76
+ - test/test_durb.rb