build.gradle.kts 29 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955
  1. import groovy.util.Node
  2. import groovy.xml.XmlParser
  3. import org.gradle.api.JavaVersion.VERSION_17
  4. import org.jetbrains.changelog.Changelog
  5. import org.jetbrains.intellij.platform.gradle.IntelliJPlatformType
  6. import org.jetbrains.intellij.platform.gradle.IntelliJPlatformType.IntellijIdeaUltimate
  7. import org.jetbrains.intellij.platform.gradle.TestFrameworkType
  8. import org.jetbrains.intellij.platform.gradle.extensions.IntelliJPlatformDependenciesExtension
  9. import org.jetbrains.intellij.platform.gradle.extensions.IntelliJPlatformTestingExtension
  10. import org.jetbrains.intellij.platform.gradle.tasks.RunIdeTask
  11. import org.jetbrains.intellij.platform.gradle.utils.extensionProvider
  12. import org.jetbrains.kotlin.gradle.tasks.KotlinCompile
  13. import java.util.*
  14. // The same as `--stacktrace` param
  15. gradle.startParameter.showStacktrace = ShowStacktrace.ALWAYS
  16. @Suppress("DSL_SCOPE_VIOLATION")
  17. plugins {
  18. id("java") // Java support
  19. alias(libs.plugins.changelog) // Gradle Changelog Plugin
  20. alias(libs.plugins.qodana) // Gradle Qodana Plugin
  21. alias(libs.plugins.kover) // Gradle Kover Plugin
  22. alias(libs.plugins.serialization)
  23. alias(libs.plugins.gradleIntelliJPlugin)
  24. id("org.jetbrains.grammarkit") version "2022.3.2.2"
  25. kotlin("jvm") version "1.8.22"
  26. id("net.saliman.properties") version "1.5.2"
  27. }
  28. fun properties(key: String) = providers.gradleProperty(key)
  29. fun environment(key: String) = providers.environmentVariable(key)
  30. val basePluginArchiveName = "autodev-jetbrains"
  31. val javaScriptPlugins = listOf("JavaScript")
  32. val pycharmPlugins = listOf(prop("pythonPlugin"))
  33. val javaPlugins = listOf("com.intellij.java", "org.jetbrains.kotlin")
  34. val clionVersion = prop("clionVersion")
  35. // https://plugins.jetbrains.com/docs/intellij/plugin-compatibility.html#modules-specific-to-functionality
  36. val clionPlugins = listOf(
  37. "com.intellij.cidr.base",
  38. "com.intellij.cidr.lang",
  39. "com.intellij.clion",
  40. prop("rustPlugin"),
  41. "org.toml.lang"
  42. )
  43. var cppPlugins: List<String> = listOf(
  44. "com.intellij.cidr.lang",
  45. "com.intellij.clion",
  46. "com.intellij.cidr.base",
  47. "org.jetbrains.plugins.clion.test.google",
  48. "org.jetbrains.plugins.clion.test.catch"
  49. )
  50. val rustPlugins = listOf(
  51. prop("rustPlugin"),
  52. "org.toml.lang"
  53. )
  54. val riderVersion = prop("riderVersion")
  55. val riderPlugins: List<String> = listOf(
  56. "rider-plugins-appender",
  57. "org.intellij.intelliLang",
  58. )
  59. val scalaPlugin = prop("scalaPlugin")
  60. val pluginProjects: List<Project> get() = rootProject.allprojects.toList()
  61. val ideaPlugins =
  62. listOf(
  63. "com.intellij.java",
  64. "org.jetbrains.plugins.gradle",
  65. "org.jetbrains.idea.maven",
  66. "org.jetbrains.kotlin",
  67. "JavaScript"
  68. )
  69. var baseIDE = prop("baseIDE")
  70. val platformVersion = prop("platformVersion").toInt()
  71. val ideaVersion = prop("ideaVersion")
  72. val golandVersion = prop("golandVersion")
  73. val pycharmVersion = prop("pycharmVersion")
  74. val webstormVersion = prop("webstormVersion")
  75. var lang = extra.properties["lang"] ?: "java"
  76. val baseVersion = when (baseIDE) {
  77. "idea" -> ideaVersion
  78. "pycharm" -> pycharmVersion
  79. "goland" -> golandVersion
  80. "clion" -> clionVersion
  81. "rider" -> riderVersion
  82. "javascript" -> webstormVersion
  83. else -> error("Unexpected IDE name: `$baseIDE`")
  84. }
  85. changelog {
  86. version.set(properties("pluginVersion"))
  87. groups.empty()
  88. path.set(rootProject.file("CHANGELOG.md").toString())
  89. repositoryUrl.set(properties("pluginRepositoryUrl"))
  90. }
  91. repositories {
  92. mavenCentral()
  93. intellijPlatform {
  94. defaultRepositories()
  95. jetbrainsRuntime()
  96. }
  97. }
  98. configure(
  99. subprojects
  100. - project(":exts")
  101. ) {
  102. apply {
  103. plugin("idea")
  104. plugin("kotlin")
  105. plugin("org.jetbrains.kotlinx.kover")
  106. plugin("org.jetbrains.intellij.platform.module")
  107. }
  108. repositories {
  109. mavenCentral()
  110. intellijPlatform {
  111. defaultRepositories()
  112. jetbrainsRuntime()
  113. }
  114. }
  115. intellijPlatform {
  116. instrumentCode = false
  117. buildSearchableOptions = false
  118. }
  119. idea {
  120. module {
  121. generatedSourceDirs.add(file("src/gen"))
  122. isDownloadJavadoc = true
  123. isDownloadSources = true
  124. }
  125. }
  126. configure<JavaPluginExtension> {
  127. sourceCompatibility = VERSION_17
  128. targetCompatibility = VERSION_17
  129. }
  130. tasks {
  131. withType<KotlinCompile> {
  132. kotlinOptions {
  133. jvmTarget = VERSION_17.toString()
  134. languageVersion = "1.8"
  135. // see https://plugins.jetbrains.com/docs/intellij/using-kotlin.html#kotlin-standard-library
  136. apiVersion = "1.7"
  137. freeCompilerArgs = listOf("-Xjvm-default=all")
  138. }
  139. }
  140. prepareSandbox { enabled = false }
  141. }
  142. val testOutput = configurations.create("testOutput")
  143. if (this.name != "ext-terminal") {
  144. sourceSets {
  145. main {
  146. java.srcDirs("src/gen")
  147. if (platformVersion == 241) {
  148. resources.srcDirs("src/233/main/resources")
  149. }
  150. resources.srcDirs("src/$platformVersion/main/resources")
  151. }
  152. test {
  153. resources.srcDirs("src/$platformVersion/test/resources")
  154. }
  155. }
  156. kotlin {
  157. sourceSets {
  158. main {
  159. // share 233 code to 241
  160. if (platformVersion == 241) {
  161. kotlin.srcDirs("src/233/main/kotlin")
  162. }
  163. kotlin.srcDirs("src/$platformVersion/main/kotlin")
  164. }
  165. test {
  166. kotlin.srcDirs("src/$platformVersion/test/kotlin")
  167. }
  168. }
  169. }
  170. }
  171. dependencies {
  172. compileOnly(kotlin("stdlib-jdk8"))
  173. implementation("org.jetbrains.kotlinx:kotlinx-coroutines-core:1.8.1")
  174. implementation("org.jetbrains.kotlinx:kotlinx-serialization-json:1.6.3")
  175. testOutput(sourceSets.test.get().output.classesDirs)
  176. intellijPlatform {
  177. testFramework(TestFrameworkType.Bundled)
  178. }
  179. }
  180. }
  181. project(":") {
  182. apply {
  183. plugin("org.jetbrains.changelog")
  184. plugin("org.jetbrains.intellij.platform")
  185. }
  186. repositories {
  187. intellijPlatform {
  188. defaultRepositories()
  189. jetbrainsRuntime()
  190. }
  191. }
  192. intellijPlatform {
  193. projectName = basePluginArchiveName
  194. pluginConfiguration {
  195. id = "cc.unitmesh.devti"
  196. name = "AutoDev"
  197. version = prop("pluginVersion")
  198. ideaVersion {
  199. sinceBuild = prop("pluginSinceBuild")
  200. untilBuild = prop("pluginUntilBuild")
  201. }
  202. vendor {
  203. name = "Phodal Huang"
  204. }
  205. }
  206. pluginVerification {
  207. freeArgs = listOf("-mute", "TemplateWordInPluginId,ForbiddenPluginIdPrefix")
  208. ides {
  209. ide(IntellijIdeaUltimate, "2024.2")
  210. select {
  211. types = listOf(IntellijIdeaUltimate)
  212. sinceBuild = "242"
  213. untilBuild = "242"
  214. }
  215. }
  216. }
  217. instrumentCode = false
  218. buildSearchableOptions = false
  219. }
  220. dependencies {
  221. intellijPlatform {
  222. pluginVerifier()
  223. intellijIde(prop("ideaVersion"))
  224. if (hasProp("jbrVersion")) {
  225. jetbrainsRuntime(prop("jbrVersion"))
  226. } else {
  227. jetbrainsRuntime()
  228. }
  229. val pluginList: MutableList<String> = mutableListOf("Git4Idea")
  230. when (lang) {
  231. "idea" -> {
  232. pluginList += javaPlugins
  233. }
  234. "scala" -> {
  235. pluginList += javaPlugins + scalaPlugin
  236. }
  237. "python" -> {
  238. pluginList += pycharmPlugins
  239. }
  240. "go" -> {
  241. pluginList += listOf("org.jetbrains.plugins.go")
  242. }
  243. "cpp" -> {
  244. pluginList += clionPlugins
  245. }
  246. "rust" -> {
  247. pluginList += rustPlugins
  248. }
  249. }
  250. intellijPlugins(pluginList)
  251. pluginModule(implementation(project(":core")))
  252. pluginModule(implementation(project(":java")))
  253. pluginModule(implementation(project(":kotlin")))
  254. pluginModule(implementation(project(":pycharm")))
  255. pluginModule(implementation(project(":javascript")))
  256. pluginModule(implementation(project(":goland")))
  257. pluginModule(implementation(project(":rust")))
  258. pluginModule(implementation(project(":cpp")))
  259. pluginModule(implementation(project(":scala")))
  260. pluginModule(implementation(project(":local-bundle")))
  261. pluginModule(implementation(project(":exts:ext-database")))
  262. pluginModule(implementation(project(":exts:ext-android")))
  263. pluginModule(implementation(project(":exts:ext-harmonyos")))
  264. pluginModule(implementation(project(":exts:ext-git")))
  265. pluginModule(implementation(project(":exts:ext-http-client")))
  266. pluginModule(implementation(project(":exts:ext-terminal")))
  267. pluginModule(implementation(project(":exts:devins-lang")))
  268. testFramework(TestFrameworkType.Bundled)
  269. }
  270. implementation(project(":core"))
  271. implementation(project(":java"))
  272. implementation(project(":kotlin"))
  273. implementation(project(":pycharm"))
  274. implementation(project(":javascript"))
  275. implementation(project(":goland"))
  276. implementation(project(":rust"))
  277. implementation(project(":cpp"))
  278. implementation(project(":scala"))
  279. implementation(project(":local-bundle"))
  280. implementation(project(":exts:ext-database"))
  281. implementation(project(":exts:ext-android"))
  282. implementation(project(":exts:ext-harmonyos"))
  283. implementation(project(":exts:ext-git"))
  284. implementation(project(":exts:ext-http-client"))
  285. implementation(project(":exts:ext-terminal"))
  286. implementation(project(":exts:devins-lang"))
  287. kover(project(":cpp"))
  288. kover(project(":core"))
  289. kover(project(":goland"))
  290. kover(project(":java"))
  291. kover(project(":javascript"))
  292. kover(project(":kotlin"))
  293. kover(project(":pycharm"))
  294. kover(project(":rust"))
  295. kover(project(":scala"))
  296. kover(project(":exts:ext-database"))
  297. kover(project(":exts:ext-android"))
  298. kover(project(":exts:devins-lang"))
  299. }
  300. tasks {
  301. val projectName = project.extensionProvider.flatMap { it.projectName }
  302. composedJar {
  303. archiveBaseName.convention(projectName)
  304. }
  305. withType<RunIdeTask> {
  306. // Default args for IDEA installation
  307. jvmArgs("-Xmx768m", "-XX:+UseG1GC", "-XX:SoftRefLRUPolicyMSPerMB=50")
  308. // Disable plugin auto reloading. See `com.intellij.ide.plugins.DynamicPluginVfsListener`
  309. jvmArgs("-Didea.auto.reload.plugins=false")
  310. // Don't show "Tip of the Day" at startup
  311. jvmArgs("-Dide.show.tips.on.startup.default.value=false")
  312. // uncomment if `unexpected exception ProcessCanceledException` prevents you from debugging a running IDE
  313. // jvmArgs("-Didea.ProcessCanceledException=disabled")
  314. }
  315. patchPluginXml {
  316. pluginDescription.set(provider { file("src/description.html").readText() })
  317. changelog {
  318. version.set(properties("pluginVersion"))
  319. groups.empty()
  320. path.set(rootProject.file("CHANGELOG.md").toString())
  321. repositoryUrl.set(properties("pluginRepositoryUrl"))
  322. }
  323. val changelog = project.changelog
  324. // Get the latest available change notes from the changelog file
  325. changeNotes.set(properties("pluginVersion").map { pluginVersion ->
  326. with(changelog) {
  327. renderItem(
  328. (getOrNull(pluginVersion) ?: getUnreleased())
  329. .withHeader(false)
  330. .withEmptySections(false),
  331. Changelog.OutputType.HTML,
  332. )
  333. }
  334. })
  335. }
  336. buildPlugin {
  337. archiveBaseName.set(basePluginArchiveName)
  338. archiveVersion.set(prop("pluginVersion") + "-" + prop("platformVersion"))
  339. }
  340. publishPlugin {
  341. dependsOn("patchChangelog")
  342. token.set(environment("PUBLISH_TOKEN"))
  343. channels.set(properties("pluginVersion").map {
  344. listOf(it.split('-').getOrElse(1) { "default" }.split('.').first())
  345. })
  346. }
  347. intellijPlatformTesting {
  348. // Generates event scheme for JetBrains Academy plugin FUS events to `build/eventScheme.json`
  349. runIde.register("buildEventsScheme") {
  350. task {
  351. args(
  352. "buildEventsScheme",
  353. "--outputFile=${buildDir()}/eventScheme.json",
  354. "--pluginId=com.jetbrains.edu"
  355. )
  356. // Force headless mode to be able to run command on CI
  357. systemProperty("java.awt.headless", "true")
  358. // BACKCOMPAT: 2024.1. Update value to 242 and this comment
  359. // `IDEA_BUILD_NUMBER` variable is used by `buildEventsScheme` task to write `buildNumber` to output json.
  360. // It will be used by TeamCity automation to set minimal IDE version for new events
  361. environment("IDEA_BUILD_NUMBER", "241")
  362. }
  363. }
  364. runIde.register("runInSplitMode") {
  365. splitMode = true
  366. // Specify custom sandbox directory to have a stable path to log file
  367. sandboxDirectory =
  368. intellijPlatform.sandboxContainer.dir("split-mode-sandbox-${prop("platformVersion")}")
  369. plugins {
  370. plugins(ideaPlugins)
  371. }
  372. }
  373. customRunIdeTask(IntellijIdeaUltimate, prop("ideaVersion"), baseTaskName = "Idea")
  374. }
  375. }
  376. }
  377. project(":core") {
  378. apply {
  379. plugin("org.jetbrains.kotlin.plugin.serialization")
  380. }
  381. dependencies {
  382. intellijPlatform {
  383. intellijIde(prop("ideaVersion"))
  384. intellijPlugins(ideaPlugins)
  385. testFramework(TestFrameworkType.Bundled)
  386. }
  387. implementation("com.theokanning.openai-gpt3-java:service:0.18.2")
  388. implementation("com.squareup.okhttp3:okhttp:4.4.1")
  389. implementation("com.squareup.okhttp3:okhttp-sse:4.4.1")
  390. implementation("com.squareup.retrofit2:converter-jackson:2.9.0")
  391. implementation("com.squareup.retrofit2:converter-gson:2.9.0")
  392. implementation("com.fasterxml.jackson.module:jackson-module-kotlin:2.14.2")
  393. implementation("com.fasterxml.jackson.core:jackson-databind:2.14.2")
  394. implementation("org.commonmark:commonmark:0.21.0")
  395. implementation("org.commonmark:commonmark-ext-gfm-tables:0.21.0")
  396. implementation("org.yaml:snakeyaml:2.2")
  397. implementation("com.nfeld.jsonpathkt:jsonpathkt:2.0.1")
  398. implementation("org.jetbrains:markdown:0.6.1")
  399. // chocolate factory
  400. // follow: https://onnxruntime.ai/docs/get-started/with-java.html
  401. // implementation("com.microsoft.onnxruntime:onnxruntime:1.18.0")
  402. // implementation("ai.djl.huggingface:tokenizers:0.29.0")
  403. implementation("cc.unitmesh:cocoa-core:1.0.0")
  404. implementation("cc.unitmesh:document:1.0.0")
  405. // kanban
  406. implementation("org.kohsuke:github-api:1.314")
  407. implementation("org.gitlab4j:gitlab4j-api:5.3.0")
  408. // template engine
  409. implementation("org.apache.velocity:velocity-engine-core:2.3")
  410. // http request/response
  411. implementation("com.fasterxml.jackson.module:jackson-module-kotlin:2.14.2")
  412. // token count
  413. implementation("com.knuddels:jtokkit:1.0.0")
  414. implementation("org.apache.commons:commons-text:1.12.0")
  415. implementation("org.jetbrains.kotlinx:kotlinx-serialization-json:1.6.3")
  416. // junit
  417. testImplementation("io.kotest:kotest-assertions-core:5.7.2")
  418. testImplementation("junit:junit:4.13.2")
  419. testRuntimeOnly("org.junit.vintage:junit-vintage-engine:5.9.3")
  420. }
  421. task("resolveDependencies") {
  422. doLast {
  423. rootProject.allprojects
  424. .map { it.configurations }
  425. .flatMap { it.filter { c -> c.isCanBeResolved } }
  426. .forEach { it.resolve() }
  427. }
  428. }
  429. }
  430. project(":pycharm") {
  431. dependencies {
  432. intellijPlatform {
  433. intellijIde(prop("ideaVersion"))
  434. intellijPlugins(ideaPlugins + pycharmPlugins)
  435. }
  436. implementation(project(":core"))
  437. }
  438. }
  439. project(":java") {
  440. dependencies {
  441. intellijPlatform {
  442. intellijIde(prop("ideaVersion"))
  443. intellijPlugins(ideaPlugins)
  444. }
  445. implementation(project(":core"))
  446. }
  447. }
  448. project(":javascript") {
  449. dependencies {
  450. intellijPlatform {
  451. intellijIde(prop("ideaVersion"))
  452. intellijPlugins(ideaPlugins)
  453. intellijPlugins(javaScriptPlugins)
  454. }
  455. implementation(project(":core"))
  456. }
  457. }
  458. project(":kotlin") {
  459. dependencies {
  460. intellijPlatform {
  461. intellijIde(prop("ideaVersion"))
  462. intellijPlugins(ideaPlugins)
  463. }
  464. implementation(project(":core"))
  465. implementation(project(":java"))
  466. }
  467. }
  468. project(":scala") {
  469. dependencies {
  470. intellijPlatform {
  471. intellijIde(prop("ideaVersion"))
  472. intellijPlugins(ideaPlugins + scalaPlugin)
  473. }
  474. implementation(project(":core"))
  475. implementation(project(":java"))
  476. }
  477. }
  478. project(":rust") {
  479. dependencies {
  480. intellijPlatform {
  481. intellijIde(prop("ideaVersion"))
  482. intellijPlugins(ideaPlugins + rustPlugins)
  483. }
  484. implementation(project(":core"))
  485. }
  486. }
  487. project(":cpp") {
  488. if (platformVersion == 233 || platformVersion == 241) {
  489. cppPlugins += "com.intellij.nativeDebug"
  490. }
  491. dependencies {
  492. intellijPlatform {
  493. intellijIde(clionVersion)
  494. intellijPlugins(cppPlugins)
  495. }
  496. implementation(project(":core"))
  497. }
  498. }
  499. //project(":csharp") {
  500. // dependencies {
  501. // intellijPlatform {
  502. // intellijIde(riderVersion)
  503. // intellijPlugins(riderPlugins)
  504. // }
  505. //
  506. // implementation(project(":core"))
  507. // }
  508. //}
  509. project(":goland") {
  510. dependencies {
  511. intellijPlatform {
  512. intellijIde(prop("ideaVersion"))
  513. intellijPlugins(prop("goPlugin").split(',').map(String::trim).filter(String::isNotEmpty))
  514. }
  515. implementation(project(":core"))
  516. }
  517. }
  518. project(":exts:ext-database") {
  519. dependencies {
  520. intellijPlatform {
  521. intellijIde(prop("ideaVersion"))
  522. intellijPlugins(ideaPlugins + "com.intellij.database")
  523. }
  524. implementation(project(":core"))
  525. }
  526. }
  527. project(":exts:ext-android") {
  528. dependencies {
  529. intellijPlatform {
  530. intellijIde(prop("ideaVersion"))
  531. intellijPlugins((ideaPlugins + prop("androidPlugin").ifBlank { "" }).filter(String::isNotEmpty))
  532. }
  533. implementation(project(":core"))
  534. }
  535. }
  536. project(":exts:ext-harmonyos") {
  537. dependencies {
  538. intellijPlatform {
  539. intellijIde(prop("ideaVersion"))
  540. intellijPlugins((ideaPlugins + prop("androidPlugin").ifBlank { "" }).filter(String::isNotEmpty))
  541. }
  542. implementation(project(":core"))
  543. }
  544. }
  545. project(":exts:ext-git") {
  546. dependencies {
  547. intellijPlatform {
  548. intellijIde(prop("ideaVersion"))
  549. intellijPlugins(ideaPlugins + "Git4Idea")
  550. }
  551. implementation(project(":core"))
  552. implementation("cc.unitmesh:git-commit-message:0.4.6")
  553. }
  554. }
  555. project(":exts:ext-http-client") {
  556. dependencies {
  557. intellijPlatform {
  558. intellijIde(prop("ideaVersion"))
  559. intellijPlugins(ideaPlugins + "com.jetbrains.restClient")
  560. }
  561. implementation(project(":core"))
  562. }
  563. }
  564. project(":local-bundle") {
  565. dependencies {
  566. intellijPlatform {
  567. intellijIde(prop("ideaVersion"))
  568. }
  569. implementation(project(":core"))
  570. }
  571. }
  572. project(":exts:ext-terminal") {
  573. dependencies {
  574. intellijPlatform {
  575. intellijIde(prop("ideaVersion"))
  576. intellijPlugins(ideaPlugins + "org.jetbrains.plugins.terminal")
  577. }
  578. implementation(project(":core"))
  579. }
  580. sourceSets {
  581. main {
  582. resources.srcDirs("src/$platformVersion/main/resources")
  583. }
  584. test {
  585. resources.srcDirs("src/$platformVersion/test/resources")
  586. }
  587. }
  588. kotlin {
  589. sourceSets {
  590. main {
  591. kotlin.srcDirs("src/$platformVersion/main/kotlin")
  592. }
  593. test {
  594. kotlin.srcDirs("src/$platformVersion/test/kotlin")
  595. }
  596. }
  597. }
  598. }
  599. project(":exts:devins-lang") {
  600. apply {
  601. plugin("org.jetbrains.grammarkit")
  602. }
  603. dependencies {
  604. intellijPlatform {
  605. intellijIde(prop("ideaVersion"))
  606. intellijPlugins(ideaPlugins + "org.intellij.plugins.markdown" + "com.jetbrains.sh" + "Git4Idea")
  607. }
  608. implementation(project(":core"))
  609. implementation(project(":exts:ext-git"))
  610. }
  611. tasks {
  612. generateLexer {
  613. sourceFile.set(file("src/grammar/DevInLexer.flex"))
  614. targetOutputDir.set(file("src/gen/cc/unitmesh/devti/language/lexer"))
  615. purgeOldFiles.set(true)
  616. }
  617. generateParser {
  618. sourceFile.set(file("src/grammar/DevInParser.bnf"))
  619. targetRootOutputDir.set(file("src/gen"))
  620. pathToParser.set("cc/unitmesh/devti/language/parser/DevInParser.java")
  621. pathToPsiRoot.set("cc/unitmesh/devti/language/psi")
  622. purgeOldFiles.set(true)
  623. }
  624. withType<KotlinCompile> {
  625. dependsOn(generateLexer, generateParser)
  626. }
  627. }
  628. }
  629. fun File.isPluginJar(): Boolean {
  630. if (!isFile) return false
  631. if (extension != "jar") return false
  632. return zipTree(this).files.any { it.isManifestFile() }
  633. }
  634. fun File.isManifestFile(): Boolean {
  635. if (extension != "xml") return false
  636. val rootNode = try {
  637. val parser = XmlParser()
  638. parser.parse(this)
  639. } catch (e: Exception) {
  640. logger.error("Failed to parse $path", e)
  641. return false
  642. }
  643. return rootNode.name() == "idea-plugin"
  644. }
  645. data class TypeWithVersion(val type: IntelliJPlatformType, val version: String)
  646. fun String.toTypeWithVersion(): TypeWithVersion {
  647. val (code, version) = split("-", limit = 2)
  648. return TypeWithVersion(IntelliJPlatformType.fromCode(code), version)
  649. }
  650. /**
  651. * Creates `run$[baseTaskName]` Gradle task to run IDE of given [type]
  652. * via `runIde` task with plugins according to [ideToPlugins] map
  653. */
  654. fun IntelliJPlatformTestingExtension.customRunIdeTask(
  655. type: IntelliJPlatformType,
  656. versionWithCode: String? = null,
  657. baseTaskName: String = type.name,
  658. ) {
  659. runIde.register("run$baseTaskName") {
  660. useInstaller = false
  661. if (versionWithCode != null) {
  662. val version = versionWithCode.toTypeWithVersion().version
  663. this.type = type
  664. this.version = version
  665. } else {
  666. val pathProperty = baseTaskName.replaceFirstChar { it.lowercaseChar() } + "Path"
  667. // Avoid throwing exception during property calculation.
  668. // Some IDE tooling (for example, Package Search plugin) may try to calculate properties during `Sync` phase for all tasks.
  669. // In our case, some `run*` task may not have `pathProperty` in your `gradle.properties`,
  670. // and as a result, the `Sync` tool window will show you the error thrown by `prop` function.
  671. //
  672. // The following solution just moves throwing the corresponding error to task execution,
  673. // i.e., only when a task is actually invoked
  674. if (hasProp(pathProperty)) {
  675. localPath.convention(layout.dir(provider { file(prop(pathProperty)) }))
  676. } else {
  677. task {
  678. doFirst {
  679. throw GradleException("Property `$pathProperty` is not defined in gradle.properties")
  680. }
  681. }
  682. }
  683. }
  684. // Specify custom sandbox directory to have a stable path to log file
  685. sandboxDirectory =
  686. intellijPlatform.sandboxContainer.dir("${baseTaskName.lowercase()}-sandbox-${prop("platformVersion")}")
  687. plugins {
  688. plugins(ideaPlugins)
  689. }
  690. }
  691. }
  692. fun IntelliJPlatformDependenciesExtension.intellijIde(versionWithCode: String) {
  693. val (type, version) = versionWithCode.toTypeWithVersion()
  694. create(type, version, useInstaller = false)
  695. }
  696. fun IntelliJPlatformDependenciesExtension.intellijPlugins(vararg notations: String) {
  697. for (notation in notations) {
  698. if (notation.contains(":")) {
  699. plugin(notation)
  700. } else {
  701. bundledPlugin(notation)
  702. }
  703. }
  704. }
  705. fun IntelliJPlatformDependenciesExtension.intellijPlugins(notations: List<String>) {
  706. intellijPlugins(*notations.toTypedArray())
  707. }
  708. fun hasProp(name: String): Boolean = extra.has(name)
  709. fun prop(name: String): String =
  710. extra.properties[name] as? String ?: error("Property `$name` is not defined in gradle.properties")
  711. fun withProp(name: String, action: (String) -> Unit) {
  712. if (hasProp(name)) {
  713. action(prop(name))
  714. }
  715. }
  716. fun withProp(filePath: String, name: String, action: (String) -> Unit) {
  717. if (!file(filePath).exists()) {
  718. println("$filePath doesn't exist")
  719. return
  720. }
  721. val properties = loadProperties(filePath)
  722. val value = properties.getProperty(name) ?: return
  723. action(value)
  724. }
  725. fun buildDir(): String {
  726. return project.layout.buildDirectory.get().asFile.absolutePath
  727. }
  728. fun <T : ModuleDependency> T.excludeKotlinDeps() {
  729. exclude(module = "kotlin-runtime")
  730. exclude(module = "kotlin-reflect")
  731. exclude(module = "kotlin-stdlib")
  732. exclude(module = "kotlin-stdlib-common")
  733. exclude(module = "kotlin-stdlib-jdk8")
  734. }
  735. fun loadProperties(path: String): Properties {
  736. val properties = Properties()
  737. file(path).bufferedReader().use { properties.load(it) }
  738. return properties
  739. }
  740. fun parseManifest(file: File): Node {
  741. val node = XmlParser().parse(file)
  742. check(node.name() == "idea-plugin") {
  743. "Manifest file `$file` doesn't contain top-level `idea-plugin` attribute"
  744. }
  745. return node
  746. }
  747. fun manifestFile(project: Project): File? {
  748. var filePath: String? = null
  749. val mainOutput = project.sourceSets.main.get().output
  750. val resourcesDir = mainOutput.resourcesDir ?: error("Failed to find resources dir for ${project.name}")
  751. if (filePath != null) {
  752. return resourcesDir.resolve(filePath).takeIf { it.exists() }
  753. ?: error("Failed to find manifest file for ${project.name} module")
  754. }
  755. val rootManifestFile =
  756. manifestFile(project(":intellij-plugin")) ?: error("Failed to find manifest file for :intellij-plugin module")
  757. val rootManifest = parseManifest(rootManifestFile)
  758. val children = ((rootManifest["content"] as? List<*>)?.single() as? Node)?.children()
  759. ?: error("Failed to find module declarations in root manifest")
  760. return children.filterIsInstance<Node>()
  761. .flatMap { node ->
  762. if (node.name() != "module") return@flatMap emptyList()
  763. val name = node.attribute("name") as? String ?: return@flatMap emptyList()
  764. listOfNotNull(resourcesDir.resolve("$name.xml").takeIf { it.exists() })
  765. }.firstOrNull() ?: error("Failed to find manifest file for ${project.name} module")
  766. }
  767. fun findModulePackage(project: Project): String? {
  768. val moduleManifest = manifestFile(project) ?: return null
  769. val node = parseManifest(moduleManifest)
  770. return node.attribute("package") as? String ?: error("Failed to find package for ${project.name}")
  771. }
  772. fun verifyClasses(project: Project) {
  773. val pkg = findModulePackage(project) ?: return
  774. val expectedDir = pkg.replace('.', '/')
  775. var hasErrors = false
  776. for (classesDir in project.sourceSets.main.get().output.classesDirs) {
  777. val basePath = classesDir.toPath()
  778. for (file in classesDir.walk()) {
  779. if (file.isFile && file.extension == "class") {
  780. val relativePath = basePath.relativize(file.toPath())
  781. if (!relativePath.startsWith(expectedDir)) {
  782. logger.error(
  783. "Wrong package of `${
  784. relativePath.joinToString(".").removeSuffix(".class")
  785. }` class. Expected `$pkg`"
  786. )
  787. hasErrors = true
  788. }
  789. }
  790. }
  791. }
  792. if (hasErrors) {
  793. throw GradleException("Classes with wrong package were found. See https://docs.google.com/document/d/1pOy-qNlGOJe6wftHVYHkH8sZOoAfav1fdGDPJgkQWJo")
  794. }
  795. }
  796. fun DependencyHandler.implementationWithoutKotlin(dependencyNotation: Provider<*>) {
  797. implementation(dependencyNotation) {
  798. excludeKotlinDeps()
  799. }
  800. }
  801. fun DependencyHandler.testImplementationWithoutKotlin(dependencyNotation: Provider<*>) {
  802. testImplementation(dependencyNotation) {
  803. excludeKotlinDeps()
  804. }
  805. }