]> git.argeo.org Git - gpl/argeo-slc.git/commitdiff
Save current state even if not completely stable
authorMathieu Baudier <mbaudier@argeo.org>
Wed, 7 Sep 2011 16:07:35 +0000 (16:07 +0000)
committerMathieu Baudier <mbaudier@argeo.org>
Wed, 7 Sep 2011 16:07:35 +0000 (16:07 +0000)
git-svn-id: https://svn.argeo.org/slc/trunk@4732 4cfe0d0a-d680-48aa-b62c-e0a02a3f76cc

39 files changed:
demo/site/org.argeo.slc.demo.basic/META-INF/MANIFEST.MF
demo/site/org.argeo.slc.demo.basic/conf/systemCall.xml [new file with mode: 0644]
demo/slc_demo_rcp.properties
demo/slc_gis_position.properties [deleted file]
eclipse/features/org.argeo.slc.ide/feature.xml
eclipse/plugins/org.argeo.slc.client.ui/src/main/java/org/argeo/slc/client/ui/editors/ProcessEditor.java
eclipse/plugins/org.argeo.slc.client.ui/src/main/java/org/argeo/slc/client/ui/editors/ProcessLogPage.java
eclipse/plugins/org.argeo.slc.ide.branding/META-INF/MANIFEST.MF
eclipse/plugins/org.argeo.slc.ide.ui/META-INF/MANIFEST.MF
eclipse/plugins/org.argeo.slc.ide.ui/src/main/java/org/argeo/slc/ide/ui/launch/osgi/EclipseBootLauncherTabGroup.java
eclipse/plugins/org.argeo.slc.ide.ui/src/main/java/org/argeo/slc/ide/ui/launch/osgi/OsgiBootMainTab.java
eclipse/plugins/org.argeo.slc.ide.ui/src/main/java/org/argeo/slc/ide/ui/launch/osgi/OsgiLaunchHelper.java
modules/agent/org.argeo.slc.agent/META-INF/spring/agent.xml
modules/agent/org.argeo.slc.lib.build/.project [new file with mode: 0644]
modules/agent/org.argeo.slc.lib.build/META-INF/MANIFEST.MF [new file with mode: 0644]
modules/agent/org.argeo.slc.lib.build/build.properties [new file with mode: 0644]
runtime/org.argeo.slc.core/src/main/java/org/argeo/slc/core/execution/AbstractExecutionModulesManager.java
runtime/org.argeo.slc.core/src/main/java/org/argeo/slc/core/execution/ExecutionScope.java
runtime/org.argeo.slc.core/src/main/java/org/argeo/slc/core/execution/ExecutionThread.java
runtime/org.argeo.slc.core/src/main/java/org/argeo/slc/core/execution/ProcessThread.java
runtime/org.argeo.slc.core/src/main/java/org/argeo/slc/core/execution/ProcessThreadGroup.java
runtime/org.argeo.slc.core/src/main/java/org/argeo/slc/core/execution/tasks/SystemCall.java
runtime/org.argeo.slc.specs/src/main/java/org/argeo/slc/execution/ExecutionContext.java
runtime/org.argeo.slc.specs/src/main/java/org/argeo/slc/execution/ExecutionProcess.java
runtime/org.argeo.slc.specs/src/main/java/org/argeo/slc/execution/ExecutionStep.java
runtime/org.argeo.slc.specs/src/main/java/org/argeo/slc/process/RealizedFlow.java
runtime/org.argeo.slc.specs/src/main/java/org/argeo/slc/process/SlcExecution.java
runtime/org.argeo.slc.specs/src/main/java/org/argeo/slc/process/SlcExecutionStep.java
runtime/org.argeo.slc.support.jcr/src/main/java/org/argeo/slc/jcr/SlcNames.java
runtime/org.argeo.slc.support.jcr/src/main/java/org/argeo/slc/jcr/SlcTypes.java
runtime/org.argeo.slc.support.jcr/src/main/java/org/argeo/slc/jcr/execution/JcrExecutionProcess.java
runtime/org.argeo.slc.support.jcr/src/main/resources/org/argeo/slc/jcr/slc.cnd
runtime/org.argeo.slc.support.simple/pom.xml
runtime/org.argeo.slc.support.simple/src/main/java/org/argeo/slc/jsch/JschExecutor.java [new file with mode: 0644]
runtime/org.argeo.slc.support.simple/src/main/java/org/argeo/slc/jsch/RemoteExec.java
runtime/org.argeo.slc.support.simple/src/main/java/org/argeo/slc/lib/linux/rpmfactory/BuildInMock.java [new file with mode: 0644]
runtime/org.argeo.slc.support.simple/src/main/java/org/argeo/slc/lib/linux/rpmfactory/CreateSrpm.java
runtime/org.argeo.slc.support.simple/src/main/java/org/argeo/slc/lib/linux/rpmfactory/RpmBuildEnvironment.java
runtime/org.argeo.slc.support.simple/src/main/java/org/argeo/slc/log4j/SlcExecutionAppender.java

