Skip to content

Commit

Permalink
Implemented annotating, need to polish and cleanup
Browse files Browse the repository at this point in the history
  • Loading branch information
hurricup committed Dec 1, 2017
1 parent a46f084 commit 781d005
Show file tree
Hide file tree
Showing 11 changed files with 382 additions and 18 deletions.
4 changes: 2 additions & 2 deletions build.gradle
Original file line number Diff line number Diff line change
Expand Up @@ -120,8 +120,8 @@ project.afterEvaluate {
into perlUtils
}
copy {
from file("perl-utils/Devel")
into "$perlUtils/lib/"
from file("perl-utils/Devel/")
into "$perlUtils/lib/Devel/"
}
}
}
Expand Down
17 changes: 11 additions & 6 deletions perl-utils/Devel/Cover/Report/Camelcade.pm
Original file line number Diff line number Diff line change
Expand Up @@ -9,16 +9,22 @@ sub report {
my $options = shift;

my $report = $db->cover;
my $result = {};
my $result = [];
for my $file_name ($report->items) {
next unless ($file_name);
my $file_result = {
name => $file_name // "",
lines => {}

};
push @$result, $file_result;
my $file_data = $report->file($file_name);
for my $criterion_name ($file_data->items) {
my $criterion = $file_data->criterion($criterion_name);
if ($criterion_name eq 'statement') {
for my $location_id ($criterion->items) {
my $location_data = $criterion->location($location_id);
$result->{$file_name} //= {};
my $location_result = $result->{$file_name}{$location_id} //= {};
my $location_result = $file_result->{lines}{$location_id} //= {};
foreach my $element (@$location_data) {
$location_result->{data}++;
$location_result->{cover} += $element->covered // 0;
Expand All @@ -29,8 +35,7 @@ sub report {
elsif ($criterion_name eq 'time') {
for my $location_id ($criterion->items) {
my $location_data = $criterion->location($location_id);
$result->{$file_name} //= {};
my $location_result = $result->{$file_name}{$location_id} //= {};
my $location_result = $file_result->{lines}{$location_id} //= {};
foreach my $element (@$location_data) {
$location_result->{time} += $element->covered // 0;
}
Expand All @@ -47,7 +52,7 @@ sub report {
}

}
print JSON->new()->encode($result);
print JSON->new()->pretty(0)->encode($result);
}

1;
11 changes: 9 additions & 2 deletions resources/messages/PerlBundle.properties
Original file line number Diff line number Diff line change
Expand Up @@ -260,6 +260,13 @@ perl.template.context.switch=inside switch block
perl.template.context.switch.after.case=inside switch after case
perl.template.context.catch=catch compound
perl.template.context.continue=continue block


perl.select.sdk.notification=Perl5 Interpreter
perl.select.sdk.notification.title=Perl5 Interpreter is not Configured
perl.select.sdk.notification.message=To make it work you should select a Perl5 interpreter
perl.select.sdk.notification.action=To make it work you should select a Perl5 interpreter
perl.missing.library.notification=Perl5 Missing Library
perl.missing.library.notification.title=Perl5 Library {0} is Missing
perl.missing.library.notification.message=Library is require to perform an action. Please, install it first
perl.coverage.loading.error=Perl5 Coverage Loading Error
perl.configure.interpreter.action=Configure

14 changes: 13 additions & 1 deletion src/com/perl5/lang/perl/idea/coverage/PerlCoverageEngine.java
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,7 @@
import com.intellij.openapi.extensions.Extensions;
import com.intellij.openapi.module.Module;
import com.intellij.openapi.project.Project;
import com.intellij.openapi.util.io.FileUtil;
import com.intellij.psi.PsiElement;
import com.intellij.psi.PsiFile;
import com.perl5.lang.perl.fileTypes.PurePerlFileType;
Expand All @@ -31,6 +32,7 @@
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;

import java.io.File;
import java.util.Collections;
import java.util.Date;
import java.util.List;
Expand Down Expand Up @@ -116,7 +118,17 @@ public boolean recompileProjectAndRerunAction(@NotNull Module module,
@NotNull
@Override
public Set<String> getQualifiedNames(@NotNull PsiFile sourceFile) {
return Collections.emptySet(); // fixme investigate
return Collections.singleton(buildQualifiedName(sourceFile));
}

@Nullable
@Override
public String getQualifiedName(@NotNull File outputFile, @NotNull PsiFile sourceFile) {
return buildQualifiedName(sourceFile);
}

private static String buildQualifiedName(@NotNull PsiFile sourceFile) {
return FileUtil.toSystemIndependentName(sourceFile.getVirtualFile().getPath());
}

@Override
Expand Down
128 changes: 127 additions & 1 deletion src/com/perl5/lang/perl/idea/coverage/PerlCoverageRunner.java
Original file line number Diff line number Diff line change
Expand Up @@ -16,26 +16,152 @@

package com.perl5.lang.perl.idea.coverage;

import com.google.gson.Gson;
import com.google.gson.JsonParseException;
import com.intellij.coverage.CoverageEngine;
import com.intellij.coverage.CoverageRunner;
import com.intellij.coverage.CoverageSuite;
import com.intellij.execution.ExecutionException;
import com.intellij.execution.configurations.GeneralCommandLine;
import com.intellij.execution.process.ProcessOutput;
import com.intellij.execution.util.ExecUtil;
import com.intellij.notification.Notification;
import com.intellij.notification.NotificationType;
import com.intellij.notification.Notifications;
import com.intellij.openapi.diagnostic.Logger;
import com.intellij.openapi.project.Project;
import com.intellij.openapi.util.io.FileUtil;
import com.intellij.openapi.util.text.StringUtil;
import com.intellij.openapi.vfs.VirtualFile;
import com.intellij.rt.coverage.data.ClassData;
import com.intellij.rt.coverage.data.LineCoverage;
import com.intellij.rt.coverage.data.LineData;
import com.intellij.rt.coverage.data.ProjectData;
import com.perl5.PerlBundle;
import com.perl5.lang.perl.util.PerlPluginUtil;
import com.perl5.lang.perl.util.PerlRunUtil;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;

import java.io.File;
import java.util.Map;
import java.util.Set;

public class PerlCoverageRunner extends CoverageRunner {
private static final String COVER = "cover";
private static final String COVER_LIB = "Devel::Cover";
private static final Logger LOG = Logger.getInstance(PerlCoverageRunner.class);

@Override
public ProjectData loadCoverageData(@NotNull File sessionDataFile, @Nullable CoverageSuite baseCoverageSuite) {
if (!(baseCoverageSuite instanceof PerlCoverageSuite)) {
return null;
}
// todo implement loading
Project project = baseCoverageSuite.getProject();
VirtualFile coverFile = PerlRunUtil.findLibraryScriptWithNotification(project, COVER, COVER_LIB);
if (coverFile == null) {
return null;
}

String libRoot = PerlPluginUtil.getPluginPerlLibRoot();
if (libRoot == null) {
return null;
}

GeneralCommandLine perlCommandLine = PerlRunUtil.getPerlCommandLine(project, coverFile,
"-I" + FileUtil.toSystemIndependentName(libRoot));
if (perlCommandLine == null) {
return null; // fixme should be a notification
}

perlCommandLine.addParameters(
"--silent", "--nosummary", "-report", "camelcade", sessionDataFile.getAbsolutePath()
);

try {
LOG.info("Loading coverage by: " + perlCommandLine.getCommandLineString());
ProcessOutput output = ExecUtil.execAndGetOutput(perlCommandLine);
if (output.getExitCode() != 0) {
String errorMessage = output.getStderr();
if (StringUtil.isEmpty(errorMessage)) {
errorMessage = output.getStdout();
}

if (!StringUtil.isEmpty(errorMessage)) {
showError(project, errorMessage);
}
return null;
}
String stdout = output.getStdout();
if (StringUtil.isEmpty(stdout)) {
return null;
}

try {
PerlFileData[] filesData = new Gson().fromJson(stdout, PerlFileData[].class);
if (filesData != null) {
return parsePerlFileData(filesData);
}
}
catch (JsonParseException e) {
showError(project, e.getMessage());
LOG.warn("Error parsing JSON", e);
}
}
catch (ExecutionException e) {
showError(project, e.getMessage());
LOG.warn("Error loading coverage", e);
}
return null;
}

private static ProjectData parsePerlFileData(@NotNull PerlFileData[] filesData) {
ProjectData projectData = new ProjectData();
for (PerlFileData perlFileData : filesData) {
if (StringUtil.isEmpty(perlFileData.name) || perlFileData.lines == null) {
continue;
}
ClassData classData = projectData.getOrCreateClassData(FileUtil.toSystemIndependentName(perlFileData.name));
Set<Map.Entry<Integer, PerlLineData>> linesEntries = perlFileData.lines.entrySet();
Integer maxLineNumber = linesEntries.stream().map(Map.Entry::getKey).max(Integer::compare).orElse(0);
LineData[] linesData = new LineData[maxLineNumber + 1];
for (Map.Entry<Integer, PerlLineData> lineEntry : linesEntries) {
PerlLineData perlLineData = lineEntry.getValue();
final Integer lineNumber = lineEntry.getKey();
LineData lineData = new LineData(lineNumber, null) {
@Override
public int getStatus() {
if (perlLineData.cover == 0) {
return LineCoverage.NONE;
}
else if (perlLineData.cover < perlLineData.data) {
return LineCoverage.PARTIAL;
}
return LineCoverage.FULL;
}
};
lineData.setHits(perlLineData.cover);
linesData[lineNumber] = lineData;
}

classData.setLines(linesData);
}

return projectData;
}

private static void showError(@NotNull Project project, @NotNull String message) {
Notifications.Bus.notify(
new Notification(
PerlBundle.message("perl.coverage.loading.error"),
PerlBundle.message("perl.coverage.loading.error"),
message,
NotificationType.ERROR
),
project
);
}

@Override
public String getPresentableName() {
return PerlBundle.message("perl.perl5");
Expand Down
24 changes: 24 additions & 0 deletions src/com/perl5/lang/perl/idea/coverage/PerlFileData.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,24 @@
/*
* Copyright 2015-2017 Alexandr Evstigneev
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/

package com.perl5.lang.perl.idea.coverage;

import java.util.Map;

class PerlFileData {
public String name;
public Map<Integer, PerlLineData> lines;
}
24 changes: 24 additions & 0 deletions src/com/perl5/lang/perl/idea/coverage/PerlLineData.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,24 @@
/*
* Copyright 2015-2017 Alexandr Evstigneev
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/

package com.perl5.lang.perl.idea.coverage;

class PerlLineData {
int data;
int cover;
int uncoverable;
int time;
}
36 changes: 36 additions & 0 deletions src/com/perl5/lang/perl/idea/project/PerlProjectManager.java
Original file line number Diff line number Diff line change
Expand Up @@ -16,13 +16,18 @@

package com.perl5.lang.perl.idea.project;

import com.intellij.notification.Notification;
import com.intellij.notification.NotificationType;
import com.intellij.notification.Notifications;
import com.intellij.openapi.actionSystem.AnActionEvent;
import com.intellij.openapi.actionSystem.CommonDataKeys;
import com.intellij.openapi.actionSystem.DataContext;
import com.intellij.openapi.application.WriteAction;
import com.intellij.openapi.components.ServiceManager;
import com.intellij.openapi.module.Module;
import com.intellij.openapi.module.ModuleManager;
import com.intellij.openapi.module.ModuleUtilCore;
import com.intellij.openapi.project.DumbAwareAction;
import com.intellij.openapi.project.Project;
import com.intellij.openapi.projectRoots.ProjectJdkTable;
import com.intellij.openapi.projectRoots.Sdk;
Expand All @@ -42,7 +47,9 @@
import com.intellij.util.containers.ContainerUtil.ImmutableMapBuilder;
import com.intellij.util.containers.FactoryMap;
import com.intellij.util.messages.MessageBusConnection;
import com.perl5.PerlBundle;
import com.perl5.lang.perl.idea.configuration.settings.PerlLocalSettings;
import com.perl5.lang.perl.idea.configuration.settings.sdk.Perl5SettingsConfigurable;
import com.perl5.lang.perl.idea.configuration.settings.sdk.PerlSdkLibrary;
import com.perl5.lang.perl.idea.modules.PerlLibrarySourceRootType;
import com.perl5.lang.perl.idea.modules.PerlSourceRootType;
Expand Down Expand Up @@ -248,6 +255,35 @@ public static Sdk getSdk(@Nullable Module module) {
return getInstance(module.getProject()).getProjectSdk();
}

/**
* @return sdk for project. If not configured - suggests to configure
*/
public static Sdk getSdkWithNotification(@NotNull Project project) {
Sdk sdk = getSdk(project);
if (sdk != null) {
return sdk;
}
showUnconfiguredInterpreterNotification(project);
return null;
}

public static void showUnconfiguredInterpreterNotification(@NotNull Project project) {
Notification notification = new Notification(
PerlBundle.message("perl.select.sdk.notification"),
PerlBundle.message("perl.select.sdk.notification.title"),
PerlBundle.message("perl.select.sdk.notification.message"),
NotificationType.ERROR
);
notification.addAction(new DumbAwareAction(PerlBundle.message("perl.configure.interpreter.action")) {
@Override
public void actionPerformed(AnActionEvent e) {
Perl5SettingsConfigurable.open(project);
notification.expire();
}
});
Notifications.Bus.notify(notification, project);
}

@Nullable
public static Sdk getSdk(@Nullable Project project) {
if (project == null) {
Expand Down
4 changes: 2 additions & 2 deletions src/com/perl5/lang/perl/idea/sdk/PerlSdkType.java
Original file line number Diff line number Diff line change
Expand Up @@ -74,7 +74,7 @@ public void setupSdkPaths(@NotNull Sdk sdk) {
public List<String> getINCPaths(String sdkHomePath) {
String executablePath = getExecutablePath(sdkHomePath);
List<String> perlLibPaths = new ArrayList<>();
for (String path : PerlRunUtil.getDataFromProgram(
for (String path : PerlRunUtil.getOutputFromProgram(
executablePath,
"-le",
"print for @INC"
Expand Down Expand Up @@ -173,7 +173,7 @@ public String getVersionString(@NotNull Sdk sdk) {

@Nullable
private VersionDescriptor getPerlVersionDescriptor(@NotNull String sdkHomePath) {
List<String> versionLines = PerlRunUtil.getDataFromProgram(getExecutablePath(sdkHomePath), "-v");
List<String> versionLines = PerlRunUtil.getOutputFromProgram(getExecutablePath(sdkHomePath), "-v");

if (versionLines.isEmpty()) {
return null;
Expand Down
Loading

0 comments on commit 781d005

Please sign in to comment.