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