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