Skip to content

Commit

Permalink
Moved TouchBundles from releng tests to releng tools
Browse files Browse the repository at this point in the history
Added TouchBundles with VersionBump to simplify unstable build fixes
caused by compiler changes.

See eclipse-platform/eclipse.platform.releng.aggregator#1931

See eclipse-platform/eclipse.platform.releng.aggregator#1923
  • Loading branch information
iloveeclipse committed Mar 25, 2024
1 parent 6743d48 commit 0cc5888
Show file tree
Hide file tree
Showing 4 changed files with 351 additions and 2 deletions.
2 changes: 1 addition & 1 deletion bundles/org.eclipse.releng.tools/META-INF/MANIFEST.MF
Expand Up @@ -2,7 +2,7 @@ Manifest-Version: 1.0
Bundle-ManifestVersion: 2
Bundle-Name: %PluginName
Bundle-SymbolicName: org.eclipse.releng.tools; singleton:=true
Bundle-Version: 4.2.0.qualifier
Bundle-Version: 4.2.100.qualifier
Bundle-Activator: org.eclipse.releng.tools.RelEngPlugin
Bundle-Vendor: %PluginProvider
Bundle-Localization: plugin
Expand Down
2 changes: 1 addition & 1 deletion bundles/org.eclipse.releng.tools/pom.xml
Expand Up @@ -18,7 +18,7 @@
</parent>
<groupId>org.eclipse.releng</groupId>
<artifactId>org.eclipse.releng.tools</artifactId>
<version>4.2.0-SNAPSHOT</version>
<version>4.2.100-SNAPSHOT</version>
<packaging>eclipse-plugin</packaging>
<properties>
<defaultSigning-excludeInnerJars>true</defaultSigning-excludeInnerJars>
Expand Down
@@ -0,0 +1,176 @@
/*******************************************************************************
* Copyright (c) 2024 Andrey Loskutov <loskutov@gmx.de> and others.
*
* This program and the accompanying materials
* are made available under the terms of the Eclipse Public License 2.0
* which accompanies this distribution, and is available at
* https://www.eclipse.org/legal/epl-2.0/
*
* SPDX-License-Identifier: EPL-2.0
*
* Contributors:
* Andrey Loskutov <loskutov@gmx.de> - initial API and implementation
*******************************************************************************/
package org.eclipse.releng.tools;

import java.io.File;
import java.nio.file.Files;
import java.nio.file.Path;
import java.nio.file.Paths;
import java.nio.file.StandardOpenOption;
import java.util.Arrays;
import java.util.Map;
import java.util.Map.Entry;
import java.util.stream.Collectors;

