Compare commits

...

4 Commits

Author SHA1 Message Date
Jarred Sumner
18ba2096e6 Implement a filesystem for tests 2021-10-08 23:25:56 -07:00
Jarred Sumner
7e2c297013 Wrap filesystem access 2021-10-08 21:10:40 -07:00
Jarred Sumner
f103018842 Flatten FS namespace to better facilitate testing 2021-10-08 17:25:31 -07:00
Jarred Sumner
dbedfa3d06 Ensure Ref is always 64 bits 2021-10-08 17:24:39 -07:00
18 changed files with 1698 additions and 1077 deletions

View File

@@ -34,10 +34,13 @@ pub const RefHashCtx = struct {
};
pub const Ref = packed struct {
const Padding = std.meta.Int(.unsigned, 64 - ((@bitSizeOf(Int) * 2) + 1));
source_index: Int = std.math.maxInt(Ref.Int),
inner_index: Int = 0,
is_source_contents_slice: bool = false,
_padding: Padding = 0,
// 2 bits of padding for whatever is the parent
pub const Int = u30;
pub const None = Ref{
@@ -93,3 +96,7 @@ pub inline fn debugl(
) void {
// Output.print("{s}\n", .{fmt});
}
comptime {
if (@bitSizeOf(Ref) != 64) @compileError("Ref should be 64 bits exactly");
}

View File

@@ -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
@@ -233,14 +236,14 @@ pub const Bundler = struct {
switch (this.options.env.behavior) {
.prefix, .load_all => {
// Step 1. Load the project root.
var dir: *Fs.FileSystem.DirEntry = ((this.resolver.readDirInfo(this.fs.top_level_dir) catch return) orelse return).getEntries() orelse return;
var dir: *Fs.DirEntry = ((this.resolver.readDirInfo(this.fs.top_level_dir) catch return) orelse return).getEntries() orelse return;
// 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();
@@ -732,7 +735,7 @@ pub const Bundler = struct {
std.hash.Wyhash.hash(@intCast(usize, std.time.milliTimestamp()) % std.math.maxInt(u32), std.mem.span(destination)),
);
var tmpfile = Fs.FileSystem.RealFS.Tmpfile{};
var tmpfile = Fs.RealFS.Tmpfile{};
try tmpfile.create(&bundler.fs.fs, tmpname);
errdefer tmpfile.closeAndDelete(tmpname);
@@ -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),
};
}
}
@@ -2971,7 +2970,7 @@ pub const Transformer = struct {
var arena: std.heap.ArenaAllocator = undefined;
const use_arenas = opts.entry_points.len > 8;
var ulimit: usize = Fs.FileSystem.RealFS.adjustUlimit() catch unreachable;
var ulimit: usize = Fs.RealFS.adjustUlimit() catch unreachable;
var care_about_closing_files = !(FeatureFlags.store_file_descriptors and opts.entry_points.len * 2 < ulimit);
var transformer = Transformer{
@@ -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 => {

View File

@@ -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;
@@ -18,7 +18,7 @@ pub const FsCacheEntry = struct {
contents: string,
fd: StoredFileDescriptorType = 0,
// Null means its not usable
mod_key: ?fs.FileSystem.Implementation.ModKey = null,
// mod_key: ?fs.FileSystem.Implementation.ModKey = null,
pub fn deinit(entry: *FsCacheEntry, allocator: *std.mem.Allocator) void {
if (entry.contents.len > 0) {
@@ -58,84 +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 });
}
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);
}
}
// If the file's modification key hasn't changed since it was cached, assume
// the contents of the file are also the same and skip reading the file.
var mod_key: ?fs.FileSystem.Implementation.ModKey = rfs.modKeyWithFile(path, file_handle) catch |err| handler: {
switch (err) {
error.FileNotFound, error.AccessDenied => {
return err;
},
else => {
if (isDebug) {
Output.printError("modkey error: {s}", .{@errorName(err)});
}
break :handler null;
},
}
};
var file: fs.File = undefined;
if (mod_key) |modk| {
file = rfs.readFileWithHandle(path, modk.size, file_handle, true, shared) catch |err| {
if (isDebug) {
Output.printError("{s}: readFile error -- {s}", .{ path, @errorName(err) });
}
return err;
};
} else {
file = rfs.readFileWithHandle(path, null, file_handle, true, shared) catch |err| {
if (isDebug) {
Output.printError("{s}: readFile error -- {s}", .{ path, @errorName(err) });
}
return err;
};
}
return Entry{
.contents = file.contents,
.mod_key = mod_key,
.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 },
@@ -146,53 +107,25 @@ pub const Fs = struct {
}
};
} else {
file_handle = try std.fs.openFileAbsolute(path, .{ .read = true });
}
}
defer {
if (rfs.needToCloseFiles() and _file_handle == null) {
file_handle.close();
}
}
// If the file's modification key hasn't changed since it was cached, assume
// the contents of the file are also the same and skip reading the file.
var mod_key: ?fs.FileSystem.Implementation.ModKey = rfs.modKeyWithFile(path, file_handle) catch |err| handler: {
switch (err) {
error.FileNotFound, error.AccessDenied => {
return err;
},
else => {
if (isDebug) {
Output.printError("modkey error: {s}", .{@errorName(err)});
}
break :handler null;
},
break :brk try FileSystem.openFileAbsolute(path, .{ .read = true });
}
};
var file: fs.File = undefined;
if (mod_key) |modk| {
file = rfs.readFileWithHandle(path, modk.size, file_handle, use_shared_buffer, &c.shared_buffer) catch |err| {
if (isDebug) {
Output.printError("{s}: readFile error -- {s}", .{ path, @errorName(err) });
}
return err;
};
} else {
file = rfs.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;
};
defer {
if (fs.needToCloseFiles() and _file_handle == null) {
FileSystem.close(file_handle);
}
}
return Entry{
.contents = file.contents,
.mod_key = mod_key,
.fd = if (FeatureFlags.store_file_descriptors) file_handle.handle else 0,
.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 else 0,
};
}
};

