Skip to content

Commit

Permalink
Added automatic tool installation for Ant.
Browse files Browse the repository at this point in the history
- Most of the installer logic is made reusable in DownloadFromUrlInstaller.
- ToolDescriptor can now contribute global.jelly to the system configuration page.

git-svn-id: https://hudson.dev.java.net/svn/hudson/trunk/hudson/main@18260 71c3de6d-444a-0410-be80-ed276b4c234a
  • Loading branch information
kohsuke committed May 21, 2009
1 parent 46b540e commit 49ace47
Show file tree
Hide file tree
Showing 20 changed files with 424 additions and 91 deletions.
35 changes: 31 additions & 4 deletions core/src/main/java/hudson/model/DownloadService.java
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@
import hudson.ExtensionPoint;
import hudson.util.QuotedStringTokenizer;
import hudson.util.TextFile;
import hudson.util.TimeUnit2;
import org.kohsuke.stapler.QueryParameter;
import org.kohsuke.stapler.Stapler;

Expand Down Expand Up @@ -39,7 +40,7 @@ public String generateFragment() {
long now = System.currentTimeMillis();
for (Downloadable d : Downloadable.all()) {
if(d.getDue()<now) {
buf.append("<script>downloadService.download(")
buf.append("<script>downloadService.download(")
.append(QuotedStringTokenizer.quote(d.getId()))
.append(',')
.append(QuotedStringTokenizer.quote(d.getUrl()))
Expand Down Expand Up @@ -75,7 +76,7 @@ public Downloadable getById(String id) {
*
* @since 1.305
*/
public static abstract class Downloadable implements ExtensionPoint {
public static class Downloadable implements ExtensionPoint {
private final String id;
private final String url;
private final long interval;
Expand All @@ -91,12 +92,27 @@ public static abstract class Downloadable implements ExtensionPoint {
* For security and privacy reasons, we don't allow the retrieval
* from random locations.
*/
protected Downloadable(String id, String url, long interval) {
public Downloadable(String id, String url, long interval) {
this.id = id;
this.url = url;
this.interval = interval;
}

/**
* Uses the class name as an ID.
*/
public Downloadable(Class id) {
this(id.getName().replace('$','.'));
}

public Downloadable(String id) {
this(id,id+".json");
}

public Downloadable(String id, String url) {
this(id,url,TimeUnit2.DAYS.toMillis(1));
}

public String getId() {
return id;
}
Expand All @@ -105,7 +121,7 @@ public String getId() {
* URL to download.
*/
public String getUrl() {
return Hudson.getInstance().getUpdateCenter().getUrl()+url;
return Hudson.getInstance().getUpdateCenter().getUrl()+"updates/"+url;
}

/**
Expand Down Expand Up @@ -167,6 +183,17 @@ public static ExtensionList<Downloadable> all() {
return Hudson.getInstance().getExtensionList(Downloadable.class);
}

/**
* Returns the {@link Downloadable} that has the given ID.
*/
public static Downloadable get(String id) {
for (Downloadable d : all()) {
if(d.id.equals(id))
return d;
}
return null;
}

private static final Logger LOGGER = Logger.getLogger(Downloadable.class.getName());
}
}
5 changes: 5 additions & 0 deletions core/src/main/java/hudson/model/Hudson.java
Original file line number Diff line number Diff line change
Expand Up @@ -45,6 +45,8 @@
import hudson.DescriptorExtensionList;
import hudson.ExtensionListView;
import hudson.Extension;
import hudson.tools.ToolInstallation;
import hudson.tools.ToolDescriptor;
import hudson.cli.CliEntryPoint;
import hudson.cli.CLICommand;
import hudson.cli.HelpCommand;
Expand Down Expand Up @@ -2209,6 +2211,9 @@ public synchronized void doConfigSubmit( StaplerRequest req, StaplerResponse rsp
for( PageDecorator d : PageDecorator.all() )
result &= configureDescriptor(req,json,d);

for( ToolDescriptor d : ToolInstallation.all() )
result &= configureDescriptor(req,json,d);

for( JSONObject o : StructuredForm.toList(json,"plugin"))
pluginManager.getPlugin(o.getString("name")).getPlugin().configure(req, o);

Expand Down
2 changes: 1 addition & 1 deletion core/src/main/java/hudson/model/UsageStatistics.java
Original file line number Diff line number Diff line change
Expand Up @@ -229,5 +229,5 @@ public CombinedCipherInputStream(InputStream in, Cipher asym, String algorithm,

private static final long DAY = DAYS.toMillis(1);

public static boolean DISABLED = Boolean.getBoolean(UsageStatistics.class.getName()+".disable");
public static boolean DISABLED = Boolean.getBoolean(UsageStatistics.class.getName()+".disabled");
}
132 changes: 89 additions & 43 deletions core/src/main/java/hudson/tasks/Ant.java
Original file line number Diff line number Diff line change
Expand Up @@ -41,6 +41,9 @@
import hudson.slaves.NodeSpecific;
import hudson.tools.ToolDescriptor;
import hudson.tools.ToolInstallation;
import hudson.tools.DownloadFromUrlInstaller;
import hudson.tools.ToolInstaller;
import hudson.tools.ToolProperty;
import hudson.util.ArgumentListBuilder;
import hudson.util.VariableResolver;
import hudson.util.FormValidation;
Expand All @@ -53,6 +56,8 @@
import java.io.IOException;
import java.util.Map;
import java.util.Properties;
import java.util.List;
import java.util.Collections;

/**
* Ant launcher.
Expand Down Expand Up @@ -185,7 +190,7 @@ public boolean perform(AbstractBuild<?,?> build, Launcher launcher, BuildListene
args.addTokenized(targets.replaceAll("[\t\r\n]+"," "));

if(ai!=null)
env.put("ANT_HOME",ai.getAntHome());
env.put("ANT_HOME",ai.getHome());
if(antOpts!=null)
env.put("ANT_OPTS",env.expand(antOpts));

Expand Down Expand Up @@ -253,14 +258,21 @@ public DescriptorImpl() {
load();
}

public boolean isApplicable(Class<? extends AbstractProject> jobType) {
return true;
}

protected DescriptorImpl(Class<? extends Ant> clazz) {
super(clazz);
}

/**
* Obtains the {@link AntInstallation.DescriptorImpl} instance.
*/
public AntInstallation.DescriptorImpl getToolDescriptor() {
return ToolInstallation.all().get(AntInstallation.DescriptorImpl.class);
}

public boolean isApplicable(Class<? extends AbstractProject> jobType) {
return true;
}

protected void convert(Map<String,Object> oldPropertyBag) {
if(oldPropertyBag.containsKey("installations"))
installations = (AntInstallation[]) oldPropertyBag.get("installations");
Expand All @@ -278,56 +290,36 @@ public AntInstallation[] getInstallations() {
return installations;
}

@Override
public boolean configure(StaplerRequest req, JSONObject json) throws FormException {
installations = req.bindJSONToList(
AntInstallation.class, json.get("ant")).toArray(new AntInstallation[0]);
save();
return true;
}

public Ant newInstance(StaplerRequest req, JSONObject formData) throws FormException {
return (Ant)req.bindJSON(clazz,formData);
}

//
// web methods
//
/**
* Checks if the ANT_HOME is valid.
*/
public FormValidation doCheckAntHome(@QueryParameter File value) {
// this can be used to check the existence of a file on the server, so needs to be protected
if(!Hudson.getInstance().hasPermission(Hudson.ADMINISTER))
return FormValidation.ok();

if(!value.isDirectory())
return FormValidation.error(Messages.Ant_NotADirectory(value));

File antJar = new File(value,"lib/ant.jar");
if(!antJar.exists())
return FormValidation.error(Messages.Ant_NotAntDirectory(value));

return FormValidation.ok();
}

public void setInstallations(AntInstallation... antInstallations) {
this.installations = antInstallations;
save();
}
}

/**
* Represents the Ant installation on the system.
*/
public static final class AntInstallation extends ToolInstallation implements
EnvironmentSpecific<AntInstallation>, NodeSpecific<AntInstallation> {
// to remain backward compatible with earlier Hudson that stored this field here.
private final String antHome;

@DataBoundConstructor
public AntInstallation(String name, String home, List<? extends ToolProperty<?>> properties) {
super(name, launderHome(home), properties);
this.antHome = super.getHome();
}

/**
* @deprecated as of 1.308
* Use {@link #AntInstallation(String, String, List)}
*/
public AntInstallation(String name, String home) {
super(name, launderHome(home));
if(home.endsWith("/") || home.endsWith("\\"))
// see https://issues.apache.org/bugzilla/show_bug.cgi?id=26947
// Ant doesn't like the trailing slash, especially on Windows
home = home.substring(0,home.length()-1);
this.antHome = home;
this(name,home,Collections.<ToolProperty<?>>emptyList());
}

private static String launderHome(String home) {
Expand All @@ -342,6 +334,8 @@ private static String launderHome(String home) {

/**
* install directory.
*
* @deprecated as of 1.307. Use {@link #getHome()}.
*/
public String getAntHome() {
return getHome();
Expand Down Expand Up @@ -388,11 +382,11 @@ public boolean getExists() throws IOException, InterruptedException {
private static final long serialVersionUID = 1L;

public AntInstallation forEnvironment(EnvVars environment) {
return new AntInstallation(getName(), environment.expand(antHome));
return new AntInstallation(getName(), environment.expand(antHome), getProperties().toList());
}

public AntInstallation forNode(Node node, TaskListener log) throws IOException, InterruptedException {
return new AntInstallation(getName(), translateFor(node, log));
return new AntInstallation(getName(), translateFor(node, log), getProperties().toList());
}

@Extension
Expand All @@ -403,6 +397,7 @@ public String getDisplayName() {
return "Ant";
}

// for compatibility reasons, the persistence is done by Ant.DescriptorImpl
@Override
public AntInstallation[] getInstallations() {
return Hudson.getInstance().getDescriptorByType(Ant.DescriptorImpl.class).getInstallations();
Expand All @@ -412,7 +407,58 @@ public AntInstallation[] getInstallations() {
public void setInstallations(AntInstallation... installations) {
Hudson.getInstance().getDescriptorByType(Ant.DescriptorImpl.class).setInstallations(installations);
}

@Override
public List<? extends ToolInstaller> getDefaultInstallers() {
return Collections.singletonList(new AntInstaller(null));
}

@Override
public boolean configure(StaplerRequest req, JSONObject json) throws FormException {
setInstallations(req.bindJSONToList(
AntInstallation.class, json.get("ant")).toArray(new AntInstallation[0]));
return true;
}

/**
* Checks if the ANT_HOME is valid.
*/
public FormValidation doCheckHome(@QueryParameter File value) {
// this can be used to check the existence of a file on the server, so needs to be protected
if(!Hudson.getInstance().hasPermission(Hudson.ADMINISTER))
return FormValidation.ok();

if(!value.isDirectory())
return FormValidation.error(Messages.Ant_NotADirectory(value));

File antJar = new File(value,"lib/ant.jar");
if(!antJar.exists())
return FormValidation.error(Messages.Ant_NotAntDirectory(value));

return FormValidation.ok();
}
}
}

/**
* Automatic Ant installer from apache.org.
*/
public static class AntInstaller extends DownloadFromUrlInstaller {
@DataBoundConstructor
public AntInstaller(String id) {
super(id);
}

@Extension
public static final class DescriptorImpl extends DownloadFromUrlInstaller.DescriptorImpl<AntInstaller> {
public String getDisplayName() {
return "Install from Apache";
}

}
@Override
public boolean isApplicable(Class<? extends ToolInstallation> toolType) {
return toolType==AntInstallation.class;
}
}
}
}

0 comments on commit 49ace47

Please sign in to comment.