Package org.jenkinsci.plugins.ios.connector

Source Code of org.jenkinsci.plugins.ios.connector.iOSDeviceList

package org.jenkinsci.plugins.ios.connector;

import com.google.common.collect.LinkedHashMultimap;
import com.google.common.collect.Multimap;
import com.google.common.collect.Multimaps;
import com.sun.jna.Platform;
import hudson.Extension;
import hudson.Launcher.LocalLauncher;
import hudson.model.Computer;
import hudson.model.ModelObject;
import hudson.model.RootAction;
import hudson.model.TaskListener;
import hudson.remoting.Callable;
import hudson.security.Permission;
import hudson.security.PermissionGroup;
import hudson.util.IOException2;
import hudson.util.StreamTaskListener;
import jenkins.model.Jenkins;
import org.apache.commons.io.FileUtils;
import org.kohsuke.stapler.HttpResponse;
import org.kohsuke.stapler.HttpResponses;
import org.kohsuke.stapler.interceptor.RequirePOST;

import java.io.BufferedReader;
import java.io.ByteArrayInputStream;
import java.io.ByteArrayOutputStream;
import java.io.File;
import java.io.IOException;
import java.io.InputStreamReader;
import java.io.PrintStream;
import java.util.Collections;
import java.util.List;
import java.util.Map;
import java.util.Map.Entry;
import java.util.Properties;
import java.util.concurrent.Future;

import static com.google.common.collect.Lists.newArrayList;
import static com.google.common.collect.Maps.newHashMap;
import static hudson.util.jna.GNUCLibrary.*;

/**
* Maintains the list of iOS Devices connected to all the slaves.
*
* @author Kohsuke Kawaguchi
*/
@Extension
public class iOSDeviceList implements RootAction, ModelObject {
    private volatile Multimap<Computer,iOSDevice> devices = LinkedHashMultimap.create();

    /**
     * List of all the devices.
     */
    public Multimap<Computer,iOSDevice> getDevices() {
        return Multimaps.unmodifiableMultimap(devices);
    }

    /**
     * Refresh all slaves in concurrently.
     */
    public void updateAll(TaskListener listener) {
        Jenkins.getInstance().checkPermission(Jenkins.ADMINISTER);

        Map<Future<List<iOSDevice>>,Computer> futures = newHashMap();

        for (Computer c : Jenkins.getInstance().getComputers()) {
            try {
                futures.put(c.getChannel().callAsync(new FetchTask(listener)), c);
            } catch (Exception e) {
                e.printStackTrace(listener.error("Failed to list up iOS devices on"+c.getName()));
            }
        }

        Multimap<Computer,iOSDevice> devices = LinkedHashMultimap.create();
        for (Entry<Future<List<iOSDevice>>, Computer> e : futures.entrySet()) {
            Computer c = e.getValue();
            try {
                List<iOSDevice> devs = e.getKey().get();
                for (iOSDevice d : devs)
                    d.computer = c;
                devices.putAll(c, devs);
            } catch (Exception x) {
                x.printStackTrace(listener.error("Failed to list up iOS devices on "+c.getName()));
            }
        }

        this.devices = devices;
    }

    public void update(Computer c, TaskListener listener) {
        Jenkins.getInstance().checkPermission(Jenkins.ADMINISTER);

        List<iOSDevice> r = Collections.emptyList();
        if (c.isOnline()) {// ignore disabled slaves
            try {
                r = c.getChannel().call(new FetchTask(listener));
                for (iOSDevice dev : r) dev.computer = c;
            } catch (Exception e) {
                e.printStackTrace(listener.error("Failed to list up iOS devices"));
            }
        }

        synchronized (this) {
            Multimap<Computer,iOSDevice> clone = LinkedHashMultimap.create(devices);
            clone.removeAll(c);
            clone.putAll(c, r);
            devices = clone;
        }
    }

    public synchronized void remove(Computer c) {
        Multimap<Computer,iOSDevice> clone = LinkedHashMultimap.create(devices);
        clone.removeAll(c);
        devices = clone;
    }

    public String getIconFileName() {
        return "/plugin/ios-device-connector/icons/24x24/iphone.png";
    }

    public String getDisplayName() {
        return "Connected iOS Devices";
    }

    public String getUrlName() {
        if (Jenkins.getInstance().hasPermission(READ))
            return "ios-devices";
        else
            return null;
    }

    @RequirePOST
    public HttpResponse doRefresh() {
        updateAll(StreamTaskListener.NULL);
        return HttpResponses.redirectToDot();
    }

    /**
     * Maps {@link iOSDevice} to URL space.
     */
    public iOSDevice getDynamic(String token) {
        return getDevice(token);
    }

    public iOSDevice getDevice(String udid) {
        for (iOSDevice dev : devices.values())
            if (udid.equalsIgnoreCase(dev.getUniqueDeviceId()) || udid.equals(dev.getDeviceName()))
                return dev;
        return null;
    }

    /**
     * Retrieves {@link iOSDevice}s connected to a machine.
     */
    private static class FetchTask implements Callable<List<iOSDevice>,IOException> {
        private final TaskListener listener;

        private FetchTask(TaskListener listener) {
            this.listener = listener;
        }

        public List<iOSDevice> call() throws IOException {
            if (!Platform.isMac())
                return Collections.emptyList();

            File exe = File.createTempFile("ios","list");
            try {
                PrintStream logger = listener.getLogger();
                logger.println("Listing up iOS Devices");

                FileUtils.copyURLToFile(getClass().getResource("list"),exe);
                LIBC.chmod(exe.getAbsolutePath(),0755);

                ByteArrayOutputStream out = new ByteArrayOutputStream();
                int exit = new LocalLauncher(listener).launch().cmds(exe).stdout(out).stderr(logger).join();
                if (exit!=0) {
                    logger.println(exe + " failed to execute:" + exit);
                    logger.write(out.toByteArray());
                    logger.println();
                    return Collections.emptyList();
                }

                return parseOutput(logger, out);
            } catch (InterruptedException e) {
                throw new IOException2("Interrupted while listing up devices",e);
            } finally {
                exe.delete();
            }
        }

        private List<iOSDevice> parseOutput(PrintStream logger, ByteArrayOutputStream out) throws IOException {
            List<iOSDevice> r = newArrayList();

            {// parse the output
                Properties p = new Properties();
                String line;
                BufferedReader in = new BufferedReader(new InputStreamReader(new ByteArrayInputStream(out.toByteArray()),"UTF-8"));
                while ((line=in.readLine())!=null) {
                    if (line.length()==0) {
                        r.add(new iOSDevice(p));
                        p.clear();
                        continue;
                    }
                    int idx = line.indexOf('=');
                    if (idx<0) {
                        logger.println("Invalid output line:"+line);
                        logger.write(out.toByteArray());
                        logger.println();
                        return Collections.emptyList();
                    }
                    p.put(line.substring(0,idx),line.substring(idx+1));
                }
            }

            return r;
        }
    }

    public static final PermissionGroup GROUP = new PermissionGroup(iOSDeviceList.class,Messages._iOSDeviceList_PermissionGroup_Title());
    public static final Permission READ = new Permission(GROUP,"Read",Messages._iOSDeviceList_ReadPermission(),Jenkins.READ);
    public static final Permission DEPLOY = new Permission(GROUP,"Deploy",Messages._iOSDeviceList_DeployPermission(),Jenkins.ADMINISTER);
}
TOP

Related Classes of org.jenkinsci.plugins.ios.connector.iOSDeviceList

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.