001package org.apache.maven.wagon.providers.file;
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 java.io.BufferedInputStream;
023import java.io.BufferedOutputStream;
024import java.io.File;
025import java.io.FileInputStream;
026import java.io.FileNotFoundException;
027import java.io.IOException;
028import java.io.InputStream;
029import java.io.OutputStream;
030import java.util.ArrayList;
031import java.util.List;
032
033import org.apache.maven.wagon.ConnectionException;
034import org.apache.maven.wagon.InputData;
035import org.apache.maven.wagon.LazyFileOutputStream;
036import org.apache.maven.wagon.OutputData;
037import org.apache.maven.wagon.ResourceDoesNotExistException;
038import org.apache.maven.wagon.StreamWagon;
039import org.apache.maven.wagon.TransferFailedException;
040import org.apache.maven.wagon.authorization.AuthorizationException;
041import org.apache.maven.wagon.resource.Resource;
042import org.codehaus.plexus.util.FileUtils;
043import org.codehaus.plexus.util.StringUtils;
044
045/**
046 * Wagon Provider for Local File System
047 * 
048 * @author <a href="michal.maczka@dimatics.com">Michal Maczka</a>
049 *
050 * @plexus.component role="org.apache.maven.wagon.Wagon" role-hint="file" instantiation-strategy="per-lookup"
051 */
052public class FileWagon
053    extends StreamWagon
054{
055    public void fillInputData( InputData inputData )
056        throws TransferFailedException, ResourceDoesNotExistException
057    {
058        if ( getRepository().getBasedir() == null )
059        {
060            throw new TransferFailedException( "Unable to operate with a null basedir." );
061        }
062
063        Resource resource = inputData.getResource();
064
065        File file = new File( getRepository().getBasedir(), resource.getName() );
066
067        if ( !file.exists() )
068        {
069            throw new ResourceDoesNotExistException( "File: " + file + " does not exist" );
070        }
071
072        try
073        {
074            InputStream in = new BufferedInputStream( new FileInputStream( file ) );
075
076            inputData.setInputStream( in );
077
078            resource.setContentLength( file.length() );
079
080            resource.setLastModified( file.lastModified() );
081        }
082        catch ( FileNotFoundException e )
083        {
084            throw new TransferFailedException( "Could not read from file: " + file.getAbsolutePath(), e );
085        }
086    }
087
088    public void fillOutputData( OutputData outputData )
089        throws TransferFailedException
090    {
091        if ( getRepository().getBasedir() == null )
092        {
093            throw new TransferFailedException( "Unable to operate with a null basedir." );
094        }
095
096        Resource resource = outputData.getResource();
097
098        File file = new File( getRepository().getBasedir(), resource.getName() );
099
100        createParentDirectories( file );
101
102        OutputStream outputStream = new BufferedOutputStream( new LazyFileOutputStream( file ) );
103
104        outputData.setOutputStream( outputStream );
105    }
106
107    protected void openConnectionInternal()
108        throws ConnectionException
109    {
110        if ( getRepository() == null )
111        {
112            throw new ConnectionException( "Unable to operate with a null repository." );
113        }
114
115        if ( getRepository().getBasedir() == null )
116        {
117            // This condition is possible when using wagon-file under integration testing conditions.
118            fireSessionDebug( "Using a null basedir." );
119            return;
120        }
121
122        // Check the File repository exists
123        File basedir = new File( getRepository().getBasedir() );
124        if ( !basedir.exists() )
125        {
126            if ( !basedir.mkdirs() )
127            {
128                throw new ConnectionException( "Repository path " + basedir + " does not exist,"
129                                               + " and cannot be created." );
130            }
131        }
132
133        if ( !basedir.canRead() )
134        {
135            throw new ConnectionException( "Repository path " + basedir + " cannot be read" );
136        }
137    }
138
139    public void closeConnection()
140    {
141    }
142
143    public boolean supportsDirectoryCopy()
144    {
145        // TODO: should we test for null basedir here?
146        return true;
147    }
148
149    public void putDirectory( File sourceDirectory, String destinationDirectory )
150        throws TransferFailedException, ResourceDoesNotExistException, AuthorizationException
151    {
152        if ( getRepository().getBasedir() == null )
153        {
154            throw new TransferFailedException( "Unable to putDirectory() with a null basedir." );
155        }
156
157        File path = resolveDestinationPath( destinationDirectory );
158
159        try
160        {
161            /*
162             * Done to address issue found in HP-UX with regards to "." directory references. Details found in ..
163             * WAGON-30 - wagon-file failed when used by maven-site-plugin WAGON-33 - FileWagon#putDirectory() fails in
164             * HP-UX if destinationDirectory is "."
165             * http://www.nabble.com/With-maven-2.0.2-site%3Adeploy-doesn%27t-work-t934716.html for details. Using
166             * path.getCanonicalFile() ensures that the path is fully resolved before an attempt to create it. TODO:
167             * consider moving this to FileUtils.mkdirs()
168             */
169            File realFile = path.getCanonicalFile();
170            realFile.mkdirs();
171        }
172        catch ( IOException e )
173        {
174            // Fall back to standard way if getCanonicalFile() fails.
175            path.mkdirs();
176        }
177
178        if ( !path.exists() || !path.isDirectory() )
179        {
180            String emsg = "Could not make directory '" + path.getAbsolutePath() + "'.";
181
182            // Add assistive message in case of failure.
183            File basedir = new File( getRepository().getBasedir() );
184            if ( !basedir.canWrite() )
185            {
186                emsg += "  The base directory " + basedir + " is read-only.";
187            }
188
189            throw new TransferFailedException( emsg );
190        }
191
192        try
193        {
194            FileUtils.copyDirectoryStructure( sourceDirectory, path );
195        }
196        catch ( IOException e )
197        {
198            throw new TransferFailedException( "Error copying directory structure", e );
199        }
200    }
201
202    private File resolveDestinationPath( String destinationPath )
203    {
204        String basedir = getRepository().getBasedir();
205
206        destinationPath = StringUtils.replace( destinationPath, "\\", "/" );
207
208        File path;
209
210        if ( destinationPath.equals( "." ) )
211        {
212            path = new File( basedir );
213        }
214        else
215        {
216            path = new File( basedir, destinationPath );
217        }
218
219        return path;
220    }
221
222    public List<String> getFileList( String destinationDirectory )
223        throws TransferFailedException, ResourceDoesNotExistException, AuthorizationException
224    {
225        if ( getRepository().getBasedir() == null )
226        {
227            throw new TransferFailedException( "Unable to getFileList() with a null basedir." );
228        }
229
230        File path = resolveDestinationPath( destinationDirectory );
231
232        if ( !path.exists() )
233        {
234            throw new ResourceDoesNotExistException( "Directory does not exist: " + destinationDirectory );
235        }
236
237        if ( !path.isDirectory() )
238        {
239            throw new ResourceDoesNotExistException( "Path is not a directory: " + destinationDirectory );
240        }
241
242        File[] files = path.listFiles();
243
244        List<String> list = new ArrayList<String>( files.length );
245        for ( int i = 0; i < files.length; i++ )
246        {
247            String name = files[i].getName();
248            if ( files[i].isDirectory() && !name.endsWith( "/" ) )
249            {
250                name += "/";
251            }
252            list.add( name );
253        }
254        return list;
255    }
256
257    public boolean resourceExists( String resourceName )
258        throws TransferFailedException, AuthorizationException
259    {
260        if ( getRepository().getBasedir() == null )
261        {
262            throw new TransferFailedException( "Unable to getFileList() with a null basedir." );
263        }
264
265        File file = resolveDestinationPath( resourceName );
266
267        if ( resourceName.endsWith( "/" ) )
268        {
269            return file.isDirectory();
270        }
271        
272        return file.exists();
273    }
274}