/* * Copyright 2017-present Facebook, Inc. * * 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.facebook.buck.rules.macros; import com.facebook.buck.model.BuildTargetPattern; import com.facebook.buck.model.Either; import com.facebook.buck.parser.BuildTargetPatternParser; import com.facebook.buck.rules.CellPathResolver; import com.facebook.buck.util.RichStream; import com.facebook.buck.util.immutables.BuckStyleTuple; import com.facebook.buck.versions.TargetNodeTranslator; import com.facebook.buck.versions.TargetTranslatable; import com.google.common.collect.ImmutableList; import java.util.Optional; import java.util.function.Function; import java.util.stream.Collectors; import org.immutables.value.Value; /** A class representing a string containing ordered, embedded, strongly typed macros. */ @Value.Immutable @BuckStyleTuple abstract class AbstractStringWithMacros implements TargetTranslatable<StringWithMacros> { // The components of the macro string. Each part is either a plain string or a macro. abstract ImmutableList<Either<String, Macro>> getParts(); /** @return the list of all {@link Macro}s in the macro string. */ public ImmutableList<Macro> getMacros() { return RichStream.from(getParts()) .filter(Either::isRight) .map(Either::getRight) .toImmutableList(); } public <T> ImmutableList<T> map( Function<? super String, ? extends T> stringMapper, Function<? super Macro, ? extends T> macroMapper) { return RichStream.from(getParts()) .map(e -> e.isLeft() ? stringMapper.apply(e.getLeft()) : macroMapper.apply(e.getRight())) .toImmutableList(); } /** * @return format the macro string into a {@link String}, using {@code mapper} to stringify the * embedded {@link Macro}s. */ public String format(Function<? super Macro, ? extends CharSequence> mapper) { return map(s -> s, mapper).stream().collect(Collectors.joining()); } /** * @return a new {@link StringWithMacros} with the string components transformed by {@code * mapper}. */ public StringWithMacros mapStrings(Function<String, String> mapper) { return StringWithMacros.of( RichStream.from(getParts()) .map(e -> e.isRight() ? e : Either.<String, Macro>ofLeft(mapper.apply(e.getLeft()))) .toImmutableList()); } @Override public Optional<StringWithMacros> translateTargets( CellPathResolver cellPathResolver, BuildTargetPatternParser<BuildTargetPattern> pattern, TargetNodeTranslator translator) { boolean modified = false; ImmutableList.Builder<Either<String, Macro>> parts = ImmutableList.builder(); for (Either<String, Macro> part : getParts()) { if (part.isLeft()) { parts.add(part); } else { Optional<Macro> translated = translator.translate(cellPathResolver, pattern, part.getRight()); if (translated.isPresent()) { parts.add(Either.ofRight(translated.get())); modified = true; } else { parts.add(part); } } } return modified ? Optional.of(StringWithMacros.of(parts.build())) : Optional.empty(); } }