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.
@@ -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: 35
4
+ hash: 33
5
5
  prerelease: false
6
6
  segments:
7
7
  - 0
8
8
  - 5
9
- - 20
10
- version: 0.5.20
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