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.hg;
020
021import javax.inject.Named;
022import javax.inject.Singleton;
023
024import java.io.File;
025import java.util.ArrayList;
026import java.util.List;
027
028import org.apache.maven.scm.CommandParameters;
029import org.apache.maven.scm.ScmException;
030import org.apache.maven.scm.ScmFileSet;
031import org.apache.maven.scm.command.add.AddScmResult;
032import org.apache.maven.scm.command.blame.BlameScmResult;
033import org.apache.maven.scm.command.branch.BranchScmResult;
034import org.apache.maven.scm.command.changelog.ChangeLogScmResult;
035import org.apache.maven.scm.command.checkin.CheckInScmResult;
036import org.apache.maven.scm.command.checkout.CheckOutScmResult;
037import org.apache.maven.scm.command.diff.DiffScmResult;
038import org.apache.maven.scm.command.info.InfoScmResult;
039import org.apache.maven.scm.command.list.ListScmResult;
040import org.apache.maven.scm.command.remove.RemoveScmResult;
041import org.apache.maven.scm.command.status.StatusScmResult;
042import org.apache.maven.scm.command.tag.TagScmResult;
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.hg.command.add.HgAddCommand;
047import org.apache.maven.scm.provider.hg.command.blame.HgBlameCommand;
048import org.apache.maven.scm.provider.hg.command.branch.HgBranchCommand;
049import org.apache.maven.scm.provider.hg.command.changelog.HgChangeLogCommand;
050import org.apache.maven.scm.provider.hg.command.checkin.HgCheckInCommand;
051import org.apache.maven.scm.provider.hg.command.checkout.HgCheckOutCommand;
052import org.apache.maven.scm.provider.hg.command.diff.HgDiffCommand;
053import org.apache.maven.scm.provider.hg.command.info.HgInfoCommand;
054import org.apache.maven.scm.provider.hg.command.inventory.HgListCommand;
055import org.apache.maven.scm.provider.hg.command.remove.HgRemoveCommand;
056import org.apache.maven.scm.provider.hg.command.status.HgStatusCommand;
057import org.apache.maven.scm.provider.hg.command.tag.HgTagCommand;
058import org.apache.maven.scm.provider.hg.command.update.HgUpdateCommand;
059import org.apache.maven.scm.provider.hg.repository.HgScmProviderRepository;
060import org.apache.maven.scm.repository.ScmRepositoryException;
061import org.apache.maven.scm.repository.UnknownRepositoryStructure;
062
063/**
064 * <a href="https://www.mercurial-scm.org/">Mercurial (HG)</a> is a decentralized revision control system.
065 *
066 * @author <a href="mailto:thurner.rupert@ymono.net">thurner rupert</a>
067 */
068@Singleton
069@Named("hg")
070public class HgScmProvider extends AbstractScmProvider {
071    /**
072     * {@inheritDoc}
073     */
074    public String getScmSpecificFilename() {
075        return ".hg";
076    }
077
078    private static class HgUrlParserResult {
079        private final List<String> messages = new ArrayList<>();
080
081        private ScmProviderRepository repository;
082    }
083
084    /**
085     * {@inheritDoc}
086     */
087    public ScmProviderRepository makeProviderScmRepository(String scmSpecificUrl, char delimiter)
088            throws ScmRepositoryException {
089        HgUrlParserResult result = parseScmUrl(scmSpecificUrl);
090
091        if (result.messages.size() > 0) {
092            throw new ScmRepositoryException("The scm url is invalid.", result.messages);
093        }
094
095        return result.repository;
096    }
097
098    private HgUrlParserResult parseScmUrl(String scmSpecificUrl) {
099        HgUrlParserResult result = new HgUrlParserResult();
100
101        // ----------------------------------------------------------------------
102        // Do some sanity checking of the SVN url
103        // ----------------------------------------------------------------------
104
105        if (scmSpecificUrl.startsWith("file")) {
106            if (!scmSpecificUrl.startsWith("file:///") && !scmSpecificUrl.startsWith("file://localhost/")) {
107                result.messages.add("An hg 'file' url must be on the form 'file:///' or 'file://localhost/'.");
108
109                return result;
110            }
111        } else if (scmSpecificUrl.startsWith("https")) {
112            if (!scmSpecificUrl.startsWith("https://")) {
113                result.messages.add("An hg 'http' url must be on the form 'https://'.");
114
115                return result;
116            }
117        } else if (scmSpecificUrl.startsWith("http")) {
118            if (!scmSpecificUrl.startsWith("http://")) {
119                result.messages.add("An hg 'http' url must be on the form 'http://'.");
120
121                return result;
122            }
123        } else {
124            try {
125                new File(scmSpecificUrl);
126            } catch (Throwable e) {
127                result.messages.add("The filename provided is not valid");
128
129                return result;
130            }
131        }
132
133        result.repository = new HgScmProviderRepository(scmSpecificUrl);
134
135        return result;
136    }
137
138    /**
139     * {@inheritDoc}
140     */
141    public ScmProviderRepository makeProviderScmRepository(File path)
142            throws ScmRepositoryException, UnknownRepositoryStructure {
143        if (path == null) {
144            throw new NullPointerException("Path argument is null");
145        }
146
147        if (!path.isDirectory()) {
148            throw new ScmRepositoryException(path.getAbsolutePath() + " isn't a valid directory.");
149        }
150
151        File hgDir = new File(path, ".hg");
152
153        if (!hgDir.exists()) {
154            throw new ScmRepositoryException(path.getAbsolutePath() + " isn't a hg directory.");
155        }
156
157        return makeProviderScmRepository(path.getAbsolutePath(), ':');
158    }
159
160    /**
161     * {@inheritDoc}
162     */
163    public List<String> validateScmUrl(String scmSpecificUrl, char delimiter) {
164        HgUrlParserResult result = parseScmUrl(scmSpecificUrl);
165
166        return result.messages;
167    }
168
169    /**
170     * {@inheritDoc}
171     */
172    public String getScmType() {
173        return "hg";
174    }
175
176    /**
177     * {@inheritDoc}
178     */
179    public AddScmResult add(ScmProviderRepository repository, ScmFileSet fileSet, CommandParameters parameters)
180            throws ScmException {
181        HgAddCommand command = new HgAddCommand();
182
183        return (AddScmResult) command.execute(repository, fileSet, parameters);
184    }
185
186    /**
187     * {@inheritDoc}
188     */
189    public ChangeLogScmResult changelog(
190            ScmProviderRepository repository, ScmFileSet fileSet, CommandParameters parameters) throws ScmException {
191        HgChangeLogCommand command = new HgChangeLogCommand();
192
193        return (ChangeLogScmResult) command.execute(repository, fileSet, parameters);
194    }
195
196    /**
197     * {@inheritDoc}
198     */
199    public CheckInScmResult checkin(ScmProviderRepository repository, ScmFileSet fileSet, CommandParameters parameters)
200            throws ScmException {
201        HgCheckInCommand command = new HgCheckInCommand();
202
203        return (CheckInScmResult) command.execute(repository, fileSet, parameters);
204    }
205
206    /**
207     * {@inheritDoc}
208     */
209    public CheckOutScmResult checkout(
210            ScmProviderRepository repository, ScmFileSet fileSet, CommandParameters parameters) throws ScmException {
211        HgCheckOutCommand command = new HgCheckOutCommand();
212
213        return (CheckOutScmResult) command.execute(repository, fileSet, parameters);
214    }
215
216    /**
217     * {@inheritDoc}
218     */
219    public TagScmResult tag(ScmProviderRepository repository, ScmFileSet fileSet, CommandParameters parameters)
220            throws ScmException {
221        HgTagCommand command = new HgTagCommand();
222
223        return (TagScmResult) command.execute(repository, fileSet, parameters);
224    }
225
226    /**
227     * {@inheritDoc}
228     */
229    public DiffScmResult diff(ScmProviderRepository repository, ScmFileSet fileSet, CommandParameters parameters)
230            throws ScmException {
231        HgDiffCommand command = new HgDiffCommand();
232
233        return (DiffScmResult) command.execute(repository, fileSet, parameters);
234    }
235
236    /**
237     * {@inheritDoc}
238     */
239    public RemoveScmResult remove(ScmProviderRepository repository, ScmFileSet fileSet, CommandParameters parameters)
240            throws ScmException {
241        HgRemoveCommand command = new HgRemoveCommand();
242
243        return (RemoveScmResult) command.execute(repository, fileSet, parameters);
244    }
245
246    /**
247     * {@inheritDoc}
248     */
249    public StatusScmResult status(ScmProviderRepository repository, ScmFileSet fileSet, CommandParameters parameters)
250            throws ScmException {
251        HgStatusCommand command = new HgStatusCommand();
252
253        return (StatusScmResult) command.execute(repository, fileSet, parameters);
254    }
255
256    /**
257     * {@inheritDoc}
258     */
259    public UpdateScmResult update(ScmProviderRepository repository, ScmFileSet fileSet, CommandParameters parameters)
260            throws ScmException {
261        HgUpdateCommand command = new HgUpdateCommand();
262
263        return (UpdateScmResult) command.execute(repository, fileSet, parameters);
264    }
265
266    /**
267     * {@inheritDoc}
268     */
269    protected BlameScmResult blame(ScmProviderRepository repository, ScmFileSet fileSet, CommandParameters parameters)
270            throws ScmException {
271        HgBlameCommand command = new HgBlameCommand();
272
273        return (BlameScmResult) command.execute(repository, fileSet, parameters);
274    }
275
276    /**
277     * {@inheritDoc}
278     */
279    public BranchScmResult branch(ScmProviderRepository repository, ScmFileSet fileSet, CommandParameters parameters)
280            throws ScmException {
281        HgBranchCommand command = new HgBranchCommand();
282
283        return (BranchScmResult) command.execute(repository, fileSet, parameters);
284    }
285
286    /**
287     * @since 1.5
288     */
289    @Override
290    protected ListScmResult list(ScmProviderRepository repository, ScmFileSet fileSet, CommandParameters parameters)
291            throws ScmException {
292        HgListCommand hgListCommand = new HgListCommand();
293
294        return (ListScmResult) hgListCommand.executeCommand(repository, fileSet, parameters);
295    }
296
297    /**
298     * Returns result of hg id -i.
299     *
300     * @see org.apache.maven.scm.provider.AbstractScmProvider#info(org.apache.maven.scm.provider.ScmProviderRepository, org.apache.maven.scm.ScmFileSet, org.apache.maven.scm.CommandParameters)
301     * @since 1.5
302     */
303    @Override
304    public InfoScmResult info(ScmProviderRepository repository, ScmFileSet fileSet, CommandParameters parameters)
305            throws ScmException {
306        HgInfoCommand infoCommand = new HgInfoCommand();
307
308        return (InfoScmResult) infoCommand.execute(repository, fileSet, parameters);
309    }
310}