public static CloneDetectiveResult FromSolutionPath(string solutionPath)
        {
            // Get path to log file.
            string logPath         = PathHelper.GetLogPath(solutionPath);
            string cloneReportPath = PathHelper.GetCloneReportPath(solutionPath);

            // If the log file does not exist no clone detective result can be
            // constructed (if only the clone report is missing it can).
            if (!File.Exists(logPath))
            {
                return(null);
            }

            // Construct the clone detective result.
            CloneDetectiveResult result = new CloneDetectiveResult();

            if (File.Exists(cloneReportPath))
            {
                try
                {
                    // We have a clone report. Parse it and construct the source tree from it.
                    result.CloneReport = CloneReport.FromFile(cloneReportPath);
                    result.SourceTree  = SourceTree.FromCloneReport(result.CloneReport, solutionPath);
                }
                catch (Exception ex)
                {
                    // If we could not parse the clone report we write an error to the
                    // log file (which we will parse below).
                    result.CloneReport = null;
                    result.SourceTree  = null;
                    LogHelper.WriteError(logPath, ex);
                    LogHelper.WriteStatusInfo(logPath, CloneDetectiveResultStatus.Failed, 0, TimeSpan.Zero);
                }
            }

            // Parse the summary information out of the log file.
            CloneDetectiveResultStatus status;
            long     usedMemory;
            TimeSpan usedTime;

            LogHelper.ParseStatusInfo(logPath, out status, out usedMemory, out usedTime);

            result.Status     = status;
            result.UsedMemory = usedMemory;
            result.UsedTime   = usedTime;

            return(result);
        }
        public void RunAsync()
        {
            if (_running)
            {
                throw ExceptionBuilder.CloneDetectiveAlreadyRunning();
            }

            // Make sure our internal state is updated first.
            _running = true;
            _aborted = false;

            // Time for multi-threading.
            //
            // For synchronization purposes we use the .NET 2.0 new SynchronizationContext.
            // This way we can write code that runs on the correct thread context without
            // binding to a concrete UI technology (such as Windows Forms, ASP.NET etc.)

            // Get context for current thread. This will typically be the main UI thread.
            SynchronizationContext ctx = SynchronizationContext.Current;

            // Now we will queue a delegate that will be run on a worker thread.
            ThreadPool.QueueUserWorkItem(
                delegate
            {
                // !! WORKER THREAD CONTEXT !!

                Exception exception = null;
                try
                {
                    // Make sure the directory exists
                    string cloneReportDirectory = Path.GetDirectoryName(_solutionSettings.CloneReportFileName);
                    if (!Directory.Exists(cloneReportDirectory))
                    {
                        Directory.CreateDirectory(cloneReportDirectory);
                    }

                    // First we delete the old clone report
                    File.Delete(_solutionSettings.CloneReportFileName);

                    // Create output lambda that is used by RunConQAT.
                    Action <string> outputHandler;
                    EventHandler <CloneDetectiveMessageEventArgs> messageHandler = Message;
                    if (messageHandler == null)
                    {
                        outputHandler = s => { }
                    }
                    ;
                    else
                    {
                        outputHandler = (s => ctx.Send(delegate
                        {
                            CloneDetectiveMessageEventArgs args = new CloneDetectiveMessageEventArgs(s);
                            messageHandler(this, args);
                        }, null));
                    }

                    // Run ConQAT and wait for completion.
                    RunConQAT(outputHandler);

                    // Check if ConQAT exited normally or we killed it using Abort().
                    if (!_aborted)
                    {
                        // OK, ConQAT has run to completion.
                        //
                        // Check if ConQAT produced a clone report.
                        //
                        // If this is not the case then ConQAT failed for some reason.
                        if (!File.Exists(_solutionSettings.CloneReportFileName) || (new FileInfo(_solutionSettings.CloneReportFileName)).Length == 0)
                        {
                            throw ExceptionBuilder.ConqatDidNotProduceCloneReport();
                        }

                        // Copy the clone report file to our solution clone report file (overwriting any existing one).
                        try
                        {
                            File.Copy(_solutionSettings.CloneReportFileName, _cloneReportFileName, true);
                        }
                        catch (IOException)
                        {
                            // If the _solutionSettings.CloneReportFileName points to the same file
                            // as _cloneReportFileName we obviously cannot copy the file. However,
                            // in .NET there is no simple way to check whether to given paths point
                            // to the same file (remember that there are many ways to express file paths:
                            // mapped drives, relative paths, special characters, etc.)
                            //
                            // The safest way is to just try to copy and in case of a failure just ignore
                            // the error.
                        }
                    }
                }
                catch (Exception ex)
                {
                    // Just record the exception, we will handle it below.
                    exception = ex;
                }

                // OK, here ConQAT has either run successully, failed or was killed by the Abort() method.
                // Depending on what our internal state is we will update the solution log file.

                if (exception != null)
                {
                    // ConQAT failed to produce a clone report.
                    LogHelper.WriteError(_conqatLogFileName, exception);
                    LogHelper.WriteStatusInfo(_conqatLogFileName, CloneDetectiveResultStatus.Failed, _usedMemory, _usedTime);
                }
                else if (_aborted)
                {
                    // ConQAT was aborted.
                    LogHelper.WriteStatusInfo(_conqatLogFileName, CloneDetectiveResultStatus.Stopped, _usedMemory, _usedTime);
                }
                else
                {
                    // ConQAT actually succeeded.
                    LogHelper.WriteStatusInfo(_conqatLogFileName, CloneDetectiveResultStatus.Succeeded, _usedMemory, _usedTime);
                }

                // Here we are still in the worker thread context. The completion event must be executed in
                // the same thread context as caller of RunAsync(). To change the thread context we use the
                // stored synchronization context.
                ctx.Send(delegate
                {
                    // !! MAIN THREAD CONTEXT !!

                    // Back to main thread. From here we can safely update our internal state and invoke the
                    // completion event.

                    // Reset process and running flag.
                    _process = null;
                    _running = false;

                    // Load clone detective result and notify event subscribers (if any).
                    CloneDetectiveResult cloneDetectiveResult = CloneDetectiveResult.FromSolutionPath(_solutionSettings.SolutionFileName);
                    EventHandler <CloneDetectiveCompletedEventArgs> handler = Completed;
                    if (handler != null)
                    {
                        CloneDetectiveCompletedEventArgs eventArgs = new CloneDetectiveCompletedEventArgs(cloneDetectiveResult, exception);
                        handler(this, eventArgs);
                    }
                }, null);
            }
Exemple #3
0
 /// <summary>
 /// Creates a new instance of <see cref="CloneDetectiveCompletedEventArgs"/> by the given
 /// <see cref="CloneDetectiveResult"/> and <see cref="Exception"/>.
 /// </summary>
 /// <param name="result">Contains the result returned by Clone Detective.</param>
 /// <param name="exception">If an error occured running Clone Detective
 /// <paramref name="exception"/> refers to the <see cref="System.Exception"/>.</param>
 public CloneDetectiveCompletedEventArgs(CloneDetectiveResult result, Exception exception)
 {
     _result    = result;
     _exception = exception;
 }