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    @Override
190    public CheckInScmResult checkIn(ScmRepository repository, ScmFileSet fileSet, CommandParameters parameters)
191            throws ScmException {
192        return (CheckInScmResult) getCheckInCommand().execute(repository.getProviderRepository(), fileSet, parameters);
193    }
194
195    protected abstract GitCommand getCheckOutCommand();
196
197    /** {@inheritDoc} */
198    public CheckOutScmResult checkout(
199            ScmProviderRepository repository, ScmFileSet fileSet, CommandParameters parameters) throws ScmException {
200        return (CheckOutScmResult) executeCommand(getCheckOutCommand(), repository, fileSet, parameters);
201    }
202
203    protected abstract GitCommand getDiffCommand();
204
205    /** {@inheritDoc} */
206    public DiffScmResult diff(ScmProviderRepository repository, ScmFileSet fileSet, CommandParameters parameters)
207            throws ScmException {
208        return (DiffScmResult) executeCommand(getDiffCommand(), repository, fileSet, parameters);
209    }
210
211    protected abstract GitCommand getExportCommand();
212
213    /** {@inheritDoc} */
214    protected ExportScmResult export(ScmProviderRepository repository, ScmFileSet fileSet, CommandParameters parameters)
215            throws ScmException {
216        return (ExportScmResult) executeCommand(getExportCommand(), repository, fileSet, parameters);
217    }
218
219    protected abstract GitCommand getRemoveCommand();
220
221    /** {@inheritDoc} */
222    public RemoveScmResult remove(ScmProviderRepository repository, ScmFileSet fileSet, CommandParameters parameters)
223            throws ScmException {
224        return (RemoveScmResult) executeCommand(getRemoveCommand(), repository, fileSet, parameters);
225    }
226
227    protected abstract GitCommand getStatusCommand();
228
229    /** {@inheritDoc} */
230    public StatusScmResult status(ScmProviderRepository repository, ScmFileSet fileSet, CommandParameters parameters)
231            throws ScmException {
232        return (StatusScmResult) executeCommand(getStatusCommand(), repository, fileSet, parameters);
233    }
234
235    protected abstract GitCommand getTagCommand();
236
237    /** {@inheritDoc} */
238    public TagScmResult tag(ScmProviderRepository repository, ScmFileSet fileSet, CommandParameters parameters)
239            throws ScmException {
240        return (TagScmResult) executeCommand(getTagCommand(), repository, fileSet, parameters);
241    }
242
243    protected abstract GitCommand getUntagCommand();
244
245    /** {@inheritDoc} */
246    public UntagScmResult untag(ScmRepository repository, ScmFileSet fileSet, CommandParameters parameters)
247            throws ScmException {
248        return (UntagScmResult)
249                executeCommand(getUntagCommand(), repository.getProviderRepository(), fileSet, parameters);
250    }
251
252    protected abstract GitCommand getUpdateCommand();
253
254    /** {@inheritDoc} */
255    public UpdateScmResult update(ScmProviderRepository repository, ScmFileSet fileSet, CommandParameters parameters)
256            throws ScmException {
257        return (UpdateScmResult) executeCommand(getUpdateCommand(), repository, fileSet, parameters);
258    }
259
260    protected ScmResult executeCommand(
261            GitCommand command, ScmProviderRepository repository, ScmFileSet fileSet, CommandParameters parameters)
262            throws ScmException {
263        return command.execute(repository, fileSet, parameters);
264    }
265
266    protected abstract GitCommand getInfoCommand();
267
268    public InfoScmResult info(ScmProviderRepository repository, ScmFileSet fileSet, CommandParameters parameters)
269            throws ScmException {
270        GitCommand cmd = getInfoCommand();
271
272        return (InfoScmResult) executeCommand(cmd, repository, fileSet, parameters);
273    }
274
275    /** {@inheritDoc} */
276    protected BlameScmResult blame(ScmProviderRepository repository, ScmFileSet fileSet, CommandParameters parameters)
277            throws ScmException {
278        GitCommand cmd = getBlameCommand();
279
280        return (BlameScmResult) executeCommand(cmd, repository, fileSet, parameters);
281    }
282
283    protected abstract GitCommand getBlameCommand();
284
285    /** {@inheritDoc} */
286    public RemoteInfoScmResult remoteInfo(
287            ScmProviderRepository repository, ScmFileSet fileSet, CommandParameters parameters) throws ScmException {
288        GitCommand cmd = getRemoteInfoCommand();
289
290        return (RemoteInfoScmResult) executeCommand(cmd, repository, fileSet, parameters);
291    }
292
293    protected abstract GitCommand getRemoteInfoCommand();
294}