diff options
author | 2021-10-08 21:10:40 -0700 | |
---|---|---|
committer | 2021-10-08 21:10:40 -0700 | |
commit | 7e2c297013e89e26da2db27d7edab886761c203e (patch) | |
tree | 22f23c5d8a2e5d86b7f3016ef0f42ec0079226af /src | |
parent | f10301884246003573a3aff123e5921e927379a5 (diff) | |
download | bun-7e2c297013e89e26da2db27d7edab886761c203e.tar.gz bun-7e2c297013e89e26da2db27d7edab886761c203e.tar.zst bun-7e2c297013e89e26da2db27d7edab886761c203e.zip |
Wrap filesystem access
Diffstat (limited to 'src')
-rw-r--r-- | src/bundler.zig | 93 | ||||
-rw-r--r-- | src/cache.zig | 79 | ||||
-rw-r--r-- | src/cli.zig | 20 | ||||
-rw-r--r-- | src/css_scanner.zig | 6 | ||||
-rw-r--r-- | src/env_loader.zig | 19 | ||||
-rw-r--r-- | src/fs.zig | 536 | ||||
-rw-r--r-- | src/http.zig | 29 | ||||
-rw-r--r-- | src/javascript/jsc/javascript.zig | 4 | ||||
-rw-r--r-- | src/js_printer.zig | 6 | ||||
-rw-r--r-- | src/linker.zig | 6 | ||||
-rw-r--r-- | src/logger.zig | 4 | ||||
-rw-r--r-- | src/node_module_bundle.zig | 2 | ||||
-rw-r--r-- | src/options.zig | 41 | ||||
-rw-r--r-- | src/resolver/resolver.zig | 119 |
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); } } } |