-
Notifications
You must be signed in to change notification settings - Fork 276
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
🔍 Upgrade only to newer versions #346
Conversation
This addresses an issue where The App Store search API is behind an Akamai CDN with a caching mechanism that sometimes reports (slightly) out-of-date information. Requesting the same information multiple times might yield dissimilar results while the CDN reaches eventual consistency. (Example here.) Before #345, this was ameliorated by the In an effort to avoid inadvertently "upgrading" to an older version, I thought it might be best to start comparing version numbers instead of checking for version string equality. One wrinkle with that plan is that the App Store does not enforce semantic versioning. However, we will assume most apps are sane and follow versioning schemes that increase numerically over time. Another wrinkle is that the App Store seems to allow vendors to publish a new release with a lower-numbered version than a previous release. In this case, the App Store app would update to the new, lower-numbered version while As seen in #331, the App Store seems to allow vendors to publish an app bundle with a If a version string from a bundle or from the App Store can't be parsed as a Semantic Version, our best effort is to revert to checking for string equality. The only version that matters is the one in the App Store. Note that this change doesn't fix the eventual consistency problem. Note also that this change does not address #331, where an app will always appear to be outdated because its bundle version does not match its App Store version. |
This last change should address the specific case outlined in #331, in that Messenger's bundle version However, this would not address a hypothetically possible case where a vendor publishes a release to the App Store with a version that is "newer" than its bundle version. In that case, |
I discovered that the app pages frequently list versions that are newer than what the search API returns. It seems that there's a delay before the search API is updated with newly published releases, unrelated to the client cache or the Akamai CDN cache. To work around this, I added logic to scrape the current version from the app page. |
Sorry for the delay in looking at this, @chris-araman. Fantastic research! I'm not surprised by these issues as the related commands were broken for so long. I'll start looking closer at these changes tonight. |
I snuck one more in to reduce the public surface area (and binary size). I'm done for the night. All yours! |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This is such great work! I have mostly style questions and suggestions.
MasKit/Network/NetworkManager.swift
Outdated
} | ||
|
||
return result | ||
throw MASError.noData |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Ending the method on an error case makes me a bit twitchy,. Could you switch this up and have the happy/golden path end the method?
throw MASError.noData | |
guard let data = data else { | |
throw MASError.noData | |
} | |
return data |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I agree it's awkward. I went back and forth on this. The problem is that this definition would conflict with the definition of data
on L42.
I've committed a force-unwrap instead as a85d4e8. Is that less twitchy?
Regarding the future direction of async code in mas-cli, I'm not thrilled with the current pyramid-of-doom style. We can't just use Swift Combine, because it requires macOS 10.15 or later. I could see a few options:
I think any of the above options would let us simplify the async code in MasKit a bit, at the cost of adding to our list of dependencies. Do you have any thoughts on this, @phatblat? Also: Unrelated, but I'm curious, what was the motivation behind breaking MasKit out into its own framework? Is there a goal to publish it as an SPM package? It seems like we could simplify the install a bit by linking MasKit and Commandant as libraries into the executable, instead of laying them down as frameworks. |
RE: Async patterns/frameworks. Maybe I'll just post PRs for a couple of options and see what you think. Did you need anything else from me on this PR, @phatblat? |
Sorry for the delay. I like your thinking on the management of async code but I haven't had time to digest the options yet. Let me approve this PR so we can move forward. |
Also:
🏃 Throw any errors from Process.run