Files
totalterminal/rakefile
2012-11-17 21:06:39 +01:00

447 lines
14 KiB
Plaintext

ROOT_DIR = File.expand_path('.')
TMP_ROOT = '/tmp'
TMP_DIR = File.join(TMP_ROOT, 'totalterminal')
BUILD_DIR = File.join(ROOT_DIR, 'build')
RELEASE_DIR = File.join(ROOT_DIR, 'release')
INSTALLER_DIR = File.join(ROOT_DIR, 'installer')
PAYLOADS_DIR = File.join(ROOT_DIR, 'payloads')
PARENT_DIR = File.expand_path('..')
PLUGIN_BUNDLE = "TotalTerminal.bundle"
XCODE_WORKSPACE = File.join(ROOT_DIR, 'TotalTerminal.xcworkspace')
SPARKLE_DIR = File.join(ROOT_DIR, 'sparkle')
OSAX_DIR = File.join(PARENT_DIR, 'totalterminal-osax')
I18N_DIR = File.join(PARENT_DIR, 'totalterminal-i18n')
TMP_GIT_MODULES = File.join(TMP_DIR, '.gitmodules')
TMP_TOTALTERMINAL_RESOURCES = File.join(TMP_DIR, 'totalterminal-i18n', 'plugin')
TMP_TOTALTERMINAL_DIR = File.join(TMP_DIR, 'totalterminal-plugin')
TMP_BIN_DIR = File.join(TMP_DIR, 'bin')
TMP_BIN_TOTALTERMINAL_FRAMEWORKS = File.join(TMP_BIN_DIR, 'TotalTerminal.osax/Contents/Resources/TotalTerminal.bundle/Contents/Frameworks')
PLUGIN_INFO_PLIST = File.join(TMP_DIR, 'totalterminal-plugin', 'Info.plist')
PLUGIN_VISOR_M = File.join(TMP_DIR, 'totalterminal-plugin', 'TotalTerminal.mm')
PLUGIN_PREFERENCES_MM = File.join(TMP_DIR, 'totalterminal-plugin', 'TotalTerminal+Preferences.mm')
PLUGIN_VISOR_XIB = File.join(TMP_DIR, 'totalterminal-i18n', 'plugin', 'TotalTerminal.xib')
OSAX_INFO_PLIST = File.join(TMP_DIR, 'totalterminal-osax', 'Info.plist')
CRASHWATCHER_INFO_PLIST = File.join(TMP_DIR, 'crashwatcher', 'CrashWatcher-Info.plist')
PUBLISH_PREFIX_URL = "http://downloads.binaryage.com"
CHANGELOG_PREFIX_URL = "http://totalterminal.binaryage.com"
################################################################################################
# dependencies
begin
require 'colored'
rescue LoadError
raise 'You must "gem install colored" to use terminal colors'
end
def file_color(text); text.yellow; end
def dir_color(text); text.blue; end
def cmd_color(text); text.magenta; end
############################################################################################
def die(msg, status=1)
puts "Error[#{status||$?}]: #{msg}".red
exit status||$?
end
def version()
$version = ENV["version"] or die("specify version")
end
def revision()
$revision = `git rev-parse HEAD`.strip
$short_revision = $revision[0...7]
end
def dirty_repo_warning()
is_clean = `git status`.match(/working directory clean/)
puts "Repository is not clean! You should commit all changes before releasing.".red unless is_clean
end
def patch(path, replacers)
puts "#{cmd_color('Patching')} #{file_color(path)}"
lines = []
File.open(path, "r") do |f|
f.each do |line|
replacers.each do |r|
line.gsub!(r[0], r[1])
end
lines << line
end
end
File.open(path, "w") do |f|
f << lines.join
end
end
def announce(cmd)
puts "> " + cmd.yellow
end
def sys(cmd)
announce(cmd)
system(cmd)
end
############################################################################################
def generate_payload_for_pkg(tmp, pkg)
tree = ""
exes = ""
tmp2 = File.join(tmp, "payload-extractor")
sys("rm -rf \"#{tmp2}\"") if File.exist? tmp2
sys("mkdir -p \"#{tmp2}\"")
sys("cp \"#{pkg}\" \"#{tmp2}\"")
name = File.basename pkg
Dir.chdir(tmp2) do
sys("xar -xf \"#{name}\"")
Dir.chdir("TotalTerminal_Plugin.pkg") do
if (File.exist? "Payload") then
sys("mv Payload Payload.gz")
sys("gunzip Payload.gz")
sys("cpio -id < Payload")
end
tree = `tree --dirsfirst -apsugif`
exes = ""
Dir.glob("**/MacOS/*") do |exe|
exes += `file "#{exe}"` + "\n"
end
end
end
res = ""
res << "\n"
res << "#{name}\n"
res << "=======================================================================\n"
res << tree
res << "\n"
res << exes
res
end
def generate_payload(dmg, out)
puts "Generating payload for: ".green + dmg.blue
volume = "/Volumes/TotalTerminal"
tmp = File.join(TMP_DIR, "payloads", File.basename(dmg, ".dmg"))
sys("rm -rf \"#{tmp}\"") if File.exist? tmp
sys("mkdir -p \"#{tmp}\"")
puts dmg
cmd = "hdiutil attach \"#{dmg}\" | grep Apple_partition_scheme"
announce(cmd)
res = `#{cmd}`
puts res
disk = res.split("\n")[0].split("\t")[0]
die("bad disk") unless disk =~ /\/dev/
sys("cp -r #{volume}/* \"#{tmp}\"")
tree1 = ""
Dir.chdir(tmp) do
tree1 = `tree --dirsfirst -apsugif`
end
pkgs = []
Dir.glob(File.join(tmp, "**/*.pkg")) do |pkg|
pkgs << generate_payload_for_pkg(tmp, pkg)
end
outdir = File.dirname out
`mkdir -p #{outdir}` unless File.exist? outdir
File.open(out, "w") do |f|
f << "BASIC DMG LAYOUT\n"
f << "================\n"
f << tree1
pkgs.each do |pkg|
f << pkg
end
end
puts " -> ".green + out.blue
sys("hdiutil detach #{disk}")
end
def retag_submodule(tags, submodule)
tags.each do |tag|
x = `git ls-tree #{tag} #{submodule}`
sha = x.split(" ")[2]
Dir.chdir(submodule) do
sha = `git log --reverse`.split("\n")[0].split(" ")[1] unless sha # take first commit in case submodule wasn't defined at this point
sys("git tag -d #{tag}")
puts "#{tag} #{sha}"
sys("git tag #{tag} #{sha}")
end
end
Dir.chdir(submodule) do
sys("git push --tags")
end
end
def release_version_from_filename(n) # /Users/darwin/code/totalterminal/payloads/TotalTerminal-0.7.1.txt
p = File.basename(n, ".txt").split("-")[1]
n = p.split(".")
while n.size < 3 do
n << "0"
end
x = (n[0]||"0").to_i
y = (n[1]||"0").to_i
z = (n[2]||"0").to_i
x*1000000 + y*1000 + z
end
def patch_gitmodules
patch(TMP_GIT_MODULES, [
['git://github.com/binaryage', ROOT_DIR],
['.git', '']
])
end
###################################################################################################################
desc "opens XCode project"
task :open do
`open "#{XCODE_WORKSPACE}"`
end
desc "prepare stage"
task :stage do
puts "#{cmd_color('Cloning sources to stage ...')}"
`rm -rf "#{TMP_DIR}"`
`mkdir -p "#{TMP_ROOT}"`
Dir.chdir(TMP_ROOT) do
`git clone #{ROOT_DIR}`
end
puts "#{cmd_color('Initializing submodules ...')}"
Dir.chdir(TMP_DIR) do
`git reset --hard HEAD`
patch_gitmodules
`git submodule update --init --recursive`
end
end
desc "prepares release build"
task :release do
unless File.exists?(TMP_DIR) then die('Doing it for first time? => rake stage') end
puts "#{cmd_color('Checking environment ...')}"
dirty_repo_warning()
version()
revision()
mkdir_p(RELEASE_DIR) unless File.exists? RELEASE_DIR
unless ENV["fast"] then
puts "#{cmd_color('Updating stage ...')}"
Dir.chdir(TMP_DIR) do
sys('git clean -fd')
sys('git reset --hard HEAD^') # use previous commit to make working tree resilient to amends
sys('git submodule foreach --recursive "git clean -fd"')
sys('git submodule foreach --recursive "git reset --hard HEAD"')
sys('git submodule update --recursive --checkout')
sys('git pull --ff-only')
patch_gitmodules
sys('git submodule update --recursive --checkout')
end
puts "#{cmd_color('Patching version info ...')}"
patch(PLUGIN_VISOR_XIB, [['##VERSION##', $version], ['##REVISION##', $short_revision]])
patch(PLUGIN_INFO_PLIST, [['##VERSION##', $version], ['##REVISION##', $short_revision]])
patch(PLUGIN_VISOR_M, [['##VERSION##', $version], ['##REVISION##', $short_revision], ['##SHA##', $revision]])
patch(PLUGIN_PREFERENCES_MM, [['##VERSION##', $version], ['##REVISION##', $short_revision], ['##SHA##', $revision]])
patch(OSAX_INFO_PLIST, [['##VERSION##', $version], ['##REVISION##', $short_revision]])
patch(OSAX_INFO_PLIST, [['##VERSION##', $version], ['##REVISION##', $short_revision]])
patch(CRASHWATCHER_INFO_PLIST, [['##VERSION##', $version], ['##REVISION##', $short_revision]])
Dir.chdir(TMP_DIR) do
unless ENV["noclean"] then
puts "#{cmd_color('Cleaning')} #{file_color(TMP_TOTALTERMINAL_DIR)}"
sys('xcodebuild -workspace TotalTerminal.xcworkspace -scheme "TotalTerminal Package" -configuration Release clean')
end
puts "#{cmd_color('Building')} #{file_color(TMP_TOTALTERMINAL_DIR)}"
sys('xcodebuild -workspace TotalTerminal.xcworkspace -scheme "TotalTerminal Package" -configuration Release')
die("build failed") unless $?==0
end
Dir.glob(File.join(TMP_BIN_TOTALTERMINAL_FRAMEWORKS, "*")) do |framework|
patch(File.join(framework, 'Resources', 'Info.plist'), [['##VERSION##', $version], ['##REVISION##', $short_revision]])
end
end
releasedmg = File.join(RELEASE_DIR, "TotalTerminal-#{$version}.dmg")
sys("rm -rf \"#{releasedmg}\"") if File.exist? releasedmg
die("build failed") unless $?==0
Dir.chdir(File.join(TMP_DIR, "totalterminal-installer")) do
sys("rake build version=#{$version} products=\"../bin\" release=\"#{RELEASE_DIR}\"")
die("installer build failed") unless $?==0
end
size = File.size(releasedmg)
sig = `ruby "sparkle/sign_update.rb" "#{releasedmg}" keys/dsa_priv.pem`.strip
die("build failed") unless $?==0
snippet = "\
<item>
<title>Version #{$version}</title>
<sparkle:releaseNotesLink>#{CHANGELOG_PREFIX_URL}/changelog-beta.html</sparkle:releaseNotesLink>
<pubDate>#{Time.new}</pubDate>
<enclosure url=\"#{PUBLISH_PREFIX_URL}/TotalTerminal-#{$version}.dmg\" sparkle:version=\"#{$version}\" length=\"#{size}\" type=\"application/octet-stream\" sparkle:dsaSignature=\"#{sig}\"/>
<sparkle:minimumSystemVersion>10.6.0</sparkle:minimumSystemVersion>
</item>"
puts snippet
puts
puts "Don't forget: ".red
puts " git tag -a v#{$version} -m \"Release #{$version}\"".green
puts " test sparkle updating on it via touch ~/.use-test-appcast, see totalterminal-plugin/TotalTerminal+Sparkle.mm"
puts "#{PUBLISH_PREFIX_URL}/TotalTerminal-#{$version}.dmg".blue
# Dir.chdir(ROOT_DIR) do
# sys("mkdir -p ttdata")
# sys("mount -t smbfs //guest:@whale/Store/ttdata ttdata")
# sys("rsync -av --delete release ttdata")
# sys("umount ttdata")
# sys("rm -rf ttdata")
# end
end
desc "removes intermediate build files"
task :clean do
puts "#{cmd_color('Removing')} #{dir_color(TMP_DIR)}"
`rm -rf "#{TMP_DIR}"`
end
desc "removes all release builds"
task :purge do
puts "#{cmd_color('Removing')} #{dir_color(RELEASE_DIR)}"
`rm -rf "#{RELEASE_DIR}"`
end
desc "beautify sources using uncrustify => see uncrustify.cfg"
task :beautify do
config = File.join(ROOT_DIR, 'configs', 'uncrustify.cfg')
what = ENV["filter"] || "*"
base = File.join(ROOT_DIR, "totalterminal-plugin")
Dir.glob(File.join(base, "**/#{what}")) do |file|
next unless file=~/\.(mm|m|c|h|cc|cpp|hpp)$/
puts file[base.size+1..-1]
`uncrustify -c "#{config}" --replace --no-backup --mtime "#{file}"`
end
end
desc "build missing payloads"
task :payload do
Dir.chdir(RELEASE_DIR) do
Dir.glob("*.dmg").each do |file|
name = File.basename(file, ".dmg")
dest = File.join(PAYLOADS_DIR, name+".txt")
unless File.exist? dest then
generate_payload(file, dest)
end
end
end
end
desc "diff two most recent payloads"
task :paydiff do
res = `ls -1 "#{PAYLOADS_DIR}"/*.txt`
res = res.split("\n")
res = res.sort do |a, b|
va = release_version_from_filename a
vb = release_version_from_filename b
vb<=>va
end
a = res[1]
b = res[0]
`ksdiff "#{a}" "#{b}"`
end
desc "update tags in submodules v1.0+"
task :retag do
tags = `git tag`.split("\n").reject {|x| x =~ /^v0/ } # skip v0.x.x
puts "found #{tags.size} tags..."
retag_submodule(tags, "totalterminal-i18n")
retag_submodule(tags, "totalterminal-installer")
retag_submodule(tags, "totalterminal-osax")
# NO! retag_submodule(tags, "crashwatcher") # crashwatcher is shared between TotalTerminal and TotalFinder
# NO! retag_submodule(tags, "sparkle") # sparkle is shared between TotalTerminal and TotalFinder
`git push --tags`
end
desc "pull all"
task :pull do
Dir.chdir("totalterminal-i18n") do
puts "in " + Dir.pwd
sys("git pull")
end
Dir.chdir("totalterminal-installer") do
puts "in " + Dir.pwd
sys("git pull")
end
Dir.chdir("totalterminal-osax") do
puts "in " + Dir.pwd
sys("git pull")
end
Dir.chdir("sparkle") do
puts "in " + Dir.pwd
sys("git pull")
end
Dir.chdir("crashwatcher") do
puts "in " + Dir.pwd
sys("git pull")
end
puts "in " + Dir.pwd
sys("git pull")
end
desc "push all"
task :push do
Dir.chdir("totalterminal-i18n") do
puts "in " + Dir.pwd
sys("git push")
end
Dir.chdir("totalterminal-installer") do
puts "in " + Dir.pwd
sys("git push")
end
Dir.chdir("totalterminal-osax") do
puts "in " + Dir.pwd
sys("git push")
end
Dir.chdir("sparkle") do
puts "in " + Dir.pwd
sys("git push")
end
Dir.chdir("crashwatcher") do
puts "in " + Dir.pwd
sys("git push")
end
puts "in " + Dir.pwd
sys("git push")
end
task :default => :open