Package hudson.plugins.android_emulator.builder

Source Code of hudson.plugins.android_emulator.builder.AbstractBuilder

package hudson.plugins.android_emulator.builder;

import static hudson.plugins.android_emulator.AndroidEmulator.log;
import hudson.EnvVars;
import hudson.FilePath;
import hudson.Launcher;
import hudson.model.BuildListener;
import hudson.model.EnvironmentContributingAction;
import hudson.model.TaskListener;
import hudson.model.AbstractBuild;
import hudson.model.Computer;
import hudson.model.Hudson;
import hudson.model.Node;
import hudson.plugins.android_emulator.AndroidEmulator;
import hudson.plugins.android_emulator.AndroidEmulator.DescriptorImpl;
import hudson.plugins.android_emulator.Messages;
import hudson.plugins.android_emulator.SdkInstallationException;
import hudson.plugins.android_emulator.SdkInstaller;
import hudson.plugins.android_emulator.sdk.AndroidSdk;
import hudson.plugins.android_emulator.sdk.Tool;
import hudson.plugins.android_emulator.util.Utils;
import hudson.tasks.Builder;
import hudson.util.ForkOutputStream;

import java.io.ByteArrayOutputStream;
import java.io.IOException;
import java.io.PrintStream;
import java.util.regex.Matcher;
import java.util.regex.Pattern;

public abstract class AbstractBuilder extends Builder {

    /** Environment variable set by the plugin to specify the serial of the started AVD. */
    private static final String DEVICE_SERIAL_VARIABLE = "ANDROID_AVD_DEVICE";

    /** Environment variable set by the plugin to specify the telnet interface port. */
    private static final String DEVICE_USER_PORT_VARIABLE = "ANDROID_AVD_USER_PORT";

    /**
     * Gets an Android SDK instance, ready for use.
     *
     * @param build The build for which we should retrieve the SDK instance.
     * @param launcher The launcher for the remote node.
     * @param listener The listener used to get the environment variables.
     * @return An Android SDK instance, or {@code null} if none could be found or installed.
     */
    protected static AndroidSdk getAndroidSdk(AbstractBuild<?, ?> build, Launcher launcher,
            BuildListener listener) throws IOException, InterruptedException {
        boolean shouldInstallSdk = true;
        boolean keepInWorkspace = false;
        DescriptorImpl descriptor = Hudson.getInstance().getDescriptorByType(DescriptorImpl.class);
        if (descriptor != null) {
            shouldInstallSdk = descriptor.shouldInstallSdk;
            keepInWorkspace = descriptor.shouldKeepInWorkspace;
        }

        // Get configured, expanded Android SDK root value
        String androidHome = Utils.expandVariables(build, listener,
                Utils.getConfiguredAndroidHome());
        EnvVars envVars = Utils.getEnvironment(build, listener);

        // Retrieve actual SDK root based on given value
        Node node = Computer.currentComputer().getNode();
        String discoveredAndroidHome = Utils.discoverAndroidHome(launcher, node, envVars,
                androidHome);

        // Get Android SDK object from the given root (or locate on PATH)
        final String androidSdkHome = (envVars != null && keepInWorkspace ? envVars
                .get("WORKSPACE") : null);
        AndroidSdk androidSdk = Utils
                .getAndroidSdk(launcher, discoveredAndroidHome, androidSdkHome);

        // Check whether we should install the SDK
        if (androidSdk == null) {
            PrintStream logger = listener.getLogger();
            if (!shouldInstallSdk) {
                // Couldn't find an SDK, don't want to install it, give up
                log(logger, Messages.SDK_TOOLS_NOT_FOUND());
                return null;
            }

            // Ok, let's download and install the SDK
            log(logger, Messages.INSTALLING_SDK());
            try {
                androidSdk = SdkInstaller.install(launcher, listener, null);
            } catch (SdkInstallationException e) {
                log(logger, Messages.SDK_INSTALLATION_FAILED(), e);
                return null;
            }

            // Check whether anything went wrong
            if (androidSdk == null) {
                log(logger, Messages.SDK_INSTALLATION_FAILED());
                return null;
            }
        }

        // Export environment variables
        final String sdkRoot = androidSdk.getSdkRoot();
        build.addAction(new EnvironmentContributingAction() {

            public void buildEnvVars(AbstractBuild<?, ?> build, EnvVars envVars) {
                if (envVars != null) {
                    envVars.put("ANDROID_HOME", sdkRoot);
                }
            }

            public String getUrlName() {
                return null;
            }

            public String getIconFileName() {
                return null;
            }

            public String getDisplayName() {
                return null;
            }
        });

        return androidSdk;
    }

    /**
     * Gets the Android device identifier for this job, defaulting to the AVD started by this plugin.
     *
     * @param build The build for which we should retrieve the SDK instance.
     * @param listener The listener used to get the environment variables.
     * @return The device identifier (defaulting to the value of "<tt>-s $ANDROID_AVD_DEVICE</tt>").
     */
    protected static String getDeviceIdentifier(AbstractBuild<?, ?> build, BuildListener listener) {
        String deviceSerial = expandVariable(build, listener, DEVICE_SERIAL_VARIABLE);
        if (deviceSerial == null) {
            // No emulator was started by this plugin; assume only one device is attached
            return "";
        }

        // Use the serial of the emulator started by this plugin
        return String.format("-s %s", deviceSerial);
    }

