-
-
Notifications
You must be signed in to change notification settings - Fork 57
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
Avoiding binary incompatibilities between codependent frameworks #200
Comments
Interesting idea. How would one map from Cartfile.resolved committish to the final hash? |
Ah, I came back to agree with your stance on semver 😆 But I'm happy to discuss further.
I think this is a reasonable stance—the real point of contention is whether an ABI-breaking but source-compatible change is "breaking" the context of semver. IMO, It probably is if you're thinking about frameworks as discrete binaries (similar to Apple's definition of "binary frameworks"). It probably isn't if you're thinking about frameworks as bundles of source code that are buildable on demand.
In pseudocode, the version hash for a dependency is the hash of its version plus the hash of its subdependencies' versions:
This assumes that the dependencies are checked out, so that you can find a Cartfile for each dependency and build up a dependency graph. |
While I was messing around with this, I wrote an implementation of the above algorithm in Python, which might be relevant for discussion :) https://gist.github.com/elliottwilliams/fdf7730ef06809abeb88299a97d57ffa |
Right now, Rome uses the resolved version of a framework to distinguish it inside the cache. This is nice because it parallels what Carthage writes to the resolved Cartfile, but it leads to potential binary incompatibilities between when frameworks in a project depend on each other. If one framework is updated but its consumer isn't, the latter framework can become out of sync in the cache and lead to runtime crashes in the project.
I'm curious if Rome has ever thought about hashing a framework's version with its dependencies' versions, and using that as a cache key. This would mean that resolving and building a new version of a framework's dependency would also cause that framework to be seen as missing and reuploaded.
Steps which explain the enhancement
Consider the following Cartfiles:
Say
leaf
's most recent version is1.4.0
. Carthage resolves and buildsleaf 1.4.0
andnode 1.2.3
. Rome uploads these, producing the following cache files:Next, suppose
leaf
releases1.5.0
, which contains a binary-breaking change. (For instance, imagine a parameter is added to a function with a default value. The default value means that node's existing source code will compile, but the symbol name will have changed.)Locally, we update our Cartfile to require
git "../leaf" ~> 1.5.0
and runcarthage update leaf --cache-builds
:Carthage understands the dependency relationship, and has conservatively rebuilt both leaf and node. This is great! It means that locally, we've got versions of both dependencies that must be binary-compatible.
Current and suggested behavior
However, when
rome list --missing
is used to detect missing dependencies, it only reports thatleaf 1.5.0
is missing, since the cache already contains a build ofnode 1.2.3
. If you're using the --cache-builds workflow, Rome only uploadsleaf 1.5.0
, meaning that the cache now contains:The next time someone else uses the cache, Rome will give them a bad version of
node
— one that only works withleaf 1.4.0
. That build will crash on launch with an error from dyld.Why would the enhancement be useful to most users
If Rome hashed frameworks using resolved versions of their dependencies, the cache could contain different builds of the same version. Given version hashes like:
the cache would contain products like:
and Rome could download the correct build of
node
regardless of the pinned version ofleaf
.Personally, I'm evaluating Rome in an organization that has a lot of tightly coupled dependencies—I can imagine this is less useful when you have few codependencies in a repo, but afaict this is a general purpose cache invalidation problem. Let me know if this makes sense! I'd be happy to try to dive into it if you think it's a useful enhancement.
Rome version: 0.23.1.61
OS and version: macOS 10.14.6
The text was updated successfully, but these errors were encountered: