1 //===- FileUpdate.cpp - Conditionally update a file -----------------------===// 2 // 3 // The LLVM Compiler Infrastructure 4 // 5 // This file is distributed under the University of Illinois Open Source 6 // License. See LICENSE.TXT for details. 7 // 8 //===----------------------------------------------------------------------===// 9 // 10 // FileUpdate is a utility for conditionally updating a file from its input 11 // based on whether the input differs from the output. It is used to avoid 12 // unnecessary modifications in a build system. 13 // 14 //===----------------------------------------------------------------------===// 15 16 #include "llvm/Support/CommandLine.h" 17 #include "llvm/Support/MemoryBuffer.h" 18 #include "llvm/ADT/OwningPtr.h" 19 #include "llvm/Support/PrettyStackTrace.h" 20 #include "llvm/Support/ToolOutputFile.h" 21 #include "llvm/Support/Signals.h" 22 #include "llvm/Support/system_error.h" 23 using namespace llvm; 24 25 static cl::opt<bool> 26 Quiet("quiet", cl::desc("Don't print unnecessary status information"), 27 cl::init(false)); 28 29 static cl::opt<std::string> 30 InputFilename("input-file", cl::desc("Input file (defaults to stdin)"), 31 cl::init("-"), cl::value_desc("filename")); 32 33 static cl::opt<std::string> 34 OutputFilename(cl::Positional, cl::desc("<output-file>"), cl::Required); 35 36 int main(int argc, char **argv) { 37 sys::PrintStackTraceOnErrorSignal(); 38 PrettyStackTraceProgram X(argc, argv); 39 cl::ParseCommandLineOptions(argc, argv); 40 41 if (OutputFilename == "-") { 42 errs() << argv[0] << ": error: Can't update standard output\n"; 43 return 1; 44 } 45 46 // Get the input data. 47 OwningPtr<MemoryBuffer> In; 48 if (error_code ec = MemoryBuffer::getFileOrSTDIN(InputFilename.c_str(), In)) { 49 errs() << argv[0] << ": error: Unable to get input '" 50 << InputFilename << "': " << ec.message() << '\n'; 51 return 1; 52 } 53 54 // Get the output data. 55 OwningPtr<MemoryBuffer> Out; 56 MemoryBuffer::getFile(OutputFilename.c_str(), Out); 57 58 // If the output exists and the contents match, we are done. 59 if (Out && In->getBufferSize() == Out->getBufferSize() && 60 memcmp(In->getBufferStart(), Out->getBufferStart(), 61 Out->getBufferSize()) == 0) { 62 if (!Quiet) 63 errs() << argv[0] << ": Not updating '" << OutputFilename 64 << "', contents match input.\n"; 65 return 0; 66 } 67 68 // Otherwise, overwrite the output. 69 if (!Quiet) 70 errs() << argv[0] << ": Updating '" << OutputFilename 71 << "', contents changed.\n"; 72 std::string ErrorStr; 73 tool_output_file OutStream(OutputFilename.c_str(), ErrorStr, 74 raw_fd_ostream::F_Binary); 75 if (!ErrorStr.empty()) { 76 errs() << argv[0] << ": Unable to write output '" 77 << OutputFilename << "': " << ErrorStr << '\n'; 78 return 1; 79 } 80 81 OutStream.os().write(In->getBufferStart(), In->getBufferSize()); 82 83 // Declare success. 84 OutStream.keep(); 85 86 return 0; 87 } 88