So, in working on #384 (holy crap, it's coming along even better than I thought!), I ran into this little problem:
[ERROR] Could not find any versions of github.com/Masterminds/semver that met constraints:
1.1.0: Could not introduce github.com/Masterminds/semver at 1.1.0, as it is not allowed by constraint >=2.0.0, <3.0.0 from project github.com/Masterminds/glide.
1.0.1: Could not introduce github.com/Masterminds/semver at 1.0.1, as it is not allowed by constraint >=2.0.0, <3.0.0 from project github.com/Masterminds/glide.
1.0.0: Could not introduce github.com/Masterminds/semver at 1.0.0, as it is not allowed by constraint >=2.0.0, <3.0.0 from project github.com/Masterminds/glide.
2.x: Could not introduce github.com/Masterminds/semver at 2.x, as it is not allowed by constraint >=2.0.0, <3.0.0 from project github.com/Masterminds/glide.
master: Could not introduce github.com/Masterminds/semver at master, as it is not allowed by constraint >=2.0.0, <3.0.0 from project github.com/Masterminds/glide.
This, resulting from the following (abbreviated) glide.yaml for glide itself:
package: github.com/Masterminds/glide
import:
- package: gopkg.in/yaml.v2
- package: github.com/Masterminds/vcs
- package: github.com/codegangsta/cli
- package: github.com/Masterminds/semver
version: 2.x # <-- this is the problem
- package: github.com/sdboyer/vsolver
I knew this was gonna be an issue in general when I started implementing vsolver's interfaces on glide's Config and Lock types, but I didn't realize it was gonna crop up so soon.
The problem here is that 2.x - a valid semver string - is actually intended to be a literal branch name. But, because we have no guidance as to the type of constraint it's supposed to be, we just have to guess. I assume that right now, glide gets away with this by just checking to see what exists in the target repository, and assuming that if there's a direct string match, that's what the user wants. That's problematic, though - for one, it requires touching network and/or disk in order to verify.
More importantly, though, it means that the pure, locally-controlled inputs (manifest and static analysis of local project files) are no longer sufficient to govern the behavior of the algorithm. For example, in this particular case, if we rely on inferring from the list of branches in semver that 2.x is actually a branch, then that constraint becomes a branch - if, however, at some later time that branch goes away and we solve again, then we'd interpret that constraint as a semver range. Externalities are affecting the way we interpret inputs. And when the meaning of inputs are dependent on external factors, memoizing becomes pointless...so, the hash digest comparison that glide already does becomes kinda pointless.
The only solution here, really, is to add a new field that allows the user to specify the type of constraint they intend to provide. We can make this less onerous by letting the preferred constraint type be an assumed default. The approach that makes the most sense to me is:
- If no constraint type is specified, assume it's either semver or version - but, either way, tied to a non-floating version. semver's parser can then differentiate between those two.
branch must be specified as the constraint type if you want to track a branch
revision must be specified as the constraint type if you want to fix to an immutable revision
We could also throw a little magic in there like what I already wrote that tries to infer if it's a revision by seeing if it's 40 hex chars. I think the cost might outweigh the benefit there, though.
So, in working on #384 (holy crap, it's coming along even better than I thought!), I ran into this little problem:
This, resulting from the following (abbreviated)
glide.yamlfor glide itself:I knew this was gonna be an issue in general when I started implementing
vsolver's interfaces on glide'sConfigandLocktypes, but I didn't realize it was gonna crop up so soon.The problem here is that
2.x- a valid semver string - is actually intended to be a literal branch name. But, because we have no guidance as to the type of constraint it's supposed to be, we just have to guess. I assume that right now, glide gets away with this by just checking to see what exists in the target repository, and assuming that if there's a direct string match, that's what the user wants. That's problematic, though - for one, it requires touching network and/or disk in order to verify.More importantly, though, it means that the pure, locally-controlled inputs (manifest and static analysis of local project files) are no longer sufficient to govern the behavior of the algorithm. For example, in this particular case, if we rely on inferring from the list of branches in
semverthat2.xis actually a branch, then that constraint becomes a branch - if, however, at some later time that branch goes away and we solve again, then we'd interpret that constraint as a semver range. Externalities are affecting the way we interpret inputs. And when the meaning of inputs are dependent on external factors, memoizing becomes pointless...so, the hash digest comparison that glide already does becomes kinda pointless.The only solution here, really, is to add a new field that allows the user to specify the type of constraint they intend to provide. We can make this less onerous by letting the preferred constraint type be an assumed default. The approach that makes the most sense to me is:
branchmust be specified as the constraint type if you want to track a branchrevisionmust be specified as the constraint type if you want to fix to an immutable revisionWe could also throw a little magic in there like what I already wrote that tries to infer if it's a revision by seeing if it's 40 hex chars. I think the cost might outweigh the benefit there, though.