aboutsummaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
authorGravatar Jarred Sumner <jarred@jarredsumner.com> 2021-10-08 21:10:40 -0700
committerGravatar Jarred Sumner <jarred@jarredsumner.com> 2021-10-08 21:10:40 -0700
commit7e2c297013e89e26da2db27d7edab886761c203e (patch)
tree22f23c5d8a2e5d86b7f3016ef0f42ec0079226af /src
parentf10301884246003573a3aff123e5921e927379a5 (diff)
downloadbun-7e2c297013e89e26da2db27d7edab886761c203e.tar.gz
bun-7e2c297013e89e26da2db27d7edab886761c203e.tar.zst
bun-7e2c297013e89e26da2db27d7edab886761c203e.zip
Wrap filesystem access
Diffstat (limited to 'src')
-rw-r--r--src/bundler.zig93
-rw-r--r--src/cache.zig79
-rw-r--r--src/cli.zig20
-rw-r--r--src/css_scanner.zig6
-rw-r--r--src/env_loader.zig19
-rw-r--r--src/fs.zig536
-rw-r--r--src/http.zig29
-rw-r--r--src/javascript/jsc/javascript.zig4
-rw-r--r--src/js_printer.zig6
-rw-r--r--src/linker.zig6
-rw-r--r--src/logger.zig4
-rw-r--r--src/node_module_bundle.zig2
-rw-r--r--src/options.zig41
-rw-r--r--src/resolver/resolver.zig119
14 files changed, 660 insertions, 304 deletions
diff --git a/src/bundler.zig b/src/bundler.zig
index 5bb037239..acd175782 100644
--- a/src/bundler.zig
+++ b/src/bundler.zig
@@ -42,6 +42,9 @@ const Analytics = @import("./analytics/analytics_thread.zig");
const Linker = linker.Linker;
const Resolver = _resolver.Resolver;
+const FileSystem = Fs.FileSystem;
+
+const Dir = Fs.Dir;
// How it works end-to-end
// 1. Resolve a file path from input using the resolver
@@ -238,9 +241,9 @@ pub const Bundler = struct {
// Process always has highest priority.
this.env.loadProcess();
if (this.options.production) {
- try this.env.load(&this.fs.fs, dir, false);
+ try this.env.load(this.fs, dir, false);
} else {
- try this.env.load(&this.fs.fs, dir, true);
+ try this.env.load(this.fs, dir, true);
}
},
.disable => {
@@ -619,7 +622,7 @@ pub const Bundler = struct {
queue: *BunQueue,
bundler: *ThisBundler,
allocator: *std.mem.Allocator,
- tmpfile: std.fs.File,
+ tmpfile: Fs.File,
log: *logger.Log,
pool: *ThreadPool,
tmpfile_byte_offset: u32 = 0,
@@ -721,7 +724,7 @@ pub const Bundler = struct {
destination: [*:0]const u8,
estimated_input_lines_of_code: *usize,
) !?Api.JavascriptBundleContainer {
- var tmpdir: std.fs.Dir = try bundler.fs.fs.openTmpDir();
+ var tmpdir: Dir = bundler.fs.tmpdir();
var tmpname_buf: [64]u8 = undefined;
bundler.resetStore();
try bundler.configureDefines();
@@ -1530,7 +1533,7 @@ pub const Bundler = struct {
var ast: js_ast.Ast = undefined;
const source = logger.Source.initRecycledFile(
- Fs.File{
+ Fs.LoadedFile{
.path = file_path,
.contents = entry.contents,
},
@@ -1845,9 +1848,9 @@ pub const Bundler = struct {
Linker,
&bundler.linker,
&this.write_lock,
- std.fs.File,
+ Fs.File,
this.tmpfile,
- std.fs.File.getPos,
+ Fs.File.getPos,
&this.tmpfile_byte_offset,
);
@@ -1885,7 +1888,7 @@ pub const Bundler = struct {
) catch return;
if (entry.contents.len == 0 or (entry.contents.len < 33 and strings.trim(entry.contents, " \n\r").len == 0)) return;
- const source = logger.Source.initRecycledFile(Fs.File{ .path = file_path, .contents = entry.contents }, bundler.allocator) catch return null;
+ const source = logger.Source.initRecycledFile(Fs.LoadedFile{ .path = file_path, .contents = entry.contents }, bundler.allocator) catch return null;
var jsx = bundler.options.jsx;
@@ -1941,7 +1944,7 @@ pub const Bundler = struct {
var can_close = false;
if (fd == 0) {
dynamic_import_file_size.value_ptr.* = 0;
- fd = (std.fs.openFileAbsolute(path.textZ(), .{}) catch |err| {
+ fd = (FileSystem.openFileAbsoluteZ(path.textZ(), .{}) catch |err| {
this.log.addRangeWarningFmt(
&source,
import_record.range,
@@ -1950,23 +1953,20 @@ pub const Bundler = struct {
.{ @errorName(err), path.text },
) catch unreachable;
continue;
- }).handle;
+ });
can_close = true;
- Fs.FileSystem.setMaxFd(fd);
}
defer {
- if (can_close and bundler.fs.fs.needToCloseFiles()) {
- var _file = std.fs.File{ .handle = fd };
- _file.close();
+ if (can_close and bundler.fs.needToCloseFiles()) {
+ FileSystem.close(fd);
_resolved_import.file_fd = 0;
} else if (FeatureFlags.store_file_descriptors) {
_resolved_import.file_fd = fd;
}
}
- var file = std.fs.File{ .handle = fd };
- var stat = file.stat() catch |err| {
+ const size = FileSystem.getFileSize(fd) catch |err| {
this.log.addRangeWarningFmt(
&source,
import_record.range,
@@ -1978,7 +1978,7 @@ pub const Bundler = struct {
continue;
};
- dynamic_import_file_size.value_ptr.* = @truncate(u32, stat.size);
+ dynamic_import_file_size.value_ptr.* = @truncate(u32, size);
}
if (dynamic_import_file_size.value_ptr.* > 1024 * 100)
@@ -2228,10 +2228,10 @@ pub const Bundler = struct {
.value = undefined,
};
- var file: std.fs.File = undefined;
+ var file: Fs.File = undefined;
- if (Outstream == std.fs.Dir) {
- const output_dir = outstream;
+ if (Outstream == Dir) {
+ const output_dir: Dir = outstream;
if (std.fs.path.dirname(file_path.pretty)) |dirname| {
try output_dir.makePath(dirname);
@@ -2279,10 +2279,10 @@ pub const Bundler = struct {
file_op.is_tmpdir = false;
- if (Outstream == std.fs.Dir) {
+ if (Outstream == Dir) {
file_op.dir = outstream.fd;
- if (bundler.fs.fs.needToCloseFiles()) {
+ if (bundler.fs.needToCloseFiles()) {
file.close();
file_op.fd = 0;
}
@@ -2292,7 +2292,7 @@ pub const Bundler = struct {
},
.css => {
const CSSWriter = Css.NewWriter(
- std.fs.File,
+ Fs.File,
@TypeOf(&bundler.linker),
import_path_format,
void,
@@ -2305,7 +2305,7 @@ pub const Bundler = struct {
null,
) catch return null;
- const _file = Fs.File{ .path = file_path, .contents = entry.contents };
+ const _file = Fs.LoadedFile{ .path = file_path, .contents = entry.contents };
var source = try logger.Source.initFile(_file, bundler.allocator);
source.contents_is_recycled = !cache_files;
var css_writer = CSSWriter.init(
@@ -2323,10 +2323,10 @@ pub const Bundler = struct {
file_op.is_tmpdir = false;
- if (Outstream == std.fs.Dir) {
+ if (Outstream == Dir) {
file_op.dir = outstream.fd;
- if (bundler.fs.fs.needToCloseFiles()) {
+ if (bundler.fs.needToCloseFiles()) {
file.close();
file_op.fd = 0;
}
@@ -2467,7 +2467,7 @@ pub const Bundler = struct {
return null;
};
input_fd = entry.fd;
- break :brk logger.Source.initRecycledFile(Fs.File{ .path = path, .contents = entry.contents }, bundler.allocator) catch return null;
+ break :brk logger.Source.initRecycledFile(Fs.LoadedFile{ .path = path, .contents = entry.contents }, bundler.allocator) catch return null;
};
if (source.contents.len == 0 or (source.contents.len < 33 and std.mem.trim(u8, source.contents, "\n\r ").len == 0)) {
@@ -2651,10 +2651,9 @@ pub const Bundler = struct {
},
else => {
var abs_path = path.text;
- const file = try std.fs.openFileAbsolute(abs_path, .{ .read = true });
- var stat = try file.stat();
+ const file = try FileSystem.openFile(abs_path, .{ .read = true });
return ServeResult{
- .file = options.OutputFile.initFile(file, abs_path, stat.size),
+ .file = options.OutputFile.initFile(file.handle, abs_path, try file.getEndPos()),
.mime_type = MimeType.byLoader(
loader,
mime_type_ext[1..],
@@ -2770,7 +2769,7 @@ pub const Bundler = struct {
var did_start = false;
if (bundler.options.output_dir_handle == null) {
- const outstream = std.io.getStdOut();
+ const outstream = Fs.File{ .handle = std.io.getStdOut().handle };
if (load_from_routes) {
if (bundler.options.framework) |*framework| {
@@ -2808,11 +2807,11 @@ pub const Bundler = struct {
if (framework.client.isEnabled()) {
did_start = true;
try switch (bundler.options.import_path_format) {
- .relative => bundler.processResolveQueue(.relative, true, std.fs.Dir, output_dir),
- .relative_nodejs => bundler.processResolveQueue(.relative_nodejs, true, std.fs.Dir, output_dir),
- .absolute_url => bundler.processResolveQueue(.absolute_url, true, std.fs.Dir, output_dir),
- .absolute_path => bundler.processResolveQueue(.absolute_path, true, std.fs.Dir, output_dir),
- .package_path => bundler.processResolveQueue(.package_path, true, std.fs.Dir, output_dir),
+ .relative => bundler.processResolveQueue(.relative, true, Dir, output_dir),
+ .relative_nodejs => bundler.processResolveQueue(.relative_nodejs, true, Dir, output_dir),
+ .absolute_url => bundler.processResolveQueue(.absolute_url, true, Dir, output_dir),
+ .absolute_path => bundler.processResolveQueue(.absolute_path, true, Dir, output_dir),
+ .package_path => bundler.processResolveQueue(.package_path, true, Dir, output_dir),
};
}
}
@@ -2820,11 +2819,11 @@ pub const Bundler = struct {
if (!did_start) {
try switch (bundler.options.import_path_format) {
- .relative => bundler.processResolveQueue(.relative, false, std.fs.Dir, output_dir),
- .relative_nodejs => bundler.processResolveQueue(.relative_nodejs, false, std.fs.Dir, output_dir),
- .absolute_url => bundler.processResolveQueue(.absolute_url, false, std.fs.Dir, output_dir),
- .absolute_path => bundler.processResolveQueue(.absolute_path, false, std.fs.Dir, output_dir),
- .package_path => bundler.processResolveQueue(.package_path, false, std.fs.Dir, output_dir),
+ .relative => bundler.processResolveQueue(.relative, false, Dir, output_dir),
+ .relative_nodejs => bundler.processResolveQueue(.relative_nodejs, false, Dir, output_dir),
+ .absolute_url => bundler.processResolveQueue(.absolute_url, false, Dir, output_dir),
+ .absolute_path => bundler.processResolveQueue(.absolute_path, false, Dir, output_dir),
+ .package_path => bundler.processResolveQueue(.package_path, false, Dir, output_dir),
};
}
}
@@ -2987,7 +2986,7 @@ pub const Transformer = struct {
const write_to_output_dir = opts.entry_points.len > 1 or opts.output_dir != null;
- var output_dir_handle: ?std.fs.Dir = null;
+ var output_dir_handle: ?Dir = null;
if (write_to_output_dir) {
output_dir_handle = try options.openOutputDir(output_dir);
}
@@ -3030,7 +3029,7 @@ pub const Transformer = struct {
entry_point: string,
i: usize,
output_files: *std.ArrayList(options.OutputFile),
- _output_dir: ?std.fs.Dir,
+ _output_dir: ?Dir,
comptime write_destination_type: options.WriteDestination,
care_about_closing_files: bool,
use_default_loaders: bool,
@@ -3044,7 +3043,7 @@ pub const Transformer = struct {
var __log = &_log;
const absolutePath = resolve_path.joinAbs(transformer.cwd, .auto, entry_point);
- const file = try std.fs.openFileAbsolute(absolutePath, std.fs.File.OpenFlags{ .read = true });
+ const file = try FileSystem.openFile(absolutePath, std.fs.File.OpenFlags{ .read = true });
defer {
if (care_about_closing_files) {
file.close();
@@ -3060,7 +3059,7 @@ pub const Transformer = struct {
}
_log.appendTo(log) catch {};
}
- const _file = Fs.File{ .path = Fs.Path.init(entry_point), .contents = code };
+ const _file = Fs.LoadedFile{ .path = Fs.Path.init(entry_point), .contents = code };
var source = try logger.Source.initFile(_file, allocator);
var loader: options.Loader = undefined;
if (use_default_loaders) {
@@ -3080,12 +3079,12 @@ pub const Transformer = struct {
.value = undefined,
};
- var file_to_write: std.fs.File = undefined;
+ var file_to_write: Fs.File = undefined;
var output_path: Fs.Path = undefined;
switch (write_destination_type) {
.stdout => {
- file_to_write = std.io.getStdOut();
+ file_to_write = Fs.File{ .handle = std.io.getStdOut().handle };
output_path = Fs.Path.init("stdout");
},
.disk => {
diff --git a/src/cache.zig b/src/cache.zig
index 53f854449..c352a2ed2 100644
--- a/src/cache.zig
+++ b/src/cache.zig
@@ -7,7 +7,7 @@ const json_parser = @import("./json_parser.zig");
const options = @import("./options.zig");
const Define = @import("./defines.zig").Define;
const std = @import("std");
-const fs = @import("./fs.zig");
+const FileSystem = @import("./fs.zig").FileSystem;
const sync = @import("sync.zig");
const Mutex = @import("./lock.zig").Lock;
@@ -58,60 +58,45 @@ pub const Fs = struct {
pub fn readFileShared(
c: *Fs,
- _fs: *fs.FileSystem,
- path: [:0]const u8,
+ fs: *FileSystem,
+ path: stringZ,
dirname_fd: StoredFileDescriptorType,
_file_handle: ?StoredFileDescriptorType,
shared: *MutableString,
) !Entry {
- var rfs = _fs.fs;
-
- var file_handle: std.fs.File = if (_file_handle) |__file| std.fs.File{ .handle = __file } else undefined;
-
- if (_file_handle == null) {
- file_handle = try std.fs.openFileAbsoluteZ(path, .{ .read = true });
- fs.FileSystem.setMaxFd(file_handle.handle);
- }
+ const file = _file_handle orelse try FileSystem.openFileAbsoluteZ(path, .{ .read = true });
defer {
- if (rfs.needToCloseFiles() and _file_handle == null) {
- file_handle.close();
+ if (fs.needToCloseFiles() and _file_handle == null) {
+ FileSystem.close(file);
}
}
- const stat = try std.os.fstat(file_handle.handle);
-
- var file = rfs.readFileWithHandle(path, @intCast(usize, stat.size), file_handle, true, shared) catch |err| {
- if (isDebug) {
- Output.printError("{s}: readFile error -- {s}", .{ path, @errorName(err) });
- }
- return err;
- };
-
return Entry{
- .contents = file.contents,
- .fd = if (FeatureFlags.store_file_descriptors) file_handle.handle else 0,
+ .contents = fs.readFileWithHandle(path, null, file, true, shared) catch |err| {
+ if (isDebug) {
+ Output.printError("{s}: readFile error -- {s}", .{ path, @errorName(err) });
+ }
+ return err;
+ },
+ .fd = if (FeatureFlags.store_file_descriptors) file else 0,
};
}
pub fn readFile(
c: *Fs,
- _fs: *fs.FileSystem,
+ fs: *FileSystem,
path: string,
dirname_fd: StoredFileDescriptorType,
comptime use_shared_buffer: bool,
_file_handle: ?StoredFileDescriptorType,
) !Entry {
- var rfs = _fs.fs;
-
- var file_handle: std.fs.File = if (_file_handle) |__file| std.fs.File{ .handle = __file } else undefined;
-
- if (_file_handle == null) {
+ const file_handle: FileDescriptorType = _file_handle orelse brk: {
if (FeatureFlags.store_file_descriptors and dirname_fd > 0) {
- file_handle = std.fs.Dir.openFile(std.fs.Dir{ .fd = dirname_fd }, std.fs.path.basename(path), .{ .read = true }) catch |err| brk: {
+ break :brk FileSystem.openFileInDir(dirname_fd, std.fs.path.basename(path), .{ .read = true }) catch |err| {
switch (err) {
error.FileNotFound => {
- const handle = try std.fs.openFileAbsolute(path, .{ .read = true });
+ const handle = try FileSystem.openFileAbsolute(path, .{ .read = true });
Output.prettyErrorln(
"<r><d>Internal error: directory mismatch for directory \"{s}\", fd {d}<r>. You don't need to do anything, but this indicates a bug.",
.{ path, dirname_fd },
@@ -122,33 +107,25 @@ pub const Fs = struct {
}
};
} else {
- file_handle = try std.fs.openFileAbsolute(path, .{ .read = true });
+ break :brk try FileSystem.openFileAbsolute(path, .{ .read = true });
}
- }
+ };
defer {
- fs.FileSystem.setMaxFd(file_handle.handle);
-
- if (rfs.needToCloseFiles() and _file_handle == null) {
- file_handle.close();
+ if (fs.needToCloseFiles() and _file_handle == null) {
+ FileSystem.close(file_handle);
}
}
- const stat = try std.os.fstat(file_handle.handle);
-
- var file: fs.File = undefined;
-
- file = rfs.readFileWithHandle(path, @intCast(usize, stat.size), file_handle, use_shared_buffer, &c.shared_buffer) catch |err| {
- if (isDebug) {
- Output.printError("{s}: readFile error -- {s}", .{ path, @errorName(err) });
- }
- return err;
- };
-
return Entry{
- .contents = file.contents,
+ .contents = fs.readFileWithHandle(path, null, file_handle, use_shared_buffer, &c.shared_buffer) catch |err| {
+ if (isDebug) {
+ Output.printError("{s}: readFile error -- {s}", .{ path, @errorName(err) });
+ }
+ return err;
+ },
// .mod_key = mod_key,
- .fd = if (FeatureFlags.store_file_descriptors) file_handle.handle else 0,
+ .fd = if (FeatureFlags.store_file_descriptors) file_handle else 0,
};
}
};
diff --git a/src/cli.zig b/src/cli.zig
index e26d94f6d..b7352057f 100644
--- a/src/cli.zig
+++ b/src/cli.zig
@@ -124,20 +124,6 @@ pub const Arguments = struct {
std.process.exit(1);
}
- pub fn readFile(
- allocator: *std.mem.Allocator,
- cwd: string,
- filename: string,
- ) ![]u8 {
- var paths = [_]string{ cwd, filename };
- const outpath = try std.fs.path.resolve(allocator, &paths);
- defer allocator.free(outpath);
- var file = try std.fs.openFileAbsolute(outpath, std.fs.File.OpenFlags{ .read = true, .write = false });
- defer file.close();
- const stats = try file.stat();
- return try file.readToEndAlloc(allocator, stats.size);
- }
-
pub fn resolve_jsx_runtime(str: string) !Api.JsxRuntime {
if (strings.eqlComptime(str, "automatic")) {
return Api.JsxRuntime.automatic;
@@ -150,7 +136,7 @@ pub const Arguments = struct {
pub const ParamType = clap.Param(clap.Help);
- const params: [26]ParamType = brk: {
+ const params: [25]ParamType = brk: {
@setEvalBranchQuota(9999);
break :brk [_]ParamType{
clap.parseParam("--use <STR> Choose a framework, e.g. \"--use next\". It checks first for a package named \"bun-framework-packagename\" and then \"packagename\".") catch unreachable,
@@ -173,7 +159,7 @@ pub const Arguments = struct {
clap.parseParam("--platform <STR> \"browser\" or \"node\". Defaults to \"browser\"") catch unreachable,
// clap.parseParam("--production   [not implemented] generate production code") catch unreachable,
clap.parseParam("--public-dir <STR> Top-level directory for .html files, fonts or anything external. Defaults to \"<cwd>/public\", to match create-react-app and Next.js") catch unreachable,
- clap.parseParam("--tsconfig-override <STR> Load tsconfig from path instead of cwd/tsconfig.json") catch unreachable,
+ // clap.parseParam("--tsconfig-override <STR> Load tsconfig from path instead of cwd/tsconfig.json") catch unreachable,
clap.parseParam("-d, --define <STR>... Substitute K:V while parsing, e.g. --define process.env.NODE_ENV:\"development\". Values are parsed as JSON.") catch unreachable,
clap.parseParam("-e, --external <STR>... Exclude module from transpilation (can use * wildcards). ex: -e react") catch unreachable,
clap.parseParam("-h, --help Display this help and exit. ") catch unreachable,
@@ -221,7 +207,7 @@ pub const Arguments = struct {
}
var opts = Api.TransformOptions{
- .tsconfig_override = if (args.option("--tsconfig-override")) |ts| (Arguments.readFile(allocator, cwd, ts) catch |err| fileReadError(err, Output.errorStream(), ts, "tsconfig.json")) else null,
+ // .tsconfig_override = if (args.option("--tsconfig-override")) |ts| (Arguments.readFile(allocator, cwd, ts) catch |err| fileReadError(err, Output.errorStream(), ts, "tsconfig.json")) else null,
.external = externals,
.absolute_working_dir = cwd,
.origin = args.option("--origin"),
diff --git a/src/css_scanner.zig b/src/css_scanner.zig
index ee2881d4e..bf475ef8a 100644
--- a/src/css_scanner.zig
+++ b/src/css_scanner.zig
@@ -1249,7 +1249,7 @@ pub fn NewBundler(
pub fn getSource(this: *CSSBundler, url: string, input_fd: StoredFileDescriptorType) !logger.Source {
const entry = try this.fs_reader.readFile(this.fs, url, 0, true, input_fd);
- const file = Fs.File{ .path = Fs.Path.init(url), .contents = entry.contents };
+ const file = Fs.LoadedFile{ .path = Fs.Path.init(url), .contents = entry.contents };
return logger.Source.initFile(file, this.allocator);
}
@@ -1262,9 +1262,9 @@ pub fn NewBundler(
const watcher_index = this.watcher.indexOf(hash);
if (watcher_index == null) {
- var file = try std.fs.openFileAbsolute(absolute_path, .{ .read = true });
+ const file = try Fs.FileSystem.openFileAbsolute(absolute_path, .{ .read = true });
- try this.watcher.appendFile(file.handle, absolute_path, hash, .css, 0, null, true);
+ try this.watcher.appendFile(file, absolute_path, hash, .css, 0, null, true);
if (this.watcher.watchloop_handle == null) {
try this.watcher.start();
}
diff --git a/src/env_loader.zig b/src/env_loader.zig
index 6c35157ce..61fddf906 100644
--- a/src/env_loader.zig
+++ b/src/env_loader.zig
@@ -3,8 +3,10 @@ const logger = @import("./logger.zig");
usingnamespace @import("./global.zig");
const CodepointIterator = @import("./string_immutable.zig").CodepointIterator;
const Analytics = @import("./analytics/analytics_thread.zig");
-const Fs = @import("./fs.zig");
const Api = @import("./api/schema.zig").Api;
+const FileSystem = @import("./fs.zig").FileSystem;
+const Dir = @import("./fs.zig").Dir;
+const DirEntry = @import("./fs.zig").DirEntry;
const Variable = struct {
key: string,
value: string,
@@ -483,12 +485,12 @@ pub const Loader = struct {
// .env goes last
pub fn load(
this: *Loader,
- fs: *Fs.RealFS,
- dir: *Fs.DirEntry,
+ fs: *FileSystem,
+ dir: *DirEntry,
comptime development: bool,
) !void {
const start = std.time.nanoTimestamp();
- var dir_handle: std.fs.Dir = std.fs.cwd();
+ const dir_handle = FileSystem.cwd();
var can_auto_close = false;
if (dir.hasComptimeQuery(".env.local")) {
@@ -557,7 +559,7 @@ pub const Loader = struct {
Output.flush();
}
- pub fn loadEnvFile(this: *Loader, fs: *Fs.RealFS, dir: std.fs.Dir, comptime base: string, comptime override: bool) !void {
+ pub fn loadEnvFile(this: *Loader, fs: *FileSystem, dir: Dir, comptime base: string, comptime override: bool) !void {
if (@field(this, base) != null) {
return;
}
@@ -574,7 +576,6 @@ pub const Loader = struct {
},
}
};
- Fs.FileSystem.setMaxFd(file.handle);
defer {
if (fs.needToCloseFiles()) {
@@ -582,13 +583,13 @@ pub const Loader = struct {
}
}
- const stat = try file.stat();
- if (stat.size == 0) {
+ const size = try file.getEndPos();
+ if (size == 0) {
@field(this, base) = logger.Source.initPathString(base, "");
return;
}
- var buf = try this.allocator.allocSentinel(u8, stat.size, 0);
+ var buf = try this.allocator.allocSentinel(u8, size, 0);
errdefer this.allocator.free(buf);
var contents = try file.readAll(buf);
// always sentinel
diff --git a/src/fs.zig b/src/fs.zig
index 1740cfa8f..dc4d1a382 100644
--- a/src/fs.zig
+++ b/src/fs.zig
@@ -11,6 +11,15 @@ const path_handler = @import("./resolver/resolve_path.zig");
const allocators = @import("./allocators.zig");
const hash_map = @import("hash_map.zig");
+const FSImpl = enum {
+ Test,
+ Real,
+
+ pub const choice = if (isTest) FSImpl.Test else FSImpl.Real;
+};
+
+const FileOpenFlags = std.fs.File.OpenFlags;
+
// pub const FilesystemImplementation = @import("fs_impl.zig");
pub const Preallocate = struct {
@@ -317,11 +326,158 @@ pub const FileSystem = struct {
dirname_store: *FileSystem.DirnameStore,
filename_store: *FileSystem.FilenameStore,
- _tmpdir: ?std.fs.Dir = null,
+ _tmpdir: ?Dir = null,
+
+ entries_mutex: Mutex = Mutex.init(),
+ entries: *EntriesOption.Map,
+
+ threadlocal var tmpdir_handle: ?Dir = null;
+
+ pub var _entries_option_map: *EntriesOption.Map = undefined;
+ pub var _entries_option_map_loaded: bool = false;
+
+ pub inline fn cwd() Dir {
+ return Implementation.cwd();
+ }
+
+ pub fn readDirectory(fs: *FileSystem, _dir: string, _handle: ?FileDescriptorType) !*EntriesOption {
+ return @call(.{ .modifier = .always_inline }, Implementation.readDirectory, .{ &fs.fs, _dir, _handle });
+ }
+
+ pub fn openDirectory(_dir: string, flags: std.fs.Dir.OpenDirOptions) !Dir {
+ return @call(.{ .modifier = .always_inline }, Implementation.openDirectory, .{
+ _dir,
+ flags,
+ });
+ }
- threadlocal var tmpdir_handle: ?std.fs.Dir = null;
+ pub fn close(fd: FileDescriptorType) void {
+ Implementation.close(fd);
+ }
- pub fn tmpdir(fs: *FileSystem) std.fs.Dir {
+ pub fn mkdir(dir: string) !void {
+ if (comptime FSImpl.choice == .Real) {
+ try std.fs.Dir.makePath(std.fs.cwd(), dir);
+ return;
+ }
+ }
+
+ pub fn readFileWithHandle(
+ fs: *FileSystem,
+ path: string,
+ _size: ?usize,
+ file: FileDescriptorType,
+ comptime use_shared_buffer: bool,
+ shared_buffer: *MutableString,
+ ) !string {
+ return @call(
+ .{
+ .modifier = .always_inline,
+ },
+ Implementation.readFileWithHandle,
+ .{
+ &fs.fs,
+ path,
+ _size,
+ file,
+ comptime use_shared_buffer,
+ shared_buffer,
+ },
+ );
+ }
+
+ pub fn openFileInDir(
+ dirname_fd: StoredFileDescriptorType,
+ path: string,
+ flags: FileOpenFlags,
+ ) !FileDescriptorType {
+ return @call(
+ .{
+ .modifier = .always_inline,
+ },
+ Implementation.openFileInDir,
+ .{ dirname_fd, path, flags },
+ );
+ }
+
+ pub fn createFileInDir(
+ dirname_fd: StoredFileDescriptorType,
+ path: string,
+ flags: std.fs.File.CreateFlags,
+ ) !FileDescriptorType {
+ return @call(
+ .{
+ .modifier = .always_inline,
+ },
+ Implementation.createFileInDir,
+ .{ dirname_fd, path, flags },
+ );
+ }
+
+ pub fn openFileAbsolute(
+ path: string,
+ flags: FileOpenFlags,
+ ) !FileDescriptorType {
+ return @call(
+ .{
+ .modifier = .always_inline,
+ },
+ Implementation.openFileAbsolute,
+ .{ path, flags },
+ );
+ }
+
+ pub fn openFileAbsoluteZ(
+ path: stringZ,
+ flags: FileOpenFlags,
+ ) !FileDescriptorType {
+ return @call(
+ .{
+ .modifier = .always_inline,
+ },
+ Implementation.openFileAbsoluteZ,
+ .{ path, flags },
+ );
+ }
+
+ pub inline fn openFileZ(
+ path: stringZ,
+ flags: FileOpenFlags,
+ ) !File {
+ return File{ .handle = try openFileAbsoluteZ(path, flags) };
+ }
+
+ pub inline fn openFile(
+ path: string,
+ flags: FileOpenFlags,
+ ) !File {
+ return File{ .handle = try openFileAbsolute(path, flags) };
+ }
+
+ pub inline fn createFile(
+ path: string,
+ flags: std.fs.File.CreateFlags,
+ ) !File {
+ return File{ .handle = try createFileAbsolute(path, flags) };
+ }
+
+ pub inline fn getFileSize(
+ handle: FileDescriptorType,
+ ) !u64 {
+ return @call(
+ .{
+ .modifier = .always_inline,
+ },
+ Implementation.getFileSize,
+ .{handle},
+ );
+ }
+
+ pub inline fn needToCloseFiles(fs: *FileSystem) bool {
+ return fs.fs.needToCloseFiles();
+ }
+
+ pub fn tmpdir(fs: *FileSystem) Dir {
if (tmpdir_handle == null) {
tmpdir_handle = fs.fs.openTmpDir() catch unreachable;
}
@@ -374,6 +530,11 @@ pub const FileSystem = struct {
_top_level_dir = tld;
}
+ if (!_entries_option_map_loaded) {
+ _entries_option_map = EntriesOption.Map.init(allocator);
+ _entries_option_map_loaded = true;
+ }
+
if (!instance_loaded) {
instance = FileSystem{
.allocator = allocator,
@@ -381,10 +542,12 @@ pub const FileSystem = struct {
.fs = Implementation.init(
allocator,
_top_level_dir,
+ _entries_option_map,
),
// .stats = std.StringHashMap(Stat).init(allocator),
.dirname_store = FileSystem.DirnameStore.init(allocator),
.filename_store = FileSystem.FilenameStore.init(allocator),
+ .entries = _entries_option_map,
};
instance_loaded = true;
@@ -494,14 +657,185 @@ pub const FileSystem = struct {
return try allocator.dupe(u8, joined);
}
- pub const Implementation = switch (build_target) {
- .wasi, .native => RealFS,
- .wasm => WasmFS,
- };
+ pub const Implementation: type = FSType;
+};
+
+pub const LoadedFile = struct { path: Path, contents: string };
+
+pub const Dir = struct {
+ fd: FileDescriptorType,
+
+ pub const OpenDirOptions = std.fs.Dir.OpenDirOptions;
+ pub const OpenError = std.fs.Dir.OpenError;
+ pub const CreateFlags = std.fs.File.CreateFlags;
+
+ pub inline fn getStd(file: Dir) std.fs.Dir {
+ return std.fs.Dir{ .fd = file.fd };
+ }
+
+ pub fn close(self: Dir) void {
+ FileSystem.close(self.fd);
+ }
+ pub inline fn openFile(self: Dir, sub_path: []const u8, flags: FileOpenFlags) File.OpenError!File {
+ return File{ .handle = try FileSystem.openFileInDir(self.fd, sub_path, flags) };
+ }
+ pub inline fn openFileZ(self: Dir, sub_path: [*:0]const u8, flags: FileOpenFlags) File.OpenError!File {
+ return try FileSystem.openFileZ(self.fd, sub_path, flags);
+ }
+ pub inline fn createFile(self: Dir, path: []const u8, flags: CreateFlags) File.OpenError!File {
+ return File{ .handle = try FileSystem.createFileInDir(self.fd, path, flags) };
+ }
+
+ pub inline fn writeFile(self: Dir, path: []const u8, buf: []const u8) !void {
+ var file = try self.createFile(path, .{ .truncate = true });
+ defer file.close();
+ _ = try file.writeAll(buf);
+ }
+
+ pub inline fn makePath(self: Dir, sub_path: []const u8) !void {
+ switch (comptime FSImpl.choice) {
+ .Test => {},
+ .Real => {
+ try std.fs.Dir.makePath(std.fs.Dir{ .fd = self.fd }, sub_path);
+ },
+ }
+ }
+ pub fn makeOpenPath(self: Dir, sub_path: []const u8, open_dir_options: OpenDirOptions) !Dir {
+ switch (comptime FSImpl.choice) {
+ .Test => {},
+ .Real => {
+ return Dir{ .fd = try std.fs.Dir.makeOpenPath(std.fs.Dir{ .fd = self.fd }, sub_path, open_dir_options) };
+ },
+ }
+ }
+
+ pub fn iterate(self: Dir) std.fs.Dir.Iterator {
+ switch (comptime FSImpl.choice) {
+ .Test => {},
+ .Real => {
+ return std.fs.Dir.iterate(std.fs.Dir{ .fd = self.fd });
+ },
+ }
+ }
};
-pub const Directory = struct { path: Path, contents: []string };
-pub const File = struct { path: Path, contents: string };
+const Stat = std.fs.File.Stat;
+
+pub const File = struct {
+ handle: FileDescriptorType,
+
+ pub const ReadError = std.fs.File.ReadError;
+ pub const PReadError = std.fs.File.PReadError;
+ pub const WriteError = std.fs.File.WriteError;
+ pub const OpenError = std.fs.File.OpenError;
+
+ pub fn close(this: File) void {
+ FSType.close(this.handle);
+ }
+
+ pub const Writer = std.io.Writer(File, WriteError, writeNoinline);
+ pub const Reader = std.io.Reader(File, ReadError, readNoinline);
+
+ pub fn writer(this: File) Writer {
+ return Writer{ .context = this };
+ }
+
+ pub fn reader(this: File) Reader {
+ return Reader{ .context = this };
+ }
+
+ pub inline fn getStd(file: File) std.fs.File {
+ return std.fs.File{ .handle = file.handle };
+ }
+
+ pub inline fn read(self: File, buffer: []u8) ReadError!usize {
+ return try FSType.read(self.handle, buffer);
+ }
+
+ pub fn readNoinline(self: File, bytes: []u8) ReadError!usize {
+ return try FSType.read(self.handle, bytes);
+ }
+
+ pub fn pread(self: File, buffer: []u8, offset: u64) PReadError!usize {
+ return try FSType.pread(self.handle, buffer, offset);
+ }
+
+ pub fn preadAll(self: File, buffer: []u8, offset: u64) PReadError!usize {
+ var index: usize = 0;
+ while (index != buffer.len) {
+ const amt = try self.pread(buffer[index..], offset);
+ if (amt == 0) break;
+ index += amt;
+ }
+ return index;
+ }
+
+ pub fn readAll(self: File, buffer: []u8) ReadError!usize {
+ var index: usize = 0;
+ while (index != buffer.len) {
+ const amt = try self.read(buffer[index..]);
+ if (amt == 0) break;
+ index += amt;
+ }
+ return index;
+ }
+
+ pub fn readToEndAlloc(
+ self: File,
+ allocator: *std.mem.Allocator,
+ size_: ?usize,
+ ) ![]u8 {
+ const size = size_ orelse try self.getEndPos();
+ var buf = try allocator.alloc(u8, size);
+ return buf[0..try self.readAll(buf)];
+ }
+
+ pub fn pwriteAll(self: File, bytes: []const u8, offset: u64) PWriteError!void {
+ var index: usize = 0;
+ while (index < bytes.len) {
+ index += try self.pwrite(bytes[index..], offset + index);
+ }
+ }
+
+ pub inline fn write(self: File, bytes: []const u8) WriteError!usize {
+ return try FSType.write(self.handle, bytes);
+ }
+
+ pub fn writeNoinline(self: File, bytes: []const u8) WriteError!usize {
+ return try FSType.write(self.handle, bytes);
+ }
+
+ pub fn writeAll(self: File, bytes: []const u8) WriteError!void {
+ var index: usize = 0;
+ while (index < bytes.len) {
+ index += try self.write(
+ bytes[index..],
+ );
+ }
+ }
+ pub inline fn pwrite(self: File, bytes: []const u8, offset: u64) PWriteError!usize {
+ return try FSType.pwrite(self.handle, bytes);
+ }
+
+ pub fn getPos(self: File) !u64 {
+ return try FSType.getPos(self.handle);
+ }
+
+ pub fn seekTo(self: File, offset: u64) !void {
+ return try FSType.seekTo(self.handle, offset);
+ }
+
+ pub inline fn stat(self: File) !std.fs.File.Stat {
+ return try FSType.stat(
+ self.handle,
+ );
+ }
+
+ pub inline fn getEndPos(self: File) !usize {
+ const stat_ = try self.stat();
+ return @intCast(usize, stat_.size);
+ }
+};
pub const PathName = struct {
base: string,
@@ -747,7 +1081,6 @@ pub const Path = struct {
};
pub const RealFS = struct {
- entries_mutex: Mutex = Mutex.init(),
entries: *EntriesOption.Map,
allocator: *std.mem.Allocator,
// limiter: *Limiter,
@@ -765,10 +1098,10 @@ pub const RealFS = struct {
};
pub var tmpdir_path: []const u8 = undefined;
- pub fn openTmpDir(fs: *const RealFS) !std.fs.Dir {
+ pub fn openTmpDir(fs: *const RealFS) !Dir {
var tmpdir_base = std.os.getenv("TMPDIR") orelse PLATFORM_TMP_DIR;
tmpdir_path = try std.fs.realpath(tmpdir_base, &tmpdir_buf);
- return try std.fs.openDirAbsolute(tmpdir_path, .{ .access_sub_paths = true, .iterate = true });
+ return try openDirectory(tmpdir_path, .{ .access_sub_paths = true, .iterate = true });
}
pub fn fetchCacheFile(fs: *RealFS, basename: string) !std.fs.File {
@@ -783,14 +1116,14 @@ pub const RealFS = struct {
fd: std.os.fd_t = 0,
dir_fd: std.os.fd_t = 0,
- pub inline fn dir(this: *Tmpfile) std.fs.Dir {
- return std.fs.Dir{
+ pub inline fn dir(this: *Tmpfile) Dir {
+ return Dir{
.fd = this.dir_fd,
};
}
- pub inline fn file(this: *Tmpfile) std.fs.File {
- return std.fs.File{
+ pub inline fn file(this: *Tmpfile) File {
+ return File{
.handle = this.fd,
};
}
@@ -821,7 +1154,7 @@ pub const RealFS = struct {
if (comptime !Environment.isLinux) {
if (this.dir_fd == 0) return;
- this.dir().deleteFileZ(name) catch {};
+ this.dir().getStd().deleteFileZ(name) catch {};
}
}
};
@@ -871,23 +1204,17 @@ pub const RealFS = struct {
}
}
- var _entries_option_map: *EntriesOption.Map = undefined;
- var _entries_option_map_loaded: bool = false;
pub fn init(
allocator: *std.mem.Allocator,
- cwd: string,
+ cwd_: string,
+ entries: *EntriesOption.Map,
) RealFS {
const file_limit = adjustUlimit() catch unreachable;
- if (!_entries_option_map_loaded) {
- _entries_option_map = EntriesOption.Map.init(allocator);
- _entries_option_map_loaded = true;
- }
-
return RealFS{
- .entries = _entries_option_map,
+ .entries = entries,
.allocator = allocator,
- .cwd = cwd,
+ .cwd = cwd_,
.file_limit = file_limit,
.file_quota = file_limit,
};
@@ -930,10 +1257,10 @@ pub const RealFS = struct {
);
}
- pub fn generate(fs: *RealFS, path: string, file: std.fs.File) anyerror!ModKey {
- const stat = try file.stat();
+ pub fn generate(fs: *RealFS, path: string, file: File) anyerror!ModKey {
+ const stat_ = try file.stat();
- const seconds = @divTrunc(stat.mtime, @as(@TypeOf(stat.mtime), std.time.ns_per_s));
+ const seconds = @divTrunc(stat_.mtime, @as(@TypeOf(stat_.mtime), std.time.ns_per_s));
// We can't detect changes if the file system zeros out the modification time
if (seconds == 0 and std.time.ns_per_s == 0) {
@@ -943,15 +1270,15 @@ pub const RealFS = struct {
// Don't generate a modification key if the file is too new
const now = std.time.nanoTimestamp();
const now_seconds = @divTrunc(now, std.time.ns_per_s);
- if (seconds > seconds or (seconds == now_seconds and stat.mtime > now)) {
+ if (seconds > seconds or (seconds == now_seconds and stat_.mtime > now)) {
return error.Unusable;
}
return ModKey{
- .inode = stat.inode,
- .size = stat.size,
- .mtime = stat.mtime,
- .mode = stat.mode,
+ .inode = stat_.inode,
+ .size = stat_.size,
+ .mtime = stat_.mtime,
+ .mode = stat_.mode,
// .uid = stat.
};
}
@@ -962,10 +1289,65 @@ pub const RealFS = struct {
return try ModKey.generate(fs, path, file);
}
- pub fn modKey(fs: *RealFS, path: string) anyerror!ModKey {
+ pub fn cwd() Dir {
+ return Dir{ .fd = std.fs.cwd().fd };
+ }
+
+ pub inline fn read(fd: FileDescriptorType, buf: []u8) !usize {
+ return try std.os.read(fd, buf);
+ }
+
+ pub inline fn write(fd: FileDescriptorType, buf: []const u8) !usize {
+ return try std.os.write(fd, buf);
+ }
+
+ pub inline fn pwrite(fd: FileDescriptorType, buf: []const u8, offset: usize) !usize {
+ return try std.os.pwrite(fd, buf, offset);
+ }
+
+ pub inline fn pread(fd: FileDescriptorType, buf: []u8, offset: usize) !usize {
+ return try std.os.pread(fd, buf, offset);
+ }
+
+ pub inline fn openFileInDir(dir: FileDescriptorType, subpath: string, flags: FileOpenFlags) !FileDescriptorType {
+ const file = try std.fs.Dir.openFile(std.fs.Dir{ .fd = dir }, subpath, flags);
+ return file.handle;
+ }
+
+ pub inline fn createFileInDir(dir: FileDescriptorType, subpath: string, flags: std.fs.File.CreateFlags) !FileDescriptorType {
+ const file = try std.fs.Dir.createFile(std.fs.Dir{ .fd = dir }, subpath, flags);
+ return file.handle;
+ }
+
+ pub inline fn openFileAbsolute(path: string, flags: FileOpenFlags) !FileDescriptorType {
+ const file = try std.fs.openFileAbsolute(path, flags);
+ return file.handle;
+ }
+
+ pub inline fn openFileAbsoluteZ(path: stringZ, flags: FileOpenFlags) !FileDescriptorType {
+ const file = try std.fs.openFileAbsoluteZ(path, flags);
+ return file.handle;
+ }
+
+ pub inline fn createFileAbsolute(path: string, flags: std.fs.File.CreateFlags) !FileDescriptorType {
+ const file = try std.fs.createFileAbsolute(path, flags);
+ return file.handle;
+ }
+
+ pub inline fn seekTo(fd: FileDescriptorType, offset: usize) !void {
+ try std.fs.File.seekTo(std.fs.File{ .handle = fd }, offset);
+ }
+
+ pub inline fn getPos(
+ fd: FileDescriptorType,
+ ) !usize {
+ return try std.fs.File.getPos(std.fs.File{ .handle = fd });
+ }
+
+ pub fn modKey(fs: *const RealFS, path: string) anyerror!ModKey {
// fs.limiter.before();
// defer fs.limiter.after();
- var file = try std.fs.openFileAbsolute(path, std.fs.File.OpenFlags{ .read = true });
+ var file = try std.fs.openFileAbsolute(path, FileOpenFlags{ .read = true });
defer {
if (fs.needToCloseFiles()) {
file.close();
@@ -1001,8 +1383,15 @@ pub const RealFS = struct {
}
};
- pub fn openDir(fs: *RealFS, unsafe_dir_string: string) std.fs.File.OpenError!std.fs.Dir {
- return try std.fs.openDirAbsolute(unsafe_dir_string, std.fs.Dir.OpenDirOptions{ .iterate = true, .access_sub_paths = true, .no_follow = false });
+ fn openDir(unsafe_dir_string: string) std.fs.File.OpenError!FileDescriptorType {
+ const fd = try std.fs.openDirAbsolute(unsafe_dir_string, std.fs.Dir.OpenDirOptions{ .iterate = true, .access_sub_paths = true, .no_follow = false });
+
+ return fd.fd;
+ }
+
+ pub fn openDirectory(path: string, flags: std.fs.Dir.OpenDirOptions) anyerror!Dir {
+ const dir = try std.fs.cwd().openDir(path, flags);
+ return Dir{ .fd = dir.fd };
}
fn readdir(
@@ -1047,15 +1436,15 @@ pub const RealFS = struct {
threadlocal var temp_entries_option: EntriesOption = undefined;
- pub fn readDirectory(fs: *RealFS, _dir: string, _handle: ?std.fs.Dir) !*EntriesOption {
+ pub fn readDirectory(fs: *RealFS, _dir: string, _handle: ?FileDescriptorType) !*EntriesOption {
var dir = _dir;
var cache_result: ?allocators.Result = null;
if (comptime FeatureFlags.enable_entry_cache) {
- fs.entries_mutex.lock();
+ fs.parent_fs.entries_mutex.lock();
}
defer {
if (comptime FeatureFlags.enable_entry_cache) {
- fs.entries_mutex.unlock();
+ fs.parent_fs.entries_mutex.unlock();
}
}
@@ -1069,7 +1458,7 @@ pub const RealFS = struct {
}
}
- var handle = _handle orelse try fs.openDir(dir);
+ var handle = std.fs.Dir{ .fd = _handle orelse try openDir(dir) };
defer {
if (_handle == null and fs.needToCloseFiles()) {
@@ -1107,14 +1496,26 @@ pub const RealFS = struct {
fn readFileError(fs: *RealFS, path: string, err: anyerror) void {}
+ pub inline fn stat(fd: FileDescriptorType) anyerror!Stat {
+ return try std.fs.File.stat(.{ .handle = fd });
+ }
+
+ pub inline fn getFileSize(
+ handle: FileDescriptorType,
+ ) !u64 {
+ const stat_ = try std.os.fstat(handle);
+ return @intCast(u64, stat_.size);
+ }
+
pub fn readFileWithHandle(
fs: *RealFS,
path: string,
_size: ?usize,
- file: std.fs.File,
+ handle: FileDescriptorType,
comptime use_shared_buffer: bool,
shared_buffer: *MutableString,
- ) !File {
+ ) !string {
+ const file = std.fs.File{ .handle = handle };
FileSystem.setMaxFd(file.handle);
if (comptime FeatureFlags.disable_filesystem_cache) {
@@ -1133,14 +1534,12 @@ pub const RealFS = struct {
if (size == 0) {
if (comptime use_shared_buffer) {
shared_buffer.reset();
- return File{ .path = Path.init(path), .contents = shared_buffer.list.items };
+ return shared_buffer.list.items;
} else {
- return File{ .path = Path.init(path), .contents = "" };
+ return "";
}
}
- var file_contents: []u8 = undefined;
-
// When we're serving a JavaScript-like file over HTTP, we do not want to cache the contents in memory
// This imposes a performance hit because not reading from disk is faster than reading from disk
// Part of that hit is allocating a temporary buffer to store the file contents in
@@ -1155,7 +1554,7 @@ pub const RealFS = struct {
return err;
};
shared_buffer.list.items = shared_buffer.list.items[0..read_count];
- file_contents = shared_buffer.list.items;
+ return shared_buffer.list.items;
} else {
// We use pread to ensure if the file handle was open, it doesn't seek from the last position
var buf = try fs.allocator.alloc(u8, size);
@@ -1163,30 +1562,12 @@ pub const RealFS = struct {
fs.readFileError(path, err);
return err;
};
- file_contents = buf[0..read_count];
+ return buf[0..read_count];
}
-
- return File{ .path = Path.init(path), .contents = file_contents };
}
- pub fn readFile(
- fs: *RealFS,
- path: string,
- _size: ?usize,
- ) !File {
- fs.limiter.before();
- defer fs.limiter.after();
- const file: std.fs.File = std.fs.openFileAbsolute(path, std.fs.File.OpenFlags{ .read = true, .write = false }) catch |err| {
- fs.readFileError(path, err);
- return err;
- };
- defer {
- if (fs.needToCloseFiles()) {
- file.close();
- }
- }
-
- return try fs.readFileWithHandle(path, _size, file);
+ pub inline fn close(fd: FileDescriptorType) void {
+ std.os.close(fd);
}
pub fn kind(fs: *RealFS, _dir: string, base: string, existing_fd: StoredFileDescriptorType) !Entry.Cache {
@@ -1200,9 +1581,9 @@ pub const RealFS = struct {
const absolute_path_c: [:0]const u8 = outpath[0..entry_path.len :0];
- var stat = try C.lstat_absolute(absolute_path_c);
- const is_symlink = stat.kind == std.fs.File.Kind.SymLink;
- var _kind = stat.kind;
+ var lstat = try C.lstat_absolute(absolute_path_c);
+ const is_symlink = lstat.kind == std.fs.File.Kind.SymLink;
+ var _kind = lstat.kind;
var cache = Entry.Cache{
.kind = Entry.Kind.file,
.symlink = PathString.empty,
@@ -1249,6 +1630,13 @@ pub const RealFS = struct {
// doNotCacheEntries bool
};
+pub const TestFS = struct {};
+
+const FSType = switch (FSImpl.choice) {
+ FSImpl.Test => TestFS,
+ FSImpl.Real => RealFS,
+};
+
test "PathName.init" {
var file = "/root/directory/file.ext".*;
const res = PathName.init(
diff --git a/src/http.zig b/src/http.zig
index cf3a4d76d..1479ad539 100644
--- a/src/http.zig
+++ b/src/http.zig
@@ -22,6 +22,7 @@ const DotEnv = @import("./env_loader.zig");
const mimalloc = @import("./allocators/mimalloc.zig");
const MacroMap = @import("./resolver/package_json.zig").MacroMap;
const Analytics = @import("./analytics/analytics_thread.zig");
+const FileSystem = Fs.FileSystem;
pub fn constStrToU8(s: string) []u8 {
return @intToPtr([*]u8, @ptrToInt(s.ptr))[0..s.len];
}
@@ -307,7 +308,7 @@ pub const RequestContext = struct {
var tmp_buildfile_buf = std.mem.span(&Bundler.tmp_buildfile_buf);
// On Windows, we don't keep the directory handle open forever because Windows doesn't like that.
- const public_dir: std.fs.Dir = this.bundler.options.routes.static_dir_handle orelse std.fs.openDirAbsolute(this.bundler.options.routes.static_dir, .{}) catch |err| {
+ const public_dir: Fs.Dir = this.bundler.options.routes.static_dir_handle orelse FileSystem.openDirectory(this.bundler.options.routes.static_dir, .{}) catch |err| {
this.bundler.log.addErrorFmt(null, logger.Loc.Empty, this.allocator, "Opening public directory failed: {s}", .{@errorName(err)}) catch unreachable;
Output.printErrorln("Opening public directory failed: {s}", .{@errorName(err)});
this.bundler.options.routes.static_dir_enabled = false;
@@ -316,7 +317,7 @@ pub const RequestContext = struct {
var relative_unrooted_path: []u8 = resolve_path.normalizeString(relative_path, false, .auto);
- var _file: ?std.fs.File = null;
+ var _file: ?FileDescriptorType = null;
// Is it the index file?
if (relative_unrooted_path.len == 0) {
@@ -331,14 +332,14 @@ pub const RequestContext = struct {
} else if (public_dir.openFile("index.html", .{})) |file| {
var index_path = "index.html".*;
relative_unrooted_path = &(index_path);
- _file = file;
+ _file = file.handle;
extension = "html";
} else |err| {}
// Okay is it actually a full path?
} else if (extension.len > 0) {
if (public_dir.openFile(relative_unrooted_path, .{})) |file| {
- _file = file;
+ _file = file.handle;
} else |err| {}
}
@@ -350,7 +351,7 @@ pub const RequestContext = struct {
std.mem.copy(u8, tmp_buildfile_buf[relative_unrooted_path.len..], ".html");
if (public_dir.openFile(tmp_buildfile_buf[0 .. relative_unrooted_path.len + ".html".len], .{})) |file| {
- _file = file;
+ _file = file.handle;
extension = "html";
break;
} else |err| {}
@@ -371,7 +372,7 @@ pub const RequestContext = struct {
const __path = _path;
relative_unrooted_path = __path;
extension = "html";
- _file = file;
+ _file = file.handle;
break;
} else |err| {}
}
@@ -379,12 +380,13 @@ pub const RequestContext = struct {
break;
}
- if (_file) |*file| {
+ if (_file) |fd| {
+ const file = Fs.File{ .handle = fd };
var stat = file.stat() catch return null;
var absolute_path = resolve_path.joinAbs(this.bundler.options.routes.static_dir, .auto, relative_unrooted_path);
if (stat.kind == .SymLink) {
- file.* = std.fs.openFileAbsolute(absolute_path, .{ .read = true }) catch return null;
+ _ = FileSystem.openFileAbsolute(absolute_path, .{ .read = true }) catch return null;
absolute_path = std.os.getFdPath(
file.handle,
@@ -399,7 +401,7 @@ pub const RequestContext = struct {
return null;
}
- var output_file = OutputFile.initFile(file.*, absolute_path, stat.size);
+ var output_file = OutputFile.initFile(fd, absolute_path, stat.size);
output_file.value.copy.close_handle_on_complete = true;
output_file.value.copy.autowatch = false;
return bundler.ServeResult{
@@ -2238,22 +2240,21 @@ pub const RequestContext = struct {
const fd = if (resolve_result.file_fd != 0)
resolve_result.file_fd
else brk: {
- var file = std.fs.openFileAbsoluteZ(path.textZ(), .{ .read = true }) catch |err| {
+ const file = FileSystem.openFileAbsoluteZ(path.textZ(), .{ .read = true }) catch |err| {
Output.prettyErrorln("Failed to open {s} due to error {s}", .{ path.text, @errorName(err) });
return try ctx.sendInternalError(err);
};
needs_close = true;
- break :brk file.handle;
+ break :brk file;
};
defer {
if (needs_close) {
- std.os.close(fd);
+ FileSystem.close(fd);
}
}
const content_length = brk: {
- var file = std.fs.File{ .handle = fd };
- var stat = file.stat() catch |err| {
+ var stat = Fs.File.stat(.{ .handle = fd }) catch |err| {
Output.prettyErrorln("Failed to read {s} due to error {s}", .{ path.text, @errorName(err) });
return try ctx.sendInternalError(err);
};
diff --git a/src/javascript/jsc/javascript.zig b/src/javascript/jsc/javascript.zig
index 7749b5182..d09865fb5 100644
--- a/src/javascript/jsc/javascript.zig
+++ b/src/javascript/jsc/javascript.zig
@@ -273,7 +273,7 @@ pub const Bun = struct {
exception: js.ExceptionRef,
) js.JSValueRef {
const path = buf_z.ptr[0..buf_z.len];
- var file = std.fs.cwd().openFileZ(buf_z, .{ .read = true, .write = false }) catch |err| {
+ var file = Fs.FileSystem.openFileZ(buf_z, .{ .read = true, .write = false }) catch |err| {
JSError(getAllocator(ctx), "Opening file {s} for path: \"{s}\"", .{ @errorName(err), path }, ctx, exception);
return js.JSValueMakeUndefined(ctx);
};
@@ -313,7 +313,7 @@ pub const Bun = struct {
) js.JSValueRef {
const path = buf_z.ptr[0..buf_z.len];
- var file = std.fs.cwd().openFileZ(buf_z, .{ .read = true, .write = false }) catch |err| {
+ var file = Fs.FileSystem.openFileZ(buf_z, .{ .read = true, .write = false }) catch |err| {
JSError(getAllocator(ctx), "Opening file {s} for path: \"{s}\"", .{ @errorName(err), path }, ctx, exception);
return js.JSValueMakeUndefined(ctx);
};
diff --git a/src/js_printer.zig b/src/js_printer.zig
index 95e8ea22c..7f2ae340e 100644
--- a/src/js_printer.zig
+++ b/src/js_printer.zig
@@ -3910,7 +3910,7 @@ pub const DirectWriter = struct {
// Buffered 16k 43ms
// Buffered 4k 55ms
const FileWriterInternal = struct {
- file: std.fs.File,
+ file: fs.File,
threadlocal var buffer: MutableString = undefined;
threadlocal var has_loaded_buffer: bool = false;
@@ -3919,7 +3919,7 @@ const FileWriterInternal = struct {
return &buffer;
}
- pub fn init(file: std.fs.File) FileWriterInternal {
+ pub fn init(file: fs.File) FileWriterInternal {
if (!has_loaded_buffer) {
buffer = MutableString.init(alloc.dynamic, 0) catch unreachable;
has_loaded_buffer = true;
@@ -4066,7 +4066,7 @@ pub const BufferPrinter = NewWriter(
BufferWriter.getLastLastByte,
);
pub const FileWriter = NewWriter(FileWriterInternal, FileWriterInternal.writeByte, FileWriterInternal.writeAll, FileWriterInternal.getLastByte, FileWriterInternal.getLastLastByte);
-pub fn NewFileWriter(file: std.fs.File) FileWriter {
+pub fn NewFileWriter(file: fs.File) FileWriter {
var internal = FileWriterInternal.init(file);
return FileWriter.init(internal);
}
diff --git a/src/linker.zig b/src/linker.zig
index 176c33ca0..7657c6665 100644
--- a/src/linker.zig
+++ b/src/linker.zig
@@ -29,6 +29,7 @@ const ResolveQueue = _bundler.ResolveQueue;
const ResolverType = Resolver.Resolver;
const Runtime = @import("./runtime.zig").Runtime;
+const FileSystem = Fs.FileSystem;
pub const CSSResolveError = error{ResolveError};
pub const OnImportCallback = fn (resolve_result: *const Resolver.Result, import_record: *ImportRecord, source_dir: string) void;
@@ -94,8 +95,7 @@ pub const Linker = struct {
}
}
- var file: std.fs.File = if (fd) |_fd| std.fs.File{ .handle = _fd } else try std.fs.openFileAbsolute(file_path.text, .{ .read = true });
- Fs.FileSystem.setMaxFd(file.handle);
+ var file = try FileSystem.openFileZ(file_path.textZ(), .{ .read = true });
var modkey = try Fs.RealFS.ModKey.generate(&this.fs.fs, file_path.text, file);
const hash_name = try modkey.hashName(file_path.name.base);
@@ -104,7 +104,7 @@ pub const Linker = struct {
try this.hashed_filenames.put(hashed, try this.allocator.dupe(u8, hash_name));
}
- if (this.fs.fs.needToCloseFiles() and fd == null) {
+ if (this.fs.needToCloseFiles() and fd == null) {
file.close();
}
diff --git a/src/logger.zig b/src/logger.zig
index 5926334aa..62af998b4 100644
--- a/src/logger.zig
+++ b/src/logger.zig
@@ -878,7 +878,7 @@ pub const Source = struct {
line_count: usize,
};
- pub fn initFile(file: fs.File, allocator: *std.mem.Allocator) !Source {
+ pub fn initFile(file: fs.LoadedFile, allocator: *std.mem.Allocator) !Source {
var name = file.path.name;
var source = Source{
@@ -890,7 +890,7 @@ pub const Source = struct {
return source;
}
- pub fn initRecycledFile(file: fs.File, allocator: *std.mem.Allocator) !Source {
+ pub fn initRecycledFile(file: fs.LoadedFile, allocator: *std.mem.Allocator) !Source {
var name = file.path.name;
var source = Source{
diff --git a/src/node_module_bundle.zig b/src/node_module_bundle.zig
index f5421c810..f0415df9c 100644
--- a/src/node_module_bundle.zig
+++ b/src/node_module_bundle.zig
@@ -62,7 +62,7 @@ pub const NodeModuleBundle = struct {
return code.str;
}
- var file = std.fs.File{ .handle = this.fd };
+ var file = Fs.File{ .handle = this.fd };
var buf = try allocator.alloc(u8, this.code_end_pos);
const count = try file.preadAll(buf, this.codeStartOffset());
diff --git a/src/options.zig b/src/options.zig
index e57c8f043..5c6949e0e 100644
--- a/src/options.zig
+++ b/src/options.zig
@@ -14,7 +14,10 @@ const URL = @import("./query_string_map.zig").URL;
const ConditionsMap = @import("./resolver/package_json.zig").ESModule.ConditionsMap;
usingnamespace @import("global.zig");
+const Dir = Fs.Dir;
+const File = Fs.File;
const Analytics = @import("./analytics/analytics_thread.zig");
+const FileSystem = Fs.FileSystem;
const DotEnv = @import("./env_loader.zig");
@@ -909,7 +912,7 @@ pub const BundleOptions = struct {
origin: URL = URL{},
output_dir: string = "",
- output_dir_handle: ?std.fs.Dir = null,
+ output_dir_handle: ?Dir = null,
node_modules_bundle_url: string = "",
node_modules_bundle_pretty_path: string = "",
@@ -1103,7 +1106,7 @@ pub const BundleOptions = struct {
if (bundle_path.len > 0) {
load_bundle: {
const pretty_path = fs.relativeTo(bundle_path);
- var bundle_file = std.fs.openFileAbsolute(bundle_path, .{ .read = true, .write = true }) catch |err| {
+ const bundle_file = Fs.FileSystem.openFileAbsolute(bundle_path, .{ .read = true, .write = true }) catch |err| {
if (is_generating_bundle) {
break :load_bundle;
}
@@ -1114,11 +1117,11 @@ pub const BundleOptions = struct {
};
defer {
- if (is_generating_bundle) bundle_file.close();
+ if (is_generating_bundle) Fs.FileSystem.close(bundle_file);
}
const time_start = std.time.nanoTimestamp();
- if (NodeModuleBundle.loadBundle(allocator, bundle_file)) |bundle| {
+ if (NodeModuleBundle.loadBundle(allocator, Fs.File{ .handle = bundle_file })) |bundle| {
if (!is_generating_bundle) {
var node_module_bundle = try allocator.create(NodeModuleBundle);
node_module_bundle.* = bundle;
@@ -1181,7 +1184,7 @@ pub const BundleOptions = struct {
"<r>error reading <d>\"<r><b>{s}<r><d>\":<r> <b><red>{s}<r>, <b>deleting it<r> so you don't keep seeing this message.",
.{ pretty_path, @errorName(err) },
);
- bundle_file.close();
+ FileSystem.close(bundle_file);
}
}
}
@@ -1254,7 +1257,7 @@ pub const BundleOptions = struct {
if (!disabled_static) {
var _dirs = [_]string{chosen_dir};
opts.routes.static_dir = try fs.absAlloc(allocator, &_dirs);
- opts.routes.static_dir_handle = std.fs.openDirAbsolute(opts.routes.static_dir, .{ .iterate = true }) catch |err| brk: {
+ opts.routes.static_dir_handle = FileSystem.openDirectory(opts.routes.static_dir, .{ .iterate = true }) catch |err| brk: {
var did_warn = false;
switch (err) {
error.FileNotFound => {
@@ -1339,14 +1342,14 @@ pub const BundleOptions = struct {
}
};
-pub fn openOutputDir(output_dir: string) !std.fs.Dir {
- return std.fs.openDirAbsolute(output_dir, std.fs.Dir.OpenDirOptions{}) catch brk: {
- std.fs.makeDirAbsolute(output_dir) catch |err| {
+pub fn openOutputDir(output_dir: string) !Dir {
+ return FileSystem.openDirectory(output_dir, Dir.OpenDirOptions{}) catch brk: {
+ FileSystem.mkdir(output_dir) catch |err| {
Output.printErrorln("error: Unable to mkdir \"{s}\": \"{s}\"", .{ output_dir, @errorName(err) });
Global.crash();
};
- var handle = std.fs.openDirAbsolute(output_dir, std.fs.Dir.OpenDirOptions{}) catch |err2| {
+ var handle = FileSystem.openDirectory(output_dir, Dir.OpenDirOptions{}) catch |err2| {
Output.printErrorln("error: Unable to open \"{s}\": \"{s}\"", .{ output_dir, @errorName(err2) });
Global.crash();
};
@@ -1365,7 +1368,7 @@ pub const TransformOptions = struct {
inject: ?[]string = null,
origin: string = "",
preserve_symlinks: bool = false,
- entry_point: Fs.File,
+ entry_point: Fs.LoadedFile,
resolve_paths: bool = false,
tsconfig_override: ?string = null,
@@ -1375,7 +1378,7 @@ pub const TransformOptions = struct {
pub fn initUncached(allocator: *std.mem.Allocator, entryPointName: string, code: string) !TransformOptions {
assert(entryPointName.len > 0);
- var entryPoint = Fs.File{
+ var entryPoint = Fs.LoadedFile{
.path = Fs.Path.init(entryPointName),
.contents = code,
};
@@ -1467,16 +1470,16 @@ pub const OutputFile = struct {
};
}
- pub fn initFile(file: std.fs.File, pathname: string, size: usize) OutputFile {
+ pub fn initFile(handle: FileDescriptorType, pathname: string, size: usize) OutputFile {
return .{
.loader = .file,
.input = Fs.Path.init(pathname),
.size = size,
- .value = .{ .copy = FileOperation.fromFile(file.handle, pathname) },
+ .value = .{ .copy = FileOperation.fromFile(handle, pathname) },
};
}
- pub fn initFileWithDir(file: std.fs.File, pathname: string, size: usize, dir: std.fs.Dir) OutputFile {
+ pub fn initFileWithDir(file: File, pathname: string, size: usize, dir: Dir) OutputFile {
var res = initFile(file, pathname, size);
res.value.copy.dir_handle = dir.fd;
return res;
@@ -1495,7 +1498,7 @@ pub const OutputFile = struct {
var move = file.value.move;
if (move.dir > 0) {
std.os.renameat(move.dir, move.pathname, dir, rel_path) catch |err| {
- const dir_ = std.fs.Dir{ .fd = dir };
+ const dir_ = Dir{ .fd = dir };
if (std.fs.path.dirname(rel_path)) |dirname| {
dir_.makePath(dirname) catch {};
std.os.renameat(move.dir, move.pathname, dir, rel_path) catch {};
@@ -1511,7 +1514,7 @@ pub const OutputFile = struct {
pub fn copyTo(file: *const OutputFile, base_path: string, rel_path: []u8, dir: FileDescriptorType) !void {
var copy = file.value.copy;
- var dir_obj = std.fs.Dir{ .fd = dir };
+ var dir_obj = Dir{ .fd = dir };
const file_out = (try dir_obj.createFile(rel_path, .{}));
const fd_out = file_out.handle;
@@ -1576,7 +1579,7 @@ pub const TransformResult = struct {
warnings: []logger.Msg = &([_]logger.Msg{}),
output_files: []OutputFile = &([_]OutputFile{}),
outbase: string,
- root_dir: ?std.fs.Dir = null,
+ root_dir: ?Dir = null,
pub fn init(
outbase: string,
output_files: []OutputFile,
@@ -1925,7 +1928,7 @@ pub const RouteConfig = struct {
routes_enabled: bool = false,
static_dir: string = "",
- static_dir_handle: ?std.fs.Dir = null,
+ static_dir_handle: ?Dir = null,
static_dir_enabled: bool = false,
single_page_app_routing: bool = false,
single_page_app_fd: StoredFileDescriptorType = 0,
diff --git a/src/resolver/resolver.zig b/src/resolver/resolver.zig
index fcd1b9fad..5283ce812 100644
--- a/src/resolver/resolver.zig
+++ b/src/resolver/resolver.zig
@@ -27,6 +27,8 @@ const allocators = @import("../allocators.zig");
const Path = Fs.Path;
const NodeModuleBundle = @import("../node_module_bundle.zig").NodeModuleBundle;
+const FileSystem = Fs.FileSystem;
+
pub fn isPackagePath(path: string) bool {
// this could probably be flattened into something more optimized
return path[0] != '/' and !strings.startsWith(path, "./") and !strings.startsWith(path, "../") and !strings.eql(path, ".") and !strings.eql(path, "..");
@@ -203,7 +205,7 @@ pub const DirEntryResolveQueueItem = struct {
};
threadlocal var _dir_entry_paths_to_resolve: [256]DirEntryResolveQueueItem = undefined;
-threadlocal var _open_dirs: [256]std.fs.Dir = undefined;
+threadlocal var _open_dirs: [256]Fs.Dir = undefined;
threadlocal var resolve_without_remapping_buf: [std.fs.MAX_PATH_BYTES]u8 = undefined;
threadlocal var index_buf: [std.fs.MAX_PATH_BYTES]u8 = undefined;
threadlocal var dir_info_uncached_filename_buf: [std.fs.MAX_PATH_BYTES]u8 = undefined;
@@ -288,7 +290,7 @@ pub const TSConfigExtender = struct {
// // // Skip "node_modules" folders
// // if (!strings.eql(std.fs.path.basename(current), "node_modules")) {
// // var paths1 = [_]string{ current, "node_modules", extends };
- // // var join1 = r.fs.absAlloc(ctx.r.allocator, &paths1) catch unreachable;
+ // // var join1 = FileSystem.instance.absAlloc(ctx.r.allocator, &paths1) catch unreachable;
// // const res = ctx.r.parseTSConfig(join1, ctx.1) catch |err| {
// // if (err == error.ENOENT) {
// // continue;
@@ -519,7 +521,7 @@ pub const Resolver = struct {
) !void {
// TODO: make this only parse package.json once
- var result = try r.resolve(r.fs.top_level_dir, package, .internal);
+ var result = try r.resolve(FileSystem.instance.top_level_dir, package, .internal);
// support passing a package.json or path to a package
const pkg: *const PackageJSON = result.package_json orelse r.packageJSONForResolvedNodeModuleWithIgnoreMissingName(&result, true) orelse return error.MissingPackageJSON;
@@ -534,21 +536,21 @@ pub const Resolver = struct {
if (pair.framework.client.isEnabled()) {
var parts = [_]string{ dir, pair.framework.client.path };
- const abs = r.fs.abs(&parts);
+ const abs = FileSystem.instance.abs(&parts);
pair.framework.client.path = try r.allocator.dupe(u8, abs);
pair.framework.resolved = true;
}
if (pair.framework.server.isEnabled()) {
var parts = [_]string{ dir, pair.framework.server.path };
- const abs = r.fs.abs(&parts);
+ const abs = FileSystem.instance.abs(&parts);
pair.framework.server.path = try r.allocator.dupe(u8, abs);
pair.framework.resolved = true;
}
if (pair.framework.fallback.isEnabled()) {
var parts = [_]string{ dir, pair.framework.fallback.path };
- const abs = r.fs.abs(&parts);
+ const abs = FileSystem.instance.abs(&parts);
pair.framework.fallback.path = try r.allocator.dupe(u8, abs);
pair.framework.resolved = true;
}
@@ -557,15 +559,15 @@ pub const Resolver = struct {
const chosen_dir: string = brk: {
if (pair.router.possible_dirs.len > 0) {
for (pair.router.possible_dirs) |route_dir| {
- var parts = [_]string{ r.fs.top_level_dir, std.fs.path.sep_str, route_dir };
- const abs = r.fs.join(&parts);
+ var parts = [_]string{ FileSystem.instance.top_level_dir, std.fs.path.sep_str, route_dir };
+ const abs = FileSystem.instance.join(&parts);
// must end in trailing slash
break :brk (std.os.realpath(abs, &buf) catch continue);
}
return error.MissingRouteDir;
} else {
- var parts = [_]string{ r.fs.top_level_dir, std.fs.path.sep_str, pair.router.dir };
- const abs = r.fs.join(&parts);
+ var parts = [_]string{ FileSystem.instance.top_level_dir, std.fs.path.sep_str, pair.router.dir };
+ const abs = FileSystem.instance.join(&parts);
// must end in trailing slash
break :brk std.os.realpath(abs, &buf) catch return error.MissingRouteDir;
}
@@ -695,7 +697,7 @@ pub const Resolver = struct {
if (dir.getEntries()) |entries| {
if (entries.get(path.name.filename)) |query| {
- const symlink_path = query.entry.symlink(&r.fs.fs);
+ const symlink_path = query.entry.symlink(&FileSystem.instance.fs);
if (symlink_path.len > 0) {
path.setRealpath(symlink_path);
if (result.file_fd == 0) result.file_fd = query.entry.cache.fd;
@@ -707,12 +709,12 @@ pub const Resolver = struct {
var parts = [_]string{ dir.abs_real_path, query.entry.base() };
var buf: [std.fs.MAX_PATH_BYTES]u8 = undefined;
- var out = r.fs.absBuf(&parts, &buf);
+ var out = FileSystem.instance.absBuf(&parts, &buf);
if (query.entry.cache.fd == 0) {
buf[out.len] = 0;
const span = buf[0..out.len :0];
- var file = try std.fs.openFileAbsoluteZ(span, .{ .read = true });
+ var file = try FileSystem.openFileZ(span, .{ .read = true });
if (comptime !FeatureFlags.store_file_descriptors) {
out = try std.os.getFdPath(query.entry.cache.fd, &buf);
@@ -724,10 +726,9 @@ pub const Resolver = struct {
}
defer {
- if (r.fs.fs.needToCloseFiles()) {
+ if (FileSystem.instance.needToCloseFiles()) {
if (query.entry.cache.fd != 0) {
- var file = std.fs.File{ .handle = query.entry.cache.fd };
- file.close();
+ Fs.FileSystem.close(query.entry.cache.fd);
query.entry.cache.fd = 0;
}
}
@@ -841,7 +842,7 @@ pub const Resolver = struct {
if (check_relative) {
const parts = [_]string{ source_dir, import_path };
- const abs_path = r.fs.absBuf(&parts, &relative_abs_path_buf);
+ const abs_path = FileSystem.instance.absBuf(&parts, &relative_abs_path_buf);
if (r.opts.external.abs_paths.count() > 0 and r.opts.external.abs_paths.contains(abs_path)) {
// If the string literal in the source text is an absolute path and has
@@ -853,7 +854,7 @@ pub const Resolver = struct {
}
return Result{
- .path_pair = .{ .primary = Path.init(r.fs.dirname_store.append(@TypeOf(abs_path), abs_path) catch unreachable) },
+ .path_pair = .{ .primary = Path.init(FileSystem.instance.dirname_store.append(@TypeOf(abs_path), abs_path) catch unreachable) },
.is_external = true,
};
}
@@ -870,7 +871,7 @@ pub const Resolver = struct {
// Is the path disabled?
if (remap.len == 0) {
- var _path = Path.init(r.fs.dirname_store.append(string, abs_path) catch unreachable);
+ var _path = Path.init(FileSystem.instance.dirname_store.append(string, abs_path) catch unreachable);
_path.is_disabled = true;
return Result{
.path_pair = PathPair{
@@ -1172,7 +1173,7 @@ pub const Resolver = struct {
if (tsconfig.hasBaseURL()) {
const base = tsconfig.base_url;
const paths = [_]string{ base, import_path };
- const abs = r.fs.absBuf(&paths, &load_as_file_or_directory_via_tsconfig_base_path);
+ const abs = FileSystem.instance.absBuf(&paths, &load_as_file_or_directory_via_tsconfig_base_path);
if (r.loadAsFileOrDirectory(abs, kind)) |res| {
return res;
@@ -1189,7 +1190,7 @@ pub const Resolver = struct {
// don't ever want to search for "node_modules/node_modules"
if (dir_info.has_node_modules) {
var _paths = [_]string{ dir_info.abs_path, "node_modules", import_path };
- const abs_path = r.fs.absBuf(&_paths, &node_modules_check_buf);
+ const abs_path = FileSystem.instance.absBuf(&_paths, &node_modules_check_buf);
if (r.debug_logs) |*debug| {
debug.addNoteFmt("Checking for a package in the directory \"{s}\"", .{abs_path}) catch {};
}
@@ -1197,7 +1198,7 @@ pub const Resolver = struct {
if (esm_) |esm| {
const abs_package_path = brk: {
var parts = [_]string{ dir_info.abs_path, "node_modules", esm.name };
- break :brk r.fs.absBuf(&parts, &esm_absolute_package_path);
+ break :brk FileSystem.instance.absBuf(&parts, &esm_absolute_package_path);
};
if (r.dirInfoCached(abs_package_path) catch null) |pkg_dir_info| {
@@ -1230,7 +1231,7 @@ pub const Resolver = struct {
abs_package_path,
esm_resolution.path[1..],
};
- break :brk r.fs.absBuf(&parts, &esm_absolute_package_path_joined);
+ break :brk FileSystem.instance.absBuf(&parts, &esm_absolute_package_path_joined);
};
switch (esm_resolution.status) {
@@ -1248,7 +1249,7 @@ pub const Resolver = struct {
return null;
};
- if (entry_query.entry.kind(&r.fs.fs) == .dir) {
+ if (entry_query.entry.kind(&FileSystem.instance.fs) == .dir) {
esm_resolution.status = .UnsupportedDirectoryImport;
return null;
}
@@ -1256,7 +1257,7 @@ pub const Resolver = struct {
const absolute_out_path = brk: {
if (entry_query.entry.abs_path.isEmpty()) {
entry_query.entry.abs_path =
- PathString.init(r.fs.dirname_store.append(@TypeOf(abs_esm_path), abs_esm_path) catch unreachable);
+ PathString.init(FileSystem.instance.dirname_store.append(@TypeOf(abs_esm_path), abs_esm_path) catch unreachable);
}
break :brk entry_query.entry.abs_path.slice();
};
@@ -1313,7 +1314,7 @@ pub const Resolver = struct {
return r.loadNodeModules(import_path, kind, source_dir_info);
} else {
const paths = [_]string{ source_dir_info.abs_path, import_path };
- var resolved = r.fs.absBuf(&paths, &resolve_without_remapping_buf);
+ var resolved = FileSystem.instance.absBuf(&paths, &resolve_without_remapping_buf);
return r.loadAsFileOrDirectory(resolved, kind);
}
}
@@ -1324,7 +1325,7 @@ pub const Resolver = struct {
dirname_fd: StoredFileDescriptorType,
) !?*TSConfigJSON {
const entry = try r.caches.fs.readFile(
- r.fs,
+ &FileSystem.instance,
file,
dirname_fd,
false,
@@ -1341,14 +1342,14 @@ pub const Resolver = struct {
// this might leak
if (!std.fs.path.isAbsolute(result.base_url)) {
const paths = [_]string{ file_dir, result.base_url };
- result.base_url = r.fs.dirname_store.append(string, r.fs.absBuf(&paths, &tsconfig_base_url_buf)) catch unreachable;
+ result.base_url = FileSystem.instance.dirname_store.append(string, FileSystem.instance.absBuf(&paths, &tsconfig_base_url_buf)) catch unreachable;
}
}
if (result.paths.count() > 0 and (result.base_url_for_paths.len == 0 or !std.fs.path.isAbsolute(result.base_url_for_paths))) {
// this might leak
const paths = [_]string{ file_dir, result.base_url };
- result.base_url_for_paths = r.fs.dirname_store.append(string, r.fs.absBuf(&paths, &tsconfig_base_url_buf)) catch unreachable;
+ result.base_url_for_paths = FileSystem.instance.dirname_store.append(string, FileSystem.instance.absBuf(&paths, &tsconfig_base_url_buf)) catch unreachable;
}
return result;
@@ -1399,7 +1400,7 @@ pub const Resolver = struct {
defer r.mutex.unlock();
var _path = __path;
if (strings.eqlComptime(_path, "./") or strings.eqlComptime(_path, "."))
- _path = r.fs.top_level_dir;
+ _path = FileSystem.instance.top_level_dir;
const top_result = try r.dir_cache.getOrPut(_path);
if (top_result.status != .unknown) {
@@ -1424,7 +1425,7 @@ pub const Resolver = struct {
// we cannot just use "/"
// we will write to the buffer past the ptr len so it must be a non-const buffer
path[0..1];
- var rfs: *Fs.RealFS = &r.fs.fs;
+ var rfs = &FileSystem.instance;
rfs.entries_mutex.lock();
defer rfs.entries_mutex.unlock();
@@ -1475,8 +1476,8 @@ pub const Resolver = struct {
defer {
// Anything
- if (open_dir_count > 0 and r.fs.fs.needToCloseFiles()) {
- var open_dirs: []std.fs.Dir = _open_dirs[0..open_dir_count];
+ if (open_dir_count > 0 and FileSystem.instance.fs.needToCloseFiles()) {
+ var open_dirs: []Fs.Dir = _open_dirs[0..open_dir_count];
for (open_dirs) |*open_dir| {
open_dir.close();
}
@@ -1503,7 +1504,7 @@ pub const Resolver = struct {
defer top_parent = queue_top.result;
queue_slice.len -= 1;
- var _open_dir: anyerror!std.fs.Dir = undefined;
+ var _open_dir: anyerror!Fs.Dir = undefined;
if (queue_top.fd == 0) {
// This saves us N copies of .toPosixPath
@@ -1512,7 +1513,7 @@ pub const Resolver = struct {
path.ptr[queue_top.unsafe_path.len] = 0;
defer path.ptr[queue_top.unsafe_path.len] = prev_char;
var sentinel = path.ptr[0..queue_top.unsafe_path.len :0];
- _open_dir = std.fs.openDirAbsoluteZ(
+ _open_dir = FileSystem.openDirectory(
sentinel,
.{
.iterate = true,
@@ -1522,7 +1523,7 @@ pub const Resolver = struct {
// }
}
- const open_dir = if (queue_top.fd != 0) std.fs.Dir{ .fd = queue_top.fd } else (_open_dir catch |err| {
+ const open_dir = if (queue_top.fd != 0) Fs.Dir{ .fd = queue_top.fd } else (_open_dir catch |err| {
switch (err) {
error.EACCESS => {},
@@ -1580,9 +1581,9 @@ pub const Resolver = struct {
// Now that we've opened the topmost directory successfully, it's reasonable to store the slice.
if (path[path.len - 1] != std.fs.path.sep) {
var parts = [_]string{ path, std.fs.path.sep_str };
- _safe_path = try r.fs.dirname_store.append(@TypeOf(parts), parts);
+ _safe_path = try FileSystem.instance.dirname_store.append(@TypeOf(parts), parts);
} else {
- _safe_path = try r.fs.dirname_store.append(string, path);
+ _safe_path = try FileSystem.instance.dirname_store.append(string, path);
}
}
@@ -1612,7 +1613,7 @@ pub const Resolver = struct {
if (needs_iter) {
dir_entries_option = try rfs.entries.put(&cached_dir_entry_result, .{
- .entries = Fs.DirEntry.init(dir_path, r.fs.allocator),
+ .entries = Fs.DirEntry.init(dir_path, FileSystem.instance.allocator),
});
if (FeatureFlags.store_file_descriptors) {
@@ -1691,7 +1692,7 @@ pub const Resolver = struct {
if (!std.fs.path.isAbsolute(absolute_original_path)) {
const parts = [_]string{ abs_base_url, original_path };
- absolute_original_path = r.fs.absBuf(&parts, &tsconfig_path_abs_buf);
+ absolute_original_path = FileSystem.instance.absBuf(&parts, &tsconfig_path_abs_buf);
}
if (r.loadAsFileOrDirectory(absolute_original_path, kind)) |res| {
@@ -1753,12 +1754,12 @@ pub const Resolver = struct {
// 1. Normalize the base path
// so that "/Users/foo/project/", "../components/*" => "/Users/foo/components/""
- var prefix = r.fs.absBuf(&prefix_parts, &TemporaryBuffer.TSConfigMatchFullBuf2);
+ var prefix = FileSystem.instance.absBuf(&prefix_parts, &TemporaryBuffer.TSConfigMatchFullBuf2);
// 2. Join the new base path with the matched result
// so that "/Users/foo/components/", "/foo/bar" => /Users/foo/components/foo/bar
var parts = [_]string{ prefix, std.mem.trimLeft(u8, matched_text, "/"), std.mem.trimLeft(u8, longest_match.suffix, "/") };
- var absolute_original_path = r.fs.absBuf(
+ var absolute_original_path = FileSystem.instance.absBuf(
&parts,
&TemporaryBuffer.TSConfigMatchFullBuf,
);
@@ -1877,7 +1878,7 @@ pub const Resolver = struct {
}
// Normalize the path so we can compare against it without getting confused by "./"
- var cleaned = r.fs.normalizeBuf(&check_browser_map_buf, input_path);
+ var cleaned = FileSystem.instance.normalizeBuf(&check_browser_map_buf, input_path);
if (cleaned.len == 1 and cleaned[0] == '.') {
// No bundler supports remapping ".", so we don't either
@@ -1959,7 +1960,7 @@ pub const Resolver = struct {
// Is the path disabled?
if (remap.len == 0) {
const paths = [_]string{ path, field_rel_path };
- const new_path = r.fs.absAlloc(r.allocator, &paths) catch unreachable;
+ const new_path = FileSystem.instance.absAlloc(r.allocator, &paths) catch unreachable;
var _path = Path.init(new_path);
_path.is_disabled = true;
return MatchResult{
@@ -1975,7 +1976,7 @@ pub const Resolver = struct {
}
}
const _paths = [_]string{ path, field_rel_path };
- const field_abs_path = r.fs.absBuf(&_paths, &field_abs_path_buf);
+ const field_abs_path = FileSystem.instance.absBuf(&_paths, &field_abs_path_buf);
// Is this a file?
if (r.loadAsFile(field_abs_path, extension_order)) |result| {
@@ -2005,7 +2006,7 @@ pub const Resolver = struct {
}
pub fn loadAsIndex(r: *ThisResolver, dir_info: *DirInfo, path: string, extension_order: []const string) ?MatchResult {
- var rfs = &r.fs.fs;
+ var rfs = &FileSystem.instance.fs;
// Try the "index" file with extensions
for (extension_order) |ext| {
var base = TemporaryBuffer.ExtensionPathBuf[0 .. "index".len + ext.len];
@@ -2018,9 +2019,9 @@ pub const Resolver = struct {
const out_buf = brk: {
if (lookup.entry.abs_path.isEmpty()) {
const parts = [_]string{ path, base };
- const out_buf_ = r.fs.absBuf(&parts, &index_buf);
+ const out_buf_ = FileSystem.instance.absBuf(&parts, &index_buf);
lookup.entry.abs_path =
- PathString.init(r.fs.dirname_store.append(@TypeOf(out_buf_), out_buf_) catch unreachable);
+ PathString.init(FileSystem.instance.dirname_store.append(@TypeOf(out_buf_), out_buf_) catch unreachable);
}
break :brk lookup.entry.abs_path.slice();
};
@@ -2079,7 +2080,7 @@ pub const Resolver = struct {
// Is the path disabled?
if (remap.len == 0) {
const paths = [_]string{ path, field_rel_path };
- const new_path = r.fs.absBuf(&paths, &remap_path_buf);
+ const new_path = FileSystem.instance.absBuf(&paths, &remap_path_buf);
var _path = Path.init(new_path);
_path.is_disabled = true;
return MatchResult{
@@ -2091,7 +2092,7 @@ pub const Resolver = struct {
}
const new_paths = [_]string{ path, remap };
- const remapped_abs = r.fs.absBuf(&new_paths, &remap_path_buf);
+ const remapped_abs = FileSystem.instance.absBuf(&new_paths, &remap_path_buf);
// Is this a file
if (r.loadAsFile(remapped_abs, extension_order)) |file_result| {
@@ -2261,7 +2262,7 @@ pub const Resolver = struct {
}
pub fn loadAsFile(r: *ThisResolver, path: string, extension_order: []const string) ?LoadResult {
- var rfs: *Fs.RealFS = &r.fs.fs;
+ var rfs: *Fs.RealFS = &FileSystem.instance.fs;
if (r.debug_logs) |*debug| {
debug.addNoteFmt("Attempting to load \"{s}\" as a file", .{path}) catch {};
@@ -2275,7 +2276,7 @@ pub const Resolver = struct {
const dir_path = Dirname.dirname(path);
- const dir_entry: *Fs.EntriesOption = rfs.readDirectory(
+ const dir_entry: *Fs.EntriesOption = FileSystem.instance.readDirectory(
dir_path,
null,
) catch {
@@ -2316,7 +2317,7 @@ pub const Resolver = struct {
const abs_path = brk: {
if (query.entry.abs_path.isEmpty()) {
const abs_path_parts = [_]string{ query.entry.dir, query.entry.base() };
- query.entry.abs_path = PathString.init(r.fs.dirname_store.append(string, r.fs.absBuf(&abs_path_parts, &load_as_file_buf)) catch unreachable);
+ query.entry.abs_path = PathString.init(FileSystem.instance.dirname_store.append(string, FileSystem.instance.absBuf(&abs_path_parts, &load_as_file_buf)) catch unreachable);
}
break :brk query.entry.abs_path.slice();
@@ -2352,7 +2353,7 @@ pub const Resolver = struct {
return LoadResult{
.path = brk: {
query.entry.abs_path = if (query.entry.abs_path.isEmpty())
- PathString.init(r.fs.dirname_store.append(@TypeOf(buffer), buffer) catch unreachable)
+ PathString.init(FileSystem.instance.dirname_store.append(@TypeOf(buffer), buffer) catch unreachable)
else
query.entry.abs_path;
@@ -2405,7 +2406,7 @@ pub const Resolver = struct {
if (query.entry.abs_path.isEmpty()) {
// Should already have a trailing slash so we shouldn't need to worry.
var parts = [_]string{ query.entry.dir, buffer };
- query.entry.abs_path = PathString.init(r.fs.filename_store.append(@TypeOf(parts), parts) catch unreachable);
+ query.entry.abs_path = PathString.init(FileSystem.instance.filename_store.append(@TypeOf(parts), parts) catch unreachable);
}
break :brk query.entry.abs_path.slice();
@@ -2451,7 +2452,7 @@ pub const Resolver = struct {
) anyerror!void {
var result = _result;
- var rfs: *Fs.RealFS = &r.fs.fs;
+ var rfs: *Fs.RealFS = &FileSystem.instance.fs;
var entries = _entries.entries;
info.* = DirInfo{
@@ -2501,7 +2502,7 @@ pub const Resolver = struct {
} else if (parent.?.abs_real_path.len > 0) {
// this might leak a little i'm not sure
const parts = [_]string{ parent.?.abs_real_path, base };
- symlink = r.fs.dirname_store.append(string, r.fs.absBuf(&parts, &dir_info_uncached_filename_buf)) catch unreachable;
+ symlink = FileSystem.instance.dirname_store.append(string, FileSystem.instance.absBuf(&parts, &dir_info_uncached_filename_buf)) catch unreachable;
if (r.debug_logs) |*logs| {
try logs.addNote(std.fmt.allocPrint(r.allocator, "Resolved symlink \"{s}\" to \"{s}\"", .{ path, symlink }) catch unreachable);
@@ -2545,7 +2546,7 @@ pub const Resolver = struct {
if (entry.kind(rfs) == .file) {
const parts = [_]string{ path, "tsconfig.json" };
- tsconfig_path = r.fs.absBuf(&parts, &dir_info_uncached_filename_buf);
+ tsconfig_path = FileSystem.instance.absBuf(&parts, &dir_info_uncached_filename_buf);
}
}
if (tsconfig_path == null) {
@@ -2553,7 +2554,7 @@ pub const Resolver = struct {
const entry = lookup.entry;
if (entry.kind(rfs) == .file) {
const parts = [_]string{ path, "jsconfig.json" };
- tsconfig_path = r.fs.absBuf(&parts, &dir_info_uncached_filename_buf);
+ tsconfig_path = FileSystem.instance.absBuf(&parts, &dir_info_uncached_filename_buf);
}
}
}