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