index 85d0238e8bdc3c4b5c27aab5e428f7db58b5f416..3df94413243366cbcdf79ae1a6ce348dd3904965 100644 (file)
@@ -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 (file)
index 0000000..41f0e5e
--- /dev/null
@@ -0,0 +1,42 @@
+<?xml version="1.0" encoding="UTF-8"?>\r
+<beans xmlns="http://www.springframework.org/schema/beans"\r
+       xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:p="http://www.springframework.org/schema/p"\r
+       xmlns:aop="http://www.springframework.org/schema/aop" xmlns:flow="http://www.argeo.org/schema/slc-flow"\r
+       xsi:schemaLocation="\r
+       http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-2.5.xsd\r
+       http://www.springframework.org/schema/aop http://www.springframework.org/schema/aop/spring-aop-2.5.xsd\r
+       http://www.argeo.org/schema/slc-flow http://www.argeo.org/schema/slc-flow-0.12.xsd">\r
+\r
+       <!-- Basic echo, should work on all OSs -->\r
+       <flow:flow name="os/systemCall">\r
+               <bean p:cmd="echo Hello World!" class="org.argeo.slc.core.execution.tasks.SystemCall" />\r
+       </flow:flow>\r
+\r
+       <!-- Must disable requiretty in sudoers file -->\r
+       <flow:flow name="os/sudo">\r
+               <bean p:cmd="sudo id" class="org.argeo.slc.core.execution.tasks.SystemCall">\r
+                       <property name="environmentVariables">\r
+                               <map>\r
+                                       <entry key="SUDO_ASKPASS" value="/usr/libexec/openssh/gnome-ssh-askpass" />\r
+                               </map>\r
+                       </property>\r
+               </bean>\r
+       </flow:flow>\r
+\r
+       <!-- SSH -->\r
+       <flow:flow name="os/ssh">\r
+               <bean p:cmd="ls /etc" class="org.argeo.slc.core.execution.tasks.SystemCall">\r
+                       <property name="executor" ref="sshExecutor" />\r
+               </bean>\r
+       </flow:flow>\r
+\r
+       <bean name="sshExecutor" class="org.argeo.slc.jsch.JschExecutor">\r
+               <property name="sshTarget">\r
+                       <bean p:host="localhost" p:port="22" p:user="${user.name}"\r
+                               p:localPrivateKey="${user.home}/.ssh/argeo_admin_rsa" class="org.argeo.slc.jsch.SshTarget" />\r
+               </property>\r
+       </bean>\r
+\r
+\r
+\r
+</beans>
\ No newline at end of file
index 9a346e4d44c417f9827eeb05809f4dd805881a66..8663b458eacaf1fe40308c30ede0c610fcc93ec9 100644 (file)
@@ -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 (file)
index 53670d6..0000000
+++ /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
index a05b5c1ee33fb26b32e0288e9fe2951d41d0f4e9..bb176d12dcff634323a33163d2a1203c654d8739 100644 (file)
@@ -2,7 +2,7 @@
 <feature
       id="org.argeo.slc.ide"
       label="Argeo Java IDE"
