Skip to content

Commit

Permalink
Merge pull request #3364 from batmat/JENKINS-50164
Browse files Browse the repository at this point in the history
[JENKINS-50164] Remove UI option to modify WS and builds locations
  • Loading branch information
batmat committed Apr 24, 2018
2 parents e511ff8 + 84e423d commit a363f2e
Show file tree
Hide file tree
Showing 19 changed files with 555 additions and 431 deletions.
16 changes: 16 additions & 0 deletions core/src/main/java/jenkins/model/InvalidBuildsDir.java
@@ -0,0 +1,16 @@
package jenkins.model;

import hudson.util.BootFailure;

public class InvalidBuildsDir extends BootFailure {
private String message;

public InvalidBuildsDir(String message) {
this.message = message;
}

@Override
public String getMessage() {
return message;
}
}
157 changes: 112 additions & 45 deletions core/src/main/java/jenkins/model/Jenkins.java
Expand Up @@ -27,6 +27,7 @@
package jenkins.model;

import antlr.ANTLRException;
import com.google.common.annotations.VisibleForTesting;
import com.google.common.collect.ImmutableMap;
import com.google.common.collect.ImmutableSet;
import com.google.common.collect.Lists;
Expand Down Expand Up @@ -399,7 +400,7 @@ public class Jenkins extends AbstractCIBase implements DirectlyModifiableTopLeve
* This value will be variable-expanded as per {@link #expandVariablesForDirectory}.
* @see #getWorkspaceFor(TopLevelItem)
*/
private String workspaceDir = "${ITEM_ROOTDIR}/"+WORKSPACE_DIRNAME;
private String workspaceDir = OLD_DEFAULT_WORKSPACES_DIR;

/**
* Root directory for the builds.
Expand Down Expand Up @@ -846,7 +847,7 @@ protected Jenkins(File root, ServletContext context, PluginManager pluginManager

if (!new File(root,"jobs").exists()) {
// if this is a fresh install, use more modern default layout that's consistent with agents
workspaceDir = "${JENKINS_HOME}/workspace/${ITEM_FULL_NAME}";
workspaceDir = DEFAULT_WORKSPACES_DIR;
}

// doing this early allows InitStrategy to set environment upfront
Expand Down Expand Up @@ -2135,46 +2136,6 @@ public FormValidation doCheckNumExecutors(@QueryParameter String value) {
return FormValidation.validateNonNegativeInteger(value);
}

public FormValidation doCheckRawBuildsDir(@QueryParameter String value) {
// do essentially what expandVariablesForDirectory does, without an Item
String replacedValue = expandVariablesForDirectory(value,
"doCheckRawBuildsDir-Marker:foo",
Jenkins.getInstance().getRootDir().getPath() + "/jobs/doCheckRawBuildsDir-Marker$foo");

File replacedFile = new File(replacedValue);
if (!replacedFile.isAbsolute()) {
return FormValidation.error(value + " does not resolve to an absolute path");
}

if (!replacedValue.contains("doCheckRawBuildsDir-Marker")) {
return FormValidation.error(value + " does not contain ${ITEM_FULL_NAME} or ${ITEM_ROOTDIR}, cannot distinguish between projects");
}

if (replacedValue.contains("doCheckRawBuildsDir-Marker:foo")) {
// make sure platform can handle colon
try {
File tmp = File.createTempFile("Jenkins-doCheckRawBuildsDir", "foo:bar");
tmp.delete();
} catch (IOException e) {
return FormValidation.error(value + " contains ${ITEM_FULLNAME} but your system does not support it (JENKINS-12251). Use ${ITEM_FULL_NAME} instead");
}
}

File d = new File(replacedValue);
if (!d.isDirectory()) {
// if dir does not exist (almost guaranteed) need to make sure nearest existing ancestor can be written to
d = d.getParentFile();
while (!d.exists()) {
d = d.getParentFile();
}
if (!d.canWrite()) {
return FormValidation.error(value + " does not exist and probably cannot be created");
}
}

return FormValidation.ok();
}

// to route /descriptor/FQCN/xxx to getDescriptor(FQCN).xxx
public Object getDynamic(String token) {
return Jenkins.getInstance().getDescriptor(token);
Expand Down Expand Up @@ -2402,6 +2363,11 @@ public boolean isDefaultBuildDir() {
return DEFAULT_BUILDS_DIR.equals(buildsDir);
}

@Restricted(NoExternalUse.class)
boolean isDefaultWorkspaceDir() {
return OLD_DEFAULT_WORKSPACES_DIR.equals(workspaceDir) || DEFAULT_WORKSPACES_DIR.equals(workspaceDir);
}

private File expandVariablesForDirectory(String base, Item item) {
return new File(expandVariablesForDirectory(base, item.getFullName(), item.getRootDir().getPath()));
}
Expand Down Expand Up @@ -3033,6 +2999,87 @@ private void loadConfig() throws IOException {
// load from disk
cfg.unmarshal(Jenkins.this);
}

try {
checkRawBuildsDir(buildsDir);
setBuildsAndWorkspacesDir();
} catch (InvalidBuildsDir invalidBuildsDir) {
throw new IOException(invalidBuildsDir);
}

}

private void setBuildsAndWorkspacesDir() throws IOException, InvalidBuildsDir {
boolean mustSave = false;
String newBuildsDir = SystemProperties.getString(BUILDS_DIR_PROP);
if (newBuildsDir != null && !buildsDir.equals(newBuildsDir)) {

checkRawBuildsDir(newBuildsDir);
LOGGER.log(Level.WARNING, "Changing builds directories from {0} to {1}. Beware that no automated data migration will occur.",
new String[]{buildsDir, newBuildsDir});
buildsDir = newBuildsDir;
mustSave = true;
} else if (!isDefaultBuildDir()) {
LOGGER.log(Level.INFO, "Using non default builds directories: {0}.", buildsDir);
}

String newWorkspacesDir = SystemProperties.getString(WORKSPACES_DIR_PROP);
if (newWorkspacesDir != null && !workspaceDir.equals(newWorkspacesDir)) {
LOGGER.log(Level.WARNING, "Changing workspaces directories from {0} to {1}. Beware that no automated data migration will occur.",
new String[]{workspaceDir, newWorkspacesDir});
workspaceDir = newWorkspacesDir;
mustSave = true;
} else if (!isDefaultWorkspaceDir()) {
LOGGER.log(Level.INFO, "Using non default workspaces directories: {0}.", workspaceDir);
}

if (mustSave) {
save();
}
}

/**
* Checks the correctness of the newBuildsDirValue for use as {@link #buildsDir}.
* @param newBuildsDirValue the candidate newBuildsDirValue for updating {@link #buildsDir}.
*/
@VisibleForTesting
/*private*/ static void checkRawBuildsDir(String newBuildsDirValue) throws InvalidBuildsDir {

// do essentially what expandVariablesForDirectory does, without an Item
String replacedValue = expandVariablesForDirectory(newBuildsDirValue,
"doCheckRawBuildsDir-Marker:foo",
Jenkins.getInstance().getRootDir().getPath() + "/jobs/doCheckRawBuildsDir-Marker$foo");

File replacedFile = new File(replacedValue);
if (!replacedFile.isAbsolute()) {
throw new InvalidBuildsDir(newBuildsDirValue + " does not resolve to an absolute path");
}

if (!replacedValue.contains("doCheckRawBuildsDir-Marker")) {
throw new InvalidBuildsDir(newBuildsDirValue + " does not contain ${ITEM_FULL_NAME} or ${ITEM_ROOTDIR}, cannot distinguish between projects");
}

if (replacedValue.contains("doCheckRawBuildsDir-Marker:foo")) {
// make sure platform can handle colon
try {
File tmp = File.createTempFile("Jenkins-doCheckRawBuildsDir", "foo:bar");
tmp.delete();
} catch (IOException e) {
throw new InvalidBuildsDir(newBuildsDirValue + " contains ${ITEM_FULLNAME} but your system does not support it (JENKINS-12251). Use ${ITEM_FULL_NAME} instead");
}
}

File d = new File(replacedValue);
if (!d.isDirectory()) {
// if dir does not exist (almost guaranteed) need to make sure nearest existing ancestor can be written to
d = d.getParentFile();
while (!d.exists()) {
d = d.getParentFile();
}
if (!d.canWrite()) {
throw new InvalidBuildsDir(newBuildsDirValue + " does not exist and probably cannot be created");
}
}
}

private synchronized TaskBuilder loadTasks() throws IOException {
Expand Down Expand Up @@ -3636,9 +3683,6 @@ public synchronized void doConfigSubmit( StaplerRequest req, StaplerResponse rsp

JSONObject json = req.getSubmittedForm();

workspaceDir = json.getString("rawWorkspaceDir");
buildsDir = json.getString("rawBuildsDir");

systemMessage = Util.nullify(req.getParameter("system_message"));

boolean result = true;
Expand Down Expand Up @@ -5055,6 +5099,29 @@ private static void computeVersion(ServletContext context) {
* @see #getRawBuildsDir()
*/
private static final String DEFAULT_BUILDS_DIR = "${ITEM_ROOTDIR}/builds";
/**
* Old layout for workspaces.
* @see #DEFAULT_WORKSPACES_DIR
*/
private static final String OLD_DEFAULT_WORKSPACES_DIR = "${ITEM_ROOTDIR}/" + WORKSPACE_DIRNAME;

/**
* Default value for the workspace's directories layout.
* @see #workspaceDir
*/
private static final String DEFAULT_WORKSPACES_DIR = "${JENKINS_HOME}/workspace/${ITEM_FULL_NAME}";

/**
* System property name to set {@link #buildsDir}.
* @see #getRawBuildsDir()
*/
static final String BUILDS_DIR_PROP = Jenkins.class.getName() + ".buildsDir";

/**
* System property name to set {@link #workspaceDir}.
* @see #getRawWorkspaceDir()
*/
static final String WORKSPACES_DIR_PROP = Jenkins.class.getName() + ".workspacesDir";

/**
* Automatically try to launch an agent when Jenkins is initialized or a new agent computer is created.
Expand Down
8 changes: 0 additions & 8 deletions core/src/main/resources/jenkins/model/Jenkins/configure.jelly
Expand Up @@ -39,14 +39,6 @@ THE SOFTWARE.
<f:entry title="${%Home directory}" help="/help/system-config/homeDirectory.html">
${it.rootDir}
</f:entry>
<f:advanced>
<f:entry field="rawWorkspaceDir" title="${%Workspace Root Directory}">
<f:textbox/>
</f:entry>
<f:entry field="rawBuildsDir" title="${%Build Record Root Directory}">
<f:textbox/>
</f:entry>
</f:advanced>
<f:entry title="${%System Message}" help="/help/system-config/systemMessage.html">
<f:textarea name="system_message" value="${it.systemMessage}"
codemirror-mode="${app.markupFormatter.codeMirrorMode}" codemirror-config="${app.markupFormatter.codeMirrorConfig}" previewEndpoint="/markupFormatter/previewDescription"/>
Expand Down

This file was deleted.

This file was deleted.

This file was deleted.

This file was deleted.

This file was deleted.

This file was deleted.

0 comments on commit a363f2e

Please sign in to comment.