Creating Sparkle Appcast via Rake Tasks
I have a RubyCocoa application that self-updates using Sparkle. To do so, you need to create an "appcast" file which contains the version and download information for your application, as well as creating the zip file that holds your app. Then, you of course have to upload this to the server and location that you have specified in the SUFeedURL key value in your Info.plist file of your app. For general instructions on using Sparkle and setting it up, see their Basic Instructions page.
- Your app root directory
- Rakefile
- appcast
- version_info.yml
- build
- Your app zip files go here (e.g. Linker_0.8.zip, Linker_0.9.zip, etc.)
- Rake task will create the linker_appcast.xml file here
linker-04: title: Linker 0.4 filename: Linker_0.4.zip description: Added Sparkle updating mechanism.linker-05: title: Linker 0.5 filename: Linker_0.5.zip description: Added help (see Help menu). Added bookmarklet support/custom URL protocol handling. See the new help for information on how to use the bookmarklet.
namespace :appcast do desc "Create/update the appcast file" task :build do make_appcast end desc "Upload the appcast file to the server" task :upload do upload_appcast endend
APPCAST_SERVER = 'your_appcast_server.com'APPCAST_URL = "http://#{APPCAST_SERVER}"APPCAST_FILENAME = 'linker_appcast.xml'def make_appcast begin versions = YAML.load_file("appcast/version_info.yml") rescue Exception => e raise StandardError, "appcast/version_info.yml could not be loaded: #{e.message}" end appcast = File.open("appcast/build/#{APPCAST_FILENAME}", 'w') xml = Builder::XmlMarkup.new(:target => appcast, :indent => 2) xml.instruct! xml.rss('xmlns:atom' => "http://www.w3.org/2005/Atom", 'xmlns:sparkle' => "http://www.andymatuschak.org/xml-namespaces/sparkle", :version => "2.0") do xml.channel do xml.title('BWA Linker') xml.link(APPCAST_URL) xml.description('Linker app updates') xml.language('en') xml.pubDate(Time.now.rfc822) xml.lastBuildDate(Time.now.rfc822) xml.atom(:link, :href => "#{APPCAST_URL}/#{APPCAST_FILENAME}", :rel => "self", :type => "application/rss+xml") versions.each do |version| guid = version.first items = version[1] file = "appcast/build/#{items['filename']}" xml.item do xml.title(items['title']) xml.description { xml << "#{items['description']}]]>" } xml.pubDate(File.mtime(file)) xml.enclosure(:url => "#{APPCAST_URL}/#{items['filename']}", :length => "#{File.size(file)}", :type => "application/zip") xml.guid(guid, :isPermaLink => "false") end end end endendLooking through that above, you'll want to modify the title and description at least. Now on to the uploader method:
def upload_appcast remote_dir = "/var/www/apps/bwa/shared/public/updaters/" Net::SSH.start( APPCAST_SERVER, 'deploy' ) do |session| cwd = Dir.pwd Dir.chdir('appcast/build') shell = session.shell.sync begin out = shell.cd remote_dir raise "Failed to change to proper remote directory." unless out.status == 0 out = shell.ls("-1") raise "Failed to get directory listing." unless out.status == 0 files = Array.new out.stdout.each { |file| files << file.strip } # Look through the list of files and see what we need to upload, as # compared to what we have locally - but always upload the appcast itself local_files = Dir.glob('*') files.delete(APPCAST_FILENAME) # we always upload this local_files.each do |local_file| unless files.include?(local_file) print "Uploading: #{local_file}... " `scp #{local_file} deploy@#{APPCAST_SERVER}:#{remote_dir}` puts $?.exitstatus == 0 ? "done." : "FAILED!" end end rescue => e puts "Failed: #{e.message}" ensure Dir.chdir(cwd) shell.exit end endendYou will of course want to modify the
remote_dir, and the login credentials towards the bottom (where it does the scp command). This also relies on you having your SSH keys set up, so you don't have to enter a password when it does the scp.You could further generalize this obviously, but this is what I have, it works fine, and I haven't needed to extract anything out further. Posting here as per a request, and hopefully it saves someone else a few minutes.
Comments [0]