/*******************************************************************************
* This file is protected by Copyright.
* Please refer to the COPYRIGHT file distributed with this source distribution.
*
* This file is part of REDHAWK IDE.
*
* 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 gov.redhawk.ide.codegen.builders;
import gov.redhawk.ide.codegen.jet.TopLevelDcdRpmSpecTemplate;
import gov.redhawk.ide.codegen.jet.TopLevelSadRpmSpecTemplate;
import gov.redhawk.ide.natures.ScaNodeProjectNature;
import gov.redhawk.ide.natures.ScaWaveformProjectNature;
import gov.redhawk.model.sca.util.ModelUtil;
import java.io.ByteArrayInputStream;
import java.util.Map;
import mil.jpeojtrs.sca.dcd.DcdPackage;
import mil.jpeojtrs.sca.dcd.DeviceConfiguration;
import mil.jpeojtrs.sca.sad.SadPackage;
import mil.jpeojtrs.sca.sad.SoftwareAssembly;
import org.eclipse.core.resources.IContainer;
import org.eclipse.core.resources.IFile;
import org.eclipse.core.resources.IProject;
import org.eclipse.core.resources.IResource;
import org.eclipse.core.resources.IResourceDelta;
import org.eclipse.core.resources.IResourceDeltaVisitor;
import org.eclipse.core.resources.IncrementalProjectBuilder;
import org.eclipse.core.runtime.CoreException;
import org.eclipse.core.runtime.IProgressMonitor;
import org.eclipse.core.runtime.SubMonitor;
import org.eclipse.emf.common.util.URI;
/**
* An incremental builder that adds a top-level RPM spec file to waveforms and nodes.
*/
public class TopLevelRPMSpec extends IncrementalProjectBuilder {
/**
* The ID of the top level build script builder.
*/
public static final String ID = "gov.redhawk.ide.codegen.builders.TopLevelRPMSpec";
/**
* A flag used internally to determine if the top-level RPM spec file should be regenerated on auto/incremental
* builds.
*/
private boolean generateFlag;
public TopLevelRPMSpec() {
}
@Override
protected IProject[] build(final int kind, @SuppressWarnings("rawtypes") final Map args, final IProgressMonitor monitor) throws CoreException {
try {
final int SCAN_DELTA_WORK = 20;
final int GENERATE_SPEC_FILE_WORK = 80;
final SubMonitor progress = SubMonitor.convert(monitor, "Create top-level RPM spec file", SCAN_DELTA_WORK + GENERATE_SPEC_FILE_WORK);
final IProject project = getProject();
final boolean isWaveform = project.hasNature(ScaWaveformProjectNature.ID);
final boolean isNode = project.hasNature(ScaNodeProjectNature.ID);
if (!isWaveform && !isNode) {
return null;
}
// Determine if we need to generate
this.generateFlag = false;
if (kind == IncrementalProjectBuilder.FULL_BUILD || kind == IncrementalProjectBuilder.CLEAN_BUILD) {
// We always generate on a full build / clean build
this.generateFlag = true;
progress.setWorkRemaining(GENERATE_SPEC_FILE_WORK);
} else if (this.getDelta(project) != null) {
// Explore the delta to see if we need to generate
final IResourceDeltaVisitor visitor = new IResourceDeltaVisitor() {
@Override
public boolean visit(final IResourceDelta delta) throws CoreException {
// We can ignore anything that's in a sub-directory
if (delta.getResource() instanceof IContainer && delta.getProjectRelativePath().segmentCount() == 1) {
return false;
}
final String resourceName = delta.getResource().getName();
if (isNode && resourceName.endsWith(DcdPackage.FILE_EXTENSION)) {
// If this is a node and the DCD file was changed, generate
TopLevelRPMSpec.this.generateFlag = true;
return false;
} else if (isWaveform && resourceName.endsWith(SadPackage.FILE_EXTENSION)) {
// If this is a waveform and the SAD file was changed, generate
TopLevelRPMSpec.this.generateFlag = true;
return false;
}
return true;
}
};
getDelta(project).accept(visitor);
progress.worked(SCAN_DELTA_WORK);
}
if (this.generateFlag) {
if (isNode) {
generateDcdRpmSpecFile(progress.newChild(GENERATE_SPEC_FILE_WORK));
} else if (isWaveform) {
generateSadRpmSpecFile(progress.newChild(GENERATE_SPEC_FILE_WORK));
}
}
return null;
} finally {
if (monitor != null) {
monitor.done();
}
}
}
/**
* Generates a top-level RPM spec file based on the device manager/devices in the DCD file.
*
* @param monitor the progress monitor to use for reporting progress to the user. It is the caller's responsibility
* to call done() on the given monitor. Accepts null, indicating that no progress should be
* reported and that the operation cannot be canceled.
* @throws CoreException An error occurs while generating the RPM spec file
*/
private void generateDcdRpmSpecFile(final IProgressMonitor monitor) throws CoreException {
final SubMonitor progress = SubMonitor.convert(monitor, "Creating top-level RPM spec file", 1);
final IProject project = getProject();
for (final IResource resource : project.members()) {
if (resource.getName().endsWith(".dcd.xml")) {
// Load the DCD
final URI dcdURI = URI.createPlatformResourceURI(resource.getFullPath().toString(), false);
final DeviceConfiguration devCfg = ModelUtil.loadDeviceConfiguration(dcdURI);
// Generate content for the RPM spec file
final TopLevelDcdRpmSpecTemplate template = new TopLevelDcdRpmSpecTemplate();
final byte[] rpmSpecFileContent = template.generate(devCfg).getBytes();
// Write the file to disk
final IFile rpmSpecFile = getProject().getFile(devCfg.getName() + ".spec");
if (rpmSpecFile.exists()) {
rpmSpecFile.setContents(new ByteArrayInputStream(rpmSpecFileContent), true, false, progress.newChild(1));
} else {
rpmSpecFile.create(new ByteArrayInputStream(rpmSpecFileContent), true, progress.newChild(1));
}
return;
}
}
}
/**
* Generates a top-level RPM spec file based on the components and devices referenced in the SAD file.
*
* @param monitor the progress monitor to use for reporting progress to the user. It is the caller's responsibility
* to call done() on the given monitor. Accepts null, indicating that no progress should be
* reported and that the operation cannot be canceled.
* @throws CoreException An error occurs while generating the RPM spec file
*/
private void generateSadRpmSpecFile(final IProgressMonitor monitor) throws CoreException {
final SubMonitor progress = SubMonitor.convert(monitor, "Creating top-level RPM spec file", 1);
final IProject project = getProject();
for (final IResource resource : project.members()) {
if (resource.getName().endsWith(SadPackage.FILE_EXTENSION)) {
// Load the SAD
final URI sadURI = URI.createPlatformResourceURI(resource.getFullPath().toString(), false);
final SoftwareAssembly sad = ModelUtil.loadSoftwareAssembly(sadURI);
if (sad == null) {
return;
}
// Generate content for the RPM spec file
final TopLevelSadRpmSpecTemplate template = new TopLevelSadRpmSpecTemplate();
final String rpmSpecFileString = template.generate(sad);
final byte[] rpmSpecFileContent;
if (rpmSpecFileString == null) {
rpmSpecFileContent = null;
} else {
rpmSpecFileContent = rpmSpecFileString.getBytes();
}
// Write the file to disk
final IFile rpmSpecFile = getProject().getFile(sad.getName() + ".spec");
if (rpmSpecFileContent == null) {
if (rpmSpecFile.exists()) {
rpmSpecFile.delete(true, progress.newChild(1));
}
} else if (rpmSpecFile.exists()) {
rpmSpecFile.setContents(new ByteArrayInputStream(rpmSpecFileContent), true, false, progress.newChild(1));
} else {
rpmSpecFile.create(new ByteArrayInputStream(rpmSpecFileContent), true, progress.newChild(1));
}
return;
}
}
}
}