View Javadoc

1   /*
2    *  LICENSE
3    *
4    * "THE BEER-WARE LICENSE" (Revision 43):
5    * "Sven Strittmatter" <weltraumschaf@googlemail.com> wrote this file.
6    * As long as you retain this notice you can do whatever you want with
7    * this stuff. If we meet some day, and you think this stuff is worth it,
8    * you can buy me a non alcohol-free beer in return.
9    *
10   * Copyright (C) 2012 "Sven Strittmatter" <weltraumschaf@googlemail.com>
11   */
12  package org.jenkinsci.plugins.darcs;
13  
14  import hudson.Extension;
15  import hudson.Launcher;
16  import hudson.Util;
17  import hudson.XmlFile;
18  import hudson.model.Hudson;
19  import hudson.model.TaskListener;
20  import hudson.scm.RepositoryBrowser;
21  import hudson.scm.SCM;
22  import hudson.scm.SCMDescriptor;
23  import hudson.util.FormValidation;
24  import java.io.File;
25  import java.io.IOException;
26  import java.lang.reflect.Field;
27  import java.util.logging.Level;
28  import static java.util.logging.Level.WARNING;
29  import java.util.logging.Logger;
30  import jenkins.model.Jenkins;
31  import net.sf.json.JSONObject;
32  import org.jenkinsci.plugins.darcs.browsers.DarcsRepositoryBrowser;
33  import org.kohsuke.stapler.QueryParameter;
34  import org.kohsuke.stapler.StaplerRequest;
35  import org.kohsuke.stapler.framework.io.ByteBuffer;
36  
37  /**
38   * Inner class of the SCM descriptor.
39   *
40   * Contains the global configuration options as fields.
41   *
42   * @author Sven Strittmatter <weltraumschaf@googlemail.com>
43   */
44  @Extension
45  public class DarcsScmDescriptor extends SCMDescriptor<DarcsScm> {
46  
47      /**
48       * Logging facility.
49       */
50      private static final Logger LOGGER = Logger.getLogger(DarcsScmDescriptor.class.getName());
51      /**
52       * String displayed in the Jenkins front end.
53       */
54      private static final String DISPLAY_NAME = "Darcs";
55      /**
56       * Default name of the Darcs binary.
57       */
58      private static final String DEFAULT_EXE = "darcs";
59      /**
60       * The executable.
61       *
62       * May be null.
63       */
64      private String darcsExe;
65  
66      /**
67       * Dedicated constructor.
68       */
69      public DarcsScmDescriptor() {
70          super(DarcsScm.class, DarcsRepositoryBrowser.class);
71          load();
72      }
73  
74      /**
75       * Own implementation of XML configuration loading to inject {@link Jenkins#XSTREAM2} for unmarshalling.
76       *
77       * TODO Remove this, if it possible to inject XStream into parent implementation.
78       *      Since 1.494 Dexcriptor#getConfigFile() is not private anymore. override load()
79       *      and call getConfigFile().getXStream().addCompatibilityAlias()
80       *
81       * <code>
82       * public void load() {
83       *      getConfigFile().getXStream().addCompatibilityAlias("org.jenkinsci.plugins.darcs.DarcsScm$DescriptorImpl",
84       *                                                         DarcsScmDescriptor.class);
85       *      super.load();
86       * }
87       * </code>
88       */
89      @Override
90      public void load() {
91          final XmlFile file = new XmlFile(Jenkins.XSTREAM2,
92                                           new File(Jenkins.getInstance().getRootDir(), getId() + ".xml"));
93          if (!file.exists()) {
94              return;
95          }
96  
97          try {
98              file.unmarshal(this);
99          } catch (IOException e) {
100             LOGGER.log(Level.WARNING, "Failed to load " + file, e);
101         }
102 
103         final Class<? extends RepositoryBrowser> rb = repositoryBrowser;
104         if (repositoryBrowser != rb) { // XStream may overwrite even the final field.
105             try {
106                 final Field f = SCMDescriptor.class.getDeclaredField("repositoryBrowser");
107                 f.setAccessible(true);
108                 f.set(this, rb);
109             } catch (NoSuchFieldException e) {
110                 LOGGER.log(WARNING, "Failed to overwrite the repositoryBrowser field", e);
111             } catch (IllegalAccessException e) {
112                 LOGGER.log(WARNING, "Failed to overwrite the repositoryBrowser field", e);
113             }
114         }
115     }
116 
117     /**
118      * Returns the display name.
119      *
120      * @return display name string
121      */
122     public String getDisplayName() {
123         return DISPLAY_NAME;
124     }
125 
126     /**
127      * Returns the executable.
128      *
129      * @return if {@link #darcsExe} is {@code null} {@link #DEFAULT_EXE} will be returned
130      */
131     public String getDarcsExe() {
132         return null == darcsExe
133                 ? DEFAULT_EXE
134                 : darcsExe;
135     }
136 
137     @Override
138     public SCM newInstance(StaplerRequest req, JSONObject formData) throws FormException {
139         return super.newInstance(req, formData);
140     }
141 
142     @Override
143     public boolean configure(final StaplerRequest req, final JSONObject formData) throws FormException {
144         darcsExe = Util.fixEmpty(req.getParameter("darcs.darcsExe").trim());
145         save();
146 
147         return true;
148     }
149 
150     /**
151      * Validated the given executable string if it is a valid Darcs executable.
152      *
153      * @param value string from the plugin configuration field
154      * @return validation object which indicates validation state
155      */
156     public FormValidation doDarcsExeCheck(@QueryParameter final String value) {
157         return FormValidation.validateExecutable(value, new FormValidation.FileValidator() {
158             @Override
159             public FormValidation validate(final File exe) {
160                 try {
161                     final Launcher launcher = Hudson.getInstance().createLauncher(TaskListener.NULL);
162                     final Launcher.ProcStarter proc = launcher.launch()
163                             .cmds(exe, "--version")
164                             .stdout(new ByteBuffer());
165 
166                     if (proc.join() == 0) {
167                         return FormValidation.ok();
168                     } else {
169                         return FormValidation.warning("Could not locate the executable in path");
170                     }
171                 } catch (IOException e) {
172                     // failed
173                     LOGGER.log(Level.WARNING, e.toString());
174                 } catch (InterruptedException e) {
175                     // failed
176                     LOGGER.log(Level.WARNING, e.toString());
177                 }
178 
179                 return FormValidation.error("Unable to check darcs version");
180             }
181         });
182     }
183 }