// Licensed to the Software Freedom Conservancy (SFC) under one
// or more contributor license agreements. See the NOTICE file
// distributed with this work for additional information
// regarding copyright ownership. The SFC licenses this file
// to you under the Apache License, Version 2.0 (the
// "License"); you may not use this file except in compliance
// with the License. You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing,
// software distributed under the License is distributed on an
// "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
// KIND, either express or implied. See the License for the
// specific language governing permissions and limitations
// under the License.
'use strict'
const fs = require('node:fs')
const path = require('node:path')
const { spawn } = require('node:child_process')
const PROJECT_ROOT = path.normalize(path.join(__dirname, '../../../../..'))
const WORKSPACE_FILE = path.join(PROJECT_ROOT, 'WORKSPACE')
function isDevMode() {
return fs.existsSync(WORKSPACE_FILE)
}
function checkIsDevMode() {
if (!isDevMode()) {
throw Error('Cannot execute build; not running in dev mode')
}
}
/**
* Targets that have been previously built.
* @type {!Object}
*/
let builtTargets = {}
/**
* @param {!Array.<string>} targets The targets to build.
* @throws {Error} If not running in dev mode.
* @constructor
*/
const Build = function (targets) {
checkIsDevMode()
this.targets_ = targets
}
/** @private {boolean} */
Build.prototype.cacheResults_ = false
/**
* Configures this build to only execute if it has not previously been
* run during the life of the current process.
* @return {!Build} A self reference.
*/
Build.prototype.onlyOnce = function () {
this.cacheResults_ = true
return this
}
/**
* Executes the build.
* @return {!Promise} A promise that will be resolved when
* the build has completed.
* @throws {Error} If no targets were specified.
*/
Build.prototype.go = function () {
let targets = this.targets_
if (!targets.length) {
throw Error('No targets specified')
}
// Filter out cached results.
if (this.cacheResults_) {
targets = targets.filter(function (target) {
return !Object.prototype.hasOwnProperty.call(builtTargets, target)
})
if (!targets.length) {
return Promise.resolve()
}
}
console.log('\nBuilding', targets.join(' '), '...')
let cmd,
args = targets
if (process.platform === 'win32') {
cmd = 'cmd.exe'
args.unshift('/c', path.join(PROJECT_ROOT, 'go.bat'))
} else {
cmd = path.join(PROJECT_ROOT, 'go')
}
return new Promise((resolve, reject) => {
spawn(cmd, args, {
cwd: PROJECT_ROOT,
env: process.env,
stdio: ['ignore', process.stdout, process.stderr],
}).on('exit', function (code, signal) {
if (code === 0) {
targets.forEach(function (target) {
builtTargets[target] = 1
})
return resolve()
}
let msg = 'Unable to build artifacts'
if (code) {
// May be null.
msg += '; code=' + code
}
if (signal) {
msg += '; signal=' + signal
}
reject(Error(msg))
})
})
}
// PUBLIC API
exports.isDevMode = isDevMode
/**
* Creates a build of the listed targets.
* @param {...string} var_args The targets to build.
* @return {!Build} The new build.
* @throws {Error} If not running in dev mode.
*/
exports.of = function (_) {
let targets = Array.prototype.slice.call(arguments, 0)
return new Build(targets)
}
/**
* @return {string} Absolute path of the project's root directory.
* @throws {Error} If not running in dev mode.
*/
exports.projectRoot = function () {
return PROJECT_ROOT
}