chocbomb 0.0.0
Sign up to get free protection for your applications and to get access to all the features.
- data/.document +5 -0
- data/LICENSE.txt +34 -0
- data/README.rdoc +34 -0
- data/Rakefile +48 -0
- data/VERSION +1 -0
- data/bin/chocbomb +7 -0
- data/lib/chocbomb/rake/tasks.rb +39 -0
- data/lib/chocbomb/tools/dmg.rb +209 -0
- data/lib/chocbomb/tools/feed.rb +104 -0
- data/lib/chocbomb/tools/images.rb +62 -0
- data/lib/chocbomb/tools/xcode.rb +9 -0
- data/lib/chocbomb.rb +151 -0
- data/templates/Rakefile.erb +13 -0
- data/templates/default_background.jpg +0 -0
- data/templates/default_volume.icns +0 -0
- data/test/helper.rb +9 -0
- data/test/ressources/default_background.jpg +0 -0
- data/test/ressources/default_background.png +0 -0
- data/test/test_chocbomb.rb +20 -0
- metadata +180 -0
data/.document
ADDED
data/LICENSE.txt
ADDED
@@ -0,0 +1,34 @@
|
|
1
|
+
Copyright (c) 2011 glejeune
|
2
|
+
|
3
|
+
Permission is hereby granted, free of charge, to any person obtaining
|
4
|
+
a copy of this software and associated documentation files (the
|
5
|
+
"Software"), to deal in the Software without restriction, including
|
6
|
+
without limitation the rights to use, copy, modify, merge, publish,
|
7
|
+
distribute, sublicense, and/or sell copies of the Software, and to
|
8
|
+
permit persons to whom the Software is furnished to do so, subject to
|
9
|
+
the following conditions:
|
10
|
+
|
11
|
+
The above copyright notice and this permission notice shall be
|
12
|
+
included in all copies or substantial portions of the Software.
|
13
|
+
|
14
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
|
15
|
+
EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
|
16
|
+
MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
|
17
|
+
NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
|
18
|
+
LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
|
19
|
+
OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
|
20
|
+
WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
21
|
+
|
22
|
+
---
|
23
|
+
|
24
|
+
A HUGE PART OF THE CODE COME FROM THE CHOCTOP PROJECT AND IS LICENCED UNDER THE MIT LICENCE :
|
25
|
+
|
26
|
+
(The MIT License)
|
27
|
+
|
28
|
+
Copyright © 2009 Dr Nic Williams, drnicwilliams@gmail.com
|
29
|
+
|
30
|
+
Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the ‘Software’), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions:
|
31
|
+
|
32
|
+
The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.
|
33
|
+
|
34
|
+
THE SOFTWARE IS PROVIDED ‘AS IS’, WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
data/README.rdoc
ADDED
@@ -0,0 +1,34 @@
|
|
1
|
+
= ChocBomb
|
2
|
+
|
3
|
+
ChocBomb is a shameful copy of ChocTop[https://github.com/drnic/choctop] - Build and deploy tools for Cocoa apps using Sparkle for distributions and upgrades; it’s like Hoe but for Cocoa apps.
|
4
|
+
|
5
|
+
== So, Why not ChocTop ?
|
6
|
+
|
7
|
+
ChocTop[https://github.com/drnic/choctop] depends on RubyCocoa. Andif it is installed on every Mac 10.5+, it can only be used with the default's ruby installation. ChocBomb can be use (but this was not tested yet ;)) with ruby 1.8/1.9, macruby, jRuby, ...
|
8
|
+
|
9
|
+
This choise don't comes without any consequences... And ChocBomb is (right now) very incomplete, compare to ChocTop!
|
10
|
+
|
11
|
+
== Contributing to ChocBomb
|
12
|
+
|
13
|
+
* Check out the latest master to make sure the feature hasn't been implemented or the bug hasn't been fixed yet
|
14
|
+
* Check out the issue tracker to make sure someone already hasn't requested it and/or contributed it
|
15
|
+
* Fork the project
|
16
|
+
* Start a feature/bugfix branch
|
17
|
+
* Commit and push until you are happy with your contribution
|
18
|
+
* Make sure to add tests for it. This is important so I don't break it in a future version unintentionally.
|
19
|
+
* Please try not to mess with the Rakefile, version, or history. If you want to have your own version, or is otherwise necessary, that is fine, but please isolate to its own commit so I can cherry-pick around it.
|
20
|
+
|
21
|
+
== Copyright
|
22
|
+
|
23
|
+
A huge part of the code come from the ChocTop[https://github.com/drnic/choctop] project and is Copyright © 2009-2011 Dr Nic Williams, drnicwilliams@gmail.com under the MIT Licence.
|
24
|
+
|
25
|
+
(The MIT License)
|
26
|
+
|
27
|
+
Copyright © 2011 Gregoire Lejeune, gregoire.lejeune@free.fr
|
28
|
+
|
29
|
+
Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the ‘Software’), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions:
|
30
|
+
|
31
|
+
The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.
|
32
|
+
|
33
|
+
THE SOFTWARE IS PROVIDED ‘AS IS’, WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
34
|
+
|
data/Rakefile
ADDED
@@ -0,0 +1,48 @@
|
|
1
|
+
require 'rubygems'
|
2
|
+
require 'rake'
|
3
|
+
|
4
|
+
require 'jeweler'
|
5
|
+
Jeweler::Tasks.new do |gem|
|
6
|
+
# gem is a Gem::Specification... see http://docs.rubygems.org/read/chapter/20 for more options
|
7
|
+
gem.name = "chocbomb"
|
8
|
+
gem.homepage = "http://github.com/glejeune/chocbomb"
|
9
|
+
gem.license = "MIT"
|
10
|
+
gem.summary = %Q{ChocBomb is a shameful copy of ChocTop}
|
11
|
+
gem.description = %Q{ChocBomb is a shameful copy of ChocTop - Build and deploy tools for Cocoa apps using Sparkle for distributions and upgrades; it’s like Hoe but for Cocoa apps.}
|
12
|
+
gem.email = "gregoire.lejeune@gmail.com"
|
13
|
+
gem.authors = ["glejeune"]
|
14
|
+
gem.add_dependency "plist", ">= 3.1.0"
|
15
|
+
gem.add_dependency "escape", ">= 0.0.4"
|
16
|
+
gem.add_dependency "builder",">=2.1.2"
|
17
|
+
gem.add_dependency "RedCloth", ">=4.2.3"
|
18
|
+
|
19
|
+
gem.add_development_dependency "jeweler", "~> 1.5.2"
|
20
|
+
gem.add_development_dependency "rcov", ">= 0"
|
21
|
+
end
|
22
|
+
Jeweler::RubygemsDotOrgTasks.new
|
23
|
+
|
24
|
+
require 'rake/testtask'
|
25
|
+
Rake::TestTask.new(:test) do |test|
|
26
|
+
test.libs << 'lib' << 'test'
|
27
|
+
test.pattern = 'test/**/test_*.rb'
|
28
|
+
test.verbose = true
|
29
|
+
end
|
30
|
+
|
31
|
+
require 'rcov/rcovtask'
|
32
|
+
Rcov::RcovTask.new do |test|
|
33
|
+
test.libs << 'test'
|
34
|
+
test.pattern = 'test/**/test_*.rb'
|
35
|
+
test.verbose = true
|
36
|
+
end
|
37
|
+
|
38
|
+
task :default => :test
|
39
|
+
|
40
|
+
require 'rake/rdoctask'
|
41
|
+
Rake::RDocTask.new do |rdoc|
|
42
|
+
version = File.exist?('VERSION') ? File.read('VERSION') : ""
|
43
|
+
|
44
|
+
rdoc.rdoc_dir = 'rdoc'
|
45
|
+
rdoc.title = "chocbomb #{version}"
|
46
|
+
rdoc.rdoc_files.include('README*')
|
47
|
+
rdoc.rdoc_files.include('lib/**/*.rb')
|
48
|
+
end
|
data/VERSION
ADDED
@@ -0,0 +1 @@
|
|
1
|
+
0.0.0
|
data/bin/chocbomb
ADDED
@@ -0,0 +1,39 @@
|
|
1
|
+
require 'chocbomb/tools/dmg'
|
2
|
+
require 'chocbomb/tools/xcode'
|
3
|
+
require 'chocbomb/tools/feed'
|
4
|
+
|
5
|
+
module ChocBomb
|
6
|
+
module Tasks
|
7
|
+
include Tools
|
8
|
+
|
9
|
+
def define_tasks
|
10
|
+
return unless Object.const_defined?("Rake")
|
11
|
+
|
12
|
+
desc "Build #{@name} #{@build_type}"
|
13
|
+
task :build => "build/#{@build_type}/#{@name}/Contents/Info.plist"
|
14
|
+
|
15
|
+
task "build/#{@build_type}/#{@name}/Contents/Info.plist" do
|
16
|
+
XCode.build(self)
|
17
|
+
end
|
18
|
+
|
19
|
+
desc "Create the dmg file"
|
20
|
+
task :dmg do
|
21
|
+
DMG.detach(self)
|
22
|
+
DMG.make(self)
|
23
|
+
DMG.detach(self)
|
24
|
+
DMG.readonly(self)
|
25
|
+
end
|
26
|
+
|
27
|
+
desc "Create feed"
|
28
|
+
task :feed do
|
29
|
+
Feed.make_appcast(self)
|
30
|
+
Feed.make_dmg_symlink(self)
|
31
|
+
Feed.make_index_redirect(self)
|
32
|
+
Feed.make_release_notes(self)
|
33
|
+
end
|
34
|
+
|
35
|
+
desc "All"
|
36
|
+
task :appcast => [:build, :dmg, :feed]
|
37
|
+
end
|
38
|
+
end
|
39
|
+
end
|
@@ -0,0 +1,209 @@
|
|
1
|
+
require 'chocbomb/tools/images'
|
2
|
+
|
3
|
+
module ChocBomb
|
4
|
+
module Tools
|
5
|
+
class DMG
|
6
|
+
attr_accessor :chocbomb
|
7
|
+
def initialize(cb)
|
8
|
+
@chocbomb = cb
|
9
|
+
@files = {}
|
10
|
+
end
|
11
|
+
|
12
|
+
def self.detach(cb)
|
13
|
+
self.new(cb).detach
|
14
|
+
end
|
15
|
+
|
16
|
+
def self.make(cb)
|
17
|
+
self.new(cb).make
|
18
|
+
end
|
19
|
+
|
20
|
+
|
21
|
+
def self.readonly(cb)
|
22
|
+
self.new(cb).readonly
|
23
|
+
end
|
24
|
+
|
25
|
+
def detach
|
26
|
+
mounted_paths = `hdiutil info | grep '#{chocbomb.volume_path}' | grep "Apple_HFS"`.split("\n").map { |e| e.split(" ").first }
|
27
|
+
mounted_paths.each do |path|
|
28
|
+
begin
|
29
|
+
sh "hdiutil detach '#{path}' -quiet -force"
|
30
|
+
rescue StandardError => e
|
31
|
+
p e
|
32
|
+
end
|
33
|
+
end
|
34
|
+
end
|
35
|
+
|
36
|
+
def make
|
37
|
+
@files = chocbomb.files.inject({}) do |files, file|
|
38
|
+
path_or_helper, options = file
|
39
|
+
path = case path_or_helper
|
40
|
+
when Symbol
|
41
|
+
chocbomb.send path_or_helper
|
42
|
+
when Proc
|
43
|
+
path_or_helper.call
|
44
|
+
else
|
45
|
+
path_or_helper
|
46
|
+
end
|
47
|
+
if path && File.exists?(path)
|
48
|
+
files[path] = options
|
49
|
+
options[:name] ||= File.basename(path)
|
50
|
+
end
|
51
|
+
files
|
52
|
+
end
|
53
|
+
|
54
|
+
FileUtils.rm_r(chocbomb.dmg_src_folder) if File.exists? chocbomb.dmg_src_folder
|
55
|
+
FileUtils.mkdir_p(chocbomb.dmg_src_folder)
|
56
|
+
|
57
|
+
@files.each do |path, options|
|
58
|
+
if options[:link]
|
59
|
+
webloc = <<-WEBLOC.gsub(/^ /, '')
|
60
|
+
<?xml version="1.0" encoding="UTF-8"?>
|
61
|
+
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
|
62
|
+
<plist version="1.0">
|
63
|
+
<dict>
|
64
|
+
<key>URL</key>
|
65
|
+
<string>#{options[:url]}</string>
|
66
|
+
</dict>
|
67
|
+
</plist>
|
68
|
+
WEBLOC
|
69
|
+
|
70
|
+
target = File.join(dmg_src_folder, options[:name])
|
71
|
+
File.new(target).print webloc
|
72
|
+
else
|
73
|
+
target = File.join(chocbomb.dmg_src_folder, options[:name])
|
74
|
+
FileUtils.copy_entry(path, target)
|
75
|
+
if options[:exclude]
|
76
|
+
exclude_list = options[:exclude].is_a?(Array) ? options[:exclude] : [options[:exclude].to_s]
|
77
|
+
exclude_list.each { |exclude| sh ::Escape.shell_command(['rm', '-rf', File.join(target, exclude)]) }
|
78
|
+
end
|
79
|
+
end
|
80
|
+
end
|
81
|
+
|
82
|
+
FileUtils.mkdir_p chocbomb.build_path
|
83
|
+
FileUtils.rm_f(chocbomb.pkg)
|
84
|
+
sh "hdiutil create -format UDRW -quiet -volname '#{chocbomb.name}' -srcfolder '#{chocbomb.dmg_src_folder}' '#{chocbomb.pkg}'"
|
85
|
+
mount
|
86
|
+
sh "bless --folder '#{chocbomb.volume_path}' --openfolder '#{chocbomb.volume_path}'"
|
87
|
+
sh "sleep 1"
|
88
|
+
|
89
|
+
# Add Volume Icon
|
90
|
+
FileUtils.cp(chocbomb.volume_icon, "#{chocbomb.volume_path}/.VolumeIcon.icns")
|
91
|
+
sh "SetFile -a C '#{chocbomb.volume_path}'"
|
92
|
+
|
93
|
+
# Configure Application Icon
|
94
|
+
Mac.applescript <<-SCRIPT.gsub(/^ /, ''), "apps_icon_script"
|
95
|
+
tell application "Finder"
|
96
|
+
set applications_folder to displayed name of (path to applications folder) -- i18n
|
97
|
+
set dest to disk "#{chocbomb.name}"
|
98
|
+
set src to folder applications_folder of startup disk
|
99
|
+
make new alias at dest to src
|
100
|
+
end tell
|
101
|
+
SCRIPT
|
102
|
+
|
103
|
+
# Configure DMG Window
|
104
|
+
if chocbomb.background_file
|
105
|
+
target_background = "#{chocbomb.volume_path}/#{chocbomb.volume_background}"
|
106
|
+
FileUtils.mkdir_p(File.dirname(target_background))
|
107
|
+
FileUtils.cp(chocbomb.background_file, target_background)
|
108
|
+
end
|
109
|
+
Mac.applescript <<-SCRIPT.gsub(/^ /, '')
|
110
|
+
tell application "Finder"
|
111
|
+
set applications_folder to displayed name of (path to applications folder) -- i18n
|
112
|
+
set mountpoint to POSIX file ("#{chocbomb.volume_path}" as string) as alias
|
113
|
+
tell folder mountpoint
|
114
|
+
open
|
115
|
+
tell container window
|
116
|
+
set toolbar visible to false
|
117
|
+
set statusbar visible to false -- doesn't do anything at DMG open time
|
118
|
+
set current view to icon view
|
119
|
+
delay 1 -- Sync
|
120
|
+
set the bounds to {#{window_bounds.join(", ")}}
|
121
|
+
end tell
|
122
|
+
delay 1 -- Sync
|
123
|
+
set icon size of the icon view options of container window to #{chocbomb.icon_size}
|
124
|
+
set text size of the icon view options of container window to #{chocbomb.icon_text_size}
|
125
|
+
set arrangement of the icon view options of container window to not arranged
|
126
|
+
#{set_position_of_files}
|
127
|
+
#{set_position_of_shortcuts}
|
128
|
+
close
|
129
|
+
open
|
130
|
+
set the bounds of the container window to {#{window_bounds.join(", ")}}
|
131
|
+
set background picture of the icon view options of container window to file "#{chocbomb.volume_background.gsub(/\//,':')}"
|
132
|
+
update without registering applications
|
133
|
+
delay 5 -- Sync
|
134
|
+
close
|
135
|
+
end tell
|
136
|
+
-- Sync
|
137
|
+
delay 5
|
138
|
+
end tell
|
139
|
+
SCRIPT
|
140
|
+
sh "SetFile -a V '#{target_background}'" if chocbomb.background_file
|
141
|
+
end
|
142
|
+
|
143
|
+
def readonly
|
144
|
+
tmp_path = "/tmp/#{chocbomb.name}-rw.dmg"
|
145
|
+
FileUtils.mv(chocbomb.pkg, tmp_path)
|
146
|
+
sh "hdiutil convert '#{tmp_path}' -format UDZO -imagekey zlib-level=9 -o '#{chocbomb.pkg}'"
|
147
|
+
end
|
148
|
+
|
149
|
+
private
|
150
|
+
def mount
|
151
|
+
sh "hdiutil attach '#{chocbomb.pkg}' -mountpoint '#{chocbomb.volume_path}' -noautoopen -quiet"
|
152
|
+
end
|
153
|
+
|
154
|
+
def window_position
|
155
|
+
[50, 100]
|
156
|
+
end
|
157
|
+
|
158
|
+
def window_bounds
|
159
|
+
window_position +
|
160
|
+
window_position.zip(background_bounds).map { |w, b| w + b }
|
161
|
+
end
|
162
|
+
|
163
|
+
def background_bounds
|
164
|
+
return [400, 300] unless chocbomb.background_file
|
165
|
+
return ChocBomb::Tools::Images.size(chocbomb.background_file)
|
166
|
+
end
|
167
|
+
|
168
|
+
def set_position_of_files
|
169
|
+
@files.map do |file_options|
|
170
|
+
path, options = file_options
|
171
|
+
target = options[:name]
|
172
|
+
position = options[:position].join(", ")
|
173
|
+
%Q{set position of item "#{target}" to {#{position}}}
|
174
|
+
end.join("\n")
|
175
|
+
end
|
176
|
+
|
177
|
+
def set_position_of_shortcuts
|
178
|
+
if include_applications_icon?
|
179
|
+
%Q{set position of item applications_folder to {#{chocbomb.applications_icon_position.join(", ")}}}
|
180
|
+
else
|
181
|
+
""
|
182
|
+
end
|
183
|
+
end
|
184
|
+
|
185
|
+
def include_applications_icon?
|
186
|
+
# target =~ /.app$/
|
187
|
+
true
|
188
|
+
end
|
189
|
+
end
|
190
|
+
|
191
|
+
module AppCast
|
192
|
+
end
|
193
|
+
|
194
|
+
module Mac
|
195
|
+
def self.applescript(applescript, tmp_file = "chocbomb-script")
|
196
|
+
File.open(scriptfile = "/tmp/#{tmp_file}", "w") do |f|
|
197
|
+
f << applescript
|
198
|
+
end
|
199
|
+
sh("osascript #{scriptfile}") do |ok, res|
|
200
|
+
if ! ok
|
201
|
+
p res
|
202
|
+
exit 1
|
203
|
+
end
|
204
|
+
end
|
205
|
+
applescript
|
206
|
+
end
|
207
|
+
end
|
208
|
+
end
|
209
|
+
end
|
@@ -0,0 +1,104 @@
|
|
1
|
+
require 'builder'
|
2
|
+
require 'RedCloth'
|
3
|
+
|
4
|
+
module ChocBomb
|
5
|
+
module Tools
|
6
|
+
class Feed
|
7
|
+
attr_accessor :chocbomb
|
8
|
+
def initialize(cb)
|
9
|
+
@chocbomb = cb
|
10
|
+
end
|
11
|
+
|
12
|
+
def self.make_appcast(cb)
|
13
|
+
self.new(cb).make_appcast
|
14
|
+
end
|
15
|
+
|
16
|
+
def self.make_dmg_symlink(cb)
|
17
|
+
self.new(cb).make_dmg_symlink
|
18
|
+
end
|
19
|
+
|
20
|
+
def self.make_index_redirect(cb)
|
21
|
+
self.new(cb).make_index_redirect
|
22
|
+
end
|
23
|
+
|
24
|
+
def self.make_release_notes(cb)
|
25
|
+
self.new(cb).make_release_notes
|
26
|
+
end
|
27
|
+
|
28
|
+
def make_appcast
|
29
|
+
FileUtils.mkdir_p(chocbomb.build_path)
|
30
|
+
appcast = File.open("#{chocbomb.build_path}/#{chocbomb.appcast_filename}", 'w') do |f|
|
31
|
+
xml = Builder::XmlMarkup.new(:indent => 2)
|
32
|
+
xml.instruct!
|
33
|
+
xml_string = xml.rss('xmlns:atom' => "http://www.w3.org/2005/Atom",
|
34
|
+
'xmlns:sparkle' => "http://www.andymatuschak.org/xml-namespaces/sparkle",
|
35
|
+
:version => "2.0") do
|
36
|
+
xml.channel do
|
37
|
+
xml.title(@name)
|
38
|
+
xml.description("#{chocbomb.name} updates")
|
39
|
+
xml.link(chocbomb.base_url)
|
40
|
+
xml.language('en')
|
41
|
+
xml.pubDate( Time.now.strftime("%a, %d %b %Y %H:%M:%S %z") )
|
42
|
+
# xml.lastBuildDate(Time.now.rfc822)
|
43
|
+
xml.atom(:link, :href => "#{chocbomb.base_url}/#{chocbomb.appcast_filename}",
|
44
|
+
:rel => "self", :type => "application/rss+xml")
|
45
|
+
|
46
|
+
xml.item do
|
47
|
+
xml.title("#{chocbomb.name} #{chocbomb.version}")
|
48
|
+
xml.tag! "sparkle:releaseNotesLink", "#{chocbomb.base_url}/#{chocbomb.release_notes}"
|
49
|
+
xml.pubDate Time.now.strftime("%a, %d %b %Y %H:%M:%S %z")
|
50
|
+
xml.guid("#{chocbomb.name}-#{chocbomb.version}", :isPermaLink => "false")
|
51
|
+
xml.enclosure(:url => "#{chocbomb.base_url}/#{chocbomb.pkg_name}",
|
52
|
+
:length => "#{File.size(chocbomb.pkg)}",
|
53
|
+
:type => "application/dmg",
|
54
|
+
:"sparkle:version" => chocbomb.version,
|
55
|
+
:"sparkle:dsaSignature" => chocbomb.dsa_signature)
|
56
|
+
end
|
57
|
+
end
|
58
|
+
end
|
59
|
+
f << xml_string
|
60
|
+
end
|
61
|
+
end
|
62
|
+
|
63
|
+
def make_dmg_symlink
|
64
|
+
if chocbomb.pkg_name != chocbomb.versionless_pkg_name
|
65
|
+
FileUtils.chdir(chocbomb.build_path) do
|
66
|
+
`rm '#{chocbomb.versionless_pkg_name}'`
|
67
|
+
`ln -s '#{chocbomb.pkg_name}' '#{chocbomb.versionless_pkg_name}'`
|
68
|
+
end
|
69
|
+
end
|
70
|
+
end
|
71
|
+
|
72
|
+
def make_index_redirect
|
73
|
+
File.open("#{chocbomb.build_path}/index.php", 'w') do |f|
|
74
|
+
f << %Q{<?php header("Location: #{chocbomb.pkg_relative_url}"); ?>}
|
75
|
+
end
|
76
|
+
end
|
77
|
+
|
78
|
+
def make_release_notes
|
79
|
+
if File.exist?(chocbomb.release_notes_template)
|
80
|
+
File.open("#{chocbomb.build_path}/#{chocbomb.release_notes}", "w") do |f|
|
81
|
+
template = File.read(chocbomb.release_notes_template)
|
82
|
+
f << ERB.new(template).result(binding)
|
83
|
+
end
|
84
|
+
end
|
85
|
+
end
|
86
|
+
|
87
|
+
def release_notes_content
|
88
|
+
if File.exists?("release_notes.txt")
|
89
|
+
File.read("release_notes.txt")
|
90
|
+
else
|
91
|
+
<<-TEXTILE.gsub(/^ /, '')
|
92
|
+
h1. #{version} #{Date.today}
|
93
|
+
|
94
|
+
h2. Another awesome release!
|
95
|
+
TEXTILE
|
96
|
+
end
|
97
|
+
end
|
98
|
+
|
99
|
+
def release_notes_html
|
100
|
+
RedCloth.new(release_notes_content).to_html
|
101
|
+
end
|
102
|
+
end
|
103
|
+
end
|
104
|
+
end
|
@@ -0,0 +1,62 @@
|
|
1
|
+
module ChocBomb
|
2
|
+
module Tools
|
3
|
+
module Images
|
4
|
+
def self.size(file)
|
5
|
+
if File.extname(file) == ".png"
|
6
|
+
png(file)
|
7
|
+
else
|
8
|
+
jpeg(file)
|
9
|
+
end
|
10
|
+
end
|
11
|
+
|
12
|
+
def self.png(file)
|
13
|
+
IO.read(file)[0x10..0x18].unpack('NN')
|
14
|
+
end
|
15
|
+
|
16
|
+
def self.jpeg(file)
|
17
|
+
j = JPEG.new(file)
|
18
|
+
[j.width, j.height]
|
19
|
+
end
|
20
|
+
|
21
|
+
class JPEG
|
22
|
+
attr_reader :width, :height, :bits
|
23
|
+
|
24
|
+
def initialize(file)
|
25
|
+
if file.kind_of? IO
|
26
|
+
examine(file)
|
27
|
+
else
|
28
|
+
File.open(file, 'rb') { |io| examine(io) }
|
29
|
+
end
|
30
|
+
end
|
31
|
+
|
32
|
+
private
|
33
|
+
def examine(io)
|
34
|
+
raise 'malformed JPEG' unless io.getc == 0xFF && io.getc == 0xD8 # SOI
|
35
|
+
|
36
|
+
class << io
|
37
|
+
def readint; (readchar << 8) + readchar; end
|
38
|
+
def readframe; read(readint - 2); end
|
39
|
+
def readsof; [readint, readchar, readint, readint, readchar]; end
|
40
|
+
def next
|
41
|
+
c = readchar while c != 0xFF
|
42
|
+
c = readchar while c == 0xFF
|
43
|
+
c
|
44
|
+
end
|
45
|
+
end
|
46
|
+
|
47
|
+
while marker = io.next
|
48
|
+
case marker
|
49
|
+
when 0xC0..0xC3, 0xC5..0xC7, 0xC9..0xCB, 0xCD..0xCF # SOF markers
|
50
|
+
length, @bits, @height, @width, components = io.readsof
|
51
|
+
raise 'malformed JPEG' unless length == 8 + components * 3
|
52
|
+
when 0xD9, 0xDA: break # EOI, SOS
|
53
|
+
when 0xFE: @comment = io.readframe # COM
|
54
|
+
when 0xE1: io.readframe # APP1, contains EXIF tag
|
55
|
+
else io.readframe # ignore frame
|
56
|
+
end
|
57
|
+
end
|
58
|
+
end
|
59
|
+
end
|
60
|
+
end
|
61
|
+
end
|
62
|
+
end
|
data/lib/chocbomb.rb
ADDED
@@ -0,0 +1,151 @@
|
|
1
|
+
require 'uri'
|
2
|
+
require 'rubygems'
|
3
|
+
require 'plist'
|
4
|
+
require 'escape'
|
5
|
+
require 'chocbomb/rake/tasks'
|
6
|
+
|
7
|
+
module ChocBomb
|
8
|
+
class Configuration
|
9
|
+
include Tasks
|
10
|
+
|
11
|
+
attr_accessor :host
|
12
|
+
attr_accessor :base_url
|
13
|
+
attr_accessor :su_feed_url
|
14
|
+
|
15
|
+
attr_accessor :release_notes
|
16
|
+
attr_accessor :private_key
|
17
|
+
|
18
|
+
# The background image
|
19
|
+
attr_accessor :background_file
|
20
|
+
|
21
|
+
# Position of the icon app
|
22
|
+
attr_accessor :app_icon_position
|
23
|
+
|
24
|
+
# Position of the Application symlink icon
|
25
|
+
attr_accessor :applications_icon_position
|
26
|
+
|
27
|
+
# Icns for the volume icon
|
28
|
+
attr_accessor :volume_icon
|
29
|
+
|
30
|
+
# Build type (Release, Debug, ...)
|
31
|
+
attr_accessor :build_type
|
32
|
+
|
33
|
+
# Target
|
34
|
+
attr_accessor :target
|
35
|
+
|
36
|
+
# Build options
|
37
|
+
attr_accessor :build_options
|
38
|
+
|
39
|
+
attr_accessor :icon_size
|
40
|
+
attr_accessor :icon_text_size
|
41
|
+
|
42
|
+
# Add an explicit file/bundle/folder into the DMG
|
43
|
+
# Examples:
|
44
|
+
# file 'build/Release/SampleApp.app', :position => [50, 100]
|
45
|
+
# file :target_bundle, :position => [50, 100]
|
46
|
+
# file proc { 'README.txt' }, :position => [50, 100]
|
47
|
+
# file :position => [50, 100] { 'README.txt' }
|
48
|
+
# Required option:
|
49
|
+
# +:position+ - two item array [x, y] window position
|
50
|
+
# Options:
|
51
|
+
# +:name+ - override the name of the project when mounted in the DMG
|
52
|
+
# +:exclude+ - do not include files/folders
|
53
|
+
def file(*args, &block)
|
54
|
+
path_or_helper, options = args.first.is_a?(Hash) ? [block, args.first] : [args.first, args.last]
|
55
|
+
throw "add_files #{path_or_helper}, :position => [x,y] option is missing" unless options[:position]
|
56
|
+
@files[path_or_helper] = options
|
57
|
+
end
|
58
|
+
|
59
|
+
# Add the whole project as a mounted item; e.g. a TextMate bundle
|
60
|
+
# Examples:
|
61
|
+
# add_link "http://github.com/drnic/choctop", :name => 'Github', :position => [50, 100]
|
62
|
+
# add_link "http://github.com/drnic/choctop", 'Github.webloc', :position => [50, 100]
|
63
|
+
# Required option:
|
64
|
+
# +:position+ - two item array [x, y] window position
|
65
|
+
# +:name+ - override the name of the project when mounted in the DMG
|
66
|
+
def link(url, *options)
|
67
|
+
name = options.first if options.first.is_a?(String)
|
68
|
+
options = options.last || {}
|
69
|
+
options[:url] = url
|
70
|
+
options[:name] = name if name
|
71
|
+
throw "add_link :position => [x,y] option is missing" unless options[:position]
|
72
|
+
throw "add_link :name => 'Name' option is missing" unless options[:name]
|
73
|
+
options[:name].gsub!(/(\.webloc|\.url)$/, '')
|
74
|
+
options[:name] += ".webloc"
|
75
|
+
self.files ||= {}
|
76
|
+
files[options[:name]] = options
|
77
|
+
end
|
78
|
+
|
79
|
+
def initialize
|
80
|
+
@plist = Plist::parse_xml(File.expand_path('Info.plist'))
|
81
|
+
@files = {}
|
82
|
+
|
83
|
+
yield self if block_given?
|
84
|
+
|
85
|
+
default
|
86
|
+
define_tasks
|
87
|
+
end
|
88
|
+
|
89
|
+
attr_reader :name
|
90
|
+
attr_reader :version
|
91
|
+
attr_reader :volume_path
|
92
|
+
attr_reader :build_path
|
93
|
+
attr_reader :pkg_name
|
94
|
+
attr_reader :pkg
|
95
|
+
attr_reader :dmg_src_folder
|
96
|
+
attr_reader :bundle
|
97
|
+
attr_reader :volume_background
|
98
|
+
|
99
|
+
attr_reader :files
|
100
|
+
|
101
|
+
attr_reader :appcast_filename
|
102
|
+
attr_reader :dsa_signature
|
103
|
+
|
104
|
+
attr_reader :versionless_pkg_name
|
105
|
+
attr_reader :pkg_relative_url
|
106
|
+
|
107
|
+
attr_reader :release_notes_template
|
108
|
+
attr_reader :release_notes
|
109
|
+
|
110
|
+
private
|
111
|
+
def default
|
112
|
+
@name = @plist['CFBundleExecutable'] || File.basename(File.expand_path("."))
|
113
|
+
@name = File.basename(File.expand_path(".")) if @name == '${EXECUTABLE_NAME}'
|
114
|
+
@version = @plist['CFBundleVersion']
|
115
|
+
|
116
|
+
@su_feed_url ||= @plist['SUFeedURL']
|
117
|
+
@base_url ||= File.dirname(su_feed_url)
|
118
|
+
@host ||= URI.parse(base_url).host
|
119
|
+
@release_notes ||= 'release_notes.html'
|
120
|
+
|
121
|
+
@background_file ||= File.expand_path(File.join(File.dirname(__FILE__), "..", "templates", "default_background.jpg"))
|
122
|
+
@app_icon_position ||= [175, 65]
|
123
|
+
@applications_icon_position ||= [347, 270]
|
124
|
+
@volume_icon ||= File.expand_path(File.join(File.dirname(__FILE__), "..", "templates", "default_volume.icns"))
|
125
|
+
@build_type ||= ENV['BUILD_TYPE'] || 'Release'
|
126
|
+
@target ||= @name
|
127
|
+
@build_options ||= ''
|
128
|
+
|
129
|
+
@icon_size ||= 104
|
130
|
+
@icon_text_size ||= 12
|
131
|
+
|
132
|
+
@volume_path = "/Volumes/#{@name}"
|
133
|
+
@build_path = "appcast/build"
|
134
|
+
@pkg_name = "#{@name}-#{@version}.dmg"
|
135
|
+
@pkg = "#{@build_path}/#{@pkg_name}"
|
136
|
+
@dmg_src_folder = "build/#{@build_type}/dmg"
|
137
|
+
@bundle = Dir["build/#{@build_type}/#{@name}.*"].first
|
138
|
+
@volume_background = ".background/background#{File.extname(@background_file)}"
|
139
|
+
file :bundle, :position => @app_icon_position
|
140
|
+
|
141
|
+
@appcast_filename ||= su_feed_url ? File.basename(su_feed_url) : 'my_feed.xml'
|
142
|
+
@private_key ||= File.expand_path('dsa_priv.pem')
|
143
|
+
@dsa_signature ||= `openssl dgst -sha1 -binary < "#{@pkg}" | openssl dgst -dss1 -sign "#{@private_key}" | openssl enc -base64`
|
144
|
+
|
145
|
+
@versionless_pkg_name = "#{@name}.dmg"
|
146
|
+
@pkg_relative_url = "#{@base_url.gsub(%r{/$}, '')}/#{@pkg_name}".gsub(%r{^.*#{@host}}, '')
|
147
|
+
|
148
|
+
@release_notes_template = "release_notes_template.html.erb"
|
149
|
+
end
|
150
|
+
end
|
151
|
+
end
|
@@ -0,0 +1,13 @@
|
|
1
|
+
require 'rubygems'
|
2
|
+
require 'rake'
|
3
|
+
|
4
|
+
require 'chocbomb'
|
5
|
+
|
6
|
+
ChocBomb::Configuration.new do |s|
|
7
|
+
# Custom DMG
|
8
|
+
# s.background_file = "background.jpg"
|
9
|
+
# s.app_icon_position = [100, 90]
|
10
|
+
# s.applications_icon_position = [400, 90]
|
11
|
+
# s.volume_icon = "dmg.icns"
|
12
|
+
# s.applications_icon = "appicon.icns" # or "appicon.png"
|
13
|
+
end
|
Binary file
|
Binary file
|
data/test/helper.rb
ADDED
Binary file
|
Binary file
|
@@ -0,0 +1,20 @@
|
|
1
|
+
require 'helper'
|
2
|
+
|
3
|
+
require 'chocbomb/tools/images'
|
4
|
+
|
5
|
+
class TestChocbomb < Test::Unit::TestCase
|
6
|
+
JPG_FILE = File.join(File.dirname(File.expand_path(__FILE__)), 'ressources', 'default_background.jpg')
|
7
|
+
PNG_FILE = File.join(File.dirname(File.expand_path(__FILE__)), 'ressources', 'default_background.png')
|
8
|
+
|
9
|
+
def test_jpg_image_size
|
10
|
+
width, height = ChocBomb::Tools::Images.size(JPG_FILE)
|
11
|
+
assert_equal(500, width)
|
12
|
+
assert_equal(400, height)
|
13
|
+
end
|
14
|
+
|
15
|
+
def test_png_image_size
|
16
|
+
width, height = ChocBomb::Tools::Images.size(PNG_FILE)
|
17
|
+
assert_equal(500, width)
|
18
|
+
assert_equal(400, height)
|
19
|
+
end
|
20
|
+
end
|
metadata
ADDED
@@ -0,0 +1,180 @@
|
|
1
|
+
--- !ruby/object:Gem::Specification
|
2
|
+
name: chocbomb
|
3
|
+
version: !ruby/object:Gem::Version
|
4
|
+
hash: 31
|
5
|
+
prerelease:
|
6
|
+
segments:
|
7
|
+
- 0
|
8
|
+
- 0
|
9
|
+
- 0
|
10
|
+
version: 0.0.0
|
11
|
+
platform: ruby
|
12
|
+
authors:
|
13
|
+
- glejeune
|
14
|
+
autorequire:
|
15
|
+
bindir: bin
|
16
|
+
cert_chain: []
|
17
|
+
|
18
|
+
date: 2011-03-25 00:00:00 +01:00
|
19
|
+
default_executable: chocbomb
|
20
|
+
dependencies:
|
21
|
+
- !ruby/object:Gem::Dependency
|
22
|
+
name: plist
|
23
|
+
prerelease: false
|
24
|
+
requirement: &id001 !ruby/object:Gem::Requirement
|
25
|
+
none: false
|
26
|
+
requirements:
|
27
|
+
- - ">="
|
28
|
+
- !ruby/object:Gem::Version
|
29
|
+
hash: 3
|
30
|
+
segments:
|
31
|
+
- 3
|
32
|
+
- 1
|
33
|
+
- 0
|
34
|
+
version: 3.1.0
|
35
|
+
type: :runtime
|
36
|
+
version_requirements: *id001
|
37
|
+
- !ruby/object:Gem::Dependency
|
38
|
+
name: escape
|
39
|
+
prerelease: false
|
40
|
+
requirement: &id002 !ruby/object:Gem::Requirement
|
41
|
+
none: false
|
42
|
+
requirements:
|
43
|
+
- - ">="
|
44
|
+
- !ruby/object:Gem::Version
|
45
|
+
hash: 23
|
46
|
+
segments:
|
47
|
+
- 0
|
48
|
+
- 0
|
49
|
+
- 4
|
50
|
+
version: 0.0.4
|
51
|
+
type: :runtime
|
52
|
+
version_requirements: *id002
|
53
|
+
- !ruby/object:Gem::Dependency
|
54
|
+
name: builder
|
55
|
+
prerelease: false
|
56
|
+
requirement: &id003 !ruby/object:Gem::Requirement
|
57
|
+
none: false
|
58
|
+
requirements:
|
59
|
+
- - ">="
|
60
|
+
- !ruby/object:Gem::Version
|
61
|
+
hash: 15
|
62
|
+
segments:
|
63
|
+
- 2
|
64
|
+
- 1
|
65
|
+
- 2
|
66
|
+
version: 2.1.2
|
67
|
+
type: :runtime
|
68
|
+
version_requirements: *id003
|
69
|
+
- !ruby/object:Gem::Dependency
|
70
|
+
name: RedCloth
|
71
|
+
prerelease: false
|
72
|
+
requirement: &id004 !ruby/object:Gem::Requirement
|
73
|
+
none: false
|
74
|
+
requirements:
|
75
|
+
- - ">="
|
76
|
+
- !ruby/object:Gem::Version
|
77
|
+
hash: 49
|
78
|
+
segments:
|
79
|
+
- 4
|
80
|
+
- 2
|
81
|
+
- 3
|
82
|
+
version: 4.2.3
|
83
|
+
type: :runtime
|
84
|
+
version_requirements: *id004
|
85
|
+
- !ruby/object:Gem::Dependency
|
86
|
+
name: jeweler
|
87
|
+
prerelease: false
|
88
|
+
requirement: &id005 !ruby/object:Gem::Requirement
|
89
|
+
none: false
|
90
|
+
requirements:
|
91
|
+
- - ~>
|
92
|
+
- !ruby/object:Gem::Version
|
93
|
+
hash: 7
|
94
|
+
segments:
|
95
|
+
- 1
|
96
|
+
- 5
|
97
|
+
- 2
|
98
|
+
version: 1.5.2
|
99
|
+
type: :development
|
100
|
+
version_requirements: *id005
|
101
|
+
- !ruby/object:Gem::Dependency
|
102
|
+
name: rcov
|
103
|
+
prerelease: false
|
104
|
+
requirement: &id006 !ruby/object:Gem::Requirement
|
105
|
+
none: false
|
106
|
+
requirements:
|
107
|
+
- - ">="
|
108
|
+
- !ruby/object:Gem::Version
|
109
|
+
hash: 3
|
110
|
+
segments:
|
111
|
+
- 0
|
112
|
+
version: "0"
|
113
|
+
type: :development
|
114
|
+
version_requirements: *id006
|
115
|
+
description: "ChocBomb is a shameful copy of ChocTop - Build and deploy tools for Cocoa apps using Sparkle for distributions and upgrades; it\xE2\x80\x99s like Hoe but for Cocoa apps."
|
116
|
+
email: gregoire.lejeune@gmail.com
|
117
|
+
executables:
|
118
|
+
- chocbomb
|
119
|
+
extensions: []
|
120
|
+
|
121
|
+
extra_rdoc_files:
|
122
|
+
- LICENSE.txt
|
123
|
+
- README.rdoc
|
124
|
+
files:
|
125
|
+
- .document
|
126
|
+
- LICENSE.txt
|
127
|
+
- README.rdoc
|
128
|
+
- Rakefile
|
129
|
+
- VERSION
|
130
|
+
- bin/chocbomb
|
131
|
+
- lib/chocbomb.rb
|
132
|
+
- lib/chocbomb/rake/tasks.rb
|
133
|
+
- lib/chocbomb/tools/dmg.rb
|
134
|
+
- lib/chocbomb/tools/feed.rb
|
135
|
+
- lib/chocbomb/tools/images.rb
|
136
|
+
- lib/chocbomb/tools/xcode.rb
|
137
|
+
- templates/Rakefile.erb
|
138
|
+
- templates/default_background.jpg
|
139
|
+
- templates/default_volume.icns
|
140
|
+
- test/helper.rb
|
141
|
+
- test/ressources/default_background.jpg
|
142
|
+
- test/ressources/default_background.png
|
143
|
+
- test/test_chocbomb.rb
|
144
|
+
has_rdoc: true
|
145
|
+
homepage: http://github.com/glejeune/chocbomb
|
146
|
+
licenses:
|
147
|
+
- MIT
|
148
|
+
post_install_message:
|
149
|
+
rdoc_options: []
|
150
|
+
|
151
|
+
require_paths:
|
152
|
+
- lib
|
153
|
+
required_ruby_version: !ruby/object:Gem::Requirement
|
154
|
+
none: false
|
155
|
+
requirements:
|
156
|
+
- - ">="
|
157
|
+
- !ruby/object:Gem::Version
|
158
|
+
hash: 3
|
159
|
+
segments:
|
160
|
+
- 0
|
161
|
+
version: "0"
|
162
|
+
required_rubygems_version: !ruby/object:Gem::Requirement
|
163
|
+
none: false
|
164
|
+
requirements:
|
165
|
+
- - ">="
|
166
|
+
- !ruby/object:Gem::Version
|
167
|
+
hash: 3
|
168
|
+
segments:
|
169
|
+
- 0
|
170
|
+
version: "0"
|
171
|
+
requirements: []
|
172
|
+
|
173
|
+
rubyforge_project:
|
174
|
+
rubygems_version: 1.5.0
|
175
|
+
signing_key:
|
176
|
+
specification_version: 3
|
177
|
+
summary: ChocBomb is a shameful copy of ChocTop
|
178
|
+
test_files:
|
179
|
+
- test/helper.rb
|
180
|
+
- test/test_chocbomb.rb
|