From a051dbfcb7e267b874f29b21628ccc3f77965f3a Mon Sep 17 00:00:00 2001 From: Mathias Lang Date: Wed, 25 Sep 2024 00:24:36 +0200 Subject: [PATCH 1/8] feat(fs): Implement chdir to change the working directory Currently our working directory is always the root, which means that we didn't care about absolute vs relative path until now. --- source/dub/internal/io/filesystem.d | 3 +++ source/dub/internal/io/mockfs.d | 8 ++++++++ source/dub/internal/io/realfs.d | 6 ++++++ 3 files changed, 17 insertions(+) diff --git a/source/dub/internal/io/filesystem.d b/source/dub/internal/io/filesystem.d index 414005551..d1373fadc 100644 --- a/source/dub/internal/io/filesystem.d +++ b/source/dub/internal/io/filesystem.d @@ -26,6 +26,9 @@ public interface Filesystem /// Returns: The `path` of this FSEntry public abstract NativePath getcwd () const scope; + /// Change current directory to `path`. Equivalent to `cd` in shell. + public abstract void chdir (in NativePath path) scope; + /** * Implements `mkdir -p`: Create a directory and every intermediary * diff --git a/source/dub/internal/io/mockfs.d b/source/dub/internal/io/mockfs.d index 20954d2db..1a0340234 100644 --- a/source/dub/internal/io/mockfs.d +++ b/source/dub/internal/io/mockfs.d @@ -34,6 +34,14 @@ public final class MockFS : Filesystem { return this.cwd.path(); } + public override void chdir (in NativePath path) scope + { + auto tmp = this.lookup(path); + enforce(tmp !is null, "No such directory: " ~ path.toNativeString()); + enforce(tmp.isDirectory(), "Cannot chdir into non-directory: " ~ path.toNativeString()); + this.cwd = tmp; + } + /// public override bool existsDirectory (in NativePath path) const scope { diff --git a/source/dub/internal/io/realfs.d b/source/dub/internal/io/realfs.d index 9497169c0..2f67f0ce3 100644 --- a/source/dub/internal/io/realfs.d +++ b/source/dub/internal/io/realfs.d @@ -28,6 +28,12 @@ public final class RealFS : Filesystem { return this.path_; } + /// + public override void chdir (in NativePath path) scope + { + std.file.chdir(path.toNativeString()); + } + /// protected override bool existsDirectory (in NativePath path) const scope { From 8d474404c192b36d707928f81d5d895fe0cab73b Mon Sep 17 00:00:00 2001 From: Mathias Lang Date: Sat, 13 Jul 2024 00:41:14 +0200 Subject: [PATCH 2/8] fix(mockfs): Improve Windows support and add tests On Windows, the root has a name, which is the drive, unlike on POSIX where the root is an empty name. This led to a flurry of problems because we assumed a POSIX style, where the FS is a directed graph, while on Windows it is multiple unconnected graphs (the drives cannot be accessed via a relative path). --- source/dub/internal/io/mockfs.d | 70 +++++++++++++++++++++++++++++---- source/dub/test/base.d | 2 +- 2 files changed, 64 insertions(+), 8 deletions(-) diff --git a/source/dub/internal/io/mockfs.d b/source/dub/internal/io/mockfs.d index 1a0340234..369aec690 100644 --- a/source/dub/internal/io/mockfs.d +++ b/source/dub/internal/io/mockfs.d @@ -23,10 +23,29 @@ public final class MockFS : Filesystem { /// private FSEntry root; - /// - public this () scope - { - this.root = this.cwd = new FSEntry(); + /*************************************************************************** + + Instantiate a `MockFS` with a given root + + A parameter-less overload exists for POSIX, while on Windows a parameter + needs to be provided, as Windows' root has a drive letter. + + Params: + root = The name of the root, e.g. "C:\" + + ***************************************************************************/ + + version (Windows) { + public this (char dir = 'C') scope + { + this.root = this.cwd = new FSEntry(); + this.root.name = dir ~ ':'; + } + } else { + public this () scope + { + this.root = this.cwd = new FSEntry(); + } } public override NativePath getcwd () const scope @@ -358,8 +377,10 @@ public class FSEntry protected inout(FSEntry) lookup(string name) inout return scope { assert(!name.canFind('/')); - if (name == ".") return this; - if (name == "..") return this.parent; + version (POSIX) { + if (name == ".") return this; + if (name == "..") return this.parent; + } foreach (c; this.children) if (c.name == name) return c; @@ -436,7 +457,8 @@ public class FSEntry public NativePath path () const scope { if (this.parent is null) - return NativePath("/"); + // The first runtime branch is for Windows, the second for POSIX + return this.name ? NativePath(this.name) : NativePath("/"); auto thisPath = this.parent.path ~ this.name; thisPath.endsWithSlash = (this.attributes.type == Type.Directory); return thisPath; @@ -484,3 +506,37 @@ public class FSEntry this.attributes.attrs = attributes; } } + +unittest { + alias P = NativePath; + scope fs = new MockFS(); + + version (Windows) immutable NativePath root = NativePath(`C:\`); + else immutable NativePath root = NativePath(`/`); + + assert(fs.getcwd == root); + // We shouldn't be able to chdir into a non-existent directory + assertThrown(fs.chdir(P("foo/bar"))); + // Even with an absolute path + assertThrown(fs.chdir(root ~ "foo/bar")); + // Now we should be + fs.mkdir(P("foo/bar")); + fs.chdir(P("foo/bar")); + assert(fs.getcwd == root ~ "foo/bar/", fs.getcwd.toNativeString()); + // chdir with absolute path + fs.chdir(root ~ "foo"); + assert(fs.getcwd == root ~ "foo/", fs.getcwd.toNativeString()); + // This still does not exists + assertThrown(fs.chdir(root ~ "bar")); + // Test pseudo entries / meta locations + version (POSIX) { + fs.chdir(P(".")); + assert(fs.getcwd == P("/foo/")); + fs.chdir(P("..")); + assert(fs.getcwd == P("/")); + fs.chdir(P(".")); + assert(fs.getcwd == P("/")); + fs.chdir(NativePath("/foo/bar/../")); + assert(fs.getcwd == P("/foo/")); + } +} diff --git a/source/dub/test/base.d b/source/dub/test/base.d index 859ba2e79..8c7ea3558 100644 --- a/source/dub/test/base.d +++ b/source/dub/test/base.d @@ -190,7 +190,7 @@ public class TestDub : Dub /// Convenience constants for use in unittests version (Windows) - public static immutable Root = NativePath("T:\\dub\\"); + public static immutable Root = NativePath(`C:\dub\`); else public static immutable Root = NativePath("/dub/"); From 1849d1bf12a790a2d8efe59c96a7f21c01dee294 Mon Sep 17 00:00:00 2001 From: Mathias Lang Date: Sun, 23 Jun 2024 23:22:18 +0200 Subject: [PATCH 3/8] fix(tests): Give a non-root CWD to tests In the real world, it's unlikely Dub is ever started from the root path. However, in our current unittest framework, that is always the case. --- source/dub/test/base.d | 1 + 1 file changed, 1 insertion(+) diff --git a/source/dub/test/base.d b/source/dub/test/base.d index 8c7ea3558..b1620c1f4 100644 --- a/source/dub/test/base.d +++ b/source/dub/test/base.d @@ -235,6 +235,7 @@ public class TestDub : Dub fs_.mkdir(Paths.userPackages); fs_.mkdir(Paths.cache); fs_.mkdir(ProjectPath); + fs_.chdir(Root); if (dg !is null) dg(fs_); this(fs_, root, extras, skip); } From 4f1ec76905035e3169718d4fdd212016062070ff Mon Sep 17 00:00:00 2001 From: Mathias Lang Date: Sat, 22 Jun 2024 15:02:24 +0200 Subject: [PATCH 4/8] CI: Move Filesystem instance to Dub class While we don't use it yet, it allows us to remove the field from out TestDub class --- source/dub/dub.d | 2 ++ source/dub/test/base.d | 15 ++++++++++----- 2 files changed, 12 insertions(+), 5 deletions(-) diff --git a/source/dub/dub.d b/source/dub/dub.d index 75f268b6c..304907057 100644 --- a/source/dub/dub.d +++ b/source/dub/dub.d @@ -11,6 +11,7 @@ import dub.compilers.compiler; import dub.data.settings : SPS = SkipPackageSuppliers, Settings; import dub.dependency; import dub.dependencyresolver; +import dub.internal.io.realfs; import dub.internal.utils; import dub.internal.vibecompat.core.file; import dub.internal.vibecompat.data.json; @@ -118,6 +119,7 @@ deprecated unittest */ class Dub { protected { + Filesystem fs; bool m_dryRun = false; PackageManager m_packageManager; PackageSupplier[] m_packageSuppliers; diff --git a/source/dub/test/base.d b/source/dub/test/base.d index b1620c1f4..0fa0eb447 100644 --- a/source/dub/test/base.d +++ b/source/dub/test/base.d @@ -175,9 +175,6 @@ public void disableLogging() */ public class TestDub : Dub { - /// The virtual filesystem that this instance acts on - public MockFS fs; - /** * Redundant reference to the registry * @@ -252,10 +249,10 @@ public class TestDub : Dub } /// Internal constructor - private this(MockFS fs_, string root, PackageSupplier[] extras, + private this(Filesystem fs_, string root, PackageSupplier[] extras, SkipPackageSuppliers skip) { - this.fs = fs_; + super.fs = fs_; super(root, extras, skip); } @@ -334,6 +331,14 @@ public class TestDub : Dub assert(this.registry !is null, "The registry hasn't been instantiated?"); return this.registry; } + + /** + * Exposes our test filesystem to unittests + */ + public @property inout(Filesystem) fs() inout + { + return super.fs; + } } /** From c2991aae2fe04da105c4afc8f0f2a9539195ac38 Mon Sep 17 00:00:00 2001 From: Mathias Lang Date: Sat, 22 Jun 2024 15:10:52 +0200 Subject: [PATCH 5/8] Instantiate PackageManager with Dub's Filesystem instance This way we can start making use of the Filesystem abstraction in the Dub class. --- source/dub/dub.d | 15 +++++++++++++-- source/dub/packagemanager.d | 5 +++-- source/dub/test/base.d | 5 ++--- 3 files changed, 18 insertions(+), 7 deletions(-) diff --git a/source/dub/dub.d b/source/dub/dub.d index 304907057..ec6365f7f 100644 --- a/source/dub/dub.d +++ b/source/dub/dub.d @@ -157,6 +157,13 @@ class Dub { this(string root_path = ".", PackageSupplier[] base = null, SkipPackageSuppliers skip = SkipPackageSuppliers.none) { + this(new RealFS(), root_path, base, skip); + } + + package this (Filesystem fs, string root_path, PackageSupplier[] base = null, + SkipPackageSuppliers skip = SkipPackageSuppliers.none) + { + this.fs = fs; m_rootPath = NativePath(root_path); if (!m_rootPath.absolute) m_rootPath = getWorkingDirectory() ~ m_rootPath; @@ -203,9 +210,10 @@ class Dub { { // Note: We're doing `init()` before setting the `rootPath`, // to prevent `init` from reading the project's settings. + this.fs = new RealFS(); init(); this.m_rootPath = root; - m_packageManager = new PackageManager(pkg_root); + m_packageManager = new PackageManager(pkg_root, this.fs); } deprecated("Use the overload that takes `(NativePath pkg_root, NativePath root)`") @@ -224,7 +232,10 @@ class Dub { */ protected PackageManager makePackageManager() { - return new PackageManager(m_rootPath, m_dirs.userPackages, m_dirs.systemSettings, false); + const local = this.m_rootPath ~ ".dub/packages/"; + const user = m_dirs.userPackages ~ "packages/"; + const system = m_dirs.systemSettings ~ "packages/"; + return new PackageManager(this.fs, local, user, system); } protected void init() diff --git a/source/dub/packagemanager.d b/source/dub/packagemanager.d index 79029cc4b..25c12de28 100644 --- a/source/dub/packagemanager.d +++ b/source/dub/packagemanager.d @@ -130,14 +130,15 @@ class PackageManager { Params: path = Path of the single repository */ - this(NativePath path) + this(NativePath path, Filesystem fs = null) { import dub.internal.io.realfs; - this.fs = new RealFS(); + this.fs = fs !is null ? fs : new RealFS(); this.m_internal.searchPath = [ path ]; this.refresh(); } + deprecated("Use the overload that accepts a `Filesystem`") this(NativePath package_path, NativePath user_path, NativePath system_path, bool refresh_packages = true) { import dub.internal.io.realfs; diff --git a/source/dub/test/base.d b/source/dub/test/base.d index 0fa0eb447..4f08a24cb 100644 --- a/source/dub/test/base.d +++ b/source/dub/test/base.d @@ -234,7 +234,7 @@ public class TestDub : Dub fs_.mkdir(ProjectPath); fs_.chdir(Root); if (dg !is null) dg(fs_); - this(fs_, root, extras, skip); + super(fs_, root, extras, skip); } /// Workaround https://issues.dlang.org/show_bug.cgi?id=24388 when called @@ -252,8 +252,7 @@ public class TestDub : Dub private this(Filesystem fs_, string root, PackageSupplier[] extras, SkipPackageSuppliers skip) { - super.fs = fs_; - super(root, extras, skip); + super(fs_, root, extras, skip); } /*************************************************************************** From a9b46210d3d1d1270854b0dd1dced0c7059fe8c3 Mon Sep 17 00:00:00 2001 From: Mathias Lang Date: Sat, 22 Jun 2024 15:37:57 +0200 Subject: [PATCH 6/8] Remove most dependency to std.file and dub.internal.core.file from Dub By using the Filesystem instance we can start writing better tests, in this case getting the ability to load configurations from tests. --- source/dub/dub.d | 71 ++++++++++++++++++++++++------------------------ 1 file changed, 35 insertions(+), 36 deletions(-) diff --git a/source/dub/dub.d b/source/dub/dub.d index ec6365f7f..709e828d7 100644 --- a/source/dub/dub.d +++ b/source/dub/dub.d @@ -13,7 +13,6 @@ import dub.dependency; import dub.dependencyresolver; import dub.internal.io.realfs; import dub.internal.utils; -import dub.internal.vibecompat.core.file; import dub.internal.vibecompat.data.json; import dub.internal.vibecompat.inet.url; import dub.internal.logging; @@ -29,7 +28,7 @@ import std.array : array, replace; import std.conv : text, to; import std.encoding : sanitize; import std.exception : enforce; -import std.file; +import std.file : tempDir, thisExePath; import std.process : environment; import std.range : assumeSorted, empty; import std.string; @@ -165,7 +164,7 @@ class Dub { { this.fs = fs; m_rootPath = NativePath(root_path); - if (!m_rootPath.absolute) m_rootPath = getWorkingDirectory() ~ m_rootPath; + if (!m_rootPath.absolute) m_rootPath = fs.getcwd() ~ m_rootPath; init(); @@ -240,7 +239,7 @@ class Dub { protected void init() { - this.m_dirs = SpecialDirs.make(); + this.m_dirs = SpecialDirs.make(this.fs); this.m_config = this.loadConfig(this.m_dirs); this.m_defaultCompiler = this.determineDefaultCompiler(); } @@ -266,13 +265,13 @@ class Dub { { import dub.internal.configy.Read; - static void readSettingsFile (NativePath path_, ref Settings current) + static void readSettingsFile (in Filesystem fs, NativePath path_, ref Settings current) { // TODO: Remove `StrictMode.Warn` after v1.40 release // The default is to error, but as the previous parser wasn't // complaining, we should first warn the user. const path = path_.toNativeString(); - if (path.exists) { + if (fs.existsFile(path_)) { auto newConf = parseConfigFileSimple!Settings(path, StrictMode.Warn); if (!newConf.isNull()) current = current.merge(newConf.get()); @@ -302,11 +301,11 @@ class Dub { } } - readSettingsFile(dirs.systemSettings ~ "settings.json", result); - readSettingsFile(dubFolderPath ~ "../etc/dub/settings.json", result); + readSettingsFile(this.fs, dirs.systemSettings ~ "settings.json", result); + readSettingsFile(this.fs, dubFolderPath ~ "../etc/dub/settings.json", result); version (Posix) { if (dubFolderPath.absolute && dubFolderPath.startsWith(NativePath("usr"))) - readSettingsFile(NativePath("/etc/dub/settings.json"), result); + readSettingsFile(this.fs, NativePath("/etc/dub/settings.json"), result); } // Override user + local package path from system / binary settings @@ -320,11 +319,11 @@ class Dub { } // load user config: - readSettingsFile(dirs.userSettings ~ "settings.json", result); + readSettingsFile(this.fs, dirs.userSettings ~ "settings.json", result); // load per-package config: if (!this.m_rootPath.empty) - readSettingsFile(this.m_rootPath ~ "dub.settings.json", result); + readSettingsFile(this.fs, this.m_rootPath ~ "dub.settings.json", result); // same as userSettings above, but taking into account the // config loaded from user settings and per-package config as well. @@ -457,7 +456,7 @@ class Dub { @property void rootPath(NativePath root_path) { m_rootPath = root_path; - if (!m_rootPath.absolute) m_rootPath = getWorkingDirectory() ~ m_rootPath; + if (!m_rootPath.absolute) m_rootPath = this.fs.getcwd() ~ m_rootPath; } /// Returns the name listed in the dub.json of the current @@ -572,12 +571,11 @@ class Dub { void loadSingleFilePackage(NativePath path) { import dub.recipe.io : parsePackageRecipe; - import std.file : readText; import std.path : baseName, stripExtension; path = makeAbsolute(path); - string file_content = readText(path.toNativeString()); + string file_content = this.fs.readText(path); if (file_content.startsWith("#!")) { auto idx = file_content.indexOf('\n'); @@ -840,9 +838,9 @@ class Dub { } } - string configFilePath = (m_project.rootPackage.path ~ "dscanner.ini").toNativeString(); - if (!args.canFind("--config") && exists(configFilePath)) { - settings.runArgs ~= ["--config", configFilePath]; + const configFilePath = (m_project.rootPackage.path ~ "dscanner.ini"); + if (!args.canFind("--config") && this.fs.existsFile(configFilePath)) { + settings.runArgs ~= ["--config", configFilePath.toNativeString()]; } settings.runArgs ~= args ~ [m_project.rootPackage.path.toNativeString()]; @@ -893,8 +891,7 @@ class Dub { const cache = this.m_dirs.cache; logInfo("Cleaning", Color.green, "all artifacts at %s", cache.toNativeString().color(Mode.bold)); - if (existsFile(cache)) - rmdirRecurse(cache.toNativeString()); + this.fs.removeDir(cache, true); } /// Ditto @@ -904,10 +901,8 @@ class Dub { logInfo("Cleaning", Color.green, "artifacts for package %s at %s", pack.name.color(Mode.bold), cache.toNativeString().color(Mode.bold)); - // TODO: clear target files and copy files - if (existsFile(cache)) - rmdirRecurse(cache.toNativeString()); + this.fs.removeDir(cache, true); } deprecated("Use the overload that accepts either a `Version` or a `VersionRange` as second argument") @@ -1477,7 +1472,7 @@ class Dub { } writePackageRecipe(srcfile.parentPath ~ ("dub."~destination_file_ext), m_project.rootPackage.rawRecipe); - removeFile(srcfile); + this.fs.removeFile(srcfile); } /** Runs DDOX to generate or serve documentation. @@ -1607,7 +1602,6 @@ class Dub { */ protected string determineDefaultCompiler() const { - import std.file : thisExePath; import std.path : buildPath, dirName, expandTilde, isAbsolute, isDirSeparator; import std.range : front; @@ -1637,12 +1631,13 @@ class Dub { if (result.length) { string compilerPath = buildPath(thisExePath().dirName(), result ~ exe); - if (existsFile(compilerPath)) + if (this.fs.existsFile(NativePath(compilerPath))) return compilerPath; } else { - auto nextFound = compilers.find!(bin => existsFile(buildPath(thisExePath().dirName(), bin ~ exe))); + auto nextFound = compilers.find!( + bin => this.fs.existsFile(NativePath(buildPath(thisExePath().dirName(), bin ~ exe)))); if (!nextFound.empty) return buildPath(thisExePath().dirName(), nextFound.front ~ exe); } @@ -1650,10 +1645,10 @@ class Dub { // If nothing found next to dub, search the user's PATH, starting // with the compiler name from their DUB config file, if specified. auto paths = environment.get("PATH", "").splitter(sep).map!NativePath; - if (result.length && paths.canFind!(p => existsFile(p ~ (result ~ exe)))) + if (result.length && paths.canFind!(p => this.fs.existsFile(p ~ (result ~ exe)))) return result; foreach (p; paths) { - auto res = compilers.find!(bin => existsFile(p ~ (bin~exe))); + auto res = compilers.find!(bin => this.fs.existsFile(p ~ (bin~exe))); if (!res.empty) return res.front; } @@ -1667,7 +1662,7 @@ class Dub { import dub.test.base : TestDub; auto dub = new TestDub(null, ".", null, SkipPackageSuppliers.configured); - immutable testdir = getWorkingDirectory() ~ "test-determineDefaultCompiler"; + immutable testdir = dub.fs.getcwd() ~ "test-determineDefaultCompiler"; immutable olddc = environment.get("DC", null); immutable oldpath = environment.get("PATH", null); @@ -1680,19 +1675,18 @@ class Dub { } scope (exit) repairenv("DC", olddc); scope (exit) repairenv("PATH", oldpath); - scope (exit) std.file.rmdirRecurse(testdir.toNativeString()); version (Windows) enum sep = ";", exe = ".exe"; version (Posix) enum sep = ":", exe = ""; immutable dmdpath = testdir ~ "dmd" ~ "bin"; immutable ldcpath = testdir ~ "ldc" ~ "bin"; - ensureDirectory(dmdpath); - ensureDirectory(ldcpath); + dub.fs.mkdir(dmdpath); + dub.fs.mkdir(ldcpath); immutable dmdbin = dmdpath ~ ("dmd" ~ exe); immutable ldcbin = ldcpath ~ ("ldc2" ~ exe); - writeFile(dmdbin, null); - writeFile(ldcbin, null); + dub.fs.writeFile(dmdbin, "dmd"); + dub.fs.writeFile(ldcbin, "ldc"); environment["DC"] = dmdbin.toNativeString(); assert(dub.determineDefaultCompiler() == dmdbin.toNativeString()); @@ -2066,9 +2060,14 @@ package struct SpecialDirs { NativePath cache; /// Returns: An instance of `SpecialDirs` initialized from the environment + deprecated("Use the overload that accepts a `Filesystem`") public static SpecialDirs make () { - import std.file : tempDir; + scope fs = new RealFS(); + return SpecialDirs.make(fs); + } + /// Ditto + public static SpecialDirs make (scope Filesystem fs) { SpecialDirs result; result.temp = NativePath(tempDir); @@ -2082,7 +2081,7 @@ package struct SpecialDirs { result.systemSettings = NativePath("/var/lib/dub/"); result.userSettings = NativePath(environment.get("HOME")) ~ ".dub/"; if (!result.userSettings.absolute) - result.userSettings = getWorkingDirectory() ~ result.userSettings; + result.userSettings = fs.getcwd() ~ result.userSettings; result.userPackages = result.userSettings; } result.cache = result.userPackages ~ "cache"; From d5b59fa9143346f2378e8b3dfed8ca4f43a6c902 Mon Sep 17 00:00:00 2001 From: Mathias Lang Date: Sat, 22 Jun 2024 15:57:59 +0200 Subject: [PATCH 7/8] Trivial: Remove a leftover std.file dependency in PackageManager --- source/dub/internal/io/mockfs.d | 2 +- source/dub/packagemanager.d | 3 +-- 2 files changed, 2 insertions(+), 3 deletions(-) diff --git a/source/dub/internal/io/mockfs.d b/source/dub/internal/io/mockfs.d index 369aec690..c79ea9a45 100644 --- a/source/dub/internal/io/mockfs.d +++ b/source/dub/internal/io/mockfs.d @@ -39,7 +39,7 @@ public final class MockFS : Filesystem { public this (char dir = 'C') scope { this.root = this.cwd = new FSEntry(); - this.root.name = dir ~ ':'; + this.root.name = [ dir, ':' ]; } } else { public this () scope diff --git a/source/dub/packagemanager.d b/source/dub/packagemanager.d index 25c12de28..7ec0df178 100644 --- a/source/dub/packagemanager.d +++ b/source/dub/packagemanager.d @@ -1003,8 +1003,7 @@ symlink_exit: enforce(found, "Cannot remove, package not found: '"~ pack.name ~"', path: " ~ to!string(pack.path)); logDebug("About to delete root folder for package '%s'.", pack.path); - import std.file : rmdirRecurse; - rmdirRecurse(pack.path.toNativeString()); + this.fs.removeDir(pack.path, true); logInfo("Removed", Color.yellow, "%s %s", pack.name.color(Mode.bold), pack.version_); } From 262699bd957a7b186cb481831c248f5b5bb23d10 Mon Sep 17 00:00:00 2001 From: Mathias Lang Date: Wed, 25 Sep 2024 03:01:33 +0200 Subject: [PATCH 8/8] debug --- source/dub/internal/io/mockfs.d | 9 +++++++-- 1 file changed, 7 insertions(+), 2 deletions(-) diff --git a/source/dub/internal/io/mockfs.d b/source/dub/internal/io/mockfs.d index c79ea9a45..390b381da 100644 --- a/source/dub/internal/io/mockfs.d +++ b/source/dub/internal/io/mockfs.d @@ -522,10 +522,15 @@ unittest { // Now we should be fs.mkdir(P("foo/bar")); fs.chdir(P("foo/bar")); - assert(fs.getcwd == root ~ "foo/bar/", fs.getcwd.toNativeString()); + assert(fs.getcwd == root ~ "foo/bar/"); // chdir with absolute path + import std.stdio; + writeln("===== ROOT ====="); + fs.root.print(); + writeln("===== CWD ====="); + fs.cwd.print(); fs.chdir(root ~ "foo"); - assert(fs.getcwd == root ~ "foo/", fs.getcwd.toNativeString()); + assert(fs.getcwd == root ~ "foo/"); // This still does not exists assertThrown(fs.chdir(root ~ "bar")); // Test pseudo entries / meta locations