-      version="0.13.1.D20110413_1126"
+      version="0.13.1.D20110904_1415"
       provider-name="Argeo"
       plugin="org.argeo.slc.ide.branding"
       image="icons/argeo-icon-100104-256.png">
@@ -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"/>
 
    <plugin
          id="org.argeo.slc.ide.branding"
          download-size="0"
          install-size="0"
-         version="0.13.1.D20110413_1126"
+         version="0.13.1.D20110904_1415"
          unpack="false"/>
 
 </feature>
index 3fa3e2efdfdaadff42e1d5e2caeb86028c661711..d619a767ac45922945a73f6c368eebb379e34804 100644 (file)
@@ -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<ExecutionStep> steps) {
-               logPage.addSteps(steps);
+               // logPage.addSteps(steps);
        }
 
        /** Expects one session per editor. */
index 00ad3e48ed43493b791ba1c4109b5842fbe71250..46e50b6f0face84914935ff89b6d252877482bb2 100644 (file)
@@ -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<ExecutionStep> 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<Event> 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<Long, Node> nodes = new TreeMap<Long, Node>();
+
+                       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);
+               }
+       }
 }
index 9928d35d8398aef1f03b06742b1f1916ea16a4ad..b127894ce31b5ae901bce2bd5e92fa7e3e6dcd0b 100644 (file)
@@ -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",
index 5a2b5cbb6ee77dd16c480381ff75ca3448c4339b..7492f78ce90665451fadbb422956669e10bda243 100644 (file)
@@ -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,
index 7d77ce624437cdb1e895ba7524accf6c9bb6aac1..3fffb8063931309b24341c0111ab016564f3413c 100644 (file)
@@ -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);
        }
 
index d0a76ce9d2c1344649673c547c1973c3c40a33e5..5e5ae50507bd63a637a6df77f8c51a7fdadbf811 100644 (file)
@@ -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)
index 2e55f87f3bc452a27c0975aed1d935c1e93e0300..d69ed53946467335ff0790840be7dcc2c356e088 100644 (file)
@@ -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<String> bundleIds = new TreeSet<String>();
                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;
index 1125ab80aef703dc22e5d7957677c63e8ee25305..c91f98b20d97a13855be653913a6bc29d2a0f320 100644 (file)
        <bean id="bundlesManager" class="org.argeo.slc.osgi.BundlesManager" />\r
 \r
        <!-- Logging -->\r
-       <bean id="log4Notification" class="org.argeo.slc.log4j.SlcExecutionAppender">\r
+       <bean id="log4Notification" class="org.argeo.slc.log4j.SlcExecutionAppender"\r
+               init-method="init" destroy-method="destroy">\r
                <property name="disabled" value="${slc.agent.log4Notification.disabled}" />\r
                <property name="level" value="${slc.agent.log4Notification.level}" />\r
                <property name="onlyExecutionThread"\r
                        value="${slc.agent.log4Notification.onlyExecutionThread}" />\r
        </bean>\r
 \r
-       \r
+\r
 </beans>
