Add support for packaging Module Sources to Artifacts. (IDEA-110964)
authorIlya Ryzhenkov <orangy@jetbrains.com>
Wed, 25 Apr 2018 18:01:37 +0000 (21:01 +0300)
committerIlya Ryzhenkov <orangy@jetbrains.com>
Fri, 1 Jun 2018 15:25:56 +0000 (18:25 +0300)
36 files changed:
java/compiler/impl/src/com/intellij/compiler/ant/artifacts/ArtifactsGenerator.java
java/compiler/impl/src/com/intellij/packaging/impl/artifacts/ArtifactUtil.java
java/compiler/impl/src/com/intellij/packaging/impl/elements/ModuleElementTypeBase.java [new file with mode: 0644]
java/compiler/impl/src/com/intellij/packaging/impl/elements/ModuleOutputElementTypeBase.java
java/compiler/impl/src/com/intellij/packaging/impl/elements/ModuleOutputPackagingElement.java
java/compiler/impl/src/com/intellij/packaging/impl/elements/ModuleOutputPackagingElementBase.java
java/compiler/impl/src/com/intellij/packaging/impl/elements/ModulePackagingElement.java [new file with mode: 0644]
java/compiler/impl/src/com/intellij/packaging/impl/elements/ModulePackagingElementBase.java [new file with mode: 0644]
java/compiler/impl/src/com/intellij/packaging/impl/elements/ModulePackagingElementState.java [new file with mode: 0644]
java/compiler/impl/src/com/intellij/packaging/impl/elements/PackagingElementFactoryImpl.java
java/compiler/impl/src/com/intellij/packaging/impl/elements/ProductionModuleOutputElementType.java
java/compiler/impl/src/com/intellij/packaging/impl/elements/ProductionModuleOutputPackagingElement.java
java/compiler/impl/src/com/intellij/packaging/impl/elements/ProductionModuleSourceElementType.kt [new file with mode: 0644]
java/compiler/impl/src/com/intellij/packaging/impl/elements/ProductionModuleSourcePackagingElement.kt [new file with mode: 0644]
java/compiler/impl/src/com/intellij/packaging/impl/elements/TestModuleOutputElementType.java
java/compiler/impl/src/com/intellij/packaging/impl/elements/TestModuleOutputPackagingElement.java
java/compiler/impl/src/com/intellij/packaging/impl/ui/ModuleElementPresentation.java
java/compiler/openapi/src/com/intellij/openapi/compiler/CompilerBundle.java
java/compiler/openapi/src/com/intellij/packaging/elements/PackagingElementFactory.java
java/compiler/openapi/src/com/intellij/packaging/elements/PackagingElementOutputKind.java
java/compiler/openapi/src/com/intellij/packaging/ui/SourceItemWeights.java
java/compiler/tests/com/intellij/compiler/artifacts/TestPackagingElementBuilder.java
java/compiler/tests/com/intellij/compiler/artifacts/UpdateArtifactsAfterRenameTest.java
java/compiler/tests/com/intellij/compiler/artifacts/ui/AddNewElementActionTest.java
java/idea-ui/src/com/intellij/openapi/roots/ui/configuration/artifacts/ArtifactProjectStructureElement.java
java/idea-ui/src/com/intellij/openapi/roots/ui/configuration/artifacts/sourceItems/ModuleOutputSourceItem.java
java/idea-ui/src/com/intellij/openapi/roots/ui/configuration/artifacts/sourceItems/ModulesAndLibrariesSourceItemsProvider.java
jps/jps-builders/src/org/jetbrains/jps/incremental/artifacts/builders/LayoutElementBuildersRegistry.java
jps/jps-builders/testSrc/org/jetbrains/jps/incremental/artifacts/ArtifactBuilderTest.kt
jps/jps-builders/testSrc/org/jetbrains/jps/incremental/artifacts/LayoutElementTestUtil.java
jps/model-api/src/org/jetbrains/jps/model/java/JpsJavaExtensionService.java
jps/model-api/src/org/jetbrains/jps/model/java/JpsProductionModuleSourcePackagingElement.java [new file with mode: 0644]
jps/model-impl/src/org/jetbrains/jps/model/java/impl/JpsJavaExtensionServiceImpl.java
jps/model-impl/src/org/jetbrains/jps/model/java/impl/JpsProductionModuleSourcePackagingElementImpl.java [new file with mode: 0644]
jps/model-serialization/src/org/jetbrains/jps/model/serialization/java/JpsJavaModelSerializerExtension.java
resources-en/src/messages/CompilerBundle.properties

index 4ce28f50f884df11f4ba76dfb03b0af9284a6d27..fbeacf6f13d61d4f9087de2c69a270c28d109142 100644 (file)
@@ -25,14 +25,11 @@ import com.intellij.openapi.util.text.StringUtil;
 import com.intellij.packaging.artifacts.Artifact;
 import com.intellij.packaging.artifacts.ArtifactManager;
 import com.intellij.packaging.artifacts.ArtifactType;
-import com.intellij.packaging.elements.PackagingElement;
 import com.intellij.packaging.elements.PackagingElementResolvingContext;
 import com.intellij.packaging.impl.artifacts.ArtifactUtil;
 import com.intellij.packaging.impl.elements.ArtifactPackagingElement;
 import com.intellij.packaging.impl.elements.ModuleOutputPackagingElement;
-import com.intellij.util.Processor;
 import org.jetbrains.annotations.NonNls;
-import org.jetbrains.annotations.NotNull;
 
 import java.util.ArrayList;
 import java.util.Arrays;
index e8017ca8dd98fd05031c6cb583d52e1afffe23ec..f7503dc47c566fae0668fc959801c4939737bbaa 100644 (file)
@@ -437,9 +437,9 @@ public class ArtifactUtil {
             ContainerUtil.addIfNotNull(result, sourceRoot.findFileByRelativePath(path));
           }
         }
