mirror of
https://github.com/apple/swift.git
synced 2025-12-21 12:14:44 +01:00
[Frontend]: Write out .swiftdeps files atomically
Modify ReferenceDependenciesEmitter::emit to write to a temporary file and then atomically rename it in place using the atomicallyWritingToFile helper function. This resolves SR-8707, where .swiftdeps files could be truncated if the compiler job was killed in the middle of a write.
This commit is contained in:
@@ -22,6 +22,7 @@
|
||||
#include "swift/AST/NameLookup.h"
|
||||
#include "swift/AST/ReferencedNameTracker.h"
|
||||
#include "swift/AST/Types.h"
|
||||
#include "swift/Basic/FileSystem.h"
|
||||
#include "swift/Basic/LLVM.h"
|
||||
#include "swift/Basic/ReferenceDependencyKeys.h"
|
||||
#include "swift/Frontend/FrontendOptions.h"
|
||||
@@ -65,11 +66,6 @@ public:
|
||||
llvm::raw_ostream &out);
|
||||
|
||||
private:
|
||||
/// Opens file for reference dependencies. Emits diagnostic if needed.
|
||||
///
|
||||
/// \return nullptr on error
|
||||
static std::unique_ptr<llvm::raw_fd_ostream> openFile(DiagnosticEngine &diags,
|
||||
StringRef OutputPath);
|
||||
/// Emits all the dependency information.
|
||||
void emit() const;
|
||||
|
||||
@@ -189,35 +185,24 @@ static std::string escape(DeclBaseName name) {
|
||||
return llvm::yaml::escape(name.userFacingName());
|
||||
}
|
||||
|
||||
std::unique_ptr<llvm::raw_fd_ostream>
|
||||
ReferenceDependenciesEmitter::openFile(DiagnosticEngine &diags,
|
||||
StringRef outputPath) {
|
||||
// Before writing to the dependencies file path, preserve any previous file
|
||||
// that may have been there. No error handling -- this is just a nicety, it
|
||||
// doesn't matter if it fails.
|
||||
llvm::sys::fs::rename(outputPath, outputPath + "~");
|
||||
|
||||
std::error_code EC;
|
||||
auto out = llvm::make_unique<llvm::raw_fd_ostream>(outputPath, EC,
|
||||
llvm::sys::fs::F_None);
|
||||
|
||||
if (out->has_error() || EC) {
|
||||
diags.diagnose(SourceLoc(), diag::error_opening_output, outputPath,
|
||||
EC.message());
|
||||
out->clear_error();
|
||||
return nullptr;
|
||||
}
|
||||
return out;
|
||||
}
|
||||
|
||||
bool ReferenceDependenciesEmitter::emit(DiagnosticEngine &diags,
|
||||
SourceFile *const SF,
|
||||
const DependencyTracker &depTracker,
|
||||
StringRef outputPath) {
|
||||
const std::unique_ptr<llvm::raw_ostream> out = openFile(diags, outputPath);
|
||||
if (!out.get())
|
||||
// Before writing to the dependencies file path, preserve any previous file
|
||||
// that may have been there. No error handling -- this is just a nicety, it
|
||||
// doesn't matter if it fails.
|
||||
llvm::sys::fs::rename(outputPath, outputPath + "~");
|
||||
std::error_code EC =
|
||||
swift::atomicallyWritingToFile(outputPath,
|
||||
[&](llvm::raw_pwrite_stream &out) {
|
||||
ReferenceDependenciesEmitter::emit(SF, depTracker, out);
|
||||
});
|
||||
if (EC) {
|
||||
diags.diagnose(SourceLoc(), diag::error_opening_output, outputPath,
|
||||
EC.message());
|
||||
return true;
|
||||
ReferenceDependenciesEmitter::emit(SF, depTracker, *out);
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user