001/*
002 * Licensed to the Apache Software Foundation (ASF) under one
003 * or more contributor license agreements.  See the NOTICE file
004 * distributed with this work for additional information
005 * regarding copyright ownership.  The ASF licenses this file
006 * to you under the Apache License, Version 2.0 (the
007 * "License"); you may not use this file except in compliance
008 * with the License.  You may obtain a copy of the License at
009 *
010 *   http://www.apache.org/licenses/LICENSE-2.0
011 *
012 * Unless required by applicable law or agreed to in writing,
013 * software distributed under the License is distributed on an
014 * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
015 * KIND, either express or implied.  See the License for the
016 * specific language governing permissions and limitations
017 * under the License.
018 */
019package org.apache.maven.scm.provider.git.gitexe.command.info;
020
021import java.io.File;
022import java.util.Collections;
023import java.util.LinkedList;
024import java.util.List;
025
026import org.apache.maven.scm.CommandParameter;
027import org.apache.maven.scm.CommandParameters;
028import org.apache.maven.scm.ScmException;
029import org.apache.maven.scm.ScmFileSet;
030import org.apache.maven.scm.ScmResult;
031import org.apache.maven.scm.command.AbstractCommand;
032import org.apache.maven.scm.command.info.InfoItem;
033import org.apache.maven.scm.command.info.InfoScmResult;
034import org.apache.maven.scm.provider.ScmProviderRepository;
035import org.apache.maven.scm.provider.git.command.GitCommand;
036import org.apache.maven.scm.provider.git.gitexe.command.GitCommandLineUtils;
037import org.codehaus.plexus.util.cli.CommandLineUtils;
038import org.codehaus.plexus.util.cli.Commandline;
039
040/**
041 * Uses {@code git log} command to retrieve info about the most recent commits related to specific files.
042 * @author Olivier Lamy
043 * @since 1.5
044 */
045public class GitInfoCommand extends AbstractCommand implements GitCommand {
046
047    public static final int NO_REVISION_LENGTH = -1;
048
049    @Override
050    protected ScmResult executeCommand(
051            ScmProviderRepository repository, ScmFileSet fileSet, CommandParameters parameters) throws ScmException {
052
053        Commandline baseCli = GitCommandLineUtils.getBaseGitCommandLine(fileSet.getBasedir(), "log");
054        baseCli.createArg().setValue("-1"); // only most recent commit matters
055        baseCli.createArg().setValue("--no-merges"); // skip merge commits
056        baseCli.addArg(GitInfoConsumer.getFormatArgument());
057
058        List<InfoItem> infoItems = new LinkedList<>();
059        if (fileSet.getFileList().isEmpty()) {
060            infoItems.add(executeInfoCommand(baseCli, parameters, fileSet.getBasedir()));
061        } else {
062            // iterate over files
063            for (File scmFile : fileSet.getFileList()) {
064                baseCli = GitCommandLineUtils.getBaseGitCommandLine(fileSet.getBasedir(), "log");
065                baseCli.createArg().setValue("-1"); // only most recent commit matters
066                baseCli.createArg().setValue("--no-merges"); // skip merge commits
067                baseCli.addArg(GitInfoConsumer.getFormatArgument());
068                // Insert a separator to make sure that files aren't interpreted as part of the version spec
069                baseCli.createArg().setValue("--");
070                GitCommandLineUtils.addTarget(baseCli, Collections.singletonList(scmFile));
071                infoItems.add(executeInfoCommand(baseCli, parameters, scmFile));
072            }
073        }
074        return new InfoScmResult(baseCli.toString(), infoItems);
075    }
076
077    protected InfoItem executeInfoCommand(Commandline cli, CommandParameters parameters, File scmFile)
078            throws ScmException {
079        GitInfoConsumer consumer = new GitInfoConsumer(scmFile.toPath(), getRevisionLength(parameters));
080        CommandLineUtils.StringStreamConsumer stderr = new CommandLineUtils.StringStreamConsumer();
081        int exitCode = GitCommandLineUtils.execute(cli, consumer, stderr);
082        if (exitCode != 0) {
083            throw new ScmException("The git log command failed: " + cli.toString() + " returned " + stderr.getOutput());
084        }
085        return consumer.getInfoItem();
086    }
087
088    /**
089     * Get the revision length from the parameters
090     *
091     * @param parameters
092     * @return -1 if parameter {@link CommandParameter.SCM_SHORT_REVISION_LENGTH} is absent, <br>
093     *         and otherwise - the length to be applied for the revision formatting
094     * @throws ScmException
095     * @since 1.7
096     */
097    private static int getRevisionLength(final CommandParameters parameters) throws ScmException {
098        if (parameters == null) {
099            return NO_REVISION_LENGTH;
100        } else {
101            return parameters.getInt(CommandParameter.SCM_SHORT_REVISION_LENGTH, NO_REVISION_LENGTH);
102        }
103    }
104}