choctop 0.11.1 → 0.12.0
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.
- data/History.txt +11 -6
- data/Manifest.txt +2 -0
- data/README.rdoc +9 -7
- data/Rakefile +1 -2
- data/app_generators/install_choctop/templates/Rakefile.erb +1 -1
- data/features/dmg.feature +0 -25
- data/features/rake_tasks.feature +12 -13
- data/features/step_definitions/dmg_steps.rb +1 -7
- data/features/step_definitions/xcode_steps.rb +1 -1
- data/features/support/env.rb +3 -1
- data/lib/choctop.rb +248 -242
- data/lib/choctop/appcast.rb +112 -105
- data/lib/choctop/dmg.rb +181 -177
- data/lib/choctop/rake_tasks.rb +74 -0
- data/lib/choctop/version_helper.rb +66 -0
- data/spec/choctop_spec.rb +22 -39
- metadata +78 -24
data/lib/choctop/appcast.rb
CHANGED
@@ -1,118 +1,125 @@
|
|
1
|
-
module ChocTop
|
2
|
-
|
3
|
-
|
4
|
-
|
5
|
-
|
6
|
-
|
1
|
+
module ChocTop
|
2
|
+
module Appcast
|
3
|
+
def make_build
|
4
|
+
if skip_build
|
5
|
+
puts "Skipping build task..."
|
6
|
+
else
|
7
|
+
sh "xcodebuild -configuration #{build_type} -target #{build_target} #{build_opts}"
|
8
|
+
end
|
7
9
|
end
|
8
|
-
end
|
9
|
-
|
10
|
-
def make_appcast
|
11
|
-
app_name = File.basename(File.expand_path('.'))
|
12
|
-
FileUtils.mkdir_p(build_path)
|
13
|
-
appcast = File.open("#{build_path}/#{appcast_filename}", 'w') do |f|
|
14
|
-
xml = Builder::XmlMarkup.new(:indent => 2)
|
15
|
-
xml.instruct!
|
16
|
-
xml_string = xml.rss('xmlns:atom' => "http://www.w3.org/2005/Atom",
|
17
|
-
'xmlns:sparkle' => "http://www.andymatuschak.org/xml-namespaces/sparkle",
|
18
|
-
:version => "2.0") do
|
19
|
-
xml.channel do
|
20
|
-
xml.title(app_name)
|
21
|
-
xml.description("#{app_name} updates")
|
22
|
-
xml.link(base_url)
|
23
|
-
xml.language('en')
|
24
|
-
xml.pubDate Time.now.to_s(:rfc822)
|
25
|
-
# xml.lastBuildDate(Time.now.rfc822)
|
26
|
-
xml.atom(:link, :href => "#{base_url}/#{appcast_filename}",
|
27
|
-
:rel => "self", :type => "application/rss+xml")
|
28
10
|
|
29
|
-
|
30
|
-
|
31
|
-
|
32
|
-
|
33
|
-
|
34
|
-
|
35
|
-
|
36
|
-
|
37
|
-
|
38
|
-
|
11
|
+
def make_appcast
|
12
|
+
FileUtils.mkdir_p(build_path)
|
13
|
+
appcast = File.open("#{build_path}/#{appcast_filename}", 'w') do |f|
|
14
|
+
xml = Builder::XmlMarkup.new(:indent => 2)
|
15
|
+
xml.instruct!
|
16
|
+
xml_string = xml.rss('xmlns:atom' => "http://www.w3.org/2005/Atom",
|
17
|
+
'xmlns:sparkle' => "http://www.andymatuschak.org/xml-namespaces/sparkle",
|
18
|
+
:version => "2.0") do
|
19
|
+
xml.channel do
|
20
|
+
xml.title(@name)
|
21
|
+
xml.description("#{@name} updates")
|
22
|
+
xml.link(base_url)
|
23
|
+
xml.language('en')
|
24
|
+
xml.pubDate( Time.now.strftime("%a, %d %b %Y %H:%M:%S %z") )
|
25
|
+
# xml.lastBuildDate(Time.now.rfc822)
|
26
|
+
xml.atom(:link, :href => "#{base_url}/#{appcast_filename}",
|
27
|
+
:rel => "self", :type => "application/rss+xml")
|
28
|
+
|
29
|
+
xml.item do
|
30
|
+
xml.title("#{name} #{version}")
|
31
|
+
xml.tag! "sparkle:releaseNotesLink", "#{base_url}/#{release_notes}"
|
32
|
+
xml.pubDate Time.now.strftime("%a, %d %b %Y %H:%M:%S %z")
|
33
|
+
xml.guid("#{name}-#{version}", :isPermaLink => "false")
|
34
|
+
xml.enclosure(:url => "#{base_url}/#{pkg_name}",
|
35
|
+
:length => "#{File.size(pkg)}",
|
36
|
+
:type => "application/dmg",
|
37
|
+
:"sparkle:version" => version,
|
38
|
+
:"sparkle:dsaSignature" => dsa_signature)
|
39
|
+
end
|
39
40
|
end
|
40
41
|
end
|
42
|
+
f << xml_string
|
41
43
|
end
|
42
|
-
f << xml_string
|
43
44
|
end
|
44
|
-
|
45
|
-
|
46
|
-
|
47
|
-
|
48
|
-
|
45
|
+
|
46
|
+
def make_dmg_symlink
|
47
|
+
FileUtils.chdir(build_path) do
|
48
|
+
`rm '#{versionless_pkg_name}'`
|
49
|
+
`ln -s '#{pkg_name}' '#{versionless_pkg_name}'`
|
50
|
+
end
|
49
51
|
end
|
50
|
-
|
51
|
-
|
52
|
-
|
53
|
-
|
54
|
-
|
52
|
+
|
53
|
+
def make_index_redirect
|
54
|
+
File.open("#{build_path}/index.php", 'w') do |f|
|
55
|
+
f << %Q{<?php header("Location: #{pkg_relative_url}"); ?>}
|
56
|
+
end
|
55
57
|
end
|
56
|
-
|
57
|
-
|
58
|
-
|
59
|
-
|
60
|
-
|
61
|
-
|
62
|
-
true
|
63
|
-
end
|
64
|
-
|
65
|
-
def make_release_notes
|
66
|
-
File.open("#{build_path}/#{release_notes}", "w") do |f|
|
67
|
-
template = File.read(release_notes_template)
|
68
|
-
f << ERB.new(template).result(binding)
|
58
|
+
|
59
|
+
def skip_build
|
60
|
+
return true if ENV['NO_BUILD']
|
61
|
+
return false if File.exists?('Info.plist')
|
62
|
+
return false if Dir['*.xcodeproj'].size > 0
|
63
|
+
true
|
69
64
|
end
|
70
|
-
|
71
|
-
|
72
|
-
|
73
|
-
|
74
|
-
|
75
|
-
|
76
|
-
<<-TEXTILE.gsub(/^ /, '')
|
77
|
-
h1. #{version} #{Date.today}
|
78
|
-
|
79
|
-
h2. Another awesome release!
|
80
|
-
TEXTILE
|
65
|
+
|
66
|
+
def make_release_notes
|
67
|
+
File.open("#{build_path}/#{release_notes}", "w") do |f|
|
68
|
+
template = File.read(release_notes_template)
|
69
|
+
f << ERB.new(template).result(binding)
|
70
|
+
end
|
81
71
|
end
|
82
|
-
end
|
83
|
-
|
84
|
-
def release_notes_html
|
85
|
-
RedCloth.new(release_notes_content).to_html
|
86
|
-
end
|
87
72
|
|
88
|
-
|
89
|
-
|
90
|
-
|
91
|
-
|
92
|
-
|
93
|
-
|
94
|
-
|
95
|
-
|
96
|
-
|
97
|
-
|
98
|
-
|
99
|
-
|
100
|
-
|
101
|
-
|
102
|
-
|
103
|
-
|
104
|
-
|
105
|
-
|
106
|
-
|
107
|
-
|
108
|
-
|
109
|
-
|
73
|
+
def release_notes_content
|
74
|
+
if File.exists?("release_notes.txt")
|
75
|
+
File.read("release_notes.txt")
|
76
|
+
else
|
77
|
+
<<-TEXTILE.gsub(/^ /, '')
|
78
|
+
h1. #{version} #{Date.today}
|
79
|
+
|
80
|
+
h2. Another awesome release!
|
81
|
+
TEXTILE
|
82
|
+
end
|
83
|
+
end
|
84
|
+
|
85
|
+
def release_notes_html
|
86
|
+
RedCloth.new(release_notes_content).to_html
|
87
|
+
end
|
88
|
+
|
89
|
+
def upload_appcast
|
90
|
+
_host = host.blank? ? "" : host
|
91
|
+
_user = user.blank? ? "" : "#{user}@"
|
92
|
+
case transport
|
93
|
+
when :scp
|
94
|
+
# this is whack, really, work out your rsync options
|
95
|
+
sh %{scp #{scp_args} #{build_path}/* #{_user}#{_host}:#{remote_dir}}
|
96
|
+
else # default to rsync as per original
|
97
|
+
sh %{rsync #{rsync_args} #{build_path}/ #{_user}#{_host}:#{remote_dir}}
|
98
|
+
end
|
99
|
+
end
|
100
|
+
|
101
|
+
# Returns a file path to the dsa_priv.pem file
|
102
|
+
# If private key + public key haven't been generated yet then
|
103
|
+
# generate them
|
104
|
+
def private_key
|
105
|
+
unless File.exists?('dsa_priv.pem')
|
106
|
+
puts "Creating new private and public keys for signing the DMG..."
|
107
|
+
`openssl dsaparam 2048 < /dev/urandom > dsaparam.pem`
|
108
|
+
`openssl gendsa dsaparam.pem -out dsa_priv.pem`
|
109
|
+
`openssl dsa -in dsa_priv.pem -pubout -out dsa_pub.pem`
|
110
|
+
`rm dsaparam.pem`
|
111
|
+
puts <<-EOS.gsub(/^ /, '')
|
112
|
+
|
113
|
+
WARNING: DO NOT PUT dsa_priv.pem IN YOUR SOURCE CONTROL
|
114
|
+
Remember to add it to your ignore list
|
115
|
+
|
116
|
+
EOS
|
117
|
+
end
|
118
|
+
File.expand_path('dsa_priv.pem')
|
119
|
+
end
|
120
|
+
|
121
|
+
def dsa_signature
|
122
|
+
@dsa_signature ||= `openssl dgst -sha1 -binary < "#{pkg}" | openssl dgst -dss1 -sign "#{private_key}" | openssl enc -base64`
|
110
123
|
end
|
111
|
-
File.expand_path('dsa_priv.pem')
|
112
|
-
end
|
113
|
-
|
114
|
-
def dsa_signature
|
115
|
-
@dsa_signature ||= `openssl dgst -sha1 -binary < "#{pkg}" | openssl dgst -dss1 -sign "#{private_key}" | openssl enc -base64`
|
116
124
|
end
|
117
|
-
end
|
118
|
-
ChocTop.send(:include, ChocTop::Appcast)
|
125
|
+
end
|
data/lib/choctop/dmg.rb
CHANGED
@@ -1,189 +1,193 @@
|
|
1
|
-
module ChocTop
|
2
|
-
|
3
|
-
|
4
|
-
|
5
|
-
|
6
|
-
|
7
|
-
|
8
|
-
|
9
|
-
|
10
|
-
|
11
|
-
|
1
|
+
module ChocTop
|
2
|
+
module Dmg
|
3
|
+
def prepare_files
|
4
|
+
self.files = files.inject({}) do |files, file|
|
5
|
+
path_or_helper, options = file
|
6
|
+
path = case path_or_helper
|
7
|
+
when Symbol
|
8
|
+
send path_or_helper
|
9
|
+
when Proc
|
10
|
+
path_or_helper.call
|
11
|
+
else
|
12
|
+
path_or_helper
|
13
|
+
end
|
14
|
+
files[path] = options if path && File.exists?(path) && File.basename(path) != '.'
|
15
|
+
files
|
12
16
|
end
|
13
|
-
files[path] = options if path && File.exists?(path) && File.basename(path) != '.'
|
14
|
-
files
|
15
17
|
end
|
16
|
-
|
17
|
-
|
18
|
-
|
19
|
-
|
20
|
-
|
21
|
-
|
18
|
+
|
19
|
+
def copy_files
|
20
|
+
FileUtils.rm_r(src_folder) if File.exists? src_folder
|
21
|
+
FileUtils.mkdir_p(src_folder)
|
22
|
+
files.each do |path, options|
|
23
|
+
FileUtils.cp_r(path, src_folder)
|
24
|
+
end
|
22
25
|
end
|
23
|
-
|
24
|
-
|
25
|
-
|
26
|
-
|
27
|
-
|
28
|
-
|
29
|
-
|
30
|
-
|
31
|
-
|
32
|
-
|
33
|
-
|
34
|
-
|
35
|
-
|
36
|
-
|
37
|
-
|
38
|
-
|
39
|
-
|
40
|
-
end
|
41
|
-
|
42
|
-
def volume_background
|
43
|
-
".background/background#{File.extname(background_file)}"
|
44
|
-
end
|
45
|
-
|
46
|
-
def window_position
|
47
|
-
[50, 100]
|
48
|
-
end
|
49
|
-
|
50
|
-
def window_bounds
|
51
|
-
window_position +
|
52
|
-
window_position.zip(background_bounds).map { |w, b| w + b }
|
53
|
-
end
|
54
|
-
|
55
|
-
def background_bounds
|
56
|
-
return [400, 300] unless background_file
|
57
|
-
background = OSX::NSImage.alloc.initByReferencingFile(background_file).size.to_a
|
58
|
-
[background.first, background.last + statusbar_height]
|
59
|
-
end
|
60
|
-
|
61
|
-
def statusbar_height; 20; end
|
62
|
-
|
63
|
-
def configure_volume_icon
|
64
|
-
if volume_icon
|
65
|
-
FileUtils.cp(volume_icon, "#{volume_path}/.VolumeIcon.icns")
|
66
|
-
sh "SetFile -a C '#{volume_path}'"
|
26
|
+
|
27
|
+
def make_dmg
|
28
|
+
prepare_files
|
29
|
+
copy_files
|
30
|
+
FileUtils.mkdir_p build_path
|
31
|
+
FileUtils.mkdir_p mountpoint # TODO can we remove random mountpoints?
|
32
|
+
FileUtils.rm_f(pkg) # make sure destination pkg doesn't already exist, or hdiutil will barf
|
33
|
+
sh "hdiutil create -format UDRW -quiet -volname '#{name}' -srcfolder '#{src_folder}' '#{pkg}'"
|
34
|
+
sh "hdiutil attach '#{pkg}' -mountpoint '#{volume_path}' -noautoopen -quiet"
|
35
|
+
sh "bless --folder '#{volume_path}' --openfolder '#{volume_path}'"
|
36
|
+
sh "sleep 1"
|
37
|
+
|
38
|
+
puts "volume_icon: #{volume_icon.inspect}"
|
39
|
+
puts "include_applications_icon?: #{include_applications_icon?.inspect}"
|
40
|
+
configure_volume_icon
|
41
|
+
configure_applications_icon if include_applications_icon?
|
42
|
+
configure_dmg_window
|
67
43
|
end
|
68
|
-
end
|
69
44
|
|
70
|
-
|
71
|
-
|
72
|
-
target_background = "#{volume_path}/#{volume_background}"
|
73
|
-
FileUtils.mkdir_p(File.dirname(target_background))
|
74
|
-
FileUtils.cp(background_file, target_background)
|
75
|
-
end
|
76
|
-
script = <<-SCRIPT.gsub(/^ /, '')
|
77
|
-
tell application "Finder"
|
78
|
-
set applications_folder to displayed name of (path to applications folder) -- i18n
|
79
|
-
set mountpoint to POSIX file ("#{volume_path}" as string) as alias
|
80
|
-
tell folder mountpoint
|
81
|
-
open
|
82
|
-
tell container window
|
83
|
-
set toolbar visible to false
|
84
|
-
set statusbar visible to false -- doesn't do anything at DMG open time
|
85
|
-
set current view to icon view
|
86
|
-
delay 1 -- Sync
|
87
|
-
set the bounds to {#{window_bounds.join(", ")}}
|
88
|
-
end tell
|
89
|
-
delay 1 -- Sync
|
90
|
-
set icon size of the icon view options of container window to #{icon_size}
|
91
|
-
set text size of the icon view options of container window to #{icon_text_size}
|
92
|
-
set arrangement of the icon view options of container window to not arranged
|
93
|
-
#{set_position_of_files}
|
94
|
-
#{set_position_of_shortcuts}
|
95
|
-
set the bounds of the container window to {#{window_bounds.join(", ")}}
|
96
|
-
set background picture of the icon view options of container window to file "#{volume_background.gsub(/\//,':')}"
|
97
|
-
update without registering applications
|
98
|
-
delay 5 -- Sync
|
99
|
-
close
|
100
|
-
end tell
|
101
|
-
-- Sync
|
102
|
-
delay 5
|
103
|
-
end tell
|
104
|
-
SCRIPT
|
105
|
-
run_applescript(script)
|
106
|
-
sh "SetFile -a V '#{target_background}'" if background_file
|
107
|
-
end
|
108
|
-
|
109
|
-
def set_position_of_files
|
110
|
-
files.map do |file_options|
|
111
|
-
path, options = file_options
|
112
|
-
target = File.basename(path)
|
113
|
-
position = options[:position].join(", ")
|
114
|
-
%Q{set position of item "#{target}" to {#{position}}}
|
115
|
-
end.join("\n")
|
116
|
-
end
|
117
|
-
|
118
|
-
def set_position_of_shortcuts
|
119
|
-
if include_applications_icon?
|
120
|
-
%Q{set position of item applications_folder to {#{applications_icon_position.join(", ")}}}
|
121
|
-
else
|
122
|
-
""
|
45
|
+
def volume_background
|
46
|
+
".background/background#{File.extname(background_file)}"
|
123
47
|
end
|
124
|
-
|
125
|
-
|
126
|
-
|
127
|
-
puts "target: #{target.inspect}"
|
128
|
-
target =~ /.app$/
|
129
|
-
end
|
130
|
-
|
131
|
-
def configure_applications_icon
|
132
|
-
run_applescript <<-SCRIPT.gsub(/^ /, ''), "apps_icon_script"
|
133
|
-
tell application "Finder"
|
134
|
-
set applications_folder to displayed name of (path to applications folder) -- i18n
|
135
|
-
set dest to disk "#{name}"
|
136
|
-
set src to folder applications_folder of startup disk
|
137
|
-
make new alias at dest to src
|
138
|
-
end tell
|
139
|
-
SCRIPT
|
140
|
-
if applications_icon
|
141
|
-
applications_path = "#{volume_path}/Applications"
|
142
|
-
OSX::NSApplicationLoad()
|
143
|
-
image = OSX::NSImage.alloc.initWithContentsOfFile(applications_icon)
|
144
|
-
OSX::NSWorkspace.sharedWorkspace.setIcon_forFile_options(image, applications_path, nil)
|
48
|
+
|
49
|
+
def window_position
|
50
|
+
[50, 100]
|
145
51
|
end
|
146
|
-
|
147
|
-
|
148
|
-
|
149
|
-
|
150
|
-
|
151
|
-
|
152
|
-
|
153
|
-
|
154
|
-
|
52
|
+
|
53
|
+
def window_bounds
|
54
|
+
window_position +
|
55
|
+
window_position.zip(background_bounds).map { |w, b| w + b }
|
56
|
+
end
|
57
|
+
|
58
|
+
def background_bounds
|
59
|
+
return [400, 300] unless background_file
|
60
|
+
background = OSX::NSImage.alloc.initByReferencingFile(background_file).size.to_a
|
61
|
+
[background.first, background.last + statusbar_height]
|
62
|
+
end
|
63
|
+
|
64
|
+
def statusbar_height; 20; end
|
65
|
+
|
66
|
+
def configure_volume_icon
|
67
|
+
if volume_icon
|
68
|
+
FileUtils.cp(volume_icon, "#{volume_path}/.VolumeIcon.icns")
|
69
|
+
sh "SetFile -a C '#{volume_path}'"
|
155
70
|
end
|
156
71
|
end
|
157
|
-
|
158
|
-
|
159
|
-
|
160
|
-
|
161
|
-
|
162
|
-
|
163
|
-
end
|
164
|
-
|
165
|
-
def add_eula
|
166
|
-
# TODO support EULA
|
167
|
-
# hdiutil unflatten $@
|
168
|
-
# /Developer/Tools/DeRez -useDF SLAResources.rsrc > build/temp/sla.r
|
169
|
-
# /Developer/Tools/Rez -a build/temp/sla.r -o $@
|
170
|
-
# hdiutil flatten $@
|
171
|
-
|
172
|
-
end
|
173
|
-
|
174
|
-
def run_applescript(applescript, tmp_file = "choctop-script")
|
175
|
-
File.open(scriptfile = "/tmp/#{tmp_file}", "w") do |f|
|
176
|
-
f << applescript
|
177
|
-
end
|
178
|
-
sh("osascript #{scriptfile}") do |ok, res|
|
179
|
-
if ! ok
|
180
|
-
p res
|
181
|
-
puts volume_path
|
182
|
-
exit 1
|
72
|
+
|
73
|
+
def configure_dmg_window
|
74
|
+
if background_file
|
75
|
+
target_background = "#{volume_path}/#{volume_background}"
|
76
|
+
FileUtils.mkdir_p(File.dirname(target_background))
|
77
|
+
FileUtils.cp(background_file, target_background)
|
183
78
|
end
|
79
|
+
script = <<-SCRIPT.gsub(/^ /, '')
|
80
|
+
tell application "Finder"
|
81
|
+
set applications_folder to displayed name of (path to applications folder) -- i18n
|
82
|
+
set mountpoint to POSIX file ("#{volume_path}" as string) as alias
|
83
|
+
tell folder mountpoint
|
84
|
+
open
|
85
|
+
tell container window
|
86
|
+
set toolbar visible to false
|
87
|
+
set statusbar visible to false -- doesn't do anything at DMG open time
|
88
|
+
set current view to icon view
|
89
|
+
delay 1 -- Sync
|
90
|
+
set the bounds to {#{window_bounds.join(", ")}}
|
91
|
+
end tell
|
92
|
+
delay 1 -- Sync
|
93
|
+
set icon size of the icon view options of container window to #{icon_size}
|
94
|
+
set text size of the icon view options of container window to #{icon_text_size}
|
95
|
+
set arrangement of the icon view options of container window to not arranged
|
96
|
+
#{set_position_of_files}
|
97
|
+
#{set_position_of_shortcuts}
|
98
|
+
close
|
99
|
+
open
|
100
|
+
set the bounds of the container window to {#{window_bounds.join(", ")}}
|
101
|
+
set background picture of the icon view options of container window to file "#{volume_background.gsub(/\//,':')}"
|
102
|
+
update without registering applications
|
103
|
+
delay 5 -- Sync
|
104
|
+
close
|
105
|
+
end tell
|
106
|
+
-- Sync
|
107
|
+
delay 5
|
108
|
+
end tell
|
109
|
+
SCRIPT
|
110
|
+
puts "script: #{script}"
|
111
|
+
run_applescript(script)
|
112
|
+
sh "SetFile -a V '#{target_background}'" if background_file
|
184
113
|
end
|
185
|
-
applescript
|
186
|
-
end
|
187
|
-
end
|
188
|
-
ChocTop.send(:include, ChocTop::Dmg)
|
189
114
|
|
115
|
+
def set_position_of_files
|
116
|
+
files.map do |file_options|
|
117
|
+
path, options = file_options
|
118
|
+
target = File.basename(path)
|
119
|
+
position = options[:position].join(", ")
|
120
|
+
%Q{set position of item "#{target}" to {#{position}}}
|
121
|
+
end.join("\n")
|
122
|
+
end
|
123
|
+
|
124
|
+
def set_position_of_shortcuts
|
125
|
+
if include_applications_icon?
|
126
|
+
%Q{set position of item applications_folder to {#{applications_icon_position.join(", ")}}}
|
127
|
+
else
|
128
|
+
""
|
129
|
+
end
|
130
|
+
end
|
131
|
+
|
132
|
+
def include_applications_icon?
|
133
|
+
target =~ /.app$/
|
134
|
+
end
|
135
|
+
|
136
|
+
def configure_applications_icon
|
137
|
+
run_applescript <<-SCRIPT.gsub(/^ /, ''), "apps_icon_script"
|
138
|
+
tell application "Finder"
|
139
|
+
set applications_folder to displayed name of (path to applications folder) -- i18n
|
140
|
+
set dest to disk "#{name}"
|
141
|
+
set src to folder applications_folder of startup disk
|
142
|
+
make new alias at dest to src
|
143
|
+
end tell
|
144
|
+
SCRIPT
|
145
|
+
if applications_icon
|
146
|
+
applications_path = "#{volume_path}/Applications"
|
147
|
+
OSX::NSApplicationLoad()
|
148
|
+
image = OSX::NSImage.alloc.initWithContentsOfFile(applications_icon)
|
149
|
+
OSX::NSWorkspace.sharedWorkspace.setIcon_forFile_options(image, applications_path, nil)
|
150
|
+
end
|
151
|
+
end
|
152
|
+
|
153
|
+
def detach_dmg
|
154
|
+
mounted_paths = `hdiutil info | grep '#{volume_path}' | grep "Apple_HFS"`.split("\n").map { |e| e.split(" ").first }
|
155
|
+
mounted_paths.each do |path|
|
156
|
+
begin
|
157
|
+
sh "hdiutil detach '#{path}' -quiet -force"
|
158
|
+
rescue StandardError => e
|
159
|
+
p e
|
160
|
+
end
|
161
|
+
end
|
162
|
+
end
|
163
|
+
|
164
|
+
def convert_dmg_readonly
|
165
|
+
tmp_path = "/tmp/rw.dmg"
|
166
|
+
FileUtils.mv(pkg, tmp_path)
|
167
|
+
sh "hdiutil convert '#{tmp_path}' -format UDZO -imagekey zlib-level=9 -o '#{pkg}'"
|
168
|
+
end
|
169
|
+
|
170
|
+
def add_eula
|
171
|
+
# TODO support EULA
|
172
|
+
# hdiutil unflatten $@
|
173
|
+
# /Developer/Tools/DeRez -useDF SLAResources.rsrc > build/temp/sla.r
|
174
|
+
# /Developer/Tools/Rez -a build/temp/sla.r -o $@
|
175
|
+
# hdiutil flatten $@
|
176
|
+
|
177
|
+
end
|
178
|
+
|
179
|
+
def run_applescript(applescript, tmp_file = "choctop-script")
|
180
|
+
File.open(scriptfile = "/tmp/#{tmp_file}", "w") do |f|
|
181
|
+
f << applescript
|
182
|
+
end
|
183
|
+
sh("osascript #{scriptfile}") do |ok, res|
|
184
|
+
if ! ok
|
185
|
+
p res
|
186
|
+
puts volume_path
|
187
|
+
exit 1
|
188
|
+
end
|
189
|
+
end
|
190
|
+
applescript
|
191
|
+
end
|
192
|
+
end
|
193
|
+
end
|