| //===- FileUpdate.cpp - Conditionally update a file -----------------------===// |
| // |
| // The LLVM Compiler Infrastructure |
| // |
| // This file is distributed under the University of Illinois Open Source |
| // License. See LICENSE.TXT for details. |
| // |
| //===----------------------------------------------------------------------===// |
| // |
| // FileUpdate is a utility for conditionally updating a file from its input |
| // based on whether the input differs from the output. It is used to avoid |
| // unnecessary modifications in a build system. |
| // |
| //===----------------------------------------------------------------------===// |
| |
| #include "llvm/Support/CommandLine.h" |
| #include "llvm/Support/MemoryBuffer.h" |
| #include "llvm/ADT/OwningPtr.h" |
| #include "llvm/Support/PrettyStackTrace.h" |
| #include "llvm/Support/ToolOutputFile.h" |
| #include "llvm/Support/Signals.h" |
| #include "llvm/Support/system_error.h" |
| using namespace llvm; |
| |
| static cl::opt<bool> |
| Quiet("quiet", cl::desc("Don't print unnecessary status information"), |
| cl::init(false)); |
| |
| static cl::opt<std::string> |
| InputFilename("input-file", cl::desc("Input file (defaults to stdin)"), |
| cl::init("-"), cl::value_desc("filename")); |
| |
| static cl::opt<std::string> |
| OutputFilename(cl::Positional, cl::desc("<output-file>"), cl::Required); |
| |
| int main(int argc, char **argv) { |
| sys::PrintStackTraceOnErrorSignal(); |
| PrettyStackTraceProgram X(argc, argv); |
| cl::ParseCommandLineOptions(argc, argv); |
| |
| if (OutputFilename == "-") { |
| errs() << argv[0] << ": error: Can't update standard output\n"; |
| return 1; |
| } |
| |
| // Get the input data. |
| OwningPtr<MemoryBuffer> In; |
| if (error_code ec = MemoryBuffer::getFileOrSTDIN(InputFilename.c_str(), In)) { |
| errs() << argv[0] << ": error: Unable to get input '" |
| << InputFilename << "': " << ec.message() << '\n'; |
| return 1; |
| } |
| |
| // Get the output data. |
| OwningPtr<MemoryBuffer> Out; |
| MemoryBuffer::getFile(OutputFilename.c_str(), Out); |
| |
| // If the output exists and the contents match, we are done. |
| if (Out && In->getBufferSize() == Out->getBufferSize() && |
| memcmp(In->getBufferStart(), Out->getBufferStart(), |
| Out->getBufferSize()) == 0) { |
| if (!Quiet) |
| errs() << argv[0] << ": Not updating '" << OutputFilename |
| << "', contents match input.\n"; |
| return 0; |
| } |
| |
| // Otherwise, overwrite the output. |
| if (!Quiet) |
| errs() << argv[0] << ": Updating '" << OutputFilename |
| << "', contents changed.\n"; |
| std::string ErrorStr; |
| tool_output_file OutStream(OutputFilename.c_str(), ErrorStr, |
| raw_fd_ostream::F_Binary); |
| if (!ErrorStr.empty()) { |
| errs() << argv[0] << ": Unable to write output '" |
| << OutputFilename << "': " << ErrorStr << '\n'; |
| return 1; |
| } |
| |
| OutStream.os().write(In->getBufferStart(), In->getBufferSize()); |
| |
| // Declare success. |
| OutStream.keep(); |
| |
| return 0; |
| } |