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); }
/// <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; }