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.
- 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
|