View File

@@ -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"),

View File

@@ -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();
}

View File

@@ -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.FileSystem.RealFS,
dir: *Fs.FileSystem.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.FileSystem.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

View File

@@ -74,6 +74,6 @@ pub const is_macro_enabled = true;
// useful for debugging the macro's JSX transform
pub const force_macro = false;
pub const include_filename_in_jsx = false;
pub const include_filename_in_jsx = true;
pub const verbose_analytics = false;

2236
src/fs.zig

File diff suppressed because it is too large Load Diff

View File

@@ -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,15 +380,15 @@ 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,
absolute_path = file.getPath(
&Bundler.tmp_buildfile_buf,
) catch return null;
@@ -399,7 +400,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{
@@ -452,6 +453,10 @@ pub const RequestContext = struct {
ctx.appendHeader("Content-Length", content_length_header_buf[0..std.fmt.formatIntBuf(&content_length_header_buf, length, 10, .upper, .{})]);
}
if (ctx.header("Cookie")) |cookie| {
ctx.appendHeader("Set-Cookie", cookie.value);
}
try ctx.flushHeaders();
}
@@ -2234,22 +2239,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);
};
@@ -2504,7 +2508,7 @@ pub const Server = struct {
defer ctx.watcher.flushEvictions();
defer Output.flush();
var rfs: *Fs.FileSystem.RealFS = &ctx.bundler.fs.fs;
var rfs: *Fs.RealFS = &ctx.bundler.fs.fs;
// It's important that this function does not do any memory allocations
// If this blocks, it can cause cascading bad things to happen
@@ -2562,7 +2566,7 @@ pub const Server = struct {
}
},
.directory => {
rfs.bustEntriesCache(file_path);
FileSystem.instance.bustEntriesCache(file_path);
ctx.bundler.resolver.dir_cache.remove(file_path);
// if (event.op.delete or event.op.rename)
@@ -2579,7 +2583,7 @@ pub const Server = struct {
}
fn run(server: *Server, comptime features: ConnectionFeatures) !void {
_ = Fs.FileSystem.RealFS.adjustUlimit() catch {};
_ = Fs.RealFS.adjustUlimit() catch {};
RequestContext.WebsocketHandler.open_websockets = @TypeOf(
RequestContext.WebsocketHandler.open_websockets,
).init(server.allocator);

View File

@@ -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);
};

View File

@@ -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);
}

View File

