DependencyFile.java

  1. /*
  2.  * Copyright 2008 The Closure Compiler Authors.
  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. package com.google.javascript.jscomp.deps;

  17. import static com.google.javascript.jscomp.deps.DefaultDependencyResolver.CLOSURE_BASE;
  18. import static com.google.javascript.jscomp.deps.DefaultDependencyResolver.CLOSURE_BASE_PROVIDE;

  19. import com.google.javascript.jscomp.ErrorManager;
  20. import com.google.javascript.jscomp.LoggerErrorManager;
  21. import java.util.ArrayList;
  22. import java.util.HashMap;
  23. import java.util.List;
  24. import java.util.Map;
  25. import java.util.logging.Logger;

  26. /**
  27.  * SourceFile containing dependency information.  Delegates file handling to
  28.  * another SourceFile such that a VirtualFile, LocalFile or RemoteFile can be
  29.  * used.
  30.  */
  31. public final class DependencyFile implements SourceFile {

  32.   /** Map of name spaces to their dependency info. */
  33.   private final Map<String, DependencyInfo> dependencies = new HashMap<>();

  34.   /** A source file to delegate functionality too. */
  35.   private final SourceFile delegate;

  36.   /** Logger for DependencyResolver. */
  37.   private static final Logger logger = Logger.getLogger(DependencyFile.class.getName());

  38.   /** Creates a new dependency file. */
  39.   public DependencyFile(SourceFile delegate) {
  40.     this.delegate = delegate;
  41.   }

  42.   @Override
  43.   public String getName() {
  44.     return delegate.getName();
  45.   }

  46.   @Override
  47.   public String getContent() {
  48.     return delegate.getContent();
  49.   }

  50.   @Override
  51.   public boolean wasModified() {
  52.     return delegate.wasModified();
  53.   }

  54.   /**
  55.    * Ensures that the dependency graph is up to date and reloads the graph if
  56.    * necessary.
  57.    */
  58.   public void ensureUpToDate() throws ServiceException {
  59.     if (dependencies.isEmpty() || wasModified()) {
  60.       loadGraph();
  61.     }
  62.   }

  63.   /**
  64.    * Gets the dependency info for the provided symbol, if contained in this
  65.    * dependency file.
  66.    */
  67.   public DependencyInfo getDependencyInfo(String symbol) {
  68.     return dependencies.get(symbol);
  69.   }

  70.   /** Loads the dependency graph. */
  71.   private void loadGraph() throws ServiceException {
  72.     dependencies.clear();

  73.     logger.info("Loading dependency graph");

  74.     // Parse the deps.js file.
  75.     ErrorManager errorManager = new LoggerErrorManager(logger);
  76.     DepsFileParser parser =
  77.         new DepsFileParser(errorManager);
  78.     List<DependencyInfo> depInfos =
  79.         parser.parseFile(getName(), getContent());

  80.     // Ensure the parse succeeded.
  81.     if (!parser.didParseSucceed()) {
  82.       throw new ServiceException("Problem parsing " + getName()
  83.           + ". See logs for details.");
  84.     }
  85.     // Incorporate the dependencies into our maps.
  86.     for (DependencyInfo depInfo : depInfos) {
  87.       for (String provide : depInfo.getProvides()) {
  88.         DependencyInfo existing = dependencies.get(provide);
  89.         if (existing != null && !existing.equals(depInfo)) {
  90.           throw new ServiceException("Duplicate provide of " + provide
  91.               + ". Was provided by " + existing.getPathRelativeToClosureBase()
  92.               + " and " + depInfo.getPathRelativeToClosureBase());
  93.         }
  94.         dependencies.put(provide, depInfo);
  95.       }
  96.     }

  97.     List<String> provides = new ArrayList<>();
  98.     provides.add(CLOSURE_BASE_PROVIDE);

  99.     // Add implicit base.js entry.
  100.     dependencies.put(
  101.         CLOSURE_BASE_PROVIDE,
  102.         SimpleDependencyInfo.builder(CLOSURE_BASE, CLOSURE_BASE).setProvides(provides).build());
  103.     errorManager.generateReport();

  104.     logger.info("Dependencies loaded");
  105.   }

  106. }