From 1d6a2ecc676aac7dde0491ea5047bebc2ce69e80 Mon Sep 17 00:00:00 2001 From: Bruno Sinou Date: Tue, 11 Mar 2014 20:05:52 +0000 Subject: [PATCH] Work on the modular distribution - generate binaries, work on layout. git-svn-id: https://svn.argeo.org/slc/trunk@6892 4cfe0d0a-d680-48aa-b62c-e0a02a3f76cc --- .../icons/clear.gif | Bin 0 -> 316 bytes .../org.argeo.slc.client.ui.dist/plugin.xml | 6 + .../argeo/slc/client/ui/dist/DistImages.java | 13 +- .../commands/OpenGenerateBinariesWizard.java | 73 +++ .../ui/dist/editors/BundleDetailsPage.java | 2 +- .../editors/ModularDistVersionEditor.java | 2 +- ...va => ModularDistVersionOverviewPage.java} | 396 +++++++++---- .../editors/WkspCategoryBaseListPage.java | 2 +- .../ui/dist/model/ModularDistBaseElem.java | 15 +- .../ui/dist/views/DistributionsView.java | 22 +- .../dist/wizards/GenerateBinariesWizard.java | 320 +++++++++++ .../java/org/argeo/slc/repo/RepoSync.java | 4 +- .../slc/repo/maven/GenerateBinaries.java | 518 ++++++++++++++++++ .../argeo/slc/repo/osgi/NormalizeGroup.java | 12 +- .../main/java/org/argeo/slc/jcr/SlcNames.java | 1 + 15 files changed, 1246 insertions(+), 140 deletions(-) create mode 100644 plugins/org.argeo.slc.client.ui.dist/icons/clear.gif create mode 100644 plugins/org.argeo.slc.client.ui.dist/src/main/java/org/argeo/slc/client/ui/dist/commands/OpenGenerateBinariesWizard.java rename plugins/org.argeo.slc.client.ui.dist/src/main/java/org/argeo/slc/client/ui/dist/editors/{ModuleListPage.java => ModularDistVersionOverviewPage.java} (59%) create mode 100644 plugins/org.argeo.slc.client.ui.dist/src/main/java/org/argeo/slc/client/ui/dist/wizards/GenerateBinariesWizard.java create mode 100644 runtime/org.argeo.slc.repo/src/main/java/org/argeo/slc/repo/maven/GenerateBinaries.java diff --git a/plugins/org.argeo.slc.client.ui.dist/icons/clear.gif b/plugins/org.argeo.slc.client.ui.dist/icons/clear.gif new file mode 100644 index 0000000000000000000000000000000000000000..cbb71bedceca9e73d10c9baa00a1f61da313ecc3 GIT binary patch literal 316 zcmZ?wbhEHb6krfwxT?gEkdRPaUG3-V7abLymX=mnSXfqG9uycD7!*4B3Q z%Ig;|zIuCmfBpJ<{kog~|Nm#84N&~a!pOj&#GnH*9^@wmwn&GG1s*z5u5*@r(%925 zFMy|*u{Ef#@s;s`oCcc&|KkNc7Ka`&O>PuR@0)c_%`h;6!^c7W2!AevyHItlG_#Lr gbB(lsJ9}pxhYx?hG?S0~jG6LEvu66tcVw^z0J% + + + it = ((IStructuredSelection) selector).iterator(); + Object element = it.next(); + if (element instanceof ModularDistBaseElem) { + ModularDistBaseElem elem = (ModularDistBaseElem) element; + + GenerateBinariesWizard wizard = new GenerateBinariesWizard( + elem.getCategoryBase()); + WizardDialog dialog = new WizardDialog( + HandlerUtil.getActiveShell(event), wizard); + int result = dialog.open(); + if (result == Dialog.OK) + CommandHelpers.callCommand(RefreshDistributionsView.ID); + } + + } + } + return null; + } +} \ No newline at end of file diff --git a/plugins/org.argeo.slc.client.ui.dist/src/main/java/org/argeo/slc/client/ui/dist/editors/BundleDetailsPage.java b/plugins/org.argeo.slc.client.ui.dist/src/main/java/org/argeo/slc/client/ui/dist/editors/BundleDetailsPage.java index d2d0773de..e34c2dbf5 100644 --- a/plugins/org.argeo.slc.client.ui.dist/src/main/java/org/argeo/slc/client/ui/dist/editors/BundleDetailsPage.java +++ b/plugins/org.argeo.slc.client.ui.dist/src/main/java/org/argeo/slc/client/ui/dist/editors/BundleDetailsPage.java @@ -90,7 +90,7 @@ public class BundleDetailsPage extends FormPage implements SlcNames, SlcTypes { form.setText(currBundle.hasProperty(DistConstants.SLC_BUNDLE_NAME) ? currBundle .getProperty(DistConstants.SLC_BUNDLE_NAME).getString() : ""); - form.setMessage(" test", IMessageProvider.NONE); + form.setMessage(" ", IMessageProvider.NONE); Composite body = form.getBody(); GridLayout layout = new GridLayout(1, false); layout.marginWidth = 5; diff --git a/plugins/org.argeo.slc.client.ui.dist/src/main/java/org/argeo/slc/client/ui/dist/editors/ModularDistVersionEditor.java b/plugins/org.argeo.slc.client.ui.dist/src/main/java/org/argeo/slc/client/ui/dist/editors/ModularDistVersionEditor.java index 75263b53a..f80c5e928 100644 --- a/plugins/org.argeo.slc.client.ui.dist/src/main/java/org/argeo/slc/client/ui/dist/editors/ModularDistVersionEditor.java +++ b/plugins/org.argeo.slc.client.ui.dist/src/main/java/org/argeo/slc/client/ui/dist/editors/ModularDistVersionEditor.java @@ -40,7 +40,7 @@ public class ModularDistVersionEditor extends ArtifactVersionEditor { @Override protected void addPages() { try { - addPage(new ModuleListPage(this, "Modules ", getArtifact())); + addPage(new ModularDistVersionOverviewPage(this, "Modules ", getArtifact())); addPage(new RunInOsgiPage(this, "Run as OSGi ", getArtifact())); super.addPages(); } catch (PartInitException e) { diff --git a/plugins/org.argeo.slc.client.ui.dist/src/main/java/org/argeo/slc/client/ui/dist/editors/ModuleListPage.java b/plugins/org.argeo.slc.client.ui.dist/src/main/java/org/argeo/slc/client/ui/dist/editors/ModularDistVersionOverviewPage.java similarity index 59% rename from plugins/org.argeo.slc.client.ui.dist/src/main/java/org/argeo/slc/client/ui/dist/editors/ModuleListPage.java rename to plugins/org.argeo.slc.client.ui.dist/src/main/java/org/argeo/slc/client/ui/dist/editors/ModularDistVersionOverviewPage.java index 68c5af7d9..66df95cc6 100644 --- a/plugins/org.argeo.slc.client.ui.dist/src/main/java/org/argeo/slc/client/ui/dist/editors/ModuleListPage.java +++ b/plugins/org.argeo.slc.client.ui.dist/src/main/java/org/argeo/slc/client/ui/dist/editors/ModularDistVersionOverviewPage.java @@ -15,6 +15,7 @@ */ package org.argeo.slc.client.ui.dist.editors; +import java.net.URL; import java.util.ArrayList; import java.util.List; @@ -33,18 +34,24 @@ import javax.jcr.query.qom.Selector; import javax.jcr.query.qom.StaticOperand; import org.argeo.ArgeoException; +import org.argeo.eclipse.ui.EclipseUiUtils; import org.argeo.eclipse.ui.utils.CommandUtils; import org.argeo.jcr.JcrUtils; import org.argeo.slc.SlcException; +import org.argeo.slc.client.ui.dist.DistConstants; import org.argeo.slc.client.ui.dist.DistImages; import org.argeo.slc.client.ui.dist.DistPlugin; import org.argeo.slc.client.ui.dist.commands.DeleteArtifacts; +import org.argeo.slc.client.ui.dist.utils.AbstractHyperlinkListener; import org.argeo.slc.client.ui.dist.utils.NodeViewerComparator; import org.argeo.slc.jcr.SlcNames; import org.argeo.slc.jcr.SlcTypes; +import org.argeo.slc.repo.RepoConstants; +import org.argeo.slc.repo.RepoUtils; import org.eclipse.jface.action.IMenuListener; import org.eclipse.jface.action.IMenuManager; import org.eclipse.jface.action.MenuManager; +import org.eclipse.jface.dialogs.IMessageProvider; import org.eclipse.jface.viewers.ColumnLabelProvider; import org.eclipse.jface.viewers.DoubleClickEvent; import org.eclipse.jface.viewers.IDoubleClickListener; @@ -54,35 +61,40 @@ import org.eclipse.jface.viewers.TableViewer; import org.eclipse.jface.viewers.TableViewerColumn; import org.eclipse.jface.viewers.Viewer; import org.eclipse.swt.SWT; -import org.eclipse.swt.events.ControlEvent; -import org.eclipse.swt.events.ControlListener; import org.eclipse.swt.events.ModifyEvent; import org.eclipse.swt.events.ModifyListener; import org.eclipse.swt.events.SelectionAdapter; import org.eclipse.swt.events.SelectionEvent; -import org.eclipse.swt.events.SelectionListener; +import org.eclipse.swt.layout.FillLayout; import org.eclipse.swt.layout.GridData; import org.eclipse.swt.layout.GridLayout; import org.eclipse.swt.widgets.Button; import org.eclipse.swt.widgets.Composite; +import org.eclipse.swt.widgets.Label; import org.eclipse.swt.widgets.Menu; import org.eclipse.swt.widgets.Table; import org.eclipse.swt.widgets.Text; import org.eclipse.ui.IWorkbenchWindow; import org.eclipse.ui.PartInitException; +import org.eclipse.ui.PlatformUI; +import org.eclipse.ui.browser.IWebBrowser; +import org.eclipse.ui.browser.IWorkbenchBrowserSupport; import org.eclipse.ui.forms.IManagedForm; import org.eclipse.ui.forms.editor.FormEditor; import org.eclipse.ui.forms.editor.FormPage; +import org.eclipse.ui.forms.events.HyperlinkEvent; import org.eclipse.ui.forms.widgets.FormToolkit; +import org.eclipse.ui.forms.widgets.Hyperlink; import org.eclipse.ui.forms.widgets.ScrolledForm; /** * Show all modules contained in a given modular distribution as filter-able * table */ -public class ModuleListPage extends FormPage implements SlcNames { +public class ModularDistVersionOverviewPage extends FormPage implements + SlcNames { - final static String PAGE_ID = "ModuleListPage"; + final static String PAGE_ID = "ModularDistVersionOverviewPage"; // Business Objects private Node modularDistribution; @@ -92,11 +104,10 @@ public class ModuleListPage extends FormPage implements SlcNames { private NodeViewerComparator comparator; private TableViewer viewer; private FormToolkit tk; - private Composite header; private Text filterTxt; private final static String FILTER_HELP_MSG = "Enter filter criterion separated by a space"; - public ModuleListPage(FormEditor formEditor, String title, + public ModularDistVersionOverviewPage(FormEditor formEditor, String title, Node modularDistribution) { super(formEditor, PAGE_ID, title); this.modularDistribution = modularDistribution; @@ -104,138 +115,222 @@ public class ModuleListPage extends FormPage implements SlcNames { @Override protected void createFormContent(IManagedForm managedForm) { + // General settings for this page ScrolledForm form = managedForm.getForm(); tk = managedForm.getToolkit(); + Composite body = form.getBody(); - // Main Layout GridLayout layout = new GridLayout(1, false); - Composite body = form.getBody(); + layout.marginWidth = 5; + layout.marginRight = 15; + layout.verticalSpacing = 0; body.setLayout(layout); - // Add the filter section - createFilterPart(body); - // Add the table - createTableViewer(body); + try { + form.setText(modularDistribution + .hasProperty(DistConstants.SLC_BUNDLE_NAME) ? modularDistribution + .getProperty(DistConstants.SLC_BUNDLE_NAME).getString() + : ""); + form.setMessage( + modularDistribution + .hasProperty(SlcNames.SLC_BUNDLE_DESCRIPTION) ? modularDistribution + .getProperty(SlcNames.SLC_BUNDLE_DESCRIPTION) + .getString() : "", IMessageProvider.NONE); + } catch (RepositoryException re) { + throw new SlcException("Unable to get bundle name for node " + + modularDistribution, re); + } - // Add a listener to enable custom resize process - form.addControlListener(new ControlListener() { - // form.addListener(SWT.RESIZE, new Listener() does not work - public void controlResized(ControlEvent e) { - refreshLayout(); - } + // Main layout + Composite header = tk.createComposite(body); + header.setLayoutData(new GridData(SWT.FILL, SWT.TOP, true, false)); + populateHeaderPart(header); - public void controlMoved(ControlEvent e) { - } - }); - refresh(); + Composite moduleTablePart = tk.createComposite(body); + moduleTablePart.setLayoutData(new GridData(SWT.FILL, SWT.FILL, true, + true)); + populateModuleTablePart(moduleTablePart); } - private void refresh() { - final List result = JcrUtils - .nodeIteratorToList(listBundleArtifacts()); - viewer.setInput(result); + private void populateHeaderPart(Composite parent) { + GridLayout layout = new GridLayout(6, false); + // layout.marginWidth = layout.horizontalSpacing = layout.marginHeight = + // 0; + layout.horizontalSpacing = 10; + parent.setLayout(layout); + try { + // 1st Line: Category, name version + createLT( + parent, + "Category", + modularDistribution.hasProperty(SlcNames.SLC_GROUP_ID) ? modularDistribution + .getProperty(SlcNames.SLC_GROUP_ID).getString() + : ""); + createLT( + parent, + "Name", + modularDistribution.hasProperty(SlcNames.SLC_SYMBOLIC_NAME) ? modularDistribution + .getProperty(SlcNames.SLC_SYMBOLIC_NAME) + .getString() : ""); + createLT( + parent, + "Version", + modularDistribution + .hasProperty(SlcNames.SLC_BUNDLE_VERSION) ? modularDistribution + .getProperty(SlcNames.SLC_BUNDLE_VERSION) + .getString() : ""); + + // 2nd Line: Vendor, licence, sources + createLT( + parent, + "Vendor", + modularDistribution + .hasProperty(DistConstants.SLC_BUNDLE_VENDOR) ? modularDistribution + .getProperty(DistConstants.SLC_BUNDLE_VENDOR) + .getString() : ""); + + createHyperlink(parent, "Licence", DistConstants.SLC_BUNDLE_LICENCE); + addSourceSourcesLink(parent); + } catch (RepositoryException re) { + throw new SlcException("Unable to get bundle name for node " + + modularDistribution, re); + } + } - /** Build repository request */ - private NodeIterator listBundleArtifacts() { - try { - Session session = modularDistribution.getSession(); - QueryManager queryManager = session.getWorkspace() - .getQueryManager(); - QueryObjectModelFactory factory = queryManager.getQOMFactory(); + private Text createLT(Composite parent, String labelValue, String textValue) { + Label label = tk.createLabel(parent, labelValue, SWT.RIGHT); + // label.setFont(EclipseUiUtils.getBoldFont(parent)); + label.setLayoutData(new GridData(SWT.RIGHT, SWT.CENTER, false, false)); - Selector source = factory.selector(SlcTypes.SLC_MODULE_COORDINATES, - SlcTypes.SLC_MODULE_COORDINATES); + // Add a trailing space to workaround a display glitch in RAP 1.3 + Text text = tk.createText(parent, textValue + " ", SWT.LEFT); + text.setLayoutData(new GridData(SWT.FILL, SWT.CENTER, true, false)); - // Create a dynamic operand for each property on which we want to - // filter - DynamicOperand catDO = factory.propertyValue( - source.getSelectorName(), SlcNames.SLC_CATEGORY); - DynamicOperand nameDO = factory.propertyValue( - source.getSelectorName(), SlcNames.SLC_NAME); - DynamicOperand versionDO = factory.propertyValue( - source.getSelectorName(), SlcNames.SLC_VERSION); + text.setEditable(false); + return text; + } - String path = modularDistribution.getPath() + "/" - + SlcNames.SLC_MODULES; + private void createHyperlink(Composite parent, String label, + String jcrPropName) throws RepositoryException { + tk.createLabel(parent, label, SWT.NONE); + if (modularDistribution.hasProperty(jcrPropName)) { + final Hyperlink link = tk.createHyperlink(parent, + modularDistribution.getProperty(jcrPropName).getString(), + SWT.NONE); + link.addHyperlinkListener(new AbstractHyperlinkListener() { + @Override + public void linkActivated(HyperlinkEvent e) { + try { + IWorkbenchBrowserSupport browserSupport = PlatformUI + .getWorkbench().getBrowserSupport(); + IWebBrowser browser = browserSupport + .createBrowser( + IWorkbenchBrowserSupport.LOCATION_BAR + | IWorkbenchBrowserSupport.NAVIGATION_BAR, + "SLC Distribution browser", + "SLC Distribution browser", + "A tool tip"); + browser.openURL(new URL(link.getText())); + } catch (Exception ex) { + throw new SlcException("error opening browser", ex); //$NON-NLS-1$ + } + } + }); + } else + tk.createLabel(parent, "", SWT.NONE); + } - // Default Constraint: correct children - Constraint defaultC = factory.descendantNode( - source.getSelectorName(), path); + // helper to check if sources are available + private void addSourceSourcesLink(Composite parent) { + try { + String srcPath = RepoUtils.relatedPdeSourcePath( + RepoConstants.DEFAULT_ARTIFACTS_BASE_PATH, + modularDistribution); + if (!modularDistribution.getSession().nodeExists(srcPath)) { + createLT(parent, "Sources", "N/A"); + } else { + Node sourcesNode = modularDistribution.getSession().getNode( + srcPath); + + Label label = tk.createLabel(parent, "Sources", SWT.RIGHT); + label.setLayoutData(new GridData(SWT.RIGHT, SWT.CENTER, false, + false)); + + final Hyperlink link = tk.createHyperlink(parent, sourcesNode + .getProperty(SlcNames.SLC_SYMBOLIC_NAME).getString(), + SWT.NONE); + link.addHyperlinkListener(new AbstractHyperlinkListener() { + @Override + public void linkActivated(HyperlinkEvent e) { + try { + System.out.println("CLICK on Sources link"); + } catch (Exception ex) { + throw new SlcException("error opening browser", ex); //$NON-NLS-1$ + } + } + }); - String filter = filterTxt.getText(); + } + } catch (RepositoryException e) { + throw new SlcException("Unable to configure sources link for " + + modularDistribution, e); + } + } - // Build constraints based the textArea content - if (filter != null && !"".equals(filter.trim())) { - // Parse the String - String[] strs = filter.trim().split(" "); - for (String token : strs) { - token = token.replace('*', '%'); - StaticOperand so = factory.literal(session - .getValueFactory().createValue("%" + token + "%")); + private void populateModuleTablePart(Composite parent) { + GridLayout layout = new GridLayout(1, false); + layout.marginWidth = layout.horizontalSpacing = 0; + layout.verticalSpacing = 5; + layout.marginTop = 15; + parent.setLayout(layout); + // A sub title + Label label = tk.createLabel(parent, + "Modules included in the current distribution", SWT.NONE); + label.setFont(EclipseUiUtils.getBoldFont(parent)); - Constraint currC = factory.comparison(catDO, - QueryObjectModelFactory.JCR_OPERATOR_LIKE, so); - currC = factory.or(currC, factory.comparison(versionDO, - QueryObjectModelFactory.JCR_OPERATOR_LIKE, so)); - currC = factory.or(currC, factory.comparison(nameDO, - QueryObjectModelFactory.JCR_OPERATOR_LIKE, so)); + // Add the filter section + Composite filterPart = tk.createComposite(parent); + filterPart.setLayoutData(new GridData(SWT.FILL, SWT.TOP, true, false)); + createFilterPart(filterPart); - defaultC = factory.and(defaultC, currC); - } - } + // Add the table + Composite tablePart = tk.createComposite(parent); + tablePart.setLayoutData(new GridData(SWT.FILL, SWT.FILL, true, true)); + createTableViewer(tablePart); + // populate it on first pass. + refresh(); - QueryObjectModel query = factory.createQuery(source, defaultC, - null, null); - QueryResult result = query.execute(); - return result.getNodes(); - } catch (RepositoryException re) { - throw new SlcException("Unable to refresh module list for node " - + modularDistribution, re); - } } private void createFilterPart(Composite parent) { - header = tk.createComposite(parent); GridLayout layout = new GridLayout(2, false); layout.marginWidth = layout.marginHeight = layout.verticalSpacing = 0; layout.horizontalSpacing = 5; - header.setLayout(layout); - GridData gd = new GridData(SWT.FILL, SWT.FILL, false, false); - header.setLayoutData(gd); + parent.setLayout(layout); // Text Area to filter - filterTxt = tk.createText(header, "", SWT.BORDER | SWT.SINGLE + filterTxt = tk.createText(parent, "", SWT.BORDER | SWT.SINGLE | SWT.SEARCH | SWT.CANCEL); filterTxt.setMessage(FILTER_HELP_MSG); - gd = new GridData(SWT.FILL, SWT.FILL, false, false); - gd.grabExcessHorizontalSpace = true; - filterTxt.setLayoutData(gd); + filterTxt.setLayoutData(new GridData(SWT.FILL, SWT.FILL, true, false)); filterTxt.addModifyListener(new ModifyListener() { public void modifyText(ModifyEvent event) { refresh(); } }); - Button resetBtn = tk.createButton(header, null, SWT.PUSH); - resetBtn.setImage(DistImages.IMG_REPO_READONLY); - resetBtn.addSelectionListener(new SelectionListener() { - + Button resetBtn = tk.createButton(parent, null, SWT.PUSH); + resetBtn.setImage(DistImages.IMG_CLEAR); + resetBtn.addSelectionListener(new SelectionAdapter() { public void widgetSelected(SelectionEvent e) { - resetFilter(); - } - - public void widgetDefaultSelected(SelectionEvent e) { + filterTxt.setText(""); + filterTxt.setMessage(FILTER_HELP_MSG); } }); - - } - - private void resetFilter() { - filterTxt.setText(""); - filterTxt.setMessage(FILTER_HELP_MSG); } private void createTableViewer(Composite parent) { + parent.setLayout(new FillLayout()); // helpers to enable sorting by column List propertiesList = new ArrayList(); List propertyTypesList = new ArrayList(); @@ -313,6 +408,71 @@ public class ModuleListPage extends FormPage implements SlcNames { viewer.addDoubleClickListener(new DoubleClickListener()); } + private void refresh() { + final List result = JcrUtils + .nodeIteratorToList(listBundleArtifacts()); + viewer.setInput(result); + } + + /** Build repository request */ + private NodeIterator listBundleArtifacts() { + try { + Session session = modularDistribution.getSession(); + QueryManager queryManager = session.getWorkspace() + .getQueryManager(); + QueryObjectModelFactory factory = queryManager.getQOMFactory(); + + Selector source = factory.selector(SlcTypes.SLC_MODULE_COORDINATES, + SlcTypes.SLC_MODULE_COORDINATES); + + // Create a dynamic operand for each property on which we want to + // filter + DynamicOperand catDO = factory.propertyValue( + source.getSelectorName(), SlcNames.SLC_CATEGORY); + DynamicOperand nameDO = factory.propertyValue( + source.getSelectorName(), SlcNames.SLC_NAME); + DynamicOperand versionDO = factory.propertyValue( + source.getSelectorName(), SlcNames.SLC_VERSION); + + String path = modularDistribution.getPath() + "/" + + SlcNames.SLC_MODULES; + + // Default Constraint: correct children + Constraint defaultC = factory.descendantNode( + source.getSelectorName(), path); + + String filter = filterTxt.getText(); + + // Build constraints based the textArea content + if (filter != null && !"".equals(filter.trim())) { + // Parse the String + String[] strs = filter.trim().split(" "); + for (String token : strs) { + token = token.replace('*', '%'); + StaticOperand so = factory.literal(session + .getValueFactory().createValue("%" + token + "%")); + + Constraint currC = factory.comparison(catDO, + QueryObjectModelFactory.JCR_OPERATOR_LIKE, so); + currC = factory.or(currC, factory.comparison(versionDO, + QueryObjectModelFactory.JCR_OPERATOR_LIKE, so)); + currC = factory.or(currC, factory.comparison(nameDO, + QueryObjectModelFactory.JCR_OPERATOR_LIKE, so)); + + defaultC = factory.and(defaultC, currC); + } + } + + QueryObjectModel query = factory.createQuery(source, defaultC, + null, null); + QueryResult result = query.execute(); + return result.getNodes(); + } catch (RepositoryException re) { + throw new SlcException("Unable to refresh module list for node " + + modularDistribution, re); + } + } + @Override public void setFocus() { viewer.getTable().setFocus(); @@ -397,32 +557,32 @@ public class ModuleListPage extends FormPage implements SlcNames { } } - /** - * UI Trick to put scroll bar on the table rather than on the scrollform - */ - private void refreshLayout() { - // Compute desired table size - int maxH = getManagedForm().getForm().getSize().y; - int maxW = getManagedForm().getForm().getParent().getSize().x; - maxH = maxH - header.getSize().y; - final Table table = viewer.getTable(); - GridData gd = new GridData(SWT.LEFT, SWT.TOP, true, true); - - // when table height is less than 200 px, we let the scroll bar on the - // scrollForm - // FIXME substract some spare space. There is room here for optimization - gd.heightHint = Math.max(maxH - 35, 200); - gd.widthHint = Math.max(maxW - 35, 200); - - table.setLayoutData(gd); - getManagedForm().reflow(true); - } + // /** + // * UI Trick to put scroll bar on the table rather than on the scrollform + // */ + // private void refreshLayout() { + // // Compute desired table size + // int maxH = getManagedForm().getForm().getSize().y; + // int maxW = getManagedForm().getForm().getParent().getSize().x; + // maxH = maxH - header.getSize().y; + // final Table table = viewer.getTable(); + // GridData gd = new GridData(SWT.LEFT, SWT.TOP, true, true); + // + // // when table height is less than 200 px, we let the scroll bar on the + // // scrollForm + // // FIXME substract some spare space. There is room here for optimization + // gd.heightHint = Math.max(maxH - 35, 200); + // gd.widthHint = Math.max(maxW - 35, 200); + // + // table.setLayoutData(gd); + // getManagedForm().reflow(true); + // } @Override public void setActive(boolean active) { super.setActive(active); if (active) { - refreshLayout(); + // refreshLayout(); } } } \ No newline at end of file diff --git a/plugins/org.argeo.slc.client.ui.dist/src/main/java/org/argeo/slc/client/ui/dist/editors/WkspCategoryBaseListPage.java b/plugins/org.argeo.slc.client.ui.dist/src/main/java/org/argeo/slc/client/ui/dist/editors/WkspCategoryBaseListPage.java index 7f67a73a3..6479eb534 100644 --- a/plugins/org.argeo.slc.client.ui.dist/src/main/java/org/argeo/slc/client/ui/dist/editors/WkspCategoryBaseListPage.java +++ b/plugins/org.argeo.slc.client.ui.dist/src/main/java/org/argeo/slc/client/ui/dist/editors/WkspCategoryBaseListPage.java @@ -114,7 +114,7 @@ public class WkspCategoryBaseListPage extends FormPage implements SlcNames { ScrolledForm form = managedForm.getForm(); tk = managedForm.getToolkit(); - form.setText("Define Relevant Category"); + form.setText("Define Relevant Categories"); form.setMessage("Choose in the below list " + "the categories that can be used as base for " + "modular distributions maintained via the current workspace", diff --git a/plugins/org.argeo.slc.client.ui.dist/src/main/java/org/argeo/slc/client/ui/dist/model/ModularDistBaseElem.java b/plugins/org.argeo.slc.client.ui.dist/src/main/java/org/argeo/slc/client/ui/dist/model/ModularDistBaseElem.java index 35e3f21dd..fab28ff37 100644 --- a/plugins/org.argeo.slc.client.ui.dist/src/main/java/org/argeo/slc/client/ui/dist/model/ModularDistBaseElem.java +++ b/plugins/org.argeo.slc.client.ui.dist/src/main/java/org/argeo/slc/client/ui/dist/model/ModularDistBaseElem.java @@ -35,6 +35,19 @@ public class ModularDistBaseElem extends DistParentElem { this.type = type; } + public Node getCategoryBase() { + // TODO clean this + if (type.equals(AETHER_CATEGORY_BASE)) + return artifactBase; + else + try { + return artifactBase.getParent(); + } catch (RepositoryException e) { + throw new SlcException("unable tyo get parent node for " + + artifactBase, e); + } + } + /** * Override normal behavior to initialize children only when first requested */ @@ -73,7 +86,7 @@ public class ModularDistBaseElem extends DistParentElem { } } - public NodeIterator getDistVersions() { + private NodeIterator getDistVersions() { try { if (AETHER_CATEGORY_BASE.equals(type)) return null; diff --git a/plugins/org.argeo.slc.client.ui.dist/src/main/java/org/argeo/slc/client/ui/dist/views/DistributionsView.java b/plugins/org.argeo.slc.client.ui.dist/src/main/java/org/argeo/slc/client/ui/dist/views/DistributionsView.java index c365a833c..283886317 100644 --- a/plugins/org.argeo.slc.client.ui.dist/src/main/java/org/argeo/slc/client/ui/dist/views/DistributionsView.java +++ b/plugins/org.argeo.slc.client.ui.dist/src/main/java/org/argeo/slc/client/ui/dist/views/DistributionsView.java @@ -34,6 +34,7 @@ import org.argeo.slc.client.ui.dist.commands.Fetch; import org.argeo.slc.client.ui.dist.commands.MergeWorkspaces; import org.argeo.slc.client.ui.dist.commands.NormalizeDistribution; import org.argeo.slc.client.ui.dist.commands.NormalizeWorkspace; +import org.argeo.slc.client.ui.dist.commands.OpenGenerateBinariesWizard; import org.argeo.slc.client.ui.dist.commands.PublishWorkspace; import org.argeo.slc.client.ui.dist.commands.RefreshDistributionsView; import org.argeo.slc.client.ui.dist.commands.RegisterRepository; @@ -45,6 +46,7 @@ import org.argeo.slc.client.ui.dist.controllers.DistTreeContentProvider; import org.argeo.slc.client.ui.dist.controllers.DistTreeDoubleClickListener; import org.argeo.slc.client.ui.dist.controllers.DistTreeLabelProvider; import org.argeo.slc.client.ui.dist.model.DistParentElem; +import org.argeo.slc.client.ui.dist.model.ModularDistBaseElem; import org.argeo.slc.client.ui.dist.model.RepoElem; import org.argeo.slc.client.ui.dist.model.WkspGroupElem; import org.argeo.slc.client.ui.dist.model.WorkspaceElem; @@ -157,7 +159,7 @@ public class DistributionsView extends ViewPart implements SlcNames, ArgeoNames String targetRepoPath = null, workspaceName = null, workspacePrefix = null; // String targetRepoUri = null; // Build conditions depending on element type - boolean isDistribElem = false, isRepoElem = false, isDistribGroupElem = false; + boolean isDistribElem = false, isModularDistBaseElem = false, isRepoElem = false, isDistribGroupElem = false; boolean isLocal = false, isReadOnly = true; RepoElem re = null; @@ -174,6 +176,12 @@ public class DistributionsView extends ViewPart implements SlcNames, ArgeoNames isRepoElem = true; isLocal = re.inHome(); isReadOnly = re.isReadOnly(); + } else if (firstElement instanceof ModularDistBaseElem) { + ModularDistBaseElem mdbe = (ModularDistBaseElem) firstElement; + re = (RepoElem) mdbe.getParent().getParent().getParent(); + isModularDistBaseElem = true; + isLocal = re.inHome(); + isReadOnly = re.isReadOnly(); } else if (firstElement instanceof WkspGroupElem) { WkspGroupElem wge = (WkspGroupElem) firstElement; isReadOnly = wge.isReadOnly(); @@ -229,8 +237,8 @@ public class DistributionsView extends ViewPart implements SlcNames, ArgeoNames params.put(Fetch.PARAM_TARGET_REPO_PATH, targetRepoPath); CommandUtils.refreshParametrizedCommand(menuManager, window, Fetch.ID, Fetch.DEFAULT_LABEL, Fetch.DEFAULT_ICON, - isRepoElem && isLocal && singleElement - && !isReadOnly, params); + isRepoElem && isLocal && singleElement && !isReadOnly, + params); // Normalize workspace params = new HashMap(); @@ -300,7 +308,13 @@ public class DistributionsView extends ViewPart implements SlcNames, ArgeoNames CommandUtils.refreshParametrizedCommand(submenu, window, RunInOsgi.ID, RunInOsgi.DEFAULT_LABEL, RunInOsgi.DEFAULT_ICON, isDistribElem && singleElement - && isLocal, params); + && isLocal, params);// Run in OSGi + + CommandUtils.refreshCommand(submenu, window, + OpenGenerateBinariesWizard.ID, + OpenGenerateBinariesWizard.DEFAULT_LABEL, + OpenGenerateBinariesWizard.DEFAULT_ICON, + isModularDistBaseElem && !isReadOnly); if (submenu.getSize() > 0) menuManager.add(submenu); diff --git a/plugins/org.argeo.slc.client.ui.dist/src/main/java/org/argeo/slc/client/ui/dist/wizards/GenerateBinariesWizard.java b/plugins/org.argeo.slc.client.ui.dist/src/main/java/org/argeo/slc/client/ui/dist/wizards/GenerateBinariesWizard.java new file mode 100644 index 000000000..e0474a090 --- /dev/null +++ b/plugins/org.argeo.slc.client.ui.dist/src/main/java/org/argeo/slc/client/ui/dist/wizards/GenerateBinariesWizard.java @@ -0,0 +1,320 @@ +/* + * Copyright (C) 2007-2012 Argeo GmbH + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.argeo.slc.client.ui.dist.wizards; + +import java.util.ArrayList; +import java.util.List; + +import javax.jcr.Node; +import javax.jcr.NodeIterator; +import javax.jcr.RepositoryException; + +import org.apache.commons.logging.Log; +import org.apache.commons.logging.LogFactory; +import org.argeo.ArgeoMonitor; +import org.argeo.eclipse.ui.EclipseArgeoMonitor; +import org.argeo.slc.SlcException; +import org.argeo.slc.client.ui.dist.DistPlugin; +import org.argeo.slc.client.ui.dist.PrivilegedJob; +import org.argeo.slc.client.ui.dist.utils.ViewerUtils; +import org.argeo.slc.jcr.SlcTypes; +import org.argeo.slc.repo.RepoConstants; +import org.argeo.slc.repo.RepoUtils; +import org.argeo.slc.repo.maven.GenerateBinaries; +import org.argeo.slc.repo.maven.IndexDistribution; +import org.eclipse.core.runtime.IProgressMonitor; +import org.eclipse.core.runtime.IStatus; +import org.eclipse.core.runtime.Status; +import org.eclipse.jface.dialogs.IMessageProvider; +import org.eclipse.jface.dialogs.MessageDialog; +import org.eclipse.jface.viewers.ColumnLabelProvider; +import org.eclipse.jface.viewers.IStructuredContentProvider; +import org.eclipse.jface.viewers.TableViewer; +import org.eclipse.jface.viewers.TableViewerColumn; +import org.eclipse.jface.viewers.Viewer; +import org.eclipse.jface.viewers.ViewerComparator; +import org.eclipse.jface.wizard.IWizardPage; +import org.eclipse.jface.wizard.Wizard; +import org.eclipse.jface.wizard.WizardPage; +import org.eclipse.swt.SWT; +import org.eclipse.swt.layout.GridData; +import org.eclipse.swt.layout.GridLayout; +import org.eclipse.swt.widgets.Button; +import org.eclipse.swt.widgets.Composite; +import org.eclipse.swt.widgets.Label; +import org.eclipse.swt.widgets.Table; +import org.eclipse.swt.widgets.Text; +import org.sonatype.aether.artifact.Artifact; + +/** + * Defines parameters to generate binaries (e.g. a specific modular + * distribution) using a {@link IndexDistribution} object + */ +public class GenerateBinariesWizard extends Wizard { + private final static Log log = LogFactory + .getLog(GenerateBinariesWizard.class); + + // Business objects + private Node groupNode; + + // The pages + private RecapPage recapPage; + + // Controls with parameters + private Button overridePomsBtn; + private Text versionTxt; + private Text latestVersionTxt; + private Text highestArtifactVersionTxt; + + // private CheckboxTableViewer wkspViewer; + + public GenerateBinariesWizard(Node groupNode) { + super(); + this.groupNode = groupNode; + } + + @Override + public void dispose() { + super.dispose(); + } + + @Override + public void addPages() { + try { + recapPage = new RecapPage(); + addPage(recapPage); + setWindowTitle("Define Binary Generation Procedure"); + } catch (Exception e) { + throw new SlcException("Cannot add page to wizard ", e); + } + } + + @Override + public boolean performFinish() { + if (!canFinish()) + return false; + try { + String msg = "Your are about to normalize group, do you really want to proceed ?"; + + boolean result = MessageDialog.openConfirm(DistPlugin.getDefault() + .getWorkbench().getDisplay().getActiveShell(), + "Confirm Process Launch", msg); + + if (result) { + GenerateBinaryJob job = new GenerateBinaryJob(groupNode, + versionTxt.getText(), overridePomsBtn.getSelection()); + job.setUser(true); + job.schedule(); + } + } catch (Exception e) { + throw new SlcException( + "Unexpected error while launching the fetch", e); + } + return true; + } + + // /////////////////////////////// + // ////// THE PAGES + private class RecapPage extends WizardPage { + + private TableViewer recapViewer; + + public RecapPage() { + super("Define parameters and launch"); + setTitle("Define parameters and launch"); + } + + @Override + public boolean isPageComplete() { + return isCurrentPage(); + } + + public IWizardPage getNextPage() { + // always last.... + return null; + } + + @Override + public void setVisible(boolean visible) { + if (visible) { + + } + super.setVisible(visible); + } + + private void refreshValues() { + try { + GenerateBinaries gb = GenerateBinaries.preProcessGroupNode( + groupNode, null); + + List binaries = new ArrayList(); + binaries.addAll(gb.getBinaries()); + + Artifact highestVersion = gb.getHighestArtifactVersion(); + if (highestVersion != null) + highestArtifactVersionTxt.setText(highestVersion + .getBaseVersion()); + + if (groupNode.hasNode(RepoConstants.BINARIES_ARTIFACT_ID)) { + Node binaryNode = groupNode + .getNode(RepoConstants.BINARIES_ARTIFACT_ID); + Artifact currHighestVersion = null; + for (NodeIterator ni = binaryNode.getNodes(); ni.hasNext();) { + Node currN = ni.nextNode(); + if (currN + .isNodeType(SlcTypes.SLC_ARTIFACT_VERSION_BASE)) { + Artifact currVersion = RepoUtils.asArtifact(currN); + + if (currHighestVersion == null + || currVersion.getBaseVersion() + .compareTo( + currHighestVersion + .getBaseVersion()) > 0) + currHighestVersion = currVersion; + } + } + if (currHighestVersion != null) + latestVersionTxt.setText(highestVersion + .getBaseVersion()); + } + + recapViewer.setInput(binaries); + recapViewer.refresh(); + } catch (RepositoryException re) { + throw new SlcException("Unable to get repositories URIs", re); + } + } + + public void createControl(Composite parent) { + Composite composite = new Composite(parent, SWT.NO_FOCUS); + composite.setLayout(new GridLayout(2, false)); + + versionTxt = createLT(composite, "Version"); + latestVersionTxt = createLT(composite, "Latest version"); + latestVersionTxt.setEditable(false); + highestArtifactVersionTxt = createLT(composite, + "Highest version in current category"); + highestArtifactVersionTxt.setEditable(false); + + overridePomsBtn = createLC(composite, "Override POMs"); + setMessage("Configure Maven Indexing", IMessageProvider.NONE); + + Table table = new Table(composite, SWT.H_SCROLL | SWT.V_SCROLL + | SWT.BORDER); + table.setLinesVisible(true); + table.setHeaderVisible(true); + table.setLayoutData(new GridData(SWT.FILL, SWT.FILL, true, true, 2, + 1)); + recapViewer = new TableViewer(table); + + // Artifact columns + TableViewerColumn column = ViewerUtils.createTableViewerColumn( + recapViewer, "Name", SWT.NONE, 250); + column.setLabelProvider(new ColumnLabelProvider() { + @Override + public String getText(Object element) { + return ((Artifact) element).getArtifactId(); + } + }); + + column = ViewerUtils.createTableViewerColumn(recapViewer, + "Version", SWT.NONE, 250); + column.setLabelProvider(new ColumnLabelProvider() { + @Override + public String getText(Object element) { + return ((Artifact) element).getBaseVersion(); + } + }); + + recapViewer.setContentProvider(new IStructuredContentProvider() { + List artifacts; + + public void inputChanged(Viewer viewer, Object oldInput, + Object newInput) { + artifacts = (List) newInput; + if (artifacts != null) + recapViewer.refresh(); + } + + public void dispose() { + } + + public Object[] getElements(Object inputElement) { + return artifacts == null ? null : artifacts.toArray(); + } + }); + + // A basic comparator + recapViewer.setComparator(new ViewerComparator()); + refreshValues(); + setControl(composite); + } + } + + /** Creates label and text. */ + protected Text createLT(Composite parent, String label) { + new Label(parent, SWT.NONE).setText(label); + Text text = new Text(parent, SWT.SINGLE | SWT.LEAD | SWT.BORDER + | SWT.NONE); + text.setLayoutData(new GridData(SWT.FILL, SWT.FILL, true, true)); + return text; + } + + /** Creates label and check. */ + protected Button createLC(Composite parent, String label) { + new Label(parent, SWT.NONE).setText(label); + Button check = new Button(parent, SWT.CHECK); + check.setSelection(false); + check.setLayoutData(new GridData(SWT.FILL, SWT.FILL, true, true)); + return check; + } + + /** + * Define the privileged job that will be run asynchronously to real + * indexing + */ + private class GenerateBinaryJob extends PrivilegedJob { + private Node groupBaseNode; + private String version; + private boolean overridePoms; + + public GenerateBinaryJob(Node groupBaseNode, String version, + boolean overridePoms) { + super("Fetch"); + this.groupBaseNode = groupBaseNode; + this.version = version; + this.overridePoms = overridePoms; + } + + @Override + protected IStatus doRun(IProgressMonitor progressMonitor) { + try { + ArgeoMonitor monitor = new EclipseArgeoMonitor(progressMonitor); + GenerateBinaries.processGroupNode(groupBaseNode, version, + overridePoms, monitor); + } catch (Exception e) { + if (log.isDebugEnabled()) + e.printStackTrace(); + return new Status(IStatus.ERROR, DistPlugin.ID, + "Cannot normalize group", e); + } + return Status.OK_STATUS; + } + } + + // //////////////////////////// + // // Helpers +} \ No newline at end of file diff --git a/runtime/org.argeo.slc.repo/src/main/java/org/argeo/slc/repo/RepoSync.java b/runtime/org.argeo.slc.repo/src/main/java/org/argeo/slc/repo/RepoSync.java index 18e864928..6ae38bf3a 100644 --- a/runtime/org.argeo.slc.repo/src/main/java/org/argeo/slc/repo/RepoSync.java +++ b/runtime/org.argeo.slc.repo/src/main/java/org/argeo/slc/repo/RepoSync.java @@ -248,6 +248,7 @@ public class RepoSync implements Runnable { if (log.isDebugEnabled()) log.debug("Synced " + sourceSession.getWorkspace().getName()); } catch (Exception e) { + e.printStackTrace(); throw new SlcException("Cannot sync " + sourceSession.getWorkspace().getName() + " to " + targetSession.getWorkspace().getName(), e); @@ -315,7 +316,8 @@ public class RepoSync implements Runnable { copyProperties(sourceNode, targetNode); // next level - for (NodeIterator ni = sourceNode.getNodes(); ni.hasNext();) { + NodeIterator ni = sourceNode.getNodes(); + while (ni != null && ni.hasNext()) { Node sourceChild = ni.nextNode(); syncNode(sourceChild, targetSession); } diff --git a/runtime/org.argeo.slc.repo/src/main/java/org/argeo/slc/repo/maven/GenerateBinaries.java b/runtime/org.argeo.slc.repo/src/main/java/org/argeo/slc/repo/maven/GenerateBinaries.java new file mode 100644 index 000000000..a1e2a071d --- /dev/null +++ b/runtime/org.argeo.slc.repo/src/main/java/org/argeo/slc/repo/maven/GenerateBinaries.java @@ -0,0 +1,518 @@ +/* + * Copyright (C) 2007-2012 Argeo GmbH + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.argeo.slc.repo.maven; + +import java.util.ArrayList; +import java.util.HashMap; +import java.util.List; +import java.util.Map; +import java.util.Set; +import java.util.TreeSet; + +import javax.jcr.Credentials; +import javax.jcr.Node; +import javax.jcr.NodeIterator; +import javax.jcr.Repository; +import javax.jcr.RepositoryException; +import javax.jcr.Session; + +import org.apache.commons.io.FilenameUtils; +import org.apache.commons.logging.Log; +import org.apache.commons.logging.LogFactory; +import org.argeo.ArgeoMonitor; +import org.argeo.jcr.JcrUtils; +import org.argeo.slc.SlcException; +import org.argeo.slc.aether.ArtifactIdComparator; +import org.argeo.slc.jcr.SlcNames; +import org.argeo.slc.jcr.SlcTypes; +import org.argeo.slc.repo.ArtifactIndexer; +import org.argeo.slc.repo.RepoConstants; +import org.argeo.slc.repo.RepoUtils; +import org.argeo.slc.repo.osgi.OsgiProfile; +import org.osgi.framework.Constants; +import org.osgi.framework.Version; +import org.sonatype.aether.artifact.Artifact; +import org.sonatype.aether.util.artifact.DefaultArtifact; + +/** + * Make sure that all JCR metadata and Maven metadata are consistent for this + * group of OSGi bundles. + */ +public class GenerateBinaries implements Runnable, SlcNames { + private final static Log log = LogFactory.getLog(GenerateBinaries.class); + + // Connection info + private Repository repository; + private Credentials credentials; + private String workspace; + + // Business info + private String groupId; + private String parentPomCoordinates; + private Boolean overridePoms = false; + private String version = null; + + // Constants + private String artifactBasePath = RepoConstants.DEFAULT_ARTIFACTS_BASE_PATH; + private List excludedSuffixes = new ArrayList(); + /** TODO make it more generic */ + private List systemPackages = OsgiProfile.PROFILE_JAVA_SE_1_6 + .getSystemPackages(); + + private ArtifactIndexer artifactIndexer = new ArtifactIndexer(); + + // Local indexes + private Map packagesToSymbolicNames = new HashMap(); + private Map symbolicNamesToNodes = new HashMap(); + private Set binaries = new TreeSet( + new ArtifactIdComparator()); + private Set sources = new TreeSet( + new ArtifactIdComparator()); + private Node allArtifactsHighestVersion; + + public void run() { + Session session = null; + try { + session = repository.login(workspace); + Node groupNode = session.getNode(MavenConventionsUtils.groupPath( + artifactBasePath, groupId)); + internalPreProcessing(groupNode, null); + processGroupNode(groupNode, null); + } catch (Exception e) { + throw new SlcException("Cannot normalize group " + groupId + " in " + + workspace, e); + } finally { + JcrUtils.logoutQuietly(session); + } + } + + public static void processGroupNode(Node groupNode, String version, + Boolean overridePoms, ArgeoMonitor monitor) + throws RepositoryException { + // TODO set artifactsBase based on group node + GenerateBinaries gb = new GenerateBinaries(); + String groupId = groupNode.getProperty(SlcNames.SLC_GROUP_BASE_ID) + .getString(); + gb.setGroupId(groupId); + gb.setVersion(version); + gb.setOverridePoms(overridePoms); + // TODO use already done pre-processing + gb.internalPreProcessing(groupNode, monitor); + gb.processGroupNode(groupNode, monitor); + } + + /** Only builds local indexes. Does not change anything in the local Session */ + public static GenerateBinaries preProcessGroupNode(Node groupNode, + ArgeoMonitor monitor) throws RepositoryException { + // TODO set artifactsBase based on group node + GenerateBinaries gb = new GenerateBinaries(); + String groupId = groupNode.getProperty(SlcNames.SLC_GROUP_BASE_ID) + .getString(); + gb.setGroupId(groupId); + // gb.setVersion(version); + // gb.setOverridePoms(overridePoms); + gb.internalPreProcessing(groupNode, monitor); + return gb; + } + + // exposes indexes. to display results of the pre-processing phase. + public Set getBinaries() { + return binaries; + } + + public Artifact getHighestArtifactVersion() throws RepositoryException { + return allArtifactsHighestVersion == null ? null : RepoUtils + .asArtifact(allArtifactsHighestVersion); + } + + protected void internalPreProcessing(Node groupNode, ArgeoMonitor monitor) + throws RepositoryException { + if (monitor != null) + monitor.subTask("Pre processing group " + groupId); + + // Process all direct children nodes, + // gathering latest versions of all artifact base + allArtifactsHighestVersion = null; + // Session session = groupNode.getSession(); + aBases: for (NodeIterator aBases = groupNode.getNodes(); aBases + .hasNext();) { + Node aBase = aBases.nextNode(); + if (aBase.isNodeType(SlcTypes.SLC_ARTIFACT_BASE)) { + Node highestAVersion = getArtifactLatestVersion(aBase); + if (highestAVersion == null) + continue aBases; + else { + // retrieve relevant child node + for (NodeIterator files = highestAVersion.getNodes(); files + .hasNext();) { + Node file = files.nextNode(); + if (file.isNodeType(SlcTypes.SLC_BUNDLE_ARTIFACT)) { + preProcessBundleArtifact(file); + if (log.isDebugEnabled()) + log.debug("Pre-processed " + file.getName()); + } + } + } + } + } + if (log.isDebugEnabled()) { + int bundleCount = symbolicNamesToNodes.size(); + log.debug("" + bundleCount + " bundles have been indexed for " + + groupId); + } + } + + /** Does the real job : writes JCR META-DATA and generates binaries */ + protected void processGroupNode(Node groupNode, ArgeoMonitor monitor) + throws RepositoryException { + if (monitor != null) + monitor.subTask("Processing group " + groupId); + + Session session = groupNode.getSession(); + + // if version not set or empty, use the highest version + // useful when indexing a product maven repository where + // all artifacts have the same version for a given release + // => the version can then be left empty + if (version == null || version.trim().equals("")) + if (allArtifactsHighestVersion != null) + version = allArtifactsHighestVersion.getProperty( + SLC_ARTIFACT_VERSION).getString(); + else + throw new SlcException("Group version " + version + + " is empty."); + + int bundleCount = symbolicNamesToNodes.size(); + + int count = 1; + for (Node bundleNode : symbolicNamesToNodes.values()) { + processBundleArtifact(bundleNode); + bundleNode.getSession().save(); + if (log.isDebugEnabled()) + log.debug(count + "/" + bundleCount + " Processed " + + bundleNode.getName()); + count++; + } + + // indexes + Set indexes = new TreeSet( + new ArtifactIdComparator()); + Artifact indexArtifact = writeIndex(session, + RepoConstants.BINARIES_ARTIFACT_ID, binaries); + indexes.add(indexArtifact); + indexArtifact = writeIndex(session, RepoConstants.SOURCES_ARTIFACT_ID, + sources); + indexes.add(indexArtifact); + // sdk + writeIndex(session, RepoConstants.SDK_ARTIFACT_ID, indexes); + if (monitor != null) + monitor.worked(1); + } + + // Helpers + private Node getArtifactLatestVersion(Node artifactBase) { + try { + Node highestAVersion = null; + for (NodeIterator aVersions = artifactBase.getNodes(); aVersions + .hasNext();) { + Node aVersion = aVersions.nextNode(); + if (aVersion.isNodeType(SlcTypes.SLC_ARTIFACT_VERSION_BASE)) { + if (highestAVersion == null) { + highestAVersion = aVersion; + if (allArtifactsHighestVersion == null) + allArtifactsHighestVersion = aVersion; + // Correctly handle following arrival order: + // Name1 - V1, name2 - V3 + else { + Version cachedHighestVersion = extractOsgiVersion(allArtifactsHighestVersion); + Version currVersion = extractOsgiVersion(aVersion); + if (currVersion.compareTo(cachedHighestVersion) > 0) + allArtifactsHighestVersion = aVersion; + } + } else { + Version currVersion = extractOsgiVersion(aVersion); + Version currentHighestVersion = extractOsgiVersion(highestAVersion); + if (currVersion.compareTo(currentHighestVersion) > 0) { + highestAVersion = aVersion; + } + if (currVersion + .compareTo(extractOsgiVersion(allArtifactsHighestVersion)) > 0) { + allArtifactsHighestVersion = aVersion; + } + } + + } + } + return highestAVersion; + } catch (RepositoryException re) { + throw new SlcException("Unable to get latest version for node " + + artifactBase, re); + } + } + + private Version extractOsgiVersion(Node artifactVersion) + throws RepositoryException { + String rawVersion = artifactVersion.getProperty(SLC_ARTIFACT_VERSION) + .getString(); + String cleanVersion = rawVersion.replace("-SNAPSHOT", ".SNAPSHOT"); + return new Version(cleanVersion); + } + + protected void preProcessBundleArtifact(Node bundleNode) + throws RepositoryException { + + String symbolicName = JcrUtils.get(bundleNode, SLC_SYMBOLIC_NAME); + if (symbolicName.endsWith(".source")) { + // TODO make a shared node with classifier 'sources'? + String bundleName = RepoUtils + .extractBundleNameFromSourceName(symbolicName); + for (String excludedSuffix : excludedSuffixes) { + if (bundleName.endsWith(excludedSuffix)) + return;// skip adding to sources + } + sources.add(RepoUtils.asArtifact(bundleNode)); + return; + } + + NodeIterator exportPackages = bundleNode.getNodes(SLC_ + + Constants.EXPORT_PACKAGE); + while (exportPackages.hasNext()) { + Node exportPackage = exportPackages.nextNode(); + String pkg = JcrUtils.get(exportPackage, SLC_NAME); + packagesToSymbolicNames.put(pkg, symbolicName); + } + + symbolicNamesToNodes.put(symbolicName, bundleNode); + for (String excludedSuffix : excludedSuffixes) { + if (symbolicName.endsWith(excludedSuffix)) + return;// skip adding to binaries + } + binaries.add(RepoUtils.asArtifact(bundleNode)); + + if (bundleNode.getSession().hasPendingChanges()) + throw new SlcException("Pending changes in the session, " + + "this should not be true here."); + // bundleNode.getSession().save(); + } + + protected void processBundleArtifact(Node bundleNode) + throws RepositoryException { + Node artifactFolder = bundleNode.getParent(); + String baseName = FilenameUtils.getBaseName(bundleNode.getName()); + + // pom + String pomName = baseName + ".pom"; + if (artifactFolder.hasNode(pomName) && !overridePoms) + return;// skip + + String pom = generatePomForBundle(bundleNode); + Node pomNode = JcrUtils.copyBytesAsFile(artifactFolder, pomName, + pom.getBytes()); + // checksum + String bundleSha = JcrUtils.checksumFile(bundleNode, "SHA-1"); + JcrUtils.copyBytesAsFile(artifactFolder, + bundleNode.getName() + ".sha1", bundleSha.getBytes()); + String pomSha = JcrUtils.checksumFile(pomNode, "SHA-1"); + JcrUtils.copyBytesAsFile(artifactFolder, pomNode.getName() + ".sha1", + pomSha.getBytes()); + } + + // Writers + private Artifact writeIndex(Session session, String artifactId, + Set artifacts) throws RepositoryException { + Artifact artifact = new DefaultArtifact(groupId, artifactId, "pom", + version); + Artifact parentArtifact = parentPomCoordinates != null ? new DefaultArtifact( + parentPomCoordinates) : null; + String pom = MavenConventionsUtils.artifactsAsDependencyPom(artifact, + artifacts, parentArtifact); + Node node = RepoUtils.copyBytesAsArtifact( + session.getNode(artifactBasePath), artifact, pom.getBytes()); + artifactIndexer.index(node); + + // TODO factorize + String pomSha = JcrUtils.checksumFile(node, "SHA-1"); + JcrUtils.copyBytesAsFile(node.getParent(), node.getName() + ".sha1", + pomSha.getBytes()); + String pomMd5 = JcrUtils.checksumFile(node, "MD5"); + JcrUtils.copyBytesAsFile(node.getParent(), node.getName() + ".md5", + pomMd5.getBytes()); + session.save(); + return artifact; + } + + private String generatePomForBundle(Node n) throws RepositoryException { + String ownSymbolicName = JcrUtils.get(n, SLC_SYMBOLIC_NAME); + + StringBuffer p = new StringBuffer(); + + // XML header + p.append("\n"); + p.append("\n"); + p.append("4.0.0"); + + // Artifact + p.append("").append(JcrUtils.get(n, SLC_GROUP_ID)) + .append("\n"); + p.append("").append(JcrUtils.get(n, SLC_ARTIFACT_ID)) + .append("\n"); + p.append("").append(JcrUtils.get(n, SLC_ARTIFACT_VERSION)) + .append("\n"); + p.append("pom\n"); + if (n.hasProperty(SLC_ + Constants.BUNDLE_NAME)) + p.append("") + .append(JcrUtils.get(n, SLC_ + Constants.BUNDLE_NAME)) + .append("\n"); + if (n.hasProperty(SLC_ + Constants.BUNDLE_DESCRIPTION)) + p.append("") + .append(JcrUtils + .get(n, SLC_ + Constants.BUNDLE_DESCRIPTION)) + .append("\n"); + + // Dependencies + Set dependenciesSymbolicNames = new TreeSet(); + Set optionalSymbolicNames = new TreeSet(); + NodeIterator importPackages = n.getNodes(SLC_ + + Constants.IMPORT_PACKAGE); + while (importPackages.hasNext()) { + Node importPackage = importPackages.nextNode(); + String pkg = JcrUtils.get(importPackage, SLC_NAME); + if (packagesToSymbolicNames.containsKey(pkg)) { + String dependencySymbolicName = packagesToSymbolicNames + .get(pkg); + if (JcrUtils.check(importPackage, SLC_OPTIONAL)) + optionalSymbolicNames.add(dependencySymbolicName); + else + dependenciesSymbolicNames.add(dependencySymbolicName); + } else { + if (!JcrUtils.check(importPackage, SLC_OPTIONAL) + && !systemPackages.contains(pkg)) + log.warn("No bundle found for pkg " + pkg); + } + } + + if (n.hasNode(SLC_ + Constants.FRAGMENT_HOST)) { + String fragmentHost = JcrUtils.get( + n.getNode(SLC_ + Constants.FRAGMENT_HOST), + SLC_SYMBOLIC_NAME); + dependenciesSymbolicNames.add(fragmentHost); + } + + // TODO require bundles + + List dependencyNodes = new ArrayList(); + for (String depSymbName : dependenciesSymbolicNames) { + if (depSymbName.equals(ownSymbolicName)) + continue;// skip self + + if (symbolicNamesToNodes.containsKey(depSymbName)) + dependencyNodes.add(symbolicNamesToNodes.get(depSymbName)); + else + log.warn("Could not find node for " + depSymbName); + } + List optionalDependencyNodes = new ArrayList(); + for (String depSymbName : optionalSymbolicNames) { + if (symbolicNamesToNodes.containsKey(depSymbName)) + optionalDependencyNodes.add(symbolicNamesToNodes + .get(depSymbName)); + else + log.warn("Could not find node for " + depSymbName); + } + + p.append("\n"); + for (Node dependencyNode : dependencyNodes) { + p.append("\n"); + p.append("\t") + .append(JcrUtils.get(dependencyNode, SLC_GROUP_ID)) + .append("\n"); + p.append("\t") + .append(JcrUtils.get(dependencyNode, SLC_ARTIFACT_ID)) + .append("\n"); + p.append("\n"); + } + + if (optionalDependencyNodes.size() > 0) + p.append("\n"); + for (Node dependencyNode : optionalDependencyNodes) { + p.append("\n"); + p.append("\t") + .append(JcrUtils.get(dependencyNode, SLC_GROUP_ID)) + .append("\n"); + p.append("\t") + .append(JcrUtils.get(dependencyNode, SLC_ARTIFACT_ID)) + .append("\n"); + p.append("\ttrue\n"); + p.append("\n"); + } + p.append("\n"); + + // Dependency management + p.append("\n"); + p.append("\n"); + p.append("\n"); + p.append("\t").append(groupId).append("\n"); + p.append("\t") + .append(ownSymbolicName.endsWith(".source") ? RepoConstants.SOURCES_ARTIFACT_ID + : RepoConstants.BINARIES_ARTIFACT_ID) + .append("\n"); + p.append("\t").append(version).append("\n"); + p.append("\tpom\n"); + p.append("\timport\n"); + p.append("\n"); + p.append("\n"); + p.append("\n"); + + p.append("\n"); + return p.toString(); + } + + /* SETTERS */ + public void setRepository(Repository repository) { + this.repository = repository; + } + + public void setWorkspace(String workspace) { + this.workspace = workspace; + } + + public void setGroupId(String groupId) { + this.groupId = groupId; + } + + public void setParentPomCoordinates(String parentPomCoordinates) { + this.parentPomCoordinates = parentPomCoordinates; + } + + public void setArtifactBasePath(String artifactBasePath) { + this.artifactBasePath = artifactBasePath; + } + + public void setVersion(String version) { + this.version = version; + } + + public void setExcludedSuffixes(List excludedSuffixes) { + this.excludedSuffixes = excludedSuffixes; + } + + public void setOverridePoms(Boolean overridePoms) { + this.overridePoms = overridePoms; + } + + public void setArtifactIndexer(ArtifactIndexer artifactIndexer) { + this.artifactIndexer = artifactIndexer; + } +} \ No newline at end of file diff --git a/runtime/org.argeo.slc.repo/src/main/java/org/argeo/slc/repo/osgi/NormalizeGroup.java b/runtime/org.argeo.slc.repo/src/main/java/org/argeo/slc/repo/osgi/NormalizeGroup.java index 0d1eded08..34e1aee24 100644 --- a/runtime/org.argeo.slc.repo/src/main/java/org/argeo/slc/repo/osgi/NormalizeGroup.java +++ b/runtime/org.argeo.slc.repo/src/main/java/org/argeo/slc/repo/osgi/NormalizeGroup.java @@ -178,8 +178,9 @@ public class NormalizeGroup implements Runnable, SlcNames { version = allArtifactsHighestVersion.getProperty( SLC_ARTIFACT_VERSION).getString(); else - throw new SlcException("Group version " + version - + " is empty."); + version = "0.0"; +// throw new SlcException("Group version " + version +// + " is empty."); int bundleCount = symbolicNamesToNodes.size(); if (log.isDebugEnabled()) @@ -243,12 +244,8 @@ public class NormalizeGroup implements Runnable, SlcNames { protected void preProcessBundleArtifact(Node bundleNode) throws RepositoryException { - // we assume nodes are already indexed - // artifactIndexer.index(bundleNode); - // jarFileIndexer.index(bundleNode); String symbolicName = JcrUtils.get(bundleNode, SLC_SYMBOLIC_NAME); - if (symbolicName.endsWith(".source")) { // TODO make a shared node with classifier 'sources'? String bundleName = RepoUtils @@ -313,7 +310,6 @@ public class NormalizeGroup implements Runnable, SlcNames { p.append("4.0.0"); // Artifact - // p.append("org.argeoparent1.2.0\n"); p.append("").append(JcrUtils.get(n, SLC_GROUP_ID)) .append("\n"); p.append("").append(JcrUtils.get(n, SLC_ARTIFACT_ID)) @@ -362,6 +358,8 @@ public class NormalizeGroup implements Runnable, SlcNames { // TODO require bundles + + List dependencyNodes = new ArrayList(); for (String depSymbName : dependenciesSymbolicNames) { if (depSymbName.equals(ownSymbolicName)) diff --git a/runtime/org.argeo.slc.support.jcr/src/main/java/org/argeo/slc/jcr/SlcNames.java b/runtime/org.argeo.slc.support.jcr/src/main/java/org/argeo/slc/jcr/SlcNames.java index bc3300515..d6ddd1921 100644 --- a/runtime/org.argeo.slc.support.jcr/src/main/java/org/argeo/slc/jcr/SlcNames.java +++ b/runtime/org.argeo.slc.support.jcr/src/main/java/org/argeo/slc/jcr/SlcNames.java @@ -105,6 +105,7 @@ public interface SlcNames { // shared OSGi public final static String SLC_SYMBOLIC_NAME = "slc:symbolic-name"; public final static String SLC_BUNDLE_VERSION = "slc:bundle-version"; + public final static String SLC_BUNDLE_DESCRIPTION = "slc:Bundle-Description"; // slc:osgiBaseVersion public final static String SLC_MAJOR = "slc:major"; -- 2.39.2