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// ----------------------------------------------------------------------------