Skip to content

Commit

Permalink
fix(builtin): properly parse status file value containing spaces (#2615)
Browse files Browse the repository at this point in the history
Based on Bazel's documentation, values provided through the workspace_status_command can contain
whitespace on the same line the key is defined on:

> The key names can be anything but they may only use upper case letters and underscores. The
> first space after the key name separates it from the value. The value is the rest of the line
> (including additional whitespaces).

The `parseStatusFile` utility function is updated to rely on a regex for performing this parsing to
match the described behavior.
  • Loading branch information
josephperrott committed Apr 19, 2021
1 parent 2ded6f9 commit 406dcb5
Show file tree
Hide file tree
Showing 5 changed files with 164 additions and 53 deletions.
46 changes: 29 additions & 17 deletions internal/pkg_npm/packager.js
Expand Up @@ -61,21 +61,32 @@ function unquoteArgs(s) {
}

/**
* The status files are expected to look like
* BUILD_SCM_HASH 83c699db39cfd74526cdf9bebb75aa6f122908bb
* BUILD_SCM_LOCAL_CHANGES true
* STABLE_BUILD_SCM_VERSION 6.0.0-beta.6+12.sha-83c699d.with-local-changes
* BUILD_TIMESTAMP 1520021990506
*
* @param {string} p the path to the status file
* @returns a two-dimensional array of key/value pairs
*/
* The status files are expected to look like
* BUILD_SCM_HASH 83c699db39cfd74526cdf9bebb75aa6f122908bb
* BUILD_SCM_LOCAL_CHANGES true
* STABLE_BUILD_SCM_VERSION 6.0.0-beta.6+12.sha-83c699d.with-local-changes
* BUILD_TIMESTAMP 1520021990506
*
* Parsing regex is created based on Bazel's documentation describing the status file schema:
* The key names can be anything but they may only use upper case letters and underscores. The
* first space after the key name separates it from the value. The value is the rest of the line
* (including additional whitespaces).
*
* @param {string} p the path to the status file
* @returns a two-dimensional array of key/value pairs
*/
function parseStatusFile(p) {
if (!p) return [];
return fs.readFileSync(p, {encoding: 'utf-8'})
.split('\n')
.filter(t => !!t)
.map(t => t.split(' '));
const results = {};
const statusFile = fs.readFileSync(p, {encoding: 'utf-8'});
for (const match of `\n${statusFile}`.matchAll(/^([A-Z_]+) (.*)/gm)) {
// Lines which go unmatched define an index value of `0` and should be skipped.
if (match.index === 0) {
continue;
}
results[match[1]] = match[2];
}
return results;
}

function main(args) {
Expand All @@ -95,15 +106,16 @@ function main(args) {
// Replace statuses last so that earlier substitutions can add
// status-related placeholders
if (volatileFile || infoFile) {
const statusEntries = parseStatusFile(volatileFile)
statusEntries.push(...parseStatusFile(infoFile))
const statuses = {
...parseStatusFile(volatileFile),
...parseStatusFile(infoFile),
};
// Looks like {'BUILD_SCM_VERSION': 'v1.2.3'}
const statuses = new Map(statusEntries)
for (let idx = 0; idx < substitutions.length; idx++) {
const match = substitutions[idx][1].match(/\{(.*)\}/);
if (!match) continue;
const statusKey = match[1];
let statusValue = statuses.get(statusKey);
let statusValue = statuses[statusKey];
if (statusValue) {
// npm versions must be numeric, so if the VCS tag starts with leading 'v', strip it
// See https://github.com/bazelbuild/rules_nodejs/pull/1591
Expand Down
38 changes: 28 additions & 10 deletions internal/pkg_web/assembler.js
Expand Up @@ -34,15 +34,33 @@ function unquoteArgs(s) {
return s.replace(/^'(.*)'$/, '$1');
}

function getBazelStatusMappings(statusFilePath) {
if (!statusFilePath) return {};
const stampFileLines = fs.readFileSync(statusFilePath, {encoding: 'utf-8'}).trim().split('\n');
const stampMap = {};
for (const line of stampFileLines) {
const [key, value] = line.split(' ');
stampMap[key] = value;
/**
* The status files are expected to look like
* BUILD_SCM_HASH 83c699db39cfd74526cdf9bebb75aa6f122908bb
* BUILD_SCM_LOCAL_CHANGES true
* STABLE_BUILD_SCM_VERSION 6.0.0-beta.6+12.sha-83c699d.with-local-changes
* BUILD_TIMESTAMP 1520021990506
*
* Parsing regex is created based on Bazel's documentation describing the status file schema:
* The key names can be anything but they may only use upper case letters and underscores. The
* first space after the key name separates it from the value. The value is the rest of the line
* (including additional whitespaces).
*
* @param {string} p the path to the status file
* @returns a two-dimensional array of key/value pairs
*/
function parseStatusFile(p) {
if (!p) return [];
const results = {};
const statusFile = fs.readFileSync(p, {encoding: 'utf-8'});
for (const match of `\n${statusFile}`.matchAll(/^([A-Z_]+) (.*)/gm)) {
// Lines which go unmatched define an index value of `0` and should be skipped.
if (match.index === 0) {
continue;
}
results[match[1]] = match[2];
}
return stampMap;
return results;
}

function normalizeSubstitutions(substitutionsArg, stampMap) {
Expand Down Expand Up @@ -74,8 +92,8 @@ function main(params) {
const rawSubstitutions = params.shift().replace(/^'(.*)'$/, '$1');

const stampMap = {
...getBazelStatusMappings(volatileFilePath),
...getBazelStatusMappings(stableFilePath),
...parseStatusFile(volatileFilePath),
...parseStatusFile(stableFilePath),
};

const normalizedSubstitutions = normalizeSubstitutions(rawSubstitutions, stampMap)
Expand Down
42 changes: 35 additions & 7 deletions packages/rollup/install.md
Expand Up @@ -99,15 +99,43 @@ To use these files, you write JS code in your `rollup.config.js` to read from th
Each line is a space-separated key/value pair.

```javascript
/**
* The status files are expected to look like
* BUILD_SCM_HASH 83c699db39cfd74526cdf9bebb75aa6f122908bb
* BUILD_SCM_LOCAL_CHANGES true
* STABLE_BUILD_SCM_VERSION 6.0.0-beta.6+12.sha-83c699d.with-local-changes
* BUILD_TIMESTAMP 1520021990506
*
* Parsing regex is created based on Bazel's documentation describing the status file schema:
* The key names can be anything but they may only use upper case letters and underscores. The
* first space after the key name separates it from the value. The value is the rest of the line
* (including additional whitespaces).
*
* @param {string} p the path to the status file
* @returns a two-dimensional array of key/value pairs
*/
function parseStatusFile(p) {
if (!p) return [];
const results = {};
const statusFile = require('fs').readFileSync(p, {encoding: 'utf-8'});
for (const match of `\n${statusFile}`.matchAll(/^([A-Z_]+) (.*)/gm)) {
// Lines which go unmatched define an index value of `0` and should be skipped.
if (match.index === 0) {
continue;
}
results[match[1]] = match[2];
}
return results;
}

const statuses = parseStatusFile(bazel_version_file);
// Parse the stamp file produced by Bazel from the version control system
let version = '<unknown>';
if (bazel_info_file) {
const versionTag = require('fs')
.readFileSync(bazel_info_file, {encoding: 'utf-8'})
.split('\n')
.find(s => s.startsWith('STABLE_GIT_COMMIT'));
if (versionTag) {
version = 'v' + versionTag.split(' ')[1].trim();
// Don't assume BUILD_SCM_VERSION exists
if (statuses['BUILD_SCM_VERSION']) {
version = 'v' + statuses['BUILD_SCM_VERSION'];
if (DEBUG) {
version += '_debug';
}
}
```
Expand Down
44 changes: 36 additions & 8 deletions packages/rollup/test/integration/rollup.config.js
Expand Up @@ -2,16 +2,44 @@ import commonjs from '@rollup/plugin-commonjs';
import json from '@rollup/plugin-json';
import nodeResolve from '@rollup/plugin-node-resolve';

/**
* The status files are expected to look like
* BUILD_SCM_HASH 83c699db39cfd74526cdf9bebb75aa6f122908bb
* BUILD_SCM_LOCAL_CHANGES true
* STABLE_BUILD_SCM_VERSION 6.0.0-beta.6+12.sha-83c699d.with-local-changes
* BUILD_TIMESTAMP 1520021990506
*
* Parsing regex is created based on Bazel's documentation describing the status file schema:
* The key names can be anything but they may only use upper case letters and underscores. The
* first space after the key name separates it from the value. The value is the rest of the line
* (including additional whitespaces).
*
* @param {string} p the path to the status file
* @returns a two-dimensional array of key/value pairs
*/
function parseStatusFile(p) {
if (!p) return [];
const results = {};
const statusFile = require('fs').readFileSync(p, {encoding: 'utf-8'});
for (const match of `\n${statusFile}`.matchAll(/^([A-Z_]+) (.*)/gm)) {
// Lines which go unmatched define an index value of `0` and should be skipped.
if (match.index === 0) {
continue;
}
results[match[1]] = match[2];
}
return results;
}

// Parse the stamp file produced by Bazel from the version control system
let version = '<unknown>';
if (bazel_version_file) {
const versionTag = require('fs')
.readFileSync(bazel_version_file, {encoding: 'utf-8'})
.split('\n')
.find(s => s.startsWith('BUILD_SCM_VERSION'));
// Don't assume BUILD_SCM_VERSION exists
if (versionTag) {
version = 'v' + versionTag.split(' ')[1].trim();

const statuses = parseStatusFile(bazel_version_file);
// Don't assume BUILD_SCM_VERSION exists
if (statuses['BUILD_SCM_VERSION']) {
version = 'v' + statuses['BUILD_SCM_VERSION'];
if (DEBUG) {
version += '_debug';
}
}

Expand Down
47 changes: 36 additions & 11 deletions packages/rollup/test/version_stamp/rollup.config.js
@@ -1,18 +1,43 @@
/**
* The status files are expected to look like
* BUILD_SCM_HASH 83c699db39cfd74526cdf9bebb75aa6f122908bb
* BUILD_SCM_LOCAL_CHANGES true
* STABLE_BUILD_SCM_VERSION 6.0.0-beta.6+12.sha-83c699d.with-local-changes
* BUILD_TIMESTAMP 1520021990506
*
* Parsing regex is created based on Bazel's documentation describing the status file schema:
* The key names can be anything but they may only use upper case letters and underscores. The
* first space after the key name separates it from the value. The value is the rest of the line
* (including additional whitespaces).
*
* @param {string} p the path to the status file
* @returns a two-dimensional array of key/value pairs
*/
function parseStatusFile(p) {
if (!p) return [];
const results = {};
const statusFile = require('fs').readFileSync(p, {encoding: 'utf-8'});
for (const match of `\n${statusFile}`.matchAll(/^([A-Z_]+) (.*)/gm)) {
// Lines which go unmatched define an index value of `0` and should be skipped.
if (match.index === 0) {
continue;
}
results[match[1]] = match[2];
}
return results;
}

const DEBUG = process.env['COMPILATION_MODE'] === 'dbg';

// Parse the stamp file produced by Bazel from the version control system
let version = '<unknown>';
if (bazel_version_file) {
const versionTag = require('fs')
.readFileSync(bazel_version_file, {encoding: 'utf-8'})
.split('\n')
.find(s => s.startsWith('BUILD_SCM_VERSION'));
// Don't assume BUILD_SCM_VERSION exists
if (versionTag) {
version = 'v' + versionTag.split(' ')[1].trim();
if (DEBUG) {
version += '_debug';
}

const statuses = parseStatusFile(bazel_version_file);
// Don't assume BUILD_SCM_VERSION exists
if (statuses['BUILD_SCM_VERSION']) {
version = 'v' + statuses['BUILD_SCM_VERSION'];
if (DEBUG) {
version += '_debug';
}
}

Expand Down

0 comments on commit 406dcb5

Please sign in to comment.