18
18
*/
19
19
package org .eclipse .aether .transport .file ;
20
20
21
+ import java .io .IOException ;
22
+ import java .io .UncheckedIOException ;
21
23
import java .nio .ByteBuffer ;
22
24
import java .nio .channels .FileChannel ;
25
+ import java .nio .file .FileSystem ;
23
26
import java .nio .file .Files ;
24
27
import java .nio .file .Path ;
25
28
28
31
import org .eclipse .aether .spi .connector .transport .PeekTask ;
29
32
import org .eclipse .aether .spi .connector .transport .PutTask ;
30
33
import org .eclipse .aether .spi .connector .transport .TransportTask ;
31
- import org .eclipse .aether .transfer .NoTransporterException ;
34
+
35
+ import static java .util .Objects .requireNonNull ;
32
36
33
37
/**
34
- * A transporter using {@link java.io.File}.
38
+ * A transporter using {@link java.nio.file.Path} that is reading and writing from specified base directory
39
+ * of given {@link java.nio.file.FileSystem}. It supports multiple {@link WriteOp} and obeys read-only property.
35
40
*/
36
41
final class FileTransporter extends AbstractTransporter {
37
42
/**
38
- * The file op transport can use.
43
+ * The write operation transport can use to write contents to the target (usually in local repository) of the
44
+ * file in remote repository reached by this transporter. Historically, and in some special cases (ZIP file system),
45
+ * it is only {@link #COPY} that can be used.
46
+ * <p>
47
+ * In case when contents of remote repository reached by this transport and target are on same volume,
48
+ * then {@link #SYMLINK} and {@link #HARDLINK} can be used as well, to reduce storage redundancy. Still, Resolver
49
+ * cannot do much smartness here, it is user who should evaluate this possibility, and if all conditions are met,
50
+ * apply it. Resolver does not try play smart here, it will obey configuration and most probably fail (ie cross
51
+ * volume hardlink).
39
52
*
40
53
* @since 2.0.2
41
54
*/
42
- enum FileOp {
55
+ enum WriteOp {
43
56
COPY ,
44
57
SYMLINK ,
45
58
HARDLINK ;
46
59
}
47
60
61
+ private final FileSystem fileSystem ;
62
+ private final boolean closeFileSystem ;
63
+ private final boolean writableFileSystem ;
48
64
private final Path basePath ;
49
- private final FileOp fileOp ;
65
+ private final WriteOp writeOp ;
66
+
67
+ FileTransporter (
68
+ FileSystem fileSystem ,
69
+ boolean closeFileSystem ,
70
+ boolean writableFileSystem ,
71
+ Path basePath ,
72
+ WriteOp writeOp ) {
73
+ this .fileSystem = requireNonNull (fileSystem );
74
+ this .closeFileSystem = closeFileSystem ;
75
+ this .writableFileSystem = writableFileSystem ;
76
+ this .basePath = requireNonNull (basePath );
77
+ this .writeOp = requireNonNull (writeOp );
50
78
51
- FileTransporter (Path basePath , FileOp fileOp ) throws NoTransporterException {
52
- this .basePath = basePath ;
53
- this .fileOp = fileOp ;
79
+ // sanity check
80
+ if (basePath .getFileSystem () != fileSystem ) {
81
+ throw new IllegalArgumentException ("basePath must originate from the fileSystem" );
82
+ }
54
83
}
55
84
56
85
Path getBasePath () {
@@ -65,12 +94,12 @@ public int classify(Throwable error) {
65
94
return ERROR_OTHER ;
66
95
}
67
96
68
- private FileOp effectiveFileOp (FileOp wanted , GetTask task ) {
97
+ private WriteOp effectiveFileOp (WriteOp wanted , GetTask task ) {
69
98
if (task .getDataPath () != null ) {
70
99
return wanted ;
71
100
}
72
- // task carries no path, caller wants in-memory read, so COPY must be used
73
- return FileOp .COPY ;
101
+ // not default FS or task carries no path ( caller wants in-memory read) = COPY must be used
102
+ return WriteOp .COPY ;
74
103
}
75
104
76
105
@ Override
@@ -82,7 +111,7 @@ protected void implPeek(PeekTask task) throws Exception {
82
111
protected void implGet (GetTask task ) throws Exception {
83
112
Path path = getPath (task , true );
84
113
long size = Files .size (path );
85
- FileOp effective = effectiveFileOp (fileOp , task );
114
+ WriteOp effective = effectiveFileOp (writeOp , task );
86
115
switch (effective ) {
87
116
case COPY :
88
117
utilGet (task , Files .newInputStream (path ), true , size , false );
@@ -91,7 +120,7 @@ protected void implGet(GetTask task) throws Exception {
91
120
case HARDLINK :
92
121
Files .deleteIfExists (task .getDataPath ());
93
122
task .getListener ().transportStarted (0L , size );
94
- if (effective == FileOp .HARDLINK ) {
123
+ if (effective == WriteOp .HARDLINK ) {
95
124
Files .createLink (task .getDataPath (), path );
96
125
} else {
97
126
Files .createSymbolicLink (task .getDataPath (), path );
@@ -113,12 +142,15 @@ protected void implGet(GetTask task) throws Exception {
113
142
}
114
143
break ;
115
144
default :
116
- throw new IllegalStateException ("Unknown fileOp" + fileOp );
145
+ throw new IllegalStateException ("Unknown fileOp " + writeOp );
117
146
}
118
147
}
119
148
120
149
@ Override
121
150
protected void implPut (PutTask task ) throws Exception {
151
+ if (!writableFileSystem ) {
152
+ throw new UnsupportedOperationException ("Read only FileSystem" );
153
+ }
122
154
Path path = getPath (task , false );
123
155
Files .createDirectories (path .getParent ());
124
156
try {
@@ -142,5 +174,13 @@ private Path getPath(TransportTask task, boolean required) throws Exception {
142
174
}
143
175
144
176
@ Override
145
- protected void implClose () {}
177
+ protected void implClose () {
178
+ if (closeFileSystem ) {
179
+ try {
180
+ fileSystem .close ();
181
+ } catch (IOException e ) {
182
+ throw new UncheckedIOException (e );
183
+ }
184
+ }
185
+ }
146
186
}
0 commit comments