mirror of https://github.com/apache/archiva.git
Adding recursive delete with cumulated result status to FileUtils
This commit is contained in:
parent
33bfded28d
commit
dfe9604884
|
@ -52,6 +52,12 @@
|
|||
<scope>test</scope>
|
||||
</dependency>
|
||||
|
||||
<dependency>
|
||||
<groupId>org.apache.logging.log4j</groupId>
|
||||
<artifactId>log4j-slf4j-impl</artifactId>
|
||||
<scope>test</scope>
|
||||
</dependency>
|
||||
|
||||
</dependencies>
|
||||
<build>
|
||||
<pluginManagement>
|
||||
|
|
|
@ -0,0 +1,72 @@
|
|||
/*
|
||||
* Licensed to the Apache Software Foundation (ASF) under one
|
||||
* or more contributor license agreements. See the NOTICE file
|
||||
* distributed with this work for additional information
|
||||
* regarding copyright ownership. The ASF licenses this file
|
||||
* to you under the Apache License, Version 2.0 (the
|
||||
* "License"); you may not use this file except in compliance
|
||||
* with the License. You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
* Unless required by applicable law or agreed to in writing,
|
||||
* software distributed under the License is distributed on an
|
||||
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
|
||||
* KIND, either express or implied. See the License for the
|
||||
* specific language governing permissions and limitations
|
||||
* under the License.
|
||||
*/
|
||||
|
||||
package org.apache.archiva.common.utils;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.nio.file.Path;
|
||||
|
||||
/**
|
||||
* File operation status for a given file.
|
||||
*
|
||||
* @author Martin Stockhammer <martin_s@apache.org>
|
||||
*/
|
||||
public class FileStatus
|
||||
{
|
||||
final private Path path;
|
||||
final private StatusResult result;
|
||||
final private IOException exception;
|
||||
|
||||
/**
|
||||
* Success status
|
||||
*
|
||||
* @param path the file path
|
||||
* @param statusResult the status of the file operation
|
||||
*/
|
||||
FileStatus( Path path, StatusResult statusResult) {
|
||||
this.path = path;
|
||||
this.result = statusResult;
|
||||
this.exception = null;
|
||||
}
|
||||
|
||||
/**
|
||||
* Error status
|
||||
* @param path the file path
|
||||
* @param e the exception, that occured during the file operation
|
||||
*/
|
||||
FileStatus( Path path, IOException e) {
|
||||
this.path = path;
|
||||
this.result = StatusResult.ERROR;
|
||||
this.exception = e;
|
||||
}
|
||||
|
||||
public IOException getException( )
|
||||
{
|
||||
return exception;
|
||||
}
|
||||
|
||||
public Path getPath( )
|
||||
{
|
||||
return path;
|
||||
}
|
||||
|
||||
public StatusResult getResult( )
|
||||
{
|
||||
return result;
|
||||
}
|
||||
}
|
|
@ -29,6 +29,7 @@ import java.nio.file.Paths;
|
|||
import java.nio.file.StandardOpenOption;
|
||||
import java.util.Comparator;
|
||||
import java.util.Optional;
|
||||
import java.util.stream.Stream;
|
||||
import java.util.zip.ZipEntry;
|
||||
import java.util.zip.ZipFile;
|
||||
|
||||
|
@ -46,14 +47,17 @@ public class FileUtils {
|
|||
* @param dir
|
||||
*/
|
||||
public static void deleteQuietly(Path dir) {
|
||||
try {
|
||||
Files.walk(dir)
|
||||
.sorted(Comparator.reverseOrder())
|
||||
try(Stream<Path> stream = Files.walk(dir)) {
|
||||
stream
|
||||
.sorted( Comparator.reverseOrder() )
|
||||
.forEach(file -> {
|
||||
try {
|
||||
Files.delete(file);
|
||||
} catch (IOException e) {
|
||||
// Ignore this
|
||||
if (log.isDebugEnabled()) {
|
||||
log.debug( "Exception during file delete: {}", e.getMessage( ), e );
|
||||
}
|
||||
}
|
||||
|
||||
});
|
||||
|
@ -64,6 +68,38 @@ public class FileUtils {
|
|||
|
||||
}
|
||||
|
||||
public static IOStatus deleteDirectoryWithStatus(Path dir) throws IOException {
|
||||
if (!Files.exists(dir)) {
|
||||
IOStatus status = new IOStatus( );
|
||||
status.addError( dir, new FileNotFoundException( "Directory not found " + dir ) );
|
||||
return status;
|
||||
}
|
||||
if (!Files.isDirectory(dir)) {
|
||||
IOStatus status = new IOStatus( );
|
||||
status.addError(dir, new IOException("Given path is not a directory " + dir));
|
||||
}
|
||||
try( Stream<Path> stream = Files.walk(dir)) {
|
||||
return stream
|
||||
.sorted( Comparator.reverseOrder() )
|
||||
.map(file ->
|
||||
{
|
||||
try {
|
||||
Files.delete(file);
|
||||
return new FileStatus( file, StatusResult.DELETED );
|
||||
} catch (UncheckedIOException e) {
|
||||
log.warn("File could not be deleted {}", file);
|
||||
return new FileStatus( file, e.getCause( ) );
|
||||
}
|
||||
catch ( IOException e )
|
||||
{
|
||||
return new FileStatus( file, e );
|
||||
}
|
||||
}).collect( IOStatus::new, IOStatus::accumulate, IOStatus::combine );
|
||||
} catch (UncheckedIOException e) {
|
||||
throw new IOException("File deletion failed ", e);
|
||||
}
|
||||
}
|
||||
|
||||
public static void deleteDirectory(Path dir) throws IOException {
|
||||
if (!Files.exists(dir)) {
|
||||
return;
|
||||
|
@ -72,16 +108,16 @@ public class FileUtils {
|
|||
throw new IOException("Given path is not a directory " + dir);
|
||||
}
|
||||
boolean result = true;
|
||||
try {
|
||||
result = Files.walk(dir)
|
||||
.sorted(Comparator.reverseOrder())
|
||||
try(Stream<Path> stream = Files.walk(dir)) {
|
||||
result = stream
|
||||
.sorted( Comparator.reverseOrder() )
|
||||
.map(file ->
|
||||
{
|
||||
try {
|
||||
Files.delete(file);
|
||||
return Optional.of(Boolean.TRUE);
|
||||
} catch (UncheckedIOException | IOException e) {
|
||||
log.warn("File could not be deleted {}", file);
|
||||
log.warn("File could not be deleted {}: {}", file, e.getMessage());
|
||||
return Optional.empty();
|
||||
}
|
||||
|
||||
|
|
|
@ -0,0 +1,168 @@
|
|||
/*
|
||||
* Licensed to the Apache Software Foundation (ASF) under one
|
||||
* or more contributor license agreements. See the NOTICE file
|
||||
* distributed with this work for additional information
|
||||
* regarding copyright ownership. The ASF licenses this file
|
||||
* to you under the Apache License, Version 2.0 (the
|
||||
* "License"); you may not use this file except in compliance
|
||||
* with the License. You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
* Unless required by applicable law or agreed to in writing,
|
||||
* software distributed under the License is distributed on an
|
||||
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
|
||||
* KIND, either express or implied. See the License for the
|
||||
* specific language governing permissions and limitations
|
||||
* under the License.
|
||||
*/
|
||||
|
||||
package org.apache.archiva.common.utils;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.nio.file.Path;
|
||||
import java.util.Collections;
|
||||
import java.util.Map;
|
||||
import java.util.TreeMap;
|
||||
|
||||
/**
|
||||
*
|
||||
* Collects information about file system operational status, e.g. if a file could be deleted,
|
||||
* or IOException was thrown.
|
||||
*
|
||||
* @author Martin Stockhammer <martin_s@apache.org>
|
||||
*/
|
||||
public class IOStatus
|
||||
{
|
||||
|
||||
Map<Path,IOException> errorList;
|
||||
Map<Path, StatusResult> okList = new TreeMap<>( );
|
||||
|
||||
/**
|
||||
* Returns <code>true</code>, if no error was recorded.
|
||||
* @return
|
||||
*/
|
||||
boolean isOk() {
|
||||
return !hasErrors( );
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns <code>true</code>, if at least one error was recorded
|
||||
* @return
|
||||
*/
|
||||
boolean hasErrors() {
|
||||
if (errorList==null || errorList.size()==0) {
|
||||
return false;
|
||||
} else {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Accumulator method used for stream collecting
|
||||
*
|
||||
* @param ioStatus
|
||||
* @param fileStatus
|
||||
* @return
|
||||
*/
|
||||
public static IOStatus accumulate(IOStatus ioStatus, FileStatus fileStatus) {
|
||||
ioStatus.addStatus( fileStatus );
|
||||
return ioStatus;
|
||||
}
|
||||
|
||||
/**
|
||||
* Combiner used for stream collecting
|
||||
* @param ioStatus1
|
||||
* @param ioStatus2
|
||||
* @return
|
||||
*/
|
||||
public static IOStatus combine(IOStatus ioStatus1, IOStatus ioStatus2) {
|
||||
IOStatus status = new IOStatus( );
|
||||
status.addAllSuccess( ioStatus1.getSuccessFiles() );
|
||||
status.addAllSuccess( ioStatus2.getSuccessFiles( ) );
|
||||
status.addAllErrors( ioStatus1.getErrorFiles( ) );
|
||||
status.addAllErrors( ioStatus2.getErrorFiles( ) );
|
||||
return status;
|
||||
}
|
||||
|
||||
/**
|
||||
* Add the status for a specific file to this status collection.
|
||||
*
|
||||
* @param status the status for a given file
|
||||
* @return the status object itself
|
||||
*/
|
||||
public IOStatus addStatus(FileStatus status) {
|
||||
if (status.getResult()== StatusResult.ERROR) {
|
||||
addError( status.getPath( ), status.getException( ) );
|
||||
} else {
|
||||
addSuccess( status.getPath( ), status.getResult( ) );
|
||||
}
|
||||
return this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Adds an error to the status collection.
|
||||
*
|
||||
* @param path the file path
|
||||
* @param e the exception thrown during the file operation
|
||||
*/
|
||||
public void addError( Path path, IOException e) {
|
||||
if (errorList==null) {
|
||||
errorList = new TreeMap<>( );
|
||||
}
|
||||
errorList.put( path, e );
|
||||
}
|
||||
|
||||
/**
|
||||
* Adds multiple errors to the collection.
|
||||
*
|
||||
* @param errors the map of file, error pairs
|
||||
*/
|
||||
public void addAllErrors(Map<Path, IOException> errors) {
|
||||
if (errorList == null) {
|
||||
errorList = new TreeMap<>( );
|
||||
}
|
||||
errorList.putAll( errors );
|
||||
}
|
||||
|
||||
/**
|
||||
* Adds all successful states to the collection.
|
||||
*
|
||||
* @param success a map of file, StatusResult pairs
|
||||
*/
|
||||
public void addAllSuccess( Map<Path, StatusResult> success) {
|
||||
okList.putAll( success );
|
||||
}
|
||||
|
||||
/**
|
||||
* Add success status for a given file to the collection.
|
||||
*
|
||||
* @param path the file path
|
||||
* @param status the status of the file operation, e.g. DELETED
|
||||
*/
|
||||
public void addSuccess( Path path, StatusResult status) {
|
||||
okList.put( path, status );
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns all the recorded errors as map of path, exception pairs.
|
||||
* @return the map of path, exception pairs.
|
||||
*/
|
||||
public Map<Path, IOException> getErrorFiles() {
|
||||
if (errorList==null) {
|
||||
return Collections.emptyMap( );
|
||||
}
|
||||
return errorList;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns all the recorded successful operations.
|
||||
*
|
||||
* @return the map of path, StatusResult pairs
|
||||
*/
|
||||
public Map<Path, StatusResult> getSuccessFiles() {
|
||||
if (okList==null) {
|
||||
return Collections.emptyMap( );
|
||||
}
|
||||
return okList;
|
||||
}
|
||||
}
|
|
@ -0,0 +1,29 @@
|
|||
/*
|
||||
* Licensed to the Apache Software Foundation (ASF) under one
|
||||
* or more contributor license agreements. See the NOTICE file
|
||||
* distributed with this work for additional information
|
||||
* regarding copyright ownership. The ASF licenses this file
|
||||
* to you under the Apache License, Version 2.0 (the
|
||||
* "License"); you may not use this file except in compliance
|
||||
* with the License. You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
* Unless required by applicable law or agreed to in writing,
|
||||
* software distributed under the License is distributed on an
|
||||
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
|
||||
* KIND, either express or implied. See the License for the
|
||||
* specific language governing permissions and limitations
|
||||
* under the License.
|
||||
*/
|
||||
|
||||
package org.apache.archiva.common.utils;
|
||||
|
||||
/**
|
||||
* Result status for file operations.
|
||||
*
|
||||
* @author Martin Stockhammer <martin_s@apache.org>
|
||||
*/
|
||||
public enum StatusResult
|
||||
{
|
||||
DELETED, EXIST, ERROR
|
||||
}
|
|
@ -34,8 +34,7 @@ import java.nio.file.attribute.PosixFilePermission;
|
|||
import java.util.HashSet;
|
||||
import java.util.Set;
|
||||
|
||||
import static org.junit.Assert.assertFalse;
|
||||
import static org.junit.Assert.assertTrue;
|
||||
import static org.junit.Assert.*;
|
||||
|
||||
/**
|
||||
* @author Martin Stockhammer <martin_s@apache.org>
|
||||
|
@ -110,6 +109,43 @@ public class FileUtilsTest
|
|||
|
||||
}
|
||||
|
||||
|
||||
@Test
|
||||
public void testDeleteWithStatus() throws IOException
|
||||
{
|
||||
Path td = Files.createTempDirectory( "FileUtilsTest" );
|
||||
Path f1 = td.resolve("file1.txt");
|
||||
Path f2 = td.resolve("file2.txt");
|
||||
Path d1 = td.resolve("dir1");
|
||||
Files.createDirectory( d1 );
|
||||
Path d11 = d1.resolve("dir11");
|
||||
Files.createDirectory( d11 );
|
||||
Path f111 = d11.resolve("file111.txt");
|
||||
Path f112 = d11.resolve("file112.txt");
|
||||
Files.write(f1,"file1".getBytes());
|
||||
Files.write(f2, "file2".getBytes());
|
||||
Files.write(f111, "file111".getBytes());
|
||||
Files.write(f112, "file112".getBytes());
|
||||
assertTrue(Files.exists(d1));
|
||||
assertTrue(Files.exists(f1));
|
||||
assertTrue(Files.exists(f2));
|
||||
assertTrue(Files.exists(f111));
|
||||
assertTrue(Files.exists(f112));
|
||||
|
||||
IOStatus status = FileUtils.deleteDirectoryWithStatus( td );
|
||||
assertFalse(Files.exists(f1));
|
||||
assertFalse(Files.exists(f2));
|
||||
assertFalse(Files.exists(f111));
|
||||
assertFalse(Files.exists(f112));
|
||||
assertFalse(Files.exists(d1));
|
||||
|
||||
assertTrue( status.isOk( ) );
|
||||
assertFalse( status.hasErrors( ) );
|
||||
assertEquals( 7, status.getSuccessFiles( ).size( ) );
|
||||
assertEquals( 0, status.getErrorFiles( ).size() );
|
||||
}
|
||||
|
||||
|
||||
@Test
|
||||
public void testDeleteNonExist() throws IOException
|
||||
{
|
||||
|
|
|
@ -33,7 +33,7 @@
|
|||
</appenders>
|
||||
<loggers>
|
||||
<logger name="org.apache.archiva" level="info"/>
|
||||
<logger name="org.apache.archiva.repository.scanner" level="info"/>
|
||||
<logger name="org.apache.archiva.common.utils" level="info"
|
||||
<root level="error" includeLocation="true">
|
||||
<appender-ref ref="console"/>
|
||||
</root>
|
||||
|
|
Loading…
Reference in New Issue