Skip to content
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

Merge stable #2299

Merged
merged 7 commits into from
Jul 13, 2022
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
39 changes: 36 additions & 3 deletions source/dub/dependency.d
Original file line number Diff line number Diff line change
Expand Up @@ -376,13 +376,16 @@ struct Dependency {

/** Tests if the specification matches a specific version.
*/
bool matches(string vers) const { return matches(Version(vers)); }
bool matches(string vers, VersionMatchMode mode = VersionMatchMode.standard) const { return matches(Version(vers), mode); }
/// ditto
bool matches(const(Version) v) const { return matches(v); }
bool matches(const(Version) v, VersionMatchMode mode = VersionMatchMode.standard) const { return matches(v, mode); }
/// ditto
bool matches(ref const(Version) v) const {
bool matches(ref const(Version) v, VersionMatchMode mode = VersionMatchMode.standard) const {
if (this.matchesAny) return true;
if (this.isSCM) return true;
if (this.isExactVersion && mode == VersionMatchMode.strict
&& this.version_.toString != v.toString)
return false;
return this.m_range.matches(v);
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This was refactored in master in the meantime. I moved the strict check before the new VersionRange.matches() call. Maybe the latter should get a new VersionMatchMode param and handle it itself?

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Probably, but the current version should work just fine, even if it's a bit ugly.

}

Expand Down Expand Up @@ -577,6 +580,13 @@ unittest {
assert(a.merge(b) == b);
assert(b.merge(a) == b);

assert(Dependency("1.0.0").matches(Version("1.0.0+foo")));
assert(Dependency("1.0.0").matches(Version("1.0.0+foo"), VersionMatchMode.standard));
assert(!Dependency("1.0.0").matches(Version("1.0.0+foo"), VersionMatchMode.strict));
assert(Dependency("1.0.0+foo").matches(Version("1.0.0+foo"), VersionMatchMode.strict));
assert(Dependency("~>1.0.0+foo").matches(Version("1.0.0+foo"), VersionMatchMode.strict));
assert(Dependency("~>1.0.0").matches(Version("1.0.0+foo"), VersionMatchMode.strict));

logDebug("Dependency unittest success.");
}

Expand Down Expand Up @@ -727,6 +737,19 @@ struct Version {
/// Tests if this represents the special unknown version constant.
@property bool isUnknown() const { return m_version == UNKNOWN_VERS; }

/** Tests two versions for equality, according to the selected match mode.
*/
bool matches(Version other, VersionMatchMode mode = VersionMatchMode.standard)
const {
if (this != other)
return false;

if (mode == VersionMatchMode.strict && this.toString() != other.toString())
return false;

return true;
}

/** Compares two versions/branches for precedence.

Versions generally have precedence over branches and the master branch
Expand Down Expand Up @@ -948,6 +971,11 @@ private struct VersionRange
}
}

enum VersionMatchMode {
standard, /// Match according to SemVer rules
strict /// Also include build metadata suffix in the comparison
}

unittest {
Version a, b;

Expand Down Expand Up @@ -1013,6 +1041,11 @@ unittest {
assert(Version("1.0.0+a") == Version("1.0.0+b"));

assert(Version("73535568b79a0b124bc1653002637a830ce0fcb8").isSCM);

assert(Version("1.0.0").matches(Version("1.0.0+foo")));
assert(Version("1.0.0").matches(Version("1.0.0+foo"), VersionMatchMode.standard));
assert(!Version("1.0.0").matches(Version("1.0.0+foo"), VersionMatchMode.strict));
assert(Version("1.0.0+foo").matches(Version("1.0.0+foo"), VersionMatchMode.strict));
}

/// Determines whether the given string is a Git hash.
Expand Down
5 changes: 3 additions & 2 deletions source/dub/dub.d
Original file line number Diff line number Diff line change
Expand Up @@ -535,7 +535,7 @@ class Dub {
foreach (ps; m_packageSuppliers) {
try {
auto versions = ps.getVersions(p);
if (versions.canFind!(v => dep.matches(v)))
if (versions.canFind!(v => dep.matches(v, VersionMatchMode.strict)))
continue next_pack;
} catch (Exception e) {
logWarn("Error querying versions for %s, %s: %s", p, ps.description, e.msg);
Expand Down Expand Up @@ -595,7 +595,8 @@ class Dub {
} else if (!ver.repository.empty) {
pack = m_packageManager.loadSCMPackage(p, ver);
} else {
pack = m_packageManager.getBestPackage(p, ver);
assert(ver.isExactVersion, "Resolved dependency is neither path, nor repository, nor exact version based!?");
pack = m_packageManager.getPackage(p, ver.version_);
if (pack && m_packageManager.isManagedPackage(pack)
&& ver.version_.isBranch && (options & UpgradeOptions.upgrade) != 0)
{
Expand Down
13 changes: 5 additions & 8 deletions source/dub/internal/git.d
Original file line number Diff line number Diff line change
Expand Up @@ -103,10 +103,7 @@ private string determineVersionFromGitDescribe(string describeOutput)
if (tag.startsWith("v") && isValidVersion(tag[1 .. $])) {
if (num == 0) return tag[1 .. $];
const i = tag.indexOf('+');
auto r = format("%s%scommit.%s.%s", tag[1 .. (i < 0) ? $ : i],
parts.length > 3 ? "." : "-", num, commit);
if (i > 0) r ~= tag[i .. $];
return r;
return format("%s%scommit.%s.%s", tag[1 .. $], i >= 0 ? '.' : '+', num, commit);
}
return null;
}
Expand All @@ -115,19 +112,19 @@ unittest {
// tag v1.0.0
assert(determineVersionFromGitDescribe("v1.0.0-0-deadbeef") == "1.0.0");
// 1 commit after v1.0.0
assert(determineVersionFromGitDescribe("v1.0.0-1-deadbeef") == "1.0.0-commit.1.deadbeef");
assert(determineVersionFromGitDescribe("v1.0.0-1-deadbeef") == "1.0.0+commit.1.deadbeef");
// tag v1.0.0+2.0.0
assert(determineVersionFromGitDescribe("v1.0.0+2.0.0-0-deadbeef") == "1.0.0+2.0.0");
// 12 commits after tag v1.0.0+2.0.0
assert(determineVersionFromGitDescribe("v1.0.0+2.0.0-12-deadbeef") == "1.0.0-commit.12.deadbeef+2.0.0");
assert(determineVersionFromGitDescribe("v1.0.0+2.0.0-12-deadbeef") == "1.0.0+2.0.0.commit.12.deadbeef");
// tag v1.0.0-beta.1
assert(determineVersionFromGitDescribe("v1.0.0-beta.1-0-deadbeef") == "1.0.0-beta.1");
// 2 commits after tag v1.0.0-beta.1
assert(determineVersionFromGitDescribe("v1.0.0-beta.1-2-deadbeef") == "1.0.0-beta.1.commit.2.deadbeef");
assert(determineVersionFromGitDescribe("v1.0.0-beta.1-2-deadbeef") == "1.0.0-beta.1+commit.2.deadbeef");
// tag v1.0.0-beta.2+2.0.0
assert(determineVersionFromGitDescribe("v1.0.0-beta.2+2.0.0-0-deadbeef") == "1.0.0-beta.2+2.0.0");
// 3 commits after tag v1.0.0-beta.2+2.0.0
assert(determineVersionFromGitDescribe("v1.0.0-beta.2+2.0.0-3-deadbeef") == "1.0.0-beta.2.commit.3.deadbeef+2.0.0");
assert(determineVersionFromGitDescribe("v1.0.0-beta.2+2.0.0-3-deadbeef") == "1.0.0-beta.2+2.0.0.commit.3.deadbeef");

// invalid tags
assert(determineVersionFromGitDescribe("1.0.0-0-deadbeef") is null);
Expand Down
14 changes: 9 additions & 5 deletions source/dub/packagemanager.d
Original file line number Diff line number Diff line change
Expand Up @@ -173,7 +173,7 @@ class PackageManager {
}

foreach (p; getPackageIterator(name))
if (p.version_ == ver)
if (p.version_.matches(ver, isManagedPackage(p) ? VersionMatchMode.strict : VersionMatchMode.standard))
return p;

return null;
Expand All @@ -188,9 +188,11 @@ class PackageManager {
/// ditto
Package getPackage(string name, Version ver, NativePath path)
{
foreach (p; getPackageIterator(name))
if (p.version_ == ver && p.path.startsWith(path))
foreach (p; getPackageIterator(name)) {
auto pvm = isManagedPackage(p) ? VersionMatchMode.strict : VersionMatchMode.standard;
if (p.version_.matches(ver, pvm) && p.path.startsWith(path))
return p;
}
return null;
}

Expand Down Expand Up @@ -316,9 +318,11 @@ class PackageManager {
Package getBestPackage(string name, Dependency version_spec, bool enable_overrides = true)
{
Package ret;
foreach (p; getPackageIterator(name))
if (version_spec.matches(p.version_) && (!ret || p.version_ > ret.version_))
foreach (p; getPackageIterator(name)) {
auto vmm = isManagedPackage(p) ? VersionMatchMode.strict : VersionMatchMode.standard;
if (version_spec.matches(p.version_, vmm) && (!ret || p.version_ > ret.version_))
ret = p;
}

if (enable_overrides && ret) {
if (auto ovr = getPackage(name, ret.version_))
Expand Down
49 changes: 49 additions & 0 deletions test/issue2262-exact-cached-version-match.sh
Original file line number Diff line number Diff line change
@@ -0,0 +1,49 @@
#!/usr/bin/env bash

. $(dirname ${BASH_SOURCE[0]})/common.sh

PACK_PATH="$CURR_DIR"/issue2262-exact-cached-version-match

# make sure that there are no left-over selections files
rm -f $PACK_PATH/dub.selections.json

# make sure that there are no cached versions of the dependency
dub remove gitcompatibledubpackage@* -n || true

# build normally, should select 1.0.4
if ! ${DUB} build --root $PACK_PATH | grep "gitcompatibledubpackage 1\.0\.4:"; then
die $LINENO 'The initial build failed.'
fi
dub remove gitcompatibledubpackage@* -n || true

# build with git dependency to a specific commit
cat > $PACK_PATH/dub.selections.json << EOF
{
"fileVersion": 1,
"versions": {
"gitcompatibledubpackage": {
"repository": "git+https://github.com/dlang-community/gitcompatibledubpackage.git",
"version": "ccb31bf6a655437176ec02e04c2305a8c7c90d67"
}
}
}
EOF
if ! ${DUB} build --root $PACK_PATH | grep "gitcompatibledubpackage 1\.0\.4+commit\.2\.gccb31bf:"; then
die $LINENO 'The build with a specific commit failed.'
fi

# select 1.0.4 again
cat > $PACK_PATH/dub.selections.json << EOF
{
"fileVersion": 1,
"versions": {
"gitcompatibledubpackage": "1.0.4"
}
}
EOF
if ! ${DUB} build --root $PACK_PATH | grep "gitcompatibledubpackage 1\.0\.4:"; then
die $LINENO 'The second 1.0.4 build failed.'
fi

# clean up
rm -f $PACK_PATH/dub.selections.json
Empty file.
2 changes: 2 additions & 0 deletions test/issue2262-exact-cached-version-match/dub.sdl
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
name "testproj"
dependency "gitcompatibledubpackage" version="~>1.0.4"
1 change: 1 addition & 0 deletions test/issue2262-exact-cached-version-match/source/app.d
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
void main() {}