Search in sources :

Example 1 with UpdateCenter

use of com.qlangtech.tis.extension.model.UpdateCenter in project tis by qlangtech.

the class PluginManager method initTasks.

public TaskBuilder initTasks(final InitStrategy initStrategy, TIS tis) {
    TaskBuilder builder;
    if (!pluginListed) {
        builder = new TaskGraphBuilder() {

            List<File> archives;

            Collection<String> bundledPlugins = Collections.emptyList();

            {
                // Handle loadBundledPlugins = add("Loading bundled plugins", new Executable() {
                // public void run(Reactor session) throws Exception {
                // bundledPlugins = loadBundledPlugins();
                // }
                // });
                Handle listUpPlugins = add("Listing up plugins", new Executable() {

                    public void run(Reactor session) throws Exception {
                        archives = initStrategy.listPluginArchives(PluginManager.this);
                    }
                });
                requires(listUpPlugins).attains(PLUGINS_LISTED).add("Preparing plugins", new Executable() {

                    public void run(Reactor session) throws Exception {
                        // once we've listed plugins, we can fill in the reactor with plugin-specific initialization tasks
                        TaskGraphBuilder g = new TaskGraphBuilder();
                        final Map<String, File> inspectedShortNames = new HashMap<String, File>();
                        for (final File arc : archives) {
                            g.followedBy().notFatal().attains(PLUGINS_LISTED).add("Inspecting plugin " + arc, new Executable() {

                                public void run(Reactor session1) throws Exception {
                                    try {
                                        PluginWrapper p = strategy.createPluginWrapper(arc);
                                        if (isDuplicate(p))
                                            return;
                                        p.isBundled = containsHpiJpi(bundledPlugins, arc.getName());
                                        plugins.add(p);
                                    } catch (IOException e) {
                                        failedPlugins.add(new FailedPlugin(arc.getName(), e));
                                        throw e;
                                    }
                                }

                                /**
                                 * Inspects duplication. this happens when you run hpi:run on a bundled plugin,
                                 * as well as putting numbered jpi files, like "cobertura-1.0.jpi" and "cobertura-1.1.jpi"
                                 */
                                private boolean isDuplicate(PluginWrapper p) {
                                    String shortName = p.getShortName();
                                    if (inspectedShortNames.containsKey(shortName)) {
                                        LOGGER.info("Ignoring " + arc + " because " + inspectedShortNames.get(shortName) + " is already loaded");
                                        return true;
                                    }
                                    inspectedShortNames.put(shortName, arc);
                                    return false;
                                }
                            });
                        }
                        g.followedBy().attains(PLUGINS_LISTED).add("Checking cyclic dependencies", new Executable() {

                            /**
                             * Makes sure there's no cycle in dependencies.
                             */
                            public void run(Reactor reactor) throws Exception {
                                try {
                                    CyclicGraphDetector<PluginWrapper> cgd = new CyclicGraphDetector<PluginWrapper>() {

                                        @Override
                                        protected List<PluginWrapper> getEdges(PluginWrapper p) {
                                            List<PluginWrapper> next = new ArrayList<PluginWrapper>();
                                            addTo(p.getDependencies(), next);
                                            addTo(p.getOptionalDependencies(), next);
                                            return next;
                                        }

                                        private void addTo(List<PluginWrapper.Dependency> dependencies, List<PluginWrapper> r) {
                                            for (PluginWrapper.Dependency d : dependencies) {
                                                PluginWrapper p = getPlugin(d.shortName);
                                                if (p != null)
                                                    r.add(p);
                                            }
                                        }

                                        @Override
                                        protected void reactOnCycle(PluginWrapper q, List<PluginWrapper> cycle) throws CyclicGraphDetector.CycleDetectedException {
                                            LOGGER.info("found cycle in plugin dependencies: (root=" + q + ", deactivating all involved) " + Util.join(cycle, " -> "));
                                            for (PluginWrapper pluginWrapper : cycle) {
                                                pluginWrapper.setHasCycleDependency(true);
                                                failedPlugins.add(new FailedPlugin(pluginWrapper.getShortName(), new CycleDetectedException(cycle)));
                                            }
                                        }
                                    };
                                    cgd.run(getPlugins());
                                    // obtain topologically sorted list and overwrite the list
                                    ListIterator<PluginWrapper> litr = getPlugins().listIterator();
                                    for (PluginWrapper p : cgd.getSorted()) {
                                        litr.next();
                                        litr.set(p);
                                        if (p.isActive()) {
                                            activePlugins.add(p);
                                        }
                                    }
                                } catch (CyclicGraphDetector.CycleDetectedException e) {
                                    // disable all plugins since classloading from them can lead to StackOverflow
                                    stop();
                                    // let Hudson fail
                                    throw e;
                                }
                            }
                        });
                        // Let's see for a while until we open this functionality up to plugins
                        // g.followedBy().attains(PLUGINS_LISTED).add("Load compatibility rules", new Executable() {
                        // public void run(Reactor reactor) throws Exception {
                        // compatibilityTransformer.loadRules(uberClassLoader);
                        // }
                        // });
                        session.addAll(g.discoverTasks(session));
                        // technically speaking this is still too early, as at this point tasks are merely scheduled, not necessarily executed.
                        pluginListed = true;
                    }
                });
            }
        };
    } else {
        builder = TaskBuilder.EMPTY_BUILDER;
    }
    // lists up initialization tasks about loading plugins.
    return TaskBuilder.union(builder, new TaskGraphBuilder() {

        {
            requires(PLUGINS_LISTED).attains(PLUGINS_PREPARED).add("Loading plugins", new Executable() {

                /**
                 * Once the plugins are listed, schedule their initialization.
                 */
                public void run(Reactor session) throws Exception {
                    // Jenkins.getInstance().lookup.set(PluginInstanceStore.class, new PluginInstanceStore());
                    TaskGraphBuilder g = new TaskGraphBuilder();
                    // schedule execution of loading plugins
                    for (final PluginWrapper pluginWrapper : activePlugins.toArray(new PluginWrapper[activePlugins.size()])) {
                        g.followedBy().notFatal().attains(PLUGINS_PREPARED).add("Loading plugin " + pluginWrapper.getShortName(), new Executable() {

                            public void run(Reactor session) throws Exception {
                                try {
                                    pluginWrapper.resolvePluginDependencies();
                                    strategy.load(pluginWrapper);
                                } catch (MissingDependencyException e) {
                                    failedPlugins.add(new FailedPlugin(pluginWrapper.getShortName(), e));
                                    activePlugins.remove(pluginWrapper);
                                    plugins.remove(pluginWrapper);
                                    LOGGER.error("Failed to install {}: {}", pluginWrapper.getShortName(), e.getMessage());
                                    return;
                                } catch (IOException e) {
                                    failedPlugins.add(new FailedPlugin(pluginWrapper.getShortName(), e));
                                    activePlugins.remove(pluginWrapper);
                                    plugins.remove(pluginWrapper);
                                    throw e;
                                }
                            }
                        });
                    }
                    // schedule execution of initializing plugins
                    for (final PluginWrapper p : activePlugins.toArray(new PluginWrapper[activePlugins.size()])) {
                        g.followedBy().notFatal().attains(PLUGINS_STARTED).add("Initializing plugin " + p.getShortName(), new Executable() {

                            public void run(Reactor session) throws Exception {
                                if (!activePlugins.contains(p)) {
                                    return;
                                }
                                try {
                                    p.getPlugin().postInitialize();
                                } catch (Exception e) {
                                    failedPlugins.add(new FailedPlugin(p.getShortName(), e));
                                    activePlugins.remove(p);
                                    plugins.remove(p);
                                    throw e;
                                }
                            }
                        });
                    }
                    if (CenterResource.notFetchFromCenterRepository()) {
                        g.followedBy().notFatal().attains(PLUGINS_STARTED).add("Load updateCenter", (reactor) -> {
                            UpdateCenter updateCenter = tis.getUpdateCenter();
                            updateCenter.load();
                            updateCenter.updateAllSites();
                        });
                    }
                    session.addAll(g.discoverTasks(session));
                }
            });
            // All plugins are loaded. Now we can figure out who depends on who.
            requires(PLUGINS_PREPARED).attains(COMPLETED).add("Resolving Dependant Plugins Graph", new Executable() {

                @Override
                public void run(Reactor reactor) throws Exception {
                    resolveDependantPlugins();
                }
            });
        }
    });
}
Also used : TaskBuilder(org.jvnet.hudson.reactor.TaskBuilder) UpdateCenter(com.qlangtech.tis.extension.model.UpdateCenter) ConcurrentHashMap(java.util.concurrent.ConcurrentHashMap) TaskGraphBuilder(org.jvnet.hudson.reactor.TaskGraphBuilder) CopyOnWriteArrayList(java.util.concurrent.CopyOnWriteArrayList) Executable(org.jvnet.hudson.reactor.Executable) Reactor(org.jvnet.hudson.reactor.Reactor) IOException(java.io.IOException) ExtensionRefreshException(com.qlangtech.tis.extension.impl.ExtensionRefreshException) IOException(java.io.IOException) MissingDependencyException(com.qlangtech.tis.extension.impl.MissingDependencyException) CyclicGraphDetector(com.qlangtech.tis.extension.util.CyclicGraphDetector) File(java.io.File) MissingDependencyException(com.qlangtech.tis.extension.impl.MissingDependencyException)

