diff --git a/app/databrowser/pom.xml b/app/databrowser/pom.xml index 6c30bc13bd..ce81134175 100644 --- a/app/databrowser/pom.xml +++ b/app/databrowser/pom.xml @@ -75,5 +75,37 @@ commons-math3 ${apache.commons.math.version} + + + org.apache.poi + poi + + + com.zaxxer + SparseBitSet + + + org.slf4j + slf4j-api + + + org.slf4j + jcl-over-slf4j + + + commons-codec + commons-codec + + + org.apache.commons + commons-collections4 + + + org.apache.commons + commons-math3 + + + 5.0.0 + diff --git a/app/databrowser/src/main/java/org/csstudio/trends/databrowser3/Messages.java b/app/databrowser/src/main/java/org/csstudio/trends/databrowser3/Messages.java index c25c88cc3b..92cee51e28 100644 --- a/app/databrowser/src/main/java/org/csstudio/trends/databrowser3/Messages.java +++ b/app/databrowser/src/main/java/org/csstudio/trends/databrowser3/Messages.java @@ -118,6 +118,9 @@ public class Messages ExportStartExport, ExportTabular, ExportTabularTT, + ExportTypeExcel, + ExportTypeExcelFilenamePrompt, + ExportTypeExcelTT, ExportTypeMatlab, ExportTypeMatlabTT, ExportTypeSpreadsheet, diff --git a/app/databrowser/src/main/java/org/csstudio/trends/databrowser3/export/ExcelExportJob.java b/app/databrowser/src/main/java/org/csstudio/trends/databrowser3/export/ExcelExportJob.java new file mode 100644 index 0000000000..ec0c5e7e65 --- /dev/null +++ b/app/databrowser/src/main/java/org/csstudio/trends/databrowser3/export/ExcelExportJob.java @@ -0,0 +1,384 @@ +/******************************************************************************* + * Copyright (c) 2025 Oak Ridge National Laboratory. + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the Eclipse Public License v1.0 + * which accompanies this distribution, and is available at + * http://www.eclipse.org/legal/epl-v10.html + ******************************************************************************/ +package org.csstudio.trends.databrowser3.export; + +import java.io.PrintStream; +import java.text.MessageFormat; +import java.time.Instant; +import java.time.LocalDateTime; +import java.time.ZoneId; +import java.util.ArrayList; +import java.util.List; +import java.util.Objects; +import java.util.function.Consumer; + +import org.csstudio.trends.databrowser3.Messages; +import org.csstudio.trends.databrowser3.model.ArchiveDataSource; +import org.csstudio.trends.databrowser3.model.Model; +import org.csstudio.trends.databrowser3.model.ModelItem; +import org.csstudio.trends.databrowser3.model.PVItem; +import org.epics.vtype.VEnum; +import org.epics.vtype.VNumber; +import org.epics.vtype.VStatistics; +import org.epics.vtype.VString; +import org.epics.vtype.VType; +import org.phoebus.archive.reader.SpreadsheetIterator; +import org.phoebus.archive.reader.ValueIterator; +import org.phoebus.archive.vtype.VTypeHelper; +import org.phoebus.framework.jobs.JobMonitor; +import org.phoebus.util.time.SecondsParser; +import org.phoebus.util.time.TimestampFormats; +import org.apache.poi.hssf.usermodel.HSSFWorkbook; +import org.apache.poi.ss.usermodel.Cell; +import org.apache.poi.ss.usermodel.CellStyle; +import org.apache.poi.ss.usermodel.CellType; +import org.apache.poi.ss.usermodel.FillPatternType; +import org.apache.poi.ss.usermodel.Font; +import org.apache.poi.ss.usermodel.IndexedColors; +import org.apache.poi.ss.usermodel.Row; +import org.apache.poi.ss.usermodel.Sheet; +import org.apache.poi.ss.usermodel.Workbook; + +/** Export Job for exporting data from Model as Excel file + * @author Kay Kasemir + */ +@SuppressWarnings("nls") +public class ExcelExportJob extends ExportJob +{ + private Workbook wb = null; + private CellStyle comment_style, header_style, timestamp_style; + private Sheet sheet; + private Row row; + private ZoneId zone = ZoneId.systemDefault(); + private final boolean tabular, min_max, sevr_stat; + + /** @param model Model + * @param start Start time + * @param end End time + * @param source Data source + * @param tabular Create one combined table? Otherwise one table per channel + * @param min_max Show min/max info (error) for statistical data? + * @param sevr_stat Include alarm severity and status? + * @param optimize_parameter Bin count + * @param filename Export file name + * @param error_handler Error handler + * @param unixTimeStamp Use UNIX time stamp epoch? + */ + public ExcelExportJob(final Model model, + final Instant start, final Instant end, final Source source, + final boolean tabular, final boolean min_max, final boolean sevr_stat, + final double optimize_parameter, + final String filename, + final Consumer error_handler, + final boolean unixTimeStamp) + { + super("", model, start, end, source, optimize_parameter, filename, error_handler, unixTimeStamp); + this.tabular = tabular; + this.min_max = min_max; + this.sevr_stat = sevr_stat; + } + + private void addComment(final Row row, final String label, final String text) + { + Cell cell = row.createCell(0, CellType.STRING); + cell.setCellValue(label); + cell.setCellStyle(comment_style); + if (text != null) + { + cell = row.createCell(1, CellType.STRING); + cell.setCellValue(text); + cell.setCellStyle(comment_style); + } + } + + /** {@inheritDoc} */ + @Override + protected void printExportInfo(final PrintStream out) throws Exception + { + // Called first and may throw Exception, so create workbook etc in here + wb = new HSSFWorkbook(); + + comment_style = wb.createCellStyle(); + Font font = wb.createFont(); + font.setBold(true); + font.setColor(IndexedColors.DARK_BLUE.getIndex()); + comment_style.setFont(font); + + header_style = wb.createCellStyle(); + font = wb.createFont(); + font.setItalic(true); + header_style.setFont(font); + header_style.setFillForegroundColor(IndexedColors.GREY_25_PERCENT.getIndex()); + header_style.setFillPattern(FillPatternType.SOLID_FOREGROUND); + + timestamp_style = wb.createCellStyle(); + timestamp_style.setDataFormat( + wb.getCreationHelper() + .createDataFormat() + .getFormat("yyyy-mm-dd hh:mm:ss.000")); + + // Create sheet with summary of exported data + sheet = wb.createSheet("Archive Data"); + + addComment(row = sheet.createRow(0), "Created by CS-Studio Data Browser", null); + addComment(row = sheet.createRow(row.getRowNum() + 2), "Start time", TimestampFormats.MILLI_FORMAT.format(start)); + addComment(row = sheet.createRow(row.getRowNum() + 1), "End time", TimestampFormats.MILLI_FORMAT.format(end)); + addComment(row = sheet.createRow(row.getRowNum() + 1), "Source", source.toString()); + + if (source == Source.OPTIMIZED_ARCHIVE) + addComment(row = sheet.createRow(row.getRowNum() + 1), "Desired Value Count", Double.toString(optimize_parameter)); + else if (source == Source.LINEAR_INTERPOLATION) + addComment(row = sheet.createRow(row.getRowNum() + 1), "Interpolation Interval", SecondsParser.formatSeconds(optimize_parameter)); + } + + /** @param row Row where to create time stamp cell + * @param time Timestamp to place in cell + * @return The cell in column 0 of row + */ + private Cell createTimeCell(final Row row, final Instant time) + { + Cell cell = row.createCell(0, CellType.NUMERIC); + if (unixTimeStamp) + cell.setCellValue(time.toEpochMilli()); + else + { + cell.setCellValue(LocalDateTime.ofInstant(time, zone)); + cell.setCellStyle(timestamp_style); + } + return cell; + } + + /** @param row Row where to create value cell + * @param column Column index + * @param value Value to show + * @return Cell that was created for the value + */ + private Cell createValueCell(final Row row, final int column, final VType value) + { + final Cell cell; + if (value instanceof VNumber v) + { + cell = row.createCell(column, CellType.NUMERIC); + cell.setCellValue(v.getValue().doubleValue()); + } + else if (value instanceof VStatistics v) + { + cell = row.createCell(column, CellType.NUMERIC); + cell.setCellValue(v.getAverage()); + } + else if (value instanceof VEnum v) + { + cell = row.createCell(column, CellType.NUMERIC); + cell.setCellValue(v.getIndex()); + } + else if (value instanceof VString v) + { + cell = row.createCell(column, CellType.STRING); + cell.setCellValue(v.getValue()); + } + else if (value == null) + cell = row.createCell(column, CellType.BLANK); + else + { + cell = row.createCell(column, CellType.STRING); + cell.setCellValue(Objects.toString(value)); + } + return cell; + } + + /** Create basic value cell as well as optional min/max and sevr/stat cells + * @param row Row where to create cells + * @param column Index of first cell column + * @param value Value to show in cell(s) + * @return Last cell created + */ + private Cell createValueCells(final Row row, final int column, final VType value) + { + Cell cell = createValueCell(row, column, value); + if (min_max) + { + if (value instanceof VStatistics stats) + { // Turn min..max into negative & positive error + cell = row.createCell(cell.getColumnIndex()+1, CellType.NUMERIC); + cell.setCellValue(stats.getAverage() - stats.getMin()); + cell = row.createCell(cell.getColumnIndex()+1, CellType.NUMERIC); + cell.setCellValue(stats.getMax() - stats.getAverage()); + } + else + { + cell = row.createCell(cell.getColumnIndex()+1, CellType.BLANK); + cell = row.createCell(cell.getColumnIndex()+1, CellType.BLANK); + } + } + if (sevr_stat) + { + cell = row.createCell(cell.getColumnIndex()+1, CellType.STRING); + cell.setCellValue(Objects.toString(org.phoebus.core.vtypes.VTypeHelper.getSeverity(value))); + + cell = row.createCell(cell.getColumnIndex()+1, CellType.STRING); + cell.setCellValue(VTypeHelper.getMessage(value)); + } + return cell; + } + + + @Override + protected void performExport(final JobMonitor monitor, final PrintStream out) throws Exception + { + // Item header + for (ModelItem item : model.getItems()) + { + addComment(row = sheet.createRow(row.getRowNum() + 2), "Channel", item.getResolvedName()); + if (! item.getName().equals(item.getDisplayName())) + addComment(row = sheet.createRow(row.getRowNum() + 1), "Name", item.getResolvedDisplayName()); + + if (item instanceof PVItem) + { + final PVItem pv = (PVItem) item; + addComment(row = sheet.createRow(row.getRowNum() + 1), "Archives:", null); + + int i=1; + for (ArchiveDataSource archive : pv.getArchiveDataSources()) + { + addComment(row = sheet.createRow(row.getRowNum() + 1), + i + ") " + archive.getName(), + "URL " + archive.getUrl()); + ++i; + } + } + } + + if (tabular) + exportTable(monitor); + else + exportList(monitor); + + wb.write(out); + } + + /** Export data in combined table */ + private void exportTable(final JobMonitor monitor) throws Exception + { + // Spreadsheet data header + row = sheet.createRow(row.getRowNum() + 2); + Cell cell = row.createCell(0, CellType.STRING); + cell.setCellStyle(header_style); + cell.setCellValue(Messages.TimeColumn); + for (ModelItem item : model.getItems()) + { + cell = row.createCell(cell.getColumnIndex()+1, CellType.STRING); + cell.setCellStyle(header_style); + cell.setCellValue(item.getResolvedName()); + + if (min_max) + { + cell = row.createCell(cell.getColumnIndex()+1, CellType.STRING); + cell.setCellStyle(header_style); + cell.setCellValue(Messages.NegErrColumn); + + cell = row.createCell(cell.getColumnIndex()+1, CellType.STRING); + cell.setCellStyle(header_style); + cell.setCellValue(Messages.PosErrColumn); + } + if (sevr_stat) + { + cell = row.createCell(cell.getColumnIndex()+1, CellType.STRING); + cell.setCellStyle(header_style); + cell.setCellValue(Messages.SeverityColumn); + + cell = row.createCell(cell.getColumnIndex()+1, CellType.STRING); + cell.setCellStyle(header_style); + cell.setCellValue(Messages.StatusColumn); + } + } + + // Create spreadsheet interpolation + final List iters = new ArrayList<>(); + for (ModelItem item : model.getItems()) + { + monitor.beginTask(MessageFormat.format("Fetching data for {0}", item.getName())); + iters.add(createValueIterator(item)); + } + final SpreadsheetIterator iter = new SpreadsheetIterator(iters.toArray(new ValueIterator[iters.size()])); + // Dump the spreadsheet lines + long line_count = 0; + while (iter.hasNext() && !monitor.isCanceled()) + { + final Instant time = iter.getTime(); + final VType line[] = iter.next(); + + cell = createTimeCell(row = sheet.createRow(row.getRowNum() + 1), time); + for (int i=0; iperformExport */ - protected void printExportInfo(final PrintStream out) + /** Print file header, gets invoked before performExport + * @param out PrintStream for output + * @throws Exception on error + */ + protected void printExportInfo(final PrintStream out) throws Exception { out.println(comment + "Created by CS-Studio Data Browser"); out.println(comment); diff --git a/app/databrowser/src/main/java/org/csstudio/trends/databrowser3/export/MatlabScriptExportJob.java b/app/databrowser/src/main/java/org/csstudio/trends/databrowser3/export/MatlabScriptExportJob.java index e925add970..357e1735ab 100644 --- a/app/databrowser/src/main/java/org/csstudio/trends/databrowser3/export/MatlabScriptExportJob.java +++ b/app/databrowser/src/main/java/org/csstudio/trends/databrowser3/export/MatlabScriptExportJob.java @@ -48,7 +48,7 @@ public MatlabScriptExportJob(final Model model, final Instant start, /** {@inheritDoc} */ @Override - protected void printExportInfo(final PrintStream out) + protected void printExportInfo(final PrintStream out) throws Exception { super.printExportInfo(out); out.println(comment); diff --git a/app/databrowser/src/main/java/org/csstudio/trends/databrowser3/export/PlainExportJob.java b/app/databrowser/src/main/java/org/csstudio/trends/databrowser3/export/PlainExportJob.java index 74992cb76a..356dcfcc64 100644 --- a/app/databrowser/src/main/java/org/csstudio/trends/databrowser3/export/PlainExportJob.java +++ b/app/databrowser/src/main/java/org/csstudio/trends/databrowser3/export/PlainExportJob.java @@ -45,15 +45,13 @@ public PlainExportJob(final Model model, final String filename, final Consumer error_handler, final boolean unixTimeStamp) - { // MS Excel fails to recognize tab-separated data columns - // unless the initial header rows also contain at least one tab per row, - // so add that to comment - super("#\t", model, start, end, source, optimize_parameter, filename, error_handler, unixTimeStamp); + { + super("# ", model, start, end, source, optimize_parameter, filename, error_handler, unixTimeStamp); this.formatter = formatter; } @Override - protected void printExportInfo(final PrintStream out) + protected void printExportInfo(final PrintStream out) throws Exception { super.printExportInfo(out); out.println(comment + "Format : " + formatter.toString()); diff --git a/app/databrowser/src/main/java/org/csstudio/trends/databrowser3/export/SpreadsheetExportJob.java b/app/databrowser/src/main/java/org/csstudio/trends/databrowser3/export/SpreadsheetExportJob.java index c759089233..dedb3894fd 100644 --- a/app/databrowser/src/main/java/org/csstudio/trends/databrowser3/export/SpreadsheetExportJob.java +++ b/app/databrowser/src/main/java/org/csstudio/trends/databrowser3/export/SpreadsheetExportJob.java @@ -66,7 +66,7 @@ protected void performExport(final JobMonitor monitor, out.print(Messages.Export_Delimiter + item.getResolvedName() + " " + formatter.getHeader()); out.println(); - // Create speadsheet interpolation + // Create spreadsheet interpolation final List iters = new ArrayList<>(); for (ModelItem item : model.getItems()) { diff --git a/app/databrowser/src/main/java/org/csstudio/trends/databrowser3/ui/export/ExportView.java b/app/databrowser/src/main/java/org/csstudio/trends/databrowser3/ui/export/ExportView.java index 5f25d10fb8..48d9fcf000 100644 --- a/app/databrowser/src/main/java/org/csstudio/trends/databrowser3/ui/export/ExportView.java +++ b/app/databrowser/src/main/java/org/csstudio/trends/databrowser3/ui/export/ExportView.java @@ -1,5 +1,5 @@ /******************************************************************************* - * Copyright (c) 2010-2018 Oak Ridge National Laboratory. + * Copyright (c) 2010-2025 Oak Ridge National Laboratory. * All rights reserved. This program and the accompanying materials * are made available under the terms of the Eclipse Public License v1.0 * which accompanies this distribution, and is available at @@ -15,6 +15,7 @@ import org.csstudio.trends.databrowser3.Activator; import org.csstudio.trends.databrowser3.Messages; +import org.csstudio.trends.databrowser3.export.ExcelExportJob; import org.csstudio.trends.databrowser3.export.ExportJob; import org.csstudio.trends.databrowser3.export.MatlabFileExportJob; import org.csstudio.trends.databrowser3.export.MatlabScriptExportJob; @@ -88,6 +89,7 @@ public class ExportView extends VBox format_digits = new TextField(Messages.ExportDefaultDigits), filename = new TextField(); private final RadioButton source_raw = new RadioButton(Source.RAW_ARCHIVE.toString()), + type_excel = new RadioButton(Messages.ExportTypeExcel), type_matlab = new RadioButton(Messages.ExportTypeMatlab); private final CheckBox useUnixTimeStamp = new CheckBox(Messages.UseUnixTimeStamp); @@ -190,7 +192,7 @@ public ExportView(final Model model) // * Format * - // (*) Spreadsheet ( ) Matlab + // (*) Excel ( ) Spreadsheet ( ) Matlab // [x] Tabular [x] ... with min/max column [x] ... with Severity/Status // (*) Default format ( ) decimal notation ( ) exponential notation _digits_ fractional digits grid = new GridPane(); @@ -198,16 +200,20 @@ public ExportView(final Model model) grid.setVgap(5); grid.setPadding(new Insets(5)); + type_excel.setTooltip(new Tooltip(Messages.ExportTypeExcelTT)); + type_excel.setToggleGroup(table_types); + grid.add(type_excel, 0, 0); + final RadioButton type_spreadsheet = new RadioButton(Messages.ExportTypeSpreadsheet); type_spreadsheet.setTooltip(new Tooltip(Messages.ExportTypeSpreadsheetTT)); type_spreadsheet.setToggleGroup(table_types); - grid.add(type_spreadsheet, 0, 0); + grid.add(type_spreadsheet, 1, 0); type_matlab.setTooltip(new Tooltip(Messages.ExportTypeMatlabTT)); type_matlab.setToggleGroup(table_types); - grid.add(type_matlab, 1, 0); + grid.add(type_matlab, 2, 0); - type_spreadsheet.setSelected(true); + type_excel.setSelected(true); tabular.setTooltip(new Tooltip(Messages.ExportTabularTT)); tabular.setSelected(true); @@ -250,10 +256,10 @@ public ExportView(final Model model) grid.add(format_digits, 3, 2); // Formatting only applies to spreadsheet - format_default.disableProperty().bind(type_matlab.selectedProperty()); - format_decimal.disableProperty().bind(type_matlab.selectedProperty()); - format_expo.disableProperty().bind(type_matlab.selectedProperty()); - format_digits.disableProperty().bind(type_matlab.selectedProperty()); + format_default.disableProperty().bind(type_matlab.selectedProperty().or(type_excel.selectedProperty())); + format_decimal.disableProperty().bind(type_matlab.selectedProperty().or(type_excel.selectedProperty())); + format_expo.disableProperty().bind(type_matlab.selectedProperty().or(type_excel.selectedProperty())); + format_digits.disableProperty().bind(type_matlab.selectedProperty().or(type_excel.selectedProperty())); grid.add(new Label(Messages.ExportDigits), 4, 2); @@ -371,7 +377,7 @@ else if (source == Source.LINEAR_INTERPOLATION) } // Get remaining export parameters - final String filename = this.filename.getText().trim(); + String filename = this.filename.getText().trim(); if (filename.isEmpty()) { ExceptionDetailsErrorDialog.openError(this.filename, Messages.Error, Messages.ExportEnterFilenameError, new Exception(filename)); @@ -395,7 +401,31 @@ else if (source == Source.LINEAR_INTERPOLATION) // Construct appropriate export job final ExportJob export; final TimeInterval start_end = range.toAbsoluteInterval(); - if (type_matlab.isSelected()) + if (type_excel.isSelected()) + { // Excel file export + if (! filename.endsWith(".xls")) + { + final Alert dialog = new Alert(AlertType.CONFIRMATION); + dialog.setTitle(Messages.ExportTypeExcel); + dialog.setHeaderText(Messages.ExportTypeExcelFilenamePrompt); + DialogHelper.positionDialog(dialog, this.filename, -200, -200); + ButtonType result = dialog.showAndWait().orElse(ButtonType.CANCEL); + if (result == ButtonType.CANCEL) + return; + if (result == ButtonType.OK) + { + int last = filename.lastIndexOf('.'); + if (last == -1) + filename = filename + ".xls"; + else + filename = filename.substring(0, last) + ".xls"; + } + } + export = new ExcelExportJob(model, start_end.getStart(), start_end.getEnd(), source, + tabular.isSelected(), min_max_col.isSelected(), sev_stat.isSelected(), + optimize_parameter, filename, this::handleError, unixTimeStamp.get()); + } + else if (type_matlab.isSelected()) { // Matlab file export if (filename.endsWith(".m")) export = new MatlabScriptExportJob(model, diff --git a/app/databrowser/src/main/resources/org/csstudio/trends/databrowser3/messages.properties b/app/databrowser/src/main/resources/org/csstudio/trends/databrowser3/messages.properties index 1685c9de68..17da45c89f 100644 --- a/app/databrowser/src/main/resources/org/csstudio/trends/databrowser3/messages.properties +++ b/app/databrowser/src/main/resources/org/csstudio/trends/databrowser3/messages.properties @@ -98,9 +98,12 @@ ExportSource_RawArchiveTT=Fetch Raw Archived Data from archive ExportStartExport=Export ExportTabular=Tabular ExportTabularTT=Generate Spreadsheet-type table for all channels, or list samples channels-by-channel? -ExportTypeMatlab=Matlab +ExportTypeExcel=Excel (*.xls) +ExportTypeExcelFilenamePrompt=File name must be *.xls. Update file extension to .xls? +ExportTypeExcelTT=Create Excel (*.xls) file +ExportTypeMatlab=Matlab (*.m, *.mat) ExportTypeMatlabTT=Create Matlab text file (*.m) or binary data (*.mat) file -ExportTypeSpreadsheet=Spreadsheet +ExportTypeSpreadsheet=Spreadsheet (*.dat, *.csv, *.txt, ...) ExportTypeSpreadsheetTT=Create text file suitable for spreadsheet ExportValueInfo=... with Severity/Status ExportValueInfoTT=Include sample Severity/Status in output diff --git a/app/databrowser/src/main/resources/org/csstudio/trends/databrowser3/messages_fr.properties b/app/databrowser/src/main/resources/org/csstudio/trends/databrowser3/messages_fr.properties index dcbfa60a42..4e56eb9190 100644 --- a/app/databrowser/src/main/resources/org/csstudio/trends/databrowser3/messages_fr.properties +++ b/app/databrowser/src/main/resources/org/csstudio/trends/databrowser3/messages_fr.properties @@ -98,9 +98,12 @@ ExportSource_RawArchiveTT=R\u00E9cup\u00E9rer les donn\u00E9es archiv\u00E9es br ExportStartExport=Exporter ExportTabular=Tabulaire ExportTabularTT=G\u00E9n\u00E9rer un tableau de type feuille de calcul pour tous les canaux, ou lister les \u00E9chantillons canal par canal ? -ExportTypeMatlab=Matlab +ExportTypeExcel=Excel (*.xls) +ExportTypeExcelFilenamePrompt=File name must be *.xls. Update file extension to .xls? +ExportTypeExcelTT=Create Excel (*.xls) file +ExportTypeMatlab=Matlab (*.m, *.mat) ExportTypeMatlabTT=Cr\u00E9er un fichier texte Matlab (*.m) ou un fichier de donn\u00E9es binaire (*.mat) -ExportTypeSpreadsheet=Feuille de calcul +ExportTypeSpreadsheet=Feuille de calcul (*.dat, *.csv, *.txt, ...) ExportTypeSpreadsheetTT=Cr\u00E9er un fichier texte adapt\u00E9 \u00E0 une feuille de calcul ExportValueInfo=... avec S\u00E9v\u00E9rit\u00E9/Statut ExportValueInfoTT=Inclure la s\u00E9v\u00E9rit\u00E9/le statut de l\u0027\u00E9chantillon dans la sortie diff --git a/dependencies/phoebus-target/.classpath b/dependencies/phoebus-target/.classpath index b40a52a677..5b5a81fc69 100644 --- a/dependencies/phoebus-target/.classpath +++ b/dependencies/phoebus-target/.classpath @@ -1,12 +1,5 @@ - - - - - - - @@ -44,17 +37,19 @@ + + - + @@ -70,6 +65,7 @@ + @@ -101,7 +97,9 @@ - + + + @@ -115,7 +113,6 @@ - @@ -131,6 +128,7 @@ + @@ -147,6 +145,7 @@ + @@ -192,20 +191,20 @@ --> - - - - - - - - - - - - - - + + + + + + + + + + + + + + diff --git a/dependencies/phoebus-target/check_classpath.py b/dependencies/phoebus-target/check_classpath.py new file mode 100755 index 0000000000..fed011c11e --- /dev/null +++ b/dependencies/phoebus-target/check_classpath.py @@ -0,0 +1,37 @@ +#!/bin/env python3 + +import argparse +from os import path +from glob import glob +import re +import xml.etree.ElementTree as ET + + +parser = argparse.ArgumentParser( + description='Check if .classpath entries exist. If not, suggest alternate version') +args = parser.parse_args() + + +xml = ET.parse(".classpath") +root = xml.getroot() + +for entry in root.iter('classpathentry'): + if entry.get('kind') == 'lib': + jar = entry.get('path') + if path.exists(jar): + pass + else: + pattern = re.sub(r'[0-9.]+', r'*', jar) + # print(pattern) + alt = glob(pattern) + # print(alt) + if len(alt) == 1: + update = alt[0] + print("%-60s -----> use %s" % (jar, update)) + elif len(alt) > 1: + update = " or ".join(alt) + print("%-60s -----> use %s" % (jar, update)) + else: + print("%-60s is missing, no replacement found" % jar) + + diff --git a/dependencies/phoebus-target/pom.xml b/dependencies/phoebus-target/pom.xml index 70cbea4cf5..405f674ba2 100644 --- a/dependencies/phoebus-target/pom.xml +++ b/dependencies/phoebus-target/pom.xml @@ -511,7 +511,39 @@ epics-jackie-client 3.1.0 - + + + + org.apache.poi + poi + + + com.zaxxer + SparseBitSet + + + org.slf4j + slf4j-api + + + org.slf4j + jcl-over-slf4j + + + commons-codec + commons-codec + + + org.apache.commons + commons-collections4 + + + org.apache.commons + commons-math3 + + + 5.0.0 +