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.
@@ -1,118 +1,125 @@
1
- module ChocTop::Appcast
2
- def make_build
3
- if skip_build
4
- puts "Skipping build task..."
5
- else
6
- sh "xcodebuild -configuration #{build_type}"
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
- xml.item do
30
- xml.title("#{name} #{version}")
31
- xml.tag! "sparkle:releaseNotesLink", "#{base_url}/#{release_notes}"
32
- xml.pubDate Time.now.to_s(:rfc822) #(File.mtime(pkg))
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)
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
- end
45
-
46
- def make_dmg_symlink
47
- FileUtils.chdir(build_path) do
48
- `ln -s #{pkg_name} #{versionless_pkg_name}`
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
- end
51
-
52
- def make_index_redirect
53
- File.open("#{build_path}/index.php", 'w') do |f|
54
- f << %Q{<?php header("Location: #{pkg_relative_url}"); ?>}
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
- end
57
-
58
- def skip_build
59
- return true if ENV['NO_BUILD']
60
- return false if File.exists?('Info.plist')
61
- return false if Dir['*.xcodeproj'].size > 0
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
- end
71
-
72
- def release_notes_content
73
- if File.exists?("release_notes.txt")
74
- File.read("release_notes.txt")
75
- else
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
- def upload_appcast
89
- _host = host.blank? ? "" : "#{host}:"
90
- _user = user.blank? ? "" : "#{user}@"
91
- sh %{rsync #{rsync_args} #{build_path}/ #{_user}#{_host}#{remote_dir}}
92
- end
93
-
94
- # Returns a file path to the dsa_priv.pem file
95
- # If private key + public key haven't been generated yet then
96
- # generate them
97
- def private_key
98
- unless File.exists?('dsa_priv.pem')
99
- puts "Creating new private and public keys for signing the DMG..."
100
- `openssl dsaparam 2048 < /dev/urandom > dsaparam.pem`
101
- `openssl gendsa dsaparam.pem -out dsa_priv.pem`
102
- `openssl dsa -in dsa_priv.pem -pubout -out dsa_pub.pem`
103
- `rm dsaparam.pem`
104
- puts <<-EOS.gsub(/^ /, '')
105
-
106
- WARNING: DO NOT PUT dsa_priv.pem IN YOUR SOURCE CONTROL
107
- Remember to add it to your ignore list
108
-
109
- EOS
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
@@ -1,189 +1,193 @@
1
- module ChocTop::Dmg
2
- def prepare_files
3
- self.files = files.inject({}) do |files, file|
4
- path_or_helper, options = file
5
- path = case path_or_helper
6
- when Symbol
7
- send path_or_helper
8
- when Proc
9
- path_or_helper.call
10
- else
11
- path_or_helper
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
- end
17
-
18
- def copy_files
19
- FileUtils.mkdir_p(dmg_pkg_folder)
20
- files.each do |path, options|
21
- FileUtils.cp_r(path, dmg_pkg_folder)
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
- end
24
-
25
- def make_dmg
26
- prepare_files
27
- copy_files
28
- FileUtils.mkdir_p build_path
29
- FileUtils.mkdir_p mountpoint # TODO can we remove random mountpoints?
30
- sh "hdiutil create -format UDRW -quiet -volname '#{name}' -srcfolder '#{dmg_pkg_folder}' '#{pkg}'"
31
- sh "hdiutil attach '#{pkg}' -mountpoint '#{volume_path}' -noautoopen -quiet"
32
- sh "bless --folder '#{volume_path}' --openfolder '#{volume_path}'"
33
- sh "sleep 1"
34
-
35
- puts "volume_icon: #{volume_icon.inspect}"
36
- puts "include_applications_icon?: #{include_applications_icon?.inspect}"
37
- configure_volume_icon
38
- configure_applications_icon if include_applications_icon?
39
- configure_dmg_window
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
- def configure_dmg_window
71
- if background_file
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
- end
125
-
126
- def include_applications_icon?
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
- end
147
-
148
- def detach_dmg
149
- mounted_paths = `hdiutil info | grep '#{volume_path}' | grep "Apple_HFS"`.split("\n").map { |e| e.split(" ").first }
150
- mounted_paths.each do |path|
151
- begin
152
- sh "hdiutil detach '#{path}' -quiet -force"
153
- rescue StandardError => e
154
- p e
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
- end
158
-
159
- def convert_dmg_readonly
160
- tmp_path = "/tmp/rw.dmg"
161
- FileUtils.mv(pkg, tmp_path)
162
- sh "hdiutil convert '#{tmp_path}' -format UDZO -imagekey zlib-level=9 -o '#{pkg}'"
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