Search in sources :

Example 1 with MutableJarApplicationModel

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();
        }
    }
}
Also used : Path(java.nio.file.Path) ObjectInputStream(java.io.ObjectInputStream) InputStream(java.io.InputStream) ArrayList(java.util.ArrayList) MutableJarApplicationModel(io.quarkus.bootstrap.model.MutableJarApplicationModel) ApplicationModel(io.quarkus.bootstrap.model.ApplicationModel) Properties(java.util.Properties) MutableJarApplicationModel(io.quarkus.bootstrap.model.MutableJarApplicationModel) CuratedApplication(io.quarkus.bootstrap.app.CuratedApplication) AdditionalDependency(io.quarkus.bootstrap.app.AdditionalDependency) ObjectInputStream(java.io.ObjectInputStream)

Example 2 with MutableJarApplicationModel

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);
    }
}
Also used : HashMap(java.util.HashMap) ZipInputStream(java.util.zip.ZipInputStream) ObjectInputStream(java.io.ObjectInputStream) InputStream(java.io.InputStream) Closeable(java.io.Closeable) MutableJarApplicationModel(io.quarkus.bootstrap.model.MutableJarApplicationModel) ApplicationModel(io.quarkus.bootstrap.model.ApplicationModel) Properties(java.util.Properties) MutableJarApplicationModel(io.quarkus.bootstrap.model.MutableJarApplicationModel) CuratedApplication(io.quarkus.bootstrap.app.CuratedApplication) DevModeContext(io.quarkus.deployment.dev.DevModeContext) DevModeType(io.quarkus.dev.spi.DevModeType) ObjectInputStream(java.io.ObjectInputStream)

Example 3 with MutableJarApplicationModel

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);
}
Also used : ArtifactKey(io.quarkus.maven.dependency.ArtifactKey) HashMap(java.util.HashMap) ZipOutputStream(java.util.zip.ZipOutputStream) ByteArrayOutputStream(java.io.ByteArrayOutputStream) ObjectOutputStream(java.io.ObjectOutputStream) OutputStream(java.io.OutputStream) FileOutputStream(java.io.FileOutputStream) JarBuildItem(io.quarkus.deployment.pkg.builditem.JarBuildItem) NativeImageSourceJarBuildItem(io.quarkus.deployment.pkg.builditem.NativeImageSourceJarBuildItem) ArrayList(java.util.ArrayList) ResolvedDependency(io.quarkus.maven.dependency.ResolvedDependency) QuarkusEntryPoint(io.quarkus.bootstrap.runner.QuarkusEntryPoint) ObjectOutputStream(java.io.ObjectOutputStream) URL(java.net.URL) AdditionalApplicationArchiveBuildItem(io.quarkus.deployment.builditem.AdditionalApplicationArchiveBuildItem) FileSystem(java.nio.file.FileSystem) GeneratedClassBuildItem(io.quarkus.deployment.builditem.GeneratedClassBuildItem) List(java.util.List) ArrayList(java.util.ArrayList) Path(java.nio.file.Path) GeneratedResourceBuildItem(io.quarkus.deployment.builditem.GeneratedResourceBuildItem) ByteArrayOutputStream(java.io.ByteArrayOutputStream) TransformedClassesBuildItem(io.quarkus.deployment.builditem.TransformedClassesBuildItem) MutableJarApplicationModel(io.quarkus.bootstrap.model.MutableJarApplicationModel) Map(java.util.Map) HashMap(java.util.HashMap)

Aggregations

MutableJarApplicationModel (io.quarkus.bootstrap.model.MutableJarApplicationModel)3 CuratedApplication (io.quarkus.bootstrap.app.CuratedApplication)2 ApplicationModel (io.quarkus.bootstrap.model.ApplicationModel)2 InputStream (java.io.InputStream)2 ObjectInputStream (java.io.ObjectInputStream)2 Path (java.nio.file.Path)2 ArrayList (java.util.ArrayList)2 HashMap (java.util.HashMap)2 Properties (java.util.Properties)2 AdditionalDependency (io.quarkus.bootstrap.app.AdditionalDependency)1 QuarkusEntryPoint (io.quarkus.bootstrap.runner.QuarkusEntryPoint)1 AdditionalApplicationArchiveBuildItem (io.quarkus.deployment.builditem.AdditionalApplicationArchiveBuildItem)1 GeneratedClassBuildItem (io.quarkus.deployment.builditem.GeneratedClassBuildItem)1 GeneratedResourceBuildItem (io.quarkus.deployment.builditem.GeneratedResourceBuildItem)1 TransformedClassesBuildItem (io.quarkus.deployment.builditem.TransformedClassesBuildItem)1 DevModeContext (io.quarkus.deployment.dev.DevModeContext)1 JarBuildItem (io.quarkus.deployment.pkg.builditem.JarBuildItem)1 NativeImageSourceJarBuildItem (io.quarkus.deployment.pkg.builditem.NativeImageSourceJarBuildItem)1 DevModeType (io.quarkus.dev.spi.DevModeType)1 ArtifactKey (io.quarkus.maven.dependency.ArtifactKey)1