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

Camelcade / Perl5-IDEA / #525521698

03 Nov 2025 11:37AM UTC coverage: 75.942% (+0.09%) from 75.853%
#525521698

push

github

hurricup
IJPL-176579 Hack for the jsvg platform conflict

There are two incompatible versions of jsvg - 1.3 used by ui, and another one provided by `jetbrains.lets.plot.export.shadowed`

14756 of 22625 branches covered (65.22%)

Branch coverage included in aggregate %.

31091 of 37746 relevant lines covered (82.37%)

0.82 hits per line

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

76.22
/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.perl5.lang.perl.idea.modules.PerlSourceRootType;
33
import org.jdom.Element;
34
import org.jetbrains.annotations.ApiStatus;
35
import org.jetbrains.annotations.NotNull;
36
import org.jetbrains.annotations.Nullable;
37
import org.jetbrains.jps.model.module.JpsModuleSourceRootType;
38
import org.jetbrains.jps.model.serialization.JpsModelSerializerExtension;
39
import org.jetbrains.jps.model.serialization.module.JpsModuleSourceRootPropertiesSerializer;
40

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

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

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

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

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

81
  @Override
82
  public void commit() {
83
    LOG.assertTrue(myOriginal != null, "Attempt to commit non-modifiable model");
1!
84
    if (isChanged()) {
1!
85
      synchronized (myOriginal) {
1✔
86
        myOriginal.myRoots = new LinkedHashMap<>(myRoots);
1✔
87
        myOriginal.myModificationTracker++;
1✔
88
      }
1✔
89
    }
90
  }
1✔
91

92
  @Override
93
  public boolean isChanged() {
94
    return !myRoots.equals(myOriginal.myRoots);
1✔
95
  }
96

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

104
  public synchronized void removeRoot(@NotNull VirtualFile root) {
105
    LOG.assertTrue(myIsWritable, "Obtain modifiableModel first");
1✔
106
    myRoots.remove(root);
1✔
107
    myModificationTracker++;
1✔
108
  }
1✔
109

110
  public Map<VirtualFile, PerlSourceRootType> getRoots() {
111
    return Collections.unmodifiableMap(myRoots);
×
112
  }
113

114
  public synchronized List<VirtualFile> getRootsByType(@NotNull PerlSourceRootType type) {
115
    return myRoots.entrySet().stream()
1✔
116
      .filter(entry -> type.equals(entry.getValue()))
1✔
117
      .map(Map.Entry::getKey)
1✔
118
      .collect(Collectors.toList());
1✔
119
  }
120

121
  public @Nullable PerlSourceRootType getRootType(@NotNull VirtualFile virtualFile) {
122
    return myRoots.get(virtualFile);
×
123
  }
124

125
  @Override
126
  public long getStateModificationCount() {
127
    return myModificationTracker;
×
128
  }
129

130
  @Override
131
  public @Nullable Element getState() {
132
    Element perlConfig = new Element(PERL_CONFIG);
1✔
133

134
    PathMacroManager macroManager = PathMacroManager.getInstance(myModule);
1✔
135

136
    for (VirtualFile root : myRoots.keySet()) {
1✔
137
      if (!root.isValid() || !root.isDirectory()) {
1!
138
        continue;
×
139
      }
140
      JpsModuleSourceRootPropertiesSerializer<?> serializer = getSerializer(it -> it != null && it.getType().equals(myRoots.get(root)));
1!
141
      if (serializer == null) {
1!
142
        continue;
×
143
      }
144

145
      String collapsedUrl = macroManager.collapsePath(root.getUrl());
1✔
146
      if (StringUtil.isEmpty(collapsedUrl)) {
1!
147
        continue;
×
148
      }
149

150

151
      Element pathElement = new Element(ELEMENT_PATH);
1✔
152
      pathElement.setAttribute(ATTRIBUTE_VALUE, collapsedUrl);
1✔
153
      pathElement.setAttribute(ATTRIBUTE_TYPE, serializer.getTypeId());
1✔
154
      perlConfig.addContent(pathElement);
1✔
155
    }
1✔
156

157
    Element root = new Element("root");
1✔
158
    if (!perlConfig.getChildren().isEmpty()) {
1✔
159
      root.addContent(perlConfig);
1✔
160
    }
161

162
    return root;
1✔
163
  }
164

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

191
  public static PerlModuleExtension getInstance(@NotNull Module module) {
192
    return ModuleRootManager.getInstance(module).getModuleExtension(PerlModuleExtension.class);
1✔
193
  }
194

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

224
  private static @Nullable JpsModuleSourceRootPropertiesSerializer<?> getSerializer(
225
    Predicate<? super JpsModuleSourceRootPropertiesSerializer<?>> predicate) {
226
    for (JpsModelSerializerExtension extension : JpsModelSerializerExtension.getExtensions()) {
1!
227
      for (JpsModuleSourceRootPropertiesSerializer<?> serializer : extension.getModuleSourceRootPropertiesSerializers()) {
1!
228
        if (predicate.test(serializer)) {
1!
229
          return serializer;
1✔
230
        }
231
      }
×
232
    }
×
233
    return null;
×
234
  }
235
}
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