| /* |
| * Copyright 2012-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.cli; |
| |
| import com.google.common.base.Function; |
| import com.google.common.base.Preconditions; |
| import com.google.common.collect.Lists; |
| |
| import java.util.List; |
| |
| /** |
| * In actual build files, Buck requires that build targets are well-formed, which means that they |
| * must start with a "//", followed by a path, and ending with the name of a build rule, which must |
| * be preceded by a colon. Although these are easy for Buck to parse, they are not always easy to |
| * type from the command line. For this reason, we are more lenient with the format of build targets |
| * when entered from the command line, keeping in mind that one of the easiest things for a user to |
| * do is tab-complete file paths. For this reason, the "//" and ":" are added, when appropriate. For |
| * example, if the following argument were specified on the command line when a build target was |
| * expected: |
| * <pre> |
| * src/com/facebook/orca |
| * </pre> |
| * then this normalizer would convert it to: |
| * <pre> |
| * //src/com/facebook/orca:orca |
| * </pre> |
| * It would also normalize it to the same thing if it contained a trailing slash: |
| * <pre> |
| * src/com/facebook/orca |
| * </pre> |
| * Similarly, if the argument were: |
| * <pre> |
| * src/com/facebook/orca:messenger |
| * </pre> |
| * then this normalizer would convert it to: |
| * <pre> |
| * //src/com/facebook/orca:messenger |
| * </pre> |
| * This makes it easier to tab-complete to the directory with the desired build target, and then |
| * append the name of the build target by typing it out. Note that because of how the normalizer |
| * works, it makes sense to name the most commonly built target in the package as the same name as |
| * the directory that contains it so that the entire target can be tab-completed when entered from |
| * the command line. |
| */ |
| class CommandLineBuildTargetNormalizer { |
| |
| /** Utility class: do not instantiate. */ |
| private CommandLineBuildTargetNormalizer() {} |
| |
| public static String normalizeBuildTargetIdentifier(final String buildTargetFromCommandLine) { |
| Preconditions.checkNotNull(buildTargetFromCommandLine); |
| |
| // Build rules in the root are weird, but they do happen. Special-case them. |
| if (buildTargetFromCommandLine.startsWith("//:")) { |
| return buildTargetFromCommandLine; |
| } |
| |
| // Add the colon, if necessary. |
| String target = buildTargetFromCommandLine; |
| int colonIndex = target.indexOf(':'); |
| if (colonIndex < 0) { |
| // Strip a trailing slash if there is no colon. |
| if (target.endsWith("/")) { |
| target = target.substring(0, target.length() - 1); |
| } |
| |
| int lastSlashIndex = target.lastIndexOf('/'); |
| if (lastSlashIndex < 0) { |
| target = target + ':' + target; |
| } else { |
| target = target + ':' + target.substring(lastSlashIndex + 1); |
| } |
| } else if (colonIndex != 0) { |
| char charBeforeColon = target.charAt(colonIndex - 1); |
| if (charBeforeColon == '/') { |
| target = target.substring(0, colonIndex - 1) + target.substring(colonIndex); |
| } |
| } |
| |
| // Add the double slash prefix, if necessary. |
| if (!target.startsWith("//")) { |
| target = "//" + target; |
| } |
| |
| return target; |
| } |
| |
| public static List<String> normalizeAll(final BuckConfig buckConfig, List<String> arguments) { |
| // When transforming command-line arguments, first check to see whether it is an alias in the |
| // BuckConfig. If so, return the value associated with the alias. Otherwise, try normalize(). |
| return Lists.transform(arguments, new Function<String, String>() { |
| @Override |
| public String apply(String arg) { |
| String aliasValue = buckConfig.getBuildTargetForAlias(arg); |
| if (aliasValue != null) { |
| return aliasValue; |
| } else { |
| return CommandLineBuildTargetNormalizer.normalize.apply(arg); |
| } |
| } |
| }); |
| } |
| |
| public static final Function<String, String> normalize = new Function<String, String>() { |
| |
| @Override |
| public String apply(String target) { |
| return normalizeBuildTargetIdentifier(target); |
| } |
| |
| }; |
| } |