right_data 0.5.20 → 0.5.21
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/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
|