Example 2 with UpdateCenter

use of com.qlangtech.tis.extension.model.UpdateCenter in project tis by qlangtech.

the class PluginAction method doGetUpdateCenterStatus.

/**
 * 取得安装进度状态
 *
 * @param context
 */
public void doGetUpdateCenterStatus(Context context) {
    UpdateCenter updateCenter = TIS.get().getUpdateCenter();
    List<UpdateCenter.UpdateCenterJob> jobs = updateCenter.getJobs();
    Collections.sort(jobs, (a, b) -> {
        // 保证最新的安装job排列在最上面
        return b.id - a.id;
    });
    setBizResult(context, jobs);
}
Also used : UpdateCenter(com.qlangtech.tis.extension.model.UpdateCenter)

Example 3 with UpdateCenter

use of com.qlangtech.tis.extension.model.UpdateCenter in project tis by qlangtech.

the class PluginAction method doInstallPlugins.

/**
 * 安装插件
 *
 * @param context
 */
public void doInstallPlugins(Context context) {
    JSONArray pluginsInstall = this.parseJsonArrayPost();
    if (pluginsInstall.size() < 1) {
        this.addErrorMessage(context, "请选择需要安装的插件");
        return;
    }
    long start = System.currentTimeMillis();
    boolean dynamicLoad = true;
    UUID correlationId = UUID.randomUUID();
    UpdateCenter updateCenter = TIS.get().getUpdateCenter();
    List<Future<UpdateCenter.UpdateCenterJob>> installJobs = new ArrayList<>();
    JSONObject willInstall = null;
    String pluginName = null;
    UpdateSite.Plugin plugin = null;
    List<PluginWrapper> batch = new ArrayList<>();
    for (int i = 0; i < pluginsInstall.size(); i++) {
        willInstall = pluginsInstall.getJSONObject(i);
        pluginName = willInstall.getString("name");
        if (StringUtils.isEmpty(pluginName)) {
            throw new IllegalStateException("plugin name can not empty");
        }
        plugin = updateCenter.getPlugin(pluginName);
        Future<UpdateCenter.UpdateCenterJob> installJob = plugin.deploy(dynamicLoad, correlationId, batch);
        installJobs.add(installJob);
    }
    if (dynamicLoad) {
        installJobs.add(updateCenter.addJob(updateCenter.new CompleteBatchJob(batch, start, correlationId)));
    }
    final TIS tis = TIS.get();
    // TODO: 每个安装流程都要进来
    if (true || !tis.getInstallState().isSetupComplete()) {
        tis.setInstallState(InstallState.INITIAL_PLUGINS_INSTALLING);
        updateCenter.persistInstallStatus();
        new Thread() {

            @Override
            public void run() {
                boolean failures = false;
                INSTALLING: while (true) {
                    try {
                        updateCenter.persistInstallStatus();
                        Thread.sleep(500);
                        failures = false;
                        for (Future<UpdateCenter.UpdateCenterJob> jobFuture : installJobs) {
                            if (!jobFuture.isDone() && !jobFuture.isCancelled()) {
                                continue INSTALLING;
                            }
                            UpdateCenter.UpdateCenterJob job = jobFuture.get();
                            if (job instanceof UpdateCenter.InstallationJob && ((UpdateCenter.InstallationJob) job).status instanceof UpdateCenter.DownloadJob.Failure) {
                                failures = true;
                            }
                        }
                    } catch (Exception e) {
                        logger.warn("Unexpected error while waiting for initial plugin set to install.", e);
                    }
                    break;
                }
                updateCenter.persistInstallStatus();
                if (!failures) {
                    InstallUtil.proceedToNextStateFrom(InstallState.INITIAL_PLUGINS_INSTALLING);
                    // 为了让Assemble等节点的uberClassLoader重新加载一次,需要主动向Assemble等节点发送一个指令
                    notifyPluginUpdate2AssembleNode(TIS.KEY_ACTION_CLEAN_TIS + "=true", "TIS");
                }
            }
        }.start();
    }
}
Also used : UpdateCenter(com.qlangtech.tis.extension.model.UpdateCenter) JSONArray(com.alibaba.fastjson.JSONArray) JSONObject(com.alibaba.fastjson.JSONObject) Future(java.util.concurrent.Future) UpdateSite(com.qlangtech.tis.extension.model.UpdateSite) TIS(com.qlangtech.tis.TIS)

Aggregations

UpdateCenter (com.qlangtech.tis.extension.model.UpdateCenter)3 JSONArray (com.alibaba.fastjson.JSONArray)1 JSONObject (com.alibaba.fastjson.JSONObject)1 TIS (com.qlangtech.tis.TIS)1 ExtensionRefreshException (com.qlangtech.tis.extension.impl.ExtensionRefreshException)1 MissingDependencyException (com.qlangtech.tis.extension.impl.MissingDependencyException)1 UpdateSite (com.qlangtech.tis.extension.model.UpdateSite)1 CyclicGraphDetector (com.qlangtech.tis.extension.util.CyclicGraphDetector)1 File (java.io.File)1 IOException (java.io.IOException)1 ConcurrentHashMap (java.util.concurrent.ConcurrentHashMap)1 CopyOnWriteArrayList (java.util.concurrent.CopyOnWriteArrayList)1 Future (java.util.concurrent.Future)1 Executable (org.jvnet.hudson.reactor.Executable)1 Reactor (org.jvnet.hudson.reactor.Reactor)1 TaskBuilder (org.jvnet.hudson.reactor.TaskBuilder)1 TaskGraphBuilder (org.jvnet.hudson.reactor.TaskGraphBuilder)1