Windows: add build step that generates license.rtf from LICENSE
This commit is contained in:
parent
930fabe43f
commit
2728dcc95b
327
tools/license2rtf.js
Normal file
327
tools/license2rtf.js
Normal file
@ -0,0 +1,327 @@
|
||||
|
||||
var assert = require('assert'),
|
||||
Stream = require('stream'),
|
||||
inherits = require('util').inherits;
|
||||
|
||||
|
||||
/*
|
||||
* This filter consumes a stream of characters and emits one string per line.
|
||||
*/
|
||||
function LineSplitter() {
|
||||
var self = this,
|
||||
buffer = "";
|
||||
|
||||
Stream.call(this);
|
||||
this.writable = true;
|
||||
|
||||
this.write = function(data) {
|
||||
var lines = (buffer + data).split(/\r\n|\n\r|\n|\r/);
|
||||
for (var i = 0; i < lines.length - 1; i++) {
|
||||
self.emit('data', lines[i]);
|
||||
}
|
||||
buffer = lines[lines.length - 1];
|
||||
return true;
|
||||
};
|
||||
|
||||
this.end = function(data) {
|
||||
this.write(data || '');
|
||||
if (buffer) {
|
||||
self.emit('data', buffer);
|
||||
}
|
||||
self.emit('end');
|
||||
};
|
||||
}
|
||||
inherits(LineSplitter, Stream);
|
||||
|
||||
|
||||
/*
|
||||
* This filter consumes lines and emits paragraph objects.
|
||||
*/
|
||||
function ParagraphParser() {
|
||||
var self = this,
|
||||
block_is_license_block = false,
|
||||
block_has_c_style_comment,
|
||||
is_first_line_in_paragraph,
|
||||
paragraph_line_indent,
|
||||
paragraph;
|
||||
|
||||
Stream.call(this);
|
||||
this.writable = true;
|
||||
|
||||
resetBlock(false);
|
||||
|
||||
this.write = function(data) {
|
||||
parseLine(data + '');
|
||||
return true;
|
||||
};
|
||||
|
||||
this.end = function(data) {
|
||||
if (data) {
|
||||
parseLine(data + '');
|
||||
}
|
||||
flushParagraph();
|
||||
self.emit('end');
|
||||
};
|
||||
|
||||
function resetParagraph() {
|
||||
is_first_line_in_paragraph = true;
|
||||
paragraph_line_indent = -1;
|
||||
|
||||
paragraph = {
|
||||
li: '',
|
||||
in_license_block: block_is_license_block,
|
||||
lines: []
|
||||
};
|
||||
}
|
||||
|
||||
function resetBlock(is_license_block) {
|
||||
block_is_license_block = is_license_block;
|
||||
block_has_c_style_comment = false;
|
||||
resetParagraph();
|
||||
}
|
||||
|
||||
function flushParagraph() {
|
||||
if (paragraph.lines.length || paragraph.li) {
|
||||
self.emit('data', paragraph);
|
||||
}
|
||||
resetParagraph();
|
||||
}
|
||||
|
||||
function parseLine(line) {
|
||||
// Strip trailing whitespace
|
||||
line = line.replace(/\s*$/, '');
|
||||
|
||||
// Detect block separator
|
||||
if (/^\s*(=|"){3,}\s*$/.test(line)) {
|
||||
flushParagraph();
|
||||
resetBlock(!block_is_license_block);
|
||||
return;
|
||||
}
|
||||
|
||||
// Strip comments around block
|
||||
if (block_is_license_block) {
|
||||
if (!block_has_c_style_comment)
|
||||
block_has_c_style_comment = /^\s*(\/\*)/.test(line);
|
||||
if (block_has_c_style_comment) {
|
||||
var prev = line;
|
||||
line = line.replace(/^(\s*?)(?:\s?\*\/|\/\*\s|\s\*\s?)/, '$1');
|
||||
if (prev == line)
|
||||
line = line.replace(/^\s{2}/, '');
|
||||
if (/\*\//.test(prev))
|
||||
block_has_c_style_comment = false;
|
||||
} else {
|
||||
// Strip C++ and perl style comments.
|
||||
line = line.replace(/^(\s*)(?:\/\/\s?|#\s?)/, '$1');
|
||||
}
|
||||
}
|
||||
|
||||
// Detect blank line (paragraph separator)
|
||||
if (!/\S/.test(line)) {
|
||||
flushParagraph();
|
||||
return;
|
||||
}
|
||||
|
||||
// Detect separator "lines" within a block. These mark a paragraph break
|
||||
// and are stripped from the output.
|
||||
if (/^\s*[=*\-]{5,}\s*$/.test(line)) {
|
||||
flushParagraph();
|
||||
return;
|
||||
}
|
||||
|
||||
// Find out indentation level and the start of a lied or numbered list;
|
||||
var result = /^(\s*)(\d+\.|\*|-)?\s*/.exec(line);
|
||||
assert.ok(result);
|
||||
// The number of characters that will be stripped from the beginning of
|
||||
// the line.
|
||||
var line_strip_length = result[0].length;
|
||||
// The indentation size that will be used to detect indentation jumps.
|
||||
// Fudge by 1 space.
|
||||
var line_indent = Math.floor(result[0].length / 2) * 2;
|
||||
// The indentation level that will be exported
|
||||
var level = Math.floor(result[1].length / 2);
|
||||
// The list indicator that precedes the actual content, if any.
|
||||
var line_li = result[2];
|
||||
|
||||
// Flush the paragraph when there is a li or an indentation jump
|
||||
if (line_li || (line_indent != paragraph_line_indent &&
|
||||
paragraph_line_indent != -1)) {
|
||||
flushParagraph();
|
||||
paragraph.li = line_li;
|
||||
}
|
||||
|
||||
// Set the paragraph indent that we use to detect indentation jumps. When
|
||||
// we just detected a list indicator, wait
|
||||
// for the next line to arrive before setting this.
|
||||
if (!line_li && paragraph_line_indent != -1) {
|
||||
paragraph_line_indent = line_indent;
|
||||
}
|
||||
|
||||
// Set the output indent level if it has not been set yet.
|
||||
if (paragraph.level === undefined)
|
||||
paragraph.level = level;
|
||||
|
||||
// Strip leading whitespace and li.
|
||||
line = line.slice(line_strip_length);
|
||||
|
||||
if (line)
|
||||
paragraph.lines.push(line);
|
||||
|
||||
is_first_line_in_paragraph = false;
|
||||
}
|
||||
}
|
||||
inherits(ParagraphParser, Stream);
|
||||
|
||||
|
||||
/*
|
||||
* This filter consumes paragraph objects and emits modified paragraph objects.
|
||||
* The lines within the paragraph are unwrapped where appropriate.
|
||||
*/
|
||||
function Unwrapper() {
|
||||
var self = this;
|
||||
|
||||
Stream.call(this);
|
||||
this.writable = true;
|
||||
|
||||
this.write = function(paragraph) {
|
||||
var lines = paragraph.lines,
|
||||
break_after = [],
|
||||
i;
|
||||
|
||||
for (i = 0; i < lines.length - 1; i++) {
|
||||
var line = lines[i];
|
||||
|
||||
// When a line is really short, the line was probably kept separate for a
|
||||
// reason.
|
||||
if (line.length < 50) {
|
||||
// If the first word on the next line really didn't fit after the line,
|
||||
// it probably was just ordinary wrapping after all.
|
||||
var next_first_word_length = lines[i + 1].replace(/\s.*$/, '').length;
|
||||
if (line.length + next_first_word_length < 60) {
|
||||
break_after[i] = true;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
for (i = 0; i < lines.length - 1; ) {
|
||||
if (!break_after[i]) {
|
||||
lines[i] += ' ' + lines.splice(i + 1, 1)[0];
|
||||
} else {
|
||||
i++;
|
||||
}
|
||||
}
|
||||
|
||||
self.emit('data', paragraph);
|
||||
};
|
||||
|
||||
this.end = function(data) {
|
||||
if (data)
|
||||
self.write(data);
|
||||
self.emit('end');
|
||||
};
|
||||
}
|
||||
inherits(Unwrapper, Stream);
|
||||
|
||||
|
||||
/*
|
||||
* This filter generates an rtf document from a stream of paragraph objects.
|
||||
*/
|
||||
function RtfGenerator() {
|
||||
var self = this,
|
||||
did_write_anything = false;
|
||||
|
||||
Stream.call(this);
|
||||
this.writable = true;
|
||||
|
||||
this.write = function(paragraph) {
|
||||
if (!did_write_anything) {
|
||||
emitHeader();
|
||||
did_write_anything = true;
|
||||
}
|
||||
|
||||
var li = paragraph.li,
|
||||
level = paragraph.level + (li ? 1 : 0),
|
||||
lic = paragraph.in_license_block;
|
||||
|
||||
var rtf = "\\pard";
|
||||
rtf += '\\sa150\\sl300\\slmult1';
|
||||
if (level > 0)
|
||||
rtf += '\\li' + (level * 240);
|
||||
if (li) {
|
||||
rtf += '\\tx' + (level) * 240;
|
||||
rtf += '\\fi-240';
|
||||
}
|
||||
if (lic)
|
||||
rtf += '\\ri240';
|
||||
if (!lic)
|
||||
rtf += '\\b';
|
||||
if (li)
|
||||
rtf += ' ' + li + '\\tab';
|
||||
rtf += ' ';
|
||||
rtf += paragraph.lines.map(rtfEscape).join('\\line ');
|
||||
if (!lic)
|
||||
rtf += '\\b0';
|
||||
rtf += '\\par\n';
|
||||
|
||||
self.emit('data', rtf);
|
||||
};
|
||||
|
||||
this.end = function(data) {
|
||||
if (data)
|
||||
self.write(data);
|
||||
if (did_write_anything)
|
||||
emitFooter();
|
||||
self.emit('end');
|
||||
};
|
||||
|
||||
function toHex(number, length) {
|
||||
var hex = (~~number).toString(16);
|
||||
while (hex.length < length)
|
||||
hex = '0' + hex;
|
||||
return hex;
|
||||
}
|
||||
|
||||
function rtfEscape(string) {
|
||||
return string
|
||||
.replace(/[\\\{\}]/g, function(m) {
|
||||
return '\\' + m;
|
||||
})
|
||||
.replace(/\t/g, function() {
|
||||
return '\\tab ';
|
||||
})
|
||||
.replace(/[\x00-\x1f\x7f-\xff]/g, function(m) {
|
||||
return '\\\'' + toHex(m.charCodeAt(0), 2);
|
||||
})
|
||||
.replace(/\ufeff/g, '')
|
||||
.replace(/[\u0100-\uffff]/g, function(m) {
|
||||
return '\\u' + toHex(m.charCodeAt(0), 4) + '?';
|
||||
});
|
||||
}
|
||||
|
||||
function emitHeader() {
|
||||
self.emit('data', '{\\rtf1\\ansi\\ansicpg1252\\uc1\\deff0\\deflang1033' +
|
||||
'{\\fonttbl{\\f0\\fswiss\\fcharset0 Tahoma;}}\\fs20\n' +
|
||||
'{\\*\\generator txt2rtf 0.0.1;}\n');
|
||||
}
|
||||
|
||||
function emitFooter() {
|
||||
self.emit('data', '}');
|
||||
}
|
||||
}
|
||||
inherits(RtfGenerator, Stream);
|
||||
|
||||
|
||||
var stdin = process.stdin,
|
||||
stdout = process.stdout,
|
||||
line_splitter = new LineSplitter(),
|
||||
paragraph_parser = new ParagraphParser(),
|
||||
unwrapper = new Unwrapper(),
|
||||
rtf_generator = new RtfGenerator();
|
||||
|
||||
stdin.setEncoding('utf-8');
|
||||
stdin.resume();
|
||||
|
||||
stdin.pipe(line_splitter);
|
||||
line_splitter.pipe(paragraph_parser);
|
||||
paragraph_parser.pipe(unwrapper);
|
||||
unwrapper.pipe(rtf_generator);
|
||||
rtf_generator.pipe(stdout);
|
18
vcbuild.bat
18
vcbuild.bat
@ -24,6 +24,7 @@ set nosnapshot=
|
||||
set test=
|
||||
set test_args=
|
||||
set msi=
|
||||
set licensertf=
|
||||
set upload=
|
||||
set jslint=
|
||||
|
||||
@ -39,6 +40,7 @@ if /i "%1"=="noprojgen" set noprojgen=1&goto arg-ok
|
||||
if /i "%1"=="nobuild" set nobuild=1&goto arg-ok
|
||||
if /i "%1"=="nosign" set nosign=1&goto arg-ok
|
||||
if /i "%1"=="nosnapshot" set nosnapshot=1&goto arg-ok
|
||||
if /i "%1"=="licensertf" set licensertf=1&goto arg-ok
|
||||
if /i "%1"=="test-uv" set test=test-uv&goto arg-ok
|
||||
if /i "%1"=="test-internet" set test=test-internet&goto arg-ok
|
||||
if /i "%1"=="test-pummel" set test=test-pummel&goto arg-ok
|
||||
@ -46,7 +48,7 @@ if /i "%1"=="test-simple" set test=test-simple&goto arg-ok
|
||||
if /i "%1"=="test-message" set test=test-message&goto arg-ok
|
||||
if /i "%1"=="test-all" set test=test-all&goto arg-ok
|
||||
if /i "%1"=="test" set test=test&goto arg-ok
|
||||
if /i "%1"=="msi" set msi=1&goto arg-ok
|
||||
if /i "%1"=="msi" set msi=1&set licensertf=1&goto arg-ok
|
||||
if /i "%1"=="upload" set upload=1&goto arg-ok
|
||||
if /i "%1"=="jslint" set jslint=1&goto arg-ok
|
||||
|
||||
@ -74,7 +76,7 @@ echo Project files generated.
|
||||
|
||||
:msbuild
|
||||
@rem Skip project generation if requested.
|
||||
if defined nobuild goto msi
|
||||
if defined nobuild goto sign
|
||||
|
||||
@rem Bail out early if not running in VS build env.
|
||||
if defined VCINSTALLDIR goto msbuild-found
|
||||
@ -93,9 +95,19 @@ goto run
|
||||
msbuild node.sln /m /t:%target% /p:Configuration=%config% /clp:NoSummary;NoItemAndPropertyList;Verbosity=minimal /nologo
|
||||
if errorlevel 1 goto exit
|
||||
|
||||
if defined nosign goto msi
|
||||
:sign
|
||||
@rem Skip signing if the `nosign` option was specified.
|
||||
if defined nosign goto licensertf
|
||||
|
||||
signtool sign /a Release\node.exe
|
||||
|
||||
:licensertf
|
||||
@rem Skip license.rtf generation if not requested.
|
||||
if not defined licensertf goto msi
|
||||
|
||||
%config%\node tools\license2rtf.js < LICENSE > %config%\license.rtf
|
||||
if errorlevel 1 echo Failed to generate license.rtf&goto exit
|
||||
|
||||
:msi
|
||||
@rem Skip msi generation if not requested
|
||||
if not defined msi goto run
|
||||
|
Loading…
x
Reference in New Issue
Block a user