Fixes #724
Record information in eclipse metadata for docker images build by IDE. Just enough info is recored for a IDE built-image so we can avoid parsing image metadata from the image itself (the image metadata format is unstable and we do not have a usable api to get at it easily, so trying to rely on it is fraught with problems).
This commit is contained in:
@@ -53,6 +53,7 @@ import org.springframework.ide.eclipse.boot.dash.docker.exceptions.MissingBuildS
|
||||
import org.springframework.ide.eclipse.boot.dash.docker.exceptions.MissingBuildTagException;
|
||||
import org.springframework.ide.eclipse.boot.dash.docker.jmx.JmxSupport;
|
||||
import org.springframework.ide.eclipse.boot.dash.docker.runtarget.BuildScriptLocator.BuildKind;
|
||||
import org.springframework.ide.eclipse.boot.dash.docker.runtarget.DockerApp.BuildCommand;
|
||||
import org.springframework.ide.eclipse.boot.dash.labels.BootDashLabels;
|
||||
import org.springframework.ide.eclipse.boot.dash.model.RunState;
|
||||
import org.springframework.ide.eclipse.boot.dash.model.remote.ChildBearing;
|
||||
@@ -61,6 +62,7 @@ import org.springframework.ide.eclipse.boot.dash.util.LineBasedStreamGobler;
|
||||
import org.springframework.ide.eclipse.boot.launch.util.PortFinder;
|
||||
import org.springframework.ide.eclipse.boot.util.JavaProjectUtil;
|
||||
import org.springsource.ide.eclipse.commons.core.pstore.PropertyStoreApi;
|
||||
import org.springsource.ide.eclipse.commons.core.pstore.PropertyStores;
|
||||
import org.springsource.ide.eclipse.commons.frameworks.core.util.JobUtil;
|
||||
import org.springsource.ide.eclipse.commons.frameworks.core.util.StringUtils;
|
||||
import org.springsource.ide.eclipse.commons.livexp.core.AbstractDisposable;
|
||||
@@ -87,7 +89,19 @@ import com.google.common.collect.ImmutableList.Builder;
|
||||
import com.google.common.collect.ImmutableMap;
|
||||
import com.google.common.collect.ImmutableSet;
|
||||
|
||||
public class DockerApp extends AbstractDisposable implements App, ChildBearing, Deletable, ProjectRelatable, DesiredInstanceCount, SystemPropertySupport, LogSource, DevtoolsConnectable {
|
||||
public class DockerApp extends AbstractDisposable implements App, ChildBearing, Deletable, ProjectRelatable, DesiredInstanceCount,
|
||||
SystemPropertySupport, LogSource, DevtoolsConnectable {
|
||||
|
||||
public class BuildCommand {
|
||||
String[] command;
|
||||
boolean builtWithDevToolsArgs;
|
||||
public BuildCommand(String[] command, boolean builtWithDevToolsArgs) {
|
||||
super();
|
||||
this.command = command;
|
||||
this.builtWithDevToolsArgs = builtWithDevToolsArgs;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
private static final String DOCKER_IO_LIBRARY = "docker.io/library/";
|
||||
private static final String[] NO_STRINGS = new String[0];
|
||||
@@ -389,14 +403,14 @@ Successfully tagged fui:latest
|
||||
private String build(AppConsole console) throws Exception {
|
||||
String[] imageIds = new String[BUILT_IMAGE_MESSAGE_PATS.length];
|
||||
File directory = new File(project.getLocation().toString());
|
||||
String[] command = getBuildCommand(directory);
|
||||
BuildCommand command = getBuildCommand(directory);
|
||||
|
||||
ProcessBuilder builder = new ProcessBuilder(command).directory(directory);
|
||||
ProcessBuilder builder = new ProcessBuilder(command.command).directory(directory);
|
||||
String jhome = getJavaHome();
|
||||
builder.environment().put("JAVA_HOME", jhome);
|
||||
console.write("build.env.JAVA_HOME="+jhome, LogType.STDOUT);
|
||||
console.write("build.directory="+directory, LogType.STDOUT);
|
||||
console.logCommand(CommandUtil.escape(command));
|
||||
console.logCommand(CommandUtil.escape(command.command));
|
||||
Process process = builder.start();
|
||||
LineBasedStreamGobler outputGobler = new LineBasedStreamGobler(process.getInputStream(), (line) -> {
|
||||
System.out.println(line);
|
||||
@@ -447,10 +461,10 @@ Successfully tagged fui:latest
|
||||
if (images.isEmpty()) {
|
||||
// maybe the 'imageTag' is not actually a tag but an id/hash.
|
||||
InspectImageResponse inspect = client.inspectImageCmd(imageTag).exec();
|
||||
addPersistedImage(inspect.getId());
|
||||
addPersistedImage(inspect.getId(), command);
|
||||
} else {
|
||||
for (Image img : images) {
|
||||
addPersistedImage(img.getId());
|
||||
addPersistedImage(img.getId(), command);
|
||||
}
|
||||
}
|
||||
return imageTag;
|
||||
@@ -461,19 +475,22 @@ Successfully tagged fui:latest
|
||||
return jvm.getInstallLocation().toString();
|
||||
}
|
||||
|
||||
private String[] getBuildCommand(File directory) throws MissingBuildScriptException {
|
||||
private BuildCommand getBuildCommand(File directory) throws MissingBuildScriptException {
|
||||
BuildScriptLocator buildScriptLocator = new BuildScriptLocator(directory);
|
||||
BuildKind buildKind = buildScriptLocator.getBuildKind();
|
||||
if (buildKind==null) {
|
||||
throw new MissingBuildScriptException(buildScriptLocator.checkedLocations);
|
||||
}
|
||||
boolean wantsDevtools = deployment().getSystemProperties().getOrDefault(DevtoolsUtil.REMOTE_SECRET_PROP, null)!=null;
|
||||
boolean withDevtoolsArgs = false;
|
||||
List<String> command = buildScriptLocator.command;
|
||||
if (wantsDevtools) {
|
||||
if (buildKind==BuildKind.MAVEN) {
|
||||
withDevtoolsArgs = true;
|
||||
command.add("-Dspring-boot.repackage.excludeDevtools=false");
|
||||
} else if (buildKind==BuildKind.GRADLE) {
|
||||
try {
|
||||
withDevtoolsArgs = true;
|
||||
command.addAll(gradle_initScript(
|
||||
"allprojects {\n" +
|
||||
" afterEvaluate {\n" +
|
||||
@@ -488,7 +505,7 @@ Successfully tagged fui:latest
|
||||
}
|
||||
}
|
||||
}
|
||||
return command.toArray(new String[command.size()]);
|
||||
return new BuildCommand(command.toArray(new String[command.size()]), withDevtoolsArgs);
|
||||
}
|
||||
|
||||
private synchronized static List<String> gradle_initScript(String script) throws IOException {
|
||||
@@ -503,7 +520,7 @@ Successfully tagged fui:latest
|
||||
);
|
||||
}
|
||||
|
||||
synchronized private void addPersistedImage(String imageId) {
|
||||
synchronized private void addPersistedImage(String imageId, BuildCommand command) {
|
||||
String key = imagesKey();
|
||||
try {
|
||||
ImmutableSet.Builder<String> builder = ImmutableSet.builder();
|
||||
@@ -511,12 +528,12 @@ Successfully tagged fui:latest
|
||||
builder.addAll(Arrays.asList(props.get(key, NO_STRINGS)));
|
||||
builder.add(imageId);
|
||||
props.put(key, builder.build().toArray(NO_STRINGS));
|
||||
|
||||
props.put(DockerImage.hasDevtoolsKey(imageId), context.projectHasDevtoolsDependency() && command.builtWithDevToolsArgs);
|
||||
} catch (Exception e) {
|
||||
Log.log(e);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
private void setPersistedImages(Set<String> existingImages) {
|
||||
try {
|
||||
getTarget().getPersistentProperties().put(imagesKey(), existingImages.toArray(NO_STRINGS));
|
||||
|
||||
@@ -25,7 +25,6 @@ import java.util.Set;
|
||||
import java.util.concurrent.CompletableFuture;
|
||||
import java.util.concurrent.atomic.AtomicBoolean;
|
||||
import java.util.concurrent.atomic.AtomicInteger;
|
||||
import java.util.stream.Collectors;
|
||||
|
||||
import org.eclipse.core.resources.IProject;
|
||||
import org.eclipse.core.resources.ResourcesPlugin;
|
||||
@@ -54,8 +53,6 @@ import org.springframework.ide.eclipse.boot.dash.docker.util.Ownable;
|
||||
import org.springframework.ide.eclipse.boot.dash.model.RunState;
|
||||
import org.springframework.ide.eclipse.boot.dash.model.remote.RefreshStateTracker;
|
||||
import org.springframework.ide.eclipse.boot.util.RetryUtil;
|
||||
import org.springframework.ide.eclipse.editor.support.yaml.path.JavaObjectNav;
|
||||
import org.springframework.ide.eclipse.editor.support.yaml.path.YamlNavigable;
|
||||
import org.springframework.ide.eclipse.editor.support.yaml.path.YamlPath;
|
||||
import org.springframework.ide.eclipse.editor.support.yaml.path.YamlTraversal;
|
||||
import org.springsource.ide.eclipse.commons.core.util.StringUtil;
|
||||
@@ -72,8 +69,6 @@ import com.github.dockerjava.api.exception.NotFoundException;
|
||||
import com.github.dockerjava.api.model.Container;
|
||||
import com.github.dockerjava.api.model.Frame;
|
||||
import com.github.dockerjava.api.model.StreamType;
|
||||
import com.google.common.base.Supplier;
|
||||
import com.google.common.base.Suppliers;
|
||||
import com.google.common.collect.ImmutableMap;
|
||||
import com.google.common.collect.ImmutableSet;
|
||||
|
||||
@@ -89,33 +84,12 @@ public class DockerContainer implements App, RunStateProvider, JmxConnectable, S
|
||||
|
||||
private static Map<RunState, ImageDescriptor> RUNSTATE_ICONS = null;
|
||||
private DockerApp app;
|
||||
private AppContext context;
|
||||
|
||||
public DockerContainer(DockerRunTarget target, DockerApp app, Container container) {
|
||||
this.target = target;
|
||||
this.app = app;
|
||||
this.container = container;
|
||||
this.hasDevtoolsDep = hasDevtoolsDependency(container::getLabels);
|
||||
}
|
||||
|
||||
public static Supplier<Boolean> hasDevtoolsDependency(Supplier<Map<String,String>> labelsSupplier) {
|
||||
return Suppliers.memoize(() ->{
|
||||
Map<String, String> labels = labelsSupplier.get();
|
||||
try {
|
||||
if (labels!=null) {
|
||||
String buildpackMetadata = labels.get("io.buildpacks.build.metadata");
|
||||
if (buildpackMetadata!=null) {
|
||||
Map<?,?> bpmd = new ObjectMapper().readValue(buildpackMetadata, Map.class);
|
||||
Set<String> deps = dependencyNamePath
|
||||
.traverseAmbiguously(YamlNavigable.javaObject(bpmd))
|
||||
.flatMap(JavaObjectNav::asStringMaybe).collect(Collectors.toSet());
|
||||
return deps.contains("spring-boot-devtools");
|
||||
}
|
||||
}
|
||||
} catch (Exception e) {
|
||||
Log.log(e);
|
||||
}
|
||||
return false;
|
||||
});
|
||||
}
|
||||
|
||||
@Override
|
||||
@@ -285,6 +259,7 @@ public class DockerContainer implements App, RunStateProvider, JmxConnectable, S
|
||||
@Override
|
||||
public void setContext(AppContext context) {
|
||||
this.refreshTracker.complete(context.getRefreshTracker());
|
||||
this.context = context;
|
||||
}
|
||||
|
||||
@Override
|
||||
@@ -362,12 +337,16 @@ public class DockerContainer implements App, RunStateProvider, JmxConnectable, S
|
||||
.thenValAt("name");
|
||||
|
||||
private static final boolean USE_DEDICATED_CLIENT = false;
|
||||
|
||||
private Supplier<Boolean> hasDevtoolsDep;
|
||||
|
||||
|
||||
|
||||
@Override
|
||||
public boolean hasDevtoolsDependency() {
|
||||
return this.hasDevtoolsDep.get();
|
||||
if (context!=null) {
|
||||
DockerImage image = context.getParent(DockerImage.class);
|
||||
return image.hasDevtoolsDependency();
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
// for debugging... keep in comments for now
|
||||
|
||||
@@ -38,6 +38,7 @@ import org.springframework.ide.eclipse.boot.dash.model.RunState;
|
||||
import org.springframework.ide.eclipse.boot.dash.model.remote.ChildBearing;
|
||||
import org.springframework.ide.eclipse.boot.dash.model.remote.RefreshStateTracker;
|
||||
import org.springframework.ide.eclipse.boot.util.RetryUtil;
|
||||
import org.springsource.ide.eclipse.commons.core.pstore.PropertyStoreApi;
|
||||
import org.springsource.ide.eclipse.commons.core.util.StringUtil;
|
||||
import org.springsource.ide.eclipse.commons.frameworks.core.util.JobUtil;
|
||||
import org.springsource.ide.eclipse.commons.livexp.ui.Stylers;
|
||||
@@ -47,7 +48,6 @@ import com.github.dockerjava.api.DockerClient;
|
||||
import com.github.dockerjava.api.exception.NotFoundException;
|
||||
import com.github.dockerjava.api.model.Container;
|
||||
import com.github.dockerjava.api.model.Image;
|
||||
import com.google.common.base.Supplier;
|
||||
import com.google.common.collect.ImmutableList;
|
||||
import com.google.common.collect.ImmutableList.Builder;
|
||||
import com.google.common.collect.ImmutableMap;
|
||||
@@ -59,14 +59,12 @@ public class DockerImage implements App, ChildBearing, Styleable, ProjectRelatab
|
||||
private final DockerApp app;
|
||||
private final Image image;
|
||||
public final CompletableFuture<RefreshStateTracker> refreshTracker = new CompletableFuture<>();
|
||||
private final Supplier<Boolean> hasDevtoolsDependency;
|
||||
|
||||
private static Map<RunState, ImageDescriptor> RUNSTATE_ICONS = null;
|
||||
|
||||
public DockerImage(DockerApp app, Image image) {
|
||||
this.app = app;
|
||||
this.image = image;
|
||||
this.hasDevtoolsDependency = DockerContainer.hasDevtoolsDependency(image::getLabels);
|
||||
}
|
||||
|
||||
@Override
|
||||
@@ -249,11 +247,16 @@ public class DockerImage implements App, ChildBearing, Styleable, ProjectRelatab
|
||||
|
||||
@Override
|
||||
public boolean hasDevtoolsDependency() {
|
||||
return this.hasDevtoolsDependency.get();
|
||||
PropertyStoreApi props = getTarget().getPersistentProperties();
|
||||
return props.get(hasDevtoolsKey(image.getId()), false);
|
||||
}
|
||||
|
||||
@Override
|
||||
public TemporalBoolean isDevtoolsConnectable() {
|
||||
return TemporalBoolean.NEVER;
|
||||
}
|
||||
|
||||
public static String hasDevtoolsKey(String imageId) {
|
||||
return imageId +".hasDevtoolsDependency";
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user