-        else if (element instanceof ModuleOutputPackagingElement) {
+        else if (element instanceof ModulePackagingElement) {
           final CompilerConfiguration compilerConfiguration = CompilerConfiguration.getInstance(context.getProject());
-          for (VirtualFile sourceRoot : ((ModuleOutputPackagingElement)element).getSourceRoots(context)) {
+          for (VirtualFile sourceRoot : ((ModulePackagingElement)element).getSourceRoots(context)) {
             final VirtualFile sourceFile = sourceRoot.findFileByRelativePath(path);
             if (sourceFile != null && compilerConfiguration.isResourceFile(sourceFile)) {
               result.add(sourceFile);
diff --git a/java/compiler/impl/src/com/intellij/packaging/impl/elements/ModuleElementTypeBase.java b/java/compiler/impl/src/com/intellij/packaging/impl/elements/ModuleElementTypeBase.java
new file mode 100644 (file)
index 0000000..4a5c1cf
--- /dev/null
@@ -0,0 +1,91 @@
+/*
+ * Copyright 2000-2011 JetBrains s.r.o.
+ *
+ * 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.intellij.packaging.impl.elements;
+
+import com.intellij.icons.AllIcons;
+import com.intellij.openapi.module.Module;
+import com.intellij.openapi.module.ModulePointer;
+import com.intellij.openapi.module.ModulePointerManager;
+import com.intellij.openapi.module.ModuleType;
+import com.intellij.openapi.project.Project;
+import com.intellij.openapi.project.ProjectBundle;
+import com.intellij.openapi.roots.ui.configuration.ModulesProvider;
+import com.intellij.packaging.artifacts.Artifact;
+import com.intellij.packaging.elements.CompositePackagingElement;
+import com.intellij.packaging.elements.PackagingElement;
+import com.intellij.packaging.elements.PackagingElementType;
+import com.intellij.packaging.ui.ArtifactEditorContext;
+import org.jetbrains.annotations.NotNull;
+import org.jetbrains.annotations.Nullable;
+
+import javax.swing.*;
+import java.util.ArrayList;
+import java.util.List;
+
+/**
+ * @author nik
+ */
+public abstract class ModuleElementTypeBase<E extends ModulePackagingElementBase> extends PackagingElementType<E> {
+  public ModuleElementTypeBase(String id, String presentableName) {
+    super(id, presentableName);
+  }
+
+  @Override
+  public boolean canCreate(@NotNull ArtifactEditorContext context, @NotNull Artifact artifact) {
+    return !getSuitableModules(context).isEmpty();
+  }
+
+  @NotNull
+  public List<? extends PackagingElement<?>> chooseAndCreate(@NotNull ArtifactEditorContext context, @NotNull Artifact artifact,
+                                                                       @NotNull CompositePackagingElement<?> parent) {
+    List<Module> suitableModules = getSuitableModules(context);
+    List<Module> selected = context.chooseModules(suitableModules, ProjectBundle.message("dialog.title.packaging.choose.module"));
+
+    final List<PackagingElement<?>> elements = new ArrayList<>();
+    final ModulePointerManager pointerManager = ModulePointerManager.getInstance(context.getProject());
+    for (Module module : selected) {
+      elements.add(createElement(context.getProject(), pointerManager.create(module)));
+    }
+    return elements;
+  }
+
+  protected abstract ModulePackagingElementBase createElement(@NotNull Project project, @NotNull ModulePointer pointer);
+
+  private List<Module> getSuitableModules(ArtifactEditorContext context) {
+    ModulesProvider modulesProvider = context.getModulesProvider();
+    ArrayList<Module> modules = new ArrayList<>();
+    for (Module module : modulesProvider.getModules()) {
+      if (isSuitableModule(modulesProvider, module)) {
+        modules.add(module);
+      }
+    }
+    return modules;
+  }
+
+  public abstract boolean isSuitableModule(@NotNull ModulesProvider modulesProvider, @NotNull Module module);
+
+  /**
+   * Provides element presentation text.
+   * @param moduleName name of the module for which this presentation is requested.
+   * @return text to display.
+   */
+  @NotNull
+  public abstract String getElementText(@NotNull String moduleName);
+
+  public Icon getElementIcon(@Nullable Module module) {
+    return module != null ? ModuleType.get(module).getIcon() : AllIcons.Modules.Output;
+  }
+}
index f3ee27bf8817d6da88e77e7728f4712a77bae81f..37c60c44b95417d4ceea7f05ee7986e4751826b7 100644 (file)
@@ -1,75 +1,17 @@
-/*
- * Copyright 2000-2011 JetBrains s.r.o.
- *
- * 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.
- */
+// Copyright 2000-2018 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license that can be found in the LICENSE file.
 package com.intellij.packaging.impl.elements;
 
-import com.intellij.openapi.module.Module;
-import com.intellij.openapi.module.ModulePointer;
-import com.intellij.openapi.module.ModulePointerManager;
-import com.intellij.openapi.project.Project;
-import com.intellij.openapi.project.ProjectBundle;
-import com.intellij.openapi.roots.ui.configuration.ModulesProvider;
-import com.intellij.packaging.artifacts.Artifact;
-import com.intellij.packaging.elements.CompositePackagingElement;
-import com.intellij.packaging.elements.PackagingElement;
-import com.intellij.packaging.elements.PackagingElementType;
-import com.intellij.packaging.ui.ArtifactEditorContext;
+import com.intellij.openapi.compiler.CompilerBundle;
 import org.jetbrains.annotations.NotNull;
 
-import java.util.ArrayList;
-import java.util.List;
-
-/**
- * @author nik
- */
-public abstract class ModuleOutputElementTypeBase<E extends ModuleOutputPackagingElementBase> extends PackagingElementType<E> {
+public abstract class ModuleOutputElementTypeBase<E extends ModulePackagingElementBase> extends ModuleElementTypeBase<E> {
   public ModuleOutputElementTypeBase(String id, String presentableName) {
     super(id, presentableName);
   }
 
-  @Override
-  public boolean canCreate(@NotNull ArtifactEditorContext context, @NotNull Artifact artifact) {
-    return !getSuitableModules(context).isEmpty();
-  }
-
   @NotNull
-  public List<? extends PackagingElement<?>> chooseAndCreate(@NotNull ArtifactEditorContext context, @NotNull Artifact artifact,
-                                                                       @NotNull CompositePackagingElement<?> parent) {
-    List<Module> suitableModules = getSuitableModules(context);
-    List<Module> selected = context.chooseModules(suitableModules, ProjectBundle.message("dialog.title.packaging.choose.module"));
-
-    final List<PackagingElement<?>> elements = new ArrayList<>();
-    final ModulePointerManager pointerManager = ModulePointerManager.getInstance(context.getProject());
-    for (Module module : selected) {
-      elements.add(createElement(context.getProject(), pointerManager.create(module)));
-    }
-    return elements;
-  }
-
-  protected abstract ModuleOutputPackagingElementBase createElement(@NotNull Project project, @NotNull ModulePointer pointer);
-
-  private List<Module> getSuitableModules(ArtifactEditorContext context) {
-    ModulesProvider modulesProvider = context.getModulesProvider();
-    ArrayList<Module> modules = new ArrayList<>();
-    for (Module module : modulesProvider.getModules()) {
-      if (isSuitableModule(modulesProvider, module)) {
-        modules.add(module);
-      }
-    }
-    return modules;
+  @Override
+  public String getElementText(@NotNull String moduleName) {
+    return CompilerBundle.message("node.text.0.compile.output", moduleName);
   }
-
-  public abstract boolean isSuitableModule(ModulesProvider modulesProvider, Module module);
 }
index d73572d365297507c8ff0b0ac62b66cfd1295a11..eab8f68339127738bd549b24024c8825340f65e6 100644 (file)
@@ -1,38 +1,5 @@
-/*
- * Copyright 2000-2010 JetBrains s.r.o.
- *
- * 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.
- */
+// Copyright 2000-2018 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license that can be found in the LICENSE file.
 package com.intellij.packaging.impl.elements;
 
-import com.intellij.openapi.module.Module;
-import com.intellij.openapi.vfs.VirtualFile;
-import com.intellij.packaging.elements.PackagingElementResolvingContext;
-import org.jetbrains.annotations.NotNull;
-import org.jetbrains.annotations.Nullable;
-
-import java.util.Collection;
-
-/**
- * @author nik
- */
-public interface ModuleOutputPackagingElement {
-  @Nullable
-  String getModuleName();
-
-  @Nullable
-  Module findModule(PackagingElementResolvingContext context);
-
-  @NotNull
-  Collection<VirtualFile> getSourceRoots(PackagingElementResolvingContext context);
+public interface ModuleOutputPackagingElement extends ModulePackagingElement{
 }
index f23b0daa160a3f2b01dde5287872b524438210a1..ed5e9cdb0ea59e3be53ebb627eb93a63217de09b 100644 (file)
@@ -3,119 +3,47 @@ package com.intellij.packaging.impl.elements;
 
 import com.intellij.compiler.ant.BuildProperties;
 import com.intellij.compiler.ant.Generator;
-import com.intellij.openapi.module.Module;
 import com.intellij.openapi.module.ModulePointer;
-import com.intellij.openapi.module.ModulePointerManager;
 import com.intellij.openapi.project.Project;
-import com.intellij.openapi.roots.CompilerModuleExtension;
-import com.intellij.openapi.roots.ui.configuration.DefaultModulesProvider;
-import com.intellij.openapi.roots.ui.configuration.ModulesProvider;
-import com.intellij.openapi.vfs.VirtualFile;
 import com.intellij.packaging.artifacts.ArtifactType;
 import com.intellij.packaging.elements.*;
-import com.intellij.util.ArrayUtil;
-import com.intellij.util.xmlb.annotations.Attribute;
-import org.jetbrains.annotations.NonNls;
 import org.jetbrains.annotations.NotNull;
 import org.jetbrains.annotations.Nullable;
 
 import java.util.Collections;
 import java.util.List;
 
-/**
- * @author nik
- */
-public abstract class ModuleOutputPackagingElementBase extends PackagingElement<ModuleOutputPackagingElementBase.ModuleOutputPackagingElementState> implements ModuleOutputPackagingElement {
-  @NonNls public static final String MODULE_NAME_ATTRIBUTE = "name";
-  protected ModulePointer myModulePointer;
-  protected final Project myProject;
-
-  public ModuleOutputPackagingElementBase(PackagingElementType type, Project project, ModulePointer modulePointer) {
-    super(type);
-    myProject = project;
-    myModulePointer = modulePointer;
+public abstract class ModuleOutputPackagingElementBase extends ModulePackagingElementBase implements ModuleOutputPackagingElement {
+  public ModuleOutputPackagingElementBase(PackagingElementType type,
+                                          Project project,
+                                          ModulePointer modulePointer) {
+    super(type, project, modulePointer);
   }
 
-  public ModuleOutputPackagingElementBase(PackagingElementType type, Project project) {
-    super(type);
-    myProject = project;
-  }
+  @Nullable
+  protected abstract String getDirectoryAntProperty(ArtifactAntGenerationContext generationContext);
 
   @NotNull
   @Override
-  public List<? extends Generator> computeAntInstructions(@NotNull PackagingElementResolvingContext resolvingContext, @NotNull AntCopyInstructionCreator creator,
+  public List<? extends Generator> computeAntInstructions(@NotNull PackagingElementResolvingContext resolvingContext,
+                                                          @NotNull AntCopyInstructionCreator creator,
                                                           @NotNull ArtifactAntGenerationContext generationContext,
                                                           @NotNull ArtifactType artifactType) {
-    if (myModulePointer != null) {
-      final String moduleOutput = BuildProperties.propertyRef(getModuleOutputAntProperty(generationContext));
+    String property = getDirectoryAntProperty(generationContext);
+    if (myModulePointer != null && property != null) {
+      final String moduleOutput = BuildProperties.propertyRef(property);
       return Collections.singletonList(creator.createDirectoryContentCopyInstruction(moduleOutput));
     }
     return Collections.emptyList();
   }
 
-  protected abstract String getModuleOutputAntProperty(ArtifactAntGenerationContext generationContext);
-
-  @Nullable
-  protected abstract VirtualFile getModuleOutputPath(CompilerModuleExtension extension);
-
   @NotNull
   @Override
   public PackagingElementOutputKind getFilesKind(PackagingElementResolvingContext context) {
     return PackagingElementOutputKind.DIRECTORIES_WITH_CLASSES;
   }
 
-  @Override
-  public boolean isEqualTo(@NotNull PackagingElement<?> element) {
-    return element.getClass() == getClass() && myModulePointer != null
-           && myModulePointer.equals(((ModuleOutputPackagingElementBase)element).myModulePointer);
-  }
-
-  public ModuleOutputPackagingElementState getState() {
-    final ModuleOutputPackagingElementState state = new ModuleOutputPackagingElementState();
-    if (myModulePointer != null) {
-      state.setModuleName(myModulePointer.getModuleName());
-    }
-    return state;
-  }
-
-  public void loadState(@NotNull ModuleOutputPackagingElementState state) {
-    final String moduleName = state.getModuleName();
-    myModulePointer = moduleName != null ? ModulePointerManager.getInstance(myProject).create(moduleName) : null;
-  }
-
-  @Override
-  @Nullable
-  public String getModuleName() {
-    return myModulePointer != null ? myModulePointer.getModuleName() : null;
-  }
-
-  @Override
-  @Nullable
-  public Module findModule(PackagingElementResolvingContext context) {
-    if (myModulePointer != null) {
-      final Module module = myModulePointer.getModule();
-      final ModulesProvider modulesProvider = context.getModulesProvider();
-      if (module != null) {
-        if (modulesProvider instanceof DefaultModulesProvider//optimization
-           || ArrayUtil.contains(module, modulesProvider.getModules())) {
-          return module;
-        }
-      }
-      return modulesProvider.getModule(myModulePointer.getModuleName());
-    }
-    return null;
-  }
-
-  public static class ModuleOutputPackagingElementState {
-    private String myModuleName;
-
-    @Attribute(MODULE_NAME_ATTRIBUTE)
-    public String getModuleName() {
-      return myModuleName;
-    }
-
-    public void setModuleName(String moduleName) {
-      myModuleName = moduleName;
-    }
+  public ModuleOutputPackagingElementBase(PackagingElementType type, Project project) {
+    super(type, project);
   }
 }
diff --git a/java/compiler/impl/src/com/intellij/packaging/impl/elements/ModulePackagingElement.java b/java/compiler/impl/src/com/intellij/packaging/impl/elements/ModulePackagingElement.java
new file mode 100644 (file)
index 0000000..3edabb4
--- /dev/null
@@ -0,0 +1,38 @@
+/*
+ * Copyright 2000-2010 JetBrains s.r.o.
+ *
+ * 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.intellij.packaging.impl.elements;
+
+import com.intellij.openapi.module.Module;
+import com.intellij.openapi.vfs.VirtualFile;
+import com.intellij.packaging.elements.PackagingElementResolvingContext;
+import org.jetbrains.annotations.NotNull;
+import org.jetbrains.annotations.Nullable;
+
+import java.util.Collection;
+
+/**
+ * @author nik
+ */
+public interface ModulePackagingElement {
+  @Nullable
+  String getModuleName();
+
+  @Nullable
+  Module findModule(PackagingElementResolvingContext context);
+
+  @NotNull
+  Collection<VirtualFile> getSourceRoots(PackagingElementResolvingContext context);
+}
diff --git a/java/compiler/impl/src/com/intellij/packaging/impl/elements/ModulePackagingElementBase.java b/java/compiler/impl/src/com/intellij/packaging/impl/elements/ModulePackagingElementBase.java
new file mode 100644 (file)
index 0000000..7c46482
--- /dev/null
@@ -0,0 +1,76 @@
+// Copyright 2000-2018 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license that can be found in the LICENSE file.
+package com.intellij.packaging.impl.elements;
+
+import com.intellij.openapi.module.Module;
+import com.intellij.openapi.module.ModulePointer;
+import com.intellij.openapi.module.ModulePointerManager;
+import com.intellij.openapi.project.Project;
+import com.intellij.openapi.roots.ui.configuration.DefaultModulesProvider;
+import com.intellij.openapi.roots.ui.configuration.ModulesProvider;
+import com.intellij.packaging.elements.PackagingElement;
+import com.intellij.packaging.elements.PackagingElementResolvingContext;
+import com.intellij.packaging.elements.PackagingElementType;
+import com.intellij.util.ArrayUtil;
+import org.jetbrains.annotations.NotNull;
+import org.jetbrains.annotations.Nullable;
+
+/**
+ * @author nik
+ */
+public abstract class ModulePackagingElementBase extends PackagingElement<ModulePackagingElementState> implements ModulePackagingElement {
+  protected final Project myProject;
+  protected ModulePointer myModulePointer;
+
+  public ModulePackagingElementBase(PackagingElementType type, Project project, ModulePointer modulePointer) {
+    super(type);
+    myProject = project;
+    myModulePointer = modulePointer;
+  }
+
+  public ModulePackagingElementBase(PackagingElementType type, Project project) {
+    super(type);
+    myProject = project;
+  }
+
+  @Override
+  public boolean isEqualTo(@NotNull PackagingElement<?> element) {
+    return element.getClass() == getClass() && myModulePointer != null
+           && myModulePointer.equals(((ModulePackagingElementBase)element).myModulePointer);
+  }
+
+  public ModulePackagingElementState getState() {
+    final ModulePackagingElementState state = new ModulePackagingElementState();
+    if (myModulePointer != null) {
+      state.setModuleName(myModulePointer.getModuleName());
+    }
+    return state;
+  }
+
+  public void loadState(@NotNull ModulePackagingElementState state) {
+    final String moduleName = state.getModuleName();
+    myModulePointer = moduleName != null ? ModulePointerManager.getInstance(myProject).create(moduleName) : null;
+  }
+
+  @Override
+  @Nullable
+  public String getModuleName() {
+    return myModulePointer != null ? myModulePointer.getModuleName() : null;
+  }
+
+  @Override
+  @Nullable
+  public Module findModule(PackagingElementResolvingContext context) {
+    if (myModulePointer != null) {
+      final Module module = myModulePointer.getModule();
+      final ModulesProvider modulesProvider = context.getModulesProvider();
+      if (module != null) {
+        if (modulesProvider instanceof DefaultModulesProvider//optimization
+            || ArrayUtil.contains(module, modulesProvider.getModules())) {
+          return module;
+        }
+      }
+      return modulesProvider.getModule(myModulePointer.getModuleName());
+    }
+    return null;
+  }
+}
diff --git a/java/compiler/impl/src/com/intellij/packaging/impl/elements/ModulePackagingElementState.java b/java/compiler/impl/src/com/intellij/packaging/impl/elements/ModulePackagingElementState.java
new file mode 100644 (file)
index 0000000..9cf96b0
--- /dev/null
@@ -0,0 +1,20 @@
+// Copyright 2000-2018 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license that can be found in the LICENSE file.
+package com.intellij.packaging.impl.elements;
+
+import com.intellij.util.xmlb.annotations.Attribute;
+import org.jetbrains.annotations.NonNls;
+
+public class ModulePackagingElementState {
+  @NonNls public static final String MODULE_NAME_ATTRIBUTE = "name";
+
+  private String myModuleName;
+
+  @Attribute(MODULE_NAME_ATTRIBUTE)
+  public String getModuleName() {
+    return myModuleName;
+  }
+
+  public void setModuleName(String moduleName) {
+    myModuleName = moduleName;
+  }
+}
index 66f059213247d1d17cf72d88604305649990273d..24ddc7c9365e305aabafc4d4924dd06eadb5c907 100644 (file)
@@ -58,7 +58,10 @@ public class PackagingElementFactoryImpl extends PackagingElementFactory {
   public static final PackagingElementType<ArtifactRootElement<?>> ARTIFACT_ROOT_ELEMENT_TYPE = new ArtifactRootElementType();
   private static final PackagingElementType[] STANDARD_TYPES = {
       DIRECTORY_ELEMENT_TYPE, ARCHIVE_ELEMENT_TYPE,
-      LibraryElementType.LIBRARY_ELEMENT_TYPE, ProductionModuleOutputElementType.ELEMENT_TYPE, TestModuleOutputElementType.ELEMENT_TYPE,
+      LibraryElementType.LIBRARY_ELEMENT_TYPE,
+      ProductionModuleOutputElementType.ELEMENT_TYPE,
+      TestModuleOutputElementType.ELEMENT_TYPE,
+      ProductionModuleSourceElementType.ELEMENT_TYPE,
       ArtifactElementType.ARTIFACT_ELEMENT_TYPE, FILE_COPY_ELEMENT_TYPE, DIRECTORY_COPY_ELEMENT_TYPE, EXTRACTED_DIRECTORY_ELEMENT_TYPE
   };
 
@@ -193,6 +196,13 @@ public class PackagingElementFactoryImpl extends PackagingElementFactory {
 
   @NotNull
   @Override
+  public PackagingElement<?> createModuleSource(@NotNull Module module) {
+    final ModulePointer modulePointer = ModulePointerManager.getInstance(module.getProject()).create(module);
+    return new ProductionModuleSourcePackagingElement(module.getProject(), modulePointer);
+  }
+
+  @NotNull
+  @Override
   public PackagingElement<?> createTestModuleOutput(@NotNull Module module) {
     ModulePointer pointer = ModulePointerManager.getInstance(module.getProject()).create(module);
     return new TestModuleOutputPackagingElement(module.getProject(), pointer);
index 3ec8f0cb54030b7659ed55882ea1c1bcc7461da8..56d22a90d489a3cd5c0f29c7f591557c7419564c 100644 (file)
@@ -31,7 +31,7 @@ import javax.swing.*;
 public class ProductionModuleOutputElementType extends ModuleOutputElementTypeBase<ProductionModuleOutputPackagingElement> {
   public static final ProductionModuleOutputElementType ELEMENT_TYPE = new ProductionModuleOutputElementType();
 
-  ProductionModuleOutputElementType() {
+  private ProductionModuleOutputElementType() {
     super("module-output", CompilerBundle.message("element.type.name.module.output"));
   }
 
@@ -49,8 +49,14 @@ public class ProductionModuleOutputElementType extends ModuleOutputElementTypeBa
     return AllIcons.Nodes.Module;
   }
 
+  @NotNull
+  @Override
+  public String getElementText(@NotNull String moduleName) {
+    return CompilerBundle.message("node.text.0.compile.output", moduleName);
+  }
+
   @Override
-  public boolean isSuitableModule(ModulesProvider modulesProvider, Module module) {
+  public boolean isSuitableModule(@NotNull ModulesProvider modulesProvider, @NotNull Module module) {
     return modulesProvider.getRootModel(module).getSourceRootUrls(false).length > 0;
   }
 }
index 900cdb8509798ffa929f3135c7a5ec207583de60..c09702adbd03c1a3f096e7621e9e5f10c63d862d 100644 (file)
@@ -18,7 +18,6 @@ package com.intellij.packaging.impl.elements;
 import com.intellij.openapi.module.Module;
 import com.intellij.openapi.module.ModulePointer;
 import com.intellij.openapi.project.Project;
-import com.intellij.openapi.roots.CompilerModuleExtension;
 import com.intellij.openapi.roots.ModuleRootModel;
 import com.intellij.openapi.vfs.VirtualFile;
 import com.intellij.packaging.elements.ArtifactAntGenerationContext;
@@ -51,14 +50,10 @@ public class ProductionModuleOutputPackagingElement extends ModuleOutputPackagin
     return "module:" + getModuleName();
   }
 
-  protected String getModuleOutputAntProperty(ArtifactAntGenerationContext generationContext) {
+  protected String getDirectoryAntProperty(ArtifactAntGenerationContext generationContext) {
     return generationContext.getModuleOutputPath(myModulePointer.getModuleName());
   }
 
-  protected VirtualFile getModuleOutputPath(CompilerModuleExtension extension) {
-    return extension.getCompilerOutputPath();
-  }
-
   @NotNull
   @Override
   public Collection<VirtualFile> getSourceRoots(PackagingElementResolvingContext context) {
@@ -71,6 +66,6 @@ public class ProductionModuleOutputPackagingElement extends ModuleOutputPackagin
 
   @NotNull
   public PackagingElementPresentation createPresentation(@NotNull ArtifactEditorContext context) {
-    return new DelegatedPackagingElementPresentation(new ModuleElementPresentation(myModulePointer, context, false));
+    return new DelegatedPackagingElementPresentation(new ModuleElementPresentation(myModulePointer, context, ProductionModuleOutputElementType.ELEMENT_TYPE));
   }
 }
diff --git a/java/compiler/impl/src/com/intellij/packaging/impl/elements/ProductionModuleSourceElementType.kt b/java/compiler/impl/src/com/intellij/packaging/impl/elements/ProductionModuleSourceElementType.kt
new file mode 100644 (file)
index 0000000..dda08b8
--- /dev/null
@@ -0,0 +1,29 @@
+// Copyright 2000-2018 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license that can be found in the LICENSE file.
+package com.intellij.packaging.impl.elements
+
+import com.intellij.icons.AllIcons
+import com.intellij.openapi.compiler.CompilerBundle
+import com.intellij.openapi.module.Module
+import com.intellij.openapi.module.ModulePointer
+import com.intellij.openapi.project.Project
+import com.intellij.openapi.roots.ui.configuration.ModulesProvider
+import javax.swing.Icon
+
+class ProductionModuleSourceElementType private constructor() : ModuleElementTypeBase<ProductionModuleSourcePackagingElement>(
+  "module-source", CompilerBundle.message("element.type.name.module.source")) {
+
+  override fun isSuitableModule(modulesProvider: ModulesProvider, module: Module): Boolean {
+    return modulesProvider.getRootModel(module).getSourceRootUrls(false).isNotEmpty()
+  }
+
+  override fun createElement(project: Project, pointer: ModulePointer) = ProductionModuleSourcePackagingElement(project, pointer)
+  override fun createEmpty(project: Project) = ProductionModuleSourcePackagingElement(project)
+  override fun getCreateElementIcon(): Icon = AllIcons.Modules.SourceFolder
+  override fun getElementIcon(module: Module?): Icon = AllIcons.Modules.SourceFolder
+  override fun getElementText(moduleName: String) = CompilerBundle.message("node.text.0.module.sources", moduleName)
+
+  companion object {
+    @JvmField
+    val ELEMENT_TYPE = ProductionModuleSourceElementType()
+  }
+}
diff --git a/java/compiler/impl/src/com/intellij/packaging/impl/elements/ProductionModuleSourcePackagingElement.kt b/java/compiler/impl/src/com/intellij/packaging/impl/elements/ProductionModuleSourcePackagingElement.kt
new file mode 100644 (file)
index 0000000..5036415
--- /dev/null
@@ -0,0 +1,52 @@
+// Copyright 2000-2018 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license that can be found in the LICENSE file.
+package com.intellij.packaging.impl.elements
+
+import com.intellij.compiler.ant.Generator
+import com.intellij.openapi.module.ModulePointer
+import com.intellij.openapi.project.Project
+import com.intellij.openapi.vfs.VirtualFile
+import com.intellij.packaging.artifacts.ArtifactType
+import com.intellij.packaging.elements.AntCopyInstructionCreator
+import com.intellij.packaging.elements.ArtifactAntGenerationContext
+import com.intellij.packaging.elements.PackagingElementOutputKind
+import com.intellij.packaging.elements.PackagingElementResolvingContext
+import com.intellij.packaging.impl.ui.DelegatedPackagingElementPresentation
+import com.intellij.packaging.impl.ui.ModuleElementPresentation
+import com.intellij.packaging.ui.ArtifactEditorContext
+import com.intellij.packaging.ui.PackagingElementPresentation
+import org.jetbrains.annotations.NonNls
+import org.jetbrains.jps.model.java.JavaModuleSourceRootTypes
+
+class ProductionModuleSourcePackagingElement : ModulePackagingElementBase {
+  constructor(project: Project) : super(ProductionModuleSourceElementType.ELEMENT_TYPE, project) {}
+  constructor(project: Project, modulePointer: ModulePointer) : super(ProductionModuleSourceElementType.ELEMENT_TYPE,
+                                                                      project,
+                                                                      modulePointer)
+
+  override fun getSourceRoots(context: PackagingElementResolvingContext): Collection<VirtualFile> {
+    val module = findModule(context) ?: return emptyList()
+
+    val rootModel = context.modulesProvider.getRootModel(module)
+    return rootModel.getSourceRoots(JavaModuleSourceRootTypes.PRODUCTION)
+  }
+
+  override fun createPresentation(context: ArtifactEditorContext): PackagingElementPresentation {
+    return DelegatedPackagingElementPresentation(
+      ModuleElementPresentation(myModulePointer, context, ProductionModuleSourceElementType.ELEMENT_TYPE))
+  }
+
+  override fun computeAntInstructions(resolvingContext: PackagingElementResolvingContext,
+                                      creator: AntCopyInstructionCreator,
+                                      generationContext: ArtifactAntGenerationContext,
+                                      artifactType: ArtifactType): List<Generator> {
+    return getSourceRoots(resolvingContext).map {
+      creator.createDirectoryContentCopyInstruction(it.path)
+    }
+  }
+
+  override fun getFilesKind(context: PackagingElementResolvingContext) = PackagingElementOutputKind.OTHER
+
+  @NonNls
+  override fun toString() = "module sources:" + moduleName!!
+}
+
index 3e07000682154d83e91a4abe5403f23105f20876..34297f60f87fc1bc10e08cce27634a11cefcb389 100644 (file)
  */
 package com.intellij.packaging.impl.elements;
 
+import com.intellij.icons.AllIcons;
 import com.intellij.openapi.compiler.CompilerBundle;
 import com.intellij.openapi.module.Module;
 import com.intellij.openapi.module.ModulePointer;
 import com.intellij.openapi.project.Project;
 import com.intellij.openapi.roots.ui.configuration.ModulesProvider;
-import com.intellij.util.PlatformIcons;
 import org.jetbrains.annotations.NotNull;
+import org.jetbrains.annotations.Nullable;
 import org.jetbrains.jps.model.java.JavaModuleSourceRootTypes;
 
 import javax.swing.*;
@@ -32,7 +33,7 @@ import javax.swing.*;
 public class TestModuleOutputElementType extends ModuleOutputElementTypeBase<TestModuleOutputPackagingElement> {
   public static final TestModuleOutputElementType ELEMENT_TYPE = new TestModuleOutputElementType();
 
-  public TestModuleOutputElementType() {
+  private TestModuleOutputElementType() {
     super("module-test-output", CompilerBundle.message("element.type.name.module.test.output"));
   }
 
@@ -48,10 +49,21 @@ public class TestModuleOutputElementType extends ModuleOutputElementTypeBase<Tes
 
   @Override
   public Icon getCreateElementIcon() {
-    return PlatformIcons.TEST_SOURCE_FOLDER;
+    return AllIcons.Modules.TestSourceFolder;
   }
 
-  public boolean isSuitableModule(ModulesProvider modulesProvider, Module module) {
+  @Override
+  public Icon getElementIcon(@Nullable Module module) {
+    return AllIcons.Modules.TestSourceFolder;
+  }
+
+  @NotNull
+  @Override
+  public String getElementText(@NotNull String moduleName) {
+    return CompilerBundle.message("node.text.0.test.compile.output", moduleName);
+  }
+
+  public boolean isSuitableModule(@NotNull ModulesProvider modulesProvider, @NotNull Module module) {
     return !modulesProvider.getRootModel(module).getSourceRoots(JavaModuleSourceRootTypes.TESTS).isEmpty();
   }
 }
index d09bc7c5160cbb6c4909fb3550b48797356d78bb..718e6aa2df14f6ca37f99dee6b89f82261ba9c8a 100644 (file)
@@ -18,7 +18,6 @@ package com.intellij.packaging.impl.elements;
 import com.intellij.openapi.module.Module;
 import com.intellij.openapi.module.ModulePointer;
 import com.intellij.openapi.project.Project;
-import com.intellij.openapi.roots.CompilerModuleExtension;
 import com.intellij.openapi.vfs.VirtualFile;
 import com.intellij.packaging.elements.ArtifactAntGenerationContext;
 import com.intellij.packaging.elements.PackagingElementResolvingContext;
@@ -49,14 +48,10 @@ public class TestModuleOutputPackagingElement extends ModuleOutputPackagingEleme
     return "module-tests:" + getModuleName();
   }
 
-  protected String getModuleOutputAntProperty(ArtifactAntGenerationContext generationContext) {
+  protected String getDirectoryAntProperty(ArtifactAntGenerationContext generationContext) {
     return generationContext.getModuleTestOutputPath(myModulePointer.getModuleName());
   }
 
-  protected VirtualFile getModuleOutputPath(CompilerModuleExtension extension) {
-    return extension.getCompilerOutputPathForTests();
-  }
-
   @NotNull
   @Override
   public Collection<VirtualFile> getSourceRoots(PackagingElementResolvingContext context) {
@@ -68,6 +63,6 @@ public class TestModuleOutputPackagingElement extends ModuleOutputPackagingEleme
 
   @NotNull
   public PackagingElementPresentation createPresentation(@NotNull ArtifactEditorContext context) {
-    return new DelegatedPackagingElementPresentation(new ModuleElementPresentation(myModulePointer, context, true));
+    return new DelegatedPackagingElementPresentation(new ModuleElementPresentation(myModulePointer, context, TestModuleOutputElementType.ELEMENT_TYPE));
   }
 }
index 0ed75b5d4fce0066b84060487dff2039f709974f..9378c2827ed17b5decb459d7b736bd9ea90c2d92 100644 (file)
 package com.intellij.packaging.impl.ui;
 
 import com.intellij.ide.projectView.PresentationData;
-import com.intellij.openapi.compiler.CompilerBundle;
 import com.intellij.openapi.module.ModifiableModuleModel;
 import com.intellij.openapi.module.Module;
 import com.intellij.openapi.module.ModulePointer;
-import com.intellij.openapi.module.ModuleType;
+import com.intellij.packaging.impl.elements.ModuleElementTypeBase;
 import com.intellij.packaging.ui.ArtifactEditorContext;
 import com.intellij.packaging.ui.PackagingElementWeights;
 import com.intellij.packaging.ui.TreeNodePresentation;
 import com.intellij.ui.SimpleTextAttributes;
-import com.intellij.util.PlatformIcons;
 import org.jetbrains.annotations.NotNull;
 import org.jetbrains.annotations.Nullable;
 
@@ -35,12 +33,14 @@ import org.jetbrains.annotations.Nullable;
 public class ModuleElementPresentation extends TreeNodePresentation {
   private final ModulePointer myModulePointer;
   private final ArtifactEditorContext myContext;
-  private final boolean myTestOutput;
+  private final ModuleElementTypeBase myElementType;
 
-  public ModuleElementPresentation(@Nullable ModulePointer modulePointer, @NotNull ArtifactEditorContext context, final boolean testOutput) {
+  public ModuleElementPresentation(@Nullable ModulePointer modulePointer,
+                                   @NotNull ArtifactEditorContext context,
+                                   @NotNull ModuleElementTypeBase elementType) {
     myModulePointer = modulePointer;
     myContext = context;
-    myTestOutput = testOutput;
+    myElementType = elementType;
   }
 
   public String getPresentableName() {
@@ -65,14 +65,12 @@ public class ModuleElementPresentation extends TreeNodePresentation {
     }
   }
 
-  public void render(@NotNull PresentationData presentationData, SimpleTextAttributes mainAttributes, SimpleTextAttributes commentAttributes) {
+  public void render(@NotNull PresentationData presentationData,
+                     SimpleTextAttributes mainAttributes,
+                     SimpleTextAttributes commentAttributes) {
     final Module module = findModule();
-    if (myTestOutput) {
-      presentationData.setIcon(PlatformIcons.TEST_SOURCE_FOLDER);
-    }
-    else if (module != null) {
-      presentationData.setIcon(ModuleType.get(module).getIcon());
-    }
+    presentationData.setIcon(myElementType.getElementIcon(module));
+
     String moduleName;
     if (module != null) {
       ModifiableModuleModel moduleModel = myContext.getModifiableModuleModel();
@@ -90,8 +88,7 @@ public class ModuleElementPresentation extends TreeNodePresentation {
       moduleName = "<unknown>";
     }
 
-    String text = myTestOutput ? CompilerBundle.message("node.text.0.test.compile.output", moduleName)
-                               : CompilerBundle.message("node.text.0.compile.output", moduleName);
+    String text = myElementType.getElementText(moduleName);
     presentationData.addText(text, module != null ? mainAttributes : SimpleTextAttributes.ERROR_ATTRIBUTES);
   }
 
index 0d4ac3819ed4ccd78323683c97f016e4b5e44daf..8bf26a6427c97756578cdc8ae2d3aaf3259c54fa 100644 (file)
@@ -30,6 +30,7 @@ import java.util.ResourceBundle;
  */
 public class CompilerBundle {
 
+  @NotNull
   public static String message(@NotNull @PropertyKey(resourceBundle = BUNDLE) String key, @NotNull Object... params) {
     return CommonBundle.message(getBundle(), key, params);
   }
index d6574fa21aa1d866799fed6520069f3927770b56..16feac71e0f5ae2cf306e3138c1b8b5fa90f52a5 100644 (file)
@@ -55,6 +55,9 @@ public abstract class PackagingElementFactory {
   public abstract PackagingElement<?> createModuleOutput(@NotNull Module module);
 
   @NotNull
+  public abstract PackagingElement<?> createModuleSource(@NotNull Module module);
+
+  @NotNull
   public abstract PackagingElement<?> createTestModuleOutput(@NotNull Module module);
 
   @NotNull
index 4ba42df839746ae0d65d5c8d8495769a7701e5fd..08df98dd153393873f0ee5787cad6820318ad929 100644 (file)
  */
 package com.intellij.packaging.elements;
 
+import org.jetbrains.annotations.NotNull;
+
 /**
  * @author nik
  */
 public class PackagingElementOutputKind {
-  public static final PackagingElementOutputKind DIRECTORIES_WITH_CLASSES = new PackagingElementOutputKind(true, false);
-  public static final PackagingElementOutputKind JAR_FILES = new PackagingElementOutputKind(false, true);
-  public static final PackagingElementOutputKind OTHER = new PackagingElementOutputKind(false, false);
+  @NotNull public static final PackagingElementOutputKind DIRECTORIES_WITH_CLASSES = new PackagingElementOutputKind(true, false);
+  @NotNull public static final PackagingElementOutputKind JAR_FILES = new PackagingElementOutputKind(false, true);
+  @NotNull public static final PackagingElementOutputKind OTHER = new PackagingElementOutputKind(false, false);
+
   private final boolean myContainsDirectoriesWithClasses;
   private final boolean myContainsJarFiles;
 
index 70e05f0e1385752b7a6a87ecd649385ff85777a7..c25223af0877d7d8382b5b3547f846d8832d7482 100644 (file)
@@ -24,6 +24,7 @@ public class SourceItemWeights {
   public static final int MODULE_GROUP_WEIGHT = 100;
   public static final int MODULE_WEIGHT = 50;
   public static final int MODULE_OUTPUT_WEIGHT = 30;
+  public static final int MODULE_SOURCE_WEIGHT = 25;
   public static final int LIBRARY_WEIGHT = 10;
 
   private SourceItemWeights() {
index 3c1f63769c041f4976631685014372164a916a61..507d9ff4ab8970198e73d3bcb97980435efee5b7 100644 (file)
@@ -71,6 +71,11 @@ public class TestPackagingElementBuilder {
     return this;
   }
 
+  public TestPackagingElementBuilder moduleSource(Module module) {
+    myElement.addOrFindChild(getFactory().createModuleSource(module));
+    return this;
+  }
+
   public TestPackagingElementBuilder lib(Library library) {
     myElement.addOrFindChildren(getFactory().createLibraryElements(library));
     return this;
index b4e6d38055a59ba9111c2566fd6035164a789e0c..5193e0ce8526d3aebaf63a139a9bb1559ab365bd 100644 (file)
@@ -69,10 +69,11 @@ public class UpdateArtifactsAfterRenameTest extends PackagingElementsTestCase {
       Module res = moduleManager.newModule(getProjectBasePath() + "/myModule.iml", StdModuleTypes.JAVA.getId());
       return res;
     });
-    final Artifact artifact = addArtifact(root().module(module));
+    final Artifact artifact = addArtifact(root().module(module).moduleSource(module));
 
     assertLayout(artifact, "<root>\n" +
-                           " module:myModule");
+                           " module:myModule\n" +
+                           " module sources:myModule");
     WriteAction.runAndWait(() -> {
       final ModifiableModuleModel model = moduleManager.getModifiableModel();
       model.renameModule(module, "newName");
@@ -80,12 +81,14 @@ public class UpdateArtifactsAfterRenameTest extends PackagingElementsTestCase {
     });
 
     assertLayout(artifact, "<root>\n" +
-                           " module:newName");
+                           " module:newName\n" +
+                           " module sources:newName");
 
     moduleManager.disposeModule(module);
 
     assertLayout(artifact, "<root>\n" +
-                           " module:newName");
+                           " module:newName\n" +
+                           " module sources:newName");
   }
 
   private void moveFile(final VirtualFile file, final VirtualFile newParent) {
index ecd66de0d5376793581b364a7154c4f818abfb81..ae70473952c1d54062de7c2e70ec90d6610231a7 100644 (file)
@@ -2,6 +2,7 @@ package com.intellij.compiler.artifacts.ui;
 
 import com.intellij.packaging.artifacts.Artifact;
 import com.intellij.packaging.impl.elements.ProductionModuleOutputElementType;
+import com.intellij.packaging.impl.elements.ProductionModuleSourceElementType;
 
 /**
  * @author nik
@@ -26,6 +27,16 @@ public class AddNewElementActionTest extends ArtifactEditorTestCase {
                  "  module:mod");
   }
 
+  public void testAddSourcesToDirectory() {
+    addModule();
+    createEditor(addArtifact(root().dir("dir")));
+    selectNode("dir");
+    myArtifactEditor.addNewPackagingElement(ProductionModuleSourceElementType.ELEMENT_TYPE);
+    assertLayout("<root>\n" +
+                 " dir/\n" +
+                 "  module sources:mod");
+  }
+
   public void testAddToDirectoryInIncludedArtifact() {
     addModule();
     Artifact included = addArtifact("included", root().dir("dir"));
index 6403d88dc0e889a7ff78b4d66ef639f6cffc7364..7adc54de20a2604f086aa4f239e051be6e714abf 100644 (file)
@@ -32,7 +32,7 @@ import com.intellij.packaging.impl.artifacts.PackagingElementProcessor;
 import com.intellij.packaging.impl.elements.ArtifactPackagingElement;
 import com.intellij.packaging.impl.elements.FacetBasedPackagingElement;
 import com.intellij.packaging.impl.elements.LibraryPackagingElement;
-import com.intellij.packaging.impl.elements.ModuleOutputPackagingElement;
+import com.intellij.packaging.impl.elements.ModulePackagingElement;
 import org.jetbrains.annotations.NotNull;
 import org.jetbrains.annotations.Nullable;
 
@@ -102,8 +102,8 @@ public class ArtifactProjectStructureElement extends ProjectStructureElement {
   public static ProjectStructureElement getProjectStructureElementFor(PackagingElement<?> packagingElement,
                                                                        final StructureConfigurableContext context,
                                                                        final ArtifactsStructureConfigurableContext artifactsStructureContext) {
-    if (packagingElement instanceof ModuleOutputPackagingElement) {
-      final Module module = ((ModuleOutputPackagingElement)packagingElement).findModule(artifactsStructureContext);
+    if (packagingElement instanceof ModulePackagingElement) {
+      final Module module = ((ModulePackagingElement)packagingElement).findModule(artifactsStructureContext);
       if (module != null) {
         return new ModuleProjectStructureElement(context, module);
       }
index 90bde421b31d18a5db215c8bb32352c76ae3ad7c..8904468d1877ef3755afe4303e8b2c3a096c08b0 100644 (file)
@@ -20,6 +20,7 @@ import com.intellij.openapi.module.ModulePointer;
 import com.intellij.openapi.module.ModulePointerManager;
 import com.intellij.packaging.elements.PackagingElement;
 import com.intellij.packaging.elements.PackagingElementOutputKind;
+import com.intellij.packaging.impl.elements.ProductionModuleOutputElementType;
 import com.intellij.packaging.impl.elements.ProductionModuleOutputPackagingElement;
 import com.intellij.packaging.impl.ui.ModuleElementPresentation;
 import com.intellij.packaging.ui.*;
@@ -54,7 +55,7 @@ public class ModuleOutputSourceItem extends PackagingSourceItem {
   @Override
   public SourceItemPresentation createPresentation(@NotNull ArtifactEditorContext context) {
     final ModulePointer modulePointer = ModulePointerManager.getInstance(context.getProject()).create(myModule);
-    return new DelegatedSourceItemPresentation(new ModuleElementPresentation(modulePointer, context, false)) {
+    return new DelegatedSourceItemPresentation(new ModuleElementPresentation(modulePointer, context, ProductionModuleOutputElementType.ELEMENT_TYPE)) {
       @Override
       public int getWeight() {
         return SourceItemWeights.MODULE_OUTPUT_WEIGHT;
index fa193aa7bb94599af3ef2a7f49704abde2b32868..9608ee2bcc59c1d72e3d15de5427f2fdb102d1a4 100644 (file)
@@ -23,8 +23,7 @@ import com.intellij.openapi.util.Comparing;
 import com.intellij.openapi.vfs.VirtualFile;
 import com.intellij.packaging.artifacts.Artifact;
 import com.intellij.packaging.impl.artifacts.ArtifactUtil;
-import com.intellij.packaging.impl.elements.PackagingElementFactoryImpl;
-import com.intellij.packaging.impl.elements.ProductionModuleOutputElementType;
+import com.intellij.packaging.impl.elements.*;
 import com.intellij.packaging.ui.ArtifactEditorContext;
 import com.intellij.packaging.ui.PackagingSourceItem;
 import com.intellij.packaging.ui.PackagingSourceItemsProvider;
@@ -49,17 +48,22 @@ public class ModulesAndLibrariesSourceItemsProvider extends PackagingSourceItems
       return createModuleItems(editorContext, ((ModuleGroupItem)parent).getPath());
     }
     else if (parent instanceof ModuleSourceItemGroup) {
-      return createClasspathItems(editorContext, artifact, ((ModuleSourceItemGroup)parent).getModule());
+      return createAvailableItems(editorContext, artifact, ((ModuleSourceItemGroup)parent).getModule());
     }
     return Collections.emptyList();
   }
 
   @NotNull
-  private static Collection<? extends PackagingSourceItem> createClasspathItems(@NotNull ArtifactEditorContext editorContext,
+  private static Collection<? extends PackagingSourceItem> createAvailableItems(@NotNull ArtifactEditorContext editorContext,
                                                                                 @NotNull Artifact artifact, @NotNull Module module) {
     final List<PackagingSourceItem> items = new ArrayList<>();
-    final ModuleRootModel rootModel = editorContext.getModulesProvider().getRootModel(module);
+
+    for (Module toAdd : getAvailableModules(editorContext, artifact, ProductionModuleOutputElementType.ELEMENT_TYPE, module)) {
+      items.add(new ModuleOutputSourceItem(toAdd));
+    }
+
     List<Library> libraries = new ArrayList<>();
+    final ModuleRootModel rootModel = editorContext.getModulesProvider().getRootModel(module);
     for (OrderEntry orderEntry : rootModel.getOrderEntries()) {
       if (orderEntry instanceof LibraryOrderEntry) {
         final LibraryOrderEntry libraryEntry = (LibraryOrderEntry)orderEntry;
@@ -71,10 +75,6 @@ public class ModulesAndLibrariesSourceItemsProvider extends PackagingSourceItems
       }
     }
 
-    for (Module toAdd : getNotAddedModules(editorContext, artifact, module)) {
-      items.add(new ModuleOutputSourceItem(toAdd));
-    }
-
     for (Library library : getNotAddedLibraries(editorContext, artifact, libraries)) {
       items.add(new LibrarySourceItem(library));
     }
@@ -102,11 +102,19 @@ public class ModulesAndLibrariesSourceItemsProvider extends PackagingSourceItems
   }
 
   @NotNull
-  private static List<? extends Module> getNotAddedModules(@NotNull final ArtifactEditorContext context, @NotNull Artifact artifact,
-                                                          final Module... allModules) {
-    final Set<Module> modules = new HashSet<>(Arrays.asList(allModules));
-    ArtifactUtil.processPackagingElements(artifact, ProductionModuleOutputElementType.ELEMENT_TYPE, moduleOutputPackagingElement -> {
-      modules.remove(moduleOutputPackagingElement.findModule(context));
+  private static <E extends ModulePackagingElementBase> List<? extends Module> getAvailableModules(@NotNull final ArtifactEditorContext context,
+                                                                                                   @NotNull Artifact artifact,
+                                                                                                   @NotNull ModuleElementTypeBase<E> elementType,
+                                                                                                   final Module... allModules) {
+    final Set<Module> modules = new HashSet<>();
+    for (Module module : allModules) {
+      if (elementType.isSuitableModule(context.getModulesProvider(), module)) {
+        modules.add(module);
+      }
+    }
+
+    ArtifactUtil.processPackagingElements(artifact, elementType, moduleElement -> {
+      modules.remove(moduleElement.findModule(context));
       return true;
     }, context, true);
     return new ArrayList<>(modules);
index b90a80dba1a990c9fadb01f5c7e8d23b959d7d3a..885d1802d71c0b0b409be9ae18abf1cbf7f72d8e 100644 (file)
@@ -29,9 +29,10 @@ import org.jetbrains.jps.incremental.artifacts.instructions.ArtifactInstructions
 import org.jetbrains.jps.incremental.artifacts.instructions.CopyToDirectoryInstructionCreator;
 import org.jetbrains.jps.model.artifact.JpsArtifact;
 import org.jetbrains.jps.model.artifact.elements.*;
-import org.jetbrains.jps.model.java.JpsProductionModuleOutputPackagingElement;
-import org.jetbrains.jps.model.java.JpsTestModuleOutputPackagingElement;
+import org.jetbrains.jps.model.java.*;
 import org.jetbrains.jps.model.module.JpsModule;
+import org.jetbrains.jps.model.module.JpsModuleSourceRoot;
+import org.jetbrains.jps.model.module.JpsTypedModuleSourceRoot;
 import org.jetbrains.jps.service.JpsServiceManager;
 import org.jetbrains.jps.util.JpsPathUtil;
 
@@ -62,6 +63,7 @@ public class LayoutElementBuildersRegistry {
     LayoutElementBuilderService<?>[] standardBuilders = {
       new RootElementBuilder(), new DirectoryElementBuilder(), new ArchiveElementBuilder(), new DirectoryCopyElementBuilder(),
       new FileCopyElementBuilder(), new ExtractedDirectoryElementBuilder(), new ModuleOutputElementBuilder(),
+      new ModuleSourceElementBuilder(),
       new ModuleTestOutputElementBuilder(), new ComplexElementBuilder(), new ArtifactOutputElementBuilder()
     };
     for (LayoutElementBuilderService<?> builder : standardBuilders) {
@@ -124,6 +126,24 @@ public class LayoutElementBuildersRegistry {
     }
   }
 
+  private static void generateModuleSourceInstructions(@NotNull List<JpsModuleSourceRoot> roots,
+                                                       @NotNull ArtifactCompilerInstructionCreator creator,
+                                                       @NotNull JpsPackagingElement contextElement) {
+    for (JpsModuleSourceRoot root : roots) {
+      File source = root.getFile();
+      ArtifactCompilerInstructionCreator target;
+      JavaSourceRootProperties javaProperties = root.getProperties(JavaModuleSourceRootTypes.SOURCES);
+      if (javaProperties != null) {
+        String prefix = javaProperties.getPackagePrefix().replace('.', '/');
+        target = creator.subFolderByRelativePath(prefix);
+      } else {
+        target = creator;
+      }
+
+      target.addDirectoryCopyInstructions(source, null, target.getInstructionsBuilder().createCopyingHandler(source, contextElement, target));
+    }
+  }
+
   private static void generateModuleOutputInstructions(@Nullable String outputUrl,
                                                        @NotNull ArtifactCompilerInstructionCreator creator,
                                                        @NotNull JpsPackagingElement contextElement) {
@@ -262,6 +282,28 @@ public class LayoutElementBuildersRegistry {
     }
   }
 
+  private static class ModuleSourceElementBuilder extends LayoutElementBuilderService<JpsProductionModuleSourcePackagingElement> {
+    public ModuleSourceElementBuilder() {
+      super(JpsProductionModuleSourcePackagingElement.class);
+    }
+
+    @Override
+    public void generateInstructions(JpsProductionModuleSourcePackagingElement element,
+                                     ArtifactCompilerInstructionCreator instructionCreator,
+                                     ArtifactInstructionsBuilderContext builderContext) {
+      JpsModule module = element.getModuleReference().resolve();
+      if (module != null) {
+        generateModuleSourceInstructions(module.getSourceRoots(), instructionCreator, element);
+      }
+    }
+
+    @Override
+    public Collection<? extends BuildTarget<?>> getDependencies(@NotNull JpsProductionModuleSourcePackagingElement element,
+                                                                TargetOutputIndex outputIndex) {
+      return Collections.emptyList();
+    }
+  }
+
   private static class ModuleTestOutputElementBuilder extends LayoutElementBuilderService<JpsTestModuleOutputPackagingElement> {
     public ModuleTestOutputElementBuilder() {
       super(JpsTestModuleOutputPackagingElement.class);
index e257f6e2951002c923c01485e3dbf7d983cc52a1..9998748666328fa20818c0813922b0b468addaff 100644 (file)
@@ -20,6 +20,7 @@ import com.intellij.util.PathUtil
 import com.intellij.util.io.directoryContent
 import org.jetbrains.jps.incremental.artifacts.LayoutElementTestUtil.archive
 import org.jetbrains.jps.incremental.artifacts.LayoutElementTestUtil.root
+import org.jetbrains.jps.model.java.JavaSourceRootType
 import org.jetbrains.jps.model.java.JpsJavaExtensionService
 import org.jetbrains.jps.util.JpsPathUtil
 import java.io.BufferedOutputStream
@@ -171,6 +172,49 @@ class ArtifactBuilderTest : ArtifactBuilderTestCase() {
     assertOutput(artifact, directoryContent { file("A.class") })
   }
 
+  fun testModuleSources() {
+    val file = createFile("src/A.java", "class A{}")
+    val m = addModule("m", PathUtil.getParentPath(file))
+    val a = addArtifact(root().moduleSource(m))
+    buildAll()
+    assertOutput(a, directoryContent {
+      file("A.java")
+    })
+
+    val b = createFile("src/B.java", "class B{}")
+
+    buildAll()
+    assertOutput(a, directoryContent {
+      file("A.java")
+      file("B.java")
+    })
+
+    delete(b)
+    buildAll()
+    assertOutput(a, directoryContent {
+      file("A.java")
+    })
+  }
+
+  fun testModuleSourcesWithPackagePrefix() {
+    val file = createFile("src/A.java", "class A{}")
+    val m = addModule("m", PathUtil.getParentPath(file))
+    val sourceRoot = assertOneElement(m.sourceRoots)
+    val typed = sourceRoot.asTyped(JavaSourceRootType.SOURCE)
+    assertNotNull(typed)
+    typed!!.properties.packagePrefix = "org.foo"
+
+    val a = addArtifact(root().moduleSource(m))
+    buildAll()
+    assertOutput(a, directoryContent {
+      dir("org") {
+        dir("foo") {
+          file("A.java")
+        }
+      }
+    })
+  }
+
   fun testCopyResourcesFromModuleOutput() {
     val file = createFile("src/a.xml", "")
     JpsJavaExtensionService.getInstance().getOrCreateCompilerConfiguration(myProject).addResourcePattern("*.xml")
index 12d1fc9f39f44b243efb8853ea5649b2bb794fa5..a633700a8e6f99764b129a20579f30f4b1de15ce 100644 (file)
@@ -82,6 +82,10 @@ public class LayoutElementTestUtil {
       return element(JpsJavaExtensionService.getInstance().createProductionModuleOutput(module.createReference()));
     }
 
+    public LayoutElementCreator moduleSource(JpsModule module) {
+      return element(JpsJavaExtensionService.getInstance().createProductionModuleSource(module.createReference()));
+    }
+
     public LayoutElementCreator element(JpsPackagingElement element) {
       myElement.addChild(element);
       return this;
index 7bcd5451ef7402b7da4192758192a6e1eba966a7..192f8d8b88dd3eeb992dd8950032bcfea10eebc3 100644 (file)
@@ -42,6 +42,9 @@ public abstract class JpsJavaExtensionService {
   public abstract JpsProductionModuleOutputPackagingElement createProductionModuleOutput(@NotNull JpsModuleReference moduleReference);
 
   @NotNull
+  public abstract JpsProductionModuleSourcePackagingElement createProductionModuleSource(@NotNull JpsModuleReference moduleReference);
+
+  @NotNull
   public abstract JpsTestModuleOutputPackagingElement createTestModuleOutput(@NotNull JpsModuleReference moduleReference);
 
   public abstract JpsJavaDependenciesEnumerator enumerateDependencies(Collection<JpsModule> modules);
diff --git a/jps/model-api/src/org/jetbrains/jps/model/java/JpsProductionModuleSourcePackagingElement.java b/jps/model-api/src/org/jetbrains/jps/model/java/JpsProductionModuleSourcePackagingElement.java
new file mode 100644 (file)
index 0000000..548980f
--- /dev/null
@@ -0,0 +1,11 @@
+// Copyright 2000-2018 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license that can be found in the LICENSE file.
+package org.jetbrains.jps.model.java;
+
+import org.jetbrains.annotations.NotNull;
+import org.jetbrains.jps.model.artifact.elements.JpsPackagingElement;
+import org.jetbrains.jps.model.module.JpsModuleReference;
+
+public interface JpsProductionModuleSourcePackagingElement extends JpsPackagingElement {
+  @NotNull
+  JpsModuleReference getModuleReference();
+}
index ba9e20de5b209f856b3f8d995a25830e27f407ab..aff6c299cf3e75b6da9e1949368e79e09ea7667d 100644 (file)
@@ -208,6 +208,12 @@ public class JpsJavaExtensionServiceImpl extends JpsJavaExtensionService {
 
   @Override
   @NotNull
+  public JpsProductionModuleSourcePackagingElement createProductionModuleSource(@NotNull JpsModuleReference moduleReference) {
+    return new JpsProductionModuleSourcePackagingElementImpl(moduleReference);
+  }
+
+  @Override
+  @NotNull
   public JpsTestModuleOutputPackagingElement createTestModuleOutput(@NotNull JpsModuleReference moduleReference) {
     return new JpsTestModuleOutputPackagingElementImpl(moduleReference);
   }
diff --git a/jps/model-impl/src/org/jetbrains/jps/model/java/impl/JpsProductionModuleSourcePackagingElementImpl.java b/jps/model-impl/src/org/jetbrains/jps/model/java/impl/JpsProductionModuleSourcePackagingElementImpl.java
new file mode 100644 (file)
index 0000000..676bf57
--- /dev/null
@@ -0,0 +1,37 @@
+// Copyright 2000-2018 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license that can be found in the LICENSE file.
+package org.jetbrains.jps.model.java.impl;
+
+import org.jetbrains.annotations.NotNull;
+import org.jetbrains.jps.model.JpsElementChildRole;
+import org.jetbrains.jps.model.ex.JpsCompositeElementBase;
+import org.jetbrains.jps.model.ex.JpsElementChildRoleBase;
+import org.jetbrains.jps.model.java.JpsProductionModuleSourcePackagingElement;
+import org.jetbrains.jps.model.module.JpsModuleReference;
+
+public class JpsProductionModuleSourcePackagingElementImpl extends JpsCompositeElementBase<JpsProductionModuleSourcePackagingElementImpl>
+  implements JpsProductionModuleSourcePackagingElement {
+
+  private static final JpsElementChildRole<JpsModuleReference>
+    MODULE_REFERENCE_CHILD_ROLE = JpsElementChildRoleBase.create("module reference");
+
+  public JpsProductionModuleSourcePackagingElementImpl(JpsModuleReference moduleReference) {
+    myContainer.setChild(MODULE_REFERENCE_CHILD_ROLE, moduleReference);
+  }
+
+  @Override
+  @NotNull
+  public JpsModuleReference getModuleReference() {
+    return myContainer.getChild(MODULE_REFERENCE_CHILD_ROLE);
+  }
+
+  private JpsProductionModuleSourcePackagingElementImpl(JpsProductionModuleSourcePackagingElementImpl original) {
+    super(original);
+  }
+
+  @NotNull
+  @Override
+  public JpsProductionModuleSourcePackagingElementImpl createCopy() {
+    return new JpsProductionModuleSourcePackagingElementImpl(this);
+  }
+
+}
index 56d9ce0ae4af840a67ee37947db444a79b900e2e..14bcec66fd8a0fc76256602c8ebef41af0f0c62e 100644 (file)
@@ -163,7 +163,9 @@ public class JpsJavaModelSerializerExtension extends JpsModelSerializerExtension
   @NotNull
   @Override
   public List<? extends JpsPackagingElementSerializer<?>> getPackagingElementSerializers() {
-    return Arrays.asList(new JpsModuleOutputPackagingElementSerializer(), new JpsTestModuleOutputPackagingElementSerializer());
+    return Arrays.asList(new JpsModuleOutputPackagingElementSerializer(),
+                         new JpsTestModuleOutputPackagingElementSerializer(),
+                         new JpsModuleSourcePackagingElementSerializer());
   }
 
   @NotNull
@@ -281,6 +283,24 @@ public class JpsJavaModelSerializerExtension extends JpsModelSerializerExtension
     }
   }
 
+  private static class JpsModuleSourcePackagingElementSerializer
+    extends JpsPackagingElementSerializer<JpsProductionModuleSourcePackagingElement> {
+    private JpsModuleSourcePackagingElementSerializer() {
+      super("module-source", JpsProductionModuleSourcePackagingElement.class);
+    }
+
+    @Override
+    public JpsProductionModuleSourcePackagingElement load(Element element) {
+      JpsModuleReference reference = JpsElementFactory.getInstance().createModuleReference(element.getAttributeValue("name"));
+      return getService().createProductionModuleSource(reference);
+    }
+
+    @Override
+    public void save(JpsProductionModuleSourcePackagingElement element, Element tag) {
+      tag.setAttribute("name", element.getModuleReference().getModuleName());
+    }
+  }
+
   private static class JpsTestModuleOutputPackagingElementSerializer extends JpsPackagingElementSerializer<JpsTestModuleOutputPackagingElement> {
     private JpsTestModuleOutputPackagingElementSerializer() {
       super("module-test-output", JpsTestModuleOutputPackagingElement.class);
index d70a36e6f34b7ee5adef7a1922e76eb4ea69351f..fec3275d4f29417712ca7e251155e065b28f27db 100644 (file)
@@ -121,6 +121,8 @@ element.type.name.library.files=Library Files
 node.text.0.compile.output=''{0}'' compile output
 node.text.0.test.compile.output=''{0}'' test compile output
 node.text.0.with.dependencies=''{0}'' with dependencies
+node.text.0.module.sources=''{0}'' sources
+element.type.name.module.source=Module Sources
 element.type.name.module.output=Module Output
 element.type.name.module.test.output=Module Test Output
 element.type.name.directory=Directory