From 4d0a556446e746f54e383c622e3ac561d70ccee2 Mon Sep 17 00:00:00 2001 From: Jonah Graham Date: Thu, 13 Oct 2016 17:14:28 +0100 Subject: [PATCH] Bug 505868: Split clean command when cleaning lots of files This change overcomes the Cannot run program "rm": Command line too long error when there are hundreds to thousands of files. This change only applies to the interal builder. Change-Id: Idc32067e27d76e3b438b2b1a07376859c7c8d1e4 --- .../testCleanProjects/testCleanExternal.zip | Bin 0 -> 3788 bytes .../testCleanProjects/testCleanInternal.zip | Bin 0 -> 3911 bytes .../testplugin/AbstractBuilderTest.java | 52 ++++-- .../core/tests/ManagedBuildClean.java | 82 ++++++++++ .../internal/buildmodel/BuildStep.java | 151 +++++++++++++----- 5 files changed, 234 insertions(+), 51 deletions(-) create mode 100644 build/org.eclipse.cdt.managedbuilder.core.tests/resources/testCleanProjects/testCleanExternal.zip create mode 100644 build/org.eclipse.cdt.managedbuilder.core.tests/resources/testCleanProjects/testCleanInternal.zip create mode 100644 build/org.eclipse.cdt.managedbuilder.core.tests/tests/org/eclipse/cdt/managedbuilder/core/tests/ManagedBuildClean.java diff --git a/build/org.eclipse.cdt.managedbuilder.core.tests/resources/testCleanProjects/testCleanExternal.zip b/build/org.eclipse.cdt.managedbuilder.core.tests/resources/testCleanProjects/testCleanExternal.zip new file mode 100644 index 0000000000000000000000000000000000000000..cac1abc2ae2bd192aef7edb66050072358e9cc70 GIT binary patch literal 3788 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 getProjectBuildExeResources(String projectName, String cfgName, String obj) throws CoreException { - return getProjectBuildExeResources(projectName, cfgName, new String[]{obj}); + return getProjectBuildExeResources(projectName, cfgName, obj, true); + } + + /** + * The externalBuilder is true for when makefiles are generated, or false for internal builder + */ + protected Collection getProjectBuildExeResources(String projectName, String cfgName, String obj, boolean externalBuilder) throws CoreException { + return getProjectBuildExeResources(projectName, cfgName, new String[]{obj}, externalBuilder); } protected Collection getProjectBuildLibResources(String projectName, String cfgName, String obj) throws CoreException { @@ -137,11 +145,22 @@ public abstract class AbstractBuilderTest extends TestCase { return getProjectBuildSharedLibResources(projectName, cfgName, new String[]{obj}); } - protected Collection getProjectBuildExeResources(String projectName, String cfgName, String[] objs) throws CoreException { - Collection resources = getProjectBuildResources(projectName, cfgName, objs); + protected IFile getProjectExe(String projectName, String cfgName) throws CoreException { IProject project = getWorkspace().getRoot().getProject(projectName); IFolder buildDir = project.getFolder(cfgName); - resources.add(buildDir.getFile(projectName + (WINDOWS ? ".exe" : ""))); + return buildDir.getFile(projectName + (WINDOWS ? ".exe" : "")); + } + + protected Collection getProjectBuildExeResources(String projectName, String cfgName, String[] objs) throws CoreException { + return getProjectBuildExeResources(projectName, cfgName, objs, true); + } + + /** + * The externalBuilder is true for when makefiles are generated, or false for internal builder + */ + protected Collection getProjectBuildExeResources(String projectName, String cfgName, String[] objs, boolean externalBuilder) throws CoreException { + Collection resources = getProjectBuildResources(projectName, cfgName, objs, externalBuilder); + resources.add(getProjectExe(projectName, cfgName)); return resources; } @@ -166,18 +185,33 @@ public abstract class AbstractBuilderTest extends TestCase { * The object files expected to be output can also be specified. */ protected Collection getProjectBuildResources(String projectName, String cfgName, String[] objs) throws CoreException { + return getProjectBuildResources(projectName, cfgName, objs, true); + } + + /** + * Returns an array of resources expected to be generated by building a project configuration. + * The object files expected to be output can also be specified. + * The externalBuilder is true for when makefiles are generated, or false for internal builder + */ + protected Collection getProjectBuildResources(String projectName, String cfgName, String[] objs, boolean externalBuilder) throws CoreException { IProject project = getWorkspace().getRoot().getProject(projectName); IFolder buildDir = project.getFolder(cfgName); Collection resources = new LinkedHashSet(); resources.add(buildDir); - resources.add(buildDir.getFile("makefile")); - resources.add(buildDir.getFile("objects.mk")); - resources.add(buildDir.getFile("sources.mk")); + if (externalBuilder) { + resources.add(buildDir.getFile("makefile")); + resources.add(buildDir.getFile("objects.mk")); + resources.add(buildDir.getFile("sources.mk")); + } for (String obj : objs) { - resources.add(buildDir.getFile(obj + ".d")); + if (externalBuilder) { + resources.add(buildDir.getFile(obj + ".d")); + } resources.add(buildDir.getFile(obj + ".o")); // Add subdir.mk in the same directory - resources.add(buildDir.getFile(new Path(obj).removeLastSegments(1).append("subdir.mk"))); + if (externalBuilder) { + resources.add(buildDir.getFile(new Path(obj).removeLastSegments(1).append("subdir.mk"))); + } // If the parent of the obj doesn't exist, then ensure we're expecting that too... IPath p = new Path(obj).removeLastSegments(1); while (p.segmentCount() > 0) { diff --git a/build/org.eclipse.cdt.managedbuilder.core.tests/tests/org/eclipse/cdt/managedbuilder/core/tests/ManagedBuildClean.java b/build/org.eclipse.cdt.managedbuilder.core.tests/tests/org/eclipse/cdt/managedbuilder/core/tests/ManagedBuildClean.java new file mode 100644 index 00000000000..197aa1bb610 --- /dev/null +++ b/build/org.eclipse.cdt.managedbuilder.core.tests/tests/org/eclipse/cdt/managedbuilder/core/tests/ManagedBuildClean.java @@ -0,0 +1,82 @@ +/******************************************************************************* + * Copyright (c) 20116 Kichwa Coders Ltd and others. + * 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 + * + * Contributors: + * Jonah Graham (Kichwa Coders) - Initial API and implementation + *******************************************************************************/ +package org.eclipse.cdt.managedbuilder.core.tests; + +import java.util.Collection; + +import org.eclipse.cdt.managedbuilder.testplugin.AbstractBuilderTest; +import org.eclipse.cdt.managedbuilder.testplugin.ManagedBuildTestHelper; +import org.eclipse.core.resources.IFile; +import org.eclipse.core.resources.IProject; +import org.eclipse.core.resources.IResource; +import org.eclipse.core.resources.IWorkspaceDescription; +import org.eclipse.core.resources.IncrementalProjectBuilder; +import org.eclipse.core.resources.ResourcesPlugin; +import org.eclipse.core.runtime.CoreException; + +public class ManagedBuildClean extends AbstractBuilderTest { + private static final String PROJ_PATH = "testCleanProjects"; + private IProject fInternalBuilderProject; + private IProject fExternalBuilderProject; + + @Override + protected void setUp() throws Exception { + super.setUp(); + IWorkspaceDescription wsDescription = ResourcesPlugin.getWorkspace().getDescription(); + wsDescription.setAutoBuilding(false); + ResourcesPlugin.getWorkspace().setDescription(wsDescription); + assertNotNull("Cannot create testCleanInternal project", + fInternalBuilderProject = ManagedBuildTestHelper.loadProject("testCleanInternal", PROJ_PATH)); + assertNotNull("Cannot create testCleanExternal project", + fExternalBuilderProject = ManagedBuildTestHelper.loadProject("testCleanExternal", PROJ_PATH)); + } + + @Override + protected void tearDown() throws Exception { + super.tearDown(); + ManagedBuildTestHelper.removeProject(fInternalBuilderProject.getName()); + } + + public void testCleanInternal() throws Exception { + helperTestClean(fInternalBuilderProject, false); + } + + public void testCleanExternal() throws Exception { + helperTestClean(fExternalBuilderProject, true); + } + + private void helperTestClean(IProject project, boolean externalBuilder) throws CoreException { + + // do a build and ensure files are present + project.build(IncrementalProjectBuilder.FULL_BUILD, null); + Collection resources = getProjectBuildExeResources(project.getName(), "Debug", + "src/" + project.getName(), externalBuilder); + for (IResource resource : resources) { + assertTrue("Resource not found: " + resource, resource.exists()); + } + + // do a clean and make sure files are gone + project.build(IncrementalProjectBuilder.CLEAN_BUILD, null); + for (IResource resource : resources) { + if (!(resource instanceof IFile)) { + // Only files are removed by clean, not folders + continue; + } + if (externalBuilder + && (resource.getName().endsWith(".mk") || resource.getName().equals("makefile"))) { + // makefiles are not removed when cleaning + continue; + } + assertFalse("Resource not deleted: " + resource, resource.exists()); + } + } + +} diff --git a/build/org.eclipse.cdt.managedbuilder.core/src/org/eclipse/cdt/managedbuilder/internal/buildmodel/BuildStep.java b/build/org.eclipse.cdt.managedbuilder.core/src/org/eclipse/cdt/managedbuilder/internal/buildmodel/BuildStep.java index 97ae9bc937c..46d87270464 100644 --- a/build/org.eclipse.cdt.managedbuilder.core/src/org/eclipse/cdt/managedbuilder/internal/buildmodel/BuildStep.java +++ b/build/org.eclipse.cdt.managedbuilder.core/src/org/eclipse/cdt/managedbuilder/internal/buildmodel/BuildStep.java @@ -46,6 +46,21 @@ import org.eclipse.core.runtime.IPath; import org.eclipse.core.runtime.Path; public class BuildStep implements IBuildStep { + /** + * When an argument of a command is joined into a String for preparation for running with exec, the + * argument may need surrounding with quotes and have spaces between each argument. This padding allows + * for that when constructing long commands. + */ + private static final int PER_ARGUMENT_PADDING = 3; + /** + * On Windows XP and above, the maximum command line length is 8191, on Linux it is at least 131072, but + * that includes the environment. We want to limit the invocation of a single command to this number of + * characters, and we want to ensure that the number isn't so low as to slow down operation. + * + * Doing each rm in its own command would be very slow, especially on Windows. + */ + private static final int MAX_CLEAN_LENGTH = 6000; + private List fInputTypes = new ArrayList(); private List fOutputTypes = new ArrayList(); private ITool fTool; @@ -230,47 +245,81 @@ public class BuildStep implements IBuildStep { cwd = calcCWD(); if (fTool == null) { - String step = null; - String appendToLastStep = null; - if (this == fBuildDescription.getInputStep()) { - step = fBuildDescription.getConfiguration().getPrebuildStep(); - } else if (this == fBuildDescription.getOutputStep()) { - step = fBuildDescription.getConfiguration().getPostbuildStep(); - } else if (this == fBuildDescription.getCleanStep()) { - step = fBuildDescription.getConfiguration().getCleanCommand(); - - IBuildResource[] generated = fBuildDescription.getResources(true); - - if (generated.length != 0) { - StringBuilder buf = new StringBuilder(); - for (int i = 0; i < generated.length; i++) { - buf.append(' '); - - IPath rel = BuildDescriptionManager.getRelPath(cwd, generated[i].getLocation()); - buf.append(rel.toString()); - } - appendToLastStep = buf.toString(); - } - } - - if (step != null && (step = step.trim()).length() > 0) { - step = resolveMacros(step, resolveAll); - if (step != null && (step = step.trim()).length() > 0) { - String commands[] = step.split(";"); //$NON-NLS-1$ - - if (appendToLastStep != null && commands.length != 0) { - commands[commands.length - 1] = commands[commands.length - 1] + appendToLastStep; - } + if (this == fBuildDescription.getCleanStep()) { + String cleanCmd = fBuildDescription.getConfiguration().getCleanCommand(); + if (cleanCmd != null && (cleanCmd = cleanCmd.trim()).length() > 0) { List list = new ArrayList(); - for (int i = 0; i < commands.length; i++) { - IBuildCommand cmds[] = createCommandsFromString(commands[i], cwd, getEnvironment()); - for (int j = 0; j < cmds.length; j++) { - list.add(cmds[j]); - } + cleanCmd = resolveMacros(cleanCmd, resolveAll); + String commands[] = cleanCmd.split(";"); //$NON-NLS-1$ + for (int i = 0; i < commands.length - 1; i++) { + list.add(createCommandFromString(commands[0], cwd, getEnvironment())); } + + List cleanCmdArgs = convertStringToArguments(commands[commands.length - 1]); + final int initialLen = cleanCmdArgs.stream() + .mapToInt(w -> w.length() + PER_ARGUMENT_PADDING).sum(); + IPath cleanCmdPath = new Path(cleanCmdArgs.get(0)); + Map env = getEnvironment(); + + IBuildResource[] resources = fBuildDescription.getResources(true); + + List args = new ArrayList<>(); + args.addAll(cleanCmdArgs.subList(1, cleanCmdArgs.size())); + int totalLen = initialLen; + for (IBuildResource resource : resources) { + IPath resLoc = BuildDescriptionManager.getRelPath(cwd, resource.getLocation()); + String path = resLoc.toString(); + int pathLen = path.length() + PER_ARGUMENT_PADDING; + + if (totalLen + pathLen > MAX_CLEAN_LENGTH && totalLen != initialLen) { + // adding new path takes us over limit, emit what we have... + BuildCommand buildCommand = new BuildCommand(cleanCmdPath, + args.toArray(new String[args.size()]), env, cwd, this); + list.add(buildCommand); + + // ...and restart + totalLen = initialLen; + args.clear(); + args.addAll(cleanCmdArgs.subList(1, cleanCmdArgs.size())); + } + + args.add(path); + totalLen += pathLen; + } + + // add remaining files + BuildCommand buildCommand = new BuildCommand(cleanCmdPath, + args.toArray(new String[args.size()]), env, cwd, this); + list.add(buildCommand); + return list.toArray(new BuildCommand[list.size()]); } + + } else { + String step = null; + if (this == fBuildDescription.getInputStep()) { + step = fBuildDescription.getConfiguration().getPrebuildStep(); + } else if (this == fBuildDescription.getOutputStep()) { + step = fBuildDescription.getConfiguration().getPostbuildStep(); + } + + if (step != null && (step = step.trim()).length() > 0) { + step = resolveMacros(step, resolveAll); + if (step != null && (step = step.trim()).length() > 0) { + String commands[] = step.split(";"); //$NON-NLS-1$ + + List list = new ArrayList(); + for (int i = 0; i < commands.length; i++) { + IBuildCommand cmds[] = createCommandsFromString(commands[i], cwd, + getEnvironment()); + for (int j = 0; j < cmds.length; j++) { + list.add(cmds[j]); + } + } + return list.toArray(new BuildCommand[list.size()]); + } + } } return new IBuildCommand[0]; } @@ -354,7 +403,29 @@ public class BuildStep implements IBuildStep { } protected IBuildCommand[] createCommandsFromString(String cmd, IPath cwd, Map env) { - char arr[] = cmd.toCharArray(); + IBuildCommand buildCommand = createCommandFromString(cmd, cwd, env); + return new IBuildCommand[] { buildCommand }; + } + + protected IBuildCommand createCommandFromString(String cmd, IPath cwd, Map env) { + List list = convertStringToArguments(cmd); + + IPath c = new Path(list.remove(0)); + String[] args = list.toArray(new String[list.size()]); + + BuildCommand buildCommand = new BuildCommand(c, args, env, cwd, this); + return buildCommand; + } + + /** + * Convert string to arguments, first argument is command + * + * @param commandLine + * to parse + * @return arguments as a list + */ + protected List convertStringToArguments(String commandLine) { + char arr[] = commandLine.toCharArray(); char expect = 0; char prev = 0; // int start = 0; @@ -400,11 +471,7 @@ public class BuildStep implements IBuildStep { if (buf.length() > 0) list.add(buf.toString()); - - IPath c = new Path(list.remove(0)); - String[] args = list.toArray(new String[list.size()]); - - return new IBuildCommand[] { new BuildCommand(c, args, env, cwd, this) }; + return list; } private BuildResource[] getPrimaryResources(boolean input) {