kythe.io@v0.0.68-0.20240422202219-7225dbc01741/kythe/cxx/indexer/proto/source_tree.cc (about)

     1  /*
     2   * Copyright 2018 The Kythe Authors. All rights reserved.
     3   *
     4   * Licensed under the Apache License, Version 2.0 (the "License");
     5   * you may not use this file except in compliance with the License.
     6   * You may obtain a copy of the License at
     7   *
     8   *   http://www.apache.org/licenses/LICENSE-2.0
     9   *
    10   * Unless required by applicable law or agreed to in writing, software
    11   * distributed under the License is distributed on an "AS IS" BASIS,
    12   * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
    13   * See the License for the specific language governing permissions and
    14   * limitations under the License.
    15   */
    16  
    17  #include "kythe/cxx/indexer/proto/source_tree.h"
    18  
    19  #include "absl/container/flat_hash_map.h"
    20  #include "absl/log/log.h"
    21  #include "absl/strings/str_cat.h"
    22  #include "absl/strings/str_join.h"
    23  #include "absl/strings/str_replace.h"
    24  #include "absl/strings/str_split.h"
    25  #include "absl/strings/strip.h"
    26  #include "google/protobuf/io/zero_copy_stream_impl_lite.h"
    27  #include "kythe/cxx/common/path_utils.h"
    28  
    29  namespace kythe {
    30  namespace {
    31  
    32  // TODO(justbuchanan): why isn't there a replace_all=false version of
    33  // StrReplace() in open-source abseil?
    34  /// Finds the first occurrence of @oldsub in @s and replaces it with @newsub. If
    35  /// @oldsub is not present, just returns @s.
    36  std::string StringReplaceFirst(absl::string_view s, absl::string_view oldsub,
    37                                 absl::string_view newsub) {
    38    return absl::StrJoin(absl::StrSplit(s, absl::MaxSplits(oldsub, 1)), newsub);
    39  }
    40  
    41  }  // namespace
    42  
    43  bool PreloadedProtoFileTree::AddFile(const std::string& filename,
    44                                       const std::string& contents) {
    45    VLOG(1) << filename << " added to PreloadedProtoFileTree";
    46    return file_map_.try_emplace(filename, contents).second;
    47  }
    48  
    49  google::protobuf::io::ZeroCopyInputStream* PreloadedProtoFileTree::Open(
    50      absl::string_view filename) {
    51    last_error_ = "";
    52  
    53    if (auto iter = file_mapping_cache_->find(filename);
    54        iter != file_mapping_cache_->end()) {
    55      const std::string& cached_path = iter->second;
    56      auto contents = file_map_.find(cached_path);
    57      if (contents == file_map_.end()) {
    58        last_error_ = absl::StrCat("Proto file Open(", filename,
    59                                   ") failed:", " cached mapping to ",
    60                                   cached_path, "no longer valid.");
    61        LOG(ERROR) << last_error_;
    62        return nullptr;
    63      }
    64      return new google::protobuf::io::ArrayInputStream(contents->second.data(),
    65                                                        contents->second.size());
    66    }
    67    for (auto& substitution : *substitutions_) {
    68      std::string found_path;
    69      if (substitution.first.empty()) {
    70        found_path = CleanPath(JoinPath(substitution.second, filename));
    71      } else if (filename == substitution.first) {
    72        found_path = substitution.second;
    73      } else if (absl::StartsWith(filename, substitution.first + "/")) {
    74        found_path = CleanPath(StringReplaceFirst(filename, substitution.first,
    75                                                  substitution.second));
    76      }
    77      if (auto iter = file_map_.find(found_path); iter != file_map_.end()) {
    78        VLOG(1) << "Proto file Open(" << filename << ") under ["
    79                << substitution.first << "->" << substitution.second << "]";
    80        if (auto [mapped_iter, inserted] =
    81                file_mapping_cache_->emplace(filename, found_path);
    82            !inserted) {
    83          LOG(ERROR) << "Redundant/contradictory data in index or internal bug."
    84                     << "  \"" << filename << "\" is mapped twice, first to \""
    85                     << mapped_iter->second << "\" and now to \"" << found_path
    86                     << "\".  Aborting "
    87                     << "new remapping...";
    88        }
    89        return new google::protobuf::io::ArrayInputStream(iter->second.data(),
    90                                                          iter->second.size());
    91      }
    92    }
    93    if (auto iter = file_map_.find(filename); iter != file_map_.end()) {
    94      VLOG(1) << "Proto file Open(" << filename << ") at root";
    95      return new google::protobuf::io::ArrayInputStream(iter->second.data(),
    96                                                        iter->second.size());
    97    }
    98    last_error_ = absl::StrCat("Proto file Open(", filename, ") failed because '",
    99                               filename, "' not recognized by indexer");
   100    LOG(WARNING) << last_error_;
   101    return nullptr;
   102  }
   103  
   104  bool PreloadedProtoFileTree::Read(absl::string_view file_path,
   105                                    std::string* out) {
   106    std::unique_ptr<google::protobuf::io::ZeroCopyInputStream> in_stream(
   107        Open({file_path.data(), file_path.size()}));
   108    if (!in_stream) {
   109      return false;
   110    }
   111  
   112    const void* data = nullptr;
   113    int size = 0;
   114    while (in_stream->Next(&data, &size)) {
   115      out->append(static_cast<const char*>(data), size);
   116    }
   117  
   118    return true;
   119  }
   120  
   121  }  // namespace kythe