    /**
     * Gets the Android device identifier for this job, defaulting to the AVD started by this plugin.
     *
     * @param build The build for which we should retrieve the SDK instance.
     * @param listener The listener used to get the environment variables.
     * @return The device identifier (defaulting to the value of "<tt>-s $ANDROID_AVD_DEVICE</tt>").
     */
    protected static int getDeviceTelnetPort(AbstractBuild<?, ?> build, BuildListener listener) {
        String devicePort = expandVariable(build, listener, DEVICE_USER_PORT_VARIABLE);
        if (devicePort == null) {
            // No emulator was started by this plugin; assume only one device is attached
            return 5554;
        }

        // Use the serial of the emulator started by this plugin
        return Integer.parseInt(devicePort);
    }

    /**
     * Expands the given variable name to its value from the given build and environment.

     * @param build Used to get build-specific variables.
     * @param listener Used to get environment variables.
     * @param variable The name of the variable to expand.
     * @return The value of the expanded variable, or {@code null} if it could not be resolved.
     */
    private static String expandVariable(AbstractBuild<?, ?> build, BuildListener listener,
            String variable) {
        String varFormat = String.format("$%s", variable);
        String value = Utils.expandVariables(build, listener, varFormat);
        if (value.equals(varFormat)) {
            // Variable did not expand to anything
            return null;
        }

        // Return expanded value
        return value;
    }

    /**
     * Uninstalls the Android package corresponding to the given APK file from an Android device.
     *
     * @param build The build for which we should uninstall the package.
     * @param launcher The launcher for the remote node.
     * @param logger Where log output should be redirected to.
     * @param androidSdk The Android SDK to use.
     * @param deviceIdentifier The device from which the package should be removed.
     * @param apkPath The path to the APK file.
     * @return {@code true} iff uninstallation completed successfully.
     * @throws IOException If execution failed.
     * @throws InterruptedException If execution failed.
     */
    protected static boolean uninstallApk(AbstractBuild<?, ?> build, Launcher launcher,
            PrintStream logger, AndroidSdk androidSdk, String deviceIdentifier, FilePath apkPath)
                throws IOException, InterruptedException {
        // Get package ID to uninstall
        String packageId = getPackageIdForApk(build, launcher, logger, androidSdk, apkPath);
        return uninstallApk(build, launcher, logger, androidSdk, deviceIdentifier, packageId);
    }

    /**
     * Uninstalls the given Android package ID from the given Android device.
     *
     * @param build The build for which we should uninstall the package.
     * @param launcher The launcher for the remote node.
     * @param logger Where log output should be redirected to.
     * @param androidSdk The Android SDK to use.
     * @param deviceIdentifier The device from which the package should be removed.
     * @param packageId The ID of the Android package to remove from the given device.
     * @return {@code true} iff uninstallation completed successfully.
     * @throws IOException If execution failed.
     * @throws InterruptedException If execution failed.
     */
    protected static boolean uninstallApk(AbstractBuild<?, ?> build, Launcher launcher,
            PrintStream logger, AndroidSdk androidSdk, String deviceIdentifier, String packageId)
                throws IOException, InterruptedException {
        AndroidEmulator.log(logger, Messages.UNINSTALLING_APK(packageId));

        ByteArrayOutputStream stdout = new ByteArrayOutputStream();
        ForkOutputStream forkStream = new ForkOutputStream(logger, stdout);
        String adbArgs = String.format("%s uninstall %s", deviceIdentifier, packageId);
        Utils.runAndroidTool(launcher, build.getEnvironment(TaskListener.NULL),
                forkStream, logger, androidSdk, Tool.ADB, adbArgs, null);

        // The package manager simply returns "Success" or "Failure" on stdout
        return stdout.toString().contains("Success");
    }

    /**
     * Determines the package ID of an APK file.
     *
     * @param build The build for which we should uninstall the package.
     * @param launcher The launcher for the remote node.
     * @param logger Where log output should be redirected to.
     * @param androidSdk The Android SDK to use.
     * @param apkPath The path to the APK file.
     * @return The package ID for the given APK, or {@code null} if it could not be determined.
     * @throws IOException If execution failed.
     * @throws InterruptedException If execution failed.
     */
    private static String getPackageIdForApk(AbstractBuild<?, ?> build, Launcher launcher,
            PrintStream logger, AndroidSdk androidSdk, FilePath apkPath)
                throws IOException, InterruptedException {
        // Run aapt command on given APK
        ByteArrayOutputStream aaptOutput = new ByteArrayOutputStream();
        String args = String.format("dump badging \"%s\"", apkPath.getName());
        Utils.runAndroidTool(launcher, aaptOutput, logger, androidSdk, Tool.AAPT, args, apkPath.getParent());

        // Determine package ID from aapt output
        String packageId = null;
        String aaptResult = aaptOutput.toString();
        if (aaptResult.length() > 0) {
            Matcher matcher = Pattern.compile("package: +name='([^']+)'").matcher(aaptResult);
            if (matcher.find()) {
                packageId = matcher.group(1);
            }
        }

        return packageId;
    }

}
TOP

Related Classes of hudson.plugins.android_emulator.builder.AbstractBuilder

TOP
Copyright © 2018 www.massapi.com. All rights reserved.
All source code are property of their respective owners. Java is a trademark of Sun Microsystems, Inc and owned by ORACLE Inc. Contact coftware#gmail.com.