Merge branch 'master' into uta-python
[idea/community.git] / python / edu / build / pycharm_edu_build.gant
1 /*
2  * Copyright 2000-2014 JetBrains s.r.o.
3  *
4  * Licensed under the Apache License, Version 2.0 (the "License");
5  * you may not use this file except in compliance with the License.
6  * You may obtain a copy of the License at
7  *
8  * http://www.apache.org/licenses/LICENSE-2.0
9  *
10  * Unless required by applicable law or agreed to in writing, software
11  * distributed under the License is distributed on an "AS IS" BASIS,
12  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13  * See the License for the specific language governing permissions and
14  * limitations under the License.
15  */
16
17 import org.jetbrains.jps.LayoutInfo
18
19 setProperty("home", getHome())
20 includeTargets << new File("$home/community/build/scripts/utils.gant")
21 includeTargets << new File("$home/community/build/scripts/libLicenses.gant")
22 includeTargets << new File("$home/build/scripts/ultimate_utils.gant")
23
24 requireProperty("buildNumber", requireProperty("build.number", snapshot))
25 setProperty("buildName", "EDU-$buildNumber")
26 setProperty("ch", "$home/community")
27 setProperty("pythonCommunityHome", "$ch/python")
28 setProperty("pythonEduHome", "$ch/python/edu")
29
30 // load ApplicationInfo.xml properties
31 ant.xmlproperty(file: "$pythonEduHome/resources/idea/PyCharmEduApplicationInfo.xml", collapseAttributes: "true")
32 setProperty("system_selector", "PyCharmEdu${p("component.version.major")}0")
33 setProperty("dryRun", false)
34 setProperty("jdk16", guessJdk())
35
36 //modules to compile
37 setProperty("pluginFilter", new File("$pythonEduHome/build/plugin-list.txt").readLines())
38
39 private String getHome(){
40   // current file is supposed to be at build/scripts/*.gant path
41   String uri = this["gant.file"]
42   return new File(new URI(uri).getSchemeSpecificPart()).getParentFile().getParentFile().getParentFile().getParentFile().getParentFile()
43 }
44
45 private List<String> pycharmPlatformApiModules() {
46   return [platformApiModules, "dom-openapi"].flatten()
47 }
48
49
50 private List pycharmImplementationModules() {   //modules to put into pycharm.jar
51   return [platformImplementationModules, "dom-impl", "python-community", "python-community-ide-resources", 
52     "python-ide-community", "python-configure", "python-educational", "python-openapi", "python-psi-api", "platform-main"].flatten()
53 }
54
55 private List modules() {
56   return [
57     "python-pydev", "colorSchemes", pycharmPlatformApiModules(), pycharmImplementationModules(), pluginFilter
58   ].flatten()
59 }
60
61 private List approvedJars() {
62   def normalizedHome = ch.replace('\\', '/')
63   def normalizedPythonHome = pythonCommunityHome.replace('\\', '/')
64   return ["$normalizedHome/lib/", "$normalizedPythonHome/lib/", "$normalizedHome/xml/relaxng/lib/"]
65 }
66
67 class Paths {
68   final sandbox
69   final distAll
70   final distWin
71   final distMac
72   final distUnix
73   final artifacts
74   final ideaSystem
75   final ideaConfig
76
77   def Paths(String home) {
78     sandbox = "$home/out/pycharmEDU"
79
80     distAll = "$sandbox/layout"
81     distWin = "$sandbox/win"
82     distMac = "$sandbox/mac"
83     distUnix = "$sandbox/unix"
84     artifacts = "$sandbox/artifacts"
85
86     ideaSystem = "$sandbox/system"
87     ideaConfig = "$sandbox/config"
88   }
89 }
90
91 setProperty("paths", new Paths(home))
92
93 target('default': "Build artifacts") {
94
95   loadProject()
96
97   projectBuilder.stage("Cleaning up sandbox folder")
98
99   projectBuilder.targetFolder = "${paths.sandbox}/classes"
100   projectBuilder.dryRun = dryRun
101
102   if (!dryRun) {
103     forceDelete(paths.sandbox)
104     ant.mkdir(dir: paths.sandbox)
105     //Use EDU versions of IdeTipsAndTricks.xml and icon-robots.txt.
106     ant.delete(file: "${pythonCommunityHome}/src/META-INF/IdeTipsAndTricks.xml")
107     ant.delete(file: "${pythonCommunityHome}/resources/icon-robots.txt")
108   }
109
110   ant.tstamp() {
111     format(property: "todayYear", pattern: "yyyy")
112   }
113
114   bundledJDKs()
115   //EDU installation with a custom page dialog
116   ant.copy(file: "$ch/python/edu/build/desktop.ini", tofile: "$ch/build/conf/nsis/desktop.ini", overwrite: "true")
117   ant.copy(file: "$ch/python/edu/build/idea.nsi",    tofile: "$ch/build/conf/nsis/idea.nsi", overwrite: "true")
118
119   ant.patternset(id: "resources.included") {
120     include(name: "**/*.properties")
121     include(name: "fileTemplates/**/*")
122     include(name: "inspectionDescriptions/**/*")
123     include(name: "intentionDescriptions/**/*")
124     include(name: "tips/**/*")
125     include(name: "search/**/*")
126   }
127
128   ant.patternset(id: "resources.excluded") {
129     exclude(name: "**/*.properties")
130     exclude(name: "fileTemplates/**/*")
131     exclude(name: "fileTemplates")
132     exclude(name: "inspectionDescriptions/**/*")
133     exclude(name: "inspectionDescriptions")
134     exclude(name: "intentionDescriptions/**/*")
135     exclude(name: "intentionDescriptions")
136     exclude(name: "tips/**/*")
137     exclude(name: "tips")
138     exclude(name: "courses")
139     exclude(name: "courses/*")
140   }
141
142   zipSources(home, paths.artifacts)
143
144   def usedJars = buildModulesAndCollectUsedJars(modules(), approvedJars(), ["/ant/"])
145
146   layoutEducational("${paths.sandbox}/classes/production", usedJars)
147
148   def extraArgs = ["build.code": "pycharm${buildName}", "build.number": "PE-$buildNumber", "artifacts.path": "${paths.artifacts}"]
149   def sitFileName = "pycharm${buildName}"
150   ant.copy(file: "${paths.artifacts}/pycharm${buildName}.mac.zip", tofile: "${paths.artifacts}/${sitFileName}-no-jdk.sit")
151
152   signMacZip("pycharm", extraArgs + ["sitFileName": "${sitFileName}-no-jdk"])
153   notifyArtifactBuilt("${paths.artifacts}/${sitFileName}-no-jdk.sit")
154   buildDmg("pycharm", "${pythonEduHome}/build/DMG_background.png", extraArgs + ["sitFileName": "${sitFileName}-no-jdk"])
155
156   if (p("jdk.mac") != "false" && new File(macCustomJDK).exists()) {
157     ant.copy(file: "${paths.artifacts}/pycharm${buildName}.mac.zip", tofile: "${paths.artifacts}/${sitFileName}.sit")
158     signMacZip("pycharm", extraArgs + ["sitFileName": "${sitFileName}", "jdk_archive_name": macCustomJDK])
159     buildDmg("pycharm", "${pythonEduHome}/build/DMG_background.png", extraArgs + ["sitFileName": "${sitFileName}"])
160   }
161
162   ant.delete(file: "${paths.artifacts}/pycharm${buildName}.mac.zip")
163 }
164
165 public layoutEducational(String classesPath, Set usedJars) {
166   setProperty("pluginFilter", new File("$pythonEduHome/build/plugin-list.txt").readLines())
167
168   if (usedJars == null) {
169     usedJars = collectUsedJars(modules(), approvedJars(), ["/ant/"], null)
170   }
171
172   def paths = new Paths(home)
173   buildSearchableOptions("${projectBuilder.moduleOutput(findModule("platform-resources"))}/search", [], {
174     projectBuilder.moduleRuntimeClasspath(findModule("main_pycharm_edu"), false).each {
175       ant.pathelement(location: it)
176     }
177   }, "-Didea.platform.prefix=PyCharmEdu -Didea.no.jre.check=true")
178
179   def appInfo = appInfoFile()
180   if (!dryRun) {
181     wireBuildDate("PE-${buildNumber}", appInfo)
182   }
183
184   Map args = [
185     buildNumber: "PE-${buildNumber}",
186     system_selector: system_selector,
187     ide_jvm_args: "-Didea.platform.prefix=PyCharmEdu -Didea.no.jre.check=true"]
188
189   LayoutInfo layoutInfo = layoutFull(args, paths.distAll, usedJars)
190   generateLicensesTable("$paths.artifacts/third-party-libraries.txt", layoutInfo.usedModules);
191
192   layoutWin(args, paths.distWin)
193   layoutUnix(args, paths.distUnix)
194   layoutMac(args, paths.distMac)
195
196   ant.echo(message: "PE-${buildNumber}", file: "${paths.distAll}/build.txt")
197
198   def launcher = "${paths.distWin}/bin/pycharm.exe"
199   List resourcePaths = ["$ch/community-resources/src",
200     "$ch/platform/icons/src",
201     "$pythonCommunityHome/python-community-ide-resources/resources",
202     "$pythonCommunityHome/resources",
203     "$pythonEduHome/resources"]
204   buildWinLauncher(ch, "$ch/bin/WinLauncher/WinLauncher.exe", launcher,
205                    appInfo, "$pythonEduHome/build/pycharm_edu_launcher.properties", system_selector, resourcePaths)
206   signExecutableFiles("${paths.distWin}/bin")
207
208   buildWinZip("${paths.artifacts}/pycharm${buildName}.zip", [paths.distAll, paths.distWin, "${paths.sandbox}/jdk.win"])
209
210   buildNSIS([paths.distAll, paths.distWin],
211             "$pythonEduHome/build/strings.nsi", "$pythonEduHome/build/paths.nsi",
212             "pycharmEDU-", false, true, system_selector)
213
214   String tarRoot = isEap() ? "pycharm-edu-$buildNumber" : "pycharm-edu-${p("component.version.major")}.${p("component.version.minor")}"
215   buildTarGz(tarRoot, "$paths.artifacts/pycharm${buildName}-no-jdk.tar", [paths.distAll, paths.distUnix])
216   if (p("jdk.linux") != "false") {
217     buildTarGz(tarRoot, "$paths.artifacts/pycharm${buildName}.tar", [paths.distAll, paths.distUnix, "${paths.sandbox}/jdk.linux"], ["jre/jre/bin/*"])
218   }
219
220
221   String macAppRoot = isEap() ? "PyCharm Edu ${p("component.version.major")}.${p("component.version.minor")} EAP.app/Contents" : "PyCharm Edu.app/Contents"
222   buildMacZip(macAppRoot, "${paths.artifacts}/pycharm${buildName}.mac.zip", [paths.distAll], paths.distMac)
223 }
224
225 private layoutPlugins(layouts) {
226   dir("plugins") {
227     layouts.layoutPlugin("interactive-learning")
228     layouts.layoutPlugin("interactive-learning-python") {
229       dir("courses") {
230         fileset(dir: "$pythonEduHome/interactive-learning-python/resources/courses")
231       }
232     }
233     layouts.layoutPlugin("course-creator")
234     layouts.layoutPlugin("course-creator-python")
235     layouts.layoutPlugin("ipnb") {
236       fileset(dir: "$pythonCommunityHome/ipnb/lib")
237     }
238   }
239
240   layouts.layoutCommunityPlugins(ch)
241 }
242
243 private String appInfoFile() {
244   return "$home/out/pycharmEDU/classes/production/python-educational/idea/PyCharmEduApplicationInfo.xml"
245 }
246
247 private layoutFull(Map args, String target, Set usedJars) {
248   def openapiModules = pycharmPlatformApiModules()
249   def superLayouts = includeFile("$ch/build/scripts/layouts.gant")
250
251   reassignAltClickToMultipleCarets("$ch")
252   
253   def result = layout(target) {
254     dir("lib") {
255       jar("util.jar") {
256         module("util")
257         module("util-rt")
258       }
259
260       jar("openapi.jar") {
261         openapiModules.each { module it }
262       }
263
264       jar("annotations.jar") {
265         module("annotations-common")
266         module("annotations")
267       }
268       jar("extensions.jar") { module("extensions") }
269
270       jar([name: "pycharm.jar", duplicate: "preserve"]) {
271         pycharmImplementationModules().each {
272           module(it) {
273             exclude(name: "**/tips/**")
274           }
275         }
276       }
277
278       jar("educational.jar") {
279         module("educational")
280       }
281
282       jar("pycharm-pydev.jar") {
283         module("python-pydev")
284       }
285
286       jar("bootstrap.jar") { module("bootstrap") }
287       jar("resources.jar") {
288         module("platform-resources")
289         module("colorSchemes")
290       }
291
292       jar("forms_rt.jar") {
293         module("forms_rt")
294       }
295
296       //noinspection GroovyAssignabilityCheck
297       jar([name: "resources_en.jar", duplicate: "preserve"]) {
298         // custom resources should go first
299         module("python-community-ide-resources") {
300           ant.patternset {
301             include(name: "**/tips/**")
302           }
303         }
304         module("platform-resources-en") {
305           ant.patternset {
306             exclude(name: "tips/images/switcher.png")
307             exclude(name: "tips/images/navigateToFilePath.gif")
308           }
309         }
310       }
311
312       jar("icons.jar") { module("icons") }
313       jar("boot.jar") { module("boot") }
314
315       usedJars.each {
316         fileset(file: it)
317       }
318
319       fileset(dir: "$ch/build/kotlinc/lib") {
320         include(name: "kotlin-runtime.jar")
321         include(name: "kotlin-reflect.jar")
322       }
323
324       dir("libpty") {
325         fileset(dir: "$ch/lib/libpty") {
326           exclude(name: "*.txt")
327         }
328       }
329
330       dir("ext") {
331         fileset(dir: "$ch/lib") {
332           include(name: "cglib*.jar")
333         }
334       }
335
336       dir("src") {
337         fileset(dir: "$ch/lib/src") {
338           include(name: "trove4j_changes.txt")
339           include(name: "trove4j_src.jar")
340         }
341
342         jar("pycharm-pydev-src.zip") {
343           fileset(dir: "$pythonCommunityHome/pydevSrc")
344         }
345         jar("pycharm-openapi-src.zip") {
346           fileset(dir: "$pythonCommunityHome/openapi/src")
347           fileset(dir: "$pythonCommunityHome/psi-api/src")
348         }
349       }
350     }
351
352     dir("help") {
353       fileset(dir: "$home/python/help") {
354         include(name: "*.pdf")
355       }
356     }
357
358     dir("helpers") {
359       fileset(dir: "$pythonCommunityHome/helpers")
360     }
361
362     dir("license") {
363       fileset(dir: "$ch/license")
364       fileset(dir: "$ch") {
365         include(name: "LICENSE.txt")
366         include(name: "NOTICE.txt")
367       }
368     }
369
370     layoutPlugins(superLayouts)
371
372     dir("bin") {
373       fileset(dir: "$ch/bin") {
374         exclude(name: "appletviewer.policy")
375         include(name: "*.*")
376       }
377     }
378   }
379   patchPropertiesFile(target, args + [appendices: ["$home/build/conf/ideaJNC.properties"]])
380   return result
381 }
382
383 private layoutWin(Map args, String target) {
384   layout(target) {
385     dir("bin") {
386       fileset(dir: "$ch/bin/win") {
387         exclude(name: "breakgen*")
388       }
389     }
390
391     dir("skeletons") {
392       fileset(dir: "$pythonCommunityHome/skeletons") {
393         include(name: "skeletons-win*.zip")
394       }
395     }
396   }
397
398   winScripts(target, ch, "pycharm.bat", args)
399   winVMOptions(target, null, "pycharm.exe")
400
401   ant.copy(file: "$home/python/help/pycharm-eduhelp.jar", todir: "$target/help", failonerror: false)
402 }
403
404 private layoutUnix(Map args, String target) {
405   layout(target) {
406     dir("bin") {
407       fileset(dir: "$ch/bin/linux") {
408         exclude(name: "libbreakgen*")
409       }
410     }
411   }
412
413   ant.copy(file: "$pythonCommunityHome/resources/PyCharmCore128.png", tofile: "$target/bin/pycharm.png")
414
415   unixScripts(target, ch, "pycharm.sh", args)
416   unixVMOptions(target, "pycharm")
417
418   ant.copy(file: "$home/python/help/pycharm-eduhelp.jar", todir: "$target/help", failonerror: false)
419 }
420
421 private layoutMac(Map _args, String target) {
422   layout(target) {
423     dir("bin") {
424       fileset(dir: "$home/bin") {
425         include(name: "*.jnilib")
426       }
427     }
428
429     dir("skeletons") {
430       fileset(dir: "$pythonCommunityHome/skeletons") {
431         include(name: "skeletons-mac*.zip")
432       }
433     }
434   }
435
436   Map args = new HashMap(_args)
437   args.icns = "$pythonCommunityHome/edu/resources/PyCharmEdu.icns"
438   args.bundleIdentifier = "com.jetbrains.pycharm"
439   args.platform_prefix = "PyCharmEdu"
440   args.help_id = "PE"
441   args."idea.properties.path" = "${paths.distAll}/bin/idea.properties"
442   args."idea.properties" = ["idea.no.jre.check": true, "ide.mac.useNativeClipboard": "false"];
443   args.executable = "pycharm"
444   layoutMacApp(target, ch, args)
445 }