1 /*
   2  * Copyright (c) 2014, 2016 Oracle and/or its affiliates. All rights reserved.
   3  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
   4  */
   5 package com.oracle.appbundlers.utils.installers;
   6 
   7 import static com.oracle.appbundlers.utils.Config.CONFIG_INSTANCE;
   8 import static com.oracle.appbundlers.utils.Utils.getProgramFilesDirWindows;
   9 import static java.nio.file.Files.exists;
  10 import static org.testng.Assert.assertTrue;
  11 import static org.testng.Assert.fail;
  12 
  13 import java.io.IOException;
  14 import java.nio.charset.StandardCharsets;
  15 import java.nio.file.Files;
  16 import java.nio.file.Path;
  17 import java.nio.file.Paths;
  18 import java.nio.file.StandardCopyOption;
  19 import java.util.List;
  20 import java.util.Optional;
  21 import java.util.concurrent.ExecutionException;
  22 import java.util.logging.Level;
  23 import java.util.logging.Logger;
  24 
  25 import com.oracle.appbundlers.utils.AppWrapper;
  26 import com.oracle.appbundlers.utils.BundlerUtils;
  27 import com.oracle.appbundlers.utils.Config;
  28 import com.oracle.appbundlers.utils.ProcessOutput;
  29 import com.oracle.appbundlers.utils.Utils;
  30 import com.oracle.appbundlers.utils.windows.Registry;
  31 
  32 /**
  33  *
  34  * @author Dmitry Ginzburg <dmitry.x.ginzburg@oracle.com>
  35  * @author Dmitry Zinkevich <dmitry.zinkevich@oracle.com>
  36  */
  37 public class WinExeBundlerUtils extends WinAbstractBundlerUtils {
  38 
  39     private static final Logger LOG = Logger
  40             .getLogger(WinExeBundlerUtils.class.getName());
  41 
  42     {
  43         verificators.put(SHORTCUT_HINT, getShortcutHintVerificator());
  44 
  45         verificators.put(MENU_HINT, getMenuGroupVerificator());
  46         verificators.put(SERVICE_HINT, getServiceHintVerificator());
  47         verificators.put(START_ON_INSTALL, getStartOnInstallVerificator());
  48         verificators.put(RUN_AT_STARTUP, getRunAtStartupVerificator());
  49         verificators.put(VENDOR, getMenuGroupVerificator());
  50         verificators.put(VERSION, (version, app, appName) -> {
  51             Path config = getInstalledAppRootLocation(app, appName)
  52                     .resolve("app/" + appName + ".cfg");
  53             try {
  54                 assertTrue(
  55                         Utils.checkFileContains(config,
  56                                 "app.version=" + version),
  57                         "[Version info not found]");
  58             } catch (IOException ex) {
  59                 fail("[Unable to read package.cfg]");
  60             }
  61         });
  62 
  63         verificators.put(SYSTEM_WIDE, getSystemWideOptionVerificator());
  64         verificators.put(EXE_SYSTEM_WIDE, getSystemWideOptionVerificator());
  65         verificators.put(MENU_GROUP, getMenuGroupVerificator());
  66         verificators.put(WIN_USER_FILE_ASSOCIATIONS,
  67                 getUserFileAssociationVerificator());
  68         verificators.put(WIN_SYSTEM_WIDE_FILE_ASSOCIATIONS,
  69                 getFileAssociationVerificator());
  70         verificators.put(TITLE, (val, app, appName) -> {
  71             Optional<String> optKey = Registry.findAppRegistryKey(appName);
  72             assertTrue(optKey.isPresent(),
  73                     "[Registry info not found for " + appName + "]");
  74 
  75             Optional<List<String>> optContent = Registry.queryKey(optKey.get());
  76             optContent.ifPresent(System.out::println);
  77             final String expectedText = val.toString();
  78 
  79             Optional<String> comment = optContent.map(content -> {
  80                 return content.parallelStream().map(String::trim)
  81                         .filter(s -> s.startsWith("Comments")
  82                                 && s.endsWith(expectedText))
  83                         .findFirst();
  84             }).orElseGet(() -> {
  85                 return Optional.empty();
  86             });
  87 
  88             assertTrue(comment.isPresent(),
  89                     "[Comments are not set in registry for " + appName + "]");
  90         });
  91 
  92         verificators.put(COPYRIGHT, (copyright, app, appName) -> {
  93             Path installer = app.getWorkDir().resolve(appName + "-1.0.exe");
  94             assertTrue(exists(installer),
  95                     "[" + installer + " does not exists]");
  96 
  97             try {
  98                 Path temp = Files.createTempDirectory("SQE");
  99                 Path tmpInstaller = Files.copy(installer,
 100                         temp.resolve("installer.exe"),
 101                         StandardCopyOption.COPY_ATTRIBUTES);
 102 
 103                 String content = new String(
 104                         Files.readAllBytes(
 105                                 Config.CONFIG_INSTANCE.getResourcePath()
 106                                         .resolve("getExeCopyright.vbs")),
 107                         StandardCharsets.UTF_8);
 108 
 109                 Path script = Files.createFile(temp.resolve("script.vbs"));
 110                 Files.write(script,
 111                         content.replace("__FILE_NAME__",
 112                                 tmpInstaller.getFileName().toString())
 113                         .getBytes());
 114 
 115                 ProcessOutput output = Utils.runCommand(
 116                         new String[] { "cscript", script.toString() }, true,
 117                         CONFIG_INSTANCE.getRunTimeout());
 118 
 119                 assertTrue(
 120                         output.getOutputStream().parallelStream()
 121                                 .map(String::trim).anyMatch(
 122                                         s -> s.contains(copyright.toString())),
 123                         "[Copyright wasn't stored in " + installer + "]");
 124 
 125             } catch (IOException | ExecutionException ex) {
 126                 fail("[Unable to query " + installer + " due to "
 127                         + ex.getMessage() + "]");
 128             }
 129         });
 130 
 131         verificators.put(DESCRIPTION, getServiceDescriptionVerificator());
 132     }
 133 
 134     public WinExeBundlerUtils() {
 135         super(BundleType.INSTALLER, BundlerUtils.EXE);
 136     }
 137 
 138     @Override
 139     public String install(AppWrapper app, String applicationTitle)
 140             throws IOException {
 141         String exePath = findByExtension(app.getBundlesDir(), "exe",
 142                 ROOT_DIRECTORY_DEPTH).toString();
 143         try {
 144             LOG.log(Level.INFO, "Installing {0}.", exePath);
 145             String[] cmd = new String[] { exePath, "/VERYSILENT" };
 146             Utils.runCommand(cmd, true, CONFIG_INSTANCE.getInstallTimeout());
 147             LOG.info("Installation done.");
 148         } catch (ExecutionException e) {
 149             throw new IOException(e);
 150         }
 151         return getInstalledExecutableLocation(app, applicationTitle).toString();
 152     }
 153 
 154     @Override
 155     public void uninstall(AppWrapper app, String appName) throws IOException {
 156         try {
 157             final Path exePath = Paths.get(appName, "unins000.exe");
 158 
 159             Path uninstaller = Paths.get(System.getenv("LOCALAPPDATA"))
 160                     .resolve(exePath);
 161             if (!exists(uninstaller)) {
 162                 uninstaller = Paths.get(getProgramFilesDirWindows())
 163                         .resolve(exePath);
 164             }
 165             if (!exists(uninstaller)) {
 166                 LOG.warning("Can't find uninstaller.");
 167                 return;
 168             }
 169             LOG.log(Level.INFO, "Using uninstaller: {0}", uninstaller);
 170             LOG.log(Level.INFO, "Uninstalling {0}", appName);
 171             String[] cmd = new String[] { uninstaller.toString(),
 172                     "/VERYSILENT" };
 173             Utils.runCommand(cmd, true, CONFIG_INSTANCE.getInstallTimeout());
 174             LOG.info("Uninstallation done.");
 175         } catch (ExecutionException e) {
 176             throw new IOException(e);
 177         }
 178     }
 179 
 180     @Override
 181     public Path getInstalledAppRootLocation(AppWrapper app, String appName) {
 182         Path installPath = Paths.get(System.getenv("LOCALAPPDATA"), appName);
 183         if (!Files.exists(installPath)) {
 184             installPath = Paths.get(getProgramFilesDirWindows(), appName);
 185         }
 186 
 187         assertTrue(Files.exists(installPath),
 188                 "[" + installPath + " not found]");
 189         return installPath;
 190     }
 191 
 192     @Override
 193     public void manualInstall(AppWrapper app) throws IOException {
 194         String exePath = findByExtension(app.getBundlesDir(), "exe",
 195                 ROOT_DIRECTORY_DEPTH).toString();
 196         try {
 197             LOG.log(Level.INFO, "Running installer: {0}", exePath);
 198             Utils.runCommand(new String[] { exePath }, true,
 199                     CONFIG_INSTANCE.getInstallTimeout());
 200         } catch (ExecutionException e) {
 201             throw new IOException(e);
 202         }
 203     }
 204 }