001package org.apache.maven.scm.provider.hg;
002
003/*
004 * Licensed to the Apache Software Foundation (ASF) under one
005 * or more contributor license agreements.  See the NOTICE file
006 * distributed with this work for additional information
007 * regarding copyright ownership.  The ASF licenses this file
008 * to you under the Apache License, Version 2.0 (the
009 * "License"); you may not use this file except in compliance
010 * with the License.  You may obtain a copy of the License at
011 *
012 * http://www.apache.org/licenses/LICENSE-2.0
013 *
014 * Unless required by applicable law or agreed to in writing,
015 * software distributed under the License is distributed on an
016 * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
017 * KIND, either express or implied.  See the License for the
018 * specific language governing permissions and limitations
019 * under the License.
020 */
021
022import org.apache.maven.scm.ScmException;
023import org.apache.maven.scm.ScmFileStatus;
024import org.apache.maven.scm.log.DefaultLog;
025import org.apache.maven.scm.provider.hg.command.HgCommandConstants;
026import org.apache.maven.scm.provider.hg.command.HgConsumer;
027import org.codehaus.plexus.util.cli.Commandline;
028
029import java.io.File;
030
031/**
032 * Check hg installation.
033 *
034 * @author <a href="mailto:thurner.rupert@ymono.net">thurner rupert</a>
035 * @author <a href="mailto:ryan@darksleep.com">ryan daum</a>
036 *
037 */
038public class HgConfig
039{
040    //Minimum version for the Hg SCM
041    private static final String HG_REQ = "0.9.2";
042
043    // The string which indicates the beginning of the Mercurial line
044    private static final String HG_VERSION_TAG = "ercurial Distributed SCM (version ";
045
046    // URL to download mercurial from
047    private static final String HG_INSTALL_URL = "'http://www.selenic.com/mercurial/wiki/index.cgi/Download'";
048
049    //Configuration to check with default values (not installed)
050    private HgVersionConsumer hgVersion = new HgVersionConsumer( null );
051
052    HgConfig( File workingDir )
053    {
054        try
055        {
056            hgVersion = getHgVersion( workingDir );
057        }
058        catch ( ScmException e )
059        {
060            //Ignore -  is not installed.
061            //This is already recorded thus we do not generate more info.
062        }
063
064    }
065
066    /**
067     * @return True if one can run basic hg commands
068     */
069    private boolean isInstalled()
070    {
071        return hgVersion.isVersionOk( HG_REQ );
072    }
073
074    /**
075     * @return True if all modules for hg are installed.
076     */
077    private boolean isComplete()
078    {
079        return isInstalled();
080    }
081
082    // Consumer to find the Mercurial version
083    public static HgVersionConsumer getHgVersion( File workingDir )
084        throws ScmException
085    {
086        String[] versionCmd = new String[]{HgCommandConstants.VERSION};
087        HgVersionConsumer consumer = new HgVersionConsumer( HG_VERSION_TAG );
088        Commandline cmd = HgUtils.buildCmd( workingDir, versionCmd );
089
090        // Execute command
091        HgUtils.executeCmd( consumer, cmd );
092
093        // Return result
094        return consumer;
095    }
096
097
098    /**
099     * Iterate through two dot-notation version strings, normalize them to the same length, then
100     * do alphabetic comparison
101     *
102     * @param version1
103     * @param version2
104     * @return true if version2 is greater than version1
105     */
106    private static boolean compareVersion( String version1, String version2 )
107    {
108        int l1, l2;
109        String v1, v2;
110
111        v1 = version1;
112        v2 = version2;
113        l1 = version1.length();
114        l2 = version2.length();
115
116        if ( l1 > l2 )
117        {
118            for ( int x = l2; x >= l1; x-- )
119            {
120                v2 += ' ';
121            }
122        }
123        if ( l2 > l1 )
124        {
125            for ( int x = l1; x <= l2; x++ )
126            {
127                v1 += ' ';
128            }
129        }
130
131        return v2.compareTo( v1 ) >= 0;
132    }
133
134
135    /**
136     * Get version of the executable.
137     * Version is resolved by splitting the line starting with the version tag and finding
138     * the second last word.
139     */
140    private static class HgVersionConsumer
141        extends HgConsumer
142    {
143
144        private String versionStr = "NA";
145
146        private String versionTag;
147
148        HgVersionConsumer( String versionTag )
149        {
150            super( new DefaultLog() );
151            this.versionTag = versionTag;
152        }
153
154        public void doConsume( ScmFileStatus status, String line )
155        {
156            if ( line.startsWith( versionTag ) )
157            {
158                String[] elements = line.split( " " );
159                versionStr = elements[elements.length - 1].split( "\\)" )[0];
160            }
161        }
162
163        String getVersion()
164        {
165            return versionStr;
166        }
167
168        boolean isVersionOk( String version )
169        {
170            // build one number out of the whole version #
171
172            return compareVersion( version, versionStr );
173        }
174    }
175
176    private String getInstalledStr()
177    {
178        if ( isComplete() )
179        {
180            return "valid and complete.";
181        }
182        return ( isInstalled() ? "incomplete. " : "invalid. " ) + "Consult " + HG_INSTALL_URL;
183    }
184
185    public String toString( File workingDir )
186    {
187        boolean hgOk = hgVersion.isVersionOk( HG_REQ );
188        return "\n  Your Hg installation seems to be " + getInstalledStr() + "\n    Hg version: "
189            + hgVersion.getVersion() + ( hgOk ? " (OK)" : " (May be INVALID)" ) + "\n";
190    }
191}