sparkle-project / Sparkle

A software update framework for macOS
https://sparkle-project.org
Other
7.28k stars 1.04k forks source link

Preserve bundle creation date when creating and applying delta updates #2583

Open zorgiepoo opened 1 month ago

zorgiepoo commented 1 month ago

This will preserve the file creation date of the new app bundle, but not the file creation date of any of the files inside the new app bundle because tracking those changes is complex/undesirable. Other updater systems that use delta updates (like the App Store) also don't make guarantees about preserving that metadata for files inside the app bundle when applying delta updates.

This bumps the major binary delta version to 4 and will need documentation updates. generate_appcast has been updated to handle the major version. A new test has been added for testing that the new bundle creation date is also preserved.

Misc Checklist

Testing

I tested and verified my change by using one or multiple of these methods:

I will run through:

macOS version tested: 14.5 (23F79)

zorgiepoo commented 1 month ago

cc @core-code for awareness

core-code commented 1 month ago

awesome, many thanks! i've been meaning to send a patch about this issue for some time, but time is always in short supply.

a few questions and/or requests: • i see this preserves the creation date of the bundle, but what about the modification date? for example ls only displays the modification date • would it be possible to also preserve the dates for a few items inside the bundle? the rationale here is that the bundle is often touched by many tools, so its date may be quite unreliable anyway. for this reason MacUpdater has never looked directly at the app bundle when trying to determine the release date of an app, but instead looked for the dates of /Contents/Info.plist and /Contents/MacOS/$(CFBundleExecutable)

zorgiepoo commented 1 month ago

Sparkle always updates the modification date of the bundle before installing it to the current time, even absent of delta updates support. Historically this is due as a way to update the bundle for LaunchServices (I'm aware of LSRegisterURL but I don't think I want to change this and don't want to use LS-related functionality from the daemon. In the long ago past using LSRegisterURL was tried-and-quickly-reverted but I would have to dig that up again to see why). If I look at apps on my machine installed by the App Store, I see the modification dates are ahead of the creation dates, so I believe the App Store does the same thing as Sparkle (i.e, update modification time to current time when installing an app update).

For preserving these dates for "new" files inside the app bundle, that will be considerably more complicated (there are a number of permutations for the delta-update commands) and require more space in the archive. I don't think I want to do that and don't consider them important enough to preserve.

The primary motivation behind this change for me is to provide useful dates when users view info on the app bundle in Finder. The modification date reflects when the app was last updated by Sparkle/App Store, and the creation date reflects when the developer originally created the app.

From a point of view I actually think the creation date of the app bundle is more accurate than the creation date of files inside of it. For example for an app installed from the App Store, the creation date of the app bundle reflects the original developer creating the app, while the creation date of Contents/MacOS/$(CFBundleExecutable) may instead reflect when the app was re-signed by the App Store -- an "internal" detail so to speak. Similarly, what Sparkle may write inside an app bundle to update it in the case of delta updates is an "internal" detail. edit: some other external tool could update the executable with a new creation date too, for example, to strip out an architecture slice.

core-code commented 1 week ago

sorry for the delay here (my pleas for the 30 hour day still go unheard…).

The primary motivation behind this change for me is to provide useful dates when users view info on the app bundle in Finder. The modification date reflects when the app was last updated by Sparkle/App Store, and the creation date reflects when the developer originally created the app.

this sounds useful and it would be great if that were always the case

From a point of view I actually think the creation date of the app bundle is more accurate than the creation date of files inside of it.

unfortunately it is just not true. i like to talk with hard data, so i've downloaded a lot of apps to run some tests. 1045 of those apps were code-signed which provides the best possible estimate for the "true release date" of the app.

i looked at the creation and modification dates of the bundle, the info plist and the executable, and calculated their difference to the true release date. for the sake of the experiment i ignored deviations of less than 5 days.

the results are Bundle Creation Date: 50 deviations Bundle Modification Date: 62 deviations

Plist Creation Date: 16 deviations Plist Modification Date: 12 deviations

Exe Creation Date: 3 deviations Exe Modification Date: 2 deviations

so the results are clear, looking at the bundle is a bad way to find out when an app has been released/built. the plist is a lot better and the exe is definitely the best approximation.

also, the bundle dates are often off by a LOT. brand new Ableton releases have bundle creation dates from 2011, and in a few cases the bundle is older than 2010 and in some cases we even see dates from the past millennium.

these results are from freshly-downloaded apps. i believe the results will be even more pronounced in the real world. while there are ways the exe or plist can get touched, it is a lot more likely for the bundle dates to become unreliable because they have been modified.

so, i had hoped we could simplify the "app release date detection" to just looking at the bundle creation date, but given the above results that would be a severe regression.

For preserving these dates for "new" files inside the app bundle, that will be considerably more complicated and require more space in the archive.

i am not sure why this would require much more space. 2 dates (plist and exe) should be encodable in 4 bytes when just storing the date and dismissing the time.

regarding complications, is this something i should look into?

zorgiepoo commented 1 week ago

At least with App Store apps, the creation date of the bundle is reflective of the developer creating the app while the creation date of the main executable (which is later) is reflective of when the executable is re-signed by the App Store. This is a deviation but doesn't mean the outer bundle one is "more wrong", at least for this case.

For my end it's just simpler to only account for the bundle, which is the most user-facing date. The format does not hardcode specifics for Info.plist files or main executable files, and if it were to remain that way, it may need to record a date per new changed file (and of course similar to App Store deltas it would not record dates for other files that haven't changed in content). My direct goal is not to adhere to a system that makes it easier for other tools to find a "release date" across various different ways developers distribute apps.

(I just haven't merged this because it's been on my backlog, and also I'm hoping to make other unrelated major changes to the format.. maybe)

core-code commented 1 week ago

For my end it's just simpler to only account for the bundle, which is the most user-facing date. My direct goal is not to adhere to a system that makes it easier for other tools to find a "release date" across various different ways developers distribute apps.

fully agreed and thanks anyway. a note to the documentation ( https://sparkle-project.org/documentation/delta-updates/ ) should suffice. something about that applying updates using delta updates has a bit-for-bit identical result for all data, but metadata (like creation dates) will not be preserved.

FWIW, code-signature dates as release dates are more reliable anyway and luckily there aren't so many unsigned apps anyway.