View Javadoc

1   /*
2    * LICENSE
3    *
4    * "THE BEER-WARE LICENSE" (Revision 42):
5    * "Sven Strittmatter" <ich@weltraumschaf.de> 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 beer in return.
9    */
10  package org.jenkinsci.plugins.darcs;
11  
12  import hudson.FilePath;
13  import hudson.Launcher;
14  import hudson.Launcher.ProcStarter;
15  import hudson.util.ArgumentListBuilder;
16  import java.io.ByteArrayOutputStream;
17  import java.util.Map;
18  
19  /**
20   * Abstracts the Darcs command.
21   *
22   * @author Sven Strittmatter <ich@weltraumschaf.de>
23   */
24  public class DarcsCmd {
25  
26      /**
27       * `darcs changes` command.
28       */
29      private static final String CMD_CHANGES = "changes";
30      /**
31       * `darcs pull` command.
32       */
33      private static final String CMD_PULL = "pull";
34      /**
35       * `darcs get` command.
36       */
37      private static final String CMD_GET = "get";
38      // Command options
39      private static final String OPT_REPO = "--repo=";
40      private static final String OPT_XML_OUTPUT = "--xml-output";
41      private static final String OPT_SUMMARY = "--summary";
42      private static final String OPT_LAST = "--last=";
43      private static final String OPT_REPODIR = "--repodir=";
44      private static final String OPT_COUNT = "--count";
45      private static final String OPT_ALL = "--all";
46      private static final String OPT_VERBOSE = "--verbose";
47      /**
48       * Used to start a process.
49       */
50      private final Launcher launcher;
51      /**
52       * Name of the Darcs executable binary.
53       */
54      private final String darcsExe;
55      /**
56       * Environment variables.
57       */
58      private final Map<String, String> envs;
59      private final FilePath workingDir;
60  
61      /**
62       * Creates a Darcs command object.
63       *
64       * @param launcher starts a process
65       * @param envs environment variables
66       * @param darcsExe executable name
67       */
68      public DarcsCmd(final Launcher launcher, final Map<String, String> envs, final String darcsExe, final FilePath workingDir) {
69          super();
70          this.envs = envs;
71          this.launcher = launcher;
72          this.darcsExe = darcsExe;
73          this.workingDir = workingDir;
74      }
75  
76      /**
77       * Creates process starter.
78       *
79       * @param args builds argument list for command
80       * @return a process starter object
81       */
82      public ProcStarter createProc(final ArgumentListBuilder args) {
83          final ProcStarter proc = launcher.launch();
84          proc.cmds(args);
85          proc.envs(envs);
86          proc.pwd(workingDir);
87          return proc;
88      }
89  
90      public ByteArrayOutputStream lastSummarizedChanges(final String repo, final int n) throws DarcsCmdException {
91          return getChanges(repo, true, n);
92      }
93  
94      public ByteArrayOutputStream allSummarizedChanges(final String repo) throws DarcsCmdException {
95          return getChanges(repo, true);
96      }
97  
98      public ByteArrayOutputStream allChanges(final String repo) throws DarcsCmdException {
99          return getChanges(repo, false);
100     }
101 
102     private ByteArrayOutputStream getChanges(final String repo, final boolean summarize) throws DarcsCmdException {
103         return getChanges(repo, summarize, 0);
104     }
105 
106     private ByteArrayOutputStream getChanges(final String repo, final boolean summarize, final int n)
107             throws DarcsCmdException {
108         final ArgumentListBuilder args = new ArgumentListBuilder();
109         args.add(darcsExe)
110                 .add(CMD_CHANGES)
111                 .add(OPT_REPO + repo)
112                 .add(OPT_XML_OUTPUT);
113 
114         if (summarize) {
115             args.add(OPT_SUMMARY);
116         }
117 
118         if (n > 0) {
119             args.add(OPT_LAST + n);
120         }
121 
122         final ProcStarter proc = createProc(args);
123         final ByteArrayOutputStream baos = new ByteArrayOutputStream();
124         proc.stdout(baos);
125 
126         try {
127             final int ret = proc.join();
128 
129             if (0 != ret) {
130                 throw new DarcsCmdException("can not do darcs changes in repo " + repo);
131             }
132         } catch (Exception ex) {
133             throw new DarcsCmdException("can not do darcs changes in repo " + repo, ex);
134         }
135 
136         return baos;
137     }
138 
139     public int countChanges(final String repo) throws DarcsCmdException {
140         final ArgumentListBuilder args = new ArgumentListBuilder();
141         args.add(darcsExe)
142                 .add(CMD_CHANGES)
143                 .add(OPT_REPODIR + repo)
144                 .add(OPT_COUNT);
145 
146         final ProcStarter proc = createProc(args);
147         final ByteArrayOutputStream baos = new ByteArrayOutputStream();
148         proc.stdout(baos);
149 
150         try {
151             final int ret = proc.join();
152 
153             if (0 != ret) {
154                 throw new DarcsCmdException("can not do darcs changes in repo " + repo);
155             }
156         } catch (Exception ex) {
157             throw new DarcsCmdException("can not do darcs changes in repo " + repo, ex);
158         }
159 
160         return Integer.parseInt(baos.toString().trim());
161     }
162 
163     public void pull(final String repo, final String from) throws DarcsCmdException {
164         final ArgumentListBuilder args = new ArgumentListBuilder();
165         args.add(darcsExe)
166                 .add(CMD_PULL)
167                 .add(from)
168                 .add(OPT_REPODIR + repo)
169                 .add(OPT_ALL)
170                 .add(OPT_VERBOSE);
171 
172         try {
173             final ProcStarter proc = createProc(args);
174             proc.stdout(this.launcher.getListener());
175             final int ret = proc.join();
176 
177             if (0 != ret) {
178                 throw new DarcsCmdException(String.format("Can't do darcs changes in repo %s! Return code: %d",
179                         repo, ret));
180             }
181         } catch (Exception ex) {
182             throw new DarcsCmdException(String.format("Can't do darcs changes in repo %s!", repo), ex);
183         }
184     }
185 
186     /**
187      * Do a fresh checkout of a repository.
188      *
189      * @param repo where to checkout
190      * @param from from where to get the repository
191      * @throws DarcsCmd.DarcsCmdException if can't do checkout
192      */
193     public void get(final String repo, final String from) throws DarcsCmdException {
194         final ArgumentListBuilder args = new ArgumentListBuilder();
195         args.add(darcsExe)
196                 .add(CMD_GET)
197                 .add(from)
198                 .add(repo);
199 
200         try {
201             final ProcStarter proc = createProc(args);
202             proc.stdout(this.launcher.getListener());
203             final int ret = proc.join();
204 
205             if (0 != ret) {
206                 throw new DarcsCmdException(String.format("Getting repo with args %s failed! Return code: %d",
207                         args.toStringWithQuote(), ret));
208             }
209         } catch (Exception ex) {
210             throw new DarcsCmdException(String.format("Can't get repo with args: %s", args.toStringWithQuote()), ex);
211         }
212     }
213 
214     /**
215      * Darcs command exception.
216      */
217     public static class DarcsCmdException extends RuntimeException {
218 
219         /**
220          * Creates exception with message.
221          *
222          * @param string exception message
223          */
224         public DarcsCmdException(final String string) {
225             super(string);
226         }
227 
228         /**
229          * Creates exception with message and a previous exception.
230          *
231          * @param string exception message
232          * @param thrwbl previous exception
233          */
234         public DarcsCmdException(final String string, final Throwable thrwbl) {
235             super(string, thrwbl);
236         }
237     }
238 }