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

Refactor filesystem abstraction to and use it in production #2944

Merged
merged 5 commits into from
Jun 25, 2024
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
2 changes: 2 additions & 0 deletions build-files.txt
Original file line number Diff line number Diff line change
Expand Up @@ -47,6 +47,8 @@ source/dub/internal/dyaml/style.d
source/dub/internal/dyaml/tagdirective.d
source/dub/internal/dyaml/token.d
source/dub/internal/git.d
source/dub/internal/io/filesystem.d
source/dub/internal/io/realfs.d
source/dub/internal/libInputVisitor.d
source/dub/internal/sdlang/ast.d
source/dub/internal/sdlang/exception.d
Expand Down
8 changes: 4 additions & 4 deletions source/dub/dub.d
Original file line number Diff line number Diff line change
Expand Up @@ -376,15 +376,15 @@ class Dub {
import dub.test.base : TestDub;

scope (exit) environment.remove("DUB_REGISTRY");
auto dub = new TestDub(null, ".", null, SkipPackageSuppliers.configured);
auto dub = new TestDub(null, "/dub/project/", null, SkipPackageSuppliers.configured);
assert(dub.packageSuppliers.length == 0);
environment["DUB_REGISTRY"] = "http://example.com/";
dub = new TestDub(null, ".", null, SkipPackageSuppliers.configured);
dub = new TestDub(null, "/dub/project/", null, SkipPackageSuppliers.configured);
assert(dub.packageSuppliers.length == 1);
environment["DUB_REGISTRY"] = "http://example.com/;http://foo.com/";
dub = new TestDub(null, ".", null, SkipPackageSuppliers.configured);
dub = new TestDub(null, "/dub/project/", null, SkipPackageSuppliers.configured);
assert(dub.packageSuppliers.length == 2);
dub = new TestDub(null, ".", [new RegistryPackageSupplier(URL("http://bar.com/"))], SkipPackageSuppliers.configured);
dub = new TestDub(null, "/dub/project/", [new RegistryPackageSupplier(URL("http://bar.com/"))], SkipPackageSuppliers.configured);
assert(dub.packageSuppliers.length == 3);

dub = new TestDub();
Expand Down
96 changes: 96 additions & 0 deletions source/dub/internal/io/filesystem.d
Original file line number Diff line number Diff line change
@@ -0,0 +1,96 @@
/**
* An abstract filesystem representation
*
* This interface allows to represent the file system to various part of Dub.
* Instead of direct use of `std.file`, an implementation of this interface can
* be used, allowing to mock all I/O in unittest on a thread-local basis.
*/
module dub.internal.io.filesystem;

public import std.datetime.systime;

public import dub.internal.vibecompat.inet.path;

/// Ditto
public interface Filesystem
{
static import dub.internal.vibecompat.core.file;

/// TODO: Remove, the API should be improved
public alias IterateDirDg = int delegate(
scope int delegate(ref dub.internal.vibecompat.core.file.FileInfo));

/// Ditto
public IterateDirDg iterateDirectory (in NativePath path) scope;

/// Returns: The `path` of this FSEntry
public abstract NativePath getcwd () const scope;

/**
* Implements `mkdir -p`: Create a directory and every intermediary
*
* There is no way to error out on intermediate directory,
* like standard mkdir does. If you want this behavior,
* simply check (`existsDirectory`) if the parent directory exists.
*
* Params:
* path = The path of the directory to be created.
*/
public abstract void mkdir (in NativePath path) scope;

/// Checks the existence of a file
public abstract bool existsFile (in NativePath path) const scope;

/// Checks the existence of a directory
public abstract bool existsDirectory (in NativePath path) const scope;

/// Reads a file, returns the content as `ubyte[]`
public abstract ubyte[] readFile (in NativePath path) const scope;

/// Reads a file, returns the content as text
public abstract string readText (in NativePath path) const scope;

/// Write to this file
public final void writeFile (in NativePath path, const(char)[] data) scope
{
import std.string : representation;

this.writeFile(path, data.representation);
}

/// Ditto
public abstract void writeFile (in NativePath path, const(ubyte)[] data) scope;

/** Remove a file
*
* Always error if the target is a directory.
* Does not error if the target does not exists
* and `force` is set to `true`.
*
* Params:
* path = Path to the file to remove
* force = Whether to ignore non-existing file,
* default to `false`.
*/
public void removeFile (in NativePath path, bool force = false);

/** Remove a directory
*
* Remove an existing empty directory.
* If `force` is set to `true`, no error will be thrown
* if the directory is empty or non-existing.
*
* Params:
* path = Path to the directory to remove
* force = Whether to ignore non-existing / non-empty directories,
* default to `false`.
*/
public void removeDir (in NativePath path, bool force = false);

/// Implement `std.file.setTimes`
public void setTimes (in NativePath path, in SysTime accessTime,
in SysTime modificationTime);

/// Implement `std.file.setAttributes`
public void setAttributes (in NativePath path, uint attributes);
}
Loading
Loading