github.com/tiagovtristao/plz@v13.4.0+incompatible/src/ide/intellij/module.go (about) 1 package intellij 2 3 import ( 4 "encoding/xml" 5 "fmt" 6 "io" 7 "path/filepath" 8 9 "github.com/thought-machine/please/src/core" 10 ) 11 12 // Module represents the IntelliJ concept of a module 13 type Module struct { 14 XMLName xml.Name `xml:"module"` 15 ModuleType string `xml:"type,attr"` 16 Version int `xml:"version,attr"` 17 Component ModuleComponent `xml:"component"` 18 } 19 20 func newModule(graph *core.BuildGraph, target *core.BuildTarget) Module { 21 component := newModuleComponent(target) 22 component.addOrderEntry(newSourceFolderEntry(false)) 23 24 for _, label := range target.DeclaredDependencies() { 25 dep := graph.TargetOrDie(label) 26 if shouldMakeModule(dep) { 27 component.addOrderEntry(newModuleEntry(moduleName(label))) 28 } 29 } 30 31 module := Module{ 32 ModuleType: "WEB_MODULE", 33 Version: 4, 34 Component: component, 35 } 36 37 return module 38 } 39 40 func newJavaModule(graph *core.BuildGraph, target *core.BuildTarget) Module { 41 module := newModule(graph, target) 42 module.ModuleType = "JAVA_MODULE" 43 module.Component.addOrderEntry(newInheritedJdkEntry()) 44 45 if shouldMakeLibrary(target) { 46 module.Component.addOrderEntry(newLibraryEntry(libraryName(target), "project")) 47 } 48 return module 49 } 50 51 func newScalaModule(graph *core.BuildGraph, target *core.BuildTarget) Module { 52 module := newJavaModule(graph, target) 53 54 module.Component.addOrderEntry(newLibraryEntry("scala-sdk", "application")) 55 56 return module 57 } 58 59 func shouldMakeJavaModule(target *core.BuildTarget) bool { 60 for _, label := range target.PrefixedLabels("rule:") { 61 if label == "java_library" { 62 return true 63 } else if label == "java_test" { 64 return true 65 } else if label == "maven_jar" { 66 return true 67 } 68 } 69 return false 70 } 71 72 func shouldMakeScalaModule(target *core.BuildTarget) bool { 73 for _, label := range target.PrefixedLabels("rule:") { 74 if label == "scala_library" { 75 return true 76 } 77 } 78 return false 79 } 80 81 func shouldMakeStaticModule(target *core.BuildTarget) bool { 82 for _, label := range target.PrefixedLabels("rule:") { 83 if label == "resources" || label == "test_resources" { 84 return true 85 } 86 } 87 return false 88 } 89 90 func shouldMakeModule(target *core.BuildTarget) bool { 91 return shouldMakeStaticModule(target) || 92 shouldMakeJavaModule(target) || 93 shouldMakeScalaModule(target) 94 } 95 96 func shouldHaveContent(target *core.BuildTarget) bool { 97 for _, label := range target.PrefixedLabels("rule:") { 98 if label == "java_library" { 99 return true 100 } else if label == "java_test" { 101 return true 102 } else if label == "scala_library" { 103 return true 104 } else if label == "resources" { 105 return true 106 } else if label == "test_resources" { 107 return true 108 } 109 } 110 return false 111 } 112 113 func shouldMakeLibrary(target *core.BuildTarget) bool { 114 for _, label := range target.PrefixedLabels("rule:") { 115 if label == "maven_jar" { 116 return true 117 } 118 } 119 return false 120 } 121 122 func isTestModule(target *core.BuildTarget) bool { 123 if target.IsTest { 124 return true 125 } 126 for _, label := range target.PrefixedLabels("rule:") { 127 if label == "java_test" { 128 return true 129 } 130 } 131 return false 132 } 133 134 func (module *Module) toXML(writer io.Writer) { 135 writer.Write([]byte("<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n")) 136 137 content, err := xml.MarshalIndent(module, "", " ") 138 if err == nil { 139 writer.Write(content) 140 } 141 } 142 143 // ModuleComponent represents the top level module wrapper. 144 type ModuleComponent struct { 145 XMLName xml.Name `xml:"component"` 146 Name string `xml:"name,attr"` 147 InheritCompilerOutput bool `xml:"inherit-compiler-output,attr"` 148 Content *ModuleContent `xml:"content,omitEmpty"` 149 OrderEntries []OrderEntry `xml:"orderEntry"` 150 } 151 152 func newModuleComponent(target *core.BuildTarget) ModuleComponent { 153 orderEntries := []OrderEntry{} 154 155 return ModuleComponent{ 156 Name: "NewModuleRootManager", 157 InheritCompilerOutput: true, 158 Content: newModuleContent(target), 159 OrderEntries: orderEntries, 160 } 161 } 162 163 func (moduleComponent *ModuleComponent) addOrderEntry(entry OrderEntry) { 164 moduleComponent.OrderEntries = append(moduleComponent.OrderEntries, entry) 165 } 166 167 // ModuleContent is a wrapper that is generally only used once in a given module. 168 type ModuleContent struct { 169 XMLName xml.Name `xml:"content"` 170 URL string `xml:"url,attr"` 171 SourceFolder []SourceFolder `xml:"sourceFolder"` 172 } 173 174 func newModuleContent(target *core.BuildTarget) *ModuleContent { 175 if !shouldHaveContent(target) { 176 return nil 177 } 178 179 sourceFolders := []SourceFolder{} 180 commonDir := target.Label.PackageDir() 181 182 joined := filepath.Join(core.RepoRoot, commonDir) 183 location := relativisedPathTo(moduleDirLocation(target), &joined) 184 185 sourceFolders = append(sourceFolders, SourceFolder{ 186 URL: fmt.Sprintf("file://$MODULE_DIR$/%s", *location), 187 IsTestSource: isTestModule(target), 188 PackagePrefix: packagePrefixFromLabels(target.PrefixedLabels("package_prefix:")), 189 }) 190 191 packageDir := commonDir 192 maybeSrcDir := target.PrefixedLabels("src_dir:") 193 if len(maybeSrcDir) == 1 { 194 packageDir = filepath.Join(packageDir, maybeSrcDir[0]) 195 } 196 joined = filepath.Join(core.RepoRoot, packageDir) 197 contentDir := relativisedPathTo(moduleDirLocation(target), &joined) 198 199 return &ModuleContent{ 200 URL: fmt.Sprintf("file://$MODULE_DIR$/%s", *contentDir), 201 SourceFolder: sourceFolders, 202 } 203 } 204 205 // SourceFolder is a location on disk that contains files of interest to this package. 206 type SourceFolder struct { 207 XMLName xml.Name `xml:"sourceFolder"` 208 URL string `xml:"url,attr"` 209 IsTestSource bool `xml:"isTestSource,attr"` 210 PackagePrefix *string `xml:"packagePrefix,attr,omitEmpty"` 211 } 212 213 // OrderEntry represents a dependency on (e.g.) another module, or a library or an SDK. 214 type OrderEntry struct { 215 XMLName xml.Name `xml:"orderEntry"` 216 Type string `xml:"type,attr"` 217 218 ForTests *bool `xml:"forTests,attr,omitEmpty"` 219 220 Exported *string `xml:"exported,attr,omitEmpty"` 221 222 LibraryName *string `xml:"name,attr,omitEmpty"` 223 LibraryLevel *string `xml:"level,attr,omitEmpty"` 224 225 ModuleName *string `xml:"module-name,attr,omitEmpty"` 226 } 227 228 func newLibraryEntry(name, level string) OrderEntry { 229 exported := "" 230 return OrderEntry{ 231 Type: "library", 232 LibraryName: &name, 233 LibraryLevel: &level, 234 Exported: &exported, 235 } 236 } 237 238 func newModuleEntry(name string) OrderEntry { 239 exported := "" 240 return OrderEntry{ 241 Type: "module", 242 ModuleName: &name, 243 Exported: &exported, 244 } 245 } 246 247 func newInheritedJdkEntry() OrderEntry { 248 return OrderEntry{ 249 Type: "inheritedJdk", 250 } 251 } 252 253 func newSourceFolderEntry(forTests bool) OrderEntry { 254 return OrderEntry{ 255 Type: "sourceFolder", 256 ForTests: &forTests, 257 } 258 } 259 260 func toModule(graph *core.BuildGraph, buildTarget *core.BuildTarget) *Module { 261 var module *Module 262 263 if shouldMakeStaticModule(buildTarget) { 264 madeModule := newModule(graph, buildTarget) 265 module = &madeModule 266 } 267 268 if shouldMakeJavaModule(buildTarget) { 269 madeModule := newJavaModule(graph, buildTarget) 270 module = &madeModule 271 } 272 273 if shouldMakeScalaModule(buildTarget) { 274 madeModule := newScalaModule(graph, buildTarget) 275 module = &madeModule 276 } 277 278 return module 279 } 280 281 func relativisedPathTo(location string, commonPath *string) *string { 282 if commonPath == nil { 283 return nil 284 } 285 286 rel, err := filepath.Rel(location, *commonPath) 287 if err != nil { 288 return nil 289 } 290 291 return &rel 292 } 293 294 func packagePrefixFromLabels(labels []string) *string { 295 if len(labels) != 1 { 296 return nil 297 } 298 return &labels[0] 299 }