I have been using Sparkle Appcast APP since initially released by Shane for enhanced apps.
Just last week I dragged and dropped to no result. I converted the app so I could test and see what’s going on and it worked with very little changes. I added choose file & changed the handler to on run instead of on open.
I post the XML and Zip file to the server address I have always used. The app gets an ‘An error occurred in retrieving update information. Please try again later.’ error when I check for updates.
I have compared setup of the app and all is identical to previous.
There is one file that is different now…the XML.
The enclosure line now is different than previous versions. The new version
I upgraded Shane’s Appcast example to fix the issue with URL, used his PrefsStorageLib & Dialog Toolkit Plus to maintain a change log and enter them. If anyone wants or wants to offer feedback on making it better:
-- Created by: Shane Stanley
-- Created on: 22/3/18
-- Modified by: Dean Marshall 1/19/2023
use AppleScript version "2.4" -- Yosemite (10.10) or later
use framework "Foundation"
use framework "AppKit"
use script "Dialog Toolkit Plus" ---version "1.1.0"
use script "PrefsStorageLib"
use scripting additions
-- classes, constants, and enums used
property NSCharacterSet : a reference to current application's NSCharacterSet
property NSURL : a reference to current application's NSURL
property NSWorkspace : a reference to current application's NSWorkspace
property NSXMLTextKind : a reference to 7
property NSXMLNodeIsCDATA : a reference to 1
property NSNumberFormatterNoStyle : a reference to 0
property NSXMLNodePrettyPrint : a reference to 131072
property NSFileManager : a reference to current application's NSFileManager
property |NSURL| : a reference to current application's |NSURL|
property NSDateFormatter : a reference to current application's NSDateFormatter
property NSTimeZone : a reference to current application's NSTimeZone
property NSXMLNode : a reference to current application's NSXMLNode
property NSXMLDocument : a reference to current application's NSXMLDocument
property NSNumberFormatter : a reference to current application's NSNumberFormatter
property NSURLFileSizeKey : a reference to current application's NSURLFileSizeKey
property NSBundle : a reference to current application's NSBundle
property NSString : a reference to current application's NSString
property NSDate : a reference to current application's NSDate
on run
----set oneFile to choose file
set diaResponse to dialogAppcast("Create Appcast File")
if item 1 of diaResponse is not "" then
set logString to item 1 of diaResponse as string
set appPosixPathAS to item 4 of diaResponse as string
else
return
end if
---set appPosixPathAS to POSIX path of oneFile
set appPosixPath to NSString's stringWithString:appPosixPathAS
set destFolder to appPosixPath's stringByDeletingLastPathComponent() -- where to place new file; same folder as applet
-- get Info.plist details from applet
set theNSBundle to NSBundle's bundleWithPath:appPosixPath
set theNSDictionary to theNSBundle's infoDictionary()
set appName to theNSDictionary's objectForKey:"CFBundleName"
set shortVersion to theNSDictionary's objectForKey:"CFBundleShortVersionString"
set buildVersion to theNSDictionary's objectForKey:"CFBundleVersion"
set appcastLink to theNSDictionary's objectForKey:"SUFeedURL"
set shortDate to short date string of (current date)
set prettyVersion to ("Version " & shortVersion & "." & buildVersion) as string
set appBundleIdentifier to theNSDictionary's objectForKey:"CFBundleIdentifier"
set appDomain to appBundleIdentifier as string
prepare storage for domain appDomain
set prefsChangeLog to value for key "App_Update"
set templist to my explode(appDomain, ".")
set appShortName to (item (length of templist) of templist) as string
set dateNow to current date
set prettyDate to date string of dateNow
if prefsChangeLog = missing value then
set prefsChangeLog to ""
end if
set changeParas to paragraphs of logString
set changeLog to ""
repeat with x from 1 to (length of changeParas)
set aLine to item x of changeParas
log aLine
if aLine is not "" then
set theLine to "<li>" & aLine & "</li>"
set changeLog to (changeLog & theLine & return) as string
end if
end repeat
if appcastLink = missing value then error "The application does not have an entry for SUFeedURL in its Info.plist file."
-- choose DSA key file
using terms from scripting additions
--set privateDSAPathAS to POSIX path of (choose file with prompt "Choose your private DSA key file (dsa_priv.pem):" of type {"pem"})
set privateDSAPathAS to POSIX path of "somepath/dsa_priv.pem" ---hard code yourprivateDSAPath here
end using terms from
-- build local path for .zip
set zipName to appPosixPath's lastPathComponent()'s stringByDeletingPathExtension()'s stringByAppendingPathExtension:"zip"
set zipDestPath to appPosixPath's stringByDeletingLastPathComponent()'s stringByAppendingPathComponent:zipName
-- remove any old version
set theNSFileManager to NSFileManager's defaultManager()
theNSFileManager's removeItemAtPath:zipDestPath |error|:(missing value)
-- make zip file and sign it
using terms from scripting additions
do shell script "ditto -c -k --keepParent " & quoted form of appPosixPathAS & space & quoted form of (zipDestPath as text)
set theSignature to do shell script "openssl dgst -sha1 -binary < " & (quoted form of (zipDestPath as text)) & " | openssl dgst -dss1 -sign " & (quoted form of privateDSAPathAS) & "| openssl enc -base64"
end using terms from
-- get zip size
set zipNSURL to NSURL's fileURLWithPath:zipDestPath
set {theResult, theSize} to zipNSURL's getResourceValue:(reference) forKey:(NSURLFileSizeKey) |error|:(missing value)
set sizeString to NSNumberFormatter's localizedStringFromNumber:theSize numberStyle:NSNumberFormatterNoStyle
-- build appcast link to app .zip
set appcastName to appcastLink's lastPathComponent()
set appcastDir to appcastLink's substringToIndex:((appcastLink's |length|()) - (appcastName's |length|()))
set appcastZipLink to appcastDir's stringByAppendingPathComponent:(zipName's stringByAddingPercentEncodingWithAllowedCharacters:(NSCharacterSet's URLQueryAllowedCharacterSet()))
set appcastDestPath to appPosixPath's stringByDeletingLastPathComponent()'s stringByAppendingPathComponent:appcastName
-- make xml
set rootElement to NSXMLNode's elementWithName:"rss"
rootElement's setAttributesWithDictionary:{|version|:"2.0", |xmlns:sparkle|:"http://www.andymatuschak.org/xml-namespaces/sparkle", |xmlns:dc|:"http://purl.org/dc/elements/1.1/"}
set theXMLDocument to NSXMLDocument's alloc()'s initWithRootElement:rootElement
theXMLDocument's setCharacterEncoding:"UTF-8"
theXMLDocument's setVersion:"1.0"
set theChanel to NSXMLNode's elementWithName:"channel"
rootElement's addChild:theChanel
theChanel's addChild:(NSXMLNode's elementWithName:"title" stringValue:(appName's stringByAppendingString:" Changelog"))
theChanel's addChild:(NSXMLNode's elementWithName:"description" stringValue:"Update")
theChanel's addChild:(NSXMLNode's elementWithName:"link" stringValue:appcastLink)
theChanel's addChild:(NSXMLNode's elementWithName:"language" stringValue:"en")
set theItem to NSXMLNode's elementWithName:"item"
theChanel's addChild:theItem
theItem's addChild:(NSXMLNode's elementWithName:"title" stringValue:("Version " & shortVersion))
theItem's addChild:(NSXMLNode's elementWithName:"pubDate" stringValue:(my dateString()))
set theEnclosure to NSXMLNode's elementWithName:"enclosure"
theEnclosure's setAttributesWithDictionary:{|url|:appcastZipLink, |sparkle:version|:buildVersion, |sparkle:shortVersionString|:shortVersion, |length|:sizeString, |type|:"application/octet-stream", |sparkle:dsaSignature|:theSignature}
theItem's addChild:theEnclosure
set theDesc to NSXMLNode's elementWithName:"description"
set cdataNode to NSXMLNode's alloc()'s initWithKind:NSXMLTextKind options:NSXMLNodeIsCDATA
set updatedChangeLog to "<p><strong>" & prettyVersion & " Bug Fixes and New Features</strong></p>
<ul>
" & changeLog & "
</ul>
"
cdataNode's setStringValue:("
<div class=\"meta\"><i class=\"far fa-clock\"></i>Last updated: " & prettyDate & "</div>
" & updatedChangeLog & "
<hr style=\"border: 1px dashed black;\" />
<p><strong>Previous Updates</strong></p>
<ul>
" & prefsChangeLog & "
</ul>
")
theDesc's addChild:cdataNode
theItem's addChild:theDesc
-- write appcast file
set theData to theXMLDocument's XMLDataWithOptions:NSXMLNodePrettyPrint
theData's writeToFile:appcastDestPath atomically:true
---add to apps changeLogHistory
set prefsUpdateChangeLog to (updatedChangeLog & return & prefsChangeLog) as string
assign value prefsUpdateChangeLog to key "App_Update"
--assign value "" to key "App_Update"
-- show the files in the Finder
NSWorkspace's sharedWorkspace()'s activateFileViewerSelectingURLs:{NSURL's fileURLWithPath:appcastDestPath, zipNSURL}
--current application's NSBeep()
(current application's NSSound's soundNamed:"Glass")'s play() ---because I like this better!
end run
on dateString()
set theNSDateFormatter to NSDateFormatter's new()
theNSDateFormatter's setDateFormat:"EEE, dd MMM yyy HH:mm:ss Z"
theNSDateFormatter's setTimeZone:(NSTimeZone's timeZoneForSecondsFromGMT:0)
return theNSDateFormatter's stringFromDate:(NSDate's |date|())
end dateString
--Sub-routine to explode a string into a list
on explode(theText, theDelim)
set AppleScript's text item delimiters to theDelim
set theList to text items of theText
set AppleScript's text item delimiters to ""
return theList
end explode
on dialogAppcast(theApp)
set accViewWidth to 400
set {theButtons, minWidth} to create buttons {"Cancel", "OK"} default button 2
if minWidth > accViewWidth then set accViewWidth to minWidth -- make sure buttons fit
set {instructionsField, instructionsLabel, theTop} to create top labeled field "" placeholder text "Enter your change log here" bottom 0 field width accViewWidth extra height 60 label text "Instructions" with accepts linebreak and tab
set {theRule, theTop} to create rule (theTop + 12) rule width accViewWidth
set {thePathControl, pathLabel, theTop} to create labeled path control (POSIX path of (path to documents folder)) bottom (theTop + 12) control width accViewWidth label text "Choose or drag the file here:"
set allControls to {instructionsField, instructionsLabel, theRule, thePathControl, pathLabel}
set {buttonName, controlsResults} to display enhanced window theApp acc view width accViewWidth acc view height theTop acc view controls allControls buttons theButtons active field instructionsField with align cancel button
return controlsResults
end dialogAppcast
Makes sense but the original reason it failed doesn’t because I added that afterwards when I updated the applet. It did not have the line but fails to run on OS 13.1. What OS are you running? This is the original code that fails.
--
-- Created by: Shane Stanley
-- Created on: 22/3/18
--
use AppleScript version "2.4" -- Yosemite (10.10) or later
use framework "Foundation"
use framework "AppKit"
-- classes, constants, and enums used
property NSCharacterSet : a reference to current application's NSCharacterSet
property NSURL : a reference to current application's NSURL
property NSWorkspace : a reference to current application's NSWorkspace
property NSXMLTextKind : a reference to 7
property NSXMLNodeIsCDATA : a reference to 1
property NSNumberFormatterNoStyle : a reference to 0
property NSXMLNodePrettyPrint : a reference to 131072
property NSFileManager : a reference to current application's NSFileManager
property |NSURL| : a reference to current application's |NSURL|
property NSDateFormatter : a reference to current application's NSDateFormatter
property NSTimeZone : a reference to current application's NSTimeZone
property NSXMLNode : a reference to current application's NSXMLNode
property NSXMLDocument : a reference to current application's NSXMLDocument
property NSNumberFormatter : a reference to current application's NSNumberFormatter
property NSURLFileSizeKey : a reference to current application's NSURLFileSizeKey
property NSBundle : a reference to current application's NSBundle
property NSString : a reference to current application's NSString
property NSDate : a reference to current application's NSDate
on open {oneFile}
set appPosixPathAS to POSIX path of oneFile
set appPosixPath to NSString's stringWithString:appPosixPathAS
set destFolder to appPosixPath's stringByDeletingLastPathComponent() -- where to place new file; same folder as applet
-- get Info.plist details from applet
set theNSBundle to NSBundle's bundleWithPath:appPosixPath
set theNSDictionary to theNSBundle's infoDictionary()
set appName to theNSDictionary's objectForKey:"CFBundleName"
set shortVersion to theNSDictionary's objectForKey:"CFBundleShortVersionString"
set buildVersion to theNSDictionary's objectForKey:"CFBundleVersion"
set appcastLink to theNSDictionary's objectForKey:"SUFeedURL"
if appcastLink = missing value then error "The application does not have an entry for SUFeedURL in its Info.plist file."
-- choose DSA key file
using terms from scripting additions
set privateDSAPathAS to POSIX path of (choose file with prompt "Choose your private DSA key file (dsa_priv.pem):" of type {"pem"})
end using terms from
-- build local path for .zip
set zipName to appPosixPath's lastPathComponent()'s stringByDeletingPathExtension()'s stringByAppendingPathExtension:"zip"
set zipDestPath to appPosixPath's stringByDeletingLastPathComponent()'s stringByAppendingPathComponent:zipName
-- remove any old version
set theNSFileManager to NSFileManager's defaultManager()
theNSFileManager's removeItemAtPath:zipDestPath |error|:(missing value)
-- make zip file and sign it
using terms from scripting additions
do shell script "ditto -c -k --keepParent " & quoted form of appPosixPathAS & space & quoted form of (zipDestPath as text)
set theSignature to do shell script "openssl dgst -sha1 -binary < " & (quoted form of (zipDestPath as text)) & " | openssl dgst -dss1 -sign " & (quoted form of privateDSAPathAS) & "| openssl enc -base64"
end using terms from
-- get zip size
set zipNSURL to NSURL's fileURLWithPath:zipDestPath
set {theResult, theSize} to zipNSURL's getResourceValue:(reference) forKey:(NSURLFileSizeKey) |error|:(missing value)
set sizeString to NSNumberFormatter's localizedStringFromNumber:theSize numberStyle:NSNumberFormatterNoStyle
-- build appcast link to app .zip
set appcastName to appcastLink's lastPathComponent()
set appcastDir to appcastLink's substringToIndex:((appcastLink's |length|()) - (appcastName's |length|()))
set appcastZipLink to appcastDir's stringByAppendingPathComponent:(zipName's stringByAddingPercentEncodingWithAllowedCharacters:(NSCharacterSet's URLQueryAllowedCharacterSet()))
set appcastDestPath to appPosixPath's stringByDeletingLastPathComponent()'s stringByAppendingPathComponent:appcastName
-- make xml
set rootElement to NSXMLNode's elementWithName:"rss"
rootElement's setAttributesWithDictionary:{|version|:"2.0", |xmlns:sparkle|:"http://www.andymatuschak.org/xml-namespaces/sparkle", |xmlns:dc|:"http://purl.org/dc/elements/1.1/"}
set theXMLDocument to NSXMLDocument's alloc()'s initWithRootElement:rootElement
theXMLDocument's setCharacterEncoding:"UTF-8"
theXMLDocument's setVersion:"1.0"
set theChanel to NSXMLNode's elementWithName:"channel"
rootElement's addChild:theChanel
theChanel's addChild:(NSXMLNode's elementWithName:"title" stringValue:(appName's stringByAppendingString:" Changelog"))
theChanel's addChild:(NSXMLNode's elementWithName:"description" stringValue:"Update")
theChanel's addChild:(NSXMLNode's elementWithName:"link" stringValue:appcastLink)
theChanel's addChild:(NSXMLNode's elementWithName:"language" stringValue:"en")
set theItem to NSXMLNode's elementWithName:"item"
theChanel's addChild:theItem
theItem's addChild:(NSXMLNode's elementWithName:"title" stringValue:("Version " & shortVersion))
theItem's addChild:(NSXMLNode's elementWithName:"pubDate" stringValue:(my dateString()))
set theEnclosure to NSXMLNode's elementWithName:"enclosure"
theEnclosure's setAttributesWithDictionary:{url:appcastZipLink, |sparkle:version|:buildVersion, |sparkle:shortVersionString|:shortVersion, |length|:sizeString, |type|:"application/octet-stream", |sparkle:dsaSignature|:theSignature}
theItem's addChild:theEnclosure
set theDesc to NSXMLNode's elementWithName:"description"
set cdataNode to NSXMLNode's alloc()'s initWithKind:NSXMLTextKind options:NSXMLNodeIsCDATA
cdataNode's setStringValue:"
<h2>Update Info</h2>
<p>Details of update.</p>
"
theDesc's addChild:cdataNode
theItem's addChild:theDesc
-- write appcast file
set theData to theXMLDocument's XMLDataWithOptions:NSXMLNodePrettyPrint
theData's writeToFile:appcastDestPath atomically:true
-- show the files in the Finder
NSWorkspace's sharedWorkspace()'s activateFileViewerSelectingURLs:{NSURL's fileURLWithPath:appcastDestPath, zipNSURL}
current application's NSBeep()
end open
on dateString()
set theNSDateFormatter to NSDateFormatter's new()
theNSDateFormatter's setDateFormat:"EEE, dd MMM yyy HH:mm:ss Z"
theNSDateFormatter's setTimeZone:(NSTimeZone's timeZoneForSecondsFromGMT:0)
return theNSDateFormatter's stringFromDate:(NSDate's |date|())
end dateString