• Home
  • Features
  • Pricing
  • Docs
  • Announcements
  • Sign In

Camelcade / Perl5-IDEA / #525521660

24 Aug 2025 01:28PM UTC coverage: 75.89% (-6.3%) from 82.227%
#525521660

push

github

hurricup
Migrated coverage reporting to https://github.com/nbaztec/coveralls-jacoco-gradle-plugin

See: https://github.com/kt3k/coveralls-gradle-plugin/issues/119

14751 of 22639 branches covered (65.16%)

Branch coverage included in aggregate %.

31091 of 37767 relevant lines covered (82.32%)

0.82 hits per line

Source File
Press 'n' to go to next uncovered line, 'b' for previous

76.55
/plugin/common/src/main/java/com/intellij/openapi/projectRoots/impl/PerlModuleExtension.java
1
/*
2
 * Copyright 2015-2025 Alexandr Evstigneev
3
 *
4
 * Licensed under the Apache License, Version 2.0 (the "License");
5
 * you may not use this file except in compliance with the License.
6
 * You may obtain a copy of the License at
7
 *
8
 * http://www.apache.org/licenses/LICENSE-2.0
9
 *
10
 * Unless required by applicable law or agreed to in writing, software
11
 * distributed under the License is distributed on an "AS IS" BASIS,
12
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13
 * See the License for the specific language governing permissions and
14
 * limitations under the License.
15
 */
16

17
package com.intellij.openapi.projectRoots.impl;
18

19
import com.intellij.openapi.application.WriteAction;
20
import com.intellij.openapi.components.PathMacroManager;
21
import com.intellij.openapi.components.PersistentStateComponentWithModificationTracker;
22
import com.intellij.openapi.diagnostic.Logger;
23
import com.intellij.openapi.module.Module;
24
import com.intellij.openapi.roots.ModifiableRootModel;
25
import com.intellij.openapi.roots.ModuleExtension;
26
import com.intellij.openapi.roots.ModuleRootManager;
27
import com.intellij.openapi.roots.ex.ProjectRootManagerEx;
28
import com.intellij.openapi.util.text.StringUtil;
29
import com.intellij.openapi.vfs.VfsUtil;
30
import com.intellij.openapi.vfs.VirtualFile;
31
import com.intellij.openapi.vfs.VirtualFileManager;
32
import com.intellij.util.indexing.BuildableRootsChangeRescanningInfo;
33
import com.perl5.lang.perl.idea.modules.PerlSourceRootType;
34
import org.jdom.Element;
35
import org.jetbrains.annotations.ApiStatus;
36
import org.jetbrains.annotations.NotNull;
37
import org.jetbrains.annotations.Nullable;
38
import org.jetbrains.jps.model.module.JpsModuleSourceRootType;
39
import org.jetbrains.jps.model.serialization.JpsModelSerializerExtension;
40
import org.jetbrains.jps.model.serialization.module.JpsModuleSourceRootPropertiesSerializer;
41

42
import java.io.File;
43
import java.util.Collections;
44
import java.util.LinkedHashMap;
45
import java.util.List;
46
import java.util.Map;
47
import java.util.function.Consumer;
48
import java.util.function.Predicate;
49
import java.util.stream.Collectors;
50

