From 53025f0e7650a8e8450ec9da02fb53ae0e1dc49a Mon Sep 17 00:00:00 2001 From: Alexey Loubyansky Date: Fri, 1 Feb 2019 10:08:28 +0100 Subject: [PATCH] [GAL-239] Use target directory directly if it's empty or does not exist instead of staging --- .../jboss/galleon/ProvisioningManager.java | 25 +++++++--- .../galleon/layout/ProvisioningLayout.java | 8 +--- .../galleon/runtime/ProvisioningRuntime.java | 25 +++++++++- .../runtime/ProvisioningRuntimeBuilder.java | 6 +++ .../java/org/jboss/galleon/util/IoUtils.java | 48 ++++++++++++++++--- .../org/jboss/galleon/util/PathsUtils.java | 19 +++++++- 6 files changed, 107 insertions(+), 24 deletions(-) diff --git a/core/src/main/java/org/jboss/galleon/ProvisioningManager.java b/core/src/main/java/org/jboss/galleon/ProvisioningManager.java index 6f450dccd..486e402b0 100644 --- a/core/src/main/java/org/jboss/galleon/ProvisioningManager.java +++ b/core/src/main/java/org/jboss/galleon/ProvisioningManager.java @@ -1,5 +1,5 @@ /* - * Copyright 2016-2018 Red Hat, Inc. and/or its affiliates + * Copyright 2016-2019 Red Hat, Inc. and/or its affiliates * and other contributors as indicated by the @author tags. * * Licensed under the Apache License, Version 2.0 (the "License"); @@ -584,15 +584,24 @@ public ProvisioningRuntime getRuntime(ProvisioningLayout provisioningLayout) private ProvisioningRuntime getRuntimeInternal(ProvisioningLayout layout, FsDiff fsDiff) throws ProvisioningException { - return ProvisioningRuntimeBuilder.newInstance(log) + return getRuntimeInternal(layout, fsDiff, false); + } + + private ProvisioningRuntime getRuntimeInternal(ProvisioningLayout layout, FsDiff fsDiff, boolean setStagedDir) + throws ProvisioningException { + final ProvisioningRuntimeBuilder rtBuilder = ProvisioningRuntimeBuilder.newInstance(log) .initRtLayout(layout) .setEncoding(encoding) - .setFsDiff(fsDiff) - .build(); + .setFsDiff(fsDiff); + if(setStagedDir) { + rtBuilder.setStagedDir(home); + } + return rtBuilder.build(); } private void doProvision(ProvisioningLayout layout, FsDiff fsDiff, boolean undo) throws ProvisioningException { - try (ProvisioningRuntime runtime = getRuntimeInternal(layout, fsDiff)) { + final boolean freshInstall = PathsUtils.isNewHome(home); + try (ProvisioningRuntime runtime = getRuntimeInternal(layout, fsDiff, freshInstall)) { runtime.provision(); if (runtime.getProvisioningConfig().hasFeaturePackDeps()) { persistHashes(runtime); @@ -622,7 +631,9 @@ private void doProvision(ProvisioningLayout layout, F if (fsDiff != null && !fsDiff.isEmpty()) { undoTasks = FsDiff.replay(fsDiff, runtime.getStagedDir(), log); } - PathsUtils.replaceDist(runtime.getStagedDir(), home, undo, undoTasks, log); + if(!freshInstall) { + PathsUtils.replaceDist(runtime.getStagedDir(), home, undo, undoTasks, log); + } } finally { this.provisioningConfig = null; } @@ -762,7 +773,7 @@ private void persistHashes(ProvisioningRuntime runtime) throws ProvisioningExcep if(log.isVerboseEnabled()) { final long timeMs = (System.nanoTime() - startTime) / 1000000; final long timeSec = timeMs / 1000; - log.print("Hashing took %d.%d seconds", timeSec, (timeMs - timeSec * 1000)); + log.verbose("Hashing took %d.%d seconds", timeSec, (timeMs - timeSec * 1000)); } } diff --git a/core/src/main/java/org/jboss/galleon/layout/ProvisioningLayout.java b/core/src/main/java/org/jboss/galleon/layout/ProvisioningLayout.java index 07a28c4c0..d20ee2f57 100644 --- a/core/src/main/java/org/jboss/galleon/layout/ProvisioningLayout.java +++ b/core/src/main/java/org/jboss/galleon/layout/ProvisioningLayout.java @@ -145,13 +145,7 @@ private void copyResources(Path fpDir) throws ProvisioningException { protected Path newStagedDir() throws ProvisioningException { final Path stagedDir = getWorkDir().resolve(STAGED); if(Files.exists(stagedDir)) { - try(DirectoryStream stream = Files.newDirectoryStream(stagedDir)) { - for(Path p : stream) { - IoUtils.recursiveDelete(p); - } - } catch (IOException e) { - throw new ProvisioningException(Errors.readDirectory(stagedDir), e); - } + IoUtils.emptyDir(stagedDir); } else { try { Files.createDirectories(stagedDir); diff --git a/core/src/main/java/org/jboss/galleon/runtime/ProvisioningRuntime.java b/core/src/main/java/org/jboss/galleon/runtime/ProvisioningRuntime.java index 5b03099aa..4d6598c33 100644 --- a/core/src/main/java/org/jboss/galleon/runtime/ProvisioningRuntime.java +++ b/core/src/main/java/org/jboss/galleon/runtime/ProvisioningRuntime.java @@ -62,6 +62,7 @@ public class ProvisioningRuntime implements FeaturePackSet, private final Path stagedDir; private final ProvisioningLayout layout; private final MessageWriter messageWriter; + private Boolean emptyStagedDir; private List configs = Collections.emptyList(); ProvisioningRuntime(final ProvisioningRuntimeBuilder builder, final MessageWriter messageWriter) throws ProvisioningException { @@ -75,11 +76,24 @@ public FeaturePackRuntime transform(FeaturePackRuntimeBuilder other) throws Prov }); this.fsDiff = builder.fsDiff; + Path stagedDir = null; try { this.configs = builder.getResolvedConfigs(); - this.stagedDir = layout.newStagedDir(); + if(builder.stagedDir == null) { + this.stagedDir = stagedDir = layout.newStagedDir(); + } else { + this.stagedDir = stagedDir = builder.stagedDir; + this.emptyStagedDir = Files.exists(stagedDir); + } } catch (ProvisioningException | RuntimeException | Error e) { layout.close(); + if(emptyStagedDir != null) { + if (emptyStagedDir) { + IoUtils.emptyDir(stagedDir); + } else { + IoUtils.recursiveDelete(stagedDir); + } + } throw e; } @@ -299,11 +313,20 @@ public void visitPlugin(InstallPlugin plugin) throws ProvisioningException { } catch (XMLStreamException | IOException e) { throw new FeaturePackInstallException(Errors.writeFile(PathsUtils.getProvisionedStateXml(stagedDir)), e); } + + emptyStagedDir = null; } @Override public void close() { layout.close(); + if(emptyStagedDir != null) { + if (emptyStagedDir) { + IoUtils.emptyDir(stagedDir); + } else { + IoUtils.recursiveDelete(stagedDir); + } + } if (messageWriter.isVerboseEnabled()) { final long time = System.currentTimeMillis() - startTime; final long seconds = time / 1000; diff --git a/core/src/main/java/org/jboss/galleon/runtime/ProvisioningRuntimeBuilder.java b/core/src/main/java/org/jboss/galleon/runtime/ProvisioningRuntimeBuilder.java index 4f27e2821..19f249fa4 100644 --- a/core/src/main/java/org/jboss/galleon/runtime/ProvisioningRuntimeBuilder.java +++ b/core/src/main/java/org/jboss/galleon/runtime/ProvisioningRuntimeBuilder.java @@ -87,6 +87,7 @@ public static ProvisioningRuntimeBuilder newInstance(final MessageWriter message String encoding; ProvisioningConfig config; ProvisioningLayout layout; + Path stagedDir; FsDiff fsDiff; private final MessageWriter messageWriter; @@ -141,6 +142,11 @@ public ProvisioningRuntimeBuilder setFsDiff(FsDiff fsDiff) { return this; } + public ProvisioningRuntimeBuilder setStagedDir(Path p) { + this.stagedDir = p; + return this; + } + public ProvisioningRuntime build() throws ProvisioningException { try { return doBuild(); diff --git a/core/src/main/java/org/jboss/galleon/util/IoUtils.java b/core/src/main/java/org/jboss/galleon/util/IoUtils.java index 349601f7d..96f0c837c 100644 --- a/core/src/main/java/org/jboss/galleon/util/IoUtils.java +++ b/core/src/main/java/org/jboss/galleon/util/IoUtils.java @@ -1,5 +1,5 @@ /* - * Copyright 2016-2018 Red Hat, Inc. and/or its affiliates + * Copyright 2016-2019 Red Hat, Inc. and/or its affiliates * and other contributors as indicated by the @author tags. * * Licensed under the Apache License, Version 2.0 (the "License"); @@ -78,12 +78,12 @@ public static Path createRandomDir(Path parentDir) { return dir; } - public static void recursiveDelete(Path root) { - if (root == null || !Files.exists(root)) { + public static void emptyDir(Path p) { + if (p == null || !Files.exists(p)) { return; } try { - Files.walkFileTree(root, new SimpleFileVisitor() { + Files.walkFileTree(p, new SimpleFileVisitor() { @Override public FileVisitResult visitFile(Path file, BasicFileAttributes attrs) throws IOException { @@ -96,16 +96,50 @@ public FileVisitResult visitFile(Path file, BasicFileAttributes attrs) @Override public FileVisitResult postVisitDirectory(Path dir, IOException e) throws IOException { - if (e == null) { + if (e != null) { + // directory iteration failed + throw e; + } + if (dir != p) { try { Files.delete(dir); } catch (IOException ex) { } - return FileVisitResult.CONTINUE; - } else { + } + return FileVisitResult.CONTINUE; + } + }); + } catch (IOException e) { + } + } + + public static void recursiveDelete(Path root) { + if (root == null || !Files.exists(root)) { + return; + } + try { + Files.walkFileTree(root, new SimpleFileVisitor() { + @Override + public FileVisitResult visitFile(Path file, BasicFileAttributes attrs) + throws IOException { + try { + Files.delete(file); + } catch (IOException ex) { + } + return FileVisitResult.CONTINUE; + } + @Override + public FileVisitResult postVisitDirectory(Path dir, IOException e) + throws IOException { + if (e != null) { // directory iteration failed throw e; } + try { + Files.delete(dir); + } catch (IOException ex) { + } + return FileVisitResult.CONTINUE; } }); } catch (IOException e) { diff --git a/core/src/main/java/org/jboss/galleon/util/PathsUtils.java b/core/src/main/java/org/jboss/galleon/util/PathsUtils.java index ef1dc6583..19015d6f0 100644 --- a/core/src/main/java/org/jboss/galleon/util/PathsUtils.java +++ b/core/src/main/java/org/jboss/galleon/util/PathsUtils.java @@ -1,5 +1,5 @@ /* - * Copyright 2016-2018 Red Hat, Inc. and/or its affiliates + * Copyright 2016-2019 Red Hat, Inc. and/or its affiliates * and other contributors as indicated by the @author tags. * * Licensed under the Apache License, Version 2.0 (the "License"); @@ -37,6 +37,21 @@ */ public class PathsUtils { + public static boolean isNewHome(Path homeDir) throws ProvisioningException { + if (!Files.exists(homeDir)) { + return true; + } + if (!Files.isDirectory(homeDir)) { + throw new ProvisioningException(Errors.notADir(homeDir)); + } + try (DirectoryStream stream = Files.newDirectoryStream(homeDir)) { + final Iterator i = stream.iterator(); + return !i.hasNext(); + } catch (IOException e) { + throw new ProvisioningException(Errors.readDirectory(homeDir), e); + } + } + public static void assertInstallationDir(Path path) throws ProvisioningException { if (!Files.exists(path)) { return; @@ -56,7 +71,7 @@ public static void assertInstallationDir(Path path) throws ProvisioningException } throw new ProvisioningException(Errors.homeDirNotUsable(path)); } catch (IOException e) { - throw new ProvisioningException(Errors.readDirectory(path)); + throw new ProvisioningException(Errors.readDirectory(path), e); } }