11package com .salesforce .sfca .cpdwrapper ;
22
3- import net .sourceforge .pmd .cpd .CPDConfiguration ;
4- import net .sourceforge .pmd .cpd .CpdAnalysis ;
5- import net .sourceforge .pmd .cpd .Mark ;
6- import net .sourceforge .pmd .cpd .Match ;
3+ import net .sourceforge .pmd .cpd .*;
74import net .sourceforge .pmd .lang .Language ;
85import net .sourceforge .pmd .lang .document .FileLocation ;
96import net .sourceforge .pmd .reporting .Report ;
@@ -64,8 +61,15 @@ private CpdLanguageRunResults runLanguage(String language, List<Path> pathsToSca
6461 CpdLanguageRunResults languageRunResults = new CpdLanguageRunResults ();
6562
6663 try (CpdAnalysis cpd = CpdAnalysis .create (config )) {
67- cpd .performAnalysis (report -> {
6864
65+ // Note that we could use cpd.files().getCollectedFiles().size() to get the true totalNumFiles but
66+ // unfortunately getCollectedFiles doesn't cache and does a sort operation which is expensive.
67+ // So instead we use pathsToScan.size() since we send in the list of files instead of folders and so
68+ // these numbers should be the same.
69+ int totalNumFiles = pathsToScan .size ();
70+ cpd .setCpdListener (new CpdRunListener (totalNumFiles ));
71+
72+ cpd .performAnalysis (report -> {
6973 for (Report .ProcessingError reportProcessingError : report .getProcessingErrors ()) {
7074 CpdLanguageRunResults .ProcessingError processingErr = new CpdLanguageRunResults .ProcessingError ();
7175 processingErr .file = reportProcessingError .getFileId ().getAbsolutePath ();
@@ -134,4 +138,44 @@ public boolean isLoggable(Level level) {
134138 public int numErrors () {
135139 return 0 ;
136140 }
141+ }
142+
143+ class CpdRunListener implements CPDListener {
144+ private final int totalNumFiles ;
145+ private int numFilesAdded = 0 ;
146+ private int currentPhase = CPDListener .INIT ;
147+
148+ public CpdRunListener (int totalNumFiles ) {
149+ this .totalNumFiles = totalNumFiles ;
150+ }
151+
152+ @ Override
153+ public void addedFile (int i ) {
154+ // All files are added while we still are on phase 0 - INIT, i.e. before the phase is updated to phase 1 - HASH.
155+ this .numFilesAdded += i ;
156+ printCompletePercentage ();
157+ }
158+
159+ @ Override
160+ public void phaseUpdate (int i ) {
161+ this .currentPhase = i ;
162+ printCompletePercentage ();
163+ }
164+
165+ private float calculateCompletePercentage () {
166+ if (this .currentPhase == CPDListener .INIT ) {
167+ // Using Math.min just in case the totalNumFiles is inaccurate - although it shouldn't be.
168+ return 25 *(Math .min ((float ) this .numFilesAdded / this .totalNumFiles , 1.0f ));
169+ }
170+ return 100 * ((float ) this .currentPhase / CPDListener .DONE );
171+ }
172+
173+ private void printCompletePercentage () {
174+ System .out .println (calculateCompletePercentage ());
175+ }
176+ }
177+
178+ // TODO: add in per language
179+ class ProgressReporter {
180+ // updateProgressForLanguage(language, percComplete)
137181}
0 commit comments