Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Writing checksum to plugins lock file #662

Open
wants to merge 6 commits into
base: master
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,7 @@
import java.net.MalformedURLException;
import java.net.URL;
import java.nio.file.Files;
import java.nio.file.Path;
import java.util.ArrayList;
import java.util.List;
import java.util.Properties;
Expand Down Expand Up @@ -162,6 +163,7 @@ class CliOptions {
*/
Config setup() {
return Config.builder()
.withPluginFile(getPluginFilePath())
.withPlugins(getPlugins())
.withPluginDir(getPluginDir())
.withCleanPluginsDir(isCleanPluginDir())
Expand Down Expand Up @@ -210,6 +212,14 @@ private File getPluginFile() {
}
return pluginFile;
}
private Path getPluginFilePath() {
File pluginFile = getPluginFile();
if (pluginFile != null) {
return pluginFile.toPath();
} else {
return null;
}
}

/**
* Gets the user specified plugin download directory from the CLI option and sets this in the configuration class
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,7 @@
* Defaults for update centers will be set for you
*/
public class Config {
private final Path pluginFilePath;
private final File pluginDir;
private final boolean cleanPluginDir;
private final boolean showWarnings;
Expand Down Expand Up @@ -58,6 +59,7 @@ public class Config {
private final LogOutput logOutput;

private Config(
Path pluginFilePath,
File pluginDir,
boolean cleanPluginDir,
boolean showWarnings,
Expand All @@ -81,6 +83,7 @@ private Config(
List<Credentials> credentials,
Path cachePath,
boolean hideWarnings) {
this.pluginFilePath = pluginFilePath;
this.pluginDir = pluginDir;
this.cleanPluginDir = cleanPluginDir;
this.showWarnings = showWarnings;
Expand All @@ -107,6 +110,9 @@ private Config(
this.hideWarnings = hideWarnings;
}

public Path getPluginFilePath(){
return pluginFilePath;
}
public File getPluginDir() {
return pluginDir;
}
Expand Down Expand Up @@ -214,6 +220,7 @@ public LogOutput getLogOutput() {
}

public static class Builder {
private Path pluginFilePath;
private File pluginDir;
private boolean cleanPluginDir;
private boolean showWarnings;
Expand Down Expand Up @@ -241,6 +248,10 @@ public static class Builder {
private Builder() {
}

public Builder withPluginFile(Path pluginFilePath) {
this.pluginFilePath = pluginFilePath;
return this;
}
public Builder withPluginDir(File pluginDir) {
this.pluginDir = pluginDir;
return this;
Expand Down Expand Up @@ -370,6 +381,7 @@ public Builder withCachePath(@NonNull Path cachePath) {

public Config build() {
return new Config(
pluginFilePath,
pluginDir,
cleanPluginDir,
showWarnings,
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
package io.jenkins.tools.pluginmanager.impl;

public enum FileType {
TXT,
YAML,
UNKNOWN
}
Original file line number Diff line number Diff line change
Expand Up @@ -27,6 +27,11 @@ public class Plugin {
private String checksum;
private VersionNumber jenkinsVersion;

public Plugin(String name, String version) {
this.name = name;
this.version = new VersionNumber(version);
}

public Plugin(String name, String version, String url, String groupId) {
this.name = name;
if (StringUtils.isEmpty(version)) {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -14,11 +14,13 @@
import io.jenkins.tools.pluginmanager.parsers.YamlPluginOutputConverter;
import io.jenkins.tools.pluginmanager.util.FileDownloadResponseHandler;
import io.jenkins.tools.pluginmanager.util.ManifestTools;
import java.io.BufferedWriter;
import java.io.Closeable;
import java.io.File;
import java.io.FileFilter;
import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.io.FileWriter;
import java.io.IOException;
import java.io.InputStream;
import java.io.UncheckedIOException;
Expand Down Expand Up @@ -90,6 +92,10 @@
public class PluginManager implements Closeable {
private static final VersionNumber LATEST = new VersionNumber(Plugin.LATEST);
private final List<Plugin> failedPlugins;
private final Path pluginFilePath;
private File pluginLockTxtFile;
private File pluginLockYamlFile;

/**
* Directory where the plugins will be downloaded
*/
Expand Down Expand Up @@ -126,6 +132,7 @@ public class PluginManager implements Closeable {
public PluginManager(Config cfg) {
this.cfg = cfg;
logOutput = cfg.getLogOutput();
pluginFilePath = cfg.getPluginFilePath();
pluginDir = cfg.getPluginDir();
jenkinsVersion = cfg.getJenkinsVersion();
final String warArg = cfg.getJenkinsWar();
Expand Down Expand Up @@ -181,6 +188,23 @@ private HttpClient getHttpClient() {
return httpClient;
}

public FileType getFileType(String filePath) {
int lastIndex = filePath.lastIndexOf('.');
if (lastIndex != -1) {
String extension = filePath.substring(lastIndex + 1);
switch (extension.toLowerCase()) {
case "txt":
return FileType.TXT;
case "yaml":
case "yml":
return FileType.YAML;
default:
return FileType.UNKNOWN;
}
}
return FileType.UNKNOWN;
}

/**
* Drives the process to download plugins. Calls methods to find installed plugins, download plugins, and output
* the failed plugins
Expand Down Expand Up @@ -234,6 +258,20 @@ public void start(boolean downloadUc) {
effectivePlugins = findEffectivePlugins(pluginsToBeDownloaded);

listPlugins();
//Generating and Writing to plugin lock file
FileType fileType = getFileType(String.valueOf(pluginFilePath));
switch (fileType) {
case YAML:
createPluginLockYamlFile();
writeToPluginLockYamlFile(allPluginsAndDependencies);
break;
case TXT:
createPluginLockTxtFile();
writeToPluginLockTxtFile(allPluginsAndDependencies);
break;
default:
System.err.println("Unsupported output format: " + cfg.getOutputFormat());
}
showSpecificSecurityWarnings(pluginsToBeDownloaded);
checkVersionCompatibility(jenkinsVersion, pluginsToBeDownloaded, exceptions);
if (!exceptions.isEmpty()) {
Expand All @@ -242,9 +280,63 @@ public void start(boolean downloadUc) {
if (cfg.doDownload()) {
downloadPlugins(pluginsToBeDownloaded);
}
// Show missing plugins
List<String> missingPlugins = checkPluginDependencies();
if (!missingPlugins.isEmpty()) {
logVerbose("The following plugins are missing from the list of plugins to be downloaded: " + missingPlugins);
}
logMessage("Done");
}

void createPluginLockTxtFile() {
if (pluginFilePath != null) {
Path pluginLockFilePath = pluginFilePath.resolveSibling("plugins-lock.txt");
pluginLockTxtFile = pluginLockFilePath.toFile();

try {
if (!pluginLockTxtFile.exists()) {
boolean created = pluginLockTxtFile.createNewFile();
if (created) {
logVerbose("plugins-lock.txt file created successfully: " + pluginLockTxtFile.getAbsolutePath());
} else {
logVerbose("plugins-lock.txt file already exists: " + pluginLockTxtFile.getAbsolutePath());
}
} else {
logVerbose("plugins-lock.txt file already exists: " + pluginLockTxtFile.getAbsolutePath());
}
} catch (IOException e) {
logVerbose("Error creating plugins-lock.txt file: " + e.getMessage());
e.printStackTrace();
}
} else {
logVerbose("Error: pluginFilePath is null. Cannot create plugins-lock.txt file.");
}
}
void createPluginLockYamlFile() {
if (pluginFilePath != null) {
Path pluginLockFilePath = pluginFilePath.resolveSibling("plugins-lock.yaml");
pluginLockYamlFile = pluginLockFilePath.toFile();

try {
if (!pluginLockYamlFile.exists()) {
boolean created = pluginLockYamlFile.createNewFile();
if (created) {
logVerbose("plugins-lock.yaml file created successfully: " + pluginLockYamlFile.getAbsolutePath());
} else {
logVerbose("plugins-lock.yaml file already exists: " + pluginLockYamlFile.getAbsolutePath());
}
} else {
logVerbose("plugins-lock.yaml file already exists: " + pluginLockYamlFile.getAbsolutePath());
}
} catch (IOException e) {
logVerbose("Error creating plugins-lock.yaml file: " + e.getMessage());
e.printStackTrace();
}
} else {
logVerbose("Error: pluginFilePath is null. Cannot create plugins-lock.yaml file");
}
}

void createPluginDir(boolean failIfExists) {
if (pluginDir.exists()) {
if (failIfExists) {
Expand Down Expand Up @@ -334,6 +426,63 @@ private void sortEffectivePlugins(Map<String, Plugin> effectivePlugins,
}
}

/**
* Writes the plugins and their versions to a plugin-lock.txt file.
*
* @param allPluginsAndDependencies List of plugins that will be downloaded.
*/
public void writeToPluginLockTxtFile(Map<String,Plugin> allPluginsAndDependencies) {
if (pluginLockTxtFile != null) {
try (BufferedWriter writer = new BufferedWriter(new FileWriter(pluginLockTxtFile,StandardCharsets.UTF_8))) {
for (Map.Entry<String, Plugin> entry : allPluginsAndDependencies.entrySet()) {
Plugin plugin = entry.getValue();
String pluginLine = String.format("%s:%s", plugin.getName(), plugin.getVersion());
writer.write(pluginLine);
writer.newLine();
}
logVerbose("plugins-lock.txt file (" + pluginLockTxtFile + ") has been successfully created.");
} catch (IOException e) {
e.printStackTrace();
}
} else {
logVerbose("pluginLockFile is null");
}
}
public void writeToPluginLockYamlFile(Map<String, Plugin> allPluginsAndDependencies) {
if (pluginLockYamlFile != null) {
try (BufferedWriter writer = new BufferedWriter(new FileWriter(pluginLockYamlFile, StandardCharsets.UTF_8))) {
writer.write("plugins:");
writer.newLine();
for (Map.Entry<String, Plugin> entry : allPluginsAndDependencies.entrySet()) {
Plugin plugin = entry.getValue();
writer.write(" - artifactId: " + plugin.getName());
writer.newLine();
writer.write(" source:");
writer.newLine();
if (plugin.getVersion() != null) {
writer.write(" version: " + plugin.getVersion());
writer.newLine();
}
if (plugin.getUrl() != null) {
writer.write(" url: " + plugin.getUrl());
writer.newLine();
}
// Calculate checksum
calculateChecksum(plugin);
if (plugin.getChecksum() != null) {
writer.write(" checksum: " + plugin.getChecksum());
writer.newLine();
}
}
logVerbose("plugins-lock.yaml file (" + pluginLockYamlFile + ") has been successfully created.");
} catch (IOException e) {
e.printStackTrace();
}
} else {
logVerbose("pluginLockFile is null");
}
}

/**
* Lists installed plugins, bundled plugins, set of all recurively determined requested plugins, which plugins will
* actually be downloaded based on the requested plugins and currently installed plugins, and the effective plugin
Expand Down Expand Up @@ -1174,6 +1323,30 @@ public Map<String, Plugin> resolveRecursiveDependencies(Plugin plugin, @CheckFor
return recursiveDependencies;
}

/**
* Compares allPluginsAndDependencies(excluding plugins which are already installed or bundled in the war) with pluginsToBeDownloaded
* @return list of missing plugins
*/
public List<String> checkPluginDependencies() {
List<String> missingPlugins = new ArrayList<>();
Set<String> remainingPlugins = new HashSet<>(allPluginsAndDependencies.keySet());
remainingPlugins.removeAll(bundledPluginVersions.keySet());
remainingPlugins.removeAll(installedPluginVersions.keySet());

Set<String> requiredPluginNames = new HashSet<>();
for (Plugin plugin : pluginsToBeDownloaded) {
requiredPluginNames.add(plugin.getName());
}

for (String pluginName : remainingPlugins) {
if (!requiredPluginNames.contains(pluginName)) {
missingPlugins.add(pluginName);
}
}

return missingPlugins;
}

/**
* Downloads a plugin, skipping if already installed or bundled in the war. A plugin's dependencies will be
* resolved after the plugin is downloaded/copied.
Expand Down
Loading
Loading