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();
}
});
}
});
}
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);
}
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();
}
}
Aggregations