From 9b2422e7198df6f34282a805058dd5f497417318 Mon Sep 17 00:00:00 2001 From: Mathieu Baudier Date: Wed, 7 Sep 2011 16:07:35 +0000 Subject: [PATCH] Save current state even if not completely stable git-svn-id: https://svn.argeo.org/slc/trunk@4732 4cfe0d0a-d680-48aa-b62c-e0a02a3f76cc --- .../META-INF/MANIFEST.MF | 1 + .../conf/systemCall.xml | 42 ++++ demo/slc_demo_rcp.properties | 1 + demo/slc_gis_position.properties | 6 - .../features/org.argeo.slc.ide/feature.xml | 6 +- .../slc/client/ui/editors/ProcessEditor.java | 8 +- .../slc/client/ui/editors/ProcessLogPage.java | 154 ++++++++++++-- .../META-INF/MANIFEST.MF | 2 +- .../org.argeo.slc.ide.ui/META-INF/MANIFEST.MF | 2 +- .../osgi/EclipseBootLauncherTabGroup.java | 52 +++-- .../ide/ui/launch/osgi/OsgiBootMainTab.java | 42 ++-- .../ide/ui/launch/osgi/OsgiLaunchHelper.java | 26 ++- .../META-INF/spring/agent.xml | 5 +- .../agent/org.argeo.slc.lib.build/.project | 22 ++ .../META-INF/MANIFEST.MF | 7 + .../org.argeo.slc.lib.build/build.properties | 4 + .../AbstractExecutionModulesManager.java | 2 + .../slc/core/execution/ExecutionScope.java | 4 + .../slc/core/execution/ExecutionThread.java | 16 +- .../slc/core/execution/ProcessThread.java | 35 ++++ .../core/execution/ProcessThreadGroup.java | 14 +- .../slc/core/execution/tasks/SystemCall.java | 74 +++++-- .../argeo/slc/execution/ExecutionContext.java | 1 + .../argeo/slc/execution/ExecutionProcess.java | 7 +- .../argeo/slc/execution/ExecutionStep.java | 32 +-- .../org/argeo/slc/process/RealizedFlow.java | 1 + .../org/argeo/slc/process/SlcExecution.java | 5 + .../argeo/slc/process/SlcExecutionStep.java | 6 +- .../main/java/org/argeo/slc/jcr/SlcNames.java | 2 + .../main/java/org/argeo/slc/jcr/SlcTypes.java | 8 + .../jcr/execution/JcrExecutionProcess.java | 71 ++++++- .../main/resources/org/argeo/slc/jcr/slc.cnd | 20 ++ runtime/org.argeo.slc.support.simple/pom.xml | 6 +- .../java/org/argeo/slc/jsch/JschExecutor.java | 110 ++++++++++ .../java/org/argeo/slc/jsch/RemoteExec.java | 176 ++++++++++------ .../slc/lib/linux/rpmfactory/BuildInMock.java | 189 ++++++++++++++++++ .../slc/lib/linux/rpmfactory/CreateSrpm.java | 16 +- .../linux/rpmfactory/RpmBuildEnvironment.java | 24 ++- .../argeo/slc/log4j/SlcExecutionAppender.java | 44 ++-- 39 files changed, 1003 insertions(+), 240 deletions(-) create mode 100644 demo/site/org.argeo.slc.demo.basic/conf/systemCall.xml delete mode 100644 demo/slc_gis_position.properties create mode 100644 modules/agent/org.argeo.slc.lib.build/.project create mode 100644 modules/agent/org.argeo.slc.lib.build/META-INF/MANIFEST.MF create mode 100644 modules/agent/org.argeo.slc.lib.build/build.properties create mode 100644 runtime/org.argeo.slc.support.simple/src/main/java/org/argeo/slc/jsch/JschExecutor.java create mode 100644 runtime/org.argeo.slc.support.simple/src/main/java/org/argeo/slc/lib/linux/rpmfactory/BuildInMock.java diff --git a/demo/site/org.argeo.slc.demo.basic/META-INF/MANIFEST.MF b/demo/site/org.argeo.slc.demo.basic/META-INF/MANIFEST.MF index 85d0238e8..3df944132 100644 --- a/demo/site/org.argeo.slc.demo.basic/META-INF/MANIFEST.MF +++ b/demo/site/org.argeo.slc.demo.basic/META-INF/MANIFEST.MF @@ -16,6 +16,7 @@ Import-Package: net.sf.cglib.core, org.argeo.slc.core.test.context, org.argeo.slc.core.test.tree, org.argeo.slc.execution, + org.argeo.slc.jsch, org.argeo.slc.osgi, org.argeo.slc.structure, org.argeo.slc.test, diff --git a/demo/site/org.argeo.slc.demo.basic/conf/systemCall.xml b/demo/site/org.argeo.slc.demo.basic/conf/systemCall.xml new file mode 100644 index 000000000..41f0e5edd --- /dev/null +++ b/demo/site/org.argeo.slc.demo.basic/conf/systemCall.xml @@ -0,0 +1,42 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/demo/slc_demo_rcp.properties b/demo/slc_demo_rcp.properties index 9a346e4d4..8663b458e 100644 --- a/demo/slc_demo_rcp.properties +++ b/demo/slc_demo_rcp.properties @@ -7,6 +7,7 @@ org.argeo.slc.agent.jcr,\ org.argeo.slc.demo.ant,\ org.argeo.slc.demo.basic,\ org.argeo.slc.demo.minimal,\ +org.argeo.elgis.rpmfactory,\ eclipse.application=org.argeo.slc.client.rcp.application org.argeo.security.ui.initialPerspective=org.argeo.slc.client.ui.slcExecutionPerspective diff --git a/demo/slc_gis_position.properties b/demo/slc_gis_position.properties deleted file mode 100644 index 53670d656..000000000 --- a/demo/slc_gis_position.properties +++ /dev/null @@ -1,6 +0,0 @@ -argeo.osgi.start=\ -org.springframework.osgi.extender,\ -org.argeo.slc.gis.position.gpsbabel,\ -org.argeo.slc.gis.position.ui - -log4j.configuration=file:../../log4j.properties diff --git a/eclipse/features/org.argeo.slc.ide/feature.xml b/eclipse/features/org.argeo.slc.ide/feature.xml index a05b5c1ee..bb176d12d 100644 --- a/eclipse/features/org.argeo.slc.ide/feature.xml +++ b/eclipse/features/org.argeo.slc.ide/feature.xml @@ -2,7 +2,7 @@ @@ -64,14 +64,14 @@ and limitations under the License. id="org.argeo.slc.ide.ui" download-size="0" install-size="0" - version="0.13.1.D20110413_1126" + version="0.13.1.D20110904_1415" unpack="false"/> diff --git a/eclipse/plugins/org.argeo.slc.client.ui/src/main/java/org/argeo/slc/client/ui/editors/ProcessEditor.java b/eclipse/plugins/org.argeo.slc.client.ui/src/main/java/org/argeo/slc/client/ui/editors/ProcessEditor.java index 3fa3e2efd..d619a767a 100644 --- a/eclipse/plugins/org.argeo.slc.client.ui/src/main/java/org/argeo/slc/client/ui/editors/ProcessEditor.java +++ b/eclipse/plugins/org.argeo.slc.client.ui/src/main/java/org/argeo/slc/client/ui/editors/ProcessEditor.java @@ -150,14 +150,14 @@ public class ProcessEditor extends FormEditor implements Node newNode = JcrUtils.mkdirs(session, destPath, SlcTypes.SLC_PROCESS); + Node rootRealizedFlowNode = newNode.addNode(SLC_FLOW); // copy node - JcrUtils.copy(processNode, newNode); + JcrUtils.copy(processNode.getNode(SLC_FLOW), rootRealizedFlowNode); newNode.setProperty(SLC_UUID, uuid); newNode.setProperty(SLC_STATUS, ExecutionProcess.INITIALIZED); // reset realized flow status - Node rootRealizedFlowNode = newNode.getNode(SLC_FLOW); // we just manage one level for the time being NodeIterator nit = rootRealizedFlowNode.getNodes(SLC_FLOW); while (nit.hasNext()) { @@ -178,7 +178,7 @@ public class ProcessEditor extends FormEditor implements builderPage = new ProcessBuilderPage(this, processNode); addPage(builderPage); firePropertyChange(PROP_DIRTY); - logPage = new ProcessLogPage(this); + logPage = new ProcessLogPage(this, processNode); addPage(logPage); } catch (PartInitException e) { throw new SlcException("Cannot add pages", e); @@ -217,7 +217,7 @@ public class ProcessEditor extends FormEditor implements } public void addSteps(ExecutionProcess process, List steps) { - logPage.addSteps(steps); + // logPage.addSteps(steps); } /** Expects one session per editor. */ diff --git a/eclipse/plugins/org.argeo.slc.client.ui/src/main/java/org/argeo/slc/client/ui/editors/ProcessLogPage.java b/eclipse/plugins/org.argeo.slc.client.ui/src/main/java/org/argeo/slc/client/ui/editors/ProcessLogPage.java index 00ad3e48e..46e50b6f0 100644 --- a/eclipse/plugins/org.argeo.slc.client.ui/src/main/java/org/argeo/slc/client/ui/editors/ProcessLogPage.java +++ b/eclipse/plugins/org.argeo.slc.client.ui/src/main/java/org/argeo/slc/client/ui/editors/ProcessLogPage.java @@ -3,8 +3,22 @@ package org.argeo.slc.client.ui.editors; import java.text.DateFormat; import java.text.SimpleDateFormat; import java.util.List; +import java.util.SortedMap; +import java.util.TreeMap; +import javax.jcr.Node; +import javax.jcr.NodeIterator; +import javax.jcr.RepositoryException; +import javax.jcr.Workspace; +import javax.jcr.observation.Event; +import javax.jcr.observation.EventListener; +import javax.jcr.query.Query; + +import org.argeo.eclipse.ui.jcr.AsyncUiEventListener; +import org.argeo.slc.SlcException; import org.argeo.slc.execution.ExecutionStep; +import org.argeo.slc.jcr.SlcNames; +import org.argeo.slc.jcr.SlcTypes; import org.eclipse.swt.SWT; import org.eclipse.swt.widgets.Composite; import org.eclipse.swt.widgets.Control; @@ -27,8 +41,46 @@ public class ProcessLogPage extends FormPage { */ private StringBuffer beforeTextInit = new StringBuffer(""); - public ProcessLogPage(FormEditor editor) { + private Node processNode; + /** + * optimization field: we compute once the length of the path to slc:log so + * that we can easily substring the relative path of logs. + */ + private Integer logPathLength; + + public ProcessLogPage(FormEditor editor, Node processNode) { super(editor, ID, "Log"); + this.processNode = processNode; + + EventListener listener = new LogListener(editor.getSite().getPage() + .getWorkbenchWindow().getWorkbench().getDisplay()); + + try { + String logBasePath = processNode.getPath() + '/' + SlcNames.SLC_LOG; + logPathLength = logBasePath.length(); + + Workspace ws = processNode.getSession().getWorkspace(); + + String statement = "SELECT * FROM [" + + SlcTypes.SLC_LOG_ENTRY + + "] as logEntry" + + " WHERE ISDESCENDANTNODE('" + + logBasePath + + "')" + + " ORDER BY logEntry.[slc:timestamp] ASC, NAME(logEntry) ASC"; + StringBuffer buf = new StringBuffer(""); + NodeIterator it = ws.getQueryManager() + .createQuery(statement, Query.JCR_SQL2).execute() + .getNodes(); + while (it.hasNext()) + appendLogEntry(buf, it.nextNode()); + beforeTextInit = new StringBuffer(buf.toString()); + // text.setText(buf.toString()); + ws.getObservationManager().addEventListener(listener, + Event.NODE_ADDED, logBasePath, true, null, null, false); + } catch (RepositoryException e) { + throw new SlcException("Cannot register listener", e); + } } @Override @@ -39,7 +91,7 @@ public class ProcessLogPage extends FormPage { text = tk.createText(parent, "", SWT.MULTI | SWT.H_SCROLL | SWT.V_SCROLL); text.setEditable(false); - + // transfer the existing buffer the first time if (beforeTextInit.length() > 0) { text.append(beforeTextInit.toString()); @@ -49,27 +101,51 @@ public class ProcessLogPage extends FormPage { } -// @Override -// protected synchronized void createFormContent(IManagedForm mf) { -// ScrolledForm form = mf.getForm(); -// form.setExpandHorizontal(true); -// form.setExpandVertical(true); -// // form.setText("Log"); -// FillLayout mainLayout = new FillLayout(); -// form.getBody().setLayout(mainLayout); -// -// FormToolkit tk = getManagedForm().getToolkit(); -// text = tk.createText(form.getBody(), "", SWT.MULTI | SWT.H_SCROLL -// | SWT.V_SCROLL); -// text.setEditable(false); -// // transfer the existing buffer the first time -// if (beforeTextInit.length() > 0) { -// text.append(beforeTextInit.toString()); -// // clear buffer -// beforeTextInit.setLength(0); -// } -// } + // @Override + // protected synchronized void createFormContent(IManagedForm mf) { + // ScrolledForm form = mf.getForm(); + // form.setExpandHorizontal(true); + // form.setExpandVertical(true); + // // form.setText("Log"); + // FillLayout mainLayout = new FillLayout(); + // form.getBody().setLayout(mainLayout); + // + // FormToolkit tk = getManagedForm().getToolkit(); + // text = tk.createText(form.getBody(), "", SWT.MULTI | SWT.H_SCROLL + // | SWT.V_SCROLL); + // text.setEditable(false); + // // transfer the existing buffer the first time + // if (beforeTextInit.length() > 0) { + // text.append(beforeTextInit.toString()); + // // clear buffer + // beforeTextInit.setLength(0); + // } + // } + protected void appendLogEntry(StringBuffer buf, Node logEntry) + throws RepositoryException { + // +1 in order to remove the first slash + String relPath = logEntry.getPath().substring(logPathLength + 1); + //System.out.println("relPath=" + relPath); + int firstSlashIndex = relPath.indexOf('/'); + int lastSlashIndex = relPath.lastIndexOf('/'); + String thread = relPath.substring(0, firstSlashIndex); + String location = relPath.substring(firstSlashIndex, lastSlashIndex); + + // String date = dateFormat.format(logEntry + // .getProperty(SlcNames.SLC_TIMESTAMP).getDate().getTime()); + String date = logEntry.getProperty(SlcNames.SLC_TIMESTAMP).getString(); + buf.append(date).append(' '); + String type = logEntry.getPrimaryNodeType().getName().substring(7); + buf.append(type).append('\t'); + // buf.append(thread).append('\t'); + // buf.append(location).append('\t'); + buf.append(logEntry.getProperty(SlcNames.SLC_MESSAGE).getString()); + buf.append('\n'); + + } + + /** @deprecated */ public synchronized void addSteps(List steps) { final StringBuffer buf = new StringBuffer(""); for (ExecutionStep step : steps) { @@ -107,4 +183,38 @@ public class ProcessLogPage extends FormPage { text.setFocus(); } + /** JCR event listener notifying when new nodes are added */ + private class LogListener extends AsyncUiEventListener { + + public LogListener(Display display) { + super(display); + } + + @Override + protected void onEventInUiThread(List events) + throws RepositoryException { + // since we use batch save, order is not guaranteed + // so we need to reorder, according to log line number for the time + // being + SortedMap nodes = new TreeMap(); + + for (Event evt : events) { + Node newNode = ProcessLogPage.this.processNode.getSession() + .getNode(evt.getPath()); + if (newNode.isNodeType(SlcTypes.SLC_LOG_ENTRY)) { + nodes.put(Long.parseLong(newNode.getName()), newNode); + } + } + + StringBuffer buf = new StringBuffer(""); + for (Node logEntry : nodes.values()) { + appendLogEntry(buf, logEntry); + } + + if (text != null) + text.append(buf.toString()); + else + beforeTextInit.append(buf); + } + } } diff --git a/eclipse/plugins/org.argeo.slc.ide.branding/META-INF/MANIFEST.MF b/eclipse/plugins/org.argeo.slc.ide.branding/META-INF/MANIFEST.MF index 9928d35d8..b127894ce 100644 --- a/eclipse/plugins/org.argeo.slc.ide.branding/META-INF/MANIFEST.MF +++ b/eclipse/plugins/org.argeo.slc.ide.branding/META-INF/MANIFEST.MF @@ -2,7 +2,7 @@ Manifest-Version: 1.0 Bundle-ManifestVersion: 2 Bundle-Name: Argeo IDE Bundle-SymbolicName: org.argeo.slc.ide.branding;singleton:=true -Bundle-Version: 0.13.1.D20110413_1126 +Bundle-Version: 0.13.1.D20110904_1415 Bundle-Vendor: Argeo.org Require-Bundle: org.eclipse.ui;bundle-version="3.5.1", org.eclipse.osgi;bundle-version="3.5.1", diff --git a/eclipse/plugins/org.argeo.slc.ide.ui/META-INF/MANIFEST.MF b/eclipse/plugins/org.argeo.slc.ide.ui/META-INF/MANIFEST.MF index 5a2b5cbb6..7492f78ce 100644 --- a/eclipse/plugins/org.argeo.slc.ide.ui/META-INF/MANIFEST.MF +++ b/eclipse/plugins/org.argeo.slc.ide.ui/META-INF/MANIFEST.MF @@ -2,7 +2,7 @@ Manifest-Version: 1.0 Bundle-ManifestVersion: 2 Bundle-Name: SLC IDE UI Bundle-SymbolicName: org.argeo.slc.ide.ui;singleton:=true -Bundle-Version: 0.13.1.D20110413_1126 +Bundle-Version: 0.13.1.D20110904_1415 Bundle-Activator: org.argeo.slc.ide.ui.SlcIdeUiPlugin Require-Bundle: org.eclipse.ui, org.eclipse.core.runtime, diff --git a/eclipse/plugins/org.argeo.slc.ide.ui/src/main/java/org/argeo/slc/ide/ui/launch/osgi/EclipseBootLauncherTabGroup.java b/eclipse/plugins/org.argeo.slc.ide.ui/src/main/java/org/argeo/slc/ide/ui/launch/osgi/EclipseBootLauncherTabGroup.java index 7d77ce624..3fffb8063 100644 --- a/eclipse/plugins/org.argeo.slc.ide.ui/src/main/java/org/argeo/slc/ide/ui/launch/osgi/EclipseBootLauncherTabGroup.java +++ b/eclipse/plugins/org.argeo.slc.ide.ui/src/main/java/org/argeo/slc/ide/ui/launch/osgi/EclipseBootLauncherTabGroup.java @@ -1,7 +1,5 @@ package org.argeo.slc.ide.ui.launch.osgi; -import org.eclipse.core.runtime.CoreException; -import org.eclipse.debug.core.ILaunchConfigurationWorkingCopy; import org.eclipse.debug.ui.CommonTab; import org.eclipse.debug.ui.EnvironmentTab; import org.eclipse.debug.ui.ILaunchConfigurationDialog; @@ -9,7 +7,6 @@ import org.eclipse.debug.ui.ILaunchConfigurationTab; import org.eclipse.pde.ui.launcher.EclipseLauncherTabGroup; import org.eclipse.pde.ui.launcher.MainTab; import org.eclipse.pde.ui.launcher.OSGiSettingsTab; -import org.eclipse.pde.ui.launcher.PluginsTab; import org.eclipse.pde.ui.launcher.TracingTab; /** Definition of the set of tabs used in Eclipse Boot launch configuration UI. */ @@ -20,30 +17,31 @@ public class EclipseBootLauncherTabGroup extends EclipseLauncherTabGroup { ILaunchConfigurationTab[] tabs = new ILaunchConfigurationTab[] { new OsgiBootMainTab(true), new MainTab(), - new PluginsTab() { - private boolean activating = false; - - @Override - public void performApply( - ILaunchConfigurationWorkingCopy config) { - super.performApply(config); - if (activating) { - try { - config.doSave(); - } catch (CoreException e) { - e.printStackTrace(); - } - activating = false; - } - } - - @Override - public void activated( - ILaunchConfigurationWorkingCopy workingCopy) { - activating = true; - } - }, new OSGiSettingsTab(), new EnvironmentTab(), - new TracingTab(), new CommonTab() }; + // new PluginsTab() { + // private boolean activating = false; + // + // @Override + // public void performApply( + // ILaunchConfigurationWorkingCopy config) { + // super.performApply(config); + // if (activating) { + // try { + // config.doSave(); + // } catch (CoreException e) { + // e.printStackTrace(); + // } + // activating = false; + // } + // } + // + // @Override + // public void activated( + // ILaunchConfigurationWorkingCopy workingCopy) { + // activating = true; + // } + // }, + new OSGiSettingsTab(), new EnvironmentTab(), new TracingTab(), + new CommonTab() }; setTabs(tabs); } diff --git a/eclipse/plugins/org.argeo.slc.ide.ui/src/main/java/org/argeo/slc/ide/ui/launch/osgi/OsgiBootMainTab.java b/eclipse/plugins/org.argeo.slc.ide.ui/src/main/java/org/argeo/slc/ide/ui/launch/osgi/OsgiBootMainTab.java index d0a76ce9d..5e5ae5050 100644 --- a/eclipse/plugins/org.argeo.slc.ide.ui/src/main/java/org/argeo/slc/ide/ui/launch/osgi/OsgiBootMainTab.java +++ b/eclipse/plugins/org.argeo.slc.ide.ui/src/main/java/org/argeo/slc/ide/ui/launch/osgi/OsgiBootMainTab.java @@ -45,31 +45,14 @@ public class OsgiBootMainTab extends AbstractLaunchConfigurationTab implements container.setLayout(new GridLayout()); container.setLayoutData(new GridData(GridData.FILL_BOTH)); - createGeneral(container); createAdditionalProgramArgs(container); createAdditionalVmArgumentBlock(container); + createAdvanced(container); Dialog.applyDialogFont(container); setControl(container); } - protected void createGeneral(Composite parent) { - Group container = new Group(parent, SWT.NONE); - container.setText("General"); - GridLayout layout = new GridLayout(); - layout.numColumns = 2; - container.setLayout(layout); - container.setLayoutData(new GridData(GridData.FILL_HORIZONTAL)); - - syncBundles = new Button(container, SWT.CHECK); - syncBundles.addSelectionListener(listener); - new Label(container, SWT.NONE) - .setText("Keep bundles in line with target platform and workspace (recommended)"); - clearDataDirectory = new Button(container, SWT.CHECK); - clearDataDirectory.addSelectionListener(listener); - new Label(container, SWT.NONE) - .setText("Clear data directory before launch"); - } - + /** Init UI for programs arguments */ protected void createAdditionalProgramArgs(Composite parent) { Group container = new Group(parent, SWT.NONE); container.setText("Additional Program Arguments"); @@ -88,6 +71,7 @@ public class OsgiBootMainTab extends AbstractLaunchConfigurationTab implements additionalProgramArgs.addModifyListener(listener); } + /** Init UI for VM arguments */ protected void createAdditionalVmArgumentBlock(Composite parent) { Group container = new Group(parent, SWT.NONE); container.setText("Additional VM Arguments"); @@ -105,6 +89,26 @@ public class OsgiBootMainTab extends AbstractLaunchConfigurationTab implements additionalVmArgs.setLayoutData(gd); additionalVmArgs.addModifyListener(listener); + } + + /** Init UI for Advanced section */ + protected void createAdvanced(Composite parent) { + Group container = new Group(parent, SWT.NONE); + container.setText("Advanced"); + GridLayout layout = new GridLayout(); + layout.numColumns = 2; + container.setLayout(layout); + container.setLayoutData(new GridData(GridData.FILL_HORIZONTAL)); + + syncBundles = new Button(container, SWT.CHECK); + syncBundles.addSelectionListener(listener); + new Label(container, SWT.NONE) + .setText("Keep bundles in line with target platform and workspace (recommended)"); + clearDataDirectory = new Button(container, SWT.CHECK); + clearDataDirectory.addSelectionListener(listener); + new Label(container, SWT.NONE) + .setText("Clear data directory before launch"); + addJvmPaths = new Button(container, SWT.CHECK); addJvmPaths.addSelectionListener(listener); new Label(container, SWT.NONE) diff --git a/eclipse/plugins/org.argeo.slc.ide.ui/src/main/java/org/argeo/slc/ide/ui/launch/osgi/OsgiLaunchHelper.java b/eclipse/plugins/org.argeo.slc.ide.ui/src/main/java/org/argeo/slc/ide/ui/launch/osgi/OsgiLaunchHelper.java index 2e55f87f3..d69ed5394 100644 --- a/eclipse/plugins/org.argeo.slc.ide.ui/src/main/java/org/argeo/slc/ide/ui/launch/osgi/OsgiLaunchHelper.java +++ b/eclipse/plugins/org.argeo.slc.ide.ui/src/main/java/org/argeo/slc/ide/ui/launch/osgi/OsgiLaunchHelper.java @@ -9,7 +9,9 @@ import java.util.Iterator; import java.util.List; import java.util.Map; import java.util.Properties; +import java.util.Set; import java.util.StringTokenizer; +import java.util.TreeSet; import org.argeo.slc.ide.ui.SlcIdeUiPlugin; import org.eclipse.core.resources.IFile; @@ -48,7 +50,7 @@ import org.eclipse.swt.widgets.Shell; */ @SuppressWarnings("restriction") public class OsgiLaunchHelper implements OsgiLauncherConstants { - private static Boolean debug = false; + private static Boolean debug = true; private final static String DEFAULT_DATA_DIR = "data"; private final static String DEFAULT_EXEC_DIR = "exec"; @@ -72,7 +74,7 @@ public class OsgiLaunchHelper implements OsgiLauncherConstants { String originalVmArgs = wc.getAttribute( IJavaLaunchConfigurationConstants.ATTR_VM_ARGUMENTS, ""); wc.setAttribute(ATTR_DEFAULT_VM_ARGS, originalVmArgs); - wc.setAttribute(IPDELauncherConstants.CONFIG_CLEAR_AREA, true); + wc.setAttribute(IPDELauncherConstants.CONFIG_CLEAR_AREA, false); } catch (CoreException e) { Shell shell = Display.getCurrent().getActiveShell(); ErrorDialog.openError(shell, "Error", @@ -358,14 +360,10 @@ public class OsgiLaunchHelper implements OsgiLauncherConstants { if (debug) System.out.println("Original bundle list: " + original); - StringBuffer bufBundles = new StringBuffer(1024); StringTokenizer stComa = new StringTokenizer(original, ","); - boolean first = true; + // sort by bundle symbolic name + Set bundleIds = new TreeSet(); bundles: while (stComa.hasMoreTokens()) { - if (first) - first = false; - else - bufBundles.append(','); String bundleId = stComa.nextToken(); if (bundleId.indexOf('*') >= 0) @@ -375,7 +373,6 @@ public class OsgiLaunchHelper implements OsgiLauncherConstants { + " not properly formatted, clean your workspace projects"); int indexAt = bundleId.indexOf('@'); - boolean modified = false; if (indexAt >= 0) { bundleId = bundleId.substring(0, indexAt); } @@ -391,7 +388,17 @@ public class OsgiLaunchHelper implements OsgiLauncherConstants { // skip simple configurator in order to avoid side-effects continue bundles; } + bundleIds.add(bundleId); + } + StringBuffer bufBundles = new StringBuffer(1024); + boolean first = true; + for (String bundleId : bundleIds) { + if (first) + first = false; + else + bufBundles.append(','); + boolean modified = false; if (bundlesToStart.contains(bundleId)) { bufBundles.append(bundleId).append('@').append("default:true"); modified = true; @@ -401,6 +408,7 @@ public class OsgiLaunchHelper implements OsgiLauncherConstants { if (!modified) bufBundles.append(bundleId); + } String output = bufBundles.toString(); return output; diff --git a/modules/agent/org.argeo.slc.agent/META-INF/spring/agent.xml b/modules/agent/org.argeo.slc.agent/META-INF/spring/agent.xml index 1125ab80a..c91f98b20 100644 --- a/modules/agent/org.argeo.slc.agent/META-INF/spring/agent.xml +++ b/modules/agent/org.argeo.slc.agent/META-INF/spring/agent.xml @@ -13,12 +13,13 @@ - + - + \ No newline at end of file diff --git a/modules/agent/org.argeo.slc.lib.build/.project b/modules/agent/org.argeo.slc.lib.build/.project new file mode 100644 index 000000000..6e7c038dc --- /dev/null +++ b/modules/agent/org.argeo.slc.lib.build/.project @@ -0,0 +1,22 @@ + + + org.argeo.slc.lib.build + + + + + + org.eclipse.pde.ManifestBuilder + + + + + org.eclipse.pde.SchemaBuilder + + + + + + org.eclipse.pde.PluginNature + + diff --git a/modules/agent/org.argeo.slc.lib.build/META-INF/MANIFEST.MF b/modules/agent/org.argeo.slc.lib.build/META-INF/MANIFEST.MF new file mode 100644 index 000000000..65cfd79b5 --- /dev/null +++ b/modules/agent/org.argeo.slc.lib.build/META-INF/MANIFEST.MF @@ -0,0 +1,7 @@ +Manifest-Version: 1.0 +Bundle-ManifestVersion: 2 +Bundle-Name: SLC Build +Bundle-SymbolicName: org.argeo.slc.lib.build +Bundle-Version: 0.13.1.SNAPSHOT +Bundle-Vendor: Argeo +Bundle-RequiredExecutionEnvironment: J2SE-1.5 diff --git a/modules/agent/org.argeo.slc.lib.build/build.properties b/modules/agent/org.argeo.slc.lib.build/build.properties new file mode 100644 index 000000000..5fc538bc8 --- /dev/null +++ b/modules/agent/org.argeo.slc.lib.build/build.properties @@ -0,0 +1,4 @@ +source.. = src/main/java/ +output.. = target/classes/ +bin.includes = META-INF/,\ + . diff --git a/runtime/org.argeo.slc.core/src/main/java/org/argeo/slc/core/execution/AbstractExecutionModulesManager.java b/runtime/org.argeo.slc.core/src/main/java/org/argeo/slc/core/execution/AbstractExecutionModulesManager.java index b3d92ae69..1a4ec57e4 100644 --- a/runtime/org.argeo.slc.core/src/main/java/org/argeo/slc/core/execution/AbstractExecutionModulesManager.java +++ b/runtime/org.argeo.slc.core/src/main/java/org/argeo/slc/core/execution/AbstractExecutionModulesManager.java @@ -104,6 +104,8 @@ public abstract class AbstractExecutionModulesManager implements public void dispatchAddSteps(ExecutionProcess process, List steps) { + process.addSteps(steps); + for (Iterator it = getSlcExecutionNotifiers() .iterator(); it.hasNext();) { it.next().addSteps(process, steps); diff --git a/runtime/org.argeo.slc.core/src/main/java/org/argeo/slc/core/execution/ExecutionScope.java b/runtime/org.argeo.slc.core/src/main/java/org/argeo/slc/core/execution/ExecutionScope.java index 82491fc58..b0bba7bf9 100644 --- a/runtime/org.argeo.slc.core/src/main/java/org/argeo/slc/core/execution/ExecutionScope.java +++ b/runtime/org.argeo.slc.core/src/main/java/org/argeo/slc/core/execution/ExecutionScope.java @@ -27,6 +27,10 @@ import org.argeo.slc.execution.ExecutionStack; import org.springframework.beans.factory.ObjectFactory; import org.springframework.beans.factory.config.Scope; +/** + * When Spring beans are instantiated with this scope, the same instance is + * reused across an execution. + */ public class ExecutionScope implements Scope { private final static Log log = LogFactory.getLog(ExecutionScope.class); diff --git a/runtime/org.argeo.slc.core/src/main/java/org/argeo/slc/core/execution/ExecutionThread.java b/runtime/org.argeo.slc.core/src/main/java/org/argeo/slc/core/execution/ExecutionThread.java index 5e288f264..7493de4e7 100644 --- a/runtime/org.argeo.slc.core/src/main/java/org/argeo/slc/core/execution/ExecutionThread.java +++ b/runtime/org.argeo.slc.core/src/main/java/org/argeo/slc/core/execution/ExecutionThread.java @@ -51,8 +51,8 @@ public class ExecutionThread extends Thread { .getFlowDescriptor(); String flowName = executionFlowDescriptor.getName(); - dispatchAddStep(new ExecutionStep(ExecutionStep.PHASE_START, "Flow " - + flowName)); + dispatchAddStep(new ExecutionStep(realizedFlow.getModuleName(), + ExecutionStep.PHASE_START, "Flow " + flowName)); try { String autoUpgrade = System @@ -68,13 +68,13 @@ public class ExecutionThread extends Thread { // TODO: re-throw exception ? String msg = "Execution of flow " + flowName + " failed."; log.error(msg, e); - dispatchAddStep(new ExecutionStep(ExecutionStep.ERROR, msg + " " - + e.getMessage())); + dispatchAddStep(new ExecutionStep(realizedFlow.getModuleName(), + ExecutionStep.ERROR, msg + " " + e.getMessage())); processThread.notifyError(); } finally { processThread.flowCompleted(); - dispatchAddStep(new ExecutionStep(ExecutionStep.PHASE_END, "Flow " - + flowName)); + dispatchAddStep(new ExecutionStep(realizedFlow.getModuleName(), + ExecutionStep.PHASE_END, "Flow " + flowName)); } } @@ -82,4 +82,8 @@ public class ExecutionThread extends Thread { processThread.getProcessThreadGroup().dispatchAddStep(step); } + public RealizedFlow getRealizedFlow() { + return realizedFlow; + } + } diff --git a/runtime/org.argeo.slc.core/src/main/java/org/argeo/slc/core/execution/ProcessThread.java b/runtime/org.argeo.slc.core/src/main/java/org/argeo/slc/core/execution/ProcessThread.java index c11e875b8..1d333845d 100644 --- a/runtime/org.argeo.slc.core/src/main/java/org/argeo/slc/core/execution/ProcessThread.java +++ b/runtime/org.argeo.slc.core/src/main/java/org/argeo/slc/core/execution/ProcessThread.java @@ -21,12 +21,15 @@ import java.util.Collections; import java.util.HashSet; import java.util.List; import java.util.Set; +import java.util.concurrent.ArrayBlockingQueue; +import java.util.concurrent.BlockingQueue; import org.apache.commons.logging.Log; import org.apache.commons.logging.LogFactory; import org.argeo.slc.SlcException; import org.argeo.slc.execution.ExecutionModulesManager; import org.argeo.slc.execution.ExecutionProcess; +import org.argeo.slc.execution.ExecutionStep; import org.argeo.slc.process.RealizedFlow; import org.argeo.slc.process.SlcExecution; @@ -44,6 +47,10 @@ public class ProcessThread extends Thread { private Boolean hadAnError = false; private Boolean killed = false; + private final static Integer STEPS_BUFFER_CAPACITY = 10000; + private BlockingQueue steps = new ArrayBlockingQueue( + STEPS_BUFFER_CAPACITY); + public ProcessThread(ThreadGroup processesThreadGroup, ExecutionModulesManager executionModulesManager, ExecutionProcess process) { @@ -58,6 +65,9 @@ public class ProcessThread extends Thread { log.info("\n##\n## SLC Process #" + process.getUuid() + " STARTED\n##\n"); + // Start logging + new LoggingThread().start(); + String oldStatus = process.getStatus(); process.setStatus(ExecutionProcess.RUNNING); executionModulesManager.dispatchUpdateStatus(process, oldStatus, @@ -170,4 +180,29 @@ public class ProcessThread extends Thread { public ExecutionModulesManager getExecutionModulesManager() { return executionModulesManager; } + + private class LoggingThread extends Thread { + public void run() { + boolean run = true; + while (run) { + List newSteps = new ArrayList(); + processThreadGroup.getSteps().drainTo(newSteps); + if (newSteps.size() > 0) { + //System.out.println(steps.size() + " steps"); + process.addSteps(newSteps); + } + + try { + Thread.sleep(1000); + } catch (InterruptedException e) { + break; + } + + if (!ProcessThread.this.isAlive() + && processThreadGroup.getSteps().size() == 0) + run = false; + } + } + + } } diff --git a/runtime/org.argeo.slc.core/src/main/java/org/argeo/slc/core/execution/ProcessThreadGroup.java b/runtime/org.argeo.slc.core/src/main/java/org/argeo/slc/core/execution/ProcessThreadGroup.java index 6f0143f0f..23d165a4c 100644 --- a/runtime/org.argeo.slc.core/src/main/java/org/argeo/slc/core/execution/ProcessThreadGroup.java +++ b/runtime/org.argeo.slc.core/src/main/java/org/argeo/slc/core/execution/ProcessThreadGroup.java @@ -18,6 +18,8 @@ package org.argeo.slc.core.execution; import java.util.ArrayList; import java.util.List; +import java.util.concurrent.ArrayBlockingQueue; +import java.util.concurrent.BlockingQueue; import org.argeo.slc.execution.ExecutionModulesManager; import org.argeo.slc.execution.ExecutionProcess; @@ -30,6 +32,11 @@ public class ProcessThreadGroup extends ThreadGroup { private final ExecutionModulesManager executionModulesManager; private final ProcessThread processThread; + private final static Integer STEPS_BUFFER_CAPACITY = 10000; + + private BlockingQueue steps = new ArrayBlockingQueue( + STEPS_BUFFER_CAPACITY); + public ProcessThreadGroup(ExecutionModulesManager executionModulesManager, ProcessThread processThread) { super("SLC Process #" + processThread.getProcess().getUuid() @@ -50,7 +57,8 @@ public class ProcessThreadGroup extends ThreadGroup { List steps = new ArrayList(); steps.add(step); - dispatchAddSteps(steps); + // dispatchAddSteps(steps); + this.steps.add(step); } public void dispatchAddSteps(List steps) { @@ -58,4 +66,8 @@ public class ProcessThreadGroup extends ThreadGroup { executionModulesManager.dispatchAddSteps(slcProcess, steps); } + public BlockingQueue getSteps() { + return steps; + } + } diff --git a/runtime/org.argeo.slc.core/src/main/java/org/argeo/slc/core/execution/tasks/SystemCall.java b/runtime/org.argeo.slc.core/src/main/java/org/argeo/slc/core/execution/tasks/SystemCall.java index 5046abb0a..a873b4dca 100644 --- a/runtime/org.argeo.slc.core/src/main/java/org/argeo/slc/core/execution/tasks/SystemCall.java +++ b/runtime/org.argeo.slc.core/src/main/java/org/argeo/slc/core/execution/tasks/SystemCall.java @@ -22,6 +22,8 @@ import java.io.FileWriter; import java.io.IOException; import java.io.InputStream; import java.io.OutputStream; +import java.io.PipedInputStream; +import java.io.PipedOutputStream; import java.io.Writer; import java.util.ArrayList; import java.util.Collections; @@ -62,6 +64,7 @@ public class SystemCall implements Runnable { private String cmd = null; private List command = null; + private Executor executor = new DefaultExecutor(); private Boolean synchronous = true; private String stdErrLogLevel = "ERROR"; @@ -69,7 +72,14 @@ public class SystemCall implements Runnable { private Resource stdOutFile = null; private Resource stdErrFile = null; + private Resource stdInFile = null; + /** + * If no {@link #stdInFile} provided, writing to this stream will write to + * the stdin of the process. + */ + private OutputStream stdInSink = null; + private Boolean redirectStdOut = false; private List outputListeners = Collections @@ -87,6 +97,7 @@ public class SystemCall implements Runnable { private String osConsole = null; private String generateScript = null; + /** 24 hours */ private Long watchdogTimeout = 24 * 60 * 60 * 1000l; private TestResult testResult; @@ -145,13 +156,17 @@ public class SystemCall implements Runnable { stdErrWriter = createWriter(stdOutFile, true); } - if (stdInFile != null) - try { + try { + if (stdInFile != null) stdInStream = stdInFile.getInputStream(); - } catch (IOException e2) { - throw new SlcException("Cannot open a stream for " + stdInFile, - e2); + else { + stdInStream = new PipedInputStream(); + stdInSink = new PipedOutputStream( + (PipedInputStream) stdInStream); } + } catch (IOException e2) { + throw new SlcException("Cannot open a stream for " + stdInFile, e2); + } if (log.isTraceEnabled()) { log.debug("os.name=" + System.getProperty("os.name")); @@ -165,20 +180,24 @@ public class SystemCall implements Runnable { dir.mkdirs(); // Watchdog to check for lost processes - Executor executor = new DefaultExecutor(); - executor.setWatchdog(new ExecuteWatchdog(watchdogTimeout)); + Executor executorToUse; + if (executor != null) + executorToUse = executor; + else + executorToUse = new DefaultExecutor(); + executorToUse.setWatchdog(new ExecuteWatchdog(watchdogTimeout)); if (redirectStreams) { // Redirect standard streams - executor.setStreamHandler(createExecuteStreamHandler(stdOutWriter, - stdOutputStream, stdErrWriter, stdInStream)); + executorToUse.setStreamHandler(createExecuteStreamHandler( + stdOutWriter, stdOutputStream, stdErrWriter, stdInStream)); } else { // Dummy stream handler (otherwise pump is used) - executor.setStreamHandler(new DummyexecuteStreamHandler()); + executorToUse.setStreamHandler(new DummyexecuteStreamHandler()); } - executor.setProcessDestroyer(new ShutdownHookProcessDestroyer()); - executor.setWorkingDirectory(dir); + executorToUse.setProcessDestroyer(new ShutdownHookProcessDestroyer()); + executorToUse.setWorkingDirectory(dir); // Command line to use final CommandLine commandLine = createCommandLine(); @@ -188,12 +207,11 @@ public class SystemCall implements Runnable { // Env variables Map environmentVariablesToUse = null; - if (environmentVariables.size() > 0) { - environmentVariablesToUse = new HashMap(); - if (mergeEnvironmentVariables) - environmentVariablesToUse.putAll(System.getenv()); + environmentVariablesToUse = new HashMap(); + if (mergeEnvironmentVariables) + environmentVariablesToUse.putAll(System.getenv()); + if (environmentVariables.size() > 0) environmentVariablesToUse.putAll(environmentVariables); - } // Execute ExecuteResultHandler executeResultHandler = createExecuteResultHandler(commandLine); @@ -204,7 +222,7 @@ public class SystemCall implements Runnable { try { if (synchronous) try { - int exitValue = executor.execute(commandLine, + int exitValue = executorToUse.execute(commandLine, environmentVariablesToUse); executeResultHandler.onProcessComplete(exitValue); } catch (ExecuteException e1) { @@ -215,7 +233,7 @@ public class SystemCall implements Runnable { executeResultHandler.onProcessFailed(e1); } else - executor.execute(commandLine, environmentVariablesToUse, + executorToUse.execute(commandLine, environmentVariablesToUse, executeResultHandler); } catch (SlcException e) { throw e; @@ -226,6 +244,7 @@ public class SystemCall implements Runnable { IOUtils.closeQuietly(stdOutWriter); IOUtils.closeQuietly(stdErrWriter); IOUtils.closeQuietly(stdInStream); + IOUtils.closeQuietly(stdInSink); } } @@ -345,7 +364,17 @@ public class SystemCall implements Runnable { if (stdErrWriter != null) appendLineToFile(stdErrWriter, line); } - }, stdInStream); + }, stdInStream) { + + @Override + public void stop() { + // prevents the method to block when joining stdin + if (stdInSink != null) + IOUtils.closeQuietly(stdInSink); + + super.stop(); + } + }; return pumpStreamHandler; } @@ -603,6 +632,10 @@ public class SystemCall implements Runnable { this.outputListeners = outputListeners; } + public void setExecutor(Executor executor) { + this.executor = executor; + } + private class DummyexecuteStreamHandler implements ExecuteStreamHandler { public void setProcessErrorStream(InputStream is) throws IOException { @@ -621,5 +654,4 @@ public class SystemCall implements Runnable { } } - } diff --git a/runtime/org.argeo.slc.specs/src/main/java/org/argeo/slc/execution/ExecutionContext.java b/runtime/org.argeo.slc.specs/src/main/java/org/argeo/slc/execution/ExecutionContext.java index 4b0fefc7f..768075030 100644 --- a/runtime/org.argeo.slc.specs/src/main/java/org/argeo/slc/execution/ExecutionContext.java +++ b/runtime/org.argeo.slc.specs/src/main/java/org/argeo/slc/execution/ExecutionContext.java @@ -16,6 +16,7 @@ package org.argeo.slc.execution; +/** Variables or references attached to an execution (typically thread bounded).*/ public interface ExecutionContext { public final static String VAR_EXECUTION_CONTEXT_ID = "slcVar.executionContext.id"; public final static String VAR_EXECUTION_CONTEXT_CREATION_DATE = "slcVar.executionContext.creationDate"; diff --git a/runtime/org.argeo.slc.specs/src/main/java/org/argeo/slc/execution/ExecutionProcess.java b/runtime/org.argeo.slc.specs/src/main/java/org/argeo/slc/execution/ExecutionProcess.java index be70b0955..447ef7f98 100644 --- a/runtime/org.argeo.slc.specs/src/main/java/org/argeo/slc/execution/ExecutionProcess.java +++ b/runtime/org.argeo.slc.specs/src/main/java/org/argeo/slc/execution/ExecutionProcess.java @@ -1,12 +1,13 @@ package org.argeo.slc.execution; +import java.util.List; + /** * A process is the functional representation of a combination of executions. * While an execution is the actual java code running, a process exists before, * during and after the execution actually took place, providing an entry point * for the definition of executions, their monitoring (e.g. logging) and - * tracking. A process can be distributed or parallelized. - *
+ * tracking. A process can be distributed or parallelized.
* NEW => INITIALIZED => SCHEDULED => RUNNING
* RUNNING => {COMPLETED | ERROR | KILLED}
* {COMPLETED | ERROR | KILLED} => PURGED
@@ -44,4 +45,6 @@ public interface ExecutionProcess { /** Sets the current status of this process */ public void setStatus(String status); + + public void addSteps(List steps); } diff --git a/runtime/org.argeo.slc.specs/src/main/java/org/argeo/slc/execution/ExecutionStep.java b/runtime/org.argeo.slc.specs/src/main/java/org/argeo/slc/execution/ExecutionStep.java index 4cabeec09..74201c0e2 100644 --- a/runtime/org.argeo.slc.specs/src/main/java/org/argeo/slc/execution/ExecutionStep.java +++ b/runtime/org.argeo.slc.specs/src/main/java/org/argeo/slc/execution/ExecutionStep.java @@ -34,9 +34,9 @@ public class ExecutionStep implements Serializable { public final static String DEBUG = "DEBUG"; public final static String TRACE = "TRACE"; - /** @deprecated*/ + /** @deprecated */ public final static String START = "START"; - /** @deprecated*/ + /** @deprecated */ public final static String END = "END"; // TODO make the fields final and private when we don't need POJO support @@ -47,27 +47,28 @@ public class ExecutionStep implements Serializable { protected Date timestamp; protected String log; + private String location; + /** Empty constructor */ public ExecutionStep() { - thread = Thread.currentThread().getName(); - } - - /** Creates a step at the current date of type INFO */ - public ExecutionStep(String log) { - this(new Date(), INFO, log); + Thread currentThread = Thread.currentThread(); + thread = currentThread.getName(); } /** Creates a step at the current date */ - public ExecutionStep(String type, String log) { - this(new Date(), type, log); + public ExecutionStep(String location, String type, String log) { + this(location, new Date(), type, log); } /** Creates a step of the given type. */ - public ExecutionStep(Date timestamp, String type, String log) { - this(timestamp, type, log, Thread.currentThread().getName()); + public ExecutionStep(String location, Date timestamp, String type, + String log) { + this(location, timestamp, type, log, Thread.currentThread().getName()); } - public ExecutionStep(Date timestamp, String type, String log, String thread) { + public ExecutionStep(String location, Date timestamp, String type, + String log, String thread) { + this.location = location; this.type = type; this.timestamp = timestamp; this.thread = thread; @@ -103,4 +104,9 @@ public class ExecutionStep implements Serializable { return "Execution step, thread=" + thread + ", type=" + type; } + /** Typically the logging category */ + public String getLocation() { + return location; + } + } diff --git a/runtime/org.argeo.slc.specs/src/main/java/org/argeo/slc/process/RealizedFlow.java b/runtime/org.argeo.slc.specs/src/main/java/org/argeo/slc/process/RealizedFlow.java index e5fdd95cd..4fc50fdfb 100644 --- a/runtime/org.argeo.slc.specs/src/main/java/org/argeo/slc/process/RealizedFlow.java +++ b/runtime/org.argeo.slc.specs/src/main/java/org/argeo/slc/process/RealizedFlow.java @@ -23,6 +23,7 @@ import org.argeo.slc.NameVersion; import org.argeo.slc.execution.ExecutionFlowDescriptor; import org.argeo.slc.execution.ExecutionSpec; +/** A fully configured execution flow, ready to be executed. */ public class RealizedFlow implements Serializable { private static final long serialVersionUID = 1L; diff --git a/runtime/org.argeo.slc.specs/src/main/java/org/argeo/slc/process/SlcExecution.java b/runtime/org.argeo.slc.specs/src/main/java/org/argeo/slc/process/SlcExecution.java index 9b4043462..13189b453 100644 --- a/runtime/org.argeo.slc.specs/src/main/java/org/argeo/slc/process/SlcExecution.java +++ b/runtime/org.argeo.slc.specs/src/main/java/org/argeo/slc/process/SlcExecution.java @@ -24,6 +24,7 @@ import java.util.Map; import java.util.TreeMap; import org.argeo.slc.execution.ExecutionProcess; +import org.argeo.slc.execution.ExecutionStep; /** @deprecated use other implementations of {@link ExecutionProcess} */ public class SlcExecution implements ExecutionProcess, Serializable { @@ -61,6 +62,10 @@ public class SlcExecution implements ExecutionProcess, Serializable { this.steps = steps; } + public void addSteps(List steps) { + // not implemented on deprecated + } + public String getUuid() { return uuid; } diff --git a/runtime/org.argeo.slc.specs/src/main/java/org/argeo/slc/process/SlcExecutionStep.java b/runtime/org.argeo.slc.specs/src/main/java/org/argeo/slc/process/SlcExecutionStep.java index 2d81d2f5a..bc79688ff 100644 --- a/runtime/org.argeo.slc.specs/src/main/java/org/argeo/slc/process/SlcExecutionStep.java +++ b/runtime/org.argeo.slc.specs/src/main/java/org/argeo/slc/process/SlcExecutionStep.java @@ -57,10 +57,8 @@ public class SlcExecutionStep extends ExecutionStep { public SlcExecutionStep(Date timestamp, String type, String log, String thread) { - super(timestamp, type, log, thread); + super("UNKOWN_LOCATION", timestamp, type, log, thread); } - - public String getUuid() { return uuid; @@ -90,7 +88,7 @@ public class SlcExecutionStep extends ExecutionStep { this.logLines = logLines; } - /** public for legacy reasons*/ + /** public for legacy reasons */ public String addLog(String log) { if (logLines == null) logLines = new ArrayList(); diff --git a/runtime/org.argeo.slc.support.jcr/src/main/java/org/argeo/slc/jcr/SlcNames.java b/runtime/org.argeo.slc.support.jcr/src/main/java/org/argeo/slc/jcr/SlcNames.java index 3330fd433..25cc780d6 100644 --- a/runtime/org.argeo.slc.support.jcr/src/main/java/org/argeo/slc/jcr/SlcNames.java +++ b/runtime/org.argeo.slc.support.jcr/src/main/java/org/argeo/slc/jcr/SlcNames.java @@ -18,6 +18,8 @@ public interface SlcNames { public final static String SLC_SPEC = "slc:spec"; public final static String SLC_EXECUTION_SPECS = "slc:executionSpecs"; public final static String SLC_FLOW = "slc:flow"; + public final static String SLC_LOG = "slc:log"; + public final static String SLC_TIMESTAMP = "slc:timestamp"; // spec attribute public final static String SLC_IS_IMMUTABLE = "slc:isImmutable"; diff --git a/runtime/org.argeo.slc.support.jcr/src/main/java/org/argeo/slc/jcr/SlcTypes.java b/runtime/org.argeo.slc.support.jcr/src/main/java/org/argeo/slc/jcr/SlcTypes.java index 382f2a855..9fc152902 100644 --- a/runtime/org.argeo.slc.support.jcr/src/main/java/org/argeo/slc/jcr/SlcTypes.java +++ b/runtime/org.argeo.slc.support.jcr/src/main/java/org/argeo/slc/jcr/SlcTypes.java @@ -20,6 +20,14 @@ public interface SlcTypes { public final static String SLC_CHECK = "slc:check"; public final static String SLC_PROPERTY = "slc:property"; + // Log levels + public final static String SLC_LOG_ENTRY = "slc:logEntry"; + public final static String SLC_LOG_TRACE = "slc:logTrace"; + public final static String SLC_LOG_DEBUG = "slc:logDebug"; + public final static String SLC_LOG_INFO = "slc:logInfo"; + public final static String SLC_LOG_WARNING = "slc:logWarn"; + public final static String SLC_LOG_ERROR = "slc:logError"; + /* * REPO */ diff --git a/runtime/org.argeo.slc.support.jcr/src/main/java/org/argeo/slc/jcr/execution/JcrExecutionProcess.java b/runtime/org.argeo.slc.support.jcr/src/main/java/org/argeo/slc/jcr/execution/JcrExecutionProcess.java index 526b5ebc4..b2fa33395 100644 --- a/runtime/org.argeo.slc.support.jcr/src/main/java/org/argeo/slc/jcr/execution/JcrExecutionProcess.java +++ b/runtime/org.argeo.slc.support.jcr/src/main/java/org/argeo/slc/jcr/execution/JcrExecutionProcess.java @@ -1,5 +1,9 @@ package org.argeo.slc.jcr.execution; +import java.util.Calendar; +import java.util.GregorianCalendar; +import java.util.List; + import javax.jcr.Node; import javax.jcr.RepositoryException; @@ -8,20 +12,24 @@ import org.apache.commons.logging.LogFactory; import org.argeo.jcr.JcrUtils; import org.argeo.slc.SlcException; import org.argeo.slc.execution.ExecutionProcess; +import org.argeo.slc.execution.ExecutionStep; import org.argeo.slc.jcr.SlcNames; +import org.argeo.slc.jcr.SlcTypes; /** Execution process implementation based on a JCR node. */ -public class JcrExecutionProcess implements ExecutionProcess { +public class JcrExecutionProcess implements ExecutionProcess, SlcNames { private Log log = LogFactory.getLog(JcrExecutionProcess.class); private final Node node; + private Long nextLogLine = 1l; + public JcrExecutionProcess(Node node) { this.node = node; } public String getUuid() { try { - return node.getProperty(SlcNames.SLC_UUID).getString(); + return node.getProperty(SLC_UUID).getString(); } catch (RepositoryException e) { throw new SlcException("Cannot get uuid for " + node, e); } @@ -29,7 +37,7 @@ public class JcrExecutionProcess implements ExecutionProcess { public String getStatus() { try { - return node.getProperty(SlcNames.SLC_STATUS).getString(); + return node.getProperty(SLC_STATUS).getString(); } catch (RepositoryException e) { log.error("Cannot get status: " + e); // we should re-throw exception because this information can @@ -41,17 +49,13 @@ public class JcrExecutionProcess implements ExecutionProcess { public void setStatus(String status) { try { - node.setProperty(SlcNames.SLC_STATUS, status); + node.setProperty(SLC_STATUS, status); // last modified properties needs to be manually updated // see https://issues.apache.org/jira/browse/JCR-2233 JcrUtils.updateLastModified(node); node.getSession().save(); } catch (RepositoryException e) { - try { - JcrUtils.discardQuietly(node.getSession()); - } catch (RepositoryException e1) { - // silent - } + JcrUtils.discardUnderlyingSessionQuietly(node); // we should re-throw exception because this information can // probably used for monitoring in case there are already unexpected // exceptions @@ -59,6 +63,55 @@ public class JcrExecutionProcess implements ExecutionProcess { } } + /** + * Synchronized in order to make sure that there is no concurrent + * modification of {@link #nextLogLine}. + */ + public synchronized void addSteps(List steps) { + try { + steps: for (ExecutionStep step : steps) { + String type; + if (step.getType().equals(ExecutionStep.TRACE)) + type = SlcTypes.SLC_LOG_TRACE; + else if (step.getType().equals(ExecutionStep.DEBUG)) + type = SlcTypes.SLC_LOG_DEBUG; + else if (step.getType().equals(ExecutionStep.INFO)) + type = SlcTypes.SLC_LOG_INFO; + else if (step.getType().equals(ExecutionStep.WARNING)) + type = SlcTypes.SLC_LOG_WARNING; + else if (step.getType().equals(ExecutionStep.ERROR)) + type = SlcTypes.SLC_LOG_ERROR; + else + // skip + continue steps; + + String relPath = SLC_LOG + '/' + step.getThread() + '/' + + step.getLocation().replace('.', '/'); + String path = node.getPath() + '/' + relPath; + Node location = JcrUtils.mkdirs(node.getSession(), path); + Node logEntry = location.addNode(Long.toString(nextLogLine), + type); + logEntry.setProperty(SLC_MESSAGE, step.getLog()); + Calendar calendar = new GregorianCalendar(); + calendar.setTime(step.getTimestamp()); + logEntry.setProperty(SLC_TIMESTAMP, calendar); + + // System.out.println("Logged " + logEntry.getPath()); + + nextLogLine++; + } + + // last modified properties needs to be manually updated + // see https://issues.apache.org/jira/browse/JCR-2233 + JcrUtils.updateLastModified(node); + + node.getSession().save(); + } catch (RepositoryException e) { + JcrUtils.discardUnderlyingSessionQuietly(node); + e.printStackTrace(); + } + } + public Node getNode() { return node; } diff --git a/runtime/org.argeo.slc.support.jcr/src/main/resources/org/argeo/slc/jcr/slc.cnd b/runtime/org.argeo.slc.support.jcr/src/main/resources/org/argeo/slc/jcr/slc.cnd index 0e2a5494a..e51744f80 100644 --- a/runtime/org.argeo.slc.support.jcr/src/main/resources/org/argeo/slc/jcr/slc.cnd +++ b/runtime/org.argeo.slc.support.jcr/src/main/resources/org/argeo/slc/jcr/slc.cnd @@ -56,6 +56,26 @@ mixin - slc:uuid (STRING) ! m - slc:status (STRING) m + slc:flow (slc:realizedFlow) ++ slc:log + +// The first part of the relative path is the thread name, rest is location +[slc:logEntry] > nt:unstructured +abstract +- slc:message (STRING) ! +- slc:timestamp (STRING) + +// Log levels are set via types. +// Querying one level also queries the higher levels thanks to the inheritance +// e.g. 'select * from [slc:logWarn]' also returns errors +[slc:logTrace] > slc:logEntry + +[slc:logDebug] > slc:logTrace + +[slc:logInfo] > slc:logDebug + +[slc:logWarning] > slc:logInfo + +[slc:logError] > slc:logWarning [slc:realizedFlow] > nt:base mixin diff --git a/runtime/org.argeo.slc.support.simple/pom.xml b/runtime/org.argeo.slc.support.simple/pom.xml index 2335b5360..36e8403e6 100644 --- a/runtime/org.argeo.slc.support.simple/pom.xml +++ b/runtime/org.argeo.slc.support.simple/pom.xml @@ -74,11 +74,15 @@ com.springsource.org.tmatesoft.svn - + org.apache.commons com.springsource.org.apache.commons.vfs + + org.argeo.dep.osgi + org.argeo.dep.osgi.commons.exec + org.argeo.dep.osgi diff --git a/runtime/org.argeo.slc.support.simple/src/main/java/org/argeo/slc/jsch/JschExecutor.java b/runtime/org.argeo.slc.support.simple/src/main/java/org/argeo/slc/jsch/JschExecutor.java new file mode 100644 index 000000000..dbf62721a --- /dev/null +++ b/runtime/org.argeo.slc.support.simple/src/main/java/org/argeo/slc/jsch/JschExecutor.java @@ -0,0 +1,110 @@ +package org.argeo.slc.jsch; + +import java.io.File; +import java.io.IOException; +import java.util.Map; + +import org.apache.commons.exec.CommandLine; +import org.apache.commons.exec.ExecuteException; +import org.apache.commons.exec.ExecuteResultHandler; +import org.apache.commons.exec.ExecuteStreamHandler; +import org.apache.commons.exec.ExecuteWatchdog; +import org.apache.commons.exec.Executor; +import org.apache.commons.exec.ProcessDestroyer; + +/** A Commons Exec executor executing remotely via SSH */ +public class JschExecutor implements Executor { + private File workingDirectory; + private ExecuteStreamHandler streamHandler; + + private SshTarget sshTarget; + + public void setExitValue(int value) { + // TODO Auto-generated method stub + + } + + public void setExitValues(int[] values) { + // TODO Auto-generated method stub + + } + + public boolean isFailure(int exitValue) { + return Executor.INVALID_EXITVALUE == exitValue; + } + + public ExecuteStreamHandler getStreamHandler() { + return streamHandler; + } + + public void setStreamHandler(ExecuteStreamHandler streamHandler) { + this.streamHandler = streamHandler; + } + + public ExecuteWatchdog getWatchdog() { + // TODO Auto-generated method stub + return null; + } + + public void setWatchdog(ExecuteWatchdog watchDog) { + // TODO Auto-generated method stub + + } + + public ProcessDestroyer getProcessDestroyer() { + // TODO Auto-generated method stub + return null; + } + + public void setProcessDestroyer(ProcessDestroyer processDestroyer) { + // TODO Auto-generated method stub + + } + + public File getWorkingDirectory() { + return workingDirectory; + } + + public void setWorkingDirectory(File workingDirectory) { + this.workingDirectory = workingDirectory; + } + + public int execute(CommandLine command) throws ExecuteException, + IOException { + return execute(command, (Map) null); + } + + public int execute(CommandLine command, Map environment) + throws ExecuteException, IOException { + String cmd = command.toString(); + RemoteExec remoteExec = new RemoteExec(); + remoteExec.setSshTarget(sshTarget); + remoteExec.setStreamHandler(streamHandler); + remoteExec.setCommand(cmd); + if (environment != null) + remoteExec.setEnv(environment); + remoteExec.run(); + return remoteExec.getLastExitStatus() != null ? remoteExec + .getLastExitStatus() : Executor.INVALID_EXITVALUE; + } + + public void execute(CommandLine command, ExecuteResultHandler handler) + throws ExecuteException, IOException { + // TODO Auto-generated method stub + + } + + public void execute(CommandLine command, Map environment, + ExecuteResultHandler handler) throws ExecuteException, IOException { + + } + + public SshTarget getSshTarget() { + return sshTarget; + } + + public void setSshTarget(SshTarget sshTarget) { + this.sshTarget = sshTarget; + } + +} diff --git a/runtime/org.argeo.slc.support.simple/src/main/java/org/argeo/slc/jsch/RemoteExec.java b/runtime/org.argeo.slc.support.simple/src/main/java/org/argeo/slc/jsch/RemoteExec.java index 814e08048..b9eae87ac 100644 --- a/runtime/org.argeo.slc.support.simple/src/main/java/org/argeo/slc/jsch/RemoteExec.java +++ b/runtime/org.argeo.slc.support.simple/src/main/java/org/argeo/slc/jsch/RemoteExec.java @@ -32,6 +32,7 @@ import java.util.List; import java.util.Map; import java.util.StringTokenizer; +import org.apache.commons.exec.ExecuteStreamHandler; import org.apache.commons.io.IOUtils; import org.apache.commons.logging.Log; import org.apache.commons.logging.LogFactory; @@ -66,6 +67,9 @@ public class RemoteExec extends AbstractJschTask { private String user; + private ExecuteStreamHandler streamHandler = null; + + private Integer lastExitStatus = null; /** * If set, stdout is written to it as a list of lines. Cleared before each * run. @@ -106,8 +110,8 @@ public class RemoteExec extends AbstractJschTask { throw new SlcException("Cannot specify commands and script"); BufferedReader reader = null; try { - reader = new BufferedReader(new InputStreamReader(script - .getInputStream())); + reader = new BufferedReader(new InputStreamReader( + script.getInputStream())); String line = null; while ((line = reader.readLine()) != null) { if (!StringUtils.hasText(line)) @@ -256,25 +260,20 @@ public class RemoteExec extends AbstractJschTask { log.debug("Run '" + command + "' on " + getSshTarget() + "..."); channel.connect(); - if (stdIn != null) { - Thread stdInThread = new Thread("Stdin " + getSshTarget()) { - @Override - public void run() { - OutputStream out = null; - try { - out = channel.getOutputStream(); - IOUtils.copy(stdIn.getInputStream(), out); - } catch (IOException e) { - throw new SlcException("Cannot write stdin on " - + getSshTarget(), e); - } finally { - IOUtils.closeQuietly(out); - } + readStdIn(channel); + readStdOut(channel); + + if (streamHandler != null){ + streamHandler.start(); + while(!channel.isClosed()){ + try { + Thread.sleep(100); + } catch (Exception e) { + break; } - }; - stdInThread.start(); + } } - readStdOut(channel); + checkExitStatus(channel); channel.disconnect(); } catch (Exception e) { @@ -283,76 +282,117 @@ public class RemoteExec extends AbstractJschTask { } } - protected void readStdErr(final ChannelExec channel) { - new Thread("stderr " + getSshTarget()) { - public void run() { - BufferedReader stdErr = null; + protected void readStdOut(Channel channel) { + try { + if (stdOut != null) { + OutputStream localStdOut = createOutputStream(stdOut); try { - InputStream in = channel.getErrStream(); - stdErr = new BufferedReader(new InputStreamReader(in)); + IOUtils.copy(channel.getInputStream(), localStdOut); + } finally { + IOUtils.closeQuietly(localStdOut); + } + } else if (streamHandler != null) { + if (channel.getInputStream() != null) + streamHandler.setProcessOutputStream(channel + .getInputStream()); + } else { + BufferedReader stdOut = null; + try { + InputStream in = channel.getInputStream(); + stdOut = new BufferedReader(new InputStreamReader(in)); String line = null; - while ((line = stdErr.readLine()) != null) { - if (!line.trim().equals("")) - log.error(line); + while ((line = stdOut.readLine()) != null) { + if (!line.trim().equals("")) { + + if (stdOutLines != null) { + stdOutLines.add(line); + if (logEvenIfStdOutLines && !quiet) + log.info(line); + } else { + if (!quiet) + log.info(line); + } + } } - } catch (IOException e) { - if (log.isDebugEnabled()) - log.error("Cannot read stderr from " + getSshTarget(), - e); } finally { - IOUtils.closeQuietly(stdErr); + IOUtils.closeQuietly(stdOut); } } - }.start(); + } catch (IOException e) { + throw new SlcException("Cannot redirect stdout from " + + getSshTarget(), e); + } } - protected void readStdOut(Channel channel) { - if (stdOut != null) { - OutputStream localStdOut = createOutputStream(stdOut); + protected void readStdErr(final ChannelExec channel) { + if (streamHandler != null) { try { - IOUtils.copy(channel.getInputStream(), localStdOut); + streamHandler.setProcessOutputStream(channel.getErrStream()); } catch (IOException e) { - throw new SlcException("Cannot redirect stdout", e); - } finally { - IOUtils.closeQuietly(localStdOut); + throw new SlcException("Cannot read stderr from " + + getSshTarget(), e); } } else { - BufferedReader stdOut = null; - try { - InputStream in = channel.getInputStream(); - stdOut = new BufferedReader(new InputStreamReader(in)); - String line = null; - while ((line = stdOut.readLine()) != null) { - if (!line.trim().equals("")) { - - if (stdOutLines != null) { - stdOutLines.add(line); - if (logEvenIfStdOutLines && !quiet) - log.info(line); - } else { - if (!quiet) - log.info(line); + new Thread("stderr " + getSshTarget()) { + public void run() { + BufferedReader stdErr = null; + try { + InputStream in = channel.getErrStream(); + stdErr = new BufferedReader(new InputStreamReader(in)); + String line = null; + while ((line = stdErr.readLine()) != null) { + if (!line.trim().equals("")) + log.error(line); } + } catch (IOException e) { + if (log.isDebugEnabled()) + log.error("Cannot read stderr from " + + getSshTarget(), e); + } finally { + IOUtils.closeQuietly(stdErr); } } + }.start(); + } + } + + protected void readStdIn(final ChannelExec channel) { + if (stdIn != null) { + Thread stdInThread = new Thread("Stdin " + getSshTarget()) { + @Override + public void run() { + OutputStream out = null; + try { + out = channel.getOutputStream(); + IOUtils.copy(stdIn.getInputStream(), out); + } catch (IOException e) { + throw new SlcException("Cannot write stdin on " + + getSshTarget(), e); + } finally { + IOUtils.closeQuietly(out); + } + } + }; + stdInThread.start(); + } else if (streamHandler != null) { + try { + streamHandler.setProcessInputStream(channel.getOutputStream()); } catch (IOException e) { - if (log.isDebugEnabled()) - log.error("Cannot read stdout from " + getSshTarget(), e); - } finally { - IOUtils.closeQuietly(stdOut); + throw new SlcException("Cannot write stdin on " + + getSshTarget(), e); } } } protected void checkExitStatus(Channel channel) { if (channel.isClosed()) { - int exitStatus = channel.getExitStatus(); - if (exitStatus == 0) { + lastExitStatus = channel.getExitStatus(); + if (lastExitStatus == 0) { if (log.isTraceEnabled()) - log.trace("Remote execution exit status: " + exitStatus); + log.trace("Remote execution exit status: " + lastExitStatus); } else { String msg = "Remote execution failed with " + " exit status: " - + exitStatus; + + lastExitStatus; if (failOnBadExitStatus) throw new SlcException(msg); else @@ -379,6 +419,14 @@ public class RemoteExec extends AbstractJschTask { return out; } + public Integer getLastExitStatus() { + return lastExitStatus; + } + + public void setStreamHandler(ExecuteStreamHandler executeStreamHandler) { + this.streamHandler = executeStreamHandler; + } + public void setCommand(String command) { this.command = command; } diff --git a/runtime/org.argeo.slc.support.simple/src/main/java/org/argeo/slc/lib/linux/rpmfactory/BuildInMock.java b/runtime/org.argeo.slc.support.simple/src/main/java/org/argeo/slc/lib/linux/rpmfactory/BuildInMock.java new file mode 100644 index 000000000..c4b35a9a7 --- /dev/null +++ b/runtime/org.argeo.slc.support.simple/src/main/java/org/argeo/slc/lib/linux/rpmfactory/BuildInMock.java @@ -0,0 +1,189 @@ +package org.argeo.slc.lib.linux.rpmfactory; + +import java.io.File; +import java.io.IOException; +import java.util.ArrayList; +import java.util.Arrays; +import java.util.HashSet; +import java.util.List; +import java.util.Set; + +import org.apache.commons.exec.Executor; +import org.apache.commons.io.FileUtils; +import org.apache.commons.logging.Log; +import org.apache.commons.logging.LogFactory; +import org.argeo.slc.SlcException; +import org.argeo.slc.core.execution.tasks.SystemCall; + +/** Rebuild an SRPM in mock. (Historical) Replaces the build-mock.sh script. */ +public class BuildInMock implements Runnable { + private final static Log log = LogFactory.getLog(BuildInMock.class); + + /** Mock flavour provided by the EPEL repository */ + public final static String EPEL = "EPEL"; + /** Mock flavour provided by CentOS until v5 */ + public final static String CENTOS = "CENTOS"; + + public final static String NOARCH = "noarch"; + + private String mockVar = "/var/lib/mock"; + + private String mockFlavour = EPEL; + private String mockConfig = null; + + private String repository; + private String release = null; + private String level = null; + private String arch = NOARCH; + + private String srpm; + + private Boolean mkdirs = true; + + private RpmBuildEnvironment buildEnvironment; + private Executor executor; + + public void run() { + // TODO check if caller is in mock group + + String cfg = mockConfig != null ? mockConfig : repository + "-" + + release + "-" + level + "-" + arch; + + // prepare mock call + SystemCall mock = new SystemCall(); + if (arch != null) + mock.arg("setarch").arg(arch); + mock.arg("mock"); + if (mockFlavour.equals(EPEL)) + mock.arg("-v"); + else if (mockFlavour.equals(CENTOS)) + mock.arg("--debug"); + if (arch != null) + mock.arg("--arch=" + arch); + mock.arg("-r").arg(cfg); + mock.arg(srpm); + + mock.setLogCommand(true); + + // mock command execution + mock.setExecutor(executor); + mock.run(); + + File repoDir = new File(buildEnvironment.getStagingBase() + "/" + + repository + "/" + level + "/" + release); + File srpmDir = new File(repoDir, "SRPMS"); + if (mkdirs) + srpmDir.mkdirs(); + File archDir = null; + File debuginfoDir = null; + if (!arch.equals(NOARCH)) { + archDir = new File(repoDir, arch); + debuginfoDir = new File(archDir, "debuginfo"); + debuginfoDir.mkdirs(); + } + + // copy RPMs + Set reposToRecreate = new HashSet(); + File resultDir = new File(mockVar + "/" + cfg + "/result"); + rpms: for (File file : resultDir.listFiles()) { + if (file.isDirectory()) + continue rpms; + + File[] targetDirs; + if (file.getName().contains(".src.rpm")) + targetDirs = new File[] { srpmDir }; + else if (file.getName().contains("-debuginfo-")) + targetDirs = new File[] { debuginfoDir }; + else if (!arch.equals(NOARCH) + && file.getName().contains("." + arch + ".rpm")) + targetDirs = new File[] { archDir }; + else if (file.getName().contains(".noarch.rpm")) { + List dirs = new ArrayList(); + for (String arch : buildEnvironment.getArchs()) + dirs.add(new File(repoDir, arch)); + targetDirs = dirs.toArray(new File[dirs.size()]); + } else if (file.getName().contains(".rpm")) + throw new SlcException("Don't know where to copy " + file); + else { + if (log.isTraceEnabled()) + log.trace("Skip " + file); + continue rpms; + } + + reposToRecreate.addAll(Arrays.asList(targetDirs)); + copyToDirs(file, targetDirs); + } + + // recreate changed repos + for (File repoToRecreate : reposToRecreate) { + SystemCall createrepo = new SystemCall(); + createrepo.arg("createrepo"); + // sqllite db + createrepo.arg("-d"); + // quiet + createrepo.arg("-q"); + createrepo.arg(repoToRecreate.getAbsolutePath()); + + createrepo.setExecutor(executor); + createrepo.run(); + log.info("Updated repo " + repoToRecreate); + } + } + + protected void copyToDirs(File file, File[] dirs) { + for (File dir : dirs) { + try { + FileUtils.copyFileToDirectory(file, dir); + if (log.isDebugEnabled()) + log.debug(file + " => " + dir); + } catch (IOException e) { + throw new SlcException("Cannot copy " + file + " to " + dir, e); + } + } + } + + public void setMockFlavour(String mockFlavour) { + this.mockFlavour = mockFlavour; + } + + public void setMockConfig(String mockConfig) { + this.mockConfig = mockConfig; + } + + public void setRepository(String repo) { + this.repository = repo; + } + + public void setRelease(String release) { + this.release = release; + } + + public void setLevel(String level) { + this.level = level; + } + + public void setArch(String arch) { + this.arch = arch; + } + + public void setSrpm(String srpm) { + this.srpm = srpm; + } + + public void setMockVar(String mockVar) { + this.mockVar = mockVar; + } + + public void setMkdirs(Boolean mkdirs) { + this.mkdirs = mkdirs; + } + + public void setBuildEnvironment(RpmBuildEnvironment buildEnvironment) { + this.buildEnvironment = buildEnvironment; + } + + public void setExecutor(Executor executor) { + this.executor = executor; + } + +} diff --git a/runtime/org.argeo.slc.support.simple/src/main/java/org/argeo/slc/lib/linux/rpmfactory/CreateSrpm.java b/runtime/org.argeo.slc.support.simple/src/main/java/org/argeo/slc/lib/linux/rpmfactory/CreateSrpm.java index 1588bfa8f..04680df7b 100644 --- a/runtime/org.argeo.slc.support.simple/src/main/java/org/argeo/slc/lib/linux/rpmfactory/CreateSrpm.java +++ b/runtime/org.argeo.slc.support.simple/src/main/java/org/argeo/slc/lib/linux/rpmfactory/CreateSrpm.java @@ -7,6 +7,7 @@ import java.io.OutputStream; import java.util.ArrayList; import java.util.List; +import org.apache.commons.exec.Executor; import org.apache.commons.io.FileUtils; import org.apache.commons.io.IOUtils; import org.apache.commons.logging.Log; @@ -22,7 +23,7 @@ public class CreateSrpm implements Runnable { private File topdir; - /** Directory where to cache downloaded dsitributions. */ + /** Directory where to cache downloaded distributions. */ private File distributionCache; private Resource specFile; @@ -33,6 +34,8 @@ public class CreateSrpm implements Runnable { private File srpmFile; + private Executor executor; + public void run() { File sourcesDir = new File(topdir, "SOURCES"); sourcesDir.mkdirs(); @@ -58,12 +61,15 @@ public class CreateSrpm implements Runnable { packageSrpm.arg("rpmbuild"); packageSrpm.arg("-bs").arg("--nodeps"); packageSrpm.arg("--rcfile=rpmrc"); + packageSrpm.arg("--macros=" + RpmBuildEnvironment.defaultMacroFiles + + ":rpmmacros"); // buildSrpm.arg("-D", "_topdir " + topdir.getCanonicalPath() + ""); packageSrpm.arg("SPECS/" + specFile.getFilename()); packageSrpm.setExecDir(topdir.getCanonicalPath()); packageSrpm.setLogCommand(true); // Execute + packageSrpm.setExecutor(executor); String answer = packageSrpm.function(); // Extract generated SRPM path @@ -131,8 +137,8 @@ public class CreateSrpm implements Runnable { if (!targetFile.exists() || overwriteSources) copyResourceToFile(res, targetFile); if (!targetDir.equals(sourcesDir)) { - File fileInSourcesDir = new File(sourcesDir, targetFile - .getName()); + File fileInSourcesDir = new File(sourcesDir, + targetFile.getName()); if (!fileInSourcesDir.exists() || !(fileInSourcesDir.length() == targetFile .length())) @@ -198,4 +204,8 @@ public class CreateSrpm implements Runnable { this.distributionCache = distributionCache; } + public void setExecutor(Executor executor) { + this.executor = executor; + } + } diff --git a/runtime/org.argeo.slc.support.simple/src/main/java/org/argeo/slc/lib/linux/rpmfactory/RpmBuildEnvironment.java b/runtime/org.argeo.slc.support.simple/src/main/java/org/argeo/slc/lib/linux/rpmfactory/RpmBuildEnvironment.java index 123e055a3..5c2ba1ed2 100644 --- a/runtime/org.argeo.slc.support.simple/src/main/java/org/argeo/slc/lib/linux/rpmfactory/RpmBuildEnvironment.java +++ b/runtime/org.argeo.slc.support.simple/src/main/java/org/argeo/slc/lib/linux/rpmfactory/RpmBuildEnvironment.java @@ -7,6 +7,7 @@ import java.util.HashMap; import java.util.List; import java.util.Map; +import org.apache.commons.exec.Executor; import org.apache.commons.io.FileUtils; import org.argeo.slc.SlcException; @@ -15,9 +16,15 @@ import org.argeo.slc.SlcException; * components performing the various actions related to RPM build. */ public class RpmBuildEnvironment { - private String defaultMacroFiles = "/usr/lib/rpm/macros:/usr/lib/rpm/ia32e-linux/macros:/usr/lib/rpm/redhat/macros:/etc/rpm/macros.*:/etc/rpm/macros:/etc/rpm/ia32e-linux/macros:~/.rpmmacros"; + static String defaultMacroFiles = "/usr/lib/rpm/macros:/usr/lib/rpm/ia32e-linux/macros:/usr/lib/rpm/redhat/macros:/etc/rpm/macros.*:/etc/rpm/macros:/etc/rpm/ia32e-linux/macros:~/.rpmmacros"; + private Map rpmmacros = new HashMap(); + private List archs = new ArrayList(); + + private String stagingBase = System.getProperty("user.home") + + "/dev/staging"; + /** Write (topdir)/rpmmacros and (topdir)/rpmrc */ public void writeRpmbuildConfigFiles(File topdir) { writeRpmbuildConfigFiles(topdir, new File(topdir, "rpmmacros"), @@ -61,4 +68,19 @@ public class RpmBuildEnvironment { this.defaultMacroFiles = defaultMacroFiles; } + public void setArchs(List archs) { + this.archs = archs; + } + + public List getArchs() { + return archs; + } + + public String getStagingBase() { + return stagingBase; + } + + public void setStagingBase(String stagingBase) { + this.stagingBase = stagingBase; + } } diff --git a/runtime/org.argeo.slc.support.simple/src/main/java/org/argeo/slc/log4j/SlcExecutionAppender.java b/runtime/org.argeo.slc.support.simple/src/main/java/org/argeo/slc/log4j/SlcExecutionAppender.java index 880aefef1..f8930fff8 100644 --- a/runtime/org.argeo.slc.support.simple/src/main/java/org/argeo/slc/log4j/SlcExecutionAppender.java +++ b/runtime/org.argeo.slc.support.simple/src/main/java/org/argeo/slc/log4j/SlcExecutionAppender.java @@ -19,20 +19,15 @@ package org.argeo.slc.log4j; import java.util.Date; import org.apache.log4j.AppenderSkeleton; -import org.apache.log4j.Layout; import org.apache.log4j.Level; import org.apache.log4j.Logger; -import org.apache.log4j.PatternLayout; import org.apache.log4j.spi.LoggingEvent; import org.argeo.slc.core.execution.ExecutionThread; import org.argeo.slc.core.execution.ProcessThreadGroup; import org.argeo.slc.execution.ExecutionStep; -import org.springframework.beans.factory.DisposableBean; -import org.springframework.beans.factory.InitializingBean; /** Not meant to be used directly in standard log4j config */ -public class SlcExecutionAppender extends AppenderSkeleton implements - InitializingBean, DisposableBean { +public class SlcExecutionAppender extends AppenderSkeleton { private Boolean disabled = false; @@ -49,15 +44,15 @@ public class SlcExecutionAppender extends AppenderSkeleton implements } }; - private Layout layout = null; - private String pattern = "%m - %c%n"; + // private Layout layout = null; + // private String pattern = "%m - %c%n"; private Boolean onlyExecutionThread = false; - public void afterPropertiesSet() { - if (layout != null) - setLayout(layout); - else - setLayout(new PatternLayout(pattern)); + public void init() { + // if (layout != null) + // setLayout(layout); + // else + // setLayout(new PatternLayout(pattern)); Logger.getRootLogger().addAppender(this); } @@ -87,6 +82,7 @@ public class SlcExecutionAppender extends AppenderSkeleton implements } } + // Check whether we are within an executing process Thread currentThread = Thread.currentThread(); if (currentThread.getThreadGroup() instanceof ProcessThreadGroup) { if (onlyExecutionThread @@ -108,13 +104,14 @@ public class SlcExecutionAppender extends AppenderSkeleton implements else type = ExecutionStep.INFO; - ExecutionStep step = new ExecutionStep(new Date( - event.getTimeStamp()), type, layout.format(event)); + ExecutionStep step = new ExecutionStep(event.getLoggerName(), + new Date(event.getTimeStamp()), type, event.getMessage() + .toString()); try { dispatching.set(true); ((ProcessThreadGroup) currentThread.getThreadGroup()) - .dispatchAddStep(step); + .getSteps().add(step); } finally { dispatching.set(false); } @@ -132,14 +129,19 @@ public class SlcExecutionAppender extends AppenderSkeleton implements return false; } - public void setLayout(Layout layout) { - this.layout = layout; - } + // public void setLayout(Layout layout) { + // this.layout = layout; + // } - public void setPattern(String pattern) { - this.pattern = pattern; + /** For development purpose, since using regular logging is not easy here */ + private static void stdOut(Object obj) { + System.out.println(obj); } + // public void setPattern(String pattern) { + // this.pattern = pattern; + // } + public void setOnlyExecutionThread(Boolean onlyExecutionThread) { this.onlyExecutionThread = onlyExecutionThread; } -- 2.39.2