@@ -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,9 +95,8 @@ 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 modkey = try Fs.FileSystem.RealFS.ModKey.generate(&this.fs.fs, file_path.text, file);
var file = try FileSystem.openFileZ(file_path.textZ(), .{ .read = true });
var modkey = try Fs.ModKey.generate(file_path.text, file);
const hash_name = try modkey.hashName(file_path.name.base);
if (Bundler.isCacheEnabled) {
@@ -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();
}

View File

@@ -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{

View File

@@ -53,7 +53,7 @@ pub const NodeModuleBundle = struct {
return this.package_name_map.contains("react-refresh");
}
pub inline fn fetchByteCodeCache(this: *NodeModuleBundle, basename: string, fs: *Fs.FileSystem.RealFS) ?StoredFileDescriptorType {
pub inline fn fetchByteCodeCache(this: *NodeModuleBundle, basename: string, fs: *Fs.RealFS) ?StoredFileDescriptorType {
return this.bytecode_cache_fetcher.fetch(basename, fs);
}
@@ -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());

View File

@@ -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);
}
}
}
@@ -1218,8 +1221,8 @@ pub const BundleOptions = struct {
if (!static_dir_set) {
chosen_dir = choice: {
if (fs.fs.readDirectory(fs.top_level_dir, null)) |dir_| {
const dir: *const Fs.FileSystem.RealFS.EntriesOption = dir_;
if (fs.readDirectory(fs.top_level_dir, null)) |dir_| {
const dir: *const Fs.EntriesOption = dir_;
switch (dir.*) {
.entries => {
if (dir.entries.getComptimeQuery("public")) |q| {
@@ -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,

View File

@@ -45,7 +45,7 @@ pub fn getFileDescriptor(dirinfo: *const DirInfo) StoredFileDescriptorType {
}
}
pub fn getEntries(dirinfo: *const DirInfo) ?*Fs.FileSystem.DirEntry {
pub fn getEntries(dirinfo: *const DirInfo) ?*Fs.DirEntry {
var entries_ptr = Fs.FileSystem.instance.fs.entries.atIndex(dirinfo.entries) orelse return null;
switch (entries_ptr.*) {
.entries => |entr| {
@@ -57,7 +57,7 @@ pub fn getEntries(dirinfo: *const DirInfo) ?*Fs.FileSystem.DirEntry {
}
}
pub fn getEntriesConst(dirinfo: *const DirInfo) ?*const Fs.FileSystem.DirEntry {
pub fn getEntriesConst(dirinfo: *const DirInfo) ?*const Fs.DirEntry {
const entries_ptr = Fs.FileSystem.instance.fs.entries.atIndex(dirinfo.entries) orelse return null;
switch (entries_ptr.*) {
.entries => |entr| {

View File

@@ -27,6 +27,9 @@ const allocators = @import("../allocators.zig");
const Path = Fs.Path;
const NodeModuleBundle = @import("../node_module_bundle.zig").NodeModuleBundle;
const FileSystem = Fs.FileSystem;
const File = Fs.File;
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, "..");
@@ -84,7 +87,7 @@ pub const Result = struct {
// This is true when the package was loaded from within the node_modules directory.
is_from_node_modules: bool = false,
diff_case: ?Fs.FileSystem.Entry.Lookup.DifferentCase = null,
diff_case: ?Fs.Entry.Lookup.DifferentCase = null,
// If present, any ES6 imports to this file can be considered to have no side
// effects. This means they should be removed if unused.
@@ -203,7 +206,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 +291,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;
@@ -309,13 +312,13 @@ pub const MatchResult = struct {
file_fd: StoredFileDescriptorType = 0,
is_node_module: bool = false,
package_json: ?*PackageJSON = null,
diff_case: ?Fs.FileSystem.Entry.Lookup.DifferentCase = null,
diff_case: ?Fs.Entry.Lookup.DifferentCase = null,
dir_info: ?*DirInfo = null,
};
pub const LoadResult = struct {
path: string,
diff_case: ?Fs.FileSystem.Entry.Lookup.DifferentCase,
diff_case: ?Fs.Entry.Lookup.DifferentCase,
dirname_fd: StoredFileDescriptorType = 0,
file_fd: StoredFileDescriptorType = 0,
dir_info: ?*DirInfo = null,
@@ -519,7 +522,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 +537,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,17 +560,17 @@ 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);
break :brk (File.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;
break :brk File.realpath(abs, &buf) catch return error.MissingRouteDir;
}
};
@@ -695,7 +698,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 +710,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 +727,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 +843,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 +855,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 +872,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 +1174,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 +1191,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 +1199,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 +1232,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 +1250,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 +1258,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 +1315,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 +1326,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 +1343,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 +1401,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 +1426,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.FileSystem.RealFS = &r.fs.fs;
var rfs = &FileSystem.instance;
rfs.entries_mutex.lock();
defer rfs.entries_mutex.unlock();
@@ -1475,8 +1477,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 +1505,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 +1514,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 +1524,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 +1582,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);
}
}
@@ -1600,7 +1602,7 @@ pub const Resolver = struct {
var cached_dir_entry_result = rfs.entries.getOrPut(dir_path) catch unreachable;
var dir_entries_option: *Fs.FileSystem.RealFS.EntriesOption = undefined;
var dir_entries_option: *Fs.EntriesOption = undefined;
var needs_iter: bool = true;
if (rfs.entries.atIndex(cached_dir_entry_result.index)) |cached_entry| {
@@ -1612,7 +1614,7 @@ pub const Resolver = struct {
if (needs_iter) {
dir_entries_option = try rfs.entries.put(&cached_dir_entry_result, .{
.entries = Fs.FileSystem.DirEntry.init(dir_path, r.fs.allocator),
.entries = Fs.DirEntry.init(dir_path, FileSystem.instance.allocator),
});
if (FeatureFlags.store_file_descriptors) {
@@ -1691,7 +1693,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 +1755,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 +1879,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 +1961,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 +1977,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 +2007,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 +2020,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 +2081,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 +2093,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 +2263,7 @@ pub const Resolver = struct {
}
pub fn loadAsFile(r: *ThisResolver, path: string, extension_order: []const string) ?LoadResult {
var rfs: *Fs.FileSystem.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,14 +2277,14 @@ pub const Resolver = struct {
const dir_path = Dirname.dirname(path);
const dir_entry: *Fs.FileSystem.RealFS.EntriesOption = rfs.readDirectory(
const dir_entry: *Fs.EntriesOption = FileSystem.instance.readDirectory(
dir_path,
null,
) catch {
return null;
};
if (@as(Fs.FileSystem.RealFS.EntriesOption.Tag, dir_entry.*) == .err) {
if (@as(Fs.EntriesOption.Tag, dir_entry.*) == .err) {
if (dir_entry.err.original_err != error.ENOENT) {
r.log.addErrorFmt(
null,
@@ -2316,7 +2318,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 +2354,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 +2407,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();
@@ -2442,7 +2444,7 @@ pub const Resolver = struct {
r: *ThisResolver,
info: *DirInfo,
path: string,
_entries: *Fs.FileSystem.RealFS.EntriesOption,
_entries: *Fs.EntriesOption,
_result: allocators.Result,
dir_entry_index: allocators.IndexType,
parent: ?*DirInfo,
@@ -2451,7 +2453,7 @@ pub const Resolver = struct {
) anyerror!void {
var result = _result;
var rfs: *Fs.FileSystem.RealFS = &r.fs.fs;
var rfs: *Fs.RealFS = &FileSystem.instance.fs;
var entries = _entries.entries;
info.* = DirInfo{
@@ -2501,7 +2503,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 +2547,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 +2555,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);
}
}
}

View File

@@ -232,7 +232,7 @@ pub const Route = struct {
hash: u32,
children: Ptr = Ptr{},
parent: u16 = top_level_parent,
entry: *Fs.FileSystem.Entry,
entry: *Fs.Entry,
full_hash: u32,
@@ -241,7 +241,7 @@ pub const Route = struct {
pub const List = std.MultiArrayList(Route);
pub const Ptr = TinyPtr;
pub fn parse(base: string, dir: string, extname: string, entry: *Fs.FileSystem.Entry) Route {
pub fn parse(base: string, dir: string, extname: string, entry: *Fs.Entry) Route {
const ensure_slash = if (dir.len > 0 and dir[dir.len - 1] != '/') "/" else "";
var parts = [3]string{ dir, ensure_slash, base };