51
public class PerlModuleExtension extends ModuleExtension implements PersistentStateComponentWithModificationTracker<Element> {
52
  private static final Logger LOG = Logger.getInstance(PerlModuleExtension.class);
1✔
53
  private static final String PERL_CONFIG = "perl5";
54
  private static final String ELEMENT_PATH = "path";
55
  private static final String ATTRIBUTE_VALUE = "value";
56
  private static final String ATTRIBUTE_TYPE = "type";
57
  private final boolean myIsWritable;
58
  private long myModificationTracker;
59
  private final PerlModuleExtension myOriginal;
60
  private final Module myModule;
61
  private Map<VirtualFile, PerlSourceRootType> myRoots = new LinkedHashMap<>();
1✔
62

63
  public PerlModuleExtension(Module module) {
1✔
64
    myModule = module;
1✔
65
    myIsWritable = false;
1✔
66
    myOriginal = null;
1✔
67
  }
1✔
68

69
  private PerlModuleExtension(@NotNull PerlModuleExtension original, boolean writable) {
1✔
70
    myModule = original.myModule;
1✔
71
    myRoots.putAll(original.myRoots);
1✔
72
    myIsWritable = writable;
1✔
73
    myOriginal = original;
1✔
74
  }
1✔
75

76
  @ApiStatus.OverrideOnly
77
  @Override
78
  public @NotNull ModuleExtension getModifiableModel(boolean writable) {
79
    return new PerlModuleExtension(this, writable);
1✔
80
  }
81

82
  @Override
83
  public void commit() {
84
    LOG.assertTrue(myOriginal != null, "Attempt to commit non-modifiable model");
1!
85
    if (isChanged()) {
1!
86
      synchronized (myOriginal) {
1✔
87
        WriteAction.run(
1✔
88
          () -> ProjectRootManagerEx.getInstanceEx(myModule.getProject()).makeRootsChange(() -> {
1✔
89
            myOriginal.myRoots = new LinkedHashMap<>(myRoots);
1✔
90
            myOriginal.myModificationTracker++;
1✔
91
          }, BuildableRootsChangeRescanningInfo.newInstance().addModule(myModule).buildInfo())
1✔
92
        );
93
      }
1✔
94
    }
95
  }
1✔
96

97
  @Override
98
  public boolean isChanged() {
99
    return !myRoots.equals(myOriginal.myRoots);
1✔
100
  }
101

102
  public synchronized void setRoot(@NotNull VirtualFile root, @NotNull JpsModuleSourceRootType<?> type) {
103
    LOG.assertTrue(myIsWritable, "Obtain modifiableModel first");
1✔
104
    LOG.assertTrue(type instanceof PerlSourceRootType, type + " is not a PerlSourceRootType");
1✔
105
    myRoots.put(root, (PerlSourceRootType)type);
1✔
106
    myModificationTracker++;
1✔
107
  }
1✔
108

109
  public synchronized void removeRoot(@NotNull VirtualFile root) {
110
    LOG.assertTrue(myIsWritable, "Obtain modifiableModel first");
1✔
111
    myRoots.remove(root);
1✔
112
    myModificationTracker++;
1✔
113
  }
1✔
114

115
  public Map<VirtualFile, PerlSourceRootType> getRoots() {
116
    return Collections.unmodifiableMap(myRoots);
×
117
  }
118

119
  public synchronized List<VirtualFile> getRootsByType(@NotNull PerlSourceRootType type) {
120
    return myRoots.entrySet().stream()
1✔
121
      .filter(entry -> type.equals(entry.getValue()))
1✔
122
      .map(Map.Entry::getKey)
1✔
123
      .collect(Collectors.toList());
1✔
124
  }
125

126
  public @Nullable PerlSourceRootType getRootType(@NotNull VirtualFile virtualFile) {
127
    return myRoots.get(virtualFile);
×
128
  }
129

130
  @Override
131
  public long getStateModificationCount() {
132
    return myModificationTracker;
×
133
  }
134

135
  @Override
136
  public @Nullable Element getState() {
137
    Element perlConfig = new Element(PERL_CONFIG);
1✔
138

139
    PathMacroManager macroManager = PathMacroManager.getInstance(myModule);
1✔
140

141
    for (VirtualFile root : myRoots.keySet()) {
1✔
142
      if (!root.isValid() || !root.isDirectory()) {
1!
143
        continue;
×
144
      }
145
      JpsModuleSourceRootPropertiesSerializer<?> serializer = getSerializer(it -> it != null && it.getType().equals(myRoots.get(root)));
1!
146
      if (serializer == null) {
1!
147
        continue;
×
148
      }
149

150
      String collapsedUrl = macroManager.collapsePath(root.getUrl());
1✔
151
      if (StringUtil.isEmpty(collapsedUrl)) {
1!
152
        continue;
×
153
      }
154

155

156
      Element pathElement = new Element(ELEMENT_PATH);
1✔
157
      pathElement.setAttribute(ATTRIBUTE_VALUE, collapsedUrl);
1✔
158
      pathElement.setAttribute(ATTRIBUTE_TYPE, serializer.getTypeId());
1✔
159
      perlConfig.addContent(pathElement);
1✔
160
    }
1✔
161

162
    Element root = new Element("root");
1✔
163
    if (!perlConfig.getChildren().isEmpty()) {
1✔
164
      root.addContent(perlConfig);
1✔
165
    }
166

167
    return root;
1✔
168
  }
169

170
  @Override
171
  public void loadState(@NotNull Element state) {
172
    state = state.getChild(PERL_CONFIG);
1✔
173
    myRoots.clear();
1✔
174
    if (state == null) {
1!
175
      return;
×
176
    }
177
    PathMacroManager macroManager = PathMacroManager.getInstance(myModule);
1✔
178
    for (Element pathElement : state.getChildren(ELEMENT_PATH)) {
1✔
179
      JpsModuleSourceRootPropertiesSerializer<?> serializer =
1✔
180
        getSerializer(it -> it != null && it.getTypeId().equals(pathElement.getAttributeValue(ATTRIBUTE_TYPE)));
1!
181
      if (serializer == null) {
1!
182
        continue;
×
183
      }
184
      String expandedPathOrUrl = macroManager.expandPath(pathElement.getAttributeValue(ATTRIBUTE_VALUE));
1✔
185
      var libRoot = VirtualFileManager.getInstance().findFileByUrl(expandedPathOrUrl);
1✔
186
      if (libRoot == null) {
1!
187
        // fixme migration part, to be removed
188
        libRoot = VfsUtil.findFileByIoFile(new File(expandedPathOrUrl), false);
×
189
      }
190
      if (libRoot != null && libRoot.isValid() && libRoot.isDirectory()) {
1!
191
        myRoots.put(libRoot, (PerlSourceRootType)serializer.getType());
1✔
192
      }
193
    }
1✔
194
  }
1✔
195

196
  public static PerlModuleExtension getInstance(@NotNull Module module) {
197
    return ModuleRootManager.getInstance(module).getModuleExtension(PerlModuleExtension.class);
1✔
198
  }
199

200
  /**
201
   * Modifies {@link PerlModuleExtension} for the {@code module} using {@code mutator}. Incapsulates proper logic of working with modifiable
202
   * model, described in {@link ModuleExtension#getModifiableModel(boolean) javadoc}.
203
   *
204
   * @see ModuleExtension#getModifiableModel(boolean)
205
   */
206
  public static void modify(@NotNull Module module, @NotNull Consumer<? super PerlModuleExtension> mutator) {
207
    ModifiableRootModel modifiableModel = ModuleRootManager.getInstance(module).getModifiableModel();
1✔
208
    PerlModuleExtension moduleExtensionModifiableModel = modifiableModel.getModuleExtension(PerlModuleExtension.class);
1✔
209
    try {
210
      mutator.accept(moduleExtensionModifiableModel);
1✔
211
    }
212
    catch (Throwable e) {
×
213
      LOG.error(e);
×
214
      modifiableModel.dispose();
×
215
    }
216
    finally {
217
      if( moduleExtensionModifiableModel.isChanged()){
1✔
218
        WriteAction.run(modifiableModel::commit);
1✔
219
      }
220
      else {
221
        modifiableModel.dispose();
1✔
222
      }
223
    }
224
  }
1✔
225

226
  private static @Nullable JpsModuleSourceRootPropertiesSerializer<?> getSerializer(
227
    Predicate<? super JpsModuleSourceRootPropertiesSerializer<?>> predicate) {
228
    for (JpsModelSerializerExtension extension : JpsModelSerializerExtension.getExtensions()) {
1!
229
      for (JpsModuleSourceRootPropertiesSerializer<?> serializer : extension.getModuleSourceRootPropertiesSerializers()) {
1!
230
        if (predicate.test(serializer)) {
1!
231
          return serializer;
1✔
232
        }
233
      }
×
234
    }
×
235
    return null;
×
236
  }
237
}
STATUS · Troubleshooting · Open an Issue · Sales · Support · CAREERS · ENTERPRISE · START FREE · SCHEDULE DEMO
ANNOUNCEMENTS · TWITTER · TOS & SLA · Supported CI Services · What's a CI service? · Automated Testing

© 2026 Coveralls, Inc