class Motion::Project::Sparkle
Constants
- CONFIG_PATH
- RELEASE_PATH
- SPARKLE_ROOT
- TEMPLATE_PATHS
- VERSION
Public Class Methods
new(config)
click to toggle source
# File lib/motion/project/sparkle.rb, line 8 def initialize(config) @config = config publish :public_key, 'dsa_pub.pem' install_and_embed end
Public Instance Methods
add_to_gitignore()
click to toggle source
File manipulation and certificates
# File lib/motion/project/sparkle.rb, line 60 def add_to_gitignore @ignorable = ['sparkle/release','sparkle/release/*','sparkle/config/dsa_priv.pem'] return unless File.exist?(gitignore_path) File.open(gitignore_path, 'r') do |f| f.each_line do |line| @ignorable.delete(line) if @ignorable.include?(line) end end File.open(gitignore_path, 'a') do |f| @ignorable.each do |i| f << "#{i}\n" end end if @ignorable.any? `cat #{gitignore_path}` end
all_templates()
click to toggle source
# File lib/motion/project/templates.rb, line 11 def all_templates @all_templates ||= begin templates = {} TEMPLATE_PATHS.map { |path| Dir.glob(path + '/*') }.flatten.each do |template_path| templates[File.basename(template_path)] = template_path end templates end end
app_bundle_path()
click to toggle source
# File lib/motion/project/sparkle.rb, line 162 def app_bundle_path Pathname.new @config.app_bundle_raw('MacOSX') end
app_file()
click to toggle source
# File lib/motion/project/sparkle.rb, line 178 def app_file "#{app_name}.app" end
app_name()
click to toggle source
# File lib/motion/project/sparkle.rb, line 170 def app_name File.basename(app_bundle_path, '.app') end
app_release_path()
click to toggle source
# File lib/motion/project/sparkle.rb, line 166 def app_release_path app_bundle_path.parent.to_s end
appcast()
click to toggle source
# File lib/motion/project/sparkle.rb, line 14 def appcast @appcast ||= Appcast.new end
appcast_xml()
click to toggle source
# File lib/motion/project/appcast.rb, line 32 def appcast_xml rss = REXML::Element.new 'rss' rss.attributes['xmlns:atom'] = "http://www.w3.org/2005/Atom" rss.attributes['xmlns:sparkle'] = "http://www.andymatuschak.org/xml-namespaces/sparkle" rss.attributes['xmlns:version'] = "2.0" rss.attributes['xmlns:dc'] = "http://purl.org/dc/elements/1.1/" channel = rss.add_element 'channel' channel.add_element('title').text = @config.name channel.add_element('description').text = "#{@config.name} updates" channel.add_element('link').text = @config.info_plist["SUFeedURL"] channel.add_element('language').text = 'en' channel.add_element('pubDate').text = Time.now.strftime("%a, %d %b %Y %H:%M:%S %z") atom_link = channel.add_element('atom:link') atom_link.attributes['href'] = @config.info_plist["SUFeedURL"] atom_link.attributes['rel'] = 'self' atom_link.attributes['type'] = "application/rss+xml" item = channel.add_element 'item' item.add_element('title').text = "#{@config.name} #{@config.version}" item.add_element('pubDate').text = Time.now.strftime("%a, %d %b %Y %H:%M:%S %z") guid = item.add_element('guid') guid.text = "#{@config.name}-#{@config.version}" guid.attributes['isPermaLink'] = false item.add_element('sparkle:releaseNotesLink').text = "#{appcast.notes_url}" enclosure = item.add_element('enclosure') enclosure.attributes['url'] = "#{appcast.package_url}" enclosure.attributes['length'] = "#{@package_size}" enclosure.attributes['type'] = "application/octet-stream" enclosure.attributes['sparkle:version'] = @config.version enclosure.attributes['sparkle:dsaSignature'] = @package_signature rss end
certificates_ok?(silence=false)
click to toggle source
# File lib/motion/project/setup.rb, line 40 def certificates_ok?(silence=false) unless File.exist?("./#{Sparkle::CONFIG_PATH}") if silence return false else App.fail "Missing `#{Sparkle::CONFIG_PATH}`. Run `rake sparkle:setup` to get started" end end unless File.exist?(private_key_path) if silence return false else App.fail "Missing `#{private_key_path}`. Please run `rake sparkle:setup_certificates` or check the docs to know where to put them." end end unless File.exist?(public_key_path) if silence return false else App.fail "Missing `#{public_key_path}`. Did you configure `release :public_key` correctly in the Rakefile? Advanced: recreate your public key with `rake sparkle:recreate_public_key`" end end true end
check_base_url()
click to toggle source
# File lib/motion/project/setup.rb, line 15 def check_base_url base_url_check = appcast.base_url.to_s if base_url_check.nil? or base_url_check.empty? App.fail "Sparkle :base_url missing. Use `release :base_url, 'http://example.com/your_app_folder'` in your Rakefile's `app.sparkle` block" end true end
check_feed_url()
click to toggle source
# File lib/motion/project/setup.rb, line 23 def check_feed_url feed_url_check = @config.info_plist['SUFeedURL'] feed_filename_check = appcast.feed_filename if feed_url_check.nil? or feed_url_check.empty? or feed_filename_check.nil? or feed_filename_check.empty? App.fail "Sparkle :feed_filename is nil or blank. Please check your Rakefile." end true end
check_public_key()
click to toggle source
# File lib/motion/project/setup.rb, line 32 def check_public_key public_key_check = @config.info_plist['SUPublicDSAKeyFile'].to_s if public_key_check.nil? or public_key_check.empty? App.fail "Sparkle :public_key is nil or blank. Please check your Rakefile." end true end
config_ok?()
click to toggle source
# File lib/motion/project/setup.rb, line 9 def config_ok? check_base_url check_feed_url check_public_key end
copy_templates(force=false)
click to toggle source
# File lib/motion/project/templates.rb, line 21 def copy_templates(force=false) all_templates.each_pair do |tmpl, path| result = "#{sparkle_config_path}/#{tmpl}" if File.exist?(result) and !force App.info 'Exists', result else FileUtils.cp(path, "#{sparkle_config_path}/") App.info 'Create', "./#{sparkle_config_path}/#{tmpl.to_s}" end end end
copy_zipball()
click to toggle source
# File lib/motion/project/install.rb, line 18 def copy_zipball `cp #{sparkle_distrib} #{sparkle_zipball}` end
create_appcast()
click to toggle source
# File lib/motion/project/appcast.rb, line 16 def create_appcast appcast_file = File.open("#{sparkle_release_path}/#{appcast.feed_filename}", 'w') do |f| xml_string = '' doc = REXML::Formatters::Pretty.new doc.write(appcast_xml, xml_string) f << "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n" f << xml_string f << "\n" end if appcast_file App.info "Create", "./#{sparkle_release_path}/#{appcast.feed_filename}" else App.info "Fail", "./#{sparkle_release_path}/#{appcast.feed_filename} not created" end end
create_config_folder()
click to toggle source
# File lib/motion/project/sparkle.rb, line 81 def create_config_folder FileUtils.mkdir_p(sparkle_config_path) unless File.exist?(sparkle_config_path) end
create_release_folder()
click to toggle source
# File lib/motion/project/sparkle.rb, line 85 def create_release_folder FileUtils.mkdir_p(sparkle_release_path) unless File.exist?(sparkle_release_path) end
create_release_notes()
click to toggle source
# File lib/motion/project/appcast.rb, line 4 def create_release_notes if File.exist?(release_notes_template_path) File.open("#{release_notes_path}", "w") do |f| template = File.read(release_notes_template_path) f << ERB.new(template).result(binding) end App.info 'Create', "./#{release_notes_path}" else App.fail "Release notes template not found as expected at ./#{release_notes_template_path}" end end
create_sparkle_folder()
click to toggle source
# File lib/motion/project/sparkle.rb, line 76 def create_sparkle_folder create_config_folder create_release_folder end
create_zip_file()
click to toggle source
# File lib/motion/project/package.rb, line 19 def create_zip_file unless File.exist?(app_bundle_path) App.fail "You need to build your app with the Release target to use Sparkle" end if File.exist?("#{sparkle_release_path}/#{zip_file}") App.fail "Release already exists at ./#{sparkle_release_path}/#{zip_file} (remove it manually with `rake sparkle:clean`)" end FileUtils.cd(app_release_path) do `zip -r --symlinks "#{zip_file}" "#{app_file}"` end FileUtils.mv "#{app_release_path}/#{zip_file}", "./#{sparkle_release_path}/" App.info "Create", "./#{sparkle_release_path}/#{zip_file}" @package_file = zip_file @package_size = File.size "./#{sparkle_release_path}/#{zip_file}" end
dsa_param_path()
click to toggle source
# File lib/motion/project/sparkle.rb, line 149 def dsa_param_path sparkle_config_path + "dsaparam.pem" end
embed()
click to toggle source
# File lib/motion/project/install.rb, line 36 def embed @config.embedded_frameworks << sparkle_path end
feed_url(url)
click to toggle source
# File lib/motion/project/sparkle.rb, line 50 def feed_url(url) @config.info_plist['SUFeedURL'] = url end
generate_keys()
click to toggle source
# File lib/motion/project/sparkle.rb, line 89 def generate_keys return false unless config_ok? unless File.exist?(sparkle_config_path) FileUtils.mkdir_p sparkle_config_path end [dsa_param_path, private_key_path, public_key_path].each do |file| if File.exist? file App.info "Sparkle", "Error: file exists. There's already a '#{file}'. Be careful not to override or lose your certificates. \n Delete this file if you're sure. \n Aborting (no action performed) " return end end `#{openssl} dsaparam 1024 < /dev/urandom > #{dsa_param_path}` `#{openssl} gendsa #{dsa_param_path} -out #{private_key_path}` generate_public_key `rm #{dsa_param_path}` App.info "Sparkle", "Generated private and public certificates. Details: * Private certificate: ./#{private_key_path} * Public certificate: ./#{public_key_path} Warning: ADD YOUR PRIVATE CERTIFICATE TO YOUR `.gitignore` OR EQUIVALENT AND BACK IT UP! KEEP IT PRIVATE AND SAFE! If you lose it, your users will be unable to upgrade. " end
generate_public_key()
click to toggle source
# File lib/motion/project/sparkle.rb, line 119 def generate_public_key `#{openssl} dsa -in #{private_key_path} -pubout -out #{public_key_path}` end
gitignore_path()
click to toggle source
# File lib/motion/project/sparkle.rb, line 137 def gitignore_path project_path + ".gitignore" end
install()
click to toggle source
# File lib/motion/project/install.rb, line 31 def install copy_zipball unzip end
install_and_embed()
click to toggle source
# File lib/motion/project/install.rb, line 40 def install_and_embed install unless installed? embed end
installed?()
click to toggle source
# File lib/motion/project/install.rb, line 27 def installed? File.directory?(sparkle_path) end
openssl()
click to toggle source
A few helpers
# File lib/motion/project/sparkle.rb, line 125 def openssl "/usr/bin/openssl" end
package()
click to toggle source
# File lib/motion/project/package.rb, line 4 def package return unless setup_ok? create_release_folder @config.build_mode = :release return unless create_zip_file App.info "Release", version_string App.info "Version", @config.version App.info "Build", @config.short_version || 'unspecified in Rakefile' App.info "Size", @package_size.to_s sign_package create_appcast create_release_notes `open #{sparkle_release_path}` end
private_key_path()
click to toggle source
# File lib/motion/project/sparkle.rb, line 153 def private_key_path sparkle_config_path + "dsa_priv.pem" end
project_path()
click to toggle source
# File lib/motion/project/sparkle.rb, line 129 def project_path @project_path ||= Pathname.new(@config.project_dir) end
public_key(path_in_resources_folder)
click to toggle source
# File lib/motion/project/sparkle.rb, line 54 def public_key(path_in_resources_folder) @config.info_plist['SUPublicDSAKeyFile'] = path_in_resources_folder end
public_key_path()
click to toggle source
# File lib/motion/project/sparkle.rb, line 157 def public_key_path pub_key_file = @config.info_plist['SUPublicDSAKeyFile'] project_path + "resources/#{pub_key_file}" end
publish(key, value)
click to toggle source
# File lib/motion/project/sparkle.rb, line 18 def publish(key, value) case key when :public_key public_key value when :base_url appcast.base_url = value feed_url appcast.feed_url when :feed_base_url appcast.feed_base_url = value feed_url appcast.feed_url when :feed_filename appcast.feed_filename = value feed_url appcast.feed_url when :version version value when :notes_base_url, :package_base_url, :notes_filename, :package_filename appcast.send "#{key}=", value else raise "Unknown Sparkle config option #{key}" end end
Also aliased as: release
release_notes_content()
click to toggle source
# File lib/motion/project/appcast.rb, line 76 def release_notes_content if File.exist?(release_notes_content_path) File.read(release_notes_content_path) else App.fail "Missing #{release_notes_content_path}" end end
release_notes_content_path()
click to toggle source
# File lib/motion/project/appcast.rb, line 68 def release_notes_content_path sparkle_config_path + "release_notes.content.html" end
release_notes_html()
click to toggle source
# File lib/motion/project/appcast.rb, line 84 def release_notes_html release_notes_content end
release_notes_path()
click to toggle source
# File lib/motion/project/appcast.rb, line 72 def release_notes_path sparkle_release_path + appcast.notes_filename.to_s end
release_notes_template_path()
click to toggle source
# File lib/motion/project/appcast.rb, line 64 def release_notes_template_path sparkle_config_path + "release_notes.template.erb" end
setup()
click to toggle source
# File lib/motion/project/setup.rb, line 65 def setup verify_installation create_sparkle_folder add_to_gitignore copy_templates if config_ok? App.info "Sparkle", "Config found" else return false end silence = true if certificates_ok?(silence) App.info "Sparkle", "Certificates found" else App.info "Sparkle", "Certificates not found Please generate your private and public keys with `rake sparkle:setup_certificates` If you already have your certificates and only need to include them in the project, follow these steps: 1. Rename your private key to `./#{private_key_path}` 2. Place your public key in `./#{public_key_path}` 3. If you wish to use a different name or location for your public key within the resources dir, make sure you add `publish :public_key, 'folder/new_name.pem'` to the sparkle config in your Rakefile " return false end App.info "Sparkle", "Setup OK. After `rake build:release`, you can now run `rake sparkle:package`." end
setup_ok?()
click to toggle source
# File lib/motion/project/setup.rb, line 4 def setup_ok? config_ok? certificates_ok? end
sign_package()
click to toggle source
# File lib/motion/project/package.rb, line 35 def sign_package package = "./#{sparkle_release_path}/#{zip_file}" @package_signature = `#{openssl} dgst -sha1 -binary < "#{package}" | #{openssl} dgst -dss1 -sign "#{private_key_path}" | #{openssl} enc -base64` @package_signature = @package_signature.strip App.info "Signature", "\"#{@package_signature}\"" end
sparkle_config_path()
click to toggle source
# File lib/motion/project/sparkle.rb, line 145 def sparkle_config_path project_path + CONFIG_PATH end
sparkle_distrib()
click to toggle source
# File lib/motion/project/install.rb, line 4 def sparkle_distrib file_path = Pathname.new File.dirname(__FILE__) distrib_path = 'vendor/Sparkle.framework.zip' (file_path.parent.parent.parent + distrib_path).to_s end
sparkle_path()
click to toggle source
# File lib/motion/project/install.rb, line 10 def sparkle_path Pathname.new(vendor_path + 'Sparkle.framework') end
sparkle_release_path()
click to toggle source
# File lib/motion/project/sparkle.rb, line 141 def sparkle_release_path project_path + RELEASE_PATH end
sparkle_zipball()
click to toggle source
# File lib/motion/project/install.rb, line 14 def sparkle_zipball Pathname.new(vendor_path + 'Sparkle.framework.zip') end
unzip()
click to toggle source
# File lib/motion/project/install.rb, line 22 def unzip `unzip #{sparkle_zipball.to_s} -d #{vendor_path.to_s}` `rm #{sparkle_zipball}` end
vendor_path()
click to toggle source
# File lib/motion/project/sparkle.rb, line 133 def vendor_path @vendor_path ||= Pathname.new(project_path + 'vendor/') end
verify_installation()
click to toggle source
# File lib/motion/project/install.rb, line 45 def verify_installation if installed? App.info "Sparkle", "Framework installed in #{sparkle_path.to_s}" else App.fail "Sparkle framework not correctly copied to #{sparkle_path.to_s} Run `rake sparkle:install` manually or, if the problem persists, please explain your setup and problem as an issue on GitHub at: https://github.com/webcracy/motion-sparkle/issues " end end
version(vstring)
click to toggle source
# File lib/motion/project/sparkle.rb, line 41 def version(vstring) @config.version = vstring.to_s @config.short_version = vstring.to_s end
version_string()
click to toggle source
# File lib/motion/project/sparkle.rb, line 46 def version_string "#{@config.version} (#{@config.short_version})" end
zip_file()
click to toggle source
# File lib/motion/project/sparkle.rb, line 174 def zip_file appcast.package_filename || "#{app_name}.zip" end