diff --git a/source/dub/compilers/utils.d b/source/dub/compilers/utils.d index 20de0de..aac768a 100644 --- a/source/dub/compilers/utils.d +++ b/source/dub/compilers/utils.d @@ -357,8 +357,7 @@ }.format(probeBeginMark, probeEndMark, platformCheck, archCheck, compilerCheck); auto path = getTempFile("dub_platform_probe", ".d"); - auto fil = openFile(path, FileMode.createTrunc); - fil.write(probe); + writeFile(path, probe); return path; } diff --git a/source/dub/generators/visuald.d b/source/dub/generators/visuald.d index 3e90d6a..9b86ef9 100644 --- a/source/dub/generators/visuald.d +++ b/source/dub/generators/visuald.d @@ -119,11 +119,7 @@ // Writing solution file logDebug("About to write to .sln file with %s bytes", to!string(ret.data.length)); - auto sln = openFile(solutionFileName(), FileMode.createTrunc); - scope(exit) sln.close(); - sln.put(ret.data); - sln.flush(); - + NativePath(solutionFileName()).writeFile(ret.data); logInfo("Generated", Color.green, "%s (solution)", solutionFileName()); } @@ -244,10 +240,7 @@ ret.put("\n \n"); logDebug("About to write to '%s.visualdproj' file %s bytes", getPackageFileName(packname), ret.data.length); - auto proj = openFile(projFileName(packname), FileMode.createTrunc); - scope(exit) proj.close(); - proj.put(ret.data); - proj.flush(); + projFileName(packname).writeFile(ret.data); } void generateProjectConfiguration(Appender!(char[]) ret, string pack, string type, GeneratorSettings settings, in TargetInfo[string] targets) diff --git a/source/dub/internal/utils.d b/source/dub/internal/utils.d index 345996c..11d6ccd 100644 --- a/source/dub/internal/utils.d +++ b/source/dub/internal/utils.d @@ -110,7 +110,7 @@ import std.random; auto fname = p ~ format("__dub_write_test_%08X", uniform(0, uint.max)); if (create_if_missing && !exists(p.toNativeString())) mkdirRecurse(p.toNativeString()); - try openFile(fname, FileMode.createTrunc).close(); + try writeFile(fname, "Canary"); catch (Exception) return false; remove(fname.toNativeString()); return true; @@ -118,9 +118,7 @@ Json jsonFromFile(NativePath file, bool silent_fail = false) { if( silent_fail && !existsFile(file) ) return Json.emptyObject; - auto f = openFile(file.toNativeString(), FileMode.read); - scope(exit) f.close(); - auto text = stripUTF8Bom(cast(string)f.readAll()); + auto text = stripUTF8Bom(cast(string)readFile(file)); return parseJsonString(text, file.toNativeString()); } @@ -139,10 +137,7 @@ import std.zip : ZipArchive, ArchiveMember; import dub.package_ : packageInfoFiles; - auto f = openFile(zip, FileMode.read); - ubyte[] b = new ubyte[cast(size_t)f.size]; - f.rawRead(b); - f.close(); + auto b = readFile(zip); auto archive = new ZipArchive(b); alias PSegment = typeof (NativePath.init.head); foreach (ArchiveMember am; archive.directory) { @@ -159,9 +154,9 @@ void writeJsonFile(NativePath path, Json json) { - auto f = openFile(path, FileMode.createTrunc); - scope(exit) f.close(); - f.writePrettyJsonString(json); + auto app = appender!string(); + app.writePrettyJsonString(json); + writeFile(path, app.data); } /// Performs a write->delete->rename sequence to atomically "overwrite" the destination file @@ -169,13 +164,9 @@ { import std.random : uniform; auto tmppath = path.parentPath ~ format("%s.%s.tmp", path.head, uniform(0, int.max)); - auto f = openFile(tmppath, FileMode.createTrunc); - scope (failure) { - f.close(); - removeFile(tmppath); - } - f.writePrettyJsonString(json); - f.close(); + auto app = appender!string(); + app.writePrettyJsonString(json); + writeFile(tmppath, app.data); if (existsFile(path)) removeFile(path); moveFile(tmppath, path); } diff --git a/source/dub/internal/vibecompat/core/file.d b/source/dub/internal/vibecompat/core/file.d index a47a849..bfe7775 100644 --- a/source/dub/internal/vibecompat/core/file.d +++ b/source/dub/internal/vibecompat/core/file.d @@ -22,57 +22,17 @@ import std.utf; -/* Add output range support to File -*/ -struct RangeFile { -@safe: - std.stdio.File file; - - void put(scope const ubyte[] bytes) @trusted { file.rawWrite(bytes); } - void put(scope const char[] str) { put(cast(const(ubyte)[])str); } - void put(char ch) @trusted { put((&ch)[0 .. 1]); } - void put(dchar ch) { char[4] chars; put(chars[0 .. encode(chars, ch)]); } - - ubyte[] readAll() - { - auto sz = this.size; - enforce(sz <= size_t.max, "File is too big to read to memory."); - () @trusted { file.seek(0, SEEK_SET); } (); - auto ret = new ubyte[cast(size_t)sz]; - rawRead(ret); - return ret; - } - - void rawRead(ubyte[] dst) @trusted { enforce(file.rawRead(dst).length == dst.length, "Failed to readall bytes from file."); } - void write(string str) { put(str); } - void close() @trusted { file.close(); } - void flush() @trusted { file.flush(); } - @property ulong size() @trusted { return file.size; } -} - - -/** - Opens a file stream with the specified mode. -*/ -RangeFile openFile(NativePath path, FileMode mode = FileMode.read) +/// Writes `buffer` to a file +public void writeFile(NativePath path, const void[] buffer) { - string fmode; - final switch(mode){ - case FileMode.read: fmode = "rb"; break; - case FileMode.readWrite: fmode = "r+b"; break; - case FileMode.createTrunc: fmode = "wb"; break; - case FileMode.append: fmode = "ab"; break; - } - auto ret = std.stdio.File(path.toNativeString(), fmode); - assert(ret.isOpen); - return RangeFile(ret); -} -/// ditto -RangeFile openFile(string path, FileMode mode = FileMode.read) -{ - return openFile(NativePath(path), mode); + std.file.write(path.toNativeString(), buffer); } +/// Returns the content of a file +public ubyte[] readFile(NativePath path) +{ + return cast(ubyte[]) std.file.read(path.toNativeString()); +} /** Moves or renames a file. diff --git a/source/dub/package_.d b/source/dub/package_.d index ce7d5a4..3303086 100644 --- a/source/dub/package_.d +++ b/source/dub/package_.d @@ -306,9 +306,7 @@ void storeInfo(NativePath path) const { auto filename = path ~ defaultPackageFilename; - auto dstFile = openFile(filename.toNativeString(), FileMode.createTrunc); - scope(exit) dstFile.close(); - dstFile.writePrettyJsonString(m_info.toJson()); + writeJsonFile(filename, m_info.toJson()); } /// Get the metadata cache for this package diff --git a/source/dub/packagemanager.d b/source/dub/packagemanager.d index 3fcdbea..7ceedca 100644 --- a/source/dub/packagemanager.d +++ b/source/dub/packagemanager.d @@ -710,9 +710,7 @@ ZipArchive archive; { logDebug("Opening file %s", src); - auto f = openFile(src, FileMode.read); - scope(exit) f.close(); - archive = new ZipArchive(f.readAll()); + archive = new ZipArchive(readFile(src)); } logDebug("Extracting from zip."); @@ -779,11 +777,7 @@ } } - { - auto dstFile = openFile(dst_path, FileMode.createTrunc); - scope(exit) dstFile.close(); - dstFile.put(archive.expand(a)); - } + writeFile(dst_path, archive.expand(a)); setAttributes(dst_path.toNativeString(), a); symlink_exit: ++countFiles; @@ -974,7 +968,7 @@ logDebug("Hashed directory name %s", NativePath(file.name).head); } else { - hash.put(openFile(NativePath(file.name)).readAll()); + hash.put(cast(ubyte[]) readFile(NativePath(file.name))); logDebug("Hashed file contents from %s", NativePath(file.name).head); } } diff --git a/source/dub/project.d b/source/dub/project.d index edc354f..87487db 100644 --- a/source/dub/project.d +++ b/source/dub/project.d @@ -335,13 +335,11 @@ import std.file : mkdirRecurse; mkdirRecurse(mainfile.parentPath.toNativeString()); - auto fil = openFile(mainfile, FileMode.createTrunc); - scope(exit) fil.close(); const runnerCode = custommodname.length ? format("import %s;", custommodname) : DefaultTestRunnerCode; const content = TestRunnerTemplate.format( import_modules, import_modules, runnerCode); - fil.write(content); + writeFile(mainfile, content); } rootPackage.recipe.configurations ~= ConfigurationInfo(config, tcinfo); @@ -1820,27 +1818,27 @@ void save(NativePath path) { Json json = serialize(); - auto file = openFile(path, FileMode.createTrunc); - scope(exit) file.close(); + auto result = appender!string(); assert(json.type == Json.Type.object); assert(json.length == 2); assert(json["versions"].type != Json.Type.undefined); - file.write("{\n\t\"fileVersion\": "); - file.writeJsonString(json["fileVersion"]); - file.write(",\n\t\"versions\": {"); + result.put("{\n\t\"fileVersion\": "); + result.writeJsonString(json["fileVersion"]); + result.put(",\n\t\"versions\": {"); auto vers = json["versions"].get!(Json[string]); bool first = true; foreach (k; vers.byKey.array.sort()) { - if (!first) file.write(","); + if (!first) result.put(","); else first = false; - file.write("\n\t\t"); - file.writeJsonString(Json(k)); - file.write(": "); - file.writeJsonString(vers[k]); + result.put("\n\t\t"); + result.writeJsonString(Json(k)); + result.put(": "); + result.writeJsonString(vers[k]); } - file.write("\n\t}\n}\n"); + result.put("\n\t}\n}\n"); + path.writeFile(result.data); m_dirty = false; m_bare = false; } diff --git a/source/dub/recipe/io.d b/source/dub/recipe/io.d index 67d0199..e0d647d 100644 --- a/source/dub/recipe/io.d +++ b/source/dub/recipe/io.d @@ -9,6 +9,7 @@ import dub.recipe.packagerecipe; import dub.internal.logging; +import dub.internal.vibecompat.core.file; import dub.internal.vibecompat.inet.path; import configy.Read; @@ -35,16 +36,8 @@ NativePath filename, string parent_name = null, StrictMode mode = StrictMode.Ignore) { import dub.internal.utils : stripUTF8Bom; - import dub.internal.vibecompat.core.file : openFile, FileMode; - string text; - - { - auto f = openFile(filename.toNativeString(), FileMode.read); - scope(exit) f.close(); - text = stripUTF8Bom(cast(string)f.readAll()); - } - + string text = stripUTF8Bom(cast(string)readFile(filename)); return parsePackageRecipe(text, filename.toNativeString(), parent_name, null, mode); } @@ -209,16 +202,16 @@ */ void writePackageRecipe(string filename, const scope ref PackageRecipe recipe) { - import dub.internal.vibecompat.core.file : openFile, FileMode; - auto f = openFile(filename, FileMode.createTrunc); - scope(exit) f.close(); - serializePackageRecipe(f, recipe, filename); + writePackageRecipe(NativePath(filename), recipe); } /// ditto void writePackageRecipe(NativePath filename, const scope ref PackageRecipe recipe) { - writePackageRecipe(filename.toNativeString, recipe); + import std.array; + auto app = appender!string(); + serializePackageRecipe(app, recipe, filename.toNativeString()); + writeFile(filename, app.data); } /** Converts a package recipe to its textual representation.