\ 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 (file)
index 0000000..6e7c038
--- /dev/null
@@ -0,0 +1,22 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<projectDescription>
+       <name>org.argeo.slc.lib.build</name>
+       <comment></comment>
+       <projects>
+       </projects>
+       <buildSpec>
+               <buildCommand>
+                       <name>org.eclipse.pde.ManifestBuilder</name>
+                       <arguments>
+                       </arguments>
+               </buildCommand>
+               <buildCommand>
+                       <name>org.eclipse.pde.SchemaBuilder</name>
+                       <arguments>
+                       </arguments>
+               </buildCommand>
+       </buildSpec>
+       <natures>
+               <nature>org.eclipse.pde.PluginNature</nature>
+       </natures>
+</projectDescription>
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 (file)
index 0000000..65cfd79
--- /dev/null
@@ -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 (file)
index 0000000..5fc538b
--- /dev/null
@@ -0,0 +1,4 @@
+source.. = src/main/java/
+output.. = target/classes/
+bin.includes = META-INF/,\
+               .
index b3d92ae69aad4d9bf6ae605e56569ed512d79197..1a4ec57e43dcdd06a8468becee622b44c78355db 100644 (file)
@@ -104,6 +104,8 @@ public abstract class AbstractExecutionModulesManager implements
 
        public void dispatchAddSteps(ExecutionProcess process,
                        List<ExecutionStep> steps) {
+               process.addSteps(steps);
+
                for (Iterator<SlcExecutionNotifier> it = getSlcExecutionNotifiers()
                                .iterator(); it.hasNext();) {
                        it.next().addSteps(process, steps);
index 82491fc589b163f2aca6c19c4c2839081cfc6446..b0bba7bf95933825a202c79602bc47381171773e 100644 (file)
@@ -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);
 
index 5e288f264f0de75447afbbbfbeecff7fa82c7392..7493de4e7bd5178474304110ede04cc84c86ac6a 100644 (file)
@@ -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;
+       }
+
 }
index c11e875b8083df0d627c51dba32587360bdfed22..1d333845d1e9bb1f7caa4996207b1b5c44533fb4 100644 (file)
@@ -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<ExecutionStep> steps = new ArrayBlockingQueue<ExecutionStep>(
+                       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<ExecutionStep> newSteps = new ArrayList<ExecutionStep>();
+                               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;
+                       }
+               }
+
+       }
 }
index 6f0143f0fcca651847610471a71ab0945e0d1b74..23d165a4c25066283cc87e4090c703afdceefbb6 100644 (file)
@@ -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<ExecutionStep> steps = new ArrayBlockingQueue<ExecutionStep>(
+                       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<ExecutionStep> steps = new ArrayList<ExecutionStep>();
                steps.add(step);
-               dispatchAddSteps(steps);
+               // dispatchAddSteps(steps);
+               this.steps.add(step);
        }
 
        public void dispatchAddSteps(List<ExecutionStep> steps) {
@@ -58,4 +66,8 @@ public class ProcessThreadGroup extends ThreadGroup {
                executionModulesManager.dispatchAddSteps(slcProcess, steps);
        }
 
+       public BlockingQueue<ExecutionStep> getSteps() {
+               return steps;
+       }
+
 }
index 5046abb0a3bd2f47d178488ab777fe5dbd356829..a873b4dca15e6e6d26371ed04760394f163b5386 100644 (file)
@@ -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<Object> 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<SystemCallOutputListener> 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<String, String> environmentVariablesToUse = null;
-               if (environmentVariables.size() > 0) {
-                       environmentVariablesToUse = new HashMap<String, String>();
-                       if (mergeEnvironmentVariables)
-                               environmentVariablesToUse.putAll(System.getenv());
+               environmentVariablesToUse = new HashMap<String, String>();
+               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 {
                }
 
        }
-
 }
index 4b0fefc7f3432124e70d27368823c8ae6f92a9c4..7680750302ec1c2a1192e6cf7a2493e6ae45c5b8 100644 (file)
@@ -16,6 +16,7 @@
 \r
 package org.argeo.slc.execution;\r
 \r