@SuppressWarnings("nls")
public class TouchBundles {

final static String FQU_FILE = "forceQualifierUpdate.txt";
static String releaseTag;
static String ticketMessage;

/**
* Tries to map & touch all bundles that are mentioned in artifact
* comparisons. Automatically bumps versions if needed.
*
* @param args
* <ol>
* <li>path to the extracted artifactcomparisons.zip
* <li>path to the root directory with all SDK repositories
* <li>last SDK release tag
* <li>the ticket message (can be empty)
* </ol>
* @throws Exception
*/
public static void main(String[] args) throws Exception {
if (args.length != 4) {
System.out.println("Arguments: "
+ "1) path to the extracted artifactcomparisons.zip, \n"
+ "2) path to the root directory with all SDK repositories, \n"
+ "3) last SDK release tag, like 'R4_31', \n"
+ "4) the ticket message (can be empty)"
);
System.exit(1);
}
Path artifactsPath = Paths.get(args[0]);
File[] badDirs = artifactsPath.toFile().listFiles();
if (badDirs == null) {
System.out.println("No files found in " + artifactsPath);
System.exit(1);
}

Path rootReposDir = Paths.get(args[1]);
File[] gitDirs = rootReposDir.toFile().listFiles();
if (gitDirs == null) {
System.out.println("No files found in " + rootReposDir);
System.exit(1);
}

releaseTag = args[2].strip();
if (releaseTag.isBlank()) {
System.out.println("Last SDK release tag (like 'R4_31') is missing");
System.exit(1);
}

ticketMessage = args[3].strip();
if (ticketMessage.isBlank()) {
ticketMessage = "Touching " + FQU_FILE + " to force bundle rebuild\n";
}

Map<String, File> badDirMap = Arrays.asList(badDirs).stream().filter(File::isDirectory)
.collect(Collectors.toMap(File::getName, f -> f));

Map<String, File> gitDirMap = Arrays.asList(gitDirs).stream().filter(File::isDirectory)
.collect(Collectors.toMap(File::getName, f -> f));

if (gitDirMap.containsKey("eclipse.pde.ui")) {
gitDirMap.put("eclipse.pde", gitDirMap.get("eclipse.pde.ui"));
}
if (gitDirMap.containsKey("eclipse.platform.releng.aggregator")) {
gitDirMap.put("eclipse.platform.releng",
new File(gitDirMap.get("eclipse.platform.releng.aggregator"), "eclipse.platform.releng"));
}

for (Entry<String, File> entry : badDirMap.entrySet()) {
String dirName = entry.getKey();
File badDir = entry.getValue();
File repoDir = gitDirMap.get(dirName);
if (repoDir == null) {
System.err.println("Repo " + dirName + " not found in " + rootReposDir);
continue;
}

if (repoDir.isDirectory()) {
updateRepo(badDir, repoDir);
} else {
System.err.println("Repo " + repoDir + " is not a directory in " + rootReposDir);
}
}
}

private static void updateRepo(File badDir, File repoDir) {
System.out.println("Checking " + badDir + " -> " + repoDir);
File[] dirs = badDir.listFiles();
if (dirs == null) {
System.err.println("No children at " + badDir);
return;
}
for (File dir : dirs) {
File gitDir = new File(repoDir, dir.getName());
if (isBundleWithChanges(dir)) {
updateFQU(gitDir);
} else {
updateRepo(new File(badDir, dir.getName()), gitDir);
}
}
}

private static void updateFQU(File bundleRoot) {
if (!bundleRoot.isDirectory()) {
System.err.println("\tCan't update non existing directory " + bundleRoot);
return;
}
System.out.println("\tUpdating " + bundleRoot);
boolean versionBumped = VersionBump.run(bundleRoot.toPath(), releaseTag);
if (versionBumped) {
System.out.println("No need to update " + FQU_FILE);
return;
}
File fquFile = new File(bundleRoot, FQU_FILE);
try {
boolean created;
if (!fquFile.exists()) {
created = true;
Files.createFile(fquFile.toPath());
} else {
created = false;
}
Path path = fquFile.toPath();
String content = Files.readString(path);
if (content.endsWith(ticketMessage)) {
// already updated
System.out.println("\t\tAlready updated: " + fquFile);
return;
}
if (created) {
System.out.println("\t\tWill create new file: " + fquFile);
} else {
System.out.println("\t\tWill update file: " + fquFile);
}
if (content.endsWith("\n")) {
Files.write(path, ticketMessage.getBytes(), StandardOpenOption.APPEND);
} else {
Files.write(path, ("\n" + ticketMessage).getBytes(), StandardOpenOption.APPEND);
}
} catch (Exception e) {
System.err.println("Failed to update file " + fquFile);
}
}

private static boolean isBundleWithChanges(File dir) {
return dir.isDirectory() && new File(dir, "target").isDirectory();
}


}
@@ -0,0 +1,173 @@
/*******************************************************************************
* Copyright (c) 2024 Andrey Loskutov <loskutov@gmx.de> and others.
*
* This program and the accompanying materials
* are made available under the terms of the Eclipse Public License 2.0
* which accompanies this distribution, and is available at
* https://www.eclipse.org/legal/epl-2.0/
*
* SPDX-License-Identifier: EPL-2.0
*
* Contributors:
* Andrey Loskutov <loskutov@gmx.de> - initial API and implementation
*******************************************************************************/
package org.eclipse.releng.tools;

import java.io.IOException;
import java.nio.charset.StandardCharsets;
import java.nio.file.Files;
import java.nio.file.Path;
import java.nio.file.Paths;
import java.util.Objects;
import java.util.regex.Matcher;
import java.util.regex.Pattern;

import org.eclipse.jgit.errors.RevisionSyntaxException;
import org.eclipse.jgit.lib.ObjectId;
import org.eclipse.jgit.lib.ObjectLoader;
import org.eclipse.jgit.lib.ObjectReader;
import org.eclipse.jgit.lib.Repository;
import org.eclipse.jgit.revwalk.RevCommit;
import org.eclipse.jgit.revwalk.RevWalk;
import org.eclipse.jgit.storage.file.FileRepositoryBuilder;
import org.eclipse.jgit.treewalk.TreeWalk;
import org.osgi.framework.Version;

