FileUpdate.cpp 2.8 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687
  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. #include "llvm/ADT/OwningPtr.h"
  16. #include "llvm/Support/CommandLine.h"
  17. #include "llvm/Support/MemoryBuffer.h"
  18. #include "llvm/Support/PrettyStackTrace.h"
  19. #include "llvm/Support/Signals.h"
  20. #include "llvm/Support/ToolOutputFile.h"
  21. #include "llvm/Support/system_error.h"
  22. using namespace llvm;
  23. static cl::opt<bool>
  24. Quiet("quiet", cl::desc("Don't print unnecessary status information"),
  25. cl::init(false));
  26. static cl::opt<std::string>
  27. InputFilename("input-file", cl::desc("Input file (defaults to stdin)"),
  28. cl::init("-"), cl::value_desc("filename"));
  29. static cl::opt<std::string>
  30. OutputFilename(cl::Positional, cl::desc("<output-file>"), cl::Required);
  31. int main(int argc, char **argv) {
  32. sys::PrintStackTraceOnErrorSignal();
  33. PrettyStackTraceProgram X(argc, argv);
  34. cl::ParseCommandLineOptions(argc, argv);
  35. if (OutputFilename == "-") {
  36. errs() << argv[0] << ": error: Can't update standard output\n";
  37. return 1;
  38. }
  39. // Get the input data.
  40. OwningPtr<MemoryBuffer> In;
  41. if (error_code ec = MemoryBuffer::getFileOrSTDIN(InputFilename.c_str(), In)) {
  42. errs() << argv[0] << ": error: Unable to get input '"
  43. << InputFilename << "': " << ec.message() << '\n';
  44. return 1;
  45. }
  46. // Get the output data.
  47. OwningPtr<MemoryBuffer> Out;
  48. MemoryBuffer::getFile(OutputFilename.c_str(), Out);
  49. // If the output exists and the contents match, we are done.
  50. if (Out && In->getBufferSize() == Out->getBufferSize() &&
  51. memcmp(In->getBufferStart(), Out->getBufferStart(),
  52. Out->getBufferSize()) == 0) {
  53. if (!Quiet)
  54. errs() << argv[0] << ": Not updating '" << OutputFilename
  55. << "', contents match input.\n";
  56. return 0;
  57. }
  58. // Otherwise, overwrite the output.
  59. if (!Quiet)
  60. errs() << argv[0] << ": Updating '" << OutputFilename
  61. << "', contents changed.\n";
  62. std::string ErrorStr;
  63. tool_output_file OutStream(OutputFilename.c_str(), ErrorStr,
  64. raw_fd_ostream::F_Binary);
  65. if (!ErrorStr.empty()) {
  66. errs() << argv[0] << ": Unable to write output '"
  67. << OutputFilename << "': " << ErrorStr << '\n';
  68. return 1;
  69. }
  70. OutStream.os().write(In->getBufferStart(), In->getBufferSize());
  71. // Declare success.
  72. OutStream.keep();
  73. return 0;
  74. }