-
Notifications
You must be signed in to change notification settings - Fork 17
/
Rakefile
446 lines (345 loc) · 12.1 KB
/
Rakefile
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
# ===========================================================================
# Project: Abbot - SproutCore Build Tools
# Copyright: ©2009 Apple Inc.
# portions copyright @2006-2009 Sprout Systems, Inc.
# and contributors
# ===========================================================================
# Rakefile used to build the SproutCore Gem. Requires Jeweler to function.
ROOT_PATH = File.dirname(__FILE__)
# files to ignore changes in
IGNORE_CHANGES = %w[.gitignore .gitmodules .DS_Store .gemspec VERSION.yml ^pkg ^tmp ^coverage]
# Get the DISTRIBUTION info
require 'yaml'
DIST_PATH = File.expand_path(File.join(ROOT_PATH, 'DISTRIBUTION.yml'))
DIST = YAML.load File.read(DIST_PATH)
LOCAL_DIST_PATH = File.expand_path(File.join(ROOT_PATH, 'LOCAL.yml'))
if File.exists? LOCAL_DIST_PATH
# merged each item in the top level hash. This allows for key-by-key
# overrides
(YAML.load(File.read(LOCAL_DIST_PATH)) || {}).each do |key, opts|
if DIST[key]
DIST[key].merge! opts
else
DIST[KEY] = opts
end
end
puts "Using local overrides for distribution"
end
REMOTE_NAME = 'dist' # used by git
# Make empty to not use sudo
SUDO = 'sudo'
################################################
## LOAD DEPENDENCIES
##
# Core dependencies. Just warn if these are not available
begin
require 'rubygems'
require 'extlib'
require 'fileutils'
require 'spec/rake/spectask'
$:.unshift(ROOT_PATH / 'lib')
require 'sproutcore'
rescue LoadError => e
$stderr.puts "WARN: some required gems are not installed (try rake init to setup)"
$stderr.puts e
end
################################################
## JEWELER PROJECT DESCRIPTION
##
namespace :gem do
task :clean do
system "rm *.gem"
end
desc "build the sproutcore gem"
task :build => :clean do
system "gem build sproutcore.gemspec"
end
desc "install the sproutcore gem to the system"
task :install => :build do
gem = Dir["*.gem"][0]
system "gem install #{gem}"
end
desc "push the sproutcore gem to rubygems.org"
task :push => :build do
gem = Dir["*.gem"][0]
system "gem push #{gem}"
end
end
################################################
## CORE TASKS
##
# git helper used to run git from within rake.
def git(path, cmd, log=true)
$stdout.puts("#{path.sub(ROOT_PATH, '')}: git #{cmd}") if log
git_path = path / '.git'
git_index = git_path / 'index'
# The env can become polluted; breaking git. This will avoid that.
%x[GIT_DIR=#{git_path}; GIT_WORK_TREE=#{path}; GIT_INDEX_FILE=#{git_index}; git #{cmd}]
end
desc "performs an initial setup on the tools. Installs gems, checkout"
task :init => [:install_gems, 'dist:init']
desc "verifies that all required gems are installed"
task :install_gems do
$stdout.puts "Installing gems (may ask for password)"
gem_names = %w(rack json json_pure extlib erubis thor jeweler gemcutter rspec)
gem_install = []
gem_update = []
# detect which ones are installed and update those
gem_names.each do |name|
if %x[gem list #{name}] =~ /#{Regexp.escape(name)} \(/
gem_update << name
else
gem_install << name
end
end
$stdout.puts "installing gems #{gem_install * ' '}" if gem_install.size>0
$stdout.puts "updating gems #{gem_update * ' '}" if gem_update.size>0
# install missing gems - updating known gems
# this is faster than just installing all gems
system %[#{SUDO} gem install #{gem_install * ' '}]
system %[#{SUDO} gem update #{gem_update * ' '}]
end
namespace :dist do
desc "checkout any frameworks in the distribution"
task :init do
$stdout.puts "Setup distribution"
DIST.each do |rel_path, opts|
path = ROOT_PATH / rel_path
repo_url = opts['repo']
dist_branch = opts['branch'] || 'master'
# if the .git repository does not exist yet, create it
if !File.exists?(path / ".git")
$stdout.puts " Creating repo for #{rel_path}"
FileUtils.mkdir_p path
$stdout.puts "\n> git clone #{repo_url} #{path}"
system "GIT_DIR=#{path / '.git'}; GIT_WORK_TREE=#{path}; git init"
end
# if git exists, make sure a "dist" remote exists and matches the named
# remote
remote = git(path, 'remote -v').split("\n").find do |l|
l =~ /^#{REMOTE_NAME}.+\(fetch\)/
end
if remote
cur_repo_url = remote.match(/^#{REMOTE_NAME}(.+)\(fetch\)/)[1].strip
if (cur_repo_url != repo_url)
$stdout.puts "ERROR: #{rel_path} has a 'dist' remote pointing to a different repo. Please remove the 'dist' remote and try again"
exit(1)
else
$stdout.puts "Found #{rel_path}:dist => #{repo_url}"
end
# remote does not yet exist, add it...
else
$stdout.puts git(path,"remote add dist #{repo_url}")
end
$stdout.puts git(path, "fetch dist")
# Make sure a "dist" branch exists.. if not checkout against the
# dist branch
if git(path, 'branch') =~ /dist\n/
$stdout.puts "WARN: #{rel_path}:dist branch already exists. delete branch and try again if you aren't sure it is setup properly"
else
git(path,"branch dist remotes/dist/#{dist_branch}")
end
git(path, "checkout dist")
end
end
desc "Make sure each repository in the distribute is set to the target remote branch and up-to-date"
task :update => 'dist:init' do
$stdout.puts "Setup distribution"
DIST.each do |rel_path, opts|
path = ROOT_PATH / rel_path
branch = opts['branch'] || 'master'
if File.exists?(path / ".git")
$stdout.puts "\n> git checkout dist"
$stdout.puts git(path, "checkout dist")
$stdout.puts "\n> git fetch dist"
$stdout.puts git(path, 'fetch dist')
$stdout.puts "\n> git rebase remotes/dist/#{branch}"
$stdout.puts git(path, "rebase remotes/dist/#{branch}")
else
$stdout.puts "WARN: cannot fix version for #{rel_path}"
end
end
end
desc "make the version of each distribution item match the one in VERSION"
task :freeze => 'dist:init' do
$stdout.puts "Setup distribution"
# Use this to get the commit hash
version_file = ROOT_PATH / 'VERSION.yml'
if File.exist?(version_file)
versions = YAML.load File.read(version_file)
versions = (versions['dist'] || versions[:dist]) if versions
versions ||= {}
end
DIST.each do |rel_path, opts|
path = ROOT_PATH / rel_path
if File.exists?(path / ".git") && versions[rel_path]
sha = versions[rel_path]
$stdout.puts "\n> git fetch"
$stdout.puts git(path, 'fetch')
if sha
$stdout.puts "\n> git checkout #{sha}"
$stdout.puts git(path, "checkout #{sha}")
end
else
$stdout.puts "WARN: cannot fix version for #{rel_path}"
end
end
end
end
namespace :release do
desc "tags the current repository and any distribution repositories. if you can push to distribution, then push tag as well"
task :tag => :update_version do
tag_name = "REL-#{RELEASE_VERSION}"
DIST.keys.push('abbot').each do |rel_path|
full_path = rel_path=='abbot' ? ROOT_PATH : (ROOT_PATH / rel_path)
git(full_path, "tag -f #{tag_name}")
end
end
task :push_tags => :tag do
tag_name = "REL-#{RELEASE_VERSION}"
DIST.keys.push('abbot').each do |rel_path|
full_path = rel_path=='abbot' ? ROOT_PATH : (ROOT_PATH / rel_path)
git(full_path, "push origin #{tag_name}")
end
end
desc "prepare release. verify clean, update version, tag"
task :prepare => ['git:verify_clean', :update_version, :tag, :push_tags]
desc "release to rubyforge for old skool folks"
task :rubyforge => [:prepare, 'rubyforge:release']
desc "release to gemcutter for new skool kids"
task :gemcutter => [:prepare, 'gemcutter:release']
desc "one release to rule them all"
task :all => [:prepare, 'release:gemcutter']
end
desc "computes the current hash of the code. used to autodetect build changes"
task :hash_content do
require 'yaml'
require 'digest/md5'
ignore = IGNORE_CHANGES.map do |x|
if x =~ /^\^/
/^#{Regexp.escape(ROOT_PATH / x[1..-1])}/
else
/#{Regexp.escape(x)}/
end
end
# First, get the hashinfo if it exists. use this to decide if we need to
# rehash
hashinfo_path = ROOT_PATH / '.hashinfo.yml'
hash_date = 0
hash_digest = nil
if File.exist?(hashinfo_path)
yaml = YAML.load_file(hashinfo_path)
hash_date = yaml['date'] || yaml[:date] || hash_date
hash_digest = yaml['digest'] || yaml[:digest] || hash_digest
end
# paths to search
paths = Dir.glob(File.join(ROOT_PATH, '**', '*')).reject do |path|
File.directory?(path) || (ignore.find { |i| path =~ i })
end
cur_date = 0
paths.each do |path|
mtime = File.mtime(path)
mtime = mtime.nil? ? 0 : mtime.to_i
$stdout.puts "detected file change: #{path.gsub(ROOT_PATH,'')}" if mtime > hash_date
cur_date = mtime if mtime > cur_date
end
if hash_digest.nil? || (cur_date != hash_date)
digests = paths.map do |path|
Digest::SHA1.hexdigest(File.read(path))
end
digests.compact!
hash_digest = Digest::SHA1.hexdigest(digests.join)
end
hash_date = cur_date
# write cache
File.open(hashinfo_path, 'w+') do |f|
YAML.dump({ :date => hash_date, :digest => hash_digest }, f)
end
# finally set the hash
CONTENT_HASH = hash_digest
$stdout.puts "CONTENT_HASH = #{CONTENT_HASH}"
end
desc "updates the VERSION file, bumbing the build rev if the current commit has changed"
task :update_version => 'hash_content' do
path = ROOT_PATH / 'VERSION.yml'
require 'yaml'
# first, load the current yaml if possible
major = 1
minor = 0
build = 99
rev = '-0-'
dist = {}
if File.exist?(path)
yaml = YAML.load_file(path)
major = yaml['major'] || yaml[:major] || major
minor = yaml['minor'] || yaml[:minor] || minor
build = yaml['patch'] || yaml[:patch] || build
rev = yaml['digest'] || yaml[:digest] || rev
end
build += 1 if rev != CONTENT_HASH #increment if needed
rev = CONTENT_HASH
# Update distribution versions
DIST.each do |rel_path, ignored|
dist_path = ROOT_PATH / rel_path
if File.exists?(dist_path)
dist_rev = git(dist_path, "log HEAD^..HEAD")
dist_rev = dist_rev.split("\n").first.scan(/commit ([^\s]+)/)
dist_rev = ((dist_rev || []).first || []).first
if dist_rev.nil?
$stdout.puts " WARN: cannot find revision for #{rel_path}"
else
dist[rel_path] = dist_rev
end
end
end
$stdout.puts "write version #{[major, minor, build].join('.')} => #{path}"
File.open(path, 'w+') do |f|
YAML.dump({
:major => major,
:minor => minor,
:patch => build,
:digest => rev,
:dist => dist
}, f)
end
RELEASE_VERSION = "#{major}.#{minor}.#{build}"
end
desc "cleanup the pkg dir"
task :clean do
path = ROOT_PATH / 'pkg'
FileUtils.rm_r(path) if File.directory?(path)
`rm #{ROOT_PATH / '*.gem'}`
end
namespace :git do
desc "verifies there are no pending changes to commit to git"
task :verify_clean do
DIST.keys.push('abbot').each do |repo_name|
full_path = repo_name=='abbot' ? ROOT_PATH : (ROOT_PATH / repo_name)
result = git(full_path, 'status')
if !(result =~ /nothing to commit \(working directory clean\)/)
if (repo_name != 'abbot') ||
(!(result =~ /#\n#\tmodified: VERSION.yml\n#\n/))
$stderr.puts "\nFATAL: Cannot complete task: changes are still pending in the '#{repo_name}' repository."
$stderr.puts " Commit your changes to git to continue.\n\n"
exit(1)
end
end
end
end
desc "Collects the current SHA1 commit hash into COMMIT_ID"
task :collect_commit do
log = `git log HEAD^..HEAD`
COMMIT_ID = log.split("\n").first.match(/commit ([\w]+)/).to_a[1]
if COMMIT_ID.empty?
$stderr.puts "\nFATAL: Cannot discover current commit id"
exit(1)
else
$stdout.puts "COMMIT_ID = #{COMMIT_ID}"
end
end
end
# Write a new version everytime we generate
task 'gemspec:generate' => :update_version
task 'rubyforge:setup' => :update_version
Spec::Rake::SpecTask.new
# EOF