@Override protected int act(List<AbstractBuild<?, ?>> builds) throws IOException { // Loading job for this CLI command requires Item.READ permission. // No other permission check needed. switch (format) { case XML: PrintWriter w = new PrintWriter(stdout); w.println("<changes>"); for (AbstractBuild build : builds) { w.println("<build number='" + build.getNumber() + "'>"); ChangeLogSet<?> cs = build.getChangeSet(); Model p = new ModelBuilder().get(cs.getClass()); p.writeTo(cs, Flavor.XML.createDataWriter(cs, w)); w.println("</build>"); } w.println("</changes>"); w.flush(); break; case CSV: for (AbstractBuild build : builds) { ChangeLogSet<?> cs = build.getChangeSet(); for (Entry e : cs) { stdout.printf( "%s,%s%n", QuotedStringTokenizer.quote(e.getAuthor().getId()), QuotedStringTokenizer.quote(e.getMsg())); } } break; case PLAIN: for (AbstractBuild build : builds) { ChangeLogSet<?> cs = build.getChangeSet(); for (Entry e : cs) { stdout.printf("%s\t%s%n", e.getAuthor(), e.getMsg()); for (String p : e.getAffectedPaths()) stdout.println(" " + p); } } break; } return 0; }
/** Exposes the bean as XML. */ public void doXml( StaplerRequest req, StaplerResponse rsp, @QueryParameter String xpath, @QueryParameter String wrapper, @QueryParameter String tree, @QueryParameter int depth) throws IOException, ServletException { setHeaders(rsp); String[] excludes = req.getParameterValues("exclude"); if (xpath == null && excludes == null) { // serve the whole thing rsp.serveExposedBean(req, bean, Flavor.XML); return; } StringWriter sw = new StringWriter(); // first write to String Model p = MODEL_BUILDER.get(bean.getClass()); TreePruner pruner = (tree != null) ? new NamedPathPruner(tree) : new ByDepth(1 - depth); p.writeTo(bean, pruner, Flavor.XML.createDataWriter(bean, sw)); // apply XPath Object result; try { Document dom = new SAXReader().read(new StringReader(sw.toString())); // apply exclusions if (excludes != null) { for (String exclude : excludes) { List<org.dom4j.Node> list = (List<org.dom4j.Node>) dom.selectNodes(exclude); for (org.dom4j.Node n : list) { Element parent = n.getParent(); if (parent != null) parent.remove(n); } } } if (xpath == null) { result = dom; } else { List list = dom.selectNodes(xpath); if (wrapper != null) { Element root = DocumentFactory.getInstance().createElement(wrapper); for (Object o : list) { if (o instanceof String) { root.addText(o.toString()); } else { root.add(((org.dom4j.Node) o).detach()); } } result = root; } else if (list.isEmpty()) { rsp.setStatus(HttpServletResponse.SC_NOT_FOUND); rsp.getWriter().print(Messages.Api_NoXPathMatch(xpath)); return; } else if (list.size() > 1) { rsp.setStatus(HttpServletResponse.SC_INTERNAL_SERVER_ERROR); rsp.getWriter().print(Messages.Api_MultipleMatch(xpath, list.size())); return; } else { result = list.get(0); } } } catch (DocumentException e) { LOGGER.log(Level.FINER, "Failed to do XPath/wrapper handling. XML is as follows:" + sw, e); throw new IOException2( "Failed to do XPath/wrapper handling. Turn on FINER logging to view XML.", e); } OutputStream o = rsp.getCompressedOutputStream(req); try { if (result instanceof CharacterData || result instanceof String || result instanceof Number || result instanceof Boolean) { if (INSECURE) { rsp.setContentType("text/plain;charset=UTF-8"); String text = result instanceof CharacterData ? ((CharacterData) result).getText() : result.toString(); o.write(text.getBytes("UTF-8")); } else { rsp.sendError( HttpURLConnection.HTTP_FORBIDDEN, "primitive XPath result sets forbidden; can use -Dhudson.model.Api.INSECURE=true if you run without security"); } return; } // otherwise XML rsp.setContentType("application/xml;charset=UTF-8"); new XMLWriter(o).write(result); } finally { o.close(); } }