2 * Copyright 2000-2009 JetBrains s.r.o.
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
8 * http://www.apache.org/licenses/LICENSE-2.0
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.
16 package com
.intellij
.packaging
.impl
.artifacts
;
18 import com
.intellij
.compiler
.CompilerConfiguration
;
19 import com
.intellij
.openapi
.module
.Module
;
20 import com
.intellij
.openapi
.project
.Project
;
21 import com
.intellij
.openapi
.roots
.CompilerProjectExtension
;
22 import com
.intellij
.openapi
.roots
.ContentEntry
;
23 import com
.intellij
.openapi
.roots
.ModuleRootModel
;
24 import com
.intellij
.openapi
.roots
.SourceFolder
;
25 import com
.intellij
.openapi
.util
.Condition
;
26 import com
.intellij
.openapi
.util
.Pair
;
27 import com
.intellij
.openapi
.util
.Trinity
;
28 import com
.intellij
.openapi
.util
.io
.FileUtil
;
29 import com
.intellij
.openapi
.util
.text
.StringUtil
;
30 import com
.intellij
.openapi
.vfs
.VfsUtil
;
31 import com
.intellij
.openapi
.vfs
.VirtualFile
;
32 import com
.intellij
.packaging
.artifacts
.Artifact
;
33 import com
.intellij
.packaging
.artifacts
.ArtifactManager
;
34 import com
.intellij
.packaging
.artifacts
.ArtifactProperties
;
35 import com
.intellij
.packaging
.artifacts
.ArtifactType
;
36 import com
.intellij
.packaging
.elements
.*;
37 import com
.intellij
.packaging
.impl
.elements
.*;
38 import com
.intellij
.util
.Processor
;
39 import com
.intellij
.util
.SmartList
;
40 import com
.intellij
.util
.containers
.ContainerUtil
;
41 import com
.intellij
.util
.containers
.FList
;
42 import org
.jetbrains
.annotations
.NotNull
;
43 import org
.jetbrains
.annotations
.Nullable
;
50 public class ArtifactUtil
{
51 private ArtifactUtil() {
54 public static CompositePackagingElement
<?
> copyFromRoot(@NotNull CompositePackagingElement
<?
> oldRoot
, @NotNull Project project
) {
55 final CompositePackagingElement
<?
> newRoot
= (CompositePackagingElement
<?
>)copyElement(oldRoot
, project
);
56 copyChildren(oldRoot
, newRoot
, project
);
61 public static void copyChildren(CompositePackagingElement
<?
> oldParent
, CompositePackagingElement
<?
> newParent
, @NotNull Project project
) {
62 for (PackagingElement
<?
> child
: oldParent
.getChildren()) {
63 newParent
.addOrFindChild(copyWithChildren(child
, project
));
68 public static <S
> PackagingElement
<S
> copyWithChildren(@NotNull PackagingElement
<S
> element
, @NotNull Project project
) {
69 final PackagingElement
<S
> copy
= copyElement(element
, project
);
70 if (element
instanceof CompositePackagingElement
<?
>) {
71 copyChildren((CompositePackagingElement
<?
>)element
, (CompositePackagingElement
<?
>)copy
, project
);
77 private static <S
> PackagingElement
<S
> copyElement(@NotNull PackagingElement
<S
> element
, @NotNull Project project
) {
78 //noinspection unchecked
79 final PackagingElement
<S
> copy
= (PackagingElement
<S
>)element
.getType().createEmpty(project
);
80 copy
.loadState(element
.getState());
84 public static <E
extends PackagingElement
<?
>> boolean processPackagingElements(@NotNull Artifact artifact
, @Nullable PackagingElementType
<E
> type
,
85 @NotNull final Processor
<?
super E
> processor
,
86 final @NotNull PackagingElementResolvingContext resolvingContext
,
87 final boolean processSubstitutions
) {
88 return processPackagingElements(artifact
, type
, new PackagingElementProcessor
<E
>() {
90 public boolean process(@NotNull E e
, @NotNull PackagingElementPath path
) {
91 return processor
.process(e
);
93 }, resolvingContext
, processSubstitutions
);
96 public static <E
extends PackagingElement
<?
>> boolean processPackagingElements(@NotNull Artifact artifact
, @Nullable PackagingElementType
<E
> type
,
97 @NotNull PackagingElementProcessor
<?
super E
> processor
,
98 final @NotNull PackagingElementResolvingContext resolvingContext
,
99 final boolean processSubstitutions
) {
100 return processPackagingElements(artifact
.getRootElement(), type
, processor
, resolvingContext
, processSubstitutions
, artifact
.getArtifactType());
103 public static <E
extends PackagingElement
<?
>> boolean processPackagingElements(final PackagingElement
<?
> rootElement
, @Nullable PackagingElementType
<E
> type
,
104 @NotNull PackagingElementProcessor
<?
super E
> processor
,
105 final @NotNull PackagingElementResolvingContext resolvingContext
,
106 final boolean processSubstitutions
,
107 final ArtifactType artifactType
) {
108 return processElement(rootElement
, type
, processor
, resolvingContext
, processSubstitutions
, artifactType
,
109 PackagingElementPath
.EMPTY
, new HashSet
<PackagingElement
<?
>>());
112 private static <E
extends PackagingElement
<?
>> boolean processElements(final List
<?
extends PackagingElement
<?
>> elements
,
113 @Nullable PackagingElementType
<E
> type
,
114 @NotNull PackagingElementProcessor
<?
super E
> processor
,
115 final @NotNull PackagingElementResolvingContext resolvingContext
,
116 final boolean processSubstitutions
, ArtifactType artifactType
,
117 @NotNull PackagingElementPath path
,
118 Set
<PackagingElement
<?
>> processed
) {
119 for (PackagingElement
<?
> element
: elements
) {
120 if (!processElement(element
, type
, processor
, resolvingContext
, processSubstitutions
, artifactType
, path
, processed
)) {
127 private static <E
extends PackagingElement
<?
>> boolean processElement(@NotNull PackagingElement
<?
> element
, @Nullable PackagingElementType
<E
> type
,
128 @NotNull PackagingElementProcessor
<?
super E
> processor
,
129 @NotNull PackagingElementResolvingContext resolvingContext
,
130 final boolean processSubstitutions
,
131 ArtifactType artifactType
,
132 @NotNull PackagingElementPath path
, Set
<PackagingElement
<?
>> processed
) {
133 if (!processor
.shouldProcess(element
) || !processed
.add(element
)) {
136 if (type
== null || element
.getType().equals(type
)) {
137 if (!processor
.process((E
)element
, path
)) {
141 if (element
instanceof CompositePackagingElement
<?
>) {
142 final CompositePackagingElement
<?
> composite
= (CompositePackagingElement
<?
>)element
;
143 return processElements(composite
.getChildren(), type
, processor
, resolvingContext
, processSubstitutions
, artifactType
,
144 path
.appendComposite(composite
), processed
);
146 else if (element
instanceof ComplexPackagingElement
<?
> && processSubstitutions
) {
147 final ComplexPackagingElement
<?
> complexElement
= (ComplexPackagingElement
<?
>)element
;
148 if (processor
.shouldProcessSubstitution(complexElement
)) {
149 final List
<?
extends PackagingElement
<?
>> substitution
= complexElement
.getSubstitution(resolvingContext
, artifactType
);
150 if (substitution
!= null) {
151 return processElements(substitution
, type
, processor
, resolvingContext
, processSubstitutions
, artifactType
,
152 path
.appendComplex(complexElement
), processed
);
159 public static void removeDuplicates(@NotNull CompositePackagingElement
<?
> parent
) {
160 List
<PackagingElement
<?
>> prevChildren
= new ArrayList
<PackagingElement
<?
>>();
162 List
<PackagingElement
<?
>> toRemove
= new ArrayList
<PackagingElement
<?
>>();
163 for (PackagingElement
<?
> child
: parent
.getChildren()) {
164 if (child
instanceof CompositePackagingElement
<?
>) {
165 removeDuplicates((CompositePackagingElement
<?
>)child
);
167 boolean merged
= false;
168 for (PackagingElement
<?
> prevChild
: prevChildren
) {
169 if (child
.isEqualTo(prevChild
)) {
170 if (child
instanceof CompositePackagingElement
<?
>) {
171 for (PackagingElement
<?
> childElement
: ((CompositePackagingElement
<?
>)child
).getChildren()) {
172 ((CompositePackagingElement
<?
>)prevChild
).addOrFindChild(childElement
);
183 prevChildren
.add(child
);
187 for (PackagingElement
<?
> child
: toRemove
) {
188 parent
.removeChild(child
);
192 public static <S
> void copyProperties(ArtifactProperties
<?
> from
, ArtifactProperties
<S
> to
) {
193 //noinspection unchecked
194 to
.loadState((S
)from
.getState());
198 public static String
getDefaultArtifactOutputPath(@NotNull String artifactName
, final @NotNull Project project
) {
199 final CompilerProjectExtension extension
= CompilerProjectExtension
.getInstance(project
);
200 if (extension
== null) return null;
201 final String outputUrl
= extension
.getCompilerOutputUrl();
202 if (outputUrl
== null) return null;
203 return VfsUtil
.urlToPath(outputUrl
) + "/artifacts/" + FileUtil
.sanitizeFileName(artifactName
);
206 public static <E
extends PackagingElement
<?
>> boolean processElements(@NotNull List
<?
extends PackagingElement
<?
>> elements
,
207 @NotNull PackagingElementResolvingContext context
,
208 @NotNull ArtifactType artifactType
,
209 @NotNull PackagingElementPath parentPath
,
210 @NotNull PackagingElementProcessor
<E
> processor
) {
211 for (PackagingElement
<?
> element
: elements
) {
212 if (element
instanceof ComplexPackagingElement
<?
> && processor
.shouldProcessSubstitution((ComplexPackagingElement
)element
)) {
213 final ComplexPackagingElement
<?
> complexElement
= (ComplexPackagingElement
<?
>)element
;
214 final List
<?
extends PackagingElement
<?
>> substitution
= complexElement
.getSubstitution(context
, artifactType
);
215 if (substitution
!= null && !processElements(substitution
, context
, artifactType
, parentPath
.appendComplex(complexElement
), processor
)) {
219 else if (!processor
.process((E
)element
, parentPath
)) {
226 public static List
<PackagingElement
<?
>> findByRelativePath(@NotNull CompositePackagingElement
<?
> parent
, @NotNull String relativePath
,
227 @NotNull PackagingElementResolvingContext context
, @NotNull ArtifactType artifactType
) {
228 final List
<PackagingElement
<?
>> result
= new ArrayList
<PackagingElement
<?
>>();
229 processElementsByRelativePath(parent
, relativePath
, context
, artifactType
, PackagingElementPath
.EMPTY
, new PackagingElementProcessor
<PackagingElement
<?
>>() {
231 public boolean process(@NotNull PackagingElement
<?
> packagingElement
, @NotNull PackagingElementPath path
) {
232 result
.add(packagingElement
);
239 public static boolean processElementsByRelativePath(@NotNull final CompositePackagingElement
<?
> parent
, @NotNull String relativePath
,
240 @NotNull final PackagingElementResolvingContext context
, @NotNull final ArtifactType artifactType
,
241 @NotNull PackagingElementPath parentPath
,
242 @NotNull final PackagingElementProcessor
<PackagingElement
<?
>> processor
) {
243 relativePath
= StringUtil
.trimStart(relativePath
, "/");
244 if (relativePath
.length() == 0) {
248 int i
= relativePath
.indexOf('/');
249 final String firstName
= i
!= -1 ? relativePath
.substring(0, i
) : relativePath
;
250 final String tail
= i
!= -1 ? relativePath
.substring(i
+1) : "";
252 return processElements(parent
.getChildren(), context
, artifactType
, parentPath
.appendComposite(parent
), new PackagingElementProcessor
<PackagingElement
<?
>>() {
254 public boolean process(@NotNull PackagingElement
<?
> element
, @NotNull PackagingElementPath path
) {
255 boolean process
= false;
256 if (element
instanceof CompositePackagingElement
&& firstName
.equals(((CompositePackagingElement
<?
>)element
).getName())) {
259 else if (element
instanceof FileCopyPackagingElement
) {
260 final FileCopyPackagingElement fileCopy
= (FileCopyPackagingElement
)element
;
261 if (firstName
.equals(fileCopy
.getOutputFileName())) {
267 if (tail
.length() == 0) {
268 if (!processor
.process(element
, path
)) return false;
270 else if (element
instanceof CompositePackagingElement
<?
>) {
271 return processElementsByRelativePath((CompositePackagingElement
)element
, tail
, context
, artifactType
, path
, processor
);
279 public static boolean processDirectoryChildren(@NotNull CompositePackagingElement
<?
> parent
,
280 @NotNull PackagingElementPath pathToParent
,
281 @NotNull String relativePath
,
282 @NotNull final PackagingElementResolvingContext context
,
283 @NotNull final ArtifactType artifactType
,
284 @NotNull final PackagingElementProcessor
<PackagingElement
<?
>> processor
) {
285 return processElementsByRelativePath(parent
, relativePath
, context
, artifactType
, pathToParent
, new PackagingElementProcessor
<PackagingElement
<?
>>() {
287 public boolean process(@NotNull PackagingElement
<?
> element
, @NotNull PackagingElementPath path
) {
288 if (element
instanceof DirectoryPackagingElement
) {
289 final List
<PackagingElement
<?
>> children
= ((DirectoryPackagingElement
)element
).getChildren();
290 if (!processElements(children
, context
, artifactType
, path
.appendComposite((DirectoryPackagingElement
)element
), processor
)) {
299 public static void processFileOrDirectoryCopyElements(Artifact artifact
,
300 PackagingElementProcessor
<FileOrDirectoryCopyPackagingElement
<?
>> processor
,
301 PackagingElementResolvingContext context
,
302 boolean processSubstitutions
) {
303 processPackagingElements(artifact
, PackagingElementFactoryImpl
.FILE_COPY_ELEMENT_TYPE
, processor
, context
, processSubstitutions
);
304 processPackagingElements(artifact
, PackagingElementFactoryImpl
.DIRECTORY_COPY_ELEMENT_TYPE
, processor
, context
, processSubstitutions
);
307 public static Collection
<Trinity
<Artifact
, PackagingElementPath
, String
>> findContainingArtifactsWithOutputPaths(@NotNull final VirtualFile file
, @NotNull Project project
) {
308 final boolean isResourceFile
= CompilerConfiguration
.getInstance(project
).isResourceFile(file
);
309 final List
<Trinity
<Artifact
, PackagingElementPath
, String
>> artifacts
= new ArrayList
<Trinity
<Artifact
, PackagingElementPath
, String
>>();
310 final PackagingElementResolvingContext context
= ArtifactManager
.getInstance(project
).getResolvingContext();
311 for (final Artifact artifact
: ArtifactManager
.getInstance(project
).getArtifacts()) {
312 processPackagingElements(artifact
, null, new PackagingElementProcessor
<PackagingElement
<?
>>() {
314 public boolean process(@NotNull PackagingElement
<?
> element
, @NotNull PackagingElementPath path
) {
315 if (element
instanceof FileOrDirectoryCopyPackagingElement
<?
>) {
316 final VirtualFile root
= ((FileOrDirectoryCopyPackagingElement
)element
).findFile();
317 if (root
!= null && VfsUtil
.isAncestor(root
, file
, false)) {
318 final String relativePath
;
319 if (root
.equals(file
) && element
instanceof FileCopyPackagingElement
) {
320 relativePath
= ((FileCopyPackagingElement
)element
).getOutputFileName();
323 relativePath
= VfsUtil
.getRelativePath(file
, root
, '/');
325 artifacts
.add(Trinity
.create(artifact
, path
, relativePath
));
329 else if (isResourceFile
&& element
instanceof ModuleOutputPackagingElement
) {
330 final String relativePath
= getRelativePathInSources(file
, (ModuleOutputPackagingElement
)element
, context
);
331 if (relativePath
!= null) {
332 artifacts
.add(Trinity
.create(artifact
, path
, relativePath
));
344 private static String
getRelativePathInSources(@NotNull VirtualFile file
, final @NotNull ModuleOutputPackagingElement moduleElement
,
345 @NotNull PackagingElementResolvingContext context
) {
346 final Module module
= moduleElement
.findModule(context
);
347 if (module
!= null) {
348 final ModuleRootModel rootModel
= context
.getModulesProvider().getRootModel(module
);
349 for (ContentEntry entry
: rootModel
.getContentEntries()) {
350 for (SourceFolder folder
: entry
.getSourceFolders()) {
351 final VirtualFile sourceRoot
= folder
.getFile();
352 if (!folder
.isTestSource() && sourceRoot
!= null && VfsUtil
.isAncestor(sourceRoot
, file
, true)) {
353 return VfsUtil
.getRelativePath(file
, sourceRoot
, '/');
362 public static VirtualFile
findSourceFileByOutputPath(Artifact artifact
, String outputPath
, PackagingElementResolvingContext context
) {
363 final List
<VirtualFile
> files
= findSourceFilesByOutputPath(artifact
.getRootElement(), outputPath
, context
, artifact
.getArtifactType());
364 return files
.isEmpty() ?
null : files
.get(0);
368 public static VirtualFile
findSourceFileByOutputPath(CompositePackagingElement
<?
> parent
, String outputPath
,
369 PackagingElementResolvingContext context
, ArtifactType artifactType
) {
370 final List
<VirtualFile
> files
= findSourceFilesByOutputPath(parent
, outputPath
, context
, artifactType
);
371 return files
.isEmpty() ?
null : files
.get(0);
374 public static List
<VirtualFile
> findSourceFilesByOutputPath(CompositePackagingElement
<?
> parent
, final String outputPath
,
375 final PackagingElementResolvingContext context
, final ArtifactType artifactType
) {
376 final String path
= StringUtil
.trimStart(outputPath
, "/");
377 if (path
.length() == 0) {
378 return Collections
.emptyList();
381 int i
= path
.indexOf('/');
382 final String firstName
= i
!= -1 ? path
.substring(0, i
) : path
;
383 final String tail
= i
!= -1 ? path
.substring(i
+1) : "";
385 final List
<VirtualFile
> result
= new SmartList
<VirtualFile
>();
386 processElements(parent
.getChildren(), context
, artifactType
, PackagingElementPath
.EMPTY
, new PackagingElementProcessor
<PackagingElement
<?
>>() {
388 public boolean process(@NotNull PackagingElement
<?
> element
, @NotNull PackagingElementPath elementPath
) {
389 //todo[nik] replace by method findSourceFile() in PackagingElement
390 if (element
instanceof CompositePackagingElement
) {
391 final CompositePackagingElement
<?
> compositeElement
= (CompositePackagingElement
<?
>)element
;
392 if (firstName
.equals(compositeElement
.getName())) {
393 result
.addAll(findSourceFilesByOutputPath(compositeElement
, tail
, context
, artifactType
));
396 else if (element
instanceof FileCopyPackagingElement
) {
397 final FileCopyPackagingElement fileCopyElement
= (FileCopyPackagingElement
)element
;
398 if (firstName
.equals(fileCopyElement
.getOutputFileName()) && tail
.length() == 0) {
399 ContainerUtil
.addIfNotNull(fileCopyElement
.findFile(), result
);
402 else if (element
instanceof DirectoryCopyPackagingElement
) {
403 final VirtualFile sourceRoot
= ((DirectoryCopyPackagingElement
)element
).findFile();
404 if (sourceRoot
!= null) {
405 ContainerUtil
.addIfNotNull(sourceRoot
.findFileByRelativePath(path
), result
);
408 else if (element
instanceof ModuleOutputPackagingElement
) {
409 final Module module
= ((ModuleOutputPackagingElement
)element
).findModule(context
);
410 if (module
!= null) {
411 final ContentEntry
[] contentEntries
= context
.getModulesProvider().getRootModel(module
).getContentEntries();
412 for (ContentEntry contentEntry
: contentEntries
) {
413 for (SourceFolder sourceFolder
: contentEntry
.getSourceFolders()) {
414 final VirtualFile sourceRoot
= sourceFolder
.getFile();
415 if (!sourceFolder
.isTestSource() && sourceRoot
!= null) {
416 ContainerUtil
.addIfNotNull(sourceRoot
.findFileByRelativePath(path
), result
);
429 public static boolean processParents(@NotNull Artifact artifact
,
430 @NotNull PackagingElementResolvingContext context
,
431 @NotNull ParentElementProcessor processor
,
433 return processParents(artifact
, context
, processor
, FList
.<Pair
<Artifact
, CompositePackagingElement
<?
>>>emptyList(), maxLevel
,
434 new HashSet
<Artifact
>());
437 private static boolean processParents(@NotNull final Artifact artifact
, @NotNull final PackagingElementResolvingContext context
,
438 @NotNull final ParentElementProcessor processor
, FList
<Pair
<Artifact
, CompositePackagingElement
<?
>>> pathToElement
,
439 final int maxLevel
, final Set
<Artifact
> processed
) {
440 if (!processed
.add(artifact
)) return true;
442 final FList
<Pair
<Artifact
, CompositePackagingElement
<?
>>> pathFromRoot
;
443 final CompositePackagingElement
<?
> rootElement
= artifact
.getRootElement();
444 if (rootElement
instanceof ArtifactRootElement
<?
>) {
445 pathFromRoot
= pathToElement
;
448 if (!processor
.process(rootElement
, pathToElement
, artifact
)) {
451 pathFromRoot
= pathToElement
.prepend(new Pair
<Artifact
, CompositePackagingElement
<?
>>(artifact
, rootElement
));
453 if (pathFromRoot
.size() > maxLevel
) return true;
455 for (final Artifact anArtifact
: context
.getArtifactModel().getArtifacts()) {
456 if (processed
.contains(anArtifact
)) continue;
458 final PackagingElementProcessor
<ArtifactPackagingElement
> elementProcessor
=
459 new PackagingElementProcessor
<ArtifactPackagingElement
>() {
461 public boolean shouldProcessSubstitution(ComplexPackagingElement
<?
> element
) {
462 return !(element
instanceof ArtifactPackagingElement
);
466 public boolean process(@NotNull ArtifactPackagingElement element
, @NotNull PackagingElementPath path
) {
467 if (artifact
.getName().equals(element
.getArtifactName())) {
468 FList
<Pair
<Artifact
, CompositePackagingElement
<?
>>> currentPath
= pathFromRoot
;
469 final List
<CompositePackagingElement
<?
>> parents
= path
.getParents();
470 for (int i
= 0, parentsSize
= parents
.size(); i
< parentsSize
- 1; i
++) {
471 CompositePackagingElement
<?
> parent
= parents
.get(i
);
472 if (!processor
.process(parent
, currentPath
, anArtifact
)) {
475 currentPath
= currentPath
.prepend(new Pair
<Artifact
, CompositePackagingElement
<?
>>(anArtifact
, parent
));
476 if (currentPath
.size() > maxLevel
) {
481 if (!parents
.isEmpty()) {
482 CompositePackagingElement
<?
> lastParent
= parents
.get(parents
.size() - 1);
483 if (lastParent
instanceof ArtifactRootElement
<?
> && !processor
.process(lastParent
, currentPath
, anArtifact
)) {
487 return processParents(anArtifact
, context
, processor
, currentPath
, maxLevel
, processed
);
492 if (!processPackagingElements(anArtifact
, ArtifactElementType
.ARTIFACT_ELEMENT_TYPE
, elementProcessor
, context
, true)) {
499 public static boolean isArchiveName(String name
) {
500 return name
.length() >= 4 && name
.charAt(name
.length() - 4) == '.' && StringUtil
.endsWithIgnoreCase(name
, "ar");
503 public static void removeChildrenRecursively(@NotNull CompositePackagingElement
<?
> element
, @NotNull Condition
<PackagingElement
<?
>> condition
) {
504 List
<PackagingElement
<?
>> toRemove
= new ArrayList
<PackagingElement
<?
>>();
505 for (PackagingElement
<?
> child
: element
.getChildren()) {
506 if (child
instanceof CompositePackagingElement
<?
>) {
507 final CompositePackagingElement
<?
> compositeChild
= (CompositePackagingElement
<?
>)child
;
508 removeChildrenRecursively(compositeChild
, condition
);
509 if (compositeChild
.getChildren().isEmpty()) {
513 else if (condition
.value(child
)) {
518 element
.removeChildren(toRemove
);
521 public static boolean shouldClearArtifactOutputBeforeRebuild(Artifact artifact
) {
522 final String outputPath
= artifact
.getOutputPath();
523 return !StringUtil
.isEmpty(outputPath
) && artifact
.getRootElement() instanceof ArtifactRootElement
<?
>;