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