This is an automated email from the ASF dual-hosted git repository. jdaugherty pushed a commit to branch wrapper-rewrite in repository https://gitbox.apache.org/repos/asf/grails-core.git
commit 3ae1e1aab6b419238eae5a6ebb26075f367c4b68 Author: James Daugherty <jdaughe...@jdresources.net> AuthorDate: Tue May 13 15:45:06 2025 -0400 Rework grails wrapper to support multiple versions and track them historically. --- ...aseHandler.java => FindLastReleaseHandler.java} | 2 +- ...otHandler.java => FindLastSnapshotHandler.java} | 2 +- .../src/main/java/grails/init/GrailsHome.java | 53 +++++--- .../main/java/grails/init/GrailsReleaseType.java | 28 +++++ .../src/main/java/grails/init/GrailsUpdater.java | 137 ++++++++++++++------- .../src/main/java/grails/init/GrailsVersion.java | 22 ++-- .../main/java/grails/init/GrailsWrapperRepo.java | 82 ++++++++++++ .../src/main/java/grails/init/Start.java | 89 ++++++++++--- 8 files changed, 321 insertions(+), 94 deletions(-) diff --git a/grails-wrapper/src/main/java/grails/init/FindReleaseHandler.java b/grails-wrapper/src/main/java/grails/init/FindLastReleaseHandler.java similarity index 97% rename from grails-wrapper/src/main/java/grails/init/FindReleaseHandler.java rename to grails-wrapper/src/main/java/grails/init/FindLastReleaseHandler.java index 9153586f9a..988111edc8 100644 --- a/grails-wrapper/src/main/java/grails/init/FindReleaseHandler.java +++ b/grails-wrapper/src/main/java/grails/init/FindLastReleaseHandler.java @@ -23,7 +23,7 @@ import org.xml.sax.helpers.DefaultHandler; /** * Created by jameskleeh on 11/2/16. */ -public class FindReleaseHandler extends DefaultHandler { +public class FindLastReleaseHandler extends DefaultHandler { private String releaseVersion; private String latestVersion; diff --git a/grails-wrapper/src/main/java/grails/init/FindSnapshotHandler.java b/grails-wrapper/src/main/java/grails/init/FindLastSnapshotHandler.java similarity index 97% rename from grails-wrapper/src/main/java/grails/init/FindSnapshotHandler.java rename to grails-wrapper/src/main/java/grails/init/FindLastSnapshotHandler.java index ba766f5d2a..0995acd93d 100644 --- a/grails-wrapper/src/main/java/grails/init/FindSnapshotHandler.java +++ b/grails-wrapper/src/main/java/grails/init/FindLastSnapshotHandler.java @@ -19,7 +19,7 @@ package grails.init; import org.xml.sax.Attributes; import org.xml.sax.helpers.DefaultHandler; -public class FindSnapshotHandler extends DefaultHandler { +public class FindLastSnapshotHandler extends DefaultHandler { private boolean insideSnapshotVersion = false; private boolean insideVersion = false; diff --git a/grails-wrapper/src/main/java/grails/init/GrailsHome.java b/grails-wrapper/src/main/java/grails/init/GrailsHome.java index b92b87ecd1..e2969ec3a5 100644 --- a/grails-wrapper/src/main/java/grails/init/GrailsHome.java +++ b/grails-wrapper/src/main/java/grails/init/GrailsHome.java @@ -31,10 +31,12 @@ public class GrailsHome { public final File home; public final File wrapperDirectory; public final List<GrailsVersion> versions; + public final List<GrailsReleaseType> allowedReleaseTypes; public final GrailsVersion latestVersion; - public GrailsHome(String grailsHome) throws IOException { - home = findGrailsHome(grailsHome).getCanonicalFile(); + public GrailsHome(List<GrailsReleaseType> allowedReleaseTypes, String forcedGrailsHome) throws IOException { + home = findGrailsHome(forcedGrailsHome).getCanonicalFile(); + this.allowedReleaseTypes = allowedReleaseTypes == null ? new ArrayList<>() : allowedReleaseTypes; wrapperDirectory = new File(home, "wrapper"); if(!wrapperDirectory.exists()) { @@ -107,16 +109,16 @@ public class GrailsHome { GrailsVersion lastMilestone = null; GrailsVersion lastSnapshot = null; for (GrailsVersion version : versions) { - if(version.releaseType == GrailsVersion.ReleaseType.RELEASE && (lastRelease == null || version.compareTo(lastRelease) > 0)) { + if(version.releaseType == GrailsReleaseType.RELEASE && (lastRelease == null || version.compareTo(lastRelease) > 0)) { lastRelease = version; } - else if(version.releaseType == GrailsVersion.ReleaseType.RC && (lastReleaseCandidate == null || version.compareTo(lastReleaseCandidate) > 0)) { + else if(version.releaseType == GrailsReleaseType.RC && (lastReleaseCandidate == null || version.compareTo(lastReleaseCandidate) > 0)) { lastReleaseCandidate = version; } - else if(version.releaseType == GrailsVersion.ReleaseType.MILESTONE && (lastMilestone == null || version.compareTo(lastMilestone) > 0)) { + else if(version.releaseType == GrailsReleaseType.MILESTONE && (lastMilestone == null || version.compareTo(lastMilestone) > 0)) { lastMilestone = version; } - else if(version.releaseType == GrailsVersion.ReleaseType.SNAPSHOT && (lastSnapshot == null || version.compareTo(lastSnapshot) > 0)) { + else if(version.releaseType == GrailsReleaseType.SNAPSHOT && (lastSnapshot == null || version.compareTo(lastSnapshot) > 0)) { lastSnapshot = version; } } @@ -151,6 +153,9 @@ public class GrailsHome { try { GrailsVersion version = new GrailsVersion(child.getName()); + if(!allowedReleaseTypes.isEmpty() && !allowedReleaseTypes.contains(version.releaseType)) { + continue; + } versions.add(version); } catch(Exception ignored) { @@ -169,13 +174,14 @@ public class GrailsHome { * 2. using the environment variable * 3. Looking in the current directory for a GRAILS_HOME_MARKERS or for a .grails directory * and all parent directories. If none, is found, the current directory will be returned. + * There is a special case for the current directory if inside of the grails core repository. * * @return the GRAILS_HOME directory * @throws IOException if canonicalization fails */ - public static File findGrailsHome(String possibleGrailsHome) throws IOException { - if (possibleGrailsHome != null && !possibleGrailsHome.isEmpty()) { - return validateGrailsHome(possibleGrailsHome, "Specified Grails Home"); + public static File findGrailsHome(String grailsHomeOverride) throws IOException { + if (grailsHomeOverride != null && !grailsHomeOverride.isEmpty()) { + return validateGrailsHome(grailsHomeOverride, "Specified Grails Home"); } String environmentOverride = System.getenv("GRAILS_HOME"); @@ -204,9 +210,15 @@ public class GrailsHome { return file.exists(); } + private static boolean directoryExists(File baseDirectory, String name) { + File file = new File(baseDirectory, name); + return file.exists() && file.isDirectory(); + } + /** * Locate the “Grails" home by first looking in `directory` for a GRAILS_HOME_MARKERS or for a .grails directory - * and all parent directories. If none, is found, the original directory will be returned. + * and all parent directories. If none, is found, the original directory will be returned. Short circuit on the + * home directory to avoid traversing into the root if possible. * * @param directory where to begin the search * @return the directory containing one of the markers, or original directory @@ -220,27 +232,34 @@ public class GrailsHome { File userHome = new File(System.getProperty("user.home")).getCanonicalFile(); File searchDirectory = directory.getCanonicalFile(); + if (searchDirectory.equals(userHome)) { - throw new IllegalStateException("GRAILS_HOME is no longer allowed to be at the user home directory."); + // if run from the user home directory, allow it to exist + return searchDirectory; } if (searchDirectory.getParentFile() == null) { - throw new IllegalStateException("GRAILS_HOME is not permitted to be at the root of the file system."); + // if run from the root, allow it to exist + return searchDirectory; } File originalDirectory = searchDirectory; while (searchDirectory != null && searchDirectory.exists() && !searchDirectory.equals(userHome)) { + if (directoryExists(searchDirectory, ".grails")) { + return searchDirectory; + } + + // Assume this is nested under the grails core directory, so assume the current directory is the root of the project + if(directoryExists(searchDirectory, "grails-core") && directoryExists(searchDirectory, "grails-bom")) { + return originalDirectory; + } + for (String name : GRAILS_HOME_MARKERS) { if (exists(searchDirectory, name)) { return searchDirectory; } } - File grailsDir = new File(searchDirectory, ".grails"); - if (grailsDir.exists() && grailsDir.isDirectory()) { - return searchDirectory; - } - searchDirectory = searchDirectory.getParentFile(); if (searchDirectory != null) { searchDirectory = searchDirectory.getCanonicalFile(); diff --git a/grails-wrapper/src/main/java/grails/init/GrailsReleaseType.java b/grails-wrapper/src/main/java/grails/init/GrailsReleaseType.java new file mode 100644 index 0000000000..1e982d1251 --- /dev/null +++ b/grails-wrapper/src/main/java/grails/init/GrailsReleaseType.java @@ -0,0 +1,28 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * https://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package grails.init; + +public enum GrailsReleaseType { + RELEASE, + RC, + MILESTONE, + SNAPSHOT; + + boolean isSnapshot() { + return this == SNAPSHOT; + } +} diff --git a/grails-wrapper/src/main/java/grails/init/GrailsUpdater.java b/grails-wrapper/src/main/java/grails/init/GrailsUpdater.java index dd9927e731..d8abe099d6 100644 --- a/grails-wrapper/src/main/java/grails/init/GrailsUpdater.java +++ b/grails-wrapper/src/main/java/grails/init/GrailsUpdater.java @@ -30,26 +30,39 @@ import java.net.URL; import java.nio.channels.Channels; import java.nio.channels.ReadableByteChannel; import java.nio.file.Files; +import java.util.List; import static java.nio.file.StandardCopyOption.REPLACE_EXISTING; public class GrailsUpdater { - private static final String WRAPPER_MAVEN_PATH = "/org/apache/grails/" + GrailsHome.CLI_COMBINED_PROJECT_NAME; - private static final String GRAILS_RELEASE_MAVEN_REPO_BASE_URL = "https://repository.apache.org/content/groups/public"; private final GrailsHome grailsHome; + private final GrailsVersion preferredVersion; private GrailsVersion updatedVersion; - public GrailsUpdater() throws IOException { - this(null); + public GrailsUpdater(List<GrailsReleaseType> allowedTypes, GrailsVersion preferredVersion) throws IOException { + this(allowedTypes, preferredVersion, null); } - public GrailsUpdater(String possibleGrailsHome) throws IOException { - grailsHome = new GrailsHome(possibleGrailsHome); + public GrailsUpdater(List<GrailsReleaseType> allowedTypes, GrailsVersion preferredVersion, String possibleGrailsHome) throws IOException { + grailsHome = new GrailsHome(allowedTypes, possibleGrailsHome); + this.preferredVersion = preferredVersion; } - public File getExecutedVersion() { - return updatedVersion == null ? grailsHome.getLatestWrapperImplementation() : grailsHome.getWrapperImplementation(grailsHome.getVersionDirectory(updatedVersion)); + public GrailsVersion getSelectedVersion() { + if(preferredVersion != null) { + return preferredVersion; + } + + if(updatedVersion != null) { + return updatedVersion; + } + + return grailsHome.latestVersion; + } + + public File getExecutedJarFile() { + return grailsHome.getWrapperImplementation(grailsHome.getVersionDirectory(getSelectedVersion())); } /** @@ -63,43 +76,57 @@ public class GrailsUpdater { return true; } - // TODO: Should we force updates for snapshots? + if(preferredVersion != null) { + if(!grailsHome.versions.contains(preferredVersion)) { + return true; + } + + // Force snapshots to update always + return preferredVersion.releaseType.isSnapshot(); + } return false; } public boolean update() { - GrailsVersion baseVersion = null; - try { - baseVersion = getVersion(); + GrailsWrapperRepo repo = GrailsWrapperRepo.getSelectedRepo(); + + GrailsVersion latestVersion = null; + if(preferredVersion != null) { + latestVersion = preferredVersion; } - catch(Exception e) { - System.err.println("You must be connected to the internet the first time you use the Grails wrapper"); - e.printStackTrace(); - System.exit(1); + else { + try { + latestVersion = getLastVersion(repo); + } + catch(Exception e) { + System.err.println("Unable to fetch latest Grails CLI."); + e.printStackTrace(); + System.exit(1); + } } String detailedVersion = null; - if (baseVersion.releaseType.isSnapshot()) { + if (latestVersion.releaseType.isSnapshot()) { try { - detailedVersion = getSnapshotVersion(baseVersion); + detailedVersion = fetchSnapshotForVersion(repo, latestVersion); } catch(Exception e) { - System.err.println("Could not parse snapshot version. You must be connected to the internet the first time you use the Grails wrapper"); + System.err.println("Could not parse snapshot version from maven metadata."); e.printStackTrace(); System.exit(1); } } - boolean theResult = updateJar(baseVersion, detailedVersion); + boolean theResult = updateJar(repo, latestVersion, detailedVersion); if(theResult) { - updatedVersion = baseVersion; + updatedVersion = latestVersion; } return theResult; } - private boolean updateJar(GrailsVersion version, String snapshotVersion) { + private boolean updateJar(GrailsWrapperRepo repo, GrailsVersion version, String snapshotVersion) { boolean success = false; final String localJarFilename = GrailsHome.CLI_COMBINED_PROJECT_NAME + "-" + version.version; @@ -108,9 +135,22 @@ public class GrailsUpdater { try { File downloadedJar = File.createTempFile(localJarFilename, jarFileExtension); - String wrapperUrl = getMavenBaseUrl() + WRAPPER_MAVEN_PATH + "/" + version.version + "/" + remoteJarFilename + jarFileExtension; - HttpURLConnection conn = createHttpURLConnection(wrapperUrl); - success = downloadWrapperJar(version, downloadedJar, conn.getInputStream()); + String wrapperUrl = repo.getFileUrl(version, remoteJarFilename + jarFileExtension); + + InputStream inputStream; + if(repo.isFile) { + File jarFile = new File(wrapperUrl); + if(!jarFile.exists()) { + throw new IllegalStateException("Could not determine local metadata file from local maven repository: " + jarFile.getAbsolutePath() + " does not exist"); + } + inputStream = Files.newInputStream(jarFile.toPath()); + } + else { + HttpURLConnection conn = createHttpURLConnection(wrapperUrl); + inputStream = conn.getInputStream(); + } + + success = downloadWrapperJar(version, downloadedJar, inputStream); } catch (Exception e) { System.err.println("There was an error downloading the wrapper jar"); e.printStackTrace(); @@ -138,30 +178,33 @@ public class GrailsUpdater { return true; } - private static String getMavenBaseUrl() { - String baseUrl = System.getProperty("grails.maven.repo.baseUrl"); - if (baseUrl != null) { - return baseUrl; + private static InputStream retrieveMavenMetadata(GrailsWrapperRepo repo, String metadataUrl) throws IOException { + if(repo.isFile) { + File metadataFile = new File(metadataUrl); + if(!metadataFile.exists()) { + throw new IllegalStateException("Could not determine local metadata file from local maven repository: " + metadataFile.getAbsolutePath() + " does not exist"); + } + return Files.newInputStream(metadataFile.toPath()); } - - baseUrl = System.getenv("GRAILS_RELEASE_MAVEN_REPO_BASE_URL"); - if (baseUrl != null) { - return baseUrl; + else { + HttpURLConnection connection = createHttpURLConnection(metadataUrl); + try { + return connection.getInputStream(); + } + catch(Exception e) { + throw new RuntimeException("There was an error downloading the metadata file", e); + } } - - return GRAILS_RELEASE_MAVEN_REPO_BASE_URL; } - private static GrailsVersion getVersion() throws IOException, SAXException, ParserConfigurationException { + private GrailsVersion getLastVersion(GrailsWrapperRepo repo) throws IOException, SAXException, ParserConfigurationException { SAXParserFactory factory = SAXParserFactory.newInstance(); SAXParser saxParser = factory.newSAXParser(); - FindReleaseHandler findReleaseHandler = new FindReleaseHandler(); - final String mavenMetadataFileUrl = getMavenBaseUrl() + WRAPPER_MAVEN_PATH + "/maven-metadata.xml"; - HttpURLConnection conn = createHttpURLConnection(mavenMetadataFileUrl); + FindLastReleaseHandler findLastReleaseHandler = new FindLastReleaseHandler(); - try(InputStream stream = conn.getInputStream()) { - saxParser.parse(stream, findReleaseHandler); - String parsedVersion = findReleaseHandler.getVersion(); + try(InputStream stream = retrieveMavenMetadata(repo, repo.getRootMetadataUrl())) { + saxParser.parse(stream, findLastReleaseHandler); + String parsedVersion = findLastReleaseHandler.getVersion(); try { return new GrailsVersion(parsedVersion); } @@ -171,14 +214,14 @@ public class GrailsUpdater { } } - private static String getSnapshotVersion(GrailsVersion baseVersion) throws IOException, SAXException, ParserConfigurationException { + private String fetchSnapshotForVersion(GrailsWrapperRepo repo, GrailsVersion baseVersion) throws IOException, SAXException, ParserConfigurationException { System.out.println("A Grails snapshot version has been detected. Downloading latest snapshot."); + SAXParserFactory factory = SAXParserFactory.newInstance(); SAXParser saxParser = factory.newSAXParser(); - FindSnapshotHandler findVersionHandler = new FindSnapshotHandler(); - final String mavenMetadataFileUrl = getMavenBaseUrl() + WRAPPER_MAVEN_PATH + "/" + baseVersion.version + "/maven-metadata.xml"; - HttpURLConnection conn = createHttpURLConnection(mavenMetadataFileUrl); - try(InputStream stream = conn.getInputStream()) { + FindLastSnapshotHandler findVersionHandler = new FindLastSnapshotHandler(); + + try(InputStream stream = retrieveMavenMetadata(repo, repo.getMetadataUrl(baseVersion))) { saxParser.parse(stream, findVersionHandler); return findVersionHandler.getVersion(); } diff --git a/grails-wrapper/src/main/java/grails/init/GrailsVersion.java b/grails-wrapper/src/main/java/grails/init/GrailsVersion.java index eb61551632..6949fd1251 100644 --- a/grails-wrapper/src/main/java/grails/init/GrailsVersion.java +++ b/grails-wrapper/src/main/java/grails/init/GrailsVersion.java @@ -33,7 +33,7 @@ public class GrailsVersion implements Comparable<GrailsVersion> { public final String major; public final String minor; public final String patch; - public final ReleaseType releaseType; + public final GrailsReleaseType releaseType; public final int patchNumber; GrailsVersion(String version) { @@ -54,16 +54,16 @@ public class GrailsVersion implements Comparable<GrailsVersion> { Matcher m; if ((m = RELEASE.matcher(patch)).matches()) { - releaseType = ReleaseType.RELEASE; + releaseType = GrailsReleaseType.RELEASE; patchNumber = Integer.parseInt(m.group(1)); } else if ((m = RC.matcher(patch)).matches()) { - releaseType = ReleaseType.RC; + releaseType = GrailsReleaseType.RC; patchNumber = Integer.parseInt(m.group(1)); } else if ((m = MILESTONE.matcher(patch)).matches()) { - releaseType = ReleaseType.MILESTONE; + releaseType = GrailsReleaseType.MILESTONE; patchNumber = Integer.parseInt(m.group(1)); } else if ((m = SNAPSHOT.matcher(patch)).matches()) { - releaseType = ReleaseType.SNAPSHOT; + releaseType = GrailsReleaseType.SNAPSHOT; patchNumber = Integer.parseInt(m.group(1)); } else { throw new IllegalArgumentException("Unrecognized patch version: " + patch); @@ -109,14 +109,8 @@ public class GrailsVersion implements Comparable<GrailsVersion> { return Integer.compare(patchNumber, o.patchNumber); } - public enum ReleaseType { - RELEASE, - RC, - MILESTONE, - SNAPSHOT; - - boolean isSnapshot() { - return this == SNAPSHOT; - } + @Override + public String toString() { + return version; } } diff --git a/grails-wrapper/src/main/java/grails/init/GrailsWrapperRepo.java b/grails-wrapper/src/main/java/grails/init/GrailsWrapperRepo.java new file mode 100644 index 0000000000..4346879cf3 --- /dev/null +++ b/grails-wrapper/src/main/java/grails/init/GrailsWrapperRepo.java @@ -0,0 +1,82 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * https://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package grails.init; + +import java.io.File; + +public class GrailsWrapperRepo { + private String baseUrl; + private String repoPath; + private String metadataName; + boolean isFile; + + private GrailsWrapperRepo() { + } + + String getUrl() { + return join(baseUrl, repoPath); + } + + String getRootMetadataUrl() { + return join(getUrl(), metadataName); + } + + String getMetadataUrl(GrailsVersion version) { + return join(getUrl(), version.version, metadataName); + } + + String getFileUrl(GrailsVersion version, String name) { + return join(getUrl(), version.version, name); + + } + + private String join(String ... elements) { + return String.join(isFile ? File.separator : "/", elements); + } + + static GrailsWrapperRepo getSelectedRepo() { + GrailsWrapperRepo repo = new GrailsWrapperRepo(); + repo.repoPath = "org/apache/grails/" + GrailsHome.CLI_COMBINED_PROJECT_NAME; + + String configured = getConfiguredMavenUrl(); + if (configured != null) { + System.out.println("... Update Repository is overridden to: " + configured); + repo.baseUrl = configured; + } else { + // default to upstream snapshots or groups + repo.baseUrl = "https://repository.apache.org/content/groups/public"; + } + repo.isFile = !repo.baseUrl.startsWith("http"); + + if((repo.isFile && repo.baseUrl.endsWith(File.separator)) || (!repo.isFile && repo.baseUrl.endsWith("/"))) { + // remove trailing slash + repo.baseUrl = repo.baseUrl.substring(0, repo.baseUrl.length() - 1); + } + + repo.metadataName = repo.isFile ? "maven-metadata-local.xml" : "maven-metadata.xml"; + return repo; + } + + static String getConfiguredMavenUrl() { + String baseUrl = System.getProperty("grails.repo.url"); + if (baseUrl != null) { + return baseUrl; + } + + return System.getenv("GRAILS_REPO_URL"); + } +} diff --git a/grails-wrapper/src/main/java/grails/init/Start.java b/grails-wrapper/src/main/java/grails/init/Start.java index e51f19b541..a9d9efe69a 100644 --- a/grails-wrapper/src/main/java/grails/init/Start.java +++ b/grails-wrapper/src/main/java/grails/init/Start.java @@ -18,40 +18,44 @@ package grails.init; import grails.proxy.SystemPropertiesAuthenticator; -import javax.xml.parsers.SAXParser; -import javax.xml.parsers.SAXParserFactory; import java.io.File; -import java.io.FileOutputStream; -import java.io.IOException; +import java.io.FileInputStream; import java.io.InputStream; import java.lang.reflect.Method; import java.net.Authenticator; -import java.net.HttpURLConnection; import java.net.URL; import java.net.URLClassLoader; -import java.nio.channels.Channels; -import java.nio.channels.ReadableByteChannel; -import java.nio.file.Files; import java.util.Arrays; - -import static java.nio.file.StandardCopyOption.REPLACE_EXISTING; +import java.util.List; +import java.util.Properties; +import java.util.stream.Collectors; /** * The purpose of this class is to download the expanded Grails wrapper jars into GRAILS_HOME (`.grails` in the project root) * This class is not meant to be distributed as part of SDKMAN since we'll distribute the expanded jars with it. - * After downloading the jars, it will delegate to the downloaded wrapper impl project + * After downloading the jars, it will delegate to the downloaded grails-cli project. + * + * There are 3 ways this class can be used: + * 1. in testing a grails release (run from a non-project directory) // will require GRAILS_HOME to be manually set + * 2. running from a non-project directory (end user usage) + * 3. running from inside a grails project */ public class Start { public static void main(String[] args) { Authenticator.setDefault(new SystemPropertiesAuthenticator()); try { - GrailsUpdater updater = new GrailsUpdater(); + List<GrailsReleaseType> allowedTypes = getAllowedReleaseTypes(); + GrailsVersion preferredGrailsVersion = getPreferredGrailsVersion(); + + GrailsUpdater updater = new GrailsUpdater(allowedTypes, preferredGrailsVersion); boolean forceUpdate = (args.length > 0 && args[0].trim().equals("update-wrapper")); + boolean updated = false; String[] adjustedArgs = args; if (forceUpdate || updater.needsUpdating()) { - updater.update(); + System.out.println("Updating Grails wrapper..."); + updated = updater.update(); // remove "update-wrapper" command argument if (forceUpdate) { @@ -59,7 +63,11 @@ public class Start { } } - URLClassLoader child = new URLClassLoader(new URL[]{updater.getExecutedVersion().toURI().toURL()}); + if(updated) { + System.out.println("Updated wrapper to version: " + updater.getSelectedVersion().toString()); + } + + URLClassLoader child = new URLClassLoader(new URL[]{updater.getExecutedJarFile().toURI().toURL()}); Class<?> classToLoad = Class.forName("grails.init.RunCommand", true, child); Method main = classToLoad.getMethod("main", String[].class); main.invoke(null, (Object[]) adjustedArgs); @@ -68,4 +76,57 @@ public class Start { System.exit(1); } } + + private static GrailsVersion getPreferredGrailsVersion() { + // Check for a properties file in case inside a grails project + File gradleProperties = new File("gradle.properties"); + if(!gradleProperties.exists()) { + return null; + } + + Properties properties = new Properties(); + try { + try (InputStream in = new FileInputStream(gradleProperties)) { + properties.load(in); + } + } + catch(Exception e) { + System.err.println("Failed to load gradle.properties from "+ gradleProperties); + e.printStackTrace(); + System.exit(1); + } + + if(!properties.containsKey("grailsVersion")) { + return null; + } + + String grailsVersion = properties.getProperty("grailsVersion"); + if(grailsVersion == null) { + System.out.println("gradle.properties does not contain grailsVersion; downloading latest Grails Version"); + return null; + } + + try { + return new GrailsVersion(grailsVersion); + } + catch(Exception e) { + System.out.println("An invalid Grails Version [" + grailsVersion + "] was specified in gradle.properties"); + e.printStackTrace(); + System.exit(1); + } + + return null; + } + + private static List<GrailsReleaseType> getAllowedReleaseTypes() { + String raw = System.getenv("GRAILS_WRAPPER_ALLOWED_TYPES"); + if (raw == null || raw.trim().isEmpty()) { + return null; + } + + return Arrays.stream(raw.split(",")) + .map(String::trim) + .map(GrailsReleaseType::valueOf) + .collect(Collectors.toList()); + } }