motomike-bnr_tools 0.0.2

Sign up to get free protection for your applications and to get access to all the features.
@@ -0,0 +1,4 @@
1
+ ---
2
+ :minor: 0
3
+ :patch: 2
4
+ :major: 0
@@ -0,0 +1,29 @@
1
+ #!/usr/bin/env ruby
2
+ begin
3
+ require 'rubygems'
4
+ gem 'bnr_tools'
5
+ rescue LoadError
6
+ $: << File.expand_path(File.dirname(__FILE__)) + "/../lib"
7
+ require 'bnr_tools'
8
+ end
9
+
10
+ require 'mergeinator'
11
+ require 'ticket'
12
+ require 'trollop'
13
+
14
+ CURRENT_RELEASE_BRANCH="9.4"
15
+
16
+ opts = Trollop::options do
17
+ opt :ticket, "A ticket number optionally followed by one or more changesets to merge", :type => :ints, :multi => true
18
+ opt :wc_root_path, "Root path to a working copy of the repository we can do merge gymnastics in", :default => "#{ENV["HOME"]}/diggRepository"
19
+ opt :release_branch, "Name of the release branch which will be the merge target", :default => CURRENT_RELEASE_BRANCH, :required => true, :multi => true
20
+ end
21
+
22
+ tickets = Set.new
23
+ Array(opts[:release_branch]).each { |release_branch|
24
+ opts[:ticket].each { |ticketRefAndChangesets|
25
+ ticket, *changesets = *ticketRefAndChangesets
26
+ tickets << Ticket.new(ticket, changesets, opts[:wc_root_path], release_branch)
27
+ }
28
+ Mergeinator.new(opts[:wc_root_path], release_branch, tickets).mergeStuff
29
+ }
@@ -0,0 +1,6 @@
1
+ begin
2
+ myPath = File.expand_path(File.dirname(__FILE__))
3
+ libPath = "#{myPath}/bnr_tools"
4
+ $: << myPath unless $:.include?(myPath)
5
+ $: << libPath unless $:.include?(libPath)
6
+ end
@@ -0,0 +1,60 @@
1
+ require 'svn_commands'
2
+ require 'digg_module'
3
+
4
+ class Changeset
5
+ include Comparable
6
+ attr_reader :revision
7
+ attr_accessor :wcBasePath, :releaseBranch
8
+ def initialize(rev, wc_base_path=SvnCommands::DIGG_DEFAULT_WC_PATH, release_branch="9.4")
9
+ @revision = Integer(rev)
10
+ @modified = {}
11
+ @affectedModules = {}
12
+ self.wcBasePath=wc_base_path
13
+ self.releaseBranch=release_branch
14
+ end
15
+
16
+ def modifiedPaths(relativeStartPath = self.wcBasePath)
17
+ @modified[relativeStartPath] ||= begin
18
+ SvnCommands::Log.new(relativeStartPath,"-r #{self.revision}", true).entries.first.paths.map {|p| p.to_s}
19
+ rescue
20
+ []
21
+ end
22
+ end
23
+
24
+ def affectedModulesbak(modulePath = "LOLz/trunk")
25
+ @affectedModules[modulePath] ||= self.modifiedPaths(modulePath).inject(Set.new) { |memo, modifiedPath|
26
+ (modifiedPath =~ /#{modulePath}\/([^\/]*)/) ? memo << DiggModule.new($1, self.wcBasePath, self.releaseBranch) : memo
27
+ }
28
+ end
29
+
30
+ def affectedModules(modulePath = "LOLz/trunk")
31
+ @affectedModules[modulePath] ||= begin
32
+ self.modifiedPaths(modulePath).inject(Set.new) { |memo, modifiedPath|
33
+ if modifiedPath =~ /#{modulePath}\/([^\/]*)/
34
+ moduleName = $1
35
+ unless (memo.detect{ |m| m.moduleName == moduleName })
36
+ memo << DiggModule.new($1, self.wcBasePath, self.releaseBranch)
37
+ end
38
+ end
39
+ memo
40
+ }
41
+ end
42
+ end
43
+
44
+ def to_s
45
+ "r#{revision}"
46
+ end
47
+
48
+ def <=>(other)
49
+ self.revision <=> other.revision
50
+ end
51
+
52
+ def hash
53
+ self.revision.hash
54
+ end
55
+
56
+ def eql?(other)
57
+ self.revision == other.revision
58
+ end
59
+
60
+ end
@@ -0,0 +1,103 @@
1
+ require 'svn_commands'
2
+ require 'version_number'
3
+ require 'fileutils'
4
+
5
+ class DiggModule
6
+ include Comparable
7
+ attr_reader :moduleName, :wcBasePath, :releaseBranch
8
+ def initialize(module_name, wc_base_path, release_branch)
9
+ @moduleName = module_name
10
+ @wcBasePath = wc_base_path
11
+ @releaseBranch = release_branch
12
+ end
13
+
14
+ def utilDir
15
+ @utilDir ||= begin
16
+ provisionalDir = "#{self.wcBasePath}/build/trunk"
17
+ unless File.exist? provisionalDir
18
+ SvnCommands::Update.new("build/trunk", nil, true, false, self.wcBasePath) # update the current working copy to be sure the dir is there
19
+ end
20
+ provisionalDir
21
+ end
22
+ end
23
+
24
+ def myCatDir
25
+ "#{self.wcBasePath}/LOLcat/branches/#{self.releaseBranch}"
26
+ end
27
+
28
+ def myDir
29
+ "#{self.myCatDir}/modules/#{self.moduleName}"
30
+ end
31
+
32
+ def getVersion
33
+ Dir.chdir(myDir) { |cwd|
34
+ VersionNumber.new(IO.popen(%Q{ #{self.utilDir}/version package.xml }).readlines.first.strip)
35
+ }
36
+ end
37
+
38
+ def updateVersion
39
+ Dir.chdir(myDir) { |cwd|
40
+ current_version = self.getVersion
41
+ new_version = block_given?() ? (yield current_version) : (current_version.next_after_patchlevel_increment)
42
+ puts IO.popen(%Q{ #{self.utilDir}/setversion package.xml #{new_version} }).readlines
43
+ self.updateManifest("#{myCatDir}/manifest/pear-common",new_version)
44
+ }
45
+ end
46
+
47
+ def updateManifest(manifest_path,new_version)
48
+ manifest_lines = File.readlines(manifest_path)
49
+ File.open(manifest_path, "w+") { |f|
50
+ manifest_lines.each { |line|
51
+ if line =~ /^pear.digg.internal\/#{self.moduleName}-/
52
+ f.puts("pear.digg.internal/#{self.moduleName}-#{new_version}")
53
+ else
54
+ f.puts(line)
55
+ end
56
+ }
57
+ }
58
+ end
59
+
60
+ def updateContents
61
+ Dir.chdir(myDir) { |cwd|
62
+ puts IO.popen(%Q{ #{self.utilDir}/update-contents package.xml }).readlines
63
+ }
64
+ end
65
+
66
+ def updateStability(stability="stable")
67
+ Dir.chdir(myDir) { |cwd|
68
+ puts IO.popen(%Q{ #{self.utilDir}/setstability package.xml #{stability} }).readlines
69
+ }
70
+ end
71
+
72
+ def buildPearPackage
73
+ Dir.chdir(myDir) { |cwd|
74
+ puts IO.popen(%Q{ pear package }).readlines
75
+ }
76
+ %Q{ #{self.utilDir}/upload #{myDir}/#{self.moduleName}-#{self.getVersion}.tgz }
77
+ end
78
+
79
+ def cleanupPackageXmlFormatting
80
+ Dir.chdir(myDir) { |cwd|
81
+ FileUtils.copy("package.xml","package.xml.unformatted")
82
+ puts IO.popen(%Q{ XMLLINT_INDENT=" " xmllint --format package.xml.unformatted > package.xml }).readlines
83
+ FileUtils.rm("package.xml.unformatted")
84
+ }
85
+ end
86
+
87
+ def to_s
88
+ self.moduleName
89
+ end
90
+
91
+ def <=>(other)
92
+ self.moduleName <=> other.moduleName
93
+ end
94
+
95
+ def eql?(other)
96
+ self.moduleName == other.moduleName
97
+ end
98
+
99
+ def hash
100
+ self.moduleName.hash
101
+ end
102
+
103
+ end
@@ -0,0 +1,129 @@
1
+ require 'svn_commands'
2
+ require 'version_number'
3
+ require 'highline/import'
4
+ require 'set'
5
+ require 'tempfile'
6
+
7
+ class Mergeinator
8
+ attr_reader :wcPath, :releaseBranchVersion
9
+ attr_accessor :catPath, :modulePath, :ticketsToMerge
10
+
11
+ def initialize(wc_path = SvnCommands::DIGG_DEFAULT_WC_PATH, release = VersionNumber.new(CURRENT_RELEASE_BRANCH,false), tickets=Set.new )
12
+ @wcPath = wc_path
13
+ @releaseBranchVersion = release.kind_of?(VersionNumber) ? release : VersionNumber.new(release,false)
14
+ self.ticketsToMerge = Set.new(Array(tickets))
15
+ self.catPath = "LOLcat/branches/#{releaseBranch}"
16
+ self.modulePath = "#{self.catPath}/modules"
17
+ end
18
+
19
+ def releaseBranch
20
+ "#{self.releaseBranchVersion.major}.#{self.releaseBranchVersion.minor}"
21
+ end
22
+
23
+ def branchWorkingDir
24
+ "#{self.wcPath}/LOLcat/branches/#{self.releaseBranch}"
25
+ end
26
+
27
+ def version
28
+ @versionToTag ||= begin
29
+ preExistingVersions = []
30
+ SvnCommands::Ls.new("LOLcat/tags").entries.each { |entry|
31
+ begin
32
+ entryVersion = VersionNumber.new(entry.name)
33
+ preExistingVersions << entryVersion
34
+ rescue Exception => e
35
+ puts "Exception processing entry: #{e}"
36
+ end
37
+ }
38
+ candidateVersions = preExistingVersions.find_all { |version| version.major == self.releaseBranchVersion.major && version.minor == self.releaseBranchVersion.minor }
39
+ highestCandidateVersion = candidateVersions.sort.last
40
+ puts "Highest existing version: #{highestCandidateVersion}"
41
+ ask("LOL{z,cat} version to tag?") { |q|
42
+ q.default = highestCandidateVersion.next_after_patchlevel_increment.to_s
43
+ q.validate = /#{self.releaseBranchVersion.major}\.#{self.releaseBranchVersion.minor}\.\d+/
44
+ }
45
+ end
46
+ end
47
+
48
+ def tagLOLCat
49
+ ref_msg = self.ticketsToMerge ? "Refs #{(self.ticketsToMerge.map {|t| "#{t}"}).join(", ")}" : "No tickets referenced"
50
+ if agree("References: #{ref_msg}\nOkay to tag branch #{self.releaseBranch} as version #{self.version}?")
51
+ SvnCommands.copy("LOLcat/branches/#{self.releaseBranch}","LOLcat/tags/#{version}", nil, nil, "Tagged LOLcat-#{version}. #{ref_msg}")
52
+ SvnCommands.copy("LOLz/branches/#{self.releaseBranch}","LOLz/tags/#{version}", nil, nil, "Tagged LOLz-#{version}. #{ref_msg}")
53
+ else
54
+ exit(1) unless agree("Oh. Well, would you like to keep going anyway, even though we can't commit anything?")
55
+ end
56
+ SvnCommands::Update.new("LOLcat/tags/#{version}",nil,true,true,self.wcPath) # shallowly checkout the new tag to ~/diggRepository/, no extra args for svn, force update
57
+ t = Tempfile.new("svn_externals").open { |tempfile|
58
+ tempfile.puts "modules svn+ssh://svn.digg.internal/repository/LOLz/tags/#{version}"
59
+ tempfile.puts "build svn+ssh://svn.digg.internal/repository/build/trunk"
60
+ }
61
+ cmd = "svn ps svn:externals --file #{t.path} #{SvnCommands::DIGG_DEFAULT_WC_PATH}/LOLcat/tags/#{version}"
62
+ puts "Running command : #{cmd}"
63
+ puts IO.popen(cmd).readlines
64
+ end
65
+
66
+ def svnMergeCommand(project, changeset)
67
+ "svn merge -c #{changeset.revision} svn+ssh://svn.digg.internal/repository/#{project}/trunk"
68
+ end
69
+
70
+ def mergeStuff
71
+ modules = Set.new
72
+ allChangesets = Set.new
73
+ self.cleanWorkingCopy
74
+ ticketsToMerge.each { |ticket|
75
+ allChangesets.merge(ticket.changesets)
76
+ modules.merge(ticket.affectedModules)
77
+ }
78
+ puts "Affected modules: #{modules.to_a.join(", ")}."
79
+ commitMessage = "Refs #{(ticketsToMerge.sort.map {|ticket| ticket.to_s(false)}).join(", ")} : Merged #{(allChangesets.sort.map {|c| c.to_s }).join(", ")} from trunk"
80
+ puts "Commit message = #{commitMessage}"
81
+ allChangesets.sort.each { |changeset|
82
+ # We could check paths and such, but that's just an extra step for the cat ...
83
+ SvnCommands.merge("LOLcat/trunk",self.catPath,changeset.revision,nil,nil,self.wcPath)
84
+ unless changeset.affectedModules("LOLz/trunk").empty? # OTOH, for modules, we already cached the information
85
+ SvnCommands.merge("LOLz/trunk",self.modulePath,changeset.revision,nil,nil,self.wcPath)
86
+ end
87
+ }
88
+
89
+ @module_upload_cmds = []
90
+ modules.each { |m|
91
+ m.updateVersion
92
+ m.updateContents
93
+ m.updateStability("stable")
94
+ m.cleanupPackageXmlFormatting
95
+ @module_upload_cmds << m.buildPearPackage
96
+ }
97
+
98
+ # Sanity check - spew the entire diff before committing it
99
+ Dir.chdir(self.branchWorkingDir) { |cwd|
100
+ puts IO.popen(%Q{ svn st && svn diff . modules }).readlines
101
+ @module_upload_cmds.each { |cmd| puts cmd }
102
+ puts "Before I commit - does everything look okay?"
103
+ if agree("Commit message: #{commitMessage}")
104
+ system %Q{ svn st | awk '/^\s?[MAD]/ { print $NF } ' | xargs svn commit -m'#{commitMessage}' }
105
+ else
106
+ exit(1) unless agree("Oh. Well, would you like to keep going anyway, even though we can't commit anything?")
107
+ end
108
+ }
109
+ tagLOLCat
110
+ if agree("Upload modified modules now?")
111
+ @module_upload_cmds.each { |cmd|
112
+ puts IO.popen(cmd).readlines
113
+ }
114
+ else
115
+ exit(1) unless agree("Oh. Well, would you like to keep going anyway, even though we can't commit anything?")
116
+ end
117
+ end
118
+
119
+ def cleanWorkingCopy(force=false)
120
+ if (force || agree("Clean working copy now?")) then
121
+ SvnCommands::Update.new(self.catPath, nil, true, false, self.wcPath) # update the current working copy to be sure the dir is there
122
+ Dir.chdir(branchWorkingDir) {
123
+ puts IO.popen(%Q{ svn revert -R . && svn revert -R modules && svn stat | grep "^\?" | cut -c8- | xargs rm -rf }).readlines
124
+ }
125
+ else
126
+ puts "Okay, trusting you ... it's all going to end in tears, I just know it ..."
127
+ end
128
+ end
129
+ end
@@ -0,0 +1,264 @@
1
+ #!/usr/bin/env ruby
2
+
3
+ begin
4
+ require 'lib/bnr_tools'
5
+ rescue
6
+ end
7
+
8
+ require 'svn_xml'
9
+ require 'fileutils'
10
+ require 'open4'
11
+
12
+ module SvnCommands
13
+ DIGG_DEFAULT_SVN_URL="svn+ssh://svn.digg.internal/repository"
14
+ DIGG_DEFAULT_WC_PATH="#{ENV['HOME']}/diggRepository"
15
+
16
+ class SvnException < RuntimeError
17
+ def initialize(status_code, output)
18
+ @status_code = status_code
19
+ @output = output
20
+ end
21
+
22
+ def to_s
23
+ "Status code:#{@status_code} / output:#{@output} #{super}"
24
+ end
25
+ end
26
+
27
+ class << self
28
+ def svnVersion
29
+ @@svnVersion ||= VersionNumber.new(`svn --version --quiet`)
30
+ end
31
+
32
+ def extra_merge_flags
33
+ (Integer(svnVersion.major) >= 1 && Integer(svnVersion.minor) >= 5) ? ["--accept postpone"] : []
34
+ end
35
+
36
+ def new_cmd(command_string, expected_result_class=nil, max_retries=3)
37
+ puts "Executing: '#{command_string}'"
38
+ retry_count = 0
39
+ begin
40
+ out = ""
41
+ err = ""
42
+ status = Open4::popen4(command_string) do |pid, stdin, stdout, stderr|
43
+ stdin.close
44
+ out = stdout.read
45
+ err = stderr.read
46
+ end
47
+ unless status.exitstatus == 0
48
+ raise SvnException.new(status.exitstatus, "stdout: #{out}\n\nstderr: #{err}")
49
+ end
50
+ if (expected_result_class)
51
+ parsed = REXML::Document.new(out)
52
+ expected_result_class.new(parsed.elements[expected_result_class.expected_node_name])
53
+ else
54
+ nil
55
+ end
56
+ rescue Exception => e
57
+ if e.kind_of?(Interrupt)
58
+ exit(1)
59
+ elsif retry_count < max_retries
60
+ # puts "invocation failed with #{e.class} #{e} ... trying again"
61
+ retry_count += 1
62
+ retry
63
+ else
64
+ raise e
65
+ end
66
+ end
67
+ end
68
+
69
+ def copy(fromPath, toPath, extra_args=nil, working_copy_path=nil, commit_msg=nil, repository_base_url=DIGG_DEFAULT_SVN_URL)
70
+ path_base = working_copy_path || repository_base_url
71
+ full_from_path = "#{path_base.chomp("/")}/#{fromPath}"
72
+ full_to_path = "#{path_base.chomp("/")}/#{toPath}"
73
+ if (working_copy_path)
74
+ SvnCommands.new_cmd("svn cp #{Array(extra_args).join(" ")} \"#{full_from_path}\" \"#{full_to_path}\"",nil,1)
75
+ else
76
+ if (commit_msg)
77
+ SvnCommands.new_cmd("svn cp #{Array(extra_args).join(" ")} \"#{full_from_path}\" \"#{full_to_path}\" -m\"#{commit_msg}\"",nil,1)
78
+ else
79
+ raise SvnException.new(-1, "Without a commit message, I can't svn cp a remote URL. Sorry.")
80
+ end
81
+ end
82
+ end
83
+
84
+ def merge(fromPath, toPath, start_rev, end_rev = nil, extra_args=nil, working_copy_path=nil, repository_base_url=DIGG_DEFAULT_SVN_URL)
85
+ extra_args = (Array(extra_args) << SvnCommands.extra_merge_flags).compact
86
+ full_from_path = "#{repository_base_url.chomp("/")}/#{fromPath}"
87
+ full_to_path = "#{working_copy_path.chomp("/")}/#{toPath}"
88
+ rev_spec = begin
89
+ if end_rev.nil?() || Integer(end_rev) == 0
90
+ "-c #{Integer(start_rev)}"
91
+ else
92
+ "-r#{Integer(start_rev)}:#{Integer(end_rev)}"
93
+ end
94
+ end
95
+ SvnCommands.new_cmd("svn merge #{rev_spec} #{extra_args.join(" ")} \"#{full_from_path}\" \"#{full_to_path}\"")
96
+ end
97
+
98
+ def sync(fromPath, toPath, working_copy_path, extra_args=nil, repository_base_url=DIGG_DEFAULT_SVN_URL)
99
+ extra_args = (Array(extra_args) << SvnCommands.extra_merge_flags).compact
100
+ repository_from_path = "#{repository_base_url.chomp("/")}/#{fromPath}"
101
+ repository_to_path = "#{repository_base_url.chomp("/")}/#{toPath}"
102
+ wc_to_path = "#{working_copy_path.chomp("/")}/#{toPath}"
103
+ SvnCommands.new_cmd("svn merge #{extra_args.join(" ")} \"#{repository_to_path}\" \"#{repository_from_path}\" \"#{wc_to_path}\"")
104
+ end
105
+
106
+ def mkdir(path, commit_msg=nil, working_copy_path=nil, repository_base_url=DIGG_DEFAULT_SVN_URL)
107
+ path_base = working_copy_path || repository_base_url
108
+ full_path = "#{path_base.chomp("/")}/#{path}"
109
+ extra_args = (Array(extra_args) << SvnCommands.extra_merge_flags).compact
110
+ if (working_copy_path)
111
+ SvnCommands.new_cmd("svn mkdir #{full_path}")
112
+ else
113
+ if (commit_msg)
114
+ SvnCommands.new_cmd("svn mkdir #{full_path} -m'#{commit_msg}'")
115
+ else
116
+ raise SvnException.new(-1, "No commit message specified; cannot mkdir directly in the repository")
117
+ end
118
+ end
119
+ end
120
+
121
+ end
122
+
123
+ class PathOp
124
+ attr_accessor :fullpath, :entries
125
+ def initialize(relativePath, repository_base_url=DIGG_DEFAULT_SVN_URL)
126
+ @fullpath=relativePath.nil? ? repository_base_url : "#{repository_base_url}/#{relativePath}"
127
+ end
128
+ end
129
+
130
+ class Ls < PathOp
131
+ attr_accessor :lists
132
+ @@all_lists ||= {}
133
+ def initialize(relativePath=nil, extra_args=nil, force_update=false, repository_base_url=DIGG_DEFAULT_SVN_URL)
134
+ super(relativePath, repository_base_url)
135
+ cmd = "svn ls --xml #{Array(extra_args).join(" ")} #{fullpath}"
136
+ @@all_lists[fullpath] = if (force_update || @@all_lists[fullpath].nil?)
137
+ SvnCommands.new_cmd(cmd, SvnXml::Lists)
138
+ else
139
+ @@all_lists[fullpath]
140
+ end
141
+ @lists = @@all_lists[fullpath]
142
+ @entries = @lists.entries
143
+ end
144
+ end
145
+
146
+ class Log < PathOp
147
+ attr_reader :entries
148
+ @@all_entries ||= {}
149
+ def initialize(relativePath=nil, extra_args=nil, force_update=false, repository_base_url=DIGG_DEFAULT_SVN_URL)
150
+ super(relativePath, repository_base_url)
151
+ @@all_entries[fullpath] = if (force_update || @@all_entries[fullpath].nil?)
152
+ SvnCommands.new_cmd("svn log -vv --xml #{Array(extra_args).join(" ")} #{fullpath}", SvnXml::Log).entries
153
+ else
154
+ @@all_entries[fullpath]
155
+ end
156
+ @entries = @@all_entries[fullpath]
157
+ end
158
+
159
+ def messages
160
+ @messages ||= self.entries.collect { |entry| entry.msg }
161
+ end
162
+
163
+ def revisions
164
+ @revisions ||= self.entries.collect { |entry| entry.revision }
165
+ end
166
+
167
+ def oldest_revision
168
+ self.revisions.sort.first
169
+ end
170
+
171
+ def newest_revision
172
+ self.revisions.sort.last
173
+ end
174
+ end
175
+
176
+ class Update < PathOp
177
+ @@shallow_paths ||= {}
178
+ @@recursive_paths ||= {}
179
+
180
+ def updatedShallow?(path)
181
+ path_parent = File.dirname(path)
182
+ if [".","/",""].include?(path_parent)
183
+ @@shallow_paths[path] || false
184
+ else
185
+ @@shallow_paths[path] || updatedRecursive?(path_parent)
186
+ end
187
+ end
188
+
189
+ def updatedRecursive?(path)
190
+ path_parent = File.dirname(path)
191
+ if [".","/",""].include? path_parent
192
+ @@recursive_paths[path] || false
193
+ else
194
+ @@recursive_paths[path] || updatedRecursive?(path_parent)
195
+ end
196
+ end
197
+
198
+ def alreadyUpdated?(shallowUpdate)
199
+ if shallowUpdate
200
+ updatedShallow?(fullpath)
201
+ else
202
+ updatedRecursive?(fullpath)
203
+ end
204
+ end
205
+
206
+ def pretty_hash(h)
207
+ if h.kind_of?(Hash)
208
+ h.inject(nil) { |memo, kv|
209
+ key = kv[0]
210
+ val = kv[1]
211
+ (memo ? "#{memo}; " : "") + "#{key}=#{pretty_hash(val)}"
212
+ }
213
+ else
214
+ h.to_s
215
+ end
216
+ end
217
+
218
+ def updateCache(shallow)
219
+ if shallow
220
+ @@shallow_paths[fullpath] ||= 0
221
+ @@shallow_paths[fullpath] += 1
222
+ #puts "Updated shallow cache; current contents #{pretty_hash(@@shallow_paths)}"
223
+ else
224
+ @@recursive_paths[fullpath] ||= 0
225
+ @@recursive_paths[fullpath] += 1
226
+ #puts "Updated recursive cache; current contents #{pretty_hash(@@recursive_paths)}"
227
+ end
228
+ end
229
+
230
+ def ensureWorkingCopyExistsAt(aPath)
231
+ out = `svn info #{aPath}`
232
+ unless $? == 0
233
+ FileUtils.mkdir_p(aPath)
234
+ SvnCommands.new_cmd("svn co -N svn+ssh://svn.digg.internal/repository/ #{aPath.chomp("/")}")
235
+ end
236
+ end
237
+
238
+ def initialize(path, extra_args=nil, force_update=false, shallow=false, working_copy_path=DIGG_DEFAULT_WC_PATH)
239
+ super(path, working_copy_path)
240
+ cache_hit = alreadyUpdated?(shallow)
241
+ #puts "Update requested on #{path} - cache hit = #{cache_hit}"
242
+ if force_update || cache_hit == false || cache_hit.nil?
243
+ argPile = Array(extra_args)
244
+ if (shallow)
245
+ argPile << "-N"
246
+ end
247
+ argPile << fullpath
248
+ if (path == nil || path.size < 2)
249
+ ensureWorkingCopyExistsAt(working_copy_path)
250
+ else
251
+ wc_fullpath = "#{working_copy_path}/#{path}"
252
+ unless (File.exist? wc_fullpath)
253
+ # make sure our parent dir is in good shape ...
254
+ #puts "Hm, #{fullpath} doesn't exist. Calling checkOut (shallow) on #{File.dirname(relative_path)} ..."
255
+ SvnCommands::Update.new(File.dirname(path), nil, force_update, true, working_copy_path)
256
+ end
257
+ end
258
+ SvnCommands.new_cmd("svn up #{argPile.join(" ")}")
259
+ end
260
+ updateCache(shallow)
261
+ end
262
+ end
263
+
264
+ end