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;
020
021import java.io.File;
022import java.util.ArrayList;
023import java.util.List;
024
025import org.apache.maven.scm.CommandParameters;
026import org.apache.maven.scm.ScmException;
027import org.apache.maven.scm.ScmFileSet;
028import org.apache.maven.scm.ScmResult;
029import org.apache.maven.scm.command.add.AddScmResult;
030import org.apache.maven.scm.command.blame.BlameScmResult;
031import org.apache.maven.scm.command.branch.BranchScmResult;
032import org.apache.maven.scm.command.changelog.ChangeLogScmResult;
033import org.apache.maven.scm.command.checkin.CheckInScmResult;
034import org.apache.maven.scm.command.checkout.CheckOutScmResult;
035import org.apache.maven.scm.command.diff.DiffScmResult;
036import org.apache.maven.scm.command.export.ExportScmResult;
037import org.apache.maven.scm.command.info.InfoScmResult;
038import org.apache.maven.scm.command.remoteinfo.RemoteInfoScmResult;
039import org.apache.maven.scm.command.remove.RemoveScmResult;
040import org.apache.maven.scm.command.status.StatusScmResult;
041import org.apache.maven.scm.command.tag.TagScmResult;
042import org.apache.maven.scm.command.untag.UntagScmResult;
043import org.apache.maven.scm.command.update.UpdateScmResult;
044import org.apache.maven.scm.provider.AbstractScmProvider;
045import org.apache.maven.scm.provider.ScmProviderRepository;
046import org.apache.maven.scm.provider.git.command.GitCommand;
047import org.apache.maven.scm.provider.git.repository.GitScmProviderRepository;
048import org.apache.maven.scm.repository.ScmRepository;
049import org.apache.maven.scm.repository.ScmRepositoryException;
050import org.apache.maven.scm.repository.UnknownRepositoryStructure;
051
052/**
053 * SCM Provider for git
054 *
055 *
056 * @author <a href="mailto:evenisse@apache.org">Emmanuel Venisse</a>
057 *
058 */
059public abstract class AbstractGitScmProvider extends AbstractScmProvider {
060
061    // ----------------------------------------------------------------------
062    //
063    // ----------------------------------------------------------------------
064
065    /**
066     * Internal class
067     */
068    private static class ScmUrlParserResult {
069        private final List<String> messages = new ArrayList<>();
070
071        private ScmProviderRepository repository;
072    }
073
074    // ----------------------------------------------------------------------
075    // ScmProvider Implementation
076    // ----------------------------------------------------------------------
077
078    /** {@inheritDoc} */
079    public String getScmSpecificFilename() {
080        return ".git";
081    }
082
083    /** {@inheritDoc} */
084    public ScmProviderRepository makeProviderScmRepository(String scmSpecificUrl, char delimiter)
085            throws ScmRepositoryException {
086        try {
087            ScmUrlParserResult result = parseScmUrl(scmSpecificUrl, delimiter);
088
089            if (result.messages.size() > 0) {
090                throw new ScmRepositoryException("The scm url " + scmSpecificUrl + " is invalid.", result.messages);
091            }
092
093            return result.repository;
094        } catch (ScmException e) {
095            // XXX We should allow throwing of SCMException.
096            throw new ScmRepositoryException("Error creating the scm repository", e);
097        }
098    }
099
100    /** {@inheritDoc} */
101    public ScmProviderRepository makeProviderScmRepository(File path)
102            throws ScmRepositoryException, UnknownRepositoryStructure {
103        if (path == null) {
104            throw new NullPointerException("Path argument is null");
105        }
106
107        if (!path.isDirectory()) {
108            throw new ScmRepositoryException(path.getAbsolutePath() + " isn't a valid directory.");
109        }
110
111        if (!new File(path, ".git").exists()) {
112            throw new ScmRepositoryException(path.getAbsolutePath() + " isn't a git checkout directory.");
113        }
114
115        try {
116            return makeProviderScmRepository(getRepositoryURL(path), ':');
117        } catch (ScmException e) {
118            // XXX We should allow throwing of SCMException.
119            throw new ScmRepositoryException("Error creating the scm repository", e);
120        }
121    }
122
123    protected abstract String getRepositoryURL(File path) throws ScmException;
124
125    /** {@inheritDoc} */
126    public List<String> validateScmUrl(String scmSpecificUrl, char delimiter) {
127        List<String> messages = new ArrayList<>();
128        try {
129            makeProviderScmRepository(scmSpecificUrl, delimiter);
130        } catch (ScmRepositoryException e) {
131            messages = e.getValidationMessages();
132        }
133        return messages;
134    }
135
136    /** {@inheritDoc} */
137    public String getScmType() {
138        return "git";
139    }
140
141    // ----------------------------------------------------------------------
142    //
143    // ----------------------------------------------------------------------
144
145    /**
146     * The git-submodule(1) command is available since Git 1.5.3, so modules will
147     * be activated in a later stage
148     */
149    private ScmUrlParserResult parseScmUrl(String scmSpecificUrl, char delimiter) throws ScmException {
150        ScmUrlParserResult result = new ScmUrlParserResult();
151
152        result.repository = new GitScmProviderRepository(scmSpecificUrl);
153
154        return result;
155    }
156
157    protected abstract GitCommand getAddCommand();
158
159    /** {@inheritDoc} */
160    public AddScmResult add(ScmProviderRepository repository, ScmFileSet fileSet, CommandParameters parameters)
161            throws ScmException {
162        return (AddScmResult) executeCommand(getAddCommand(), repository, fileSet, parameters);
163    }
164
165    protected abstract GitCommand getBranchCommand();
166
167    /** {@inheritDoc} */
168    protected BranchScmResult branch(ScmProviderRepository repository, ScmFileSet fileSet, CommandParameters parameters)
169            throws ScmException {
170        return (BranchScmResult) executeCommand(getBranchCommand(), repository, fileSet, parameters);
171    }
172
173    protected abstract GitCommand getChangeLogCommand();
174
175    /** {@inheritDoc} */
176    public ChangeLogScmResult changelog(
177            ScmProviderRepository repository, ScmFileSet fileSet, CommandParameters parameters) throws ScmException {
178        return (ChangeLogScmResult) executeCommand(getChangeLogCommand(), repository, fileSet, parameters);
179    }
180
181    protected abstract GitCommand getCheckInCommand();
182
183    /** {@inheritDoc} */
184    public CheckInScmResult checkin(ScmProviderRepository repository, ScmFileSet fileSet, CommandParameters parameters)
185            throws ScmException {
186        return (CheckInScmResult) executeCommand(getCheckInCommand(), repository, fileSet, parameters);
187    }
188
189    protected abstract GitCommand getCheckOutCommand();
190
191    /** {@inheritDoc} */
192    public CheckOutScmResult checkout(
193            ScmProviderRepository repository, ScmFileSet fileSet, CommandParameters parameters) throws ScmException {
194        return (CheckOutScmResult) executeCommand(getCheckOutCommand(), repository, fileSet, parameters);
195    }
196
197    protected abstract GitCommand getDiffCommand();
198
199    /** {@inheritDoc} */
200    public DiffScmResult diff(ScmProviderRepository repository, ScmFileSet fileSet, CommandParameters parameters)
201            throws ScmException {
202        return (DiffScmResult) executeCommand(getDiffCommand(), repository, fileSet, parameters);
203    }
204
205    protected abstract GitCommand getExportCommand();
206
207    /** {@inheritDoc} */
208    protected ExportScmResult export(ScmProviderRepository repository, ScmFileSet fileSet, CommandParameters parameters)
209            throws ScmException {
210        return (ExportScmResult) executeCommand(getExportCommand(), repository, fileSet, parameters);
211    }
212
213    protected abstract GitCommand getRemoveCommand();
214
215    /** {@inheritDoc} */
216    public RemoveScmResult remove(ScmProviderRepository repository, ScmFileSet fileSet, CommandParameters parameters)
217            throws ScmException {
218        return (RemoveScmResult) executeCommand(getRemoveCommand(), repository, fileSet, parameters);
219    }
220
221    protected abstract GitCommand getStatusCommand();
222
223    /** {@inheritDoc} */
224    public StatusScmResult status(ScmProviderRepository repository, ScmFileSet fileSet, CommandParameters parameters)
225            throws ScmException {
226        return (StatusScmResult) executeCommand(getStatusCommand(), repository, fileSet, parameters);
227    }
228
229    protected abstract GitCommand getTagCommand();
230
231    /** {@inheritDoc} */
232    public TagScmResult tag(ScmProviderRepository repository, ScmFileSet fileSet, CommandParameters parameters)
233            throws ScmException {
234        return (TagScmResult) executeCommand(getTagCommand(), repository, fileSet, parameters);
235    }
236
237    protected abstract GitCommand getUntagCommand();
238
239    /** {@inheritDoc} */
240    public UntagScmResult untag(ScmRepository repository, ScmFileSet fileSet, CommandParameters parameters)
241            throws ScmException {
242        return (UntagScmResult)
243                executeCommand(getUntagCommand(), repository.getProviderRepository(), fileSet, parameters);
244    }
245
246    protected abstract GitCommand getUpdateCommand();
247
248    /** {@inheritDoc} */
249    public UpdateScmResult update(ScmProviderRepository repository, ScmFileSet fileSet, CommandParameters parameters)
250            throws ScmException {
251        return (UpdateScmResult) executeCommand(getUpdateCommand(), repository, fileSet, parameters);
252    }
253
254    protected ScmResult executeCommand(
255            GitCommand command, ScmProviderRepository repository, ScmFileSet fileSet, CommandParameters parameters)
256            throws ScmException {
257        return command.execute(repository, fileSet, parameters);
258    }
259
260    protected abstract GitCommand getInfoCommand();
261
262    public InfoScmResult info(ScmProviderRepository repository, ScmFileSet fileSet, CommandParameters parameters)
263            throws ScmException {
264        GitCommand cmd = getInfoCommand();
265
266        return (InfoScmResult) executeCommand(cmd, repository, fileSet, parameters);
267    }
268
269    /** {@inheritDoc} */
270    protected BlameScmResult blame(ScmProviderRepository repository, ScmFileSet fileSet, CommandParameters parameters)
271            throws ScmException {
272        GitCommand cmd = getBlameCommand();
273
274        return (BlameScmResult) executeCommand(cmd, repository, fileSet, parameters);
275    }
276
277    protected abstract GitCommand getBlameCommand();
278
279    /** {@inheritDoc} */
280    public RemoteInfoScmResult remoteInfo(
281            ScmProviderRepository repository, ScmFileSet fileSet, CommandParameters parameters) throws ScmException {
282        GitCommand cmd = getRemoteInfoCommand();
283
284        return (RemoteInfoScmResult) executeCommand(cmd, repository, fileSet, parameters);
285    }
286
287    protected abstract GitCommand getRemoteInfoCommand();
288}