4 import java.io.IOException;
6 import java.nio.file.Files;
7 import java.nio.file.Path;
8 import java.time.LocalDateTime;
9 import java.time.format.DateTimeFormatter;
11 import org.eclipse.core.runtime.CoreException;
12 import org.eclipse.core.runtime.IProgressMonitor;
13 import org.eclipse.core.runtime.IStatus;
14 import org.eclipse.core.runtime.NullProgressMonitor;
15 import org.eclipse.core.runtime.Platform;
16 import org.eclipse.core.runtime.Status;
17 import org.eclipse.equinox.app.IApplication;
18 import org.eclipse.equinox.app.IApplicationContext;
19 import org.eclipse.osgi.service.datalocation.Location;
20 import org.simantics.application.arguments.Arguments;
21 import org.simantics.application.arguments.IArgumentFactory;
22 import org.simantics.application.arguments.IArgumentFactory.NoValueArgumentFactory;
23 import org.simantics.application.arguments.IArgumentFactory.StringArgumentFactory;
24 import org.simantics.application.arguments.IArguments;
25 import org.simantics.application.arguments.SimanticsArguments;
26 import org.simantics.internal.Activator;
27 import org.simantics.scl.runtime.SCLContext;
28 import org.simantics.scl.runtime.reporting.SCLReportingHandler;
29 import org.simantics.scl.runtime.tuple.Tuple0;
30 import org.slf4j.Logger;
31 import org.slf4j.LoggerFactory;
34 * @author Tuukka Lehtonen
37 public class BaselineCreatorApplication implements IApplication {
39 private static final Logger LOGGER = LoggerFactory.getLogger(BaselineCreatorApplication.class);
41 private static final IArgumentFactory<String> OUTPUT = new StringArgumentFactory("-o");
42 private static final IArgumentFactory<Boolean> VERBOSE = new NoValueArgumentFactory("-v");
45 * The -f argument specifies an SCL function that shall be executed after the
46 * platform has been started and before the platform is shutdown.
49 * The function must be:
51 * <li>a parameterless function</li>
52 * <li>a function with <code><Proc></code> effect only</li>. It must internally invoke
53 * <code>syncWrite</code> etc. to have other effects.
57 * This means the function must have the following signature:
58 * <code>func :: <Proc> ()</code>
60 private static final IArgumentFactory<String> FUNCTION = new StringArgumentFactory("-f");
62 IArgumentFactory<?>[] accepted = {
63 SimanticsArguments.RECOVERY_POLICY_FIX_ERRORS,
64 SimanticsArguments.ONTOLOGY_RECOVERY_POLICY_REINSTALL,
65 SimanticsArguments.DISABLE_INDEX,
66 SimanticsArguments.DATABASE_ID,
72 private static String currentLocalDateTimeStamp() {
73 return LocalDateTime.now().format(DateTimeFormatter.ofPattern("yyyy-MM-dd_HHmm"));
76 private static Path constructOutputPath(Path workspace, IArguments parsedArgs) {
77 if (parsedArgs.contains(OUTPUT)) {
78 return workspace.resolve(parsedArgs.get(OUTPUT));
80 return workspace.resolve(workspace.getFileName().toString() + "-" + currentLocalDateTimeStamp() + ".zip");
84 private static Path getInstanceLocation() throws CoreException, IOException {
85 Location l = Platform.getInstanceLocation();
86 if (l == null || l.isReadOnly())
87 throw new CoreException(new Status(IStatus.ERROR, Activator.PLUGIN_ID,
88 "Workspace not defined. Use -data <path> argument to define where to place the baselining workspace."));
90 URL workspaceUrl = l.getURL();
91 Path workspacePath = new File(workspaceUrl.getPath()).toPath();
92 Files.createDirectories(workspacePath);
97 public Object start(IApplicationContext context) throws Exception {
99 Path workspace = getInstanceLocation();
101 String[] args = (String[]) context.getArguments().get("application.args");
102 IArguments parsedArgs = Arguments.parse(args, accepted);
104 Path output = constructOutputPath(workspace, parsedArgs);
105 LOGGER.info("Selected output file: {} ", output);
107 // Create database and indexes
108 IProgressMonitor progress = parsedArgs.contains(VERBOSE)
109 ? new TimingProgressMonitor()
110 : new NullProgressMonitor();
111 Simantics.startUpHeadless(parsedArgs, progress);
113 if (parsedArgs.contains(FUNCTION)) {
114 String func = parsedArgs.get(FUNCTION);
115 String[] moduleAndFunc = splitFunction(func);
116 if (moduleAndFunc != null) {
118 LOGGER.info("Invoking SCL function {}/{}", moduleAndFunc[0], moduleAndFunc[1]);
119 SCLContext.getCurrent().put(SCLReportingHandler.REPORTING_HANDLER, SCLReportingHandler.DEFAULT);
120 Simantics.applySCL(moduleAndFunc[0], moduleAndFunc[1], Tuple0.INSTANCE);
121 } catch (Throwable t) {
122 LOGGER.error("Invocation failed", t);
125 LOGGER.error("SCL function '{}' not invocable for baselining the database", func);
129 Simantics.shutdown(progress);
131 // Create the baseline package file
132 Path actualOutput = DatabaseBaselines.packageBaseline(workspace, output);
133 System.out.println("OK " + actualOutput.normalize().toAbsolutePath());
135 return IApplication.EXIT_OK;
136 } catch (Exception e) {
137 LOGGER.error("Baseline creation failed.", e);
144 private String[] splitFunction(String func) {
145 int l = func.lastIndexOf('/');
148 return new String[] { func.substring(0, l), func.substring(l+1) };