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.svn.svnexe.command.tag;
020
021import java.io.File;
022import java.io.IOException;
023import java.util.ArrayList;
024import java.util.Iterator;
025import java.util.List;
026
027import org.apache.commons.lang3.StringUtils;
028import org.apache.maven.scm.ScmException;
029import org.apache.maven.scm.ScmFile;
030import org.apache.maven.scm.ScmFileSet;
031import org.apache.maven.scm.ScmFileStatus;
032import org.apache.maven.scm.ScmResult;
033import org.apache.maven.scm.ScmTag;
034import org.apache.maven.scm.ScmTagParameters;
035import org.apache.maven.scm.command.tag.AbstractTagCommand;
036import org.apache.maven.scm.command.tag.TagScmResult;
037import org.apache.maven.scm.provider.ScmProviderRepository;
038import org.apache.maven.scm.provider.svn.SvnCommandUtils;
039import org.apache.maven.scm.provider.svn.SvnTagBranchUtils;
040import org.apache.maven.scm.provider.svn.command.SvnCommand;
041import org.apache.maven.scm.provider.svn.repository.SvnScmProviderRepository;
042import org.apache.maven.scm.provider.svn.svnexe.command.SvnCommandLineUtils;
043import org.codehaus.plexus.util.FileUtils;
044import org.codehaus.plexus.util.Os;
045import org.codehaus.plexus.util.cli.CommandLineException;
046import org.codehaus.plexus.util.cli.CommandLineUtils;
047import org.codehaus.plexus.util.cli.Commandline;
048
049/**
050 * @author <a href="mailto:brett@apache.org">Brett Porter</a>
051 * @author Olivier Lamy
052 *
053 * TODO since this is just a copy, use that instead.
054 */
055public class SvnTagCommand extends AbstractTagCommand implements SvnCommand {
056
057    public ScmResult executeTagCommand(ScmProviderRepository repo, ScmFileSet fileSet, String tag, String message)
058            throws ScmException {
059        ScmTagParameters scmTagParameters = new ScmTagParameters(message);
060        // force false to preserve backward comp
061        scmTagParameters.setRemoteTagging(false);
062        scmTagParameters.setPinExternals(false);
063        return executeTagCommand(repo, fileSet, tag, scmTagParameters);
064    }
065
066    /** {@inheritDoc} */
067    public ScmResult executeTagCommand(
068            ScmProviderRepository repo, ScmFileSet fileSet, String tag, ScmTagParameters scmTagParameters)
069            throws ScmException {
070        // NPE free
071        if (scmTagParameters == null) {
072            logger.debug("SvnTagCommand :: scmTagParameters is null create an empty one");
073            scmTagParameters = new ScmTagParameters();
074            scmTagParameters.setRemoteTagging(false);
075            scmTagParameters.setPinExternals(false);
076        } else {
077            logger.debug("SvnTagCommand :: scmTagParameters.remoteTagging : " + scmTagParameters.isRemoteTagging());
078        }
079        if (tag == null || tag.trim().isEmpty()) {
080            throw new ScmException("tag must be specified");
081        }
082
083        if (!fileSet.getFileList().isEmpty()) {
084            throw new ScmException("This provider doesn't support tagging subsets of a directory");
085        }
086
087        SvnScmProviderRepository repository = (SvnScmProviderRepository) repo;
088
089        File messageFile = FileUtils.createTempFile("maven-scm-", ".commit", null);
090
091        try {
092            FileUtils.fileWrite(messageFile.getAbsolutePath(), "UTF-8", scmTagParameters.getMessage());
093        } catch (IOException ex) {
094            return new TagScmResult(
095                    null,
096                    "Error while making a temporary file for the commit message: " + ex.getMessage(),
097                    null,
098                    false);
099        }
100
101        Commandline cl = createCommandLine(repository, fileSet.getBasedir(), tag, messageFile, scmTagParameters);
102
103        CommandLineUtils.StringStreamConsumer stdout = new CommandLineUtils.StringStreamConsumer();
104
105        CommandLineUtils.StringStreamConsumer stderr = new CommandLineUtils.StringStreamConsumer();
106
107        if (logger.isInfoEnabled()) {
108            logger.info("Executing: " + SvnCommandLineUtils.cryptPassword(cl));
109
110            if (Os.isFamily(Os.FAMILY_WINDOWS)) {
111                logger.info("Working directory: " + cl.getWorkingDirectory().getAbsolutePath());
112            }
113        }
114
115        int exitCode;
116
117        try {
118            exitCode = SvnCommandLineUtils.execute(cl, stdout, stderr);
119        } catch (CommandLineException ex) {
120            throw new ScmException("Error while executing command.", ex);
121        } finally {
122            try {
123                FileUtils.forceDelete(messageFile);
124            } catch (IOException ex) {
125                // ignore
126            }
127        }
128
129        if (exitCode != 0) {
130            // TODO: Improve this error message
131            return new TagScmResult(cl.toString(), "The svn tag command failed.", stderr.getOutput(), false);
132        }
133
134        List<ScmFile> fileList = new ArrayList<>();
135
136        List<File> files = null;
137
138        try {
139            if (StringUtils.isNotEmpty(fileSet.getExcludes())) {
140                files = FileUtils.getFiles(
141                        fileSet.getBasedir(),
142                        (StringUtils.isEmpty(fileSet.getIncludes()) ? "**" : fileSet.getIncludes()),
143                        fileSet.getExcludes() + ",**/.svn/**",
144                        false);
145            } else {
146                files = FileUtils.getFiles(
147                        fileSet.getBasedir(),
148                        (StringUtils.isEmpty(fileSet.getIncludes()) ? "**" : fileSet.getIncludes()),
149                        "**/.svn/**",
150                        false);
151            }
152        } catch (IOException e) {
153            throw new ScmException("Error while executing command.", e);
154        }
155
156        for (Iterator<File> i = files.iterator(); i.hasNext(); ) {
157            File f = i.next();
158
159            fileList.add(new ScmFile(f.getPath(), ScmFileStatus.TAGGED));
160        }
161
162        return new TagScmResult(cl.toString(), fileList);
163    }
164
165    // ----------------------------------------------------------------------
166    //
167    // ----------------------------------------------------------------------
168
169    /**
170     * @deprecated
171     * @param repository
172     * @param workingDirectory
173     * @param tag
174     * @param messageFile
175     * @return TODO
176     */
177    public static Commandline createCommandLine(
178            SvnScmProviderRepository repository, File workingDirectory, String tag, File messageFile) {
179        Commandline cl = SvnCommandLineUtils.getBaseSvnCommandLine(workingDirectory, repository);
180
181        cl.createArg().setValue("copy");
182
183        cl.createArg().setValue("--parents");
184
185        cl.createArg().setValue("--file");
186
187        cl.createArg().setValue(messageFile.getAbsolutePath());
188
189        cl.createArg().setValue(".");
190
191        // Note: this currently assumes you have the tag base checked out too
192        String tagUrl = SvnTagBranchUtils.resolveTagUrl(repository, new ScmTag(tag));
193        tagUrl = SvnCommandUtils.fixUrl(tagUrl, repository.getUser());
194        cl.createArg().setValue(tagUrl + "@");
195
196        return cl;
197    }
198
199    public static Commandline createCommandLine(
200            SvnScmProviderRepository repository,
201            File workingDirectory,
202            String tag,
203            File messageFile,
204            ScmTagParameters scmTagParameters) {
205        Commandline cl = SvnCommandLineUtils.getBaseSvnCommandLine(workingDirectory, repository);
206
207        cl.createArg().setValue("copy");
208
209        cl.createArg().setValue("--file");
210
211        cl.createArg().setValue(messageFile.getAbsolutePath());
212
213        cl.createArg().setValue("--encoding");
214
215        cl.createArg().setValue("UTF-8");
216
217        cl.createArg().setValue("--parents");
218
219        if (scmTagParameters != null && scmTagParameters.getScmRevision() != null) {
220            cl.createArg().setValue("--revision");
221
222            cl.createArg().setValue(scmTagParameters.getScmRevision());
223        }
224
225        if (scmTagParameters != null && scmTagParameters.isPinExternals()) {
226            cl.createArg().setValue("--pin-externals");
227        }
228
229        if (scmTagParameters != null && scmTagParameters.isRemoteTagging()) {
230            String url = SvnCommandUtils.fixUrl(repository.getUrl(), repository.getUser());
231            cl.createArg().setValue(url + "@");
232        } else {
233            cl.createArg().setValue(".");
234        }
235
236        // Note: this currently assumes you have the tag base checked out too
237        String tagUrl = SvnTagBranchUtils.resolveTagUrl(repository, new ScmTag(tag));
238        tagUrl = SvnCommandUtils.fixUrl(tagUrl, repository.getUser());
239        cl.createArg().setValue(tagUrl + "@");
240
241        return cl;
242    }
243}