Advertisement
Guest User

Untitled

a guest
Feb 22nd, 2019
101
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
text 8.55 KB | None | 0 0
  1. # COPYRIGHT 2018, TIOBE SOFTWARE B.V.
  2. # $Id: TICSBuildGradle.pm 36651 2019-02-13 17:23:07Z steneker $
  3. # $URL: svn+ssh://steneker@esp.tiobe.com/home/wilde/svnrepository/tics/branches/release/9.4.x/components/analyzer/TICSBuildGradle.pm $
  4.  
  5. =head1 TICSBuildGradle
  6.  
  7. Build integration for Gradle (https://gradle.org/)
  8.  
  9. =cut
  10.  
  11. package TICSBuildGradle;
  12.  
  13. use TIOBEPragma;
  14.  
  15. use Exception qw(:all);
  16.  
  17. use List::MoreUtils qw(uniq);
  18. use List::Util qw(all);
  19.  
  20. use TICSAccess;
  21. use TICSCompiler;
  22. use TICSConfig;
  23. use TICSEnv;
  24. use TICSFile;
  25. use TICSFiles;
  26. use TICSSystem;
  27. use TIOBEEnv;
  28. use TIOBEError;
  29. use TIOBEFiles;
  30. use TIOBEJson;
  31. use TIOBEOS;
  32. use TIOBEPerl;
  33. use TIOBEString;
  34. use TIOBESystem;
  35. use TICSServer;
  36. use TICSDatabase;
  37.  
  38.  
  39. my $TOOL = 'gradlew';
  40.  
  41. sub IsBuildTypeEnumFiles () : Protected {
  42. return 0;
  43. }
  44.  
  45. sub IsMakeFile ($) : Protected {
  46. my ($file) = @_;
  47.  
  48. return grep { &TIOBEFiles::BaseName($file) eq $_} ('build.gradle', 'build.gradle.kts');
  49. }
  50.  
  51. sub ExtractFilesFromMakefile ($) : Protected {
  52. my ($makefile) = @_;
  53. my $fileopts = {};
  54.  
  55. try {
  56. $fileopts = &GetCompilerOptionsForMakefile($makefile);
  57. } except {
  58. my $err = &TIOBEError::Stringify(shift);
  59.  
  60. &TICSSystem::Log(5073, $TOOL, $err)
  61. };
  62. return keys %$fileopts;
  63. }
  64.  
  65. sub GetCompilerOptions ($$) : Protected {
  66. my ($inputfile, $target) = @_;
  67. my $makefile = &TICSFile::GetFileProperty($TICSFile::MAKEFILE, $inputfile);
  68. my $fileopts = &GetCompilerOptionsForMakefile($makefile);
  69.  
  70.  
  71. my @compileroptions = @{$fileopts->{$inputfile} // []};
  72. my ($pathoption) = grep($_->[0] eq '-compilerpath', @compileroptions);
  73. my $compilerpath = $pathoption->[1];
  74.  
  75. &TICSCompiler::SetCompilerInfo($inputfile, 'None', 'kotlinc', $compilerpath, $target);
  76. return grep($_->[0] ne '-compilerpath', @compileroptions);
  77.  
  78. return @{$fileopts->{$inputfile} // []};
  79. }
  80.  
  81. {
  82.  
  83. my %COMPOPTSCACHE = ();
  84.  
  85. sub GetCompilerOptionsForMakefile ($) : Private {
  86. my ($makefile) = @_;
  87.  
  88. $COMPOPTSCACHE{$makefile} //= &GetCompilerOptionsByRunningGradle($makefile);
  89. return $COMPOPTSCACHE{$makefile};
  90. }
  91.  
  92. }
  93.  
  94. {
  95. #Environment variable which tells Gradle were to output the compiler options
  96. my $GRADLE_OUTPUT_ENV_VAR = 'TICS_OUTPUT_FILE';
  97.  
  98. sub GetGradleOutputEnvVarName () : Public {
  99. return $GRADLE_OUTPUT_ENV_VAR;
  100. }
  101.  
  102. sub GetCompilerOptionsByRunningGradle ($) : Private {
  103. my ($makefile) = @_;
  104. my $workdir = &TIOBEFiles::DirName($makefile);
  105. my $toolexe = &FindToolExe($makefile);
  106. my $gradleplugin = &GetTICSGradlePlugin();
  107. my $out = '';
  108. my $buildfile = &GetBuildFile($makefile);
  109.  
  110. &TICSEnv::SaveEnv();
  111. &TIOBEEnv::SetEnvVar($GRADLE_OUTPUT_ENV_VAR, $buildfile);
  112. my $project = &TICSDatabase::GetProject();
  113. my $gradleoptionalparams = &GetToolCfgProp($TOOL, 'ADDITIONALARGS', $project);
  114. my @gradleflags = ('-Dorg.gradle.parallel=false', '-Dorg.gradle.daemon=false',
  115. '-Dorg.gradle.configureondemand=false', @$gradleoptionalparams);
  116. my $status =
  117. &TIOBESystem::SysQXCmd(
  118. workdir=>$workdir,
  119. cmd=>[$toolexe, @gradleflags, '-I', $gradleplugin, ':tics'],
  120. output=>\$out,
  121. );
  122.  
  123. &TICSEnv::ResetEnv();
  124. &TIOBEFiles::WriteFileContent("$buildfile.log", [$out]);
  125. if ($status || !-e $buildfile) {
  126. my $err = &GetFirstGradleError($out);
  127.  
  128. &TICSSystem::Assert(!defined $err || $err eq '', 5073, $TOOL, $err);
  129. &TICSSystem::Die(5073, $TOOL, 'An unknown error occurred');
  130. }
  131. return &ParseBuildFile($buildfile, $makefile);
  132. }
  133.  
  134. }
  135.  
  136. sub FindToolExe ($) : Private {
  137. my ($makefile) = @_;
  138. my $makedir = &TIOBEFiles::DirName($makefile);
  139. my $toolexe = &TIOBEOS::IsWin32() ? "$TOOL.bat" : $TOOL;
  140.  
  141. foreach my $dir (&TIOBEFiles::DirPrefixList($makedir)) {
  142. my $toolpath = &TIOBEFiles::SimpleCatFile($dir, $toolexe);
  143.  
  144. return $toolpath if -e $toolpath;
  145. }
  146. &TICSSystem::Die(5000, "No installation of \'$TOOL\' found.");
  147. }
  148.  
  149. {
  150.  
  151. my $GRADLE_PLUGIN_FILE = 'TICSGradlePlugin.gradle';
  152.  
  153. sub GetTICSGradlePlugin () : Private {
  154. my $gradleplugin = &TICSConfig::GetCfgFile($GRADLE_PLUGIN_FILE);
  155.  
  156. return &TIOBEFiles::CanonicalPath($gradleplugin) if -f $gradleplugin;
  157.  
  158. # PR19320: copy the bound file to the tmpdir and use it from there
  159. my $boundfile = &TIOBEPerl::ExtractBoundFile($GRADLE_PLUGIN_FILE, __PACKAGE__);
  160.  
  161. $gradleplugin = &TICSConfig::GetTmpPath($GRADLE_PLUGIN_FILE);
  162. &TIOBEFiles::Copy($boundfile, $gradleplugin) if !-f $gradleplugin;
  163. return &TIOBEFiles::CanonicalPath($gradleplugin);
  164. }
  165.  
  166. }
  167.  
  168. my $MAX_FILENAME_LENGTH = 150;
  169.  
  170. sub GetBuildFile ($) : Private {
  171. my ($makefile) = @_;
  172.  
  173. $makefile =~ tr{\\/:}{-};
  174. my $buildfile = "$makefile.json";
  175. #Restrict length filename to prevent assertion failure when deleting TMPDIR
  176. my $striplength = length($buildfile) - $MAX_FILENAME_LENGTH;
  177.  
  178. $buildfile = substr($buildfile, $striplength) if $striplength > 0;
  179. return &TICSConfig::GetTmpPath($buildfile);
  180. }
  181.  
  182. #Error is the first line that starts with a > after the line 'What went wrong:'
  183. sub GetFirstGradleError ($) : Private {
  184. my ($gradleoutput) = @_;
  185.  
  186. return if !$gradleoutput;
  187. my @lines =
  188. map(&TIOBEString::Trim($_), &TIOBEString::SplitLines($gradleoutput));
  189. my $error = '';
  190. my $seenerrormarker = 0;
  191.  
  192. foreach my $line (@lines) {
  193. if ($line =~ m/What went wrong:/) {
  194. $seenerrormarker = 1;
  195. } elsif ($seenerrormarker && $line =~ m/^>\s*(.*)/) {
  196. $error = $1;
  197. last;
  198. }
  199. }
  200. return $error;
  201. }
  202.  
  203. sub ParseBuildFile ($$) : Private {
  204. my ($buildfile, $makefile) = @_;
  205. my $configurationsperproject = &TIOBEJson::DecodeJsonFromFile($buildfile);
  206. my %compoptsperfile = ();
  207.  
  208. foreach my $project (keys %{$configurationsperproject}) {
  209. my %projectconfigurations = %{$configurationsperproject->{$project}};
  210.  
  211. foreach my $conf (keys %projectconfigurations) {
  212. my $configuration = $projectconfigurations{$conf};
  213.  
  214. if (&IsDeadCode($configuration)) {
  215. #Configurations that have not been built are dead code
  216. &TICSSystem::Warn(1120, $conf, $project, $makefile);
  217. next;
  218. }
  219. my $compileropts = &GetCompilerOptionsForConfiguration($configuration);
  220.  
  221. foreach my $srcfile (@{$configuration->{'sourceFiles'}}) {
  222. my $filename = &TICSFiles::CanonicalPath($srcfile);
  223.  
  224. $compoptsperfile{$filename} //= $compileropts;
  225. }
  226. }
  227. }
  228. return \%compoptsperfile;
  229. }
  230.  
  231. sub IsDeadCode ($) : Private {
  232. my ($configuration) = @_;
  233. my $classesdir = $configuration->{'classesDir'};
  234.  
  235. return !-e &TIOBEFiles::CanonicalPath($classesdir) if defined $classesdir;
  236. my $classesdirs = $configuration->{'classesDirs'};
  237. return all { !-e &TIOBEFiles::CanonicalPath($_) } @$classesdirs;
  238. }
  239.  
  240. sub GetCompilerOptionsForConfiguration (\%) : Private {
  241. my ($configuration) = @_;
  242.  
  243. &AddClassesDirToClasspath($configuration);
  244. &AddSingularClassesDir($configuration);
  245. my %mapping = (
  246. 'bootstrapClasspath' => '-bootclasspath',
  247. 'classesDir' => '-d',
  248. 'sourceCompatibility' => '-source',
  249. 'targetCompatibility' => '-target',
  250. 'sourcePaths' => '-sourcepath',
  251. 'classpath' => '-classpath',
  252. 'compilerPath' => '-compilerpath',
  253. );
  254. my @compopts = ();
  255.  
  256. foreach my $key (keys %mapping) {
  257. my $value = $configuration->{$key};
  258.  
  259. next if !$value || ref $value eq 'ARRAY' && !@$value;
  260. $value = &JoinPaths($value) if ref $value eq 'ARRAY';
  261. my $name = $mapping{$key};
  262.  
  263. push(@compopts, [$name, $value]);
  264. }
  265. #Add additional compiler arguments
  266. push(@compopts, map([$_], @{$configuration->{'compilerArgs'} // []}));
  267. return \@compopts;
  268. }
  269.  
  270. #Adds classesDir to front of classpath
  271. sub AddClassesDirToClasspath (\%) : Private {
  272. my ($configuration) = @_;
  273. my $classesdirs = $configuration->{'classesDirs'} // [$configuration->{'classesDir'}];
  274.  
  275. return if !$classesdirs;
  276. $configuration->{'classpath'} //= [];
  277. unshift(@{$configuration->{'classpath'}}, @$classesdirs);
  278. }
  279.  
  280. #Adds classesDir property with a single value.
  281. sub AddSingularClassesDir(\%) : Private {
  282. my ($configuration) = @_;
  283. my $classesdirs = $configuration->{'classesDirs'};
  284.  
  285. return if !$classesdirs;
  286. return if $configuration->{'classesDir'}; # already set
  287. $configuration->{'classesDir'} = @$classesdirs[0];
  288. }
  289.  
  290. sub JoinPaths (\@) : Private {
  291. my ($paths) = @_;
  292. my $sep = &TIOBEOS::IsWin32() ? ';' : ':';
  293.  
  294. return join($sep, uniq(@$paths));
  295. }
  296.  
  297. sub GetBuildTargets ($) : Protected {
  298. my ($inputfile) = @_;
  299.  
  300. return;
  301. }
  302.  
  303. sub GetToolCfgProp ($$$) : Private {
  304. my ($tool, $prop, $project) = @_;
  305.  
  306. return &TICSServer::GetProjectOrGlobalPropPath($project, 'TOOLS', $tool, $prop) // [];
  307. }
  308.  
  309. 1;
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement