jib-profiles.js revision 2133:cd05b3e4720c
11590Srgrimes/*
21590Srgrimes * Copyright (c) 2015, Oracle and/or its affiliates. All rights reserved.
31590Srgrimes * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
41590Srgrimes *
51590Srgrimes * This code is free software; you can redistribute it and/or modify it
61590Srgrimes * under the terms of the GNU General Public License version 2 only, as
71590Srgrimes * published by the Free Software Foundation.  Oracle designates this
81590Srgrimes * particular file as subject to the "Classpath" exception as provided
91590Srgrimes * by Oracle in the LICENSE file that accompanied this code.
101590Srgrimes *
111590Srgrimes * This code is distributed in the hope that it will be useful, but WITHOUT
121590Srgrimes * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
131590Srgrimes * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
141590Srgrimes * version 2 for more details (a copy is included in the LICENSE file that
151590Srgrimes * accompanied this code).
161590Srgrimes *
171590Srgrimes * You should have received a copy of the GNU General Public License version
181590Srgrimes * 2 along with this work; if not, write to the Free Software Foundation,
191590Srgrimes * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
201590Srgrimes *
211590Srgrimes * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
221590Srgrimes * or visit www.oracle.com if you need additional information or have any
231590Srgrimes * questions.
241590Srgrimes */
251590Srgrimes
261590Srgrimes/*
271590Srgrimes * This file defines build profiles for the JIB tool and others.
281590Srgrimes *
291590Srgrimes * A build profile defines a set of configuration options and external
3087628Sdwmalone * dependencies that we for some reason or other care about specifically.
3187628Sdwmalone * Typically, build profiles are defined for the build configurations we
3287628Sdwmalone * build regularly.
3387628Sdwmalone *
3487628Sdwmalone * Contract against this file from the tools that use it, is to provide
3587628Sdwmalone * a function on the form:
3687249Smarkm *
3787249Smarkm * getJibProfiles(input)
3887249Smarkm *
391590Srgrimes * which returns an object graph describing the profiles and their
401590Srgrimes * dependencies. The name of the function is based on the name of this
411590Srgrimes * file, minus the extension and the '-', camel cased and prefixed with
4290382Sgallatin * 'get'.
431590Srgrimes *
441590Srgrimes *
451590Srgrimes * The parameter 'input' is an object that optionally contains  some data.
4692920Simp * Optionally because a tool may read the configuration for different purposes.
471590Srgrimes * To initially get a list of available profiles, the active profile may not
481590Srgrimes * yet be known for instance.
491590Srgrimes *
501590Srgrimes * Data that may be set on the input object:
51201606Sdwmalone *
521590Srgrimes * input.profile = <name of active profile>
531590Srgrimes *
541590Srgrimes * If the active profile is set, the following data from it must also
551590Srgrimes * be provided:
561590Srgrimes *
571590Srgrimes * input.profile
581590Srgrimes * input.target_os
591590Srgrimes * input.target_cpu
601590Srgrimes * input.build_os
611590Srgrimes * input.build_cpu
621590Srgrimes * input.target_platform
631590Srgrimes * input.build_platform
641590Srgrimes * // The build_osenv_* variables describe the unix layer on Windows systems,
651590Srgrimes * // i.e. Cygwin, which may also be 32 or 64 bit.
661590Srgrimes * input.build_osenv
671590Srgrimes * input.build_osenv_cpu
681590Srgrimes * input.build_osenv_platform
691590Srgrimes *
701590Srgrimes * For more complex nested attributes, there is a method "get":
711590Srgrimes *
721590Srgrimes * input.get("<dependency>", "<attribute>")
731590Srgrimes *
741590Srgrimes * Valid attributes are:
751590Srgrimes * install_path
761590Srgrimes * download_path
771590Srgrimes * download_dir
781590Srgrimes *
791590Srgrimes *
801590Srgrimes * The output data generated by this configuration file has the following
811590Srgrimes * format:
821590Srgrimes *
831590Srgrimes * data: {
841590Srgrimes *   // Identifies the version of this format to the tool reading it
851590Srgrimes *   format_version: "1.0",
861590Srgrimes *
871590Srgrimes *   // Name of base outputdir. JIB assumes the actual output dir is formed
881590Srgrimes *   // by adding the configuration name: <output_basedir>/<config-name>
891590Srgrimes *   output_basedir: "build",
901590Srgrimes *   // Configure argument to use to specify configuration name
911590Srgrimes *   configuration_configure_arg:
921590Srgrimes *   // Make argument to use to specify configuration name
931590Srgrimes *   configuration_make_arg:
941590Srgrimes *
951590Srgrimes *   profiles: {
961590Srgrimes *     <profile-name>: {
971590Srgrimes *       // Name of os the profile is built to run on
981590Srgrimes *       target_os; <string>
991590Srgrimes *       // Name of cpu the profile is built to run on
1001590Srgrimes *       target_cpu; <string>
1011590Srgrimes *       // Combination of target_os and target_cpu for convenience
1021590Srgrimes *       target_platform; <string>
1031590Srgrimes *       // Name of os the profile is built on
1041590Srgrimes *       build_os; <string>
1051590Srgrimes *       // Name of cpu the profile is built on
1061590Srgrimes *       build_cpu; <string>
1071590Srgrimes *       // Combination of build_os and build_cpu for convenience
1081590Srgrimes *       build_platform; <string>
1091590Srgrimes *
1101590Srgrimes *       // List of dependencies needed to build this profile
1111590Srgrimes *       dependencies: <Array of strings>
1121590Srgrimes *
1131590Srgrimes *       // List of configure args to use for this profile
1141590Srgrimes *       configure_args: <Array of strings>
1151590Srgrimes *
1161590Srgrimes *       // List of free form labels describing aspects of this profile
1171590Srgrimes *       labels: <Array of strings>
1181590Srgrimes *     }
1191590Srgrimes *   }
1201590Srgrimes *
1211590Srgrimes *   // Dependencies use a Maven like deployment structure
1221590Srgrimes *   dependencies: {
123166502Srse *     <dependency-name>: {
1241590Srgrimes *       // Organization part of path defining this dependency
1251590Srgrimes *       organization: <string>
12697574Stjr *       // File extension for this dependency
1271590Srgrimes *       ext: <string>
1281590Srgrimes *       // Module part of path for defining this dependency,
1291590Srgrimes *       // defaults to <dependency-name>
1301590Srgrimes *       module: <string>
1311590Srgrimes *       // Revision part of path for defining this dependency
1321590Srgrimes *       revision: <string>
1331590Srgrimes *
1341590Srgrimes *       // List of configure args to add when using this dependency,
1351590Srgrimes *       // defaults to
1361590Srgrimes *       // "--with-<dependency-name>=input.get("<dependency-name", "install_path")"
1371590Srgrimes *       configure_args: <array of strings>
1381590Srgrimes *
139100822Sdwmalone *       // Name of environment variable to set when using this dependency
1401590Srgrimes *       // when running make
1411590Srgrimes *       environment_name: <string>
1421590Srgrimes *       // Value of environment variable to set when using this dependency
1431590Srgrimes *       // when running make
1441590Srgrimes *       environment_value: <string>
1451590Srgrimes *
1461590Srgrimes *       // Value to add to the PATH variable when using this dependency,
1471590Srgrimes *       // applies to both make and configure
1481590Srgrimes *       environment_path: <string>
1491590Srgrimes *     }
1501590Srgrimes *
1511590Srgrimes *     <dependency-name>: {
1521590Srgrimes *       // For certain dependencies where a legacy distribution mechanism is
1531590Srgrimes *       // already in place, the "javare" server layout is also supported
1541590Srgrimes *       // Indicate that an alternate server source and layout should be used
155100822Sdwmalone *       server: "javare"
1561590Srgrimes *
1571590Srgrimes *       // For "javare", a combination of module, revision,
1581590Srgrimes *       // build number (optional), files and checksum file is possible for
1591590Srgrimes *       // artifacts following the standard layout.
1601590Srgrimes *       module: <string>
1611590Srgrimes *       revision: <string>
1621590Srgrimes *       build_number: <string>
1631590Srgrimes *       checksum_file: <string>
1641590Srgrimes *       file: <string>
1651590Srgrimes *
1661590Srgrimes *       // For other files, use checksum path and path instead
1671590Srgrimes *       checksum_path: <string>
1681590Srgrimes *       path: <string>
169 *     }
170 *   }
171 * }
172 */
173
174/**
175 * Main entry to generate the profile configuration
176 *
177 * @param input External data to use for generating the configuration
178 * @returns {{}} Profile configuration
179 */
180var getJibProfiles = function (input) {
181
182    var data = {};
183
184    // Identifies the version of this format to the tool reading it
185    data.format_version = "1.0";
186
187    // Organization is used when uploading/publishing build results
188    data.organization = "com.oracle.jpg.jdk";
189
190    // The base directory for the build output. JIB will assume that the
191    // actual build directory will be <output_basedir>/<configuration>
192    data.output_basedir = "build";
193    // The configure argument to use to specify the name of the configuration
194    data.configuration_configure_arg = "--with-conf-name=";
195    // The make argument to use to specify the name of the configuration
196    data.configuration_make_arg = "CONF_NAME=";
197
198    // Define some common values
199    var common = getJibProfilesCommon(input);
200    // Generate the profiles part of the configuration
201    data.profiles = getJibProfilesProfiles(input, common);
202    // Generate the dependencies part of the configuration
203    data.dependencies = getJibProfilesDependencies(input, common);
204
205    return data;
206};
207
208/**
209 * Generates some common values
210 *
211 * @param input External data to use for generating the configuration
212 * @returns Common values
213 */
214var getJibProfilesCommon = function (input) {
215    var common = {};
216
217    common.dependencies = ["boot_jdk", "gnumake", "jtreg"],
218    common.default_make_targets = ["product-bundles", "test-bundles"],
219    common.default_make_targets_debug = common.default_make_targets;
220    common.default_make_targets_slowdebug = common.default_make_targets;
221    common.configure_args = ["--enable-jtreg-failure-handler"],
222    common.configure_args_32bit = ["--with-target-bits=32"],
223    common.configure_args_debug = ["--enable-debug"],
224    common.configure_args_slowdebug = ["--with-debug-level=slowdebug"],
225    common.organization = "jpg.infra.builddeps"
226
227    return common;
228};
229
230/**
231 * Generates the profiles part of the configuration.
232 *
233 * @param input External data to use for generating the configuration
234 * @param common The common values
235 * @returns {{}} Profiles part of the configuration
236 */
237var getJibProfilesProfiles = function (input, common) {
238    var profiles = {};
239
240    // Main SE profiles
241    var mainProfiles = {
242
243        "linux-x64": {
244            target_os: "linux",
245            target_cpu: "x64",
246            dependencies: concat(common.dependencies, "devkit"),
247            configure_args: concat(common.configure_args, "--with-zlib=system"),
248            default_make_targets: concat(common.default_make_targets, "docs-bundles")
249        },
250
251        "linux-x86": {
252            target_os: "linux",
253            target_cpu: "x86",
254            build_cpu: "x64",
255            dependencies: concat(common.dependencies, "devkit"),
256            configure_args: concat(common.configure_args, common.configure_args_32bit,
257                "--with-jvm-variants=minimal,server", "--with-zlib=system"),
258            default_make_targets: common.default_make_targets
259        },
260
261        "macosx-x64": {
262            target_os: "macosx",
263            target_cpu: "x64",
264            dependencies: concat(common.dependencies, "devkit"),
265            configure_args: concat(common.configure_args, "--with-zlib=system"),
266            default_make_targets: common.default_make_targets
267        },
268
269        "solaris-x64": {
270            target_os: "solaris",
271            target_cpu: "x64",
272            dependencies: concat(common.dependencies, "devkit", "cups"),
273            configure_args: concat(common.configure_args, "--with-zlib=system"),
274            default_make_targets: common.default_make_targets
275        },
276
277        "solaris-sparcv9": {
278            target_os: "solaris",
279            target_cpu: "sparcv9",
280            dependencies: concat(common.dependencies, "devkit", "cups"),
281            configure_args: concat(common.configure_args, "--with-zlib=system"),
282            default_make_targets: common.default_make_targets
283        },
284
285        "windows-x64": {
286            target_os: "windows",
287            target_cpu: "x64",
288            dependencies: concat(common.dependencies, "devkit", "freetype"),
289            configure_args: concat(common.configure_args),
290            default_make_targets: common.default_make_targets
291        },
292
293        "windows-x86": {
294            target_os: "windows",
295            target_cpu: "x86",
296            build_cpu: "x64",
297            dependencies: concat(common.dependencies, "devkit", "freetype"),
298            configure_args: concat(common.configure_args, common.configure_args_32bit),
299            default_make_targets: common.default_make_targets
300        }
301    };
302    profiles = concatObjects(profiles, mainProfiles);
303    // Generate debug versions of all the main profiles
304    profiles = concatObjects(profiles, generateDebugProfiles(common, mainProfiles));
305    // Generate slowdebug versions of all the main profiles
306    profiles = concatObjects(profiles, generateSlowdebugProfiles(common, mainProfiles));
307
308    // Generate open only profiles for all the main profiles for JPRT and reference
309    // implementation builds.
310    var openOnlyProfiles = generateOpenOnlyProfiles(common, mainProfiles);
311    // The open only profiles on linux are used for reference builds and should
312    // produce the compact profile images by default. This adds "profiles" as an
313    // extra default target.
314    var openOnlyProfilesExtra = {
315        "linux-x64-open": {
316            default_make_targets: "profiles"
317        },
318
319        "linux-x86-open": {
320            default_make_targets: "profiles",
321            configure_args: "--with-jvm-variants=client,server"
322        }
323    };
324    var openOnlyProfiles = concatObjects(openOnlyProfiles, openOnlyProfilesExtra);
325
326    profiles = concatObjects(profiles, openOnlyProfiles);
327    // Generate debug profiles for the open jprt profiles
328    profiles = concatObjects(profiles, generateDebugProfiles(common, openOnlyProfiles));
329
330    // Profiles used to run tests. Used in JPRT.
331    var testOnlyProfiles = {
332
333        "run-test": {
334            target_os: input.build_os,
335            target_cpu: input.build_cpu,
336            dependencies: [ "jtreg", "gnumake" ],
337            labels: "test"
338        }
339    };
340    profiles = concatObjects(profiles, testOnlyProfiles);
341
342    // Generate the missing platform attributes
343    profiles = generatePlatformAttributes(profiles);
344    profiles = generateDefaultMakeTargetsConfigureArg(common, profiles);
345    return profiles;
346};
347
348/**
349 * Generate the dependencies part of the configuration
350 *
351 * @param input External data to use for generating the configuration
352 * @param common The common values
353 * @returns {{}} Dependencies part of configuration
354 */
355var getJibProfilesDependencies = function (input, common) {
356
357    var boot_jdk_platform = input.build_os + "-"
358        + (input.build_cpu == "x86" ? "i586" : input.build_cpu);
359
360    var devkit_platform_revisions = {
361        linux_x64: "gcc4.9.2-OEL6.4+1.0",
362        macosx_x64: "Xcode6.3-MacOSX10.9+1.0",
363        solaris_x64: "SS12u4-Solaris11u1+1.0",
364        solaris_sparcv9: "SS12u4-Solaris11u1+1.0",
365        windows_x64: "VS2013SP4+1.0"
366    };
367
368    var devkit_platform = (input.target_cpu == "x86"
369        ? input.target_os + "_x64"
370        : input.target_platform);
371
372    var dependencies = {
373
374        boot_jdk: {
375            server: "javare",
376            module: "jdk",
377            revision: "8",
378            checksum_file: boot_jdk_platform + "/MD5_VALUES",
379            file: boot_jdk_platform + "/jdk-8-" + boot_jdk_platform + ".tar.gz",
380            configure_args: (input.build_os == "macosx"
381                ? "--with-boot-jdk=" + input.get("boot_jdk", "install_path") + "/jdk1.8.0.jdk/Contents/Home"
382                : "--with-boot-jdk=" + input.get("boot_jdk", "install_path") + "/jdk1.8.0")
383        },
384
385        devkit: {
386            organization: common.organization,
387            ext: "tar.gz",
388            module: "devkit-" + devkit_platform,
389            revision: devkit_platform_revisions[devkit_platform]
390        },
391
392        build_devkit: {
393            organization: common.organization,
394            ext: "tar.gz",
395            module: "devkit-" + input.build_platform,
396            revision: devkit_platform_revisions[input.build_platform]
397        },
398
399        cups: {
400            organization: common.organization,
401            ext: "tar.gz",
402            revision: "1.0118+1.0"
403        },
404
405        jtreg: {
406            server: "javare",
407            revision: "4.2",
408            build_number: "b02",
409            checksum_file: "MD5_VALUES",
410            file: "jtreg_bin-4.2.zip",
411            environment_name: "JT_HOME"
412        },
413
414        gnumake: {
415            organization: common.organization,
416            ext: "tar.gz",
417            revision: "4.0+1.0",
418
419            module: (input.build_os == "windows"
420                ? "gnumake-" + input.build_osenv_platform
421                : "gnumake-" + input.build_platform),
422
423            configure_args: (input.build_os == "windows"
424                ? "MAKE=" + input.get("gnumake", "install_path") + "/cygwin/bin/make"
425                : "MAKE=" + input.get("gnumake", "install_path") + "/bin/make"),
426
427            environment_path: (input.build_os == "windows"
428                ? input.get("gnumake", "install_path") + "/cygwin/bin"
429                : input.get("gnumake", "install_path") + "/bin")
430        },
431
432        freetype: {
433            organization: common.organization,
434            ext: "tar.gz",
435            revision: "2.3.4+1.0",
436            module: "freetype-" + input.target_platform
437        }
438    };
439
440    return dependencies;
441};
442
443/**
444 * Generate the missing platform attributes for profiles
445 *
446 * @param profiles Profiles map to generate attributes on
447 * @returns {{}} New profiles map with platform attributes fully filled in
448 */
449var generatePlatformAttributes = function (profiles) {
450    var ret = concatObjects(profiles, {});
451    for (var profile in profiles) {
452        if (ret[profile].build_os == null) {
453            ret[profile].build_os = ret[profile].target_os;
454        }
455        if (ret[profile].build_cpu == null) {
456            ret[profile].build_cpu = ret[profile].target_cpu;
457        }
458        ret[profile].target_platform = ret[profile].target_os + "_" + ret[profile].target_cpu;
459        ret[profile].build_platform = ret[profile].build_os + "_" + ret[profile].build_cpu;
460    }
461    return ret;
462};
463
464/**
465 * Generates debug versions of profiles. Clones the given profiles and adds
466 * debug metadata.
467 *
468 * @param common Common values
469 * @param profiles Profiles map to generate debug profiles for
470 * @returns {{}} New map of profiles containing debug profiles
471 */
472var generateDebugProfiles = function (common, profiles) {
473    var newProfiles = {};
474    for (var profile in profiles) {
475        var debugProfile = profile + "-debug";
476        newProfiles[debugProfile] = clone(profiles[profile]);
477        newProfiles[debugProfile].debug_level = "fastdebug";
478        newProfiles[debugProfile].default_make_targets
479            = common.default_make_targets_debug;
480        newProfiles[debugProfile].labels
481            = concat(newProfiles[debugProfile].labels || [], "debug"),
482            newProfiles[debugProfile].configure_args
483                = concat(newProfiles[debugProfile].configure_args,
484                common.configure_args_debug);
485    }
486    return newProfiles;
487};
488
489/**
490 * Generates slowdebug versions of profiles. Clones the given profiles and adds
491 * debug metadata.
492 *
493 * @param common Common values
494 * @param profiles Profiles map to generate debug profiles for
495 * @returns {{}} New map of profiles containing debug profiles
496 */
497var generateSlowdebugProfiles = function (common, profiles) {
498    var newProfiles = {};
499    for (var profile in profiles) {
500        var debugProfile = profile + "-slowdebug";
501        newProfiles[debugProfile] = clone(profiles[profile]);
502        newProfiles[debugProfile].debug_level = "slowdebug";
503        newProfiles[debugProfile].default_make_targets
504            = common.default_make_targets_slowdebug;
505        newProfiles[debugProfile].labels
506            = concat(newProfiles[debugProfile].labels || [], "slowdebug"),
507            newProfiles[debugProfile].configure_args
508                = concat(newProfiles[debugProfile].configure_args,
509                common.configure_args_slowdebug);
510    }
511    return newProfiles;
512};
513
514/**
515 * Generates open only versions of profiles. Clones the given profiles and adds
516 * open metadata.
517 *
518 * @param common Common values
519 * @param profiles Profiles map to generate open only profiles for
520 * @returns {{}} New map of profiles containing open only profiles
521 */
522var generateOpenOnlyProfiles = function (common, profiles) {
523    var newProfiles = {};
524    for (var profile in profiles) {
525        var openProfile = profile + "-open";
526        newProfiles[openProfile] = clone(profiles[profile]);
527        newProfiles[openProfile].labels
528            = concat(newProfiles[openProfile].labels || [], "open"),
529            newProfiles[openProfile].configure_args
530                = concat(newProfiles[openProfile].configure_args,
531                "--enable-openjdk-only");
532    }
533    return newProfiles;
534};
535
536/**
537 * The default_make_targets attribute on a profile is not a real Jib attribute.
538 * This function rewrites that attribute into the corresponding configure arg.
539 * Calling this function multiple times on the same profiles object is safe.
540 *
541 * @param common Common values
542 * @param profiles Profiles map to rewrite profiles for
543 * @returns {{}} New map of profiles with the make targets converted
544 */
545var generateDefaultMakeTargetsConfigureArg = function (common, profiles) {
546    var ret = concatObjects(profiles, {});
547    for (var profile in ret) {
548        if (ret[profile]["default_make_targets"] != null) {
549            var targetsString = concat(ret[profile].default_make_targets).join(" ");
550            // Iterate over all configure args and see if --with-default-make-target
551            // is already there and change it, otherwise add it.
552            var found = false;
553            for (var arg in ret[profile].configure_args) {
554                if (arg.startsWith("--with-default-make-target")) {
555                    found = true;
556                    arg.replace(/=.*/, "=" + targetsString);
557                }
558            }
559            if (!found) {
560                ret[profile].configure_args = concat(
561                    ret[profile].configure_args,
562                    "--with-default-make-target=" + targetsString);
563            }
564        }
565    }
566    return ret;
567}
568
569/**
570 * Deep clones an object tree.
571 *
572 * @param o Object to clone
573 * @returns {{}} Clone of o
574 */
575var clone = function (o) {
576    return JSON.parse(JSON.stringify(o));
577};
578
579/**
580 * Concatenates all arguments into a new array
581 *
582 * @returns {Array.<T>} New array containing all arguments
583 */
584var concat = function () {
585    return Array.prototype.concat.apply([], arguments);
586};
587
588/**
589 * Copies all elements in an array into a new array but replacing all
590 * occurrences of original with replacement.
591 *
592 * @param original Element to look for
593 * @param replacement Element to replace with
594 * @param a Array to copy
595 * @returns {Array} New array with all occurrences of original replaced
596 *                  with replacement
597 */
598var replace = function (original, replacement, a) {
599    var newA = [];
600    for (var i in a) {
601        if (original == a[i]) {
602            newA.push(replacement);
603        } else {
604            newA.push(a[i]);
605        }
606    }
607    return newA;
608};
609
610/**
611 * Deep concatenation of two objects. For each node encountered, merge
612 * the contents with the corresponding node in the other object tree,
613 * treating all strings as array elements.
614 *
615 * @param o1 Object to concatenate
616 * @param o2 Object to concatenate
617 * @returns {{}} New object tree containing the concatenation of o1 and o2
618 */
619var concatObjects = function (o1, o2) {
620    var ret = {};
621    for (var a in o1) {
622        if (o2[a] == null) {
623            ret[a] = o1[a];
624        }
625    }
626    for (var a in o2) {
627        if (o1[a] == null) {
628            ret[a] = o2[a];
629        } else {
630            if (typeof o1[a] == 'string') {
631                ret[a] = [o1[a]].concat(o2[a]);
632            } else if (Array.isArray(o1[a])) {
633                ret[a] = o1[a].concat(o2[a]);
634            } else if (typeof o1[a] == 'object') {
635                ret[a] = concatObjects(o1[a], o2[a]);
636            }
637        }
638    }
639    return ret;
640};
641