1/* Copyright (C) 2003 Vladimir Roubtsov. All rights reserved. 2 * 3 * This program and the accompanying materials are made available under 4 * the terms of the Common Public License v1.0 which accompanies this distribution, 5 * and is available at http://www.eclipse.org/legal/cpl-v10.html 6 * 7 * $Id: instrCommand.java,v 1.1.1.1.2.1 2004/07/16 23:32:04 vlad_r Exp $ 8 */ 9package com.vladium.emma.instr; 10 11import java.io.IOException; 12 13import com.vladium.util.ClassLoaderResolver; 14import com.vladium.util.args.IOptsParser; 15import com.vladium.util.asserts.$assert; 16import com.vladium.emma.Command; 17import com.vladium.emma.IAppConstants; 18import com.vladium.emma.IAppErrorCodes; 19import com.vladium.emma.EMMARuntimeException; 20 21// ---------------------------------------------------------------------------- 22/** 23 * @author Vlad Roubtsov, (C) 2003 24 */ 25public 26final class instrCommand extends Command 27{ 28 // public: ................................................................ 29 30 public instrCommand (final String usageToolName, final String [] args) 31 { 32 super (usageToolName, args); 33 34 m_outMode = InstrProcessor.OutMode.OUT_MODE_COPY; // default 35 } 36 37 public synchronized void run () 38 { 39 ClassLoader loader; 40 try 41 { 42 loader = ClassLoaderResolver.getClassLoader (); 43 } 44 catch (Throwable t) 45 { 46 loader = getClass ().getClassLoader (); 47 } 48 49 try 50 { 51 // process 'args': 52 { 53 final IOptsParser parser = getOptParser (loader); 54 final IOptsParser.IOpts parsedopts = parser.parse (m_args); 55 56 // check if usage is requested before checking args parse errors etc: 57 { 58 final int usageRequestLevel = parsedopts.usageRequestLevel (); 59 60 if (usageRequestLevel > 0) 61 { 62 usageexit (parser, usageRequestLevel, null); 63 return; 64 } 65 } 66 67 final IOptsParser.IOpt [] opts = parsedopts.getOpts (); 68 69 if (opts == null) // this means there were args parsing errors 70 { 71 parsedopts.error (m_out, STDOUT_WIDTH); 72 usageexit (parser, IOptsParser.SHORT_USAGE, null); 73 return; 74 } 75 76 // process parsed args: 77 try 78 { 79 for (int o = 0; o < opts.length; ++ o) 80 { 81 final IOptsParser.IOpt opt = opts [o]; 82 final String on = opt.getCanonicalName (); 83 84 if (! processOpt (opt)) 85 { 86 if ("ip".equals (on)) 87 { 88 m_instrpath = getListOptValue (opt, PATH_DELIMITERS, true); 89 } 90 else if ("d".equals (on)) 91 { 92 m_outDirName = opt.getFirstValue (); 93 } 94 else if ("out".equals (on)) 95 { 96 m_outFileName = opt.getFirstValue (); 97 } 98 else if ("merge".equals (on)) 99 { 100 m_outDataMerge = getOptionalBooleanOptValue (opt) ? Boolean.TRUE : Boolean.FALSE; 101 } 102 else if ("ix".equals (on)) 103 { 104 // note: this allows path delimiter in the pattern list as well 105 m_ixpath = getListOptValue (opt, COMMA_DELIMITERS, true); 106 } 107 else if ("m".equals (on)) 108 { 109 final String ov = opt.getFirstValue (); 110 111 final InstrProcessor.OutMode outMode = InstrProcessor.OutMode.nameToMode (ov); 112 if (outMode == null) 113 { 114 usageexit (parser, IOptsParser.SHORT_USAGE, 115 "invalid '" + opts [o].getName () + "' option value: " + ov); 116 return; 117 } 118 m_outMode = outMode; 119 } 120 } 121 } 122 123 // user '-props' file property overrides: 124 125 if (! processFilePropertyOverrides ()) return; 126 127 // process prefixed opts: 128 129 processCmdPropertyOverrides (parsedopts); 130 } 131 catch (IOException ioe) 132 { 133 throw new EMMARuntimeException (IAppErrorCodes.ARGS_IO_FAILURE, ioe); 134 } 135 136 // handle cmd line-level defaults: 137 { 138 if ($assert.ENABLED) $assert.ASSERT (m_outMode != null, "m_outMode not set"); 139 140 if ((m_outMode != InstrProcessor.OutMode.OUT_MODE_OVERWRITE) && (m_outDirName == null)) 141 { 142 usageexit (parser, IOptsParser.SHORT_USAGE, 143 "output directory must be specified for '" + m_outMode + "' output mode"); 144 return; 145 } 146 } 147 } 148 149 // run the instrumentor: 150 { 151 final InstrProcessor processor = InstrProcessor.create (); 152 processor.setAppName (IAppConstants.APP_NAME); // for log prefixing 153 154 processor.setInstrPath (m_instrpath, true); // TODO: an option to set 'canonical'? 155 processor.setInclExclFilter (m_ixpath); 156 $assert.ASSERT (m_outMode != null, "m_outMode not set"); 157 processor.setOutMode (m_outMode); 158 processor.setInstrOutDir (m_outDirName); 159 processor.setMetaOutFile (m_outFileName); 160 processor.setMetaOutMerge (m_outDataMerge); 161 processor.setPropertyOverrides (m_propertyOverrides); 162 163 processor.run (); 164 } 165 } 166 catch (EMMARuntimeException yre) 167 { 168 // TODO: see below 169 170 exit (true, yre.getMessage (), yre, RC_UNEXPECTED); // does not return 171 return; 172 } 173 catch (Throwable t) 174 { 175 // TODO: embed: OS/JVM fingerprint, build #, etc 176 // TODO: save stack trace in a file and prompt user to send it to ... 177 178 exit (true, "unexpected failure: ", t, RC_UNEXPECTED); // does not return 179 return; 180 } 181 182 exit (false, null, null, RC_OK); 183 } 184 185 // protected: ............................................................. 186 187 188 protected void initialize () 189 { 190 super.initialize (); 191 } 192 193 protected String usageArgsMsg () 194 { 195 return "[options]"; 196 } 197 198 // package: ............................................................... 199 200 // private: ............................................................... 201 202 203 private String [] m_instrpath; 204 private String [] m_ixpath; 205 private String m_outDirName; 206 private String m_outFileName; 207 private Boolean m_outDataMerge; 208 private InstrProcessor.OutMode m_outMode; 209 210} // end of class 211// ----------------------------------------------------------------------------