xref: /third_party/gn/src/gn/filesystem_utils.h (revision 6d528ed9)
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.
4
5#ifndef TOOLS_GN_FILESYSTEM_UTILS_H_
6#define TOOLS_GN_FILESYSTEM_UTILS_H_
7
8#include <stddef.h>
9
10#include <string>
11#include <string_view>
12
13#include "base/files/file_path.h"
14#include "gn/settings.h"
15#include "gn/target.h"
16
17class Err;
18
19std::string FilePathToUTF8(const base::FilePath::StringType& str);
20inline std::string FilePathToUTF8(const base::FilePath& path) {
21  return FilePathToUTF8(path.value());
22}
23base::FilePath UTF8ToFilePath(std::string_view sp);
24
25// Extensions -----------------------------------------------------------------
26
27// Returns the index of the extension (character after the last dot not after a
28// slash). Returns std::string::npos if not found. Returns path.size() if the
29// file ends with a dot.
30size_t FindExtensionOffset(const std::string& path);
31
32// Returns a string piece pointing into the input string identifying the
33// extension. Note that the input pointer must outlive the output.
34std::string_view FindExtension(const std::string* path);
35
36// Filename parts -------------------------------------------------------------
37
38// Returns the offset of the character following the last slash, or
39// 0 if no slash was found. Returns path.size() if the path ends with a slash.
40// Note that the input pointer must outlive the output.
41size_t FindFilenameOffset(const std::string& path);
42
43// Returns a string piece pointing into the input string identifying the
44// file name (following the last slash, including the extension). Note that the
45// input pointer must outlive the output.
46std::string_view FindFilename(const std::string* path);
47
48// Like FindFilename but does not include the extension.
49std::string_view FindFilenameNoExtension(const std::string* path);
50
51// Removes everything after the last slash. The last slash, if any, will be
52// preserved.
53void RemoveFilename(std::string* path);
54
55// Returns if the given character is a slash. This allows both slashes and
56// backslashes for consistency between Posix and Windows (as opposed to
57// FilePath::IsSeparator which is based on the current platform).
58inline bool IsSlash(const char ch) {
59  return ch == '/' || ch == '\\';
60}
61
62// Returns true if the given path ends with a slash.
63bool EndsWithSlash(std::string_view s);
64
65// Path parts -----------------------------------------------------------------
66
67// Returns a string piece pointing into the input string identifying the
68// directory name of the given path, including the last slash. Note that the
69// input pointer must outlive the output.
70std::string_view FindDir(const std::string* path);
71
72// Returns the substring identifying the last component of the dir, or the
73// empty substring if none. For example "//foo/bar/" -> "bar".
74std::string_view FindLastDirComponent(const SourceDir& dir);
75
76// Returns true if the given string is in the given output dir. This is pretty
77// stupid and doesn't handle "." and "..", etc., it is designed for a sanity
78// check to keep people from writing output files to the source directory
79// accidentally.
80bool IsStringInOutputDir(const SourceDir& output_dir, const std::string& str);
81
82// Verifies that the given string references a file inside of the given
83// directory. This just uses IsStringInOutputDir above.
84//
85// The origin will be blamed in the error.
86//
87// If the file isn't in the dir, returns false and sets the error. Otherwise
88// returns true and leaves the error untouched.
89bool EnsureStringIsInOutputDir(const SourceDir& output_dir,
90                               const std::string& str,
91                               const ParseNode* origin,
92                               Err* err);
93
94// ----------------------------------------------------------------------------
95
96// Returns true if the input string is absolute. Double-slashes at the
97// beginning are treated as source-relative paths. On Windows, this handles
98// paths of both the native format: "C:/foo" and ours "/C:/foo"
99bool IsPathAbsolute(std::string_view path);
100
101// Returns true if the input string is source-absolute. Source-absolute
102// paths begin with two forward slashes and resolve as if they are
103// relative to the source root.
104bool IsPathSourceAbsolute(std::string_view path);
105
106// Given an absolute path, checks to see if is it is inside the source root.
107// If it is, fills a source-absolute path into the given output and returns
108// true. If it isn't, clears the dest and returns false.
109//
110// The source_root should be a base::FilePath converted to UTF-8. On Windows,
111// it should begin with a "C:/" rather than being our SourceFile's style
112// ("/C:/"). The source root can end with a slash or not.
113//
114// Note that this does not attempt to normalize slashes in the output.
115bool MakeAbsolutePathRelativeIfPossible(std::string_view source_root,
116                                        std::string_view path,
117                                        std::string* dest);
118
119// Given two absolute paths |base| and |target|, returns a relative path to
120// |target| as if the current directory was |base|.  The relative path returned
121// is minimal.  For example, if "../../a/b/" and "../b" are both valid, then the
122// latter will be returned.  On Windows, it's impossible to have a relative path
123// from C:\foo to D:\bar, so the absolute path |target| is returned instead for
124// this case.
125base::FilePath MakeAbsoluteFilePathRelativeIfPossible(
126    const base::FilePath& base,
127    const base::FilePath& target);
128
129// Collapses "." and sequential "/"s and evaluates "..". |path| may be
130// system-absolute, source-absolute, or relative. If |path| is source-absolute
131// and |source_root| is non-empty, |path| may be system absolute after this
132// function returns, if |path| references the filesystem outside of
133// |source_root| (ex. path = "//.."). In this case on Windows, |path| will have
134// a leading slash. Otherwise, |path| will retain its relativity. |source_root|
135// must not end with a slash.
136void NormalizePath(std::string* path,
137                   std::string_view source_root = std::string_view());
138
139// Converts slashes to backslashes for Windows. Keeps the string unchanged
140// for other systems.
141void ConvertPathToSystem(std::string* path);
142
143// Takes a path, |input|, and makes it relative to the given directory
144// |dest_dir|. Both inputs may be source-relative (e.g. begins with
145// with "//") or may be absolute.
146//
147// If supplied, the |source_root| parameter is the absolute path to
148// the source root and not end in a slash. Unless you know that the
149// inputs are always source relative, this should be supplied.
150std::string RebasePath(const std::string& input,
151                       const SourceDir& dest_dir,
152                       std::string_view source_root = std::string_view());
153
154// Resolves a file or dir name (parameter input) relative to
155// value directory. Will return an empty SourceDir/File on error
156// and set the give *err pointer (required). Empty input is always an error.
157// Returned value can be used to set value in either SourceFile or SourceDir
158// (based on as_file parameter).
159//
160// Parameter as_file defines whether result path will look like a file path
161// or it should be treated as a directory (contains "/" and the end
162// of the string).
163//
164// If source_root is supplied, these functions will additionally handle the
165// case where the input is a system-absolute but still inside the source
166// tree. This is the case for some external tools.
167std::string ResolveRelative(std::string_view input,
168                            const std::string& value,
169                            bool as_file,
170                            std::string_view source_root);
171
172// Resolves source file or directory relative to some given source root. Returns
173// an empty file path on error.
174base::FilePath ResolvePath(const std::string& value,
175                           bool as_file,
176                           const base::FilePath& source_root);
177
178// Returns the given directory with no terminating slash at the end, such that
179// appending a slash and more stuff will produce a valid path.
180//
181// If the directory refers to either the source or system root, we'll append
182// a "." so this remains valid.
183std::string DirectoryWithNoLastSlash(const SourceDir& dir);
184
185// Returns the "best" SourceDir representing the given path. If it's inside the
186// given source_root, a source-relative directory will be returned (e.g.
187// "//foo/bar.cc". If it's outside of the source root or the source root is
188// empty, a system-absolute directory will be returned.
189SourceDir SourceDirForPath(const base::FilePath& source_root,
190                           const base::FilePath& path);
191
192// Like SourceDirForPath but returns the SourceDir representing the current
193// directory.
194SourceDir SourceDirForCurrentDirectory(const base::FilePath& source_root);
195
196// Given the label of a toolchain and whether that toolchain is the default
197// toolchain, returns the name of the subdirectory for that toolchain's
198// output. This will be the empty string to indicate that the toolchain outputs
199// go in the root build directory. Otherwise, the result will end in a slash.
200std::string GetOutputSubdirName(const Label& toolchain_label, bool is_default);
201
202// Returns true if the contents of the file and stream given are equal, false
203// otherwise.
204bool ContentsEqual(const base::FilePath& file_path, const std::string& data);
205
206// Writes given stream contents to the given file. Returns true if data was
207// successfully written, false otherwise. |err| is set on error if not nullptr.
208bool WriteFile(const base::FilePath& file_path,
209               const std::string& data,
210               Err* err);
211
212// -----------------------------------------------------------------------------
213
214enum class BuildDirType {
215  // Returns the root toolchain dir rather than the generated or output
216  // subdirectories. This is valid only for the toolchain directory getters.
217  // Asking for this for a target or source dir makes no sense.
218  TOOLCHAIN_ROOT,
219
220  // Generated file directory.
221  GEN,
222
223  // Output file directory.
224  OBJ,
225
226  // Phony file directory. As the name implies, this is not a real file
227  // directory, but a path that is used for the declaration of phony targets.
228  // This is done to avoid duplicate target names between real files and phony
229  // aliases that point to them.
230  PHONY,
231};
232
233// In different contexts, different information is known about the toolchain in
234// question. If you have a Target or settings object, everything can be
235// extracted from there. But when querying label information on something in
236// another toolchain, for example, the only thing known (it may not even exist)
237// is the toolchain label string and whether it matches the default toolchain.
238//
239// This object extracts the relevant information from a variety of input
240// types for the convenience of the caller.
241class BuildDirContext {
242 public:
243  // Extracts toolchain information associated with the given target.
244  explicit BuildDirContext(const Target* target);
245
246  // Extracts toolchain information associated with the given settings object.
247  explicit BuildDirContext(const Settings* settings);
248
249  // Extrats toolchain information from the current toolchain of the scope.
250  explicit BuildDirContext(const Scope* execution_scope);
251
252  // Extracts the default toolchain information from the given execution
253  // scope. The toolchain you want to query must be passed in. This doesn't
254  // use the settings object from the Scope so one can query other toolchains.
255  // If you want to use the scope's current toolchain, use the version above.
256  BuildDirContext(const Scope* execution_scope, const Label& toolchain_label);
257
258  // Specify all information manually.
259  BuildDirContext(const BuildSettings* build_settings,
260                  const Label& toolchain_label,
261                  bool is_default_toolchain);
262
263  const BuildSettings* build_settings;
264  const Label& toolchain_label;
265  bool is_default_toolchain;
266};
267
268// Returns the root, object, or generated file directory for the toolchain.
269//
270// The toolchain object file root is never exposed in GN (there is no
271// root_obj_dir variable) so BuildDirType::OBJ would normally never be passed
272// to this function except when it's called by one of the variants below that
273// append paths to it.
274SourceDir GetBuildDirAsSourceDir(const BuildDirContext& context,
275                                 BuildDirType type);
276OutputFile GetBuildDirAsOutputFile(const BuildDirContext& context,
277                                   BuildDirType type);
278
279// Returns the output or generated file directory corresponding to the given
280// source directory.
281SourceDir GetSubBuildDirAsSourceDir(const BuildDirContext& context,
282                                    const SourceDir& source_dir,
283                                    BuildDirType type);
284OutputFile GetSubBuildDirAsOutputFile(const BuildDirContext& context,
285                                      const SourceDir& source_dir,
286                                      BuildDirType type);
287
288// Returns the output or generated file directory corresponding to the given
289// target.
290SourceDir GetBuildDirForTargetAsSourceDir(const Target* target,
291                                          BuildDirType type);
292OutputFile GetBuildDirForTargetAsOutputFile(const Target* target,
293                                            BuildDirType type);
294
295// Returns the scope's current directory.
296SourceDir GetScopeCurrentBuildDirAsSourceDir(const Scope* scope,
297                                             BuildDirType type);
298// Lack of OutputDir version is due only to it not currently being needed,
299// please add one if you need it.
300
301#endif  // TOOLS_GN_FILESYSTEM_UTILS_H_
302