right_data 0.5.20 → 0.5.21
Sign up to get free protection for your applications and to get access to all the features.
- data/lib/FileSystemTree.rb +172 -0
- data/lib/main.rb +31 -0
- data/lib/right_data.rb +11 -0
- metadata +4 -3
@@ -0,0 +1,172 @@
|
|
1
|
+
require 'escape'
|
2
|
+
module RightData
|
3
|
+
class FileSystemTree
|
4
|
+
|
5
|
+
attr_reader :relativePath
|
6
|
+
attr_reader :parent
|
7
|
+
|
8
|
+
attr_reader :ignore_children
|
9
|
+
attr_reader :duplicate_children
|
10
|
+
attr_accessor :duplicates
|
11
|
+
attr_accessor :ignorable
|
12
|
+
|
13
|
+
def initialize path, args
|
14
|
+
if args[:parent]
|
15
|
+
@relativePath = File.basename(path)
|
16
|
+
@parent = args[:parent]
|
17
|
+
else
|
18
|
+
@relativePath = path
|
19
|
+
@parent = nil
|
20
|
+
end
|
21
|
+
@ignorable = false
|
22
|
+
@duplicates = [] # for this node
|
23
|
+
@duplicate_children = 0 # counts for children
|
24
|
+
@ignore_children = 0
|
25
|
+
self
|
26
|
+
end
|
27
|
+
|
28
|
+
# TODO: Do this for LEAVES instead of files. Include empty dirs.
|
29
|
+
def files
|
30
|
+
return 0 if leaf? && File.directory?(fullPath)
|
31
|
+
return 1 if leaf?
|
32
|
+
return children.map {|n| n.files}.inject {|sum, n| sum + n }
|
33
|
+
end
|
34
|
+
def ignore_files
|
35
|
+
return 0 if leaf? && File.directory?(fullPath)
|
36
|
+
return ignorable? ? 1 : 0 if leaf?
|
37
|
+
return children.map {|n| n.ignore_files}.inject {|sum, n| sum + n }
|
38
|
+
end
|
39
|
+
def duplicate_files
|
40
|
+
return 0 if leaf? && File.directory?(fullPath)
|
41
|
+
return duplicate? ? 1 : 0 if leaf?
|
42
|
+
return children.map {|n| n.duplicate_files}.inject {|sum, n| sum + n }
|
43
|
+
end
|
44
|
+
|
45
|
+
|
46
|
+
def basename; @relativePath; end
|
47
|
+
|
48
|
+
def self.rootItem
|
49
|
+
@rootItem ||= self.new '/', :parent => nil
|
50
|
+
end
|
51
|
+
|
52
|
+
def children
|
53
|
+
unless @children
|
54
|
+
if File.directory?(fullPath) and File.readable?(fullPath)
|
55
|
+
@children = Dir.entries(fullPath).select { |path|
|
56
|
+
path != '.' and path != '..'
|
57
|
+
}.map { |path|
|
58
|
+
FileSystemTree.new path, :parent => self
|
59
|
+
}
|
60
|
+
else
|
61
|
+
@children = nil
|
62
|
+
end
|
63
|
+
end
|
64
|
+
@children
|
65
|
+
end
|
66
|
+
|
67
|
+
def path; fullPath; end
|
68
|
+
def fullPath
|
69
|
+
@parent ? File.join(@parent.fullPath, @relativePath) : @relativePath
|
70
|
+
end
|
71
|
+
|
72
|
+
def childAtIndex n
|
73
|
+
children[n]
|
74
|
+
end
|
75
|
+
|
76
|
+
def numberOfChildren
|
77
|
+
children == nil ? -1 : children.size
|
78
|
+
end
|
79
|
+
|
80
|
+
def children?; !children.nil? && !children.empty?; end
|
81
|
+
|
82
|
+
def duplicate?
|
83
|
+
if leaf?
|
84
|
+
!duplicates.empty?
|
85
|
+
else # Dup if all ignored / dup children
|
86
|
+
((@ignore_children + @duplicate_children) == numberOfChildren)
|
87
|
+
end
|
88
|
+
end
|
89
|
+
|
90
|
+
def ignorable?; ignorable; end
|
91
|
+
|
92
|
+
def increment_ignorable_children
|
93
|
+
@ignore_children += 1
|
94
|
+
update_duplicate_ignorable_status
|
95
|
+
end
|
96
|
+
|
97
|
+
def update_duplicate_ignorable_status
|
98
|
+
parent.increment_duplicate_children if((@ignore_children + @duplicate_children) == numberOfChildren)
|
99
|
+
end
|
100
|
+
|
101
|
+
def increment_duplicate_children
|
102
|
+
@duplicate_children += 1
|
103
|
+
update_duplicate_ignorable_status
|
104
|
+
end
|
105
|
+
|
106
|
+
def leaf?; !children?; end
|
107
|
+
|
108
|
+
def traverse(&block) # Allow proc to decide if we traverse
|
109
|
+
if block.call(self) && children?
|
110
|
+
children.each { |c| c.traverse(&block) }
|
111
|
+
end
|
112
|
+
end
|
113
|
+
|
114
|
+
def other_children
|
115
|
+
children.size - ignore_children - duplicate_children
|
116
|
+
end
|
117
|
+
|
118
|
+
def to_param; to_s; end
|
119
|
+
def to_s
|
120
|
+
"<Tree :path => #{self.path}, :files => #{self.files}>"
|
121
|
+
end
|
122
|
+
|
123
|
+
def put_for_shell(pre,path,comment)
|
124
|
+
if(pre.empty?)
|
125
|
+
puts Escape.shell_command([path, "# #{comment}"])
|
126
|
+
else
|
127
|
+
puts Escape.shell_command([pre.split(" "), path, "# #{comment}"].flatten)
|
128
|
+
end
|
129
|
+
end
|
130
|
+
|
131
|
+
# Inspect the nodes:
|
132
|
+
def report(pre="")
|
133
|
+
pre += " " if !pre.empty?
|
134
|
+
self.traverse do |n|
|
135
|
+
# Is this a leaf (e.g. a file)?
|
136
|
+
if n.leaf?
|
137
|
+
if(File.directory?(n.path))
|
138
|
+
# Prune empty dirs!
|
139
|
+
put_for_shell(pre,n.path,"Empty dir") # Remove the dups/igns!
|
140
|
+
#puts "#{pre}'#{n.path.gsub(/'/,"\\\\'")}' # Empty dir"
|
141
|
+
else
|
142
|
+
msg = nil
|
143
|
+
msg = " dup(#{n.duplicates.count})" if n.duplicate?
|
144
|
+
msg = " ign" if n.ignorable?
|
145
|
+
if msg
|
146
|
+
put_for_shell(pre,n.path,msg) # Remove the dups/igns!
|
147
|
+
# puts "#{pre}'#{n.path.gsub(/'/,"\\\\'")}' #{msg}" # Remove the dups/igns!
|
148
|
+
else
|
149
|
+
puts "# #{n.path} unique"
|
150
|
+
end
|
151
|
+
end
|
152
|
+
false # Don't traverse deeper!
|
153
|
+
else
|
154
|
+
if n.duplicate_children + n.ignore_children == n.children.size
|
155
|
+
put_for_shell(pre,n.path,"#{n.duplicate_children} dups / #{n.ignore_children} ignores")
|
156
|
+
# puts "#{pre}'#{n.path.gsub(/'/,"\\\\'")}' # #{n.duplicate_children} dups / #{n.ignore_children} ignores"
|
157
|
+
false # Don't traverse deeper!
|
158
|
+
elsif n.children.size == 0
|
159
|
+
put_for_shell(pre,n.path," Empty")
|
160
|
+
# puts "#{pre}'#{n.path.gsub(/'/,"\\\\'")}' # Empty... "
|
161
|
+
false
|
162
|
+
else
|
163
|
+
puts "# #{n.path} # Not #{n.duplicate_children} dup/ #{n.ignore_children} ign / #{n.other_children} other "
|
164
|
+
true
|
165
|
+
end
|
166
|
+
end
|
167
|
+
end
|
168
|
+
puts "# #{self.ignore_files} ignores, #{self.duplicate_files} dups of #{self.files} files"
|
169
|
+
end
|
170
|
+
|
171
|
+
end
|
172
|
+
end
|
data/lib/main.rb
CHANGED
@@ -286,6 +286,37 @@ module RightData
|
|
286
286
|
# prunable_files
|
287
287
|
end
|
288
288
|
|
289
|
+
# This is a weak check! Also does nothing to check one svn in another.
|
290
|
+
def svn?(path)
|
291
|
+
File.directory?(File.join(path, ".svn"))
|
292
|
+
end
|
293
|
+
def git?(path)
|
294
|
+
File.directory?(File.join(path, ".git"))
|
295
|
+
end
|
296
|
+
def self.scan_for_repos(prune, &block)
|
297
|
+
tree = FileSystemTree.new(prune, :parent => nil)
|
298
|
+
repos = {}
|
299
|
+
# Mark the nodes:
|
300
|
+
tree.traverse do |n|
|
301
|
+
if File.directory?(n.path)
|
302
|
+
if svn?(n.path)
|
303
|
+
cd_cmd = Escape.shell_command(["cd",n.path])
|
304
|
+
status = `#{cd_cmd}; svn status`
|
305
|
+
info = `#{cd_cmd}; svn info`
|
306
|
+
repos[n.path] = { :kind => "svn", :status => status, :info => info }
|
307
|
+
end
|
308
|
+
if git?(n.path)
|
309
|
+
cd_cmd = Escape.shell_command(["cd",n.path])
|
310
|
+
status = `#{cd_cmd}; git status`
|
311
|
+
info = `#{cd_cmd}; git show`
|
312
|
+
repos[n.path] = { :kind => "git", :status => status, :info => info }
|
313
|
+
end
|
314
|
+
!repos[n.path] # recurse only if we DID NOT find a repo
|
315
|
+
end
|
316
|
+
end
|
317
|
+
return repos
|
318
|
+
end
|
319
|
+
|
289
320
|
# each_set_of_duplicates(dirs) do |f|
|
290
321
|
# puts "Duplicates: #{f.join(", ")}"
|
291
322
|
#end
|
data/lib/right_data.rb
CHANGED
@@ -2,14 +2,25 @@ require 'main'
|
|
2
2
|
|
3
3
|
module RightData
|
4
4
|
def self.hello; "Hi!"; end
|
5
|
+
|
6
|
+
# Run this in a directory (prunable) that is suspected of containing duplicate files that
|
7
|
+
# already exist in master. E.g. check a discovered backup drive and whether anything on it is valid
|
5
8
|
def self.prune_report(master,prunable)
|
6
9
|
tree = RightData::scan_for_prunable(master,prunable)
|
7
10
|
tree.report('rm -rf'); nil
|
8
11
|
end
|
9
12
|
|
13
|
+
# Run this in a directory that is suspected of containing self-duplicate files.
|
14
|
+
# Compare to: fdupes -r -n prunable
|
10
15
|
def self.dup_report(prunable)
|
11
16
|
RightData::scan_for_dup(prunable)
|
12
17
|
end
|
18
|
+
|
19
|
+
# Run this on a directory that is suspected of containing unchecked in GIT or SVN repos.
|
20
|
+
# Get back a list of all repos, versions and whether any files are unchecked in.
|
21
|
+
def self.repo_report(search_dir)
|
22
|
+
tree = RightData::scan_for_repos(search_dir)
|
23
|
+
end
|
13
24
|
end
|
14
25
|
# Usage:
|
15
26
|
# Prune any files from prunable that are already in master:
|
metadata
CHANGED
@@ -1,13 +1,13 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: right_data
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
hash:
|
4
|
+
hash: 33
|
5
5
|
prerelease: false
|
6
6
|
segments:
|
7
7
|
- 0
|
8
8
|
- 5
|
9
|
-
-
|
10
|
-
version: 0.5.
|
9
|
+
- 21
|
10
|
+
version: 0.5.21
|
11
11
|
platform: ruby
|
12
12
|
authors:
|
13
13
|
- Jonathan Siegel
|
@@ -57,6 +57,7 @@ extra_rdoc_files:
|
|
57
57
|
- README.rdoc
|
58
58
|
files:
|
59
59
|
- lib/FileSystemItem.rb
|
60
|
+
- lib/FileSystemTree.rb
|
60
61
|
- lib/main.rb
|
61
62
|
- lib/right_data.rb
|
62
63
|
- LICENSE
|