@SuppressWarnings("nls")
public class VersionBump {

/**
* Checks if the version bump needed for given bundle, and if needed, bumps
* micro segment in manifest and pom
*
* @param args first argument is bundle root path to check, second version SDK
* release tag like 'R4_31'
*/
public static void main(String[] args) {
if (args.length != 2) {
System.out.println("Arguments: first is path to the bundle root, \n" + "second is the release tag");
System.exit(1);
}
run(Paths.get(args[0]), args[1]);
}

/**
*
* @param bundleRoot
* @param releaseTag
* @return true if manifest and pom (if exists) were updated
*/
public static boolean run(Path bundleRoot, String releaseTag) {
if (!Files.isDirectory(bundleRoot)) {
System.err.println("Bundle root is not a directory: " + bundleRoot);
return false;
}
if (releaseTag == null || releaseTag.isBlank()) {
System.err.println("Release tag missing");
return false;
}

String manifestPath = "META-INF/MANIFEST.MF";
String pomPath = "pom.xml";

String oldManifestContent = readFileAtTag(bundleRoot, manifestPath, releaseTag);
String oldTagVersion = getVersionFromManifest(oldManifestContent);
System.out.println("Version at tag " + releaseTag + ": " + oldTagVersion);

String currentManifestContent = readCurrentFile(bundleRoot, manifestPath);
String currentVersion = getVersionFromManifest(currentManifestContent);
System.out.println("Version checked out : " + currentVersion);

if (currentVersion != null && Objects.equals(oldTagVersion, currentVersion)) {
Version cv = new Version(currentVersion);
Version updated = new Version(cv.getMajor(), cv.getMinor(), cv.getMicro() + 100, cv.getQualifier());
System.out.println("Update to: " + updated);
String newManifest = oldManifestContent.replace("Bundle-Version: " + oldTagVersion,
"Bundle-Version: " + updated);

writeFile(bundleRoot, manifestPath, newManifest);
System.out.println("Updated META-INF/MANIFEST.MF in " + bundleRoot);

String currentPomContent = readCurrentFile(bundleRoot, pomPath);
if (currentPomContent != null) {
String newPom = currentPomContent.replace("<version>" + oldTagVersion, "<version>" + updated);
writeFile(bundleRoot, pomPath, newPom);
System.out.println("Updated pom.xml in " + bundleRoot);
}
return true;
} else {
System.out.println("No version bump needed");
return false;
}

}

private static void writeFile(Path bundleRoot, String manifestPath, String newManifest) {
try {
Files.write(bundleRoot.resolve(manifestPath), newManifest.getBytes(StandardCharsets.UTF_8));
} catch (IOException e) {
e.printStackTrace();
}
}

private static String readCurrentFile(Path bundleRoot, String relativePath) {
try {
return Files.readString(bundleRoot.resolve(relativePath), StandardCharsets.UTF_8);
} catch (IOException e) {
e.printStackTrace();
}
return null;
}

private static Pattern VERSION_PATTERN = Pattern.compile(".*Bundle-Version: (\\d+\\.\\d+\\.\\d+).*",
Pattern.DOTALL);

private static String getVersionFromManifest(String oldManifestContent) {
if (oldManifestContent == null) {
return null;
}
Matcher matcher = VERSION_PATTERN.matcher(oldManifestContent);
if (matcher.matches()) {
return matcher.group(1);
}
return null;
}

private static String readFileAtTag(Path filePath, String fileInBundle, String releaseTag) {
try {
FileRepositoryBuilder repoBuilder = new FileRepositoryBuilder();
repoBuilder.findGitDir(filePath.toFile());
try (Repository repository = repoBuilder.build()) {
Path workDir = repository.getWorkTree().toPath();
Path repoRelativePath = workDir.relativize(filePath.resolve(fileInBundle));
String pathInGit = repoRelativePath.toString().replace('\\', '/');

ObjectId treeId = repository.resolve(releaseTag);
if (treeId == null) {
System.err.println("Unable to find tag " + releaseTag + " in repo " + workDir);
return null;
}
try (RevWalk revWalk = new RevWalk(repository)) {
RevCommit commit = revWalk.parseCommit(treeId);
System.out.println(
"Checking repo " + workDir + " at commit " + commit.getName() + " : '"
+ commit.getShortMessage() + "'");
TreeWalk treeWalk = TreeWalk.forPath(repository, pathInGit, commit.getTree());
ObjectId blobId = treeWalk.getObjectId(0);
ObjectLoader objectLoader = loadObject(blobId, repository);
byte[] bytes = objectLoader.getBytes();
return new String(bytes, StandardCharsets.UTF_8);
}
}
} catch (IllegalStateException | RevisionSyntaxException | IOException e) {
e.printStackTrace();
}
return null;
}

private static ObjectLoader loadObject(ObjectId objectId, Repository repository) throws IOException {
try (ObjectReader objectReader = repository.newObjectReader()) {
return objectReader.open(objectId);
}
}
}

0 comments on commit 0cc5888

Please sign in to comment.