1
+ import { CommandLineValues } from './Common/CommandLineValues' ;
2
+ import { ProgramFeatures } from './FeaturesEntities/ProgramFeatures' ;
3
+ import { Common } from './Common/Common' ;
4
+ import { FeatureExtractor } from './FeaturesExtractor' ;
5
+ import { appendFileSync , writeFileSync } from 'fs' ;
6
+ import fs = require( 'fs' ) ;
7
+ import path = require( 'path' ) ;
8
+
9
+ export class ExtractFeaturesTask {
10
+ static log_file : string = "TSE.log" ;
11
+ static m_CommandLineValues : CommandLineValues ;
12
+
13
+ /**
14
+ * Processes the command line values and returns the number of extracted files.
15
+ */
16
+ public static process ( ) : number {
17
+ ExtractFeaturesTask . log_file = this . m_CommandLineValues . logDir + ExtractFeaturesTask . log_file ;
18
+ let num_extracted : number = 0 ;
19
+ if ( this . m_CommandLineValues . File != null ) {
20
+ let extracted : boolean = ExtractFeaturesTask . processFile ( this . m_CommandLineValues . File ) ;
21
+ if ( extracted ) num_extracted = 1 ;
22
+ } else if ( this . m_CommandLineValues . Dir != null ) {
23
+ num_extracted = ExtractFeaturesTask . processDir ( ) ;
24
+ }
25
+ return num_extracted ;
26
+ }
27
+
28
+ /**
29
+ * Processes a file and returns true if it was extracted (meaning, if there were program features extracted out of it)
30
+ * and false otherwise.
31
+ * @param filePath - the file to be processed.
32
+ */
33
+ private static processFile ( filePath : string ) : boolean {
34
+ let processing_msg : string = new Date ( ) . toLocaleString ( ) + ": Processing file:\n\t\t\t\t\t\t" + filePath + "\n" ;
35
+ appendFileSync ( ExtractFeaturesTask . log_file , processing_msg , Common . UTF8 ) ;
36
+ if ( ! filePath . endsWith ( '.ts' ) ) {
37
+ let processing_msg : string = new Date ( ) . toLocaleString ( ) + ": Given file is not a .ts file:\n\t\t\t\t\t\t" + filePath + "\n" ;
38
+ appendFileSync ( ExtractFeaturesTask . log_file , processing_msg , Common . UTF8 ) ;
39
+ return false ;
40
+ }
41
+ try {
42
+ var featureExtractor : FeatureExtractor = new FeatureExtractor ( this . m_CommandLineValues , filePath ) ;
43
+ // var features: Array<ProgramFeatures> = featureExtractor.extractFeatures();
44
+ var features : Array < ProgramFeatures > = featureExtractor . extractFeatures ( ) ;
45
+ if ( features == null || features . length == 0 ) {
46
+ let no_paths_msg : string = new Date ( ) . toLocaleString ( ) + ": No paths in file:\n\t\t\t\t\t\t" + filePath + "\n" ;
47
+ appendFileSync ( ExtractFeaturesTask . log_file , no_paths_msg , Common . UTF8 ) ;
48
+ return false ;
49
+ }
50
+ var toPrint : Array < string > = ExtractFeaturesTask . featuresToString ( features ) ;
51
+ for ( let i = 0 ; i < toPrint . length ; i ++ ) {
52
+ console . log ( toPrint [ i ] ) ;
53
+ }
54
+ }
55
+ catch ( e ) {
56
+ let e_msg : string = new Date ( ) . toLocaleString ( ) + ": Exception in file:\n\t\t\t\t\t\t" + filePath + ": \"" + e + "\"\n" ;
57
+ appendFileSync ( ExtractFeaturesTask . log_file , e_msg , Common . UTF8 ) ;
58
+ return false ;
59
+ }
60
+ let finished_msg : string = new Date ( ) . toLocaleString ( ) + ": Finished processing file:\n\t\t\t\t\t\t" + filePath + "\n" ;
61
+ appendFileSync ( ExtractFeaturesTask . log_file , finished_msg , Common . UTF8 ) ;
62
+ return true ;
63
+ }
64
+
65
+ /**
66
+ * Processes a directory and returns the number of .ts files that were extracted.
67
+ */
68
+ private static processDir ( ) : number {
69
+ let processing_msg : string = new Date ( ) . toLocaleString ( ) + ": Processing directory:\n\t\t\t\t\t\t" + this . m_CommandLineValues . Dir + "\n" ;
70
+ appendFileSync ( ExtractFeaturesTask . log_file , processing_msg , Common . UTF8 ) ;
71
+ let dir_path : string = this . m_CommandLineValues . Dir ;
72
+ var num_ts_files : number = 0 , num_processed : number = 0 , num_extracted : number = 0 ;
73
+ let dir_path_splitted : Array < string > = dir_path . split ( "/" ) ;
74
+ let dir_name : string = dir_path_splitted [ dir_path_splitted . length - 1 ] ;
75
+ let dir_progress_file : string = this . m_CommandLineValues . logDir + dir_name + "_progress.log" ;
76
+
77
+ // count the number of .ts files
78
+ walkDir ( dir_path , function ( filePath : string ) {
79
+ if ( filePath . endsWith ( '.ts' ) ) {
80
+ num_ts_files ++ ;
81
+ }
82
+ } ) ;
83
+
84
+ let start_time : Date = new Date ( ) ;
85
+ let progress_msg : string =
86
+ ExtractFeaturesTask . getProgressMessage ( num_processed , num_extracted , num_ts_files , dir_path , start_time , false ) ;
87
+ writeFileSync ( dir_progress_file , progress_msg ) ;
88
+
89
+ // extract all .ts files in the directory
90
+ walkDir ( dir_path , function ( filePath : string ) {
91
+ if ( ! filePath . endsWith ( '.ts' ) ) {
92
+ return ;
93
+ }
94
+ let extracted : boolean = ExtractFeaturesTask . processFile ( filePath ) ;
95
+ num_processed ++ ;
96
+ if ( extracted ) num_extracted ++ ;
97
+ if ( num_processed % 5 == 0 || num_processed == num_ts_files ) {
98
+ let progress_msg : string =
99
+ ExtractFeaturesTask . getProgressMessage ( num_processed , num_extracted , num_ts_files , dir_path , start_time , false ) ;
100
+ writeFileSync ( dir_progress_file , progress_msg ) ;
101
+ }
102
+ } ) ;
103
+
104
+ progress_msg =
105
+ ExtractFeaturesTask . getProgressMessage ( num_processed , num_extracted , num_ts_files , dir_path , start_time , true ) ;
106
+ writeFileSync ( dir_progress_file , progress_msg ) ;
107
+
108
+ let finished_msg : string = new Date ( ) . toLocaleString ( ) + ": Extracted a total of " + num_extracted . toString ( ) + " .ts files out of " + num_ts_files + " from directory:\n\t\t\t\t\t\t" + dir_path + "\n" ;
109
+ finished_msg += new Date ( ) . toLocaleString ( ) + ": Finished processing directory:\n\t\t\t\t\t\t" + this . m_CommandLineValues . Dir + "\n" ;
110
+ appendFileSync ( ExtractFeaturesTask . log_file , finished_msg , Common . UTF8 ) ;
111
+ appendFileSync ( this . m_CommandLineValues . logDir + "NumExtracted.log" , num_extracted . toString ( ) + "/" + num_processed . toString ( ) + "\n" , Common . UTF8 )
112
+ return num_extracted ;
113
+ }
114
+
115
+ /**
116
+ * Generates a progress message. Meant to be used by ExtractFeaturesTask.processDir.
117
+ * @param num_processed - the number of .ts files processed so far.
118
+ * @param num_extracted - the number of .ts files extracted so far.
119
+ * @param num_ts_files - the total number of .ts files in the directory.
120
+ * @param dir_path - the directories' path.
121
+ * @param start_time - the time when the processing started.
122
+ * @param finished - a flag that indicates whether the directory has been wholy processed or not.
123
+ */
124
+ private static getProgressMessage ( num_processed :number , num_extracted :number , num_ts_files :number , dir_path :string , start_time :Date , finished :boolean ) {
125
+ let current_time : Date = new Date ( ) ;
126
+ let progress = ( num_processed / num_ts_files * 100 ) | 0 ;
127
+ let progress_msg : string = "TSExtractor is processing directory " + dir_path + ": " + progress + "%\n" ;
128
+ let processed_msg : string = "Processed " + num_processed . toString ( ) + "/" + num_ts_files . toString ( ) + " .ts files\n" ;
129
+ let extracted_msg : string = "Extracted " + num_extracted . toString ( ) + "/" + num_processed . toString ( ) + " .ts files\n" ;
130
+ let start_time_msg : string = "Processing started:\n\t\t\t\t\t" + start_time . toLocaleString ( ) + "\n" ;
131
+ let current_time_msg : string = "Last updated:\n\t\t\t\t\t" + current_time . toLocaleString ( ) + "\n" ;
132
+ if ( finished ) {
133
+ progress_msg = "TSExtractor finished processing directory " + dir_path + ": " + progress + "%\n" ;
134
+ current_time_msg = "Processing finished:\n\t\t\t\t\t" + current_time . toLocaleString ( ) + "\n" ;
135
+ let time_difference = new splittedTimeDifference ( start_time , current_time ) ;
136
+ current_time_msg += "Total time:\n\t\t\t\t\t" ;
137
+ if ( time_difference . days > 0 ) current_time_msg += time_difference . days + " days, " ;
138
+ if ( time_difference . hours > 0 ) current_time_msg += time_difference . hours + " hours, " ;
139
+ if ( time_difference . minutes > 0 ) current_time_msg += time_difference . minutes + " minutes, " ;
140
+ current_time_msg = current_time_msg + time_difference . seconds + " seconds.\n" ;
141
+ }
142
+ return progress_msg + processed_msg + extracted_msg + "\n" + start_time_msg + current_time_msg ;
143
+ }
144
+
145
+ /**
146
+ * Renders an array of ProgramFeatures to printable strings.
147
+ * @param features - the program features.
148
+ */
149
+ private static featuresToString ( features : Array < ProgramFeatures > ) : Array < string > {
150
+ var strings = new Array < string > ( ) ;
151
+ for ( let singleIdFeatures of features ) {
152
+ var toPrint = singleIdFeatures . toString ( ) ;
153
+ strings . push ( toPrint ) ;
154
+ }
155
+ return strings ;
156
+ }
157
+ }
158
+
159
+ /**
160
+ * Recursively walks a dir.
161
+ * @param dir - the directory.
162
+ * @param callback - the function to be applied on each file in the directory and in its subdirectories.
163
+ */
164
+ function walkDir ( dir , callback ) {
165
+ fs . readdirSync ( dir ) . forEach ( f => {
166
+ let dirPath = path . join ( dir , f ) ;
167
+ let isDirectory = fs . statSync ( dirPath ) . isDirectory ( ) ;
168
+ isDirectory ?
169
+ walkDir ( dirPath , callback ) : callback ( path . join ( dir , f ) ) ;
170
+ } ) ;
171
+ } ;
172
+
173
+ /**
174
+ * Calculates the time difference between two given dates in a human-readable form.
175
+ * @param date1 - the first date.
176
+ * @param date2 - the second date.
177
+ */
178
+ function splittedTimeDifference ( date1 : Date , date2 : Date ) {
179
+ let time_difference : number = date2 . getTime ( ) - date1 . getTime ( ) ;
180
+ this . seconds = ( time_difference / 1000 ) | 0 ;
181
+ this . minutes = ( time_difference / ( 1000 * 60 ) ) | 0 ;
182
+ this . hours = ( time_difference / ( 1000 * 60 * 60 ) ) | 0 ;
183
+ this . days = ( time_difference / ( 1000 * 60 * 60 * 24 ) ) | 0 ;
184
+ this . seconds = this . seconds - 60 * this . minutes ;
185
+ this . minutes = this . minutes - 60 * this . hours ;
186
+ this . hours = this . hours - 24 * this . days ;
187
+ }
0 commit comments