+/** Variables or references attached to an execution (typically thread bounded).*/\r
 public interface ExecutionContext {\r
        public final static String VAR_EXECUTION_CONTEXT_ID = "slcVar.executionContext.id";\r
        public final static String VAR_EXECUTION_CONTEXT_CREATION_DATE = "slcVar.executionContext.creationDate";\r
index be70b0955d01738287db5967e649889e0cc1a7b9..447ef7f982c054fe3da0b3c348f875a2a8525ed7 100644 (file)
@@ -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.
- * <br/>
+ * tracking. A process can be distributed or parallelized. <br/>
  * NEW => INITIALIZED => SCHEDULED => RUNNING<br/>
  * RUNNING => {COMPLETED | ERROR | KILLED}<br/>
  * {COMPLETED | ERROR | KILLED} => PURGED<br/>
@@ -44,4 +45,6 @@ public interface ExecutionProcess {
 
        /** Sets the current status of this process */
        public void setStatus(String status);
+
+       public void addSteps(List<ExecutionStep> steps);
 }
index 4cabeec097d6f5c2406c7d434cca6e238c0893cc..74201c0e2ff4cea0f08a3a16dab76cd3e24df3db 100644 (file)
@@ -34,9 +34,9 @@ public class ExecutionStep implements Serializable {
        public final static String DEBUG = "DEBUG";\r
        public final static String TRACE = "TRACE";\r
 \r
-       /** @deprecated*/\r
+       /** @deprecated */\r
        public final static String START = "START";\r
-       /** @deprecated*/\r
+       /** @deprecated */\r
        public final static String END = "END";\r
 \r
        // TODO make the fields final and private when we don't need POJO support\r
@@ -47,27 +47,28 @@ public class ExecutionStep implements Serializable {
        protected Date timestamp;\r
        protected String log;\r
 \r
+       private String location;\r
+\r
        /** Empty constructor */\r
        public ExecutionStep() {\r
-               thread = Thread.currentThread().getName();\r
-       }\r
-\r
-       /** Creates a step at the current date of type INFO */\r
-       public ExecutionStep(String log) {\r
-               this(new Date(), INFO, log);\r
+               Thread currentThread = Thread.currentThread();\r
+               thread = currentThread.getName();\r
        }\r
 \r
        /** Creates a step at the current date */\r
-       public ExecutionStep(String type, String log) {\r
-               this(new Date(), type, log);\r
+       public ExecutionStep(String location, String type, String log) {\r
+               this(location, new Date(), type, log);\r
        }\r
 \r
        /** Creates a step of the given type. */\r
-       public ExecutionStep(Date timestamp, String type, String log) {\r
-               this(timestamp, type, log, Thread.currentThread().getName());\r
+       public ExecutionStep(String location, Date timestamp, String type,\r
+                       String log) {\r
+               this(location, timestamp, type, log, Thread.currentThread().getName());\r
        }\r
 \r
-       public ExecutionStep(Date timestamp, String type, String log, String thread) {\r
+       public ExecutionStep(String location, Date timestamp, String type,\r
+                       String log, String thread) {\r
+               this.location = location;\r
                this.type = type;\r
                this.timestamp = timestamp;\r
                this.thread = thread;\r
@@ -103,4 +104,9 @@ public class ExecutionStep implements Serializable {
                return "Execution step, thread=" + thread + ", type=" + type;\r
        }\r
 \r
+       /** Typically the logging category */\r
+       public String getLocation() {\r
+               return location;\r
+       }\r
+\r
 }\r
index e5fdd95cd31ed879d49f1557f692252cb917b41c..4fc50fdfb0f5310fea93b9de7a4e70c904c05cc0 100644 (file)
@@ -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;
 
index 9b40434628017698b0426d5981a9ce9674bbca27..13189b453d37ec0f95e469fa0470bd6adffb4f8d 100644 (file)
@@ -24,6 +24,7 @@ import java.util.Map;
 import java.util.TreeMap;\r
 \r
 import org.argeo.slc.execution.ExecutionProcess;\r
+import org.argeo.slc.execution.ExecutionStep;\r
 \r
 /** @deprecated use other implementations of {@link ExecutionProcess} */\r
 public class SlcExecution implements ExecutionProcess, Serializable {\r
@@ -61,6 +62,10 @@ public class SlcExecution implements ExecutionProcess, Serializable {
                this.steps = steps;\r
        }\r
 \r
+       public void addSteps(List<ExecutionStep> steps) {\r
+               // not implemented on deprecated\r
+       }\r
+\r
        public String getUuid() {\r
                return uuid;\r
        }\r
index 2d81d2f5ae0164653b7a8a31a03e1d06dd49b0d8..bc79688ff7033eb703b9f96dc5033aff872b3229 100644 (file)
@@ -57,10 +57,8 @@ public class SlcExecutionStep extends ExecutionStep {
 \r
        public SlcExecutionStep(Date timestamp, String type, String log,\r
                        String thread) {\r
-               super(timestamp, type, log, thread);\r
+               super("UNKOWN_LOCATION", timestamp, type, log, thread);\r
        }\r
-       \r
-       \r
 \r
        public String getUuid() {\r
                return uuid;\r
@@ -90,7 +88,7 @@ public class SlcExecutionStep extends ExecutionStep {
                this.logLines = logLines;\r
        }\r
 \r
-       /** public for legacy reasons*/\r
+       /** public for legacy reasons */\r
        public String addLog(String log) {\r
                if (logLines == null)\r
                        logLines = new ArrayList<String>();\r
index 3330fd433581d60d7a1dee5843ab24811e50258d..25cc780d6cce21a08b61d51902169c0b720e865c 100644 (file)
@@ -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";
index 382f2a855187d1468baa3a70272df99629b987a5..9fc152902f6da3061c67610aff6a921236377653 100644 (file)
@@ -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
         */
index 526b5ebc4e5fb10add998c3b635088423dd59031..b2fa33395b51d8bf8a586acbfb39642eb88d3267 100644 (file)
@@ -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<ExecutionStep> 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;
        }
index 0e2a5494acb603fc586b637ed552c3d5d0fdf998..e51744f80b7ef1a6c91c6415794fdf0b5ebf84c0 100644 (file)
@@ -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
index 2335b53606462a886714fe959b58c86cb32462c9..36e8403e6d53bcf96f15ff0ee81d7e0baf4a9b05 100644 (file)
                        <artifactId>com.springsource.org.tmatesoft.svn</artifactId>
                </dependency>
 
-               <!-- Commons VFS -->
+               <!-- Commons -->
                <dependency>
                        <groupId>org.apache.commons</groupId>
                        <artifactId>com.springsource.org.apache.commons.vfs</artifactId>
                </dependency>
+               <dependency>
+                       <groupId>org.argeo.dep.osgi</groupId>
+                       <artifactId>org.argeo.dep.osgi.commons.exec</artifactId>
+               </dependency>
 
                <dependency>
                        <groupId>org.argeo.dep.osgi</groupId>
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 (file)
index 0000000..dbf6272
--- /dev/null
@@ -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;
+       }
+
+}
index 814e080481219641027d74f96df82648cf8f0eab..b9eae87ac19b215fd444de23525233bce294d640 100644 (file)
@@ -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 (file)
index 0000000..c4b35a9
--- /dev/null
@@ -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<File> reposToRecreate = new HashSet<File>();
+               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<File> dirs = new ArrayList<File>();
+                               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;
+       }
+
+}
index 1588bfa8fa93c2bf3e54d7557523ed284df96126..04680df7b438e77bb0cc603d48d9d86b36f986fb 100644 (file)
@@ -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;
+       }
+
 }
index 123e055a36b3d68f04c4c84a48ca112a1bdc8da2..5c2ba1ed2e67f04f88bff83350112a64525de6bc 100644 (file)
@@ -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<String, String> rpmmacros = new HashMap<String, String>();
 
+       private List<String> archs = new ArrayList<String>();
+
+       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<String> archs) {
+               this.archs = archs;
+       }
+
+       public List<String> getArchs() {
+               return archs;
+       }
+
+       public String getStagingBase() {
+               return stagingBase;
+       }
+
+       public void setStagingBase(String stagingBase) {
+               this.stagingBase = stagingBase;
+       }
 }
index 880aefef1f51b27e3a4a7100e6407629495bc018..f8930fff8f9ae344d9c1f4014c9e18611c8eab33 100644 (file)
@@ -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;
        }