1 /* 2 * Copyright (C) 2010 Google Inc. 3 * 4 * Licensed under the Apache License, Version 2.0 (the "License"); 5 * you may not use this file except in compliance with the License. 6 * You may obtain a copy of the License at 7 * 8 * http://www.apache.org/licenses/LICENSE-2.0 9 * 10 * Unless required by applicable law or agreed to in writing, software 11 * distributed under the License is distributed on an "AS IS" BASIS, 12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 * See the License for the specific language governing permissions and 14 * limitations under the License. 15 */ 16 17 package com.google.doclava.apicheck; 18 19 import java.io.FileInputStream; 20 import java.io.FileNotFoundException; 21 import java.io.IOException; 22 import java.io.InputStream; 23 import java.io.PrintStream; 24 import java.net.URL; 25 import java.util.ArrayList; 26 import java.util.Set; 27 import java.util.Stack; 28 29 import com.google.doclava.Errors; 30 import com.google.doclava.Errors.ErrorMessage; 31 import com.google.doclava.Stubs; 32 33 public class ApiCheck { 34 // parse out and consume the -whatever command line flags parseFlags(ArrayList<String> allArgs)35 private static ArrayList<String[]> parseFlags(ArrayList<String> allArgs) { 36 ArrayList<String[]> ret = new ArrayList<String[]>(); 37 38 int i; 39 for (i = 0; i < allArgs.size(); i++) { 40 // flags with one value attached 41 String flag = allArgs.get(i); 42 if (flag.equals("-error") || flag.equals("-warning") || flag.equals("-hide")) { 43 String[] arg = new String[2]; 44 arg[0] = flag; 45 arg[1] = allArgs.get(++i); 46 ret.add(arg); 47 } else { 48 // we've consumed all of the -whatever args, so we're done 49 break; 50 } 51 } 52 53 // i now points to the first non-flag arg; strip what came before 54 for (; i > 0; i--) { 55 allArgs.remove(0); 56 } 57 return ret; 58 } 59 main(String[] originalArgs)60 public static void main(String[] originalArgs) { 61 if (originalArgs.length == 3 && "-convert".equals(originalArgs[0])) { 62 System.exit(convertToApi(originalArgs[1], originalArgs[2])); 63 } else if (originalArgs.length == 3 && "-convert2xml".equals(originalArgs[0])) { 64 System.exit(convertToXml(originalArgs[1], originalArgs[2])); 65 } else { 66 ApiCheck acheck = new ApiCheck(); 67 Report report = acheck.checkApi(originalArgs); 68 69 Errors.printErrors(report.errors()); 70 System.exit(report.code); 71 } 72 } 73 74 /** 75 * Compares two api xml files for consistency. 76 */ checkApi(String[] originalArgs)77 public Report checkApi(String[] originalArgs) { 78 // translate to an ArrayList<String> for munging 79 ArrayList<String> args = new ArrayList<String>(originalArgs.length); 80 for (String a : originalArgs) { 81 args.add(a); 82 } 83 84 ArrayList<String[]> flags = ApiCheck.parseFlags(args); 85 for (String[] a : flags) { 86 if (a[0].equals("-error") || a[0].equals("-warning") || a[0].equals("-hide")) { 87 try { 88 int level = -1; 89 if (a[0].equals("-error")) { 90 level = Errors.ERROR; 91 } else if (a[0].equals("-warning")) { 92 level = Errors.WARNING; 93 } else if (a[0].equals("-hide")) { 94 level = Errors.HIDDEN; 95 } 96 Errors.setErrorLevel(Integer.parseInt(a[1]), level); 97 } catch (NumberFormatException e) { 98 System.err.println("Bad argument: " + a[0] + " " + a[1]); 99 return new Report(2, Errors.getErrors()); 100 } 101 } 102 } 103 104 ApiInfo oldApi; 105 ApiInfo newApi; 106 107 try { 108 oldApi = parseApi(args.get(0)); 109 newApi = parseApi(args.get(1)); 110 } catch (ApiParseException e) { 111 e.printStackTrace(); 112 System.err.println("Error parsing API"); 113 return new Report(1, Errors.getErrors()); 114 } 115 116 // only run the consistency check if we haven't had XML parse errors 117 if (!Errors.hadError) { 118 oldApi.isConsistent(newApi); 119 } 120 121 return new Report(Errors.hadError ? 1 : 0, Errors.getErrors()); 122 } 123 parseApi(String filename)124 public static ApiInfo parseApi(String filename) throws ApiParseException { 125 InputStream stream = null; 126 // try it as our format 127 try { 128 stream = new FileInputStream(filename); 129 } catch (IOException e) { 130 throw new ApiParseException("Could not open file for parsing: " + filename, e); 131 } 132 try { 133 return ApiFile.parseApi(filename, stream); 134 } catch (ApiParseException ignored) { 135 if (false) { 136 System.out.println("stopping for file: " + filename); 137 ignored.printStackTrace(); 138 return null; 139 } 140 } finally { 141 try { 142 stream.close(); 143 } catch (IOException ignored) {} 144 } 145 // try it as xml 146 try { 147 stream = new FileInputStream(filename); 148 } catch (IOException e) { 149 throw new ApiParseException("Could not open file for parsing: " + filename, e); 150 } 151 try { 152 return XmlApiFile.parseApi(stream); 153 } finally { 154 try { 155 stream.close(); 156 } catch (IOException ignored) {} 157 } 158 } 159 parseApi(URL url)160 public ApiInfo parseApi(URL url) throws ApiParseException { 161 InputStream stream = null; 162 // try it as our format 163 try { 164 stream = url.openStream(); 165 } catch (IOException e) { 166 throw new ApiParseException("Could not open stream for parsing: " + url, e); 167 } 168 try { 169 return ApiFile.parseApi(url.toString(), stream); 170 } catch (ApiParseException ignored) { 171 } finally { 172 try { 173 stream.close(); 174 } catch (IOException ignored) {} 175 } 176 // try it as xml 177 try { 178 stream = url.openStream(); 179 } catch (IOException e) { 180 throw new ApiParseException("Could not open stream for parsing: " + url, e); 181 } 182 try { 183 return XmlApiFile.parseApi(stream); 184 } finally { 185 try { 186 stream.close(); 187 } catch (IOException ignored) {} 188 } 189 } 190 191 public class Report { 192 private int code; 193 private Set<ErrorMessage> errors; 194 Report(int code, Set<ErrorMessage> errors)195 private Report(int code, Set<ErrorMessage> errors) { 196 this.code = code; 197 this.errors = errors; 198 } 199 code()200 public int code() { 201 return code; 202 } 203 errors()204 public Set<ErrorMessage> errors() { 205 return errors; 206 } 207 } 208 convertToApi(String src, String dst)209 static int convertToApi(String src, String dst) { 210 ApiInfo api; 211 try { 212 api = parseApi(src); 213 } catch (ApiParseException e) { 214 e.printStackTrace(); 215 System.err.println("Error parsing API: " + src); 216 return 1; 217 } 218 219 PrintStream apiWriter = null; 220 try { 221 apiWriter = new PrintStream(dst); 222 } catch (FileNotFoundException ex) { 223 System.err.println("can't open file: " + dst); 224 } 225 226 Stubs.writeApi(apiWriter, api.getPackages().values()); 227 228 return 0; 229 } 230 convertToXml(String src, String dst)231 static int convertToXml(String src, String dst) { 232 ApiInfo api; 233 try { 234 api = parseApi(src); 235 } catch (ApiParseException e) { 236 e.printStackTrace(); 237 System.err.println("Error parsing API: " + src); 238 return 1; 239 } 240 241 PrintStream apiWriter = null; 242 try { 243 apiWriter = new PrintStream(dst); 244 } catch (FileNotFoundException ex) { 245 System.err.println("can't open file: " + dst); 246 } 247 248 Stubs.writeXml(apiWriter, api.getPackages().values()); 249 250 return 0; 251 } 252 253 } 254