durb 0.1
Sign up to get free protection for your applications and to get access to all the features.
- data/History.txt +4 -0
- data/Manifest.txt +11 -0
- data/README.txt +40 -0
- data/Rakefile +11 -0
- data/bin/durb +39 -0
- data/lib/directory_inspector.rb +58 -0
- data/lib/directory_node.rb +41 -0
- data/lib/durb.rb +3 -0
- data/lib/human_readable.rb +27 -0
- data/lib/reducer.rb +14 -0
- data/lib/text_output.rb +76 -0
- data/test/test_durb.rb +0 -0
- metadata +76 -0
data/History.txt
ADDED
data/Manifest.txt
ADDED
data/README.txt
ADDED
@@ -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/>.
|
data/Rakefile
ADDED
data/bin/durb
ADDED
@@ -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
|
data/lib/durb.rb
ADDED
@@ -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
|
data/lib/reducer.rb
ADDED
@@ -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
|
data/lib/text_output.rb
ADDED
@@ -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
|
data/test/test_durb.rb
ADDED
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
|