// Copyright 2014 The Bazel Authors. All rights reserved.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
//    http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
package com.google.devtools.build.lib.packages;

import com.google.devtools.build.lib.events.Event;
import com.google.devtools.build.lib.events.StoredEventHandler;
import com.google.devtools.build.lib.syntax.BuildFileAST;
import com.google.devtools.build.lib.syntax.ParserInputSource;
import com.google.devtools.build.lib.vfs.FileSystemUtils;
import com.google.devtools.build.lib.vfs.Path;
import com.google.devtools.build.lib.vfs.PathFragment;
import java.io.IOException;
import java.util.Set;
import javax.annotation.Nullable;

/** A Preprocessor is an interface to implement generic text-based preprocessing of BUILD files. */
public interface Preprocessor {
  /** Factory for {@link Preprocessor} instances. */
  interface Factory {
    /**
     * Returns whether this {@link Factory} is still suitable for providing {@link Preprocessor}s.
     * If not, all previous preprocessing results should be assumed to be invalid and a new
     * {@link Factory} should be created via {@link Supplier#getFactory}.
     */
    boolean isStillValid();

    /**
     * Returns whether all globs encountered during {@link Preprocessor#preprocess} will be passed
     * along to the {@link Globber} given there (which then executes them asynchronously). If this
     * is not the case, then e.g. prefetching globs during normal BUILD file evaluation may be
     * profitable.
     */
    boolean considersGlobs();

    /**
     * Returns a Preprocessor instance capable of preprocessing a BUILD file independently (e.g. it
     * ought to be fine to call {@link #getPreprocessor} for each BUILD file).
     */
    @Nullable
    Preprocessor getPreprocessor();

    /** Factory that always returns {@code null} {@link Preprocessor}s. */
    static class NullFactory implements Factory {
      public static final NullFactory INSTANCE = new NullFactory();

      private NullFactory() {
      }

      @Override
      public boolean isStillValid() {
        return true;
      }

      @Override
      public boolean considersGlobs() {
        return false;
      }

      @Override
      public Preprocessor getPreprocessor() {
        return null;
      }
    }
  }

  /**
   * A (result, success) tuple indicating the outcome of preprocessing.
   */
  static class Result {
    public final ParserInputSource result;

    private Result(ParserInputSource result) {
      this.result = result;
    }

    public static Result noPreprocessing(PathFragment buildFilePathFragment,
        byte[] buildFileBytes) {
      return noPreprocessing(ParserInputSource.create(
          FileSystemUtils.convertFromLatin1(buildFileBytes), buildFilePathFragment));
    }

    /** Convenience factory for a {@link Result} wrapping non-preprocessed BUILD file contents. */
    public static Result noPreprocessing(ParserInputSource buildFileSource) {
      return new Result(buildFileSource);
    }
  }

  /**
   * Returns a Result resulting from applying Python preprocessing to the contents of "in". If
   * errors happen, they must be reported both as an event on eventHandler and in the function
   * return value. An IOException is only thrown when preparing for preprocessing. Once
   * preprocessing actually begins, any I/O problems encountered will be reflected in the return
   * value, not manifested as exceptions.
   *
   * @param buildFilePath the BUILD file to be preprocessed.
   * @param buildFileBytes the raw contents of the BUILD file to be preprocessed.
   * @param packageName the BUILD file's package.
   * @param globber a globber for evaluating globs.
   * @param globals the global bindings for the Python environment.
   * @param ruleNames the set of names of all rules in the build language.
   * @throws IOException if there was an I/O problem preparing for preprocessing.
   * @return a pair of the ParserInputSource and a map of subincludes seen during the evaluation
   */
  Result preprocess(
      Path buildFilePath,
      byte[] buildFileBytes,
      String packageName,
      Globber globber,
      Set<String> ruleNames)
    throws IOException, InterruptedException;

  /** The result of parsing a preprocessed BUILD file. */
  static class AstAfterPreprocessing {
    public final BuildFileAST ast;
    public final boolean containsAstParsingErrors;
    public final Iterable<Event> allEvents;

    public AstAfterPreprocessing(Result preprocessingResult, BuildFileAST ast,
        StoredEventHandler astParsingEventHandler) {
      this.ast = ast;
      this.containsAstParsingErrors = astParsingEventHandler.hasErrors();
      this.allEvents = astParsingEventHandler.getEvents();
    }
  }
}

@@ -1106,42 +1106,8 @@
 Set;
-%0Aimport javax.annotation.Nullable;
 %0A%0A/*
@@ -1240,1504 +1240,8 @@
 r %7B%0A
-  /** Factory for %7B@link Preprocessor%7D instances. */%0A  interface Factory %7B%0A    /**%0A     * Returns whether this %7B@link Factory%7D is still suitable for providing %7B@link Preprocessor%7Ds.%0A     * If not, all previous preprocessing results should be assumed to be invalid and a new%0A     * %7B@link Factory%7D should be created via %7B@link Supplier#getFactory%7D.%0A     */%0A    boolean isStillValid();%0A%0A    /**%0A     * Returns whether all globs encountered during %7B@link Preprocessor#preprocess%7D will be passed%0A     * along to the %7B@link Globber%7D given there (which then executes them asynchronously). If this%0A     * is not the case, then e.g. prefetching globs during normal BUILD file evaluation may be%0A     * profitable.%0A     */%0A    boolean considersGlobs();%0A%0A    /**%0A     * Returns a Preprocessor instance capable of preprocessing a BUILD file independently (e.g. it%0A     * ought to be fine to call %7B@link #getPreprocessor%7D for each BUILD file).%0A     */%0A    @Nullable%0A    Preprocessor getPreprocessor();%0A%0A    /** Factory that always returns %7B@code null%7D %7B@link Preprocessor%7Ds. */%0A    static class NullFactory implements Factory %7B%0A      public static final NullFactory INSTANCE = new NullFactory();%0A%0A      private NullFactory() %7B%0A      %7D%0A%0A      @Override%0A      public boolean isStillValid() %7B%0A        return true;%0A      %7D%0A%0A      @Override%0A      public boolean considersGlobs() %7B%0A        return false;%0A      %7D%0A%0A      @Override%0A      public Preprocessor getPreprocessor() %7B%0A        return null;%0A      %7D%0A    %7D%0A  %7D%0A%0A
   /*

Delete Preprocessor.Factory