use of io.quarkus.bootstrap.model.MutableJarApplicationModel in project quarkus by quarkusio.
the class ReaugmentTask method main.
public static void main(Path appRoot) throws Exception {
Path deploymentLib = appRoot.resolve(LIB).resolve(DEPLOYMENT_LIB);
Path buildSystemProps = appRoot.resolve(QUARKUS).resolve(BUILD_SYSTEM_PROPERTIES);
try (ObjectInputStream in = new ObjectInputStream(Files.newInputStream(deploymentLib.resolve(JarResultBuildStep.APPMODEL_DAT)))) {
Properties buildSystemProperties = new Properties();
try (InputStream buildIn = Files.newInputStream(buildSystemProps)) {
buildSystemProperties.load(buildIn);
}
MutableJarApplicationModel appModel = (MutableJarApplicationModel) in.readObject();
List<AdditionalDependency> additional = new ArrayList<>();
if (appModel.getUserProvidersDirectory() != null) {
// bit of a hack, but keeps things simple
System.setProperty("quarkus.package.user-providers-directory", appModel.getUserProvidersDirectory());
try (Stream<Path> files = Files.list(appRoot.resolve(appModel.getUserProvidersDirectory()))) {
files.forEach(new Consumer<Path>() {
@Override
public void accept(Path path) {
if (path.toString().endsWith(".jar")) {
additional.add(new AdditionalDependency(path, false, true));
}
}
});
}
}
final ApplicationModel existingModel = appModel.getAppModel(appRoot);
System.setProperty("quarkus.package.type", "mutable-jar");
try (CuratedApplication bootstrap = QuarkusBootstrap.builder().setAppArtifact(existingModel.getAppArtifact()).setExistingModel(existingModel).setRebuild(true).setBuildSystemProperties(buildSystemProperties).setBaseName(appModel.getBaseName()).addAdditionalApplicationArchives(additional).setApplicationRoot(existingModel.getAppArtifact().getResolvedPaths().getSinglePath()).setTargetDirectory(appRoot.getParent()).setBaseClassLoader(ReaugmentTask.class.getClassLoader()).build().bootstrap()) {
bootstrap.createAugmentor().createProductionApplication();
}
}
}
use of io.quarkus.bootstrap.model.MutableJarApplicationModel in project quarkus by quarkusio.
the class DevModeTask method main.
public static Closeable main(Path appRoot) throws Exception {
try (ObjectInputStream in = new ObjectInputStream(Files.newInputStream(appRoot.resolve(LIB).resolve(DEPLOYMENT_LIB).resolve(JarResultBuildStep.APPMODEL_DAT)))) {
Properties buildSystemProperties = new Properties();
try (InputStream buildIn = Files.newInputStream(appRoot.resolve(QUARKUS).resolve(BUILD_SYSTEM_PROPERTIES))) {
buildSystemProperties.load(buildIn);
}
final MutableJarApplicationModel appModel = (MutableJarApplicationModel) in.readObject();
ApplicationModel existingModel = appModel.getAppModel(appRoot);
DevModeContext context = createDevModeContext(appRoot, existingModel);
CuratedApplication bootstrap = QuarkusBootstrap.builder().setAppArtifact(existingModel.getAppArtifact()).setExistingModel(existingModel).setIsolateDeployment(true).setMode(QuarkusBootstrap.Mode.REMOTE_DEV_SERVER).setBuildSystemProperties(buildSystemProperties).setBaseName(appModel.getBaseName()).setApplicationRoot(existingModel.getAppArtifact().getResolvedPaths().getSinglePath()).setTargetDirectory(appRoot.getParent()).setBaseClassLoader(DevModeTask.class.getClassLoader()).build().bootstrap();
Map<String, Object> map = new HashMap<>();
map.put(DevModeContext.class.getName(), context);
map.put(IsolatedDevModeMain.APP_ROOT, appRoot);
map.put(DevModeType.class.getName(), DevModeType.REMOTE_SERVER_SIDE);
return (Closeable) bootstrap.runInAugmentClassLoader(IsolatedDevModeMain.class.getName(), map);
}
}
use of io.quarkus.bootstrap.model.MutableJarApplicationModel in project quarkus by quarkusio.
the class JarResultBuildStep method buildThinJar.
private JarBuildItem buildThinJar(CurateOutcomeBuildItem curateOutcomeBuildItem, OutputTargetBuildItem outputTargetBuildItem, TransformedClassesBuildItem transformedClasses, ApplicationArchivesBuildItem applicationArchivesBuildItem, PackageConfig packageConfig, ClassLoadingConfig classLoadingConfig, ApplicationInfoBuildItem applicationInfo, List<GeneratedClassBuildItem> generatedClasses, List<GeneratedResourceBuildItem> generatedResources, List<AdditionalApplicationArchiveBuildItem> additionalApplicationArchiveBuildItems, MainClassBuildItem mainClassBuildItem) throws Exception {
boolean rebuild = outputTargetBuildItem.isRebuild();
Path buildDir;
if (packageConfig.outputDirectory.isPresent()) {
buildDir = outputTargetBuildItem.getOutputDirectory();
} else {
buildDir = outputTargetBuildItem.getOutputDirectory().resolve(DEFAULT_FAST_JAR_DIRECTORY_NAME);
}
// unmodified 3rd party dependencies
Path libDir = buildDir.resolve(LIB);
Path mainLib = libDir.resolve(MAIN);
// parent first entries
Path baseLib = libDir.resolve(BOOT_LIB);
Files.createDirectories(baseLib);
Path appDir = buildDir.resolve(APP);
Path quarkus = buildDir.resolve(QUARKUS);
Path userProviders = null;
if (packageConfig.userProvidersDirectory.isPresent()) {
userProviders = buildDir.resolve(packageConfig.userProvidersDirectory.get());
}
if (!rebuild) {
IoUtils.createOrEmptyDir(buildDir);
Files.createDirectories(mainLib);
Files.createDirectories(baseLib);
Files.createDirectories(appDir);
Files.createDirectories(quarkus);
if (userProviders != null) {
Files.createDirectories(userProviders);
// we add this dir so that it can be copied into container images if required
// and will still be copied even if empty
Files.createFile(userProviders.resolve(".keep"));
}
} else {
IoUtils.createOrEmptyDir(quarkus);
}
Map<ArtifactKey, List<Path>> copiedArtifacts = new HashMap<>();
Path fernflowerJar = null;
Path decompiledOutputDir = null;
boolean wasDecompiledSuccessfully = true;
if (packageConfig.fernflower.enabled) {
Path jarDirectory = Paths.get(packageConfig.fernflower.jarDirectory);
if (!Files.exists(jarDirectory)) {
Files.createDirectory(jarDirectory);
}
fernflowerJar = jarDirectory.resolve(String.format("fernflower-%s.jar", packageConfig.fernflower.hash));
if (!Files.exists(fernflowerJar)) {
boolean downloadComplete = downloadFernflowerJar(packageConfig, fernflowerJar);
if (!downloadComplete) {
// will ensure that no decompilation takes place
fernflowerJar = null;
}
}
decompiledOutputDir = buildDir.getParent().resolve("decompiled");
FileUtil.deleteDirectory(decompiledOutputDir);
Files.createDirectory(decompiledOutputDir);
}
List<Path> jars = new ArrayList<>();
List<Path> parentFirst = new ArrayList<>();
// transformed classes first
if (!transformedClasses.getTransformedClassesByJar().isEmpty()) {
Path transformedZip = quarkus.resolve(TRANSFORMED_BYTECODE_JAR);
jars.add(transformedZip);
try (FileSystem out = ZipUtils.newZip(transformedZip)) {
for (Set<TransformedClassesBuildItem.TransformedClass> transformedSet : transformedClasses.getTransformedClassesByJar().values()) {
for (TransformedClassesBuildItem.TransformedClass transformed : transformedSet) {
Path target = out.getPath(transformed.getFileName());
if (transformed.getData() != null) {
if (target.getParent() != null) {
Files.createDirectories(target.getParent());
}
Files.write(target, transformed.getData());
}
}
}
}
if (fernflowerJar != null) {
wasDecompiledSuccessfully &= decompile(fernflowerJar, decompiledOutputDir, transformedZip);
}
}
// now generated classes and resources
Path generatedZip = quarkus.resolve(GENERATED_BYTECODE_JAR);
jars.add(generatedZip);
try (FileSystem out = ZipUtils.newZip(generatedZip)) {
for (GeneratedClassBuildItem i : generatedClasses) {
String fileName = i.getName().replace('.', '/') + ".class";
Path target = out.getPath(fileName);
if (target.getParent() != null) {
Files.createDirectories(target.getParent());
}
Files.write(target, i.getClassData());
}
for (GeneratedResourceBuildItem i : generatedResources) {
Path target = out.getPath(i.getName());
if (target.getParent() != null) {
Files.createDirectories(target.getParent());
}
Files.write(target, i.getClassData());
}
}
if (fernflowerJar != null) {
wasDecompiledSuccessfully &= decompile(fernflowerJar, decompiledOutputDir, generatedZip);
}
if (wasDecompiledSuccessfully && (decompiledOutputDir != null)) {
log.info("The decompiled output can be found at: " + decompiledOutputDir.toAbsolutePath().toString());
}
// now the application classes
Path runnerJar = appDir.resolve(outputTargetBuildItem.getBaseName() + ".jar");
jars.add(runnerJar);
if (!rebuild) {
Predicate<String> ignoredEntriesPredicate = getThinJarIgnoredEntriesPredicate(packageConfig);
try (FileSystem runnerZipFs = ZipUtils.newZip(runnerJar)) {
copyFiles(applicationArchivesBuildItem.getRootArchive(), runnerZipFs, null, ignoredEntriesPredicate);
}
}
final Set<ArtifactKey> parentFirstKeys = getParentFirstKeys(curateOutcomeBuildItem, classLoadingConfig);
StringBuilder classPath = new StringBuilder();
final Set<ArtifactKey> removed = getRemovedKeys(classLoadingConfig);
for (ResolvedDependency appDep : curateOutcomeBuildItem.getApplicationModel().getRuntimeDependencies()) {
if (rebuild) {
appDep.getResolvedPaths().forEach(jars::add);
} else {
copyDependency(parentFirstKeys, outputTargetBuildItem, copiedArtifacts, mainLib, baseLib, jars, true, classPath, appDep, transformedClasses, removed);
}
if (parentFirstKeys.contains(appDep.getKey())) {
appDep.getResolvedPaths().forEach(parentFirst::add);
}
}
for (AdditionalApplicationArchiveBuildItem i : additionalApplicationArchiveBuildItems) {
for (Path path : i.getResolvedPaths()) {
if (!path.getParent().equals(userProviders)) {
throw new RuntimeException("Additional application archives can only be provided from the user providers directory. " + path + " is not present in " + userProviders);
}
jars.add(path);
}
}
/*
* There are some files like META-INF/microprofile-config.properties that usually don't exist in application
* and yet are always looked up (spec compliance...) and due to the location in the jar,
* the RunnerClassLoader needs to look into every jar to determine whether they exist or not.
* In keeping true to the original design of the RunnerClassLoader which indexes the directory structure,
* we just add a fail-fast path for files we know don't exist.
*
* TODO: if this gets more complex, we'll probably want a build item to carry this information instead of hard
* coding it here
*/
List<String> nonExistentResources = new ArrayList<>(1);
Enumeration<URL> mpConfigURLs = Thread.currentThread().getContextClassLoader().getResources(MP_CONFIG_FILE);
if (!mpConfigURLs.hasMoreElements()) {
nonExistentResources.add(MP_CONFIG_FILE);
}
Path appInfo = buildDir.resolve(QuarkusEntryPoint.QUARKUS_APPLICATION_DAT);
try (OutputStream out = Files.newOutputStream(appInfo)) {
SerializedApplication.write(out, mainClassBuildItem.getClassName(), buildDir, jars, parentFirst, nonExistentResources);
}
runnerJar.toFile().setReadable(true, false);
Path initJar = buildDir.resolve(QUARKUS_RUN_JAR);
boolean mutableJar = packageConfig.type.equalsIgnoreCase(PackageConfig.MUTABLE_JAR);
if (mutableJar) {
// we output the properties in a reproducible manner, so we remove the date comment
// and sort them
// we still use Properties to get the escaping right though, so basically we write out the lines
// to memory, split them, discard comments, sort them, then write them to disk
ByteArrayOutputStream out = new ByteArrayOutputStream();
outputTargetBuildItem.getBuildSystemProperties().store(out, null);
List<String> lines = Arrays.stream(new String(out.toByteArray(), StandardCharsets.UTF_8).split("\n")).filter(s -> !s.startsWith("#")).sorted().collect(Collectors.toList());
Path buildSystemProps = quarkus.resolve(BUILD_SYSTEM_PROPERTIES);
try (OutputStream fileOutput = Files.newOutputStream(buildSystemProps)) {
fileOutput.write(String.join("\n", lines).getBytes(StandardCharsets.UTF_8));
}
}
if (!rebuild) {
try (FileSystem runnerZipFs = ZipUtils.newZip(initJar)) {
ResolvedDependency appArtifact = curateOutcomeBuildItem.getApplicationModel().getAppArtifact();
generateManifest(runnerZipFs, classPath.toString(), packageConfig, appArtifact, QuarkusEntryPoint.class.getName(), applicationInfo);
}
// now copy the deployment artifacts, if required
if (mutableJar) {
Path deploymentLib = libDir.resolve(DEPLOYMENT_LIB);
Files.createDirectories(deploymentLib);
for (ResolvedDependency appDep : curateOutcomeBuildItem.getApplicationModel().getDependencies()) {
copyDependency(parentFirstKeys, outputTargetBuildItem, copiedArtifacts, deploymentLib, baseLib, jars, false, classPath, appDep, new TransformedClassesBuildItem(Collections.emptyMap()), // we don't care about transformation here, so just pass in an empty item
removed);
}
Map<ArtifactKey, List<String>> relativePaths = new HashMap<>();
for (Map.Entry<ArtifactKey, List<Path>> e : copiedArtifacts.entrySet()) {
relativePaths.put(e.getKey(), e.getValue().stream().map(s -> buildDir.relativize(s).toString().replace('\\', '/')).collect(Collectors.toList()));
}
// now we serialize the data needed to build up the reaugmentation class path
// first the app model
MutableJarApplicationModel model = new MutableJarApplicationModel(outputTargetBuildItem.getBaseName(), relativePaths, curateOutcomeBuildItem.getApplicationModel(), packageConfig.userProvidersDirectory.orElse(null), buildDir.relativize(runnerJar).toString());
Path appmodelDat = deploymentLib.resolve(APPMODEL_DAT);
try (OutputStream out = Files.newOutputStream(appmodelDat)) {
ObjectOutputStream obj = new ObjectOutputStream(out);
obj.writeObject(model);
obj.close();
}
// now the bootstrap CP
// we just include all deployment deps, even though we only really need bootstrap
// as we don't really have a resolved bootstrap CP
// once we have the app model it will all be done in QuarkusClassLoader anyway
Path deploymentCp = deploymentLib.resolve(DEPLOYMENT_CLASS_PATH_DAT);
try (OutputStream out = Files.newOutputStream(deploymentCp)) {
ObjectOutputStream obj = new ObjectOutputStream(out);
List<String> paths = new ArrayList<>();
for (ResolvedDependency i : curateOutcomeBuildItem.getApplicationModel().getDependencies()) {
final List<String> list = relativePaths.get(i.getKey());
// some of the dependencies may have been filtered out
if (list != null) {
paths.addAll(list);
}
}
obj.writeObject(paths);
obj.close();
}
}
if (packageConfig.includeDependencyList) {
Path deplist = buildDir.resolve(QUARKUS_APP_DEPS);
List<String> lines = new ArrayList<>();
for (ResolvedDependency i : curateOutcomeBuildItem.getApplicationModel().getRuntimeDependencies()) {
lines.add(i.toGACTVString());
}
lines.sort(Comparator.naturalOrder());
Files.write(deplist, lines);
}
} else {
// if it is a rebuild we might have classes
}
try (Stream<Path> files = Files.walk(buildDir)) {
files.forEach(new Consumer<Path>() {
@Override
public void accept(Path path) {
path.toFile().setReadable(true, false);
}
});
}
return new JarBuildItem(initJar, null, libDir, packageConfig.type, null);
}
Aggregations