Home | History | Annotate | Download | only in gn
      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 #include "tools/gn/import_manager.h"
      6 
      7 #include "base/memory/scoped_ptr.h"
      8 #include "base/stl_util.h"
      9 #include "tools/gn/parse_tree.h"
     10 #include "tools/gn/scheduler.h"
     11 
     12 namespace {
     13 
     14 // Returns a newly-allocated scope on success, null on failure.
     15 Scope* UncachedImport(const Settings* settings,
     16                       const SourceFile& file,
     17                       const ParseNode* node_for_err,
     18                       Err* err) {
     19   const ParseNode* node = g_scheduler->input_file_manager()->SyncLoadFile(
     20       node_for_err->GetRange(), settings->build_settings(), file, err);
     21   if (!node)
     22     return NULL;
     23   const BlockNode* block = node->AsBlock();
     24   CHECK(block);
     25 
     26   scoped_ptr<Scope> scope(new Scope(settings->base_config()));
     27   scope->set_source_dir(file.GetDir());
     28   scope->SetProcessingImport();
     29   block->ExecuteBlockInScope(scope.get(), err);
     30   if (err->has_error())
     31     return NULL;
     32   scope->ClearProcessingImport();
     33 
     34   return scope.release();
     35 }
     36 
     37 }  // namesapce
     38 
     39 ImportManager::ImportManager() {
     40 }
     41 
     42 ImportManager::~ImportManager() {
     43   STLDeleteContainerPairSecondPointers(imports_.begin(), imports_.end());
     44 }
     45 
     46 bool ImportManager::DoImport(const SourceFile& file,
     47                              const ParseNode* node_for_err,
     48                              Scope* scope,
     49                              Err* err) {
     50   // See if we have a cached import, but be careful to actually do the scope
     51   // copying outside of the lock.
     52   const Scope* imported_scope = NULL;
     53   {
     54     base::AutoLock lock(lock_);
     55     ImportMap::const_iterator found = imports_.find(file);
     56     if (found != imports_.end())
     57       imported_scope = found->second;
     58   }
     59 
     60   if (!imported_scope) {
     61     // Do a new import of the file.
     62     imported_scope = UncachedImport(scope->settings(), file,
     63                                     node_for_err, err);
     64     if (!imported_scope)
     65       return false;
     66 
     67     // We loaded the file outside the lock. This means that there could be a
     68     // race and the file was already loaded on a background thread. Recover
     69     // from this and use the existing one if that happens.
     70     {
     71       base::AutoLock lock(lock_);
     72       ImportMap::const_iterator found = imports_.find(file);
     73       if (found != imports_.end()) {
     74         delete imported_scope;
     75         imported_scope = found->second;
     76       } else {
     77         imports_[file] = imported_scope;
     78       }
     79     }
     80   }
     81 
     82   return imported_scope->NonRecursiveMergeTo(scope, node_for_err,
     83                                              "import", err);
     84 }
     85