diff --git a/source/dub/packagemanager.d b/source/dub/packagemanager.d index 179a81a..3b071b8 100644 --- a/source/dub/packagemanager.d +++ b/source/dub/packagemanager.d @@ -464,13 +464,19 @@ string gitReference = repo.ref_.chompPrefix("~"); NativePath destination = this.getPackagePath(PlacementLocation.user, name, repo.ref_); - foreach (p; getPackageIterator(name.toString())) { - if (p.path == destination) { - return p; - } - } - - if (!this.gitClone(repo.remote, gitReference, destination)) + // Before doing a git clone, let's see if the package exists locally + if (this.existsDirectory(destination)) { + // It exists, check if we already loaded it. + // Either we loaded it on refresh and it's in PlacementLocation.user, + // or we just added it and it's in m_internal. + foreach (p; this.m_internal.fromPath) + if (p.path == destination) + return p; + if (this.m_repositories.length) + foreach (p; this.m_repositories[PlacementLocation.user].fromPath) + if (p.path == destination) + return p; + } else if (!this.gitClone(repo.remote, gitReference, destination)) return null; Package result = this.load(destination); diff --git a/source/dub/test/base.d b/source/dub/test/base.d index 89c0624..d61dc66 100644 --- a/source/dub/test/base.d +++ b/source/dub/test/base.d @@ -784,6 +784,11 @@ { auto entry = this.lookup(path); enforce(entry.attributes.type == Type.File, "Trying to read a directory"); + // This is a hack to make poisoning a file possible. + // However, it is rather crude and doesn't allow to poison directory. + // Consider introducing a derived type to allow it. + assert(entry.content != "poison".representation, + "Trying to access poisoned path: " ~ path.toNativeString()); return entry.content.dup; } @@ -792,11 +797,11 @@ { import std.utf : validate; - auto entry = this.lookup(path); - enforce(entry.attributes.type == Type.File, "Trying to read a directory"); + const content = this.readFile(path); // Ignore BOM: If it's needed for a test, add support for it. - validate(cast(const(char[])) entry.content); - return cast(string) entry.content.idup(); + validate(cast(const(char[])) content); + // `readFile` just `dup` the content, so it's safe to cast. + return cast(string) content; } /// Write to this file diff --git a/source/dub/test/other.d b/source/dub/test/other.d index 241fb0f..e3a17db 100644 --- a/source/dub/test/other.d +++ b/source/dub/test/other.d @@ -79,3 +79,26 @@ const actualDir = newDub.project.getDependency("b", true).path(); assert(actualDir == BDir, actualDir.toNativeString()); } + +// Check that SCM-only dependencies don't lead to a scan of the FS +unittest +{ + const ValidURL = `git+https://example.com/dlang/dub`; + // Taken from a commit in the dub repository + const ValidHash = "54339dff7ce9ec24eda550f8055354f712f15800"; + const Template = `{"name": "%s", "version": "1.0.0", "dependencies": { +"dep1": { "repository": "%s", "version": "%s" }}}`; + + scope dub = new TestDub((scope FSEntry fs) { + // This should never be read + fs.writePackageFile("poison", "1.0.0", `poison`); + fs.writeFile(TestDub.ProjectPath ~ "dub.json", + `{ "name": "a", "dependencies": {"b": { "repository": "` ~ + ValidURL ~ `", "version": "` ~ ValidHash ~ `" }} }`); + }); + dub.packageManager.addTestSCMPackage( + Repository(ValidURL, ValidHash), `{"name":"b"}`); + + dub.loadPackage(); + assert(dub.project.hasAllDependencies()); +}