001/* 002 * Copyright (C) 2022 - 2024, the original author or authors. 003 * 004 * Licensed under the Apache License, Version 2.0 (the "License"); 005 * you may not use this file except in compliance with the License. 006 * You may obtain a copy of the License at 007 * 008 * http://www.apache.org/licenses/LICENSE-2.0 009 * 010 * Unless required by applicable law or agreed to in writing, software 011 * distributed under the License is distributed on an "AS IS" BASIS, 012 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 013 * See the License for the specific language governing permissions and 014 * limitations under the License. 015 */ 016package io.github.ascopes.jct.workspaces; 017 018import java.io.File; 019import java.io.InputStream; 020import java.net.URL; 021import java.nio.charset.Charset; 022import java.nio.file.Path; 023import org.apiguardian.api.API; 024import org.apiguardian.api.API.Status; 025 026/** 027 * Chainable builder for creating individual files. 028 * 029 * @author Ashley Scopes 030 * @since 0.0.1 031 */ 032@API(since = "0.0.1", status = Status.STABLE) 033@SuppressWarnings("unused") 034public interface FileBuilder { 035 036 /** 037 * Take the directory, represented by the given {@link ManagedDirectory}, and convert it into a 038 * JAR file, that will be written to the file being created. 039 * 040 * @param directory the managed directory to use. 041 * @return the root managed directory for further configuration. 042 * @since 0.3.0 043 */ 044 @API(since = "0.3.0", status = Status.STABLE) 045 ManagedDirectory asJarFrom(PathRoot directory); 046 047 /** 048 * Take the directory, represented by the given path, and convert it into a JAR file, that will be 049 * written to the file being created. 050 * 051 * <pre><code> 052 * ManagedDirectory someDirectory = ...; 053 * someDirectory 054 * .createFile("first.jar") 055 * .asJarFrom(firstClassOutputs); 056 * var secondCompilation = secondCompiler.compile(secondWorkspace); 057 * ... 058 * </code></pre> 059 * 060 * @param directory the directory to use. 061 * @return the root managed directory for further configuration. 062 * @since 0.3.0 063 */ 064 @API(since = "0.3.0", status = Status.STABLE) 065 ManagedDirectory asJarFrom(Path directory); 066 067 /** 068 * Copy a resource from the given class loader into the file system. 069 * 070 * <pre><code> 071 * var classLoader = getClass().getClassLoader(); 072 * 073 * directory 074 * .createFile("org", "example", "HelloWorld.class") 075 * .copiedFromClassPath(classLoader, "org/example/HelloWorld.class"); 076 * </code></pre> 077 * 078 * @param classLoader the class loader to use. 079 * @param resource the resource to copy. 080 * @return the root managed directory for further configuration. 081 */ 082 ManagedDirectory copiedFromClassPath(ClassLoader classLoader, String resource); 083 084 /** 085 * Copy a resource from the class loader on the current thread into the file system. 086 * 087 * <pre><code> 088 * directory 089 * .createFile("org", "example", "HelloWorld.class") 090 * .copiedFromClassPath("org/example/HelloWorld.class"); 091 * </code></pre> 092 * 093 * @param resource the resource to copy. 094 * @return the root managed directory for further configuration. 095 */ 096 ManagedDirectory copiedFromClassPath(String resource); 097 098 /** 099 * Copy the contents from the given file into the file system. 100 * 101 * <pre><code> 102 * var file = new File("src/test/resources/code/HelloWorld.java"); 103 * 104 * directory 105 * .createFile("org", "example", "HelloWorld.java") 106 * .copiedFromFile(file); 107 * </code></pre> 108 * 109 * @param file the file to read. 110 * @return the root managed directory for further configuration. 111 */ 112 ManagedDirectory copiedFromFile(File file); 113 114 /** 115 * Copy the contents from the given path into the file system. 116 * 117 * <pre><code> 118 * var file = Path.of("src", "test", "resources", "code", "HelloWorld.java"); 119 * 120 * directory 121 * .createFile("org", "example", "HelloWorld.java") 122 * .copiedFromFile(file); 123 * </code></pre> 124 * 125 * @param file the file to read. 126 * @return the root managed directory for further configuration. 127 */ 128 ManagedDirectory copiedFromFile(Path file); 129 130 /** 131 * Copy the contents from the given URL into the file system. 132 * 133 * <pre><code> 134 * var url = URI.create("file:///code/org/example/HelloWorld.java").toURI(); 135 * 136 * directory 137 * .createFile("org", "example", "HelloWorld.java") 138 * .copiedFromUrl(url); 139 * </code></pre> 140 * 141 * @param url the URL to read. 142 * @return the root managed directory for further configuration. 143 */ 144 ManagedDirectory copiedFromUrl(URL url); 145 146 /** 147 * Copy the contents from the given input stream into the file system. 148 * 149 * <p>The input stream will be closed when reading completes. 150 * 151 * <pre><code> 152 * try (var is = getClass().getResourceAsStream("code/examples/HelloWorld.java")) { 153 * directory 154 * .createFile("org", "example", "HelloWorld.java") 155 * .fromInputStream(is); 156 * } 157 * </code></pre> 158 * 159 * @param inputStream the input stream to read. 160 * @return the root managed directory for further configuration. 161 */ 162 ManagedDirectory fromInputStream(InputStream inputStream); 163 164 /** 165 * Create the file but do not put anything in it. 166 * 167 * <p>The resultant file will be 0 bytes long. 168 * 169 * <pre><code> 170 * directory 171 * .createFile(".gitkeep") 172 * .thatIsEmpty(); 173 * </code></pre> 174 * 175 * @return the root managed directory for further configuration. 176 */ 177 ManagedDirectory thatIsEmpty(); 178 179 180 /** 181 * Create the file with the given byte contents. 182 * 183 * <pre><code> 184 * var classFile = new byte[]{ 185 * -54, -2, -70, -66, 0, 0, 0, 63, 0, 29, 10, 0, 2, 0, 3, 7, 0, 4, 12, 0, 5, 0, 6, 1, 0, 186 * 16, 106, 97, 118, 97, 47, 108, 97, 110, 103, 47, 79, 98, 106, 101, 99, 116, 1, 0, 6, 187 * 60, 105, 110, 105, 116, 62, 1, 0, 3, 40, 41, 86, 9, 0, 8, 0, 9, 7, 0, 10, 12, 0, 11, 188 * 0, 12, 1, 0, 16, 106, 97, 118, 97, 47, 108, 97, 110, 103, 47, 83, 121, 115, 116, 101, 189 * 109, 1, 0, 3, 111, 117, 116, 1, 0, 21, 76, 106, 97, 118, 97, 47, 105, 111, 47, 80, 114, 190 * 105, 110, 116, 83, 116, 114, 101, 97, 109, 59, 8, 0, 14, 1, 0, 13, 72, 101, 108, 108, 191 * 111, 44, 32, 87, 111, 114, 108, 100, 33, 10, 0, 16, 0, 17, 7, 0, 18, 12, 0, 19, 0, 20, 192 * 1, 0, 19, 106, 97, 118, 97, 47, 105, 111, 47, 80, 114, 105, 110, 116, 83, 116, 114, 101, 193 * 97, 109, 1, 0, 7, 112, 114, 105, 110, 116, 108, 110, 1, 0, 21, 40, 76, 106, 97, 118, 97, 194 * 47, 108, 97, 110, 103, 47, 83, 116, 114, 105, 110, 103, 59, 41, 86, 7, 0, 22, 1, 0, 10, 195 * 72, 101, 108, 108, 111, 87, 111, 114, 108, 100, 1, 0, 4, 67, 111, 100, 101, 1, 0, 15, 76, 196 * 105, 110, 101, 78, 117, 109, 98, 101, 114, 84, 97, 98, 108, 101, 1, 0, 4, 109, 97, 105, 197 * 110, 1, 0, 22, 40, 91, 76, 106, 97, 118, 97, 47, 108, 97, 110, 103, 47, 83, 116, 114, 198 * 105, 110, 103, 59, 41, 86, 1, 0, 10, 83, 111, 117, 114, 99, 101, 70, 105, 108, 101, 1, 199 * 0, 15, 72, 101, 108, 108, 111, 87, 111, 114, 108, 100, 46, 106, 97, 118, 97, 0, 33, 0, 200 * 21, 0, 2, 0, 0, 0, 0, 0, 2, 0, 1, 0, 5, 0, 6, 0, 1, 0, 23, 0, 0, 0, 29, 0, 1, 0, 1, 0, 201 * 0, 0, 5, 42, -73, 0, 1, -79, 0, 0, 0, 1, 0, 24, 0, 0, 0, 6, 0, 1, 0, 0, 0, 1, 0, 9, 0, 202 * 25, 0, 26, 0, 1, 0, 23, 0, 0, 0, 37, 0, 2, 0, 1, 0, 0, 0, 9, -78, 0, 7, 18, 13, -74, 0, 203 * 15, -79, 0, 0, 0, 1, 0, 24, 0, 0, 0, 10, 0, 2, 0, 0, 0, 3, 0, 8, 0, 4, 0, 1, 0, 27, 0, 204 * 0, 0, 2, 0, 28 205 * }; 206 * 207 * directory 208 * .createFile("HelloWorld.class") 209 * .withContents(classFile); 210 * </code></pre> 211 * 212 * @param contents the bytes to write. 213 * @return the root managed directory for further configuration. 214 */ 215 ManagedDirectory withContents(byte[] contents); 216 217 /** 218 * Create the file with the given contents. 219 * 220 * <pre><code> 221 * directory 222 * .createFile("org", "example", "HelloWorld.java") 223 * .withContents(StandardCharsets.US_ASCII, """ 224 * package org.example; 225 * 226 * public class HelloWorld { 227 * public static void main(String[] args) { 228 * System.out.println("Hello, World!"); 229 * } 230 * } 231 * """); 232 * </code></pre> 233 * 234 * <p>If the Java language level of your tests does not support multi-line strings, you can 235 * alternatively pass each line of text to write as a separate string. These will be written to 236 * the file using line-feed {@code '\n'} separators. For example: 237 * 238 * <pre><code> 239 * directory 240 * .createFile("org", "example", "HelloWorld.java") 241 * .withContents( 242 * StandardCharsets.US_ASCII, 243 * "package org.example;", 244 * "", 245 * "public class HelloWorld {", 246 * " public static void main(String[] args) {", 247 * " System.out.println(\"Hello, World!\");", 248 * " }", 249 * "}" 250 * ); 251 * </code></pre> 252 * 253 * @param charset the character encoding to use. 254 * @param lines the lines to write. 255 * @return the root managed directory for further configuration. 256 * @see #withContents(String...) 257 * @see #withContents(byte[]) 258 */ 259 ManagedDirectory withContents(Charset charset, String... lines); 260 261 /** 262 * Create the file with the given contents as UTF-8. 263 * 264 * <p>If you are using multi-line strings, an example of usage would be: 265 * 266 * <pre><code> 267 * directory 268 * .createFile("org", "example", "HelloWorld.java") 269 * .withContents(""" 270 * package org.example; 271 * 272 * public class HelloWorld { 273 * public static void main(String[] args) { 274 * System.out.println("Hello, World!"); 275 * } 276 * } 277 * """); 278 * </code></pre> 279 * 280 * <p>If the Java language level of your tests does not support multi-line strings, you can 281 * alternatively pass each line of text to write as a separate string. These will be written to 282 * the file using line-feed {@code '\n'} separators. For example: 283 * 284 * <pre><code> 285 * directory 286 * .createFile("org", "example", "HelloWorld.java") 287 * .withContents( 288 * "package org.example;", 289 * "", 290 * "public class HelloWorld {", 291 * " public static void main(String[] args) {", 292 * " System.out.println(\"Hello, World!\");", 293 * " }", 294 * "}" 295 * ); 296 * </code></pre> 297 * 298 * @param lines the lines to write using the default charset. 299 * @return the root managed directory for further configuration. 300 * @see #withContents(Charset, String...) 301 * @see #withContents(byte[]) 302 */ 303 ManagedDirectory withContents(String... lines); 304}