25ca87b39d959924164aa62ea13b1965f0d39522
[idea/community.git] / python / educational-python / 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/educational-python")
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-community-configure", "educational-python", "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
116   ant.patternset(id: "resources.included") {
117     include(name: "**/*.properties")
118     include(name: "fileTemplates/**/*")
119     include(name: "inspectionDescriptions/**/*")
120     include(name: "intentionDescriptions/**/*")
121     include(name: "tips/**/*")
122     include(name: "search/**/*")
123   }
124
125   ant.patternset(id: "resources.excluded") {
126     exclude(name: "**/*.properties")
127     exclude(name: "fileTemplates/**/*")
128     exclude(name: "fileTemplates")
129     exclude(name: "inspectionDescriptions/**/*")
130     exclude(name: "inspectionDescriptions")
131     exclude(name: "intentionDescriptions/**/*")
132     exclude(name: "intentionDescriptions")
133     exclude(name: "tips/**/*")
134     exclude(name: "tips")
135     exclude(name: "courses")
136     exclude(name: "courses/*")
137   }
138
139   zipSources(home, paths.artifacts)
140
141   def usedJars = buildModulesAndCollectUsedJars(modules(), approvedJars(), ["/ant/"])
142
143   layoutEducational("${paths.sandbox}/classes/production", usedJars)
144
145   def extraArgs = ["build.code": "pycharm${buildName}", "build.number": "PE-$buildNumber", "artifacts.path": "${paths.artifacts}"]
146   def sitFileName = "pycharm${buildName}"
147   ant.copy(file: "${paths.artifacts}/pycharm${buildName}.mac.zip", tofile: "${paths.artifacts}/${sitFileName}-no-jdk.sit")
148
149   signMacZip("pycharm", extraArgs + ["sitFileName": "${sitFileName}-no-jdk"])
150   notifyArtifactBuilt("${paths.artifacts}/${sitFileName}-no-jdk.sit")
151   buildDmg("pycharm", "${pythonEduHome}/build/DMG_background.png", extraArgs + ["sitFileName": "${sitFileName}-no-jdk"])
152
153   if (p("jdk.mac") != "false" && new File(macCustomJDK).exists()) {
154     ant.copy(file: "${paths.artifacts}/pycharm${buildName}.mac.zip", tofile: "${paths.artifacts}/${sitFileName}.sit")
155     signMacZip("pycharm", extraArgs + ["sitFileName": "${sitFileName}", "jdk_archive_name": macCustomJDK])
156     buildDmg("pycharm", "${pythonEduHome}/build/DMG_background.png", extraArgs + ["sitFileName": "${sitFileName}"])
157   }
158
159   ant.delete(file: "${paths.artifacts}/pycharm${buildName}.mac.zip")
160 }
161
162 public layoutEducational(String classesPath, Set usedJars) {
163   setProperty("pluginFilter", new File("$pythonEduHome/build/plugin-list.txt").readLines())
164
165   if (usedJars == null) {
166     usedJars = collectUsedJars(modules(), approvedJars(), ["/ant/"], null)
167   }
168
169   def paths = new Paths(home)
170   buildSearchableOptions("${projectBuilder.moduleOutput(findModule("platform-resources"))}/search", [], {
171     projectBuilder.moduleRuntimeClasspath(findModule("main_pycharm_edu"), false).each {
172       ant.pathelement(location: it)
173     }
174   }, "-Didea.platform.prefix=PyCharmEdu")
175
176   def appInfo = appInfoFile()
177   if (!dryRun) {
178     wireBuildDate("PE-${buildNumber}", appInfo)
179   }
180
181   Map args = [
182     buildNumber: "PE-${buildNumber}",
183     system_selector: system_selector,
184     ide_jvm_args: "-Didea.platform.prefix=PyCharmEdu"]
185
186   LayoutInfo layoutInfo = layoutFull(args, paths.distAll, usedJars)
187   generateLicensesTable("$paths.artifacts/third-party-libraries.txt", layoutInfo.usedModules);
188
189   layoutWin(args, paths.distWin)
190   layoutUnix(args, paths.distUnix)
191   layoutMac(args, paths.distMac)
192
193   ant.echo(message: "PE-${buildNumber}", file: "${paths.distAll}/build.txt")
194
195   def launcher = "${paths.distWin}/bin/pycharm.exe"
196   List resourcePaths = ["$ch/community-resources/src",
197     "$ch/platform/icons/src",
198     "$pythonCommunityHome/python-community-ide-resources/resources",
199     "$pythonCommunityHome/resources",
200     "$pythonEduHome/resources"]
201   buildWinLauncher(ch, "$ch/bin/WinLauncher/WinLauncher.exe", launcher,
202                    appInfo, "$pythonEduHome/build/pycharm_edu_launcher.properties", system_selector, resourcePaths)
203   signExecutableFiles("${paths.distWin}/bin")
204
205   buildWinZip("${paths.artifacts}/pycharm${buildName}.zip", [paths.distAll, paths.distWin, "${paths.sandbox}/jdk.win"])
206
207   //EDU installation with a custom page dialog
208   ant.copy(file: "$ch/python/educational-python/build/desktop.ini", tofile: "${paths.sandbox}/nsiconf/desktop.ini", overwrite: "true")
209   ant.copy(file: "$ch/python/educational-python/build/customInstallActions.nsi", tofile: "${paths.sandbox}/nsiconf/customInstallActions.nsi", overwrite: "true")
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("student")
228     layouts.layoutPlugin("student-python") {
229       dir("courses") {
230         fileset(dir: "$pythonEduHome/student-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/educational-python/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("pycharm-pydev.jar") {
279         module("python-pydev")
280       }
281
282       jar("bootstrap.jar") { module("bootstrap") }
283       jar("resources.jar") {
284         module("platform-resources")
285         module("colorSchemes")
286       }
287
288       jar("forms_rt.jar") {
289         module("forms_rt")
290       }
291
292       //noinspection GroovyAssignabilityCheck
293       jar([name: "resources_en.jar", duplicate: "preserve"]) {
294         // custom resources should go first
295         module("python-community-ide-resources") {
296           ant.patternset {
297             include(name: "**/tips/**")
298           }
299         }
300         module("platform-resources-en") {
301           ant.patternset {
302             exclude(name: "tips/images/switcher.png")
303             exclude(name: "tips/images/navigateToFilePath.gif")
304           }
305         }
306       }
307
308       jar("icons.jar") { module("icons") }
309       jar("boot.jar") { module("boot") }
310
311       usedJars.each {
312         fileset(file: it)
313       }
314
315       fileset(dir: "$ch/build/kotlinc/lib") {
316         include(name: "kotlin-runtime.jar")
317         include(name: "kotlin-reflect.jar")
318       }
319
320       dir("libpty") {
321         fileset(dir: "$ch/lib/libpty") {
322           exclude(name: "*.txt")
323         }
324       }
325
326       dir("ext") {
327         fileset(dir: "$ch/lib") {
328           include(name: "cglib*.jar")
329         }
330       }
331
332       dir("src") {
333         fileset(dir: "$ch/lib/src") {
334           include(name: "trove4j_changes.txt")
335           include(name: "trove4j_src.jar")
336         }
337
338         jar("pycharm-pydev-src.zip") {
339           fileset(dir: "$pythonCommunityHome/pydevSrc")
340         }
341         jar("pycharm-openapi-src.zip") {
342           fileset(dir: "$pythonCommunityHome/openapi/src")
343           fileset(dir: "$pythonCommunityHome/psi-api/src")
344         }
345       }
346     }
347
348     dir("help") {
349       fileset(dir: "$home/python/help") {
350         include(name: "*.pdf")
351       }
352     }
353
354     dir("helpers") {
355       fileset(dir: "$pythonCommunityHome/helpers")
356     }
357
358     dir("license") {
359       fileset(dir: "$ch/license")
360       fileset(dir: "$ch") {
361         include(name: "LICENSE.txt")
362         include(name: "NOTICE.txt")
363       }
364     }
365
366     layoutPlugins(superLayouts)
367
368     dir("bin") {
369       fileset(dir: "$ch/bin") {
370         exclude(name: "appletviewer.policy")
371         include(name: "*.*")
372       }
373     }
374   }
375   patchPropertiesFile(target, args + [appendices: ["$home/build/conf/ideaJNC.properties"]])
376   return result
377 }
378
379 private layoutWin(Map args, String target) {
380   layout(target) {
381     dir("bin") {
382       fileset(dir: "$ch/bin/win") {
383         exclude(name: "breakgen*")
384       }
385     }
386
387     dir("skeletons") {
388       fileset(dir: "$pythonCommunityHome/skeletons") {
389         include(name: "skeletons-win*.zip")
390       }
391     }
392   }
393
394   winScripts(target, ch, "pycharm.bat", args)
395   winVMOptions(target, null, "pycharm.exe")
396
397   ant.copy(file: "$home/python/help/pycharm-eduhelp.jar", todir: "$target/help", failonerror: false)
398 }
399
400 private layoutUnix(Map args, String target) {
401   layout(target) {
402     dir("bin") {
403       fileset(dir: "$ch/bin/linux") {
404         exclude(name: "libbreakgen*")
405       }
406     }
407   }
408
409   ant.copy(file: "$pythonCommunityHome/resources/PyCharmCore128.png", tofile: "$target/bin/pycharm.png")
410
411   unixScripts(target, ch, "pycharm.sh", args)
412   unixVMOptions(target, "pycharm")
413
414   ant.copy(file: "$home/python/help/pycharm-eduhelp.jar", todir: "$target/help", failonerror: false)
415 }
416
417 private layoutMac(Map _args, String target) {
418   layout(target) {
419     dir("bin") {
420       fileset(dir: "$home/bin") {
421         include(name: "*.jnilib")
422       }
423     }
424
425     dir("skeletons") {
426       fileset(dir: "$pythonCommunityHome/skeletons") {
427         include(name: "skeletons-mac*.zip")
428       }
429     }
430   }
431
432   Map args = new HashMap(_args)
433   args.icns = "$pythonCommunityHome/educational-python/resources/PyCharmEdu.icns"
434   args.bundleIdentifier = "com.jetbrains.pycharm"
435   args.platform_prefix = "PyCharmEdu"
436   args.help_id = "PE"
437   args."idea.properties.path" = "${paths.distAll}/bin/idea.properties"
438   args."idea.properties" = ["ide.mac.useNativeClipboard": "false"];
439   args.executable = "pycharm"
440   layoutMacApp(target, ch, args)
441 }