title: Gradle deployment fails with "java.io.IOException: The filename, directory name, or volume label syntax is incorrect"
body: <p>I'm onboarding new developers to our Java code, but I'm running into an error in Windows. Most Gradle commands work fine, but our deployment command (dpDeployAll) fails. I followed same setup process on 3 different Windows machines; two Win10 machines face this error, Win7 machine does not.</p>
  
  <p>Here is the stacktrace:</p>
  
  <pre><code>$ gradle dpDeployAll -Phost=10.2.9.106 --stacktrace
  :deploy:checkJavaVersion UP-TO-DATE
  :deploy:compileJava UP-TO-DATE
  :deploy:compileGroovy UP-TO-DATE
  :deploy:processResources UP-TO-DATE
  :deploy:classes UP-TO-DATE
  :deploy:dpDeployAll
  
  ChargeAdmin servlet version on 10.2.9.106 is 1.3.1
  
  Using profile all_production
  Exception in thread "main" java.io.IOException: The filename, directory name, or volume label syntax is incorrect
      at java.io.WinNTFileSystem.canonicalize0(Native Method)
      at java.io.Win32FileSystem.canonicalize(Win32FileSystem.java:414)
      at java.io.File.getCanonicalPath(File.java:618)
      at java_io_File$getCanonicalPath$0.call(Unknown Source)
      at org.codehaus.groovy.runtime.callsite.CallSiteArray.defaultCall(CallSiteArray.java:48)
      at org.codehaus.groovy.runtime.callsite.AbstractCallSite.call(AbstractCallSite.java:113)
      at org.codehaus.groovy.runtime.callsite.AbstractCallSite.call(AbstractCallSite.java:117)
      at deploy.Deploy$_runDeploy_closure7.doCall(Deploy.groovy:164)
      at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
      at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:57)
      at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
      at java.lang.reflect.Method.invoke(Method.java:606)
      at org.codehaus.groovy.reflection.CachedMethod.invoke(CachedMethod.java:93)
      at groovy.lang.MetaMethod.doMethodInvoke(MetaMethod.java:325)
      at org.codehaus.groovy.runtime.metaclass.ClosureMetaClass.invokeMethod(ClosureMetaClass.java:294)
      at groovy.lang.MetaClassImpl.invokeMethod(MetaClassImpl.java:1024)
      at groovy.lang.Closure.call(Closure.java:414)
      at groovy.lang.Closure.call(Closure.java:430)
      at org.codehaus.groovy.runtime.DefaultGroovyMethods.each(DefaultGroovyMethods.java:2030)
      at org.codehaus.groovy.runtime.DefaultGroovyMethods.each(DefaultGroovyMethods.java:2015)
      at org.codehaus.groovy.runtime.DefaultGroovyMethods.each(DefaultGroovyMethods.java:2056)
      at org.codehaus.groovy.runtime.dgm$162.invoke(Unknown Source)
      at org.codehaus.groovy.runtime.callsite.PojoMetaMethodSite$PojoMetaMethodSiteNoUnwrapNoCoerce.invoke(PojoMetaMethodSite.java:274)
      at org.codehaus.groovy.runtime.callsite.PojoMetaMethodSite.call(PojoMetaMethodSite.java:56)
      at org.codehaus.groovy.runtime.callsite.CallSiteArray.defaultCall(CallSiteArray.java:48)
      at org.codehaus.groovy.runtime.callsite.AbstractCallSite.call(AbstractCallSite.java:113)
      at org.codehaus.groovy.runtime.callsite.AbstractCallSite.call(AbstractCallSite.java:125)
      at deploy.Deploy.runDeploy(Deploy.groovy:161)
      at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
      at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:57)
      at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
      at java.lang.reflect.Method.invoke(Method.java:606)
      at org.codehaus.groovy.runtime.callsite.PogoMetaMethodSite$PogoCachedMethodSiteNoUnwrapNoCoerce.invoke(PogoMetaMethodSite.java:210)
      at org.codehaus.groovy.runtime.callsite.PogoMetaMethodSite.callCurrent(PogoMetaMethodSite.java:59)
      at org.codehaus.groovy.runtime.callsite.CallSiteArray.defaultCallCurrent(CallSiteArray.java:52)
      at org.codehaus.groovy.runtime.callsite.AbstractCallSite.callCurrent(AbstractCallSite.java:154)
      at org.codehaus.groovy.runtime.callsite.AbstractCallSite.callCurrent(AbstractCallSite.java:182)
      at deploy.Deploy.runDeployProfile(Deploy.groovy:144)
      at deploy.Deploy.run(Deploy.groovy:67)
      at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
      at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:57)
      at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
      at java.lang.reflect.Method.invoke(Method.java:606)
      at org.codehaus.groovy.runtime.callsite.PogoMetaMethodSite$PogoCachedMethodSiteNoUnwrapNoCoerce.invoke(PogoMetaMethodSite.java:210)
      at org.codehaus.groovy.runtime.callsite.PogoMetaMethodSite.call(PogoMetaMethodSite.java:71)
      at org.codehaus.groovy.runtime.callsite.CallSiteArray.defaultCall(CallSiteArray.java:48)
      at org.codehaus.groovy.runtime.callsite.AbstractCallSite.call(AbstractCallSite.java:113)
      at org.codehaus.groovy.runtime.callsite.AbstractCallSite.call(AbstractCallSite.java:117)
      at deploy.Deploy.main(Deploy.groovy:335)
  :deploy:dpDeployAll FAILED
  
  FAILURE: Build failed with an exception.
  
  * What went wrong:
  Execution failed for task ':deploy:dpDeployAll'.
  &gt; Process 'command 'C:\Program Files\Java\jdk1.7.0_80\bin\java.exe'' finished with non-zero exit value 1
  
  * Try:
  Run with --info or --debug option to get more log output.
  
  * Exception is:
  org.gradle.api.tasks.TaskExecutionException: Execution failed for task ':deploy:dpDeployAll'.
      at org.gradle.api.internal.tasks.execution.ExecuteActionsTaskExecuter.executeActions(ExecuteActionsTaskExecuter.java:84)
      at org.gradle.api.internal.tasks.execution.ExecuteActionsTaskExecuter.execute(ExecuteActionsTaskExecuter.java:55)
      at org.gradle.api.internal.tasks.execution.SkipUpToDateTaskExecuter.execute(SkipUpToDateTaskExecuter.java:62)
      at org.gradle.api.internal.tasks.execution.ValidatingTaskExecuter.execute(ValidatingTaskExecuter.java:58)
      at org.gradle.api.internal.tasks.execution.SkipEmptySourceFilesTaskExecuter.execute(SkipEmptySourceFilesTaskExecuter.java:88)
      at org.gradle.api.internal.tasks.execution.ResolveTaskArtifactStateTaskExecuter.execute(ResolveTaskArtifactStateTaskExecuter.java:46)
      at org.gradle.api.internal.tasks.execution.SkipTaskWithNoActionsExecuter.execute(SkipTaskWithNoActionsExecuter.java:51)
      at org.gradle.api.internal.tasks.execution.SkipOnlyIfTaskExecuter.execute(SkipOnlyIfTaskExecuter.java:54)
      at org.gradle.api.internal.tasks.execution.ExecuteAtMostOnceTaskExecuter.execute(ExecuteAtMostOnceTaskExecuter.java:43)
      at org.gradle.api.internal.tasks.execution.CatchExceptionTaskExecuter.execute(CatchExceptionTaskExecuter.java:34)
      at org.gradle.execution.taskgraph.DefaultTaskGraphExecuter$EventFiringTaskWorker$1.execute(DefaultTaskGraphExecuter.java:236)
      at org.gradle.execution.taskgraph.DefaultTaskGraphExecuter$EventFiringTaskWorker$1.execute(DefaultTaskGraphExecuter.java:228)
      at org.gradle.internal.Transformers$4.transform(Transformers.java:169)
      at org.gradle.internal.progress.DefaultBuildOperationExecutor.run(DefaultBuildOperationExecutor.java:106)
      at org.gradle.internal.progress.DefaultBuildOperationExecutor.run(DefaultBuildOperationExecutor.java:61)
      at org.gradle.execution.taskgraph.DefaultTaskGraphExecuter$EventFiringTaskWorker.execute(DefaultTaskGraphExecuter.java:228)
      at org.gradle.execution.taskgraph.DefaultTaskGraphExecuter$EventFiringTaskWorker.execute(DefaultTaskGraphExecuter.java:215)
      at org.gradle.execution.taskgraph.AbstractTaskPlanExecutor$TaskExecutorWorker.processTask(AbstractTaskPlanExecutor.java:77)
      at org.gradle.execution.taskgraph.AbstractTaskPlanExecutor$TaskExecutorWorker.run(AbstractTaskPlanExecutor.java:58)
      at org.gradle.execution.taskgraph.DefaultTaskPlanExecutor.process(DefaultTaskPlanExecutor.java:32)
      at org.gradle.execution.taskgraph.DefaultTaskGraphExecuter.execute(DefaultTaskGraphExecuter.java:113)
      at org.gradle.execution.SelectedTaskExecutionAction.execute(SelectedTaskExecutionAction.java:37)
      at org.gradle.execution.DefaultBuildExecuter.execute(DefaultBuildExecuter.java:37)
      at org.gradle.execution.DefaultBuildExecuter.access$000(DefaultBuildExecuter.java:23)
      at org.gradle.execution.DefaultBuildExecuter$1.proceed(DefaultBuildExecuter.java:43)
      at org.gradle.execution.DryRunBuildExecutionAction.execute(DryRunBuildExecutionAction.java:32)
      at org.gradle.execution.DefaultBuildExecuter.execute(DefaultBuildExecuter.java:37)
      at org.gradle.execution.DefaultBuildExecuter.execute(DefaultBuildExecuter.java:30)
      at org.gradle.initialization.DefaultGradleLauncher$3.execute(DefaultGradleLauncher.java:196)
      at org.gradle.initialization.DefaultGradleLauncher$3.execute(DefaultGradleLauncher.java:193)
      at org.gradle.internal.Transformers$4.transform(Transformers.java:169)
      at org.gradle.internal.progress.DefaultBuildOperationExecutor.run(DefaultBuildOperationExecutor.java:106)
      at org.gradle.internal.progress.DefaultBuildOperationExecutor.run(DefaultBuildOperationExecutor.java:56)
      at org.gradle.initialization.DefaultGradleLauncher.doBuildStages(DefaultGradleLauncher.java:193)
      at org.gradle.initialization.DefaultGradleLauncher.doBuild(DefaultGradleLauncher.java:119)
      at org.gradle.initialization.DefaultGradleLauncher.run(DefaultGradleLauncher.java:102)
      at org.gradle.launcher.exec.GradleBuildController.run(GradleBuildController.java:71)
      at org.gradle.tooling.internal.provider.ExecuteBuildActionRunner.run(ExecuteBuildActionRunner.java:28)
      at org.gradle.launcher.exec.ChainingBuildActionRunner.run(ChainingBuildActionRunner.java:35)
      at org.gradle.launcher.exec.InProcessBuildActionExecuter.execute(InProcessBuildActionExecuter.java:41)
      at org.gradle.launcher.exec.InProcessBuildActionExecuter.execute(InProcessBuildActionExecuter.java:26)
      at org.gradle.tooling.internal.provider.ContinuousBuildActionExecuter.execute(ContinuousBuildActionExecuter.java:75)
      at org.gradle.tooling.internal.provider.ContinuousBuildActionExecuter.execute(ContinuousBuildActionExecuter.java:49)
      at org.gradle.tooling.internal.provider.ServicesSetupBuildActionExecuter.execute(ServicesSetupBuildActionExecuter.java:44)
      at org.gradle.tooling.internal.provider.ServicesSetupBuildActionExecuter.execute(ServicesSetupBuildActionExecuter.java:29)
      at org.gradle.launcher.daemon.server.exec.ExecuteBuild.doBuild(ExecuteBuild.java:67)
      at org.gradle.launcher.daemon.server.exec.BuildCommandOnly.execute(BuildCommandOnly.java:36)
      at org.gradle.launcher.daemon.server.api.DaemonCommandExecution.proceed(DaemonCommandExecution.java:120)
      at org.gradle.launcher.daemon.server.exec.WatchForDisconnection.execute(WatchForDisconnection.java:47)
      at org.gradle.launcher.daemon.server.api.DaemonCommandExecution.proceed(DaemonCommandExecution.java:120)
      at org.gradle.launcher.daemon.server.exec.ResetDeprecationLogger.execute(ResetDeprecationLogger.java:26)
      at org.gradle.launcher.daemon.server.api.DaemonCommandExecution.proceed(DaemonCommandExecution.java:120)
      at org.gradle.launcher.daemon.server.exec.RequestStopIfSingleUsedDaemon.execute(RequestStopIfSingleUsedDaemon.java:34)
      at org.gradle.launcher.daemon.server.api.DaemonCommandExecution.proceed(DaemonCommandExecution.java:120)
      at org.gradle.launcher.daemon.server.exec.ForwardClientInput$2.call(ForwardClientInput.java:74)
      at org.gradle.launcher.daemon.server.exec.ForwardClientInput$2.call(ForwardClientInput.java:72)
      at org.gradle.util.Swapper.swap(Swapper.java:38)
      at org.gradle.launcher.daemon.server.exec.ForwardClientInput.execute(ForwardClientInput.java:72)
      at org.gradle.launcher.daemon.server.api.DaemonCommandExecution.proceed(DaemonCommandExecution.java:120)
      at org.gradle.launcher.daemon.server.exec.LogAndCheckHealth.execute(LogAndCheckHealth.java:55)
      at org.gradle.launcher.daemon.server.api.DaemonCommandExecution.proceed(DaemonCommandExecution.java:120)
      at org.gradle.launcher.daemon.server.exec.LogToClient.doBuild(LogToClient.java:60)
      at org.gradle.launcher.daemon.server.exec.BuildCommandOnly.execute(BuildCommandOnly.java:36)
      at org.gradle.launcher.daemon.server.api.DaemonCommandExecution.proceed(DaemonCommandExecution.java:120)
      at org.gradle.launcher.daemon.server.exec.EstablishBuildEnvironment.doBuild(EstablishBuildEnvironment.java:72)
      at org.gradle.launcher.daemon.server.exec.BuildCommandOnly.execute(BuildCommandOnly.java:36)
      at org.gradle.launcher.daemon.server.api.DaemonCommandExecution.proceed(DaemonCommandExecution.java:120)
      at org.gradle.launcher.daemon.server.exec.StartBuildOrRespondWithBusy$1.run(StartBuildOrRespondWithBusy.java:50)
      at org.gradle.launcher.daemon.server.DaemonStateCoordinator$1.run(DaemonStateCoordinator.java:297)
      at org.gradle.internal.concurrent.ExecutorPolicy$CatchAndRecordFailures.onExecute(ExecutorPolicy.java:54)
      at org.gradle.internal.concurrent.StoppableExecutorImpl$1.run(StoppableExecutorImpl.java:40)
  Caused by: org.gradle.process.internal.ExecException: Process 'command 'C:\Program Files\Java\jdk1.7.0_80\bin\java.exe'' finished with non-zero exit value 1
      at org.gradle.process.internal.DefaultExecHandle$ExecResultImpl.assertNormalExitValue(DefaultExecHandle.java:369)
      at org.gradle.process.internal.DefaultJavaExecAction.execute(DefaultJavaExecAction.java:31)
      at org.gradle.api.tasks.JavaExec.exec(JavaExec.java:74)
      at org.gradle.internal.reflect.JavaMethod.invoke(JavaMethod.java:73)
      at org.gradle.api.internal.project.taskfactory.DefaultTaskClassInfoStore$StandardTaskAction.doExecute(DefaultTaskClassInfoStore.java:141)
      at org.gradle.api.internal.project.taskfactory.DefaultTaskClassInfoStore$StandardTaskAction.execute(DefaultTaskClassInfoStore.java:134)
      at org.gradle.api.internal.project.taskfactory.DefaultTaskClassInfoStore$StandardTaskAction.execute(DefaultTaskClassInfoStore.java:123)
      at org.gradle.api.internal.AbstractTask$TaskActionWrapper.execute(AbstractTask.java:632)
      at org.gradle.api.internal.AbstractTask$TaskActionWrapper.execute(AbstractTask.java:615)
      at org.gradle.api.internal.tasks.execution.ExecuteActionsTaskExecuter.executeAction(ExecuteActionsTaskExecuter.java:95)
      at org.gradle.api.internal.tasks.execution.ExecuteActionsTaskExecuter.executeActions(ExecuteActionsTaskExecuter.java:76)
      ... 70 more
  
  
  BUILD FAILED
  
  Total time: 4.258 secs
  </code></pre>
  
  <p>Edit: adding deploy.gradle file:</p>
  
  <pre><code>version '3.8.0'
  
  apply plugin: 'groovy'
  
  dependencies {
      compile localGroovy()
      compile group: 'org.codehaus.groovy.modules.http-builder', name: 'http-builder', version: '0.7'
      compile group: 'org.apache.httpcomponents', name: 'httpmime', version: '4.5.3'
      compile group: 'com.github.inamik.text.tables', name: 'inamik-text-tables', version: '1.0-SNAPSHOT'
      compile group: 'org.eclipse', name: 'org.eclipse.osgi', version: ECLIPSE_OSGI_VERSION
  }
  
  ['dpDeployAll', 'dpDeploy', 'dpDeployAllCustom', 'dpList', 'dpUninstall', 'dpUninstallAll'].each { name -&gt;
      //noinspection GroovyAssignabilityCheck
      task "$name"(type: JavaExec) {
          classpath = sourceSets.main.runtimeClasspath
          main = 'deploy.Deploy'
          //noinspection GrUnresolvedAccess
          doFirst {
              if (project.hasProperty('host')) {
                  arguments.add(0, project.getProperty('host'))
              } else {
                  throw new InvalidUserDataException("Missing host property: specify with \"-Phost=hostname\"")
              }
              //noinspection GrUnresolvedAccess,GroovyAssignabilityCheck
              args arguments
          }
      }
  }
  
  dpDeployAll {
      doFirst {
          ext.arguments = ['deploy_all']
          arguments += ['all_production']
      }
  }
  
  
  dpDeploy {
      doFirst {
          ext.arguments = ['deploy']
          if (project.hasProperty('package')) {
              def packageName = project.getProperty('package')
              arguments += [packageName]
          } else {
              throw new InvalidUserDataException("Missing packageName property: specify with \"-Ppackage=package\"")
          }
      }
  }
  
  dpUninstall {
      doFirst {
          ext.arguments = ['uninstall']
          if (project.hasProperty('package')) {
              def packageName = project.getProperty('package')
              arguments += [packageName]
          } else {
              throw new InvalidUserDataException("Missing packageName property: specify with \"-Ppackage=package\"")
          }
      }
  }
  
  dpUninstallAll {
      doFirst {
          ext.arguments = ['uninstall_all']
      }
  }
  
  dpList {
      doFirst {
          ext.arguments = ['list']
      }
  }
  </code></pre>
  
  <p>Edit: adding deploy.groovy file:</p>
  
  <pre><code>package deploy
  
  import com.inamik.text.tables.Cell.Functions
  import com.inamik.text.tables.GridTable
  import com.inamik.text.tables.grid.Border
  import groovyx.net.http.ContentType
  import groovyx.net.http.HTTPBuilder
  import groovyx.net.http.HttpResponseDecorator
  import groovyx.net.http.Method
  import org.apache.http.HttpStatus
  import org.apache.http.entity.mime.MultipartEntityBuilder
  import org.apache.http.entity.mime.content.ByteArrayBody
  
  class Deploy {
      private static final String DEPLOY_ALL = 'deploy_all'
      private static final String DEPLOY = 'deploy'
      private static final String UNINSTALL = 'uninstall'
      private static final String LIST = 'list'
      private static final String UNINSTALL_ALL = 'uninstall_all'
  
      private static final String ADMIN_USERNAME = 'REDACTED'
      private static final String ADMIN_PASSWORD = 'REDACTED'
  
      private static final String ADMIN_SERVLET_PREFIX = '/charge_admin'
      private static final String GET_PACKAGES_SERVLET = ADMIN_SERVLET_PREFIX + '/get_packages'
      private static final String UNINSTALL_PACKAGES_SERVLET = ADMIN_SERVLET_PREFIX + '/uninstall_package'
      private static final String UPLOAD_PACKAGE_SERVLET = ADMIN_SERVLET_PREFIX + '/upload_package'
  
      private static final String CHARGEADMIN_PACKAGE_NAME = 'com.projectfw.charge.chargeadmin'
  
      private static final String PACKAGE_COLUMN_HEADER = "Package"
      private static final String OLD_VERSION_COLUMN_HEADER = "Old Version"
      private static final String NEW_VERSION_COLUMN_HEADER = "New Version"
      private static final String STATUS_COLUMN_HEADER = "Status"
  
      private static final String DEV_VERSION_STRING = "dev"
  
      private static final String UNINSTALLED_STATUS = "UNINSTALLED"
      private static final String NO_CHANGE_STATUS = "NO_CHANGE"
      private static final String INSTALLED_FRESH_STATUS = "INSTALLED_FRESH"
      private static final String OVERWRITTEN_STATUS = "OVERWRITTEN"
  
      private final HTTPBuilder http
      private final String[] args
      private final String command
      private final String host
  
      private DeploymentPackage chargeAdminPackage
      private List&lt;DeploymentPackage&gt; nonChargeAdminPackages
  
      private Deploy(String[] args) {
          this.args = args
          this.host = args[0]
          this.command = args[1]
          this.http = new HTTPBuilder(String.format("http://%s", host))
          http.auth.basic(ADMIN_USERNAME, ADMIN_PASSWORD)
      }
  
      private void run() {
          populateExistingPackages()
          println()
          println "ChargeAdmin servlet version on $host is ${chargeAdminPackage.getOldVersion()}"
          println()
          switch (command) {
              case DEPLOY_ALL:
                  final String profileName = args[2]
                  runDeployProfile(profileName)
                  break
              case DEPLOY:
                  final String packageName = args[2]
                  runDeploySingle(packageName)
                  break
              case UNINSTALL:
                  final String packageName = args[2]
                  runUninstall(packageName)
                  break
              case LIST:
                  runList()
                  break
              case UNINSTALL_ALL:
                  runUninstallAll()
                  break
              default:
                  throw new RuntimeException("Unknown command $command")
          }
      }
  
      private void runUninstallAll() {
          if (nonChargeAdminPackages.size() == 0) {
              println "No packages to uninstall on $host"
          } else {
              nonChargeAdminPackages.each {
                  uninstallSinglePackage(it.packageName)
              }
          }
          println()
          printStatusTable()
      }
  
      private void runList() {
          printStatusTable()
      }
  
      private void runDeploySingle(String packageName) {
          runDeploy(Arrays.asList(packageName), false, true)
      }
  
      private void runUninstall(String packageName) {
          uninstallSinglePackage(packageName)
          println()
          printStatusTable()
      }
  
      private void uninstallSinglePackage(String packageName) {
          if (nonChargeAdminPackages.find { it.packageName == packageName } == null) {
              println "WARNING: Package $packageName does not exist on $host"
          } else {
              http.request(Method.POST) { req -&gt;
                  uri.path = UNINSTALL_PACKAGES_SERVLET
                  requestContentType = ContentType.URLENC
                  body = [package: packageName]
              }
              DeploymentPackage packageUninstalled = nonChargeAdminPackages.find { it.packageName == packageName }
              packageUninstalled.setStatus(UNINSTALLED_STATUS)
              packageUninstalled.clearNewVersion()
              println "Uninstalled package $packageName version ${packageUninstalled.getOldVersion()}"
          }
      }
  
      private void runDeployProfile(String profileName) {
          File profile = new File(profileName + '.txt')
          println "Using profile $profileName"
          if (!profile.exists()) {
              throw new RuntimeException("Profile file ${profile.getCanonicalPath()} does not exist")
          }
  
          String contents = profile.getText('UTF-8')
          List&lt;String&gt; deploymentPackageNames = contents.tokenize('\n').asList()
          Collections.sort(deploymentPackageNames)
  
          deploymentPackageNames = deploymentPackageNames.findAll {
              !it.contains(CHARGEADMIN_PACKAGE_NAME)
          }
          runDeploy(deploymentPackageNames, true, false)
      }
  
      private void runDeploy(List&lt;String&gt; deploymentPackageNames, boolean deleteUnlistedPackages, boolean force) {
          List&lt;DeploymentPackage&gt; packagesToUninstall = new LinkedList&lt;&gt;()
          List&lt;DeploymentPackage&gt; packagesToInstallFresh = new LinkedList&lt;&gt;()
          List&lt;DeploymentPackage&gt; packagesToOverwrite = new LinkedList&lt;&gt;()
  
          if (deleteUnlistedPackages) {
              // First, uninstall packages which are on the server but which aren't in the profile.
              nonChargeAdminPackages.each {
                  if (!deploymentPackageNames.contains(it.getPackageName())) {
                      packagesToUninstall.add(it)
                  }
              }
          }
  
          deploymentPackageNames.each {
              File localPackageDir = new File("../$it/build/distributions")
              if (!localPackageDir.exists()) {
                  throw new RuntimeException("Build directory ${localPackageDir.getCanonicalPath()} does not exist")
              }
  
              File[] deploymentPackageVersionFiles = localPackageDir.listFiles()
              if (deploymentPackageVersionFiles.length == 0) {
                  throw new RuntimeException("Build directory ${localPackageDir.getCanonicalPath()} is empty")
              }
  
              // Collect all the versions in the directory
              DeploymentPackage[] deploymentPackageVersions = deploymentPackageVersionFiles.collect { File file -&gt;
                  String version = file.getName().substring(
                          file.getName().indexOf('-') + 1, file.getName().lastIndexOf('.'))
                  String packageName = file.getName().substring(0, file.getName().indexOf('-'))
                  DeploymentPackage deploymentPackageVersion = new DeploymentPackage(packageName)
                  deploymentPackageVersion.setNewVersion(version)
                  deploymentPackageVersion.setLocalPath(file.getCanonicalPath())
                  deploymentPackageVersion
              }
  
              // Find the one with the highest version number
              DeploymentPackage highestVersionedDeploymentPackage = deploymentPackageVersions.max {
                  it.getNewVersion()
              }
  
              // Find the one that already exists on the server that we are comparing to:
              DeploymentPackage existingOnServer = nonChargeAdminPackages.find {
                  it.getPackageName() == highestVersionedDeploymentPackage.getPackageName()
              }
  
              if (existingOnServer == null) {
                  // We need to upload the package for the first time
                  packagesToInstallFresh.add(highestVersionedDeploymentPackage)
              } else if (existingOnServer.getOldVersion() != highestVersionedDeploymentPackage.getNewVersion()) {
                  // Existing version on server doesn't equal candidate version, should replace,
                  // even if candidate version is older.
                  packagesToUninstall.add(existingOnServer)
                  packagesToOverwrite.add(highestVersionedDeploymentPackage)
              } else if (existingOnServer.getOldVersion().getQualifier().contains(DEV_VERSION_STRING)) {
                  // Existing version on server has the dev version qualifier, should replace,
                  // even though the version numbers are identical.
                  packagesToUninstall.add(existingOnServer)
                  packagesToOverwrite.add(highestVersionedDeploymentPackage)
              } else if (force) {
                  // Replace it no matter what.
                  packagesToUninstall.add(existingOnServer)
                  packagesToOverwrite.add(highestVersionedDeploymentPackage)
              }
          }
  
          Collections.sort(packagesToUninstall)
          Collections.sort(packagesToOverwrite)
          Collections.sort(packagesToInstallFresh)
  
          packagesToUninstall.each {
              uninstallSinglePackage(it.getPackageName())
          }
  
          packagesToOverwrite.each {
              uploadPackage(it)
              DeploymentPackage existing =
                      nonChargeAdminPackages.find { existing -&gt; existing.getPackageName() == it.getPackageName() }
              existing.setNewVersion(it.getNewVersion())
              existing.setStatus(OVERWRITTEN_STATUS)
          }
  
          packagesToInstallFresh.each {
              uploadPackage(it)
              it.setStatus(INSTALLED_FRESH_STATUS)
              nonChargeAdminPackages.add(it)
          }
  
          println()
          printStatusTable()
      }
  
      private void uploadPackage(DeploymentPackage pkg) {
          File file = new File(pkg.getLocalPath())
          http.request(Method.POST) { req -&gt;
              uri.path = UPLOAD_PACKAGE_SERVLET
              requestContentType = 'multipart/form-data'
              req.entity = MultipartEntityBuilder.create()
                      .addPart("file", new ByteArrayBody(file.bytes, file.getName()))
                      .build()
          }
          println "Deployed ${pkg.getPackageName()} version ${pkg.getNewVersion()}"
      }
  
      private void populateExistingPackages() {
          String packagesString = http.request(Method.GET) { req -&gt;
              uri.path = GET_PACKAGES_SERVLET
              response.success = { resp, reader -&gt;
                  reader.getText().toString()
              }
              response.failure = { HttpResponseDecorator resp, reader -&gt;
                  if (resp.getStatus() == HttpStatus.SC_UNAUTHORIZED) {
                      throw new RuntimeException("Unauthorized -- is the ChargeAdmin servlet installed?")
                  }
              }
          }
  </code></pre>