Supervised user import: Listen for profile creation/deletion
[chromium-blink-merge.git] / tools / gn / function_write_file.cc
blob9f853f87008769695c24495a6df2eff469e0245b
1 // Copyright (c) 2013 The Chromium Authors. All rights reserved.
2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file.
5 #include <iostream>
6 #include <sstream>
8 #include "base/files/file_util.h"
9 #include "base/strings/string_split.h"
10 #include "base/strings/string_util.h"
11 #include "base/strings/utf_string_conversions.h"
12 #include "tools/gn/err.h"
13 #include "tools/gn/filesystem_utils.h"
14 #include "tools/gn/functions.h"
15 #include "tools/gn/input_file.h"
16 #include "tools/gn/parse_tree.h"
17 #include "tools/gn/scheduler.h"
19 namespace functions {
21 namespace {
23 // On Windows, provide a custom implementation of base::WriteFile. Sometimes
24 // the base version would fail, and this alternate implementation provides
25 // additional logging. See http://crbug.com/468437
26 #if defined(OS_WIN)
27 int DoWriteFile(const base::FilePath& filename, const char* data, int size) {
28 base::win::ScopedHandle file(::CreateFile(
29 filename.value().c_str(),
30 GENERIC_WRITE,
31 FILE_SHARE_READ, // Not present in the base version, speculative fix.
32 NULL,
33 CREATE_ALWAYS,
35 NULL));
36 if (!file.IsValid()) {
37 PLOG(ERROR) << "CreateFile failed for path "
38 << base::UTF16ToUTF8(filename.value());
39 return -1;
42 DWORD written;
43 BOOL result = ::WriteFile(file.Get(), data, size, &written, NULL);
44 if (result && static_cast<int>(written) == size)
45 return written;
47 if (!result) {
48 // WriteFile failed.
49 PLOG(ERROR) << "writing file " << base::UTF16ToUTF8(filename.value())
50 << " failed";
51 } else {
52 // Didn't write all the bytes.
53 LOG(ERROR) << "wrote" << written << " bytes to "
54 << base::UTF16ToUTF8(filename.value()) << " expected " << size;
56 return -1;
58 #else
59 int DoWriteFile(const base::FilePath& filename, const char* data, int size) {
60 return base::WriteFile(filename, data, size);
62 #endif
64 } // namespace
66 const char kWriteFile[] = "write_file";
67 const char kWriteFile_HelpShort[] =
68 "write_file: Write a file to disk.";
69 const char kWriteFile_Help[] =
70 "write_file: Write a file to disk.\n"
71 "\n"
72 " write_file(filename, data)\n"
73 "\n"
74 " If data is a list, the list will be written one-item-per-line with no\n"
75 " quoting or brackets.\n"
76 "\n"
77 " If the file exists and the contents are identical to that being\n"
78 " written, the file will not be updated. This will prevent unnecessary\n"
79 " rebuilds of targets that depend on this file.\n"
80 "\n"
81 " TODO(brettw) we probably need an optional third argument to control\n"
82 " list formatting.\n"
83 "\n"
84 "Arguments:\n"
85 "\n"
86 " filename\n"
87 " Filename to write. This must be within the output directory.\n"
88 "\n"
89 " data:\n"
90 " The list or string to write.\n";
92 Value RunWriteFile(Scope* scope,
93 const FunctionCallNode* function,
94 const std::vector<Value>& args,
95 Err* err) {
96 if (args.size() != 2) {
97 *err = Err(function->function(), "Wrong number of arguments to write_file",
98 "I expected two arguments.");
99 return Value();
102 // Compute the file name and make sure it's in the output dir.
103 if (!args[0].VerifyTypeIs(Value::STRING, err))
104 return Value();
105 const SourceDir& cur_dir = scope->GetSourceDir();
106 SourceFile source_file = cur_dir.ResolveRelativeFile(args[0].string_value(),
107 scope->settings()->build_settings()->root_path_utf8());
108 if (!EnsureStringIsInOutputDir(
109 scope->settings()->build_settings()->build_dir(),
110 source_file.value(), args[0].origin(), err))
111 return Value();
113 // Compute output.
114 std::ostringstream contents;
115 if (args[1].type() == Value::LIST) {
116 const std::vector<Value>& list = args[1].list_value();
117 for (const auto& cur : list)
118 contents << cur.ToString(false) << std::endl;
119 } else {
120 contents << args[1].ToString(false);
122 const std::string& new_contents = contents.str();
123 base::FilePath file_path =
124 scope->settings()->build_settings()->GetFullPath(source_file);
126 // Make sure we're not replacing the same contents.
127 std::string existing_contents;
128 if (base::ReadFileToString(file_path, &existing_contents) &&
129 existing_contents == new_contents)
130 return Value(); // Nothing to do.
132 // Write file, creating the directory if necessary.
133 if (!base::CreateDirectory(file_path.DirName())) {
134 *err = Err(function->function(), "Unable to create directory.",
135 "I was using \"" + FilePathToUTF8(file_path.DirName()) + "\".");
136 return Value();
139 int int_size = static_cast<int>(new_contents.size());
140 if (DoWriteFile(file_path, new_contents.c_str(), int_size)
141 != int_size) {
142 *err = Err(function->function(), "Unable to write file.",
143 "I was writing \"" + FilePathToUTF8(file_path) + "\".");
144 return Value();
146 return Value();
149 } // namespace functions