FazBrowse GitHub Viewer
|
Trending
|
URL:
|
Home
Tools:
[Download Repo ZIP]
[View Raw Code]
[Original HTTPS Page]
livecode/builder/release_notes_builder.livecodescript at develop · livecode/livecode · GitHub
Uh oh!
There was an error while loading.
Please reload this page
.
This repository was archived by the owner on Aug 31, 2021. It is now read-only.
livecode
/
livecode
Public archive
Notifications
You must be signed in to change notification settings
Fork
223
Star
517
Code
Pull requests
189
Actions
Security and quality
0
Insights
Additional navigation options
Code
Pull requests
Actions
Security and quality
Insights
Expand file tree
Breadcrumbs
livecode
/
builder
/
release_notes_builder.livecodescript
Copy path
More file actions
More file actions
Latest commit
History
History
History
1452 lines (1196 loc) · 46.4 KB
Breadcrumbs
livecode
/
builder
/
release_notes_builder.livecodescript
Copy path
File metadata and controls
1452 lines (1196 loc) · 46.4 KB
Raw
Copy raw file
Download raw file
Open symbols panel
Edit and raw actions
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
487
488
489
490
491
492
493
494
495
496
497
498
499
500
501
502
503
504
505
506
507
508
509
510
511
512
513
514
515
516
517
518
519
520
521
522
523
524
525
526
527
528
529
530
531
532
533
534
535
536
537
538
539
540
541
542
543
544
545
546
547
548
549
550
551
552
553
554
555
556
557
558
559
560
561
562
563
564
565
566
567
568
569
570
571
572
573
574
575
576
577
578
579
580
581
582
583
584
585
586
587
588
589
590
591
592
593
594
595
596
597
598
599
600
601
602
603
604
605
606
607
608
609
610
611
612
613
614
615
616
617
618
619
620
621
622
623
624
625
626
627
628
629
630
631
632
633
634
635
636
637
638
639
640
641
642
643
644
645
646
647
648
649
650
651
652
653
654
655
656
657
658
659
660
661
662
663
664
665
666
667
668
669
670
671
672
673
674
675
676
677
678
679
680
681
682
683
684
685
686
687
688
689
690
691
692
693
694
695
696
697
698
699
700
701
702
703
704
705
706
707
708
709
710
711
712
713
714
715
716
717
718
719
720
721
722
723
724
725
726
727
728
729
730
731
732
733
734
735
736
737
738
739
740
741
742
743
744
745
746
747
748
749
750
751
752
753
754
755
756
757
758
759
760
761
762
763
764
765
766
767
768
769
770
771
772
773
774
775
776
777
778
779
780
781
782
783
784
785
786
787
788
789
790
791
792
793
794
795
796
797
798
799
800
801
802
803
804
805
806
807
808
809
810
811
812
813
814
815
816
817
818
819
820
821
822
823
824
825
826
827
828
829
830
831
832
833
834
835
836
837
838
839
840
841
842
843
844
845
846
847
848
849
850
851
852
853
854
855
856
857
858
859
860
861
862
863
864
865
866
867
868
869
870
871
872
873
874
875
876
877
878
879
880
881
882
883
884
885
886
887
888
889
890
891
892
893
894
895
896
897
898
899
900
901
902
903
904
905
906
907
908
909
910
911
912
913
914
915
916
917
918
919
920
921
922
923
924
925
926
927
928
929
930
931
932
933
934
935
936
937
938
939
940
941
942
943
944
945
946
947
948
949
950
951
952
953
954
955
956
957
958
959
960
961
962
963
964
965
966
967
968
969
970
971
972
973
974
975
976
977
978
979
980
981
982
983
984
985
986
987
988
989
990
991
992
993
994
995
996
997
998
999
1000
script
"ReleaseNotesBuilder
"
constant
kExtensionLcbTypes
=
"widgets,libraries,modules"
constant
kExtensionLcbStrings
=
"widget,library,module"
constant
kExtensionScriptTypes
=
"script-libraries"
local
sMarkdownText
local
sVersion
local
sOutputPath
private
command
Initialize
pVersion, pOutputPath
if
pOutputPath
is
empty
then
throw
"Release notes output path must be specified"
exit Initialize
end if
start
using
stack (builderSystemFolder()
&
slash
&
"edition_utilities.livecodescript"
)
set
the
defaultfolder
to
builderRepoFolder()
set
the
hideconsolewindows
to
true
put
empty
into
sMarkdownText
put
pVersion
into
sVersion
put
pOutputPath
into
sOutputPath
end
Initialize
private
command
Finalize
end
Finalize
command
releaseNotesBuilderRun
pEdition, pVersion, pReleaseType, pOutputDir
local
tError
builderLog
"report"
,
"Building release notes for version"
&&
pVersion
try
Initialize
pVersion
,
pOutputDir
BaseCreate
local
tComponents
put
builderComponentFolders()
into
tComponents
--
special case some extra folders
local
tIndex
put
the
number
of
elements
of
tComponents
+
1
into
tIndex
put
builderRepoFolder()
&
"/docs"
into
tComponents
[
tIndex
][
"folder"
]
put
"engine"
into
tComponents
[
tIndex
][
"metadata"
][
"category"
]
put
"community"
into
tComponents
[
tIndex
][
"metadata"
][
"edition"
]
add
1
to
tIndex
put
builderRepoFolder()
&
"/ide"
into
tComponents
[
tIndex
][
"folder"
]
put
"ide"
into
tComponents
[
tIndex
][
"metadata"
][
"category"
]
put
"community"
into
tComponents
[
tIndex
][
"metadata"
][
"edition"
]
put
the
number
of
elements
of
tComponents
+
1
into
tIndex
put
builderRepoFolder()
&
"/docs/lcb"
into
tComponents
[
tIndex
][
"folder"
]
put
"builder"
into
tComponents
[
tIndex
][
"metadata"
][
"category"
]
put
""
into
tComponents
[
tIndex
][
"metadata"
][
"edition"
]
local
tPath
,
tTypePath
local
tReposA
,
tDefaultEdition
put
builderPrivateRepoFolder()
into
tReposA
[
"indy"
]
put
builderRepoFolder()
into
tReposA
[
"community"
]
repeat
for
each
key
tDefaultEdition
in
tReposA
put
tReposA
[
tDefaultEdition
]
into
tPath
repeat
for
each
item
tType
in
kExtensionLcbTypes
,
kExtensionScriptTypes
put
tPath
&
slash
&
"extensions"
&
slash
&
tType
into
tTypePath
if
there is not a
folder
tTypePath
then
next
repeat
end if
repeat
for
each
line
tFolder
in
FileGetSubFolders(
tTypePath
)
put
the
number
of
elements
of
tComponents
+
1
into
tIndex
put
tFolder
into
tComponents
[
tIndex
][
"folder"
]
put
"extension"
into
tComponents
[
tIndex
][
"metadata"
][
"category"
]
local
tEdition
put
ExtensionsGetEdition(
tFolder
)
into
tEdition
if
tEdition
is
empty
then
put
tDefaultEdition
into
tEdition
end if
put
tEdition
into
tComponents
[
tIndex
][
"metadata"
][
"edition"
]
put
ExtensionsGetSectionName(
tFolder
)
into
tComponents
[
tIndex
][
"metadata"
][
"section"
]
end repeat
end repeat
end repeat
ComponentsCreate
tComponents
DictionaryCreate
tComponents
PreviousCreate
OutputNotes
OutputUpdates
Finalize
return builderFileGetUTF8Contents(OutputGetUpdatesFilename(
"html"
))
catch
tError
put
tError
builderLog
"error"
,
tError
end try
end
releaseNotesBuilderRun
private
function
PathGetLastComponent
pPath
set
the
itemdelimiter
to
slash
return
item
-
1
of
pPath
end
PathGetLastComponent
private
command
ComponentsCreateForEdition
pEdition, pCollated, pBugInfo
local
tDisplayName
if
pEdition
is not
empty
then
put
editionDisplayName(
pEdition
)
into
tDisplayName
end if
repeat
for
each
item
tCategory
in
builderComponentCategories()
local
tTitle
if
tDisplayName
is not
empty
then
put
merge
(
"# LiveCode [[ tDisplayName ]] [[ tCategory ]] changes"
)
into
tTitle
else
put
merge
(
"# LiveCode [[ tCategory ]] changes"
)
into
tTitle
end if
if
NotesHaveContent(
pCollated
[
pEdition
][
tCategory
],
pBugInfo
[
pEdition
][
tCategory
])
then
MarkdownApp
end
"notes"
,
tTitle
MarkdownApp
end
"updates"
,
tTitle
NotesGenerate
tCategory
,
pCollated
[
pEdition
][
tCategory
],
1
BugGenerate
pBugInfo
[
pEdition
][
tCategory
],
tCategory
end if
end repeat
end
ComponentsCreateForEdition
private
command
ComponentsCreate
pComponents
BuilderLog
"report"
,
"Creating component release notes"
local
tCollated
,
tBugInfo
repeat
for
each
element
tComponent
in
pComponents
ComponentsCreatePath
tComponent
,
tCollated
,
tBugInfo
end repeat
repeat
for
each
item
tEdition
in
editionNames()
ComponentsCreateForEditi
on
tEdition
,
tCollated
,
tBugInfo
end repeat
ComponentsCreateForEdition
""
,
tCollated
,
tBugInfo
end
ComponentsCreate
private
command
ComponentsCreatePath
pComponent, @xCollated, @xBugInfo
local
tSkip
=
true
try
put
there is not a
folder (
pComponent
[
"folder"
]
&
"/notes"
)
into
tSkip
end try
set
the
itemDelimiter
to
slash
if
tSkip
then
builderLog
"report"
,
"Skipping no notes for component"
&&
the
last
item
of
pComponent
[
"folder"
]
exit ComponentsCreatePath
end if
builderLog
"report"
,
"Creating release notes for"
&&
the
last
item
of
pComponent
[
"folder"
]
if
pComponent
[
"metadata"
][
"section"
]
is
empty
then
--
just because something is a LCB module or a script library does not mean
--
we necessarily want to give it a separate section in the release notes
--
for example a widget or library for use purely within the IDE should
--
just merge into the IDE notes.
ScanAndCollatePath \
pComponent
[
"folder"
], \
xCollated[
pComponent
[
"metadata"
][
"edition"
]][
pComponent
[
"metadata"
][
"category"
]], \
xBugInfo[
pComponent
[
"metadata"
][
"edition"
]][
pComponent
[
"metadata"
][
"category"
]]
else
local
tCollatedSection
,
tToMerge
ScanAndCollatePath \
pComponent
[
"folder"
], \
tCollatedSection
, \
xBugInfo[
pComponent
[
"metadata"
][
"edition"
]][
pComponent
[
"metadata"
][
"category"
]]
--
Note the use of AppendToSection here means multiple components can be merged
--
into the same sub-section of the notes. For example, engine -> Mobile or
--
ide -> Script Editor
put
1
into
tToMerge
[
"__count"
]
put
tCollatedSection
into
tToMerge
[
1
]
put
pComponent
[
"metadata"
][
"section"
]
into
tToMerge
[
1
][
"__name"
]
if
NotesHaveContent(
tCollatedSection
)
then
NotesMerge \
tToMerge
, \
xCollated[
pComponent
[
"metadata"
][
"edition"
]][
pComponent
[
"metadata"
][
"category"
]]
end if
end if
end
ComponentsCreatePath
private
function
NotesGetExperimentalText
return
"<div class="
&
quote
&
"experimental"
&
quote
&
">"
&
\
"Important: This feature is currently experimental. This means it may not be complete, or may fail in some circumstances that you would expect it to work. Please do not be afraid to try it out as we need feedback to develop it further."
&
\
"</div>"
end
NotesGetExperimentalText
--
--------------------------------------------------------------
--
Output
--
--------------------------------------------------------------
private
function
OutputGetNotesFilename
tSuffix, pVersion
if
pVersion
is
empty
then
put
sVersion
into
pVersion
end if
local
tBasename
put
"LiveCodeNotes-"
&
replaceText
(
pVersion
,
"[-,\.]"
,
"_"
)
into
tBasename
return
sOutputPath
&
slash
&
tBasename
&
"."
&
tSuffix
end
OutputGetNotesFilename
private
function
OutputGetUpdatesFilename
tSuffix, pVersion
if
pVersion
is
empty
then
put
sVersion
into
pVersion
end if
local
tBasename
put
"LiveCodeUpdates-"
&
replaceText
(
pVersion
,
"[-,\.]"
,
"_"
)
into
tBasename
return
sOutputPath
&
slash
&
tBasename
&
"."
&
tSuffix
end
OutputGetUpdatesFilename
private
function
OutputGetGuideFilename
builderEnsureFolder builderBuiltGuidesFolder()
return builderBuiltGuidesFolder()
&
slash
&
"Release Notes.md"
end
OutputGetGuideFilename
private
function
OutputGetNotesUrl
tSuffix, pVersion
put
replaceText
(
pVersion
,
"[-,\.]"
,
"_"
)
into
pVersion
return
"https://downloads.livecode.com/livecode/"
&
pVersion
&
\
"/LiveCodeNotes-"
&
pVersion
&
"."
&
tSuffix
end
OutputGetNotesUrl
private
function
OutputGetNotesTitle
return
merge
(
"LiveCode [[sVersion]] Release Notes"
)
end
OutputGetNotesTitle
private
command
OutputNotes
OutputNotesMarkdown
OutputNotesHtml
OutputNotesPdf
OutputNotesGuide
end
OutputNotes
private
command
OutputNotesMarkdown
local
tPath
put
OutputGetNotesFilename(
"md"
)
into
tPath
builderLog
"report"
,
merge
(
"Writing [[tPath]]"
)
builderFileSetUTF8Contents
tPath
,
sMarkdownText
[
"notes"
]
end
OutputNotesMarkdown
private
command
OutputNotesGuide
local
tPath
put
OutputGetGuideFilename()
into
tPath
builderLog
"report"
,
merge
(
"Writing [[tPath]]"
)
builderFileSetUTF8Contents
tPath
,
sMarkdownText
[
"notes"
]
end
OutputNotesGuide
private
command
OutputNotesHtml
--
Try to do the minimum possible escaping to be able to insert the
--
markdown into a JavaScript string
local
tEscaped
put
sMarkdownText
[
"notes"
]
into
tEscaped
replace
"\"
with
"\\"
in
tEscaped
replace
"'"
with
"\'"
in
tEscaped
replace
return
with
"\n"
in
tEscaped
local
tHtmlTemplatePath
put
builderSystemFolder()
&
"/release-notes-template.html"
into
tHtmlTemplatePath
local
tHtml
put
builderFileGetUTF8Contents(
tHtmlTemplatePath
)
into
tHtml
replace
"@MARKDOWN@"
with
tEscaped
in
tHtml
local
tOutpath
put
OutputGetNotesFilename(
"html"
)
into
tOutpath
builderLog
"report"
,
merge
(
"Writing [[tOutpath]]"
)
builderFileSetUTF8Contents
tOutpath
,
tHtml
end
OutputNotesHtml
private
command
OutputNotesPdf
local
tCommand
--
Use wkhtmltopdf to convert the HTML representation
if
$WKHTMLTOPDF
is not
empty
then
put
$WKHTMLTOPDF
into
tCommand
else
put
builderRepoFolder()
&
"/builder/wkhtmltopdf"
into
tCommand
end if
local
tTitle
,
tDate
,
tHtmlPath
,
tPdfPath
put
OutputGetNotesTitle()
into
tTitle
put
the
date
into
tDate
put
OutputGetNotesFilename(
"html"
)
into
tHtmlPath
put
OutputGetNotesFilename(
"pdf"
)
into
tPdfPath
local
tArgs
put
empty
into
tArgs
put
merge
(
"--header-right '[[tTitle]] [[tDate]]' "
)
after
tArgs
put
"--header-font-size 8 --header-spacing 5 "
after
tArgs
put
"--footer-center [page] --footer-font-size 8 --footer-spacing 5 "
after
tArgs
put
"--margin-top 30 --margin-bottom 20 --margin-left 20 --margin-right 20 "
after
tArgs
put
"--enable-internal-links --encoding UTF-8 "
after
tArgs
local
tExitCode
builderLog
"report"
,
merge
(
"Generating [[tPdfPath]] with [[tCommand]]"
)
get
shell
(
tCommand
&&
tArgs
&&
tHtmlPath
&&
tPdfPath
)
put
the
result
into
tExitCode
if
tExitCode
is not
0
then
throw
merge
(
"Failed to run [[tCommand]]: exit code [[tExitCode]]"
)
end if
end
OutputNotesPdf
private
command
OutputUpdates
OutputUpdatesMarkdown
OutputUpdatesHtml
end
OutputUpdates
private
command
OutputUpdatesMarkdown
local
tPath
put
OutputGetUpdatesFilename(
"md"
)
into
tPath
builderLog
"report"
,
merge
(
"Writing [[tPath]]"
)
builderFileSetUTF8Contents
tPath
,
sMarkdownText
[
"updates"
]
end
OutputUpdatesMarkdown
//
Find <h(n)> elements and make them <h(n+pAmount)>
private
command
MakeHeadersSmaller
@xHTML, pAmount
local
tStart
,
tEnd
,
tOldEnd
,
tNumber
put
1
into
tOldEnd
repeat
while
matchChunk
(
char
tOldEnd
to
-
1
of
xHTML, \
"<(?:\/)?h([0-9]+)>"
,
tStart
,
tEnd
)
add
tOldEnd
-
1
to
tEnd
add
tOldEnd
-
1
to
tStart
put
char
tStart
to
tEnd
of
xHTML
into
tNumber
add
pAmount
to
tNumber
put
tNumber
into
char
tStart
to
tEnd
of
xHTML
put
tEnd
into
tOldEnd
add
the
number
of
chars
in
tNumber
-
(
tEnd
-
tStart
)
+
1
\
to
tOldEnd
end repeat
end
MakeHeadersSmaller
//
Find (at least) double blank lines between specified tags
//
and add empty paragraph
private
command
RespectBlankLinesBetween
@xHTML, pFromTagSuffix, pToTagPrefix
put
replaceText
(xHtml,
pFromTagSuffix
&
">\n{2,}<"
&
pToTagPrefix
, \
pFromTagSuffix
&
">"
&
return
&
"<p> </p>"
&
\
return
&
"<"
&
pToTagPrefix
)
into
xHtml
end
RespectBlankLinesBetween
private
command
EnsureMergMarkdown
builderExtUnpack
"Community"
local
tMergMarkdown
put
builderUnpackFolder(
"Community"
)
&
slash
&
"Ext"
into
tMergMarkdown
local
tFolders
put
folders
(
tMergMarkdown
)
into
tFolders
filter
tFolders
with
"mergMarkdown*"
if
tFolders
is
empty
then
builderLog
"error"
,
"couldn't download mergMarkdown"
end if
put
slash
&
line
1
of
tFolders
&
slash
&
"mergMarkdown"
after
tMergMarkdown
switch
the
platform
case
"macos"
put
".bundle"
after
tMergMarkdown
break
case
"linux"
if
the
processor
is
"x86_64"
then
put
"-x64.so"
after
tMergMarkdown
else
put
".so"
after
tMergMarkdown
end if
break
case
"win32"
if
the
processor
is
"x86_64"
then
put
"-x86_64.dll"
after
tMergMarkdown
else
put
"-x86.dll"
after
tMergMarkdown
end if
break
end switch
set
the
externals
of
the
templatestack
to
tMergMarkdown
lock messages
create
stack
unlock messages
start
using
it
end
EnsureMergMarkdown
command
OutputUpdatesHtml
local
tHtml
EnsureMergMarkdown
put
mergMarkdownToXHTML(
sMarkdownText
[
"updates"
] \
,
true
,
true
,
true
,
true
,
false
,
true
,
true
,
true
)
into
tHtml
//
Shrink all headers by 2
MakeHeadersSmaller
tHTML
,
2
//
Add extra blank paragraphs between any tag &
//
subsequent header
RespectBlankLinesBetween
tHTML
,
""
,
"h"
//
Add extra blank paragraphs between paragraphs
RespectBlankLinesBetween
tHTML
,
"p"
,
"p"
local
tPath
put
OutputGetUpdatesFilename(
"html"
)
into
tPath
builderLog
"report"
,
merge
(
"Writing [[tPath]]"
)
builderFileSetUTF8Contents
tPath
,
tHtml
end
OutputUpdatesHtml
--
--------------------------------------------------------------
--
Base file sections
--
--------------------------------------------------------------
private
command
BaseCreate
builderLog
"report"
,
"Creating base release notes"
BaseCreateTitle
BaseCreateContents
BaseCreateOverview
BaseCreateIssues
MarkdownApp
end
"notes"
, BaseReadFile(
"breaking_changes"
)
MarkdownApp
end
"notes"
, BaseReadFile(
"platforms"
)
MarkdownApp
end
"notes"
, BaseReadFile(
"setup"
)
MarkdownApp
end
"notes"
, BaseReadFile(
"proposed_changes"
)
BaseCreateUpdates
end
BaseCreate
private
command
BaseCreateTitle
MarkdownApp
end
"notes"
,
"<h1 class="
&
quote
&
"title"
&
quote
&
">"
&
OutputGetNotesTitle()
&
"</h1>"
&
return
end
BaseCreateTitle
private
command
BaseCreateContents
MarkdownApp
end
"notes"
,
"[TOC]"
end
BaseCreateContents
private
command
BaseCreateOverview
local
tOverview
put
BaseReadFile(
"overview"
)
into
tOverview
if
tOverview
is
empty
then
put
"# Overview"
&
return
&
return
after
tOverview
put
merge
(
"This document describes all the changes that have been made for LiveCode [[sVersion]], including bug fixes and new syntax."
)
after
tOverview
end if
MarkdownApp
end
"notes"
,
tOverview
end
BaseCreateOverview
private
command
BaseCreateIssues
local
tIssues
put
BaseReadFile(
"issues"
)
into
tIssues
if
tIssues
is
empty
then
put
"# Known Issues"
&
return
&
return
after
tIssues
put
"There are no known issues with this release."
after
tIssues
end if
MarkdownApp
end
"notes"
,
tIssues
end
BaseCreateIssues
private
function
BaseReadFile
pBasename
local
tPath
put
FileGetPath(
"base"
)
&
slash
&
pBasename
&
".md"
into
tPath
if
there is a
file
tPath
then
return builderFileGetUTF8Contents(
tPath
)
else
return
empty
end if
end
BaseReadFile
private
command
BaseCreateUpdates
MarkdownApp
end
"updates"
,
merge
(
"LiveCode [[sVersion]] is now available."
)
&
return
MarkdownApp
end
"updates"
,
merge
(
"The full [[sVersion]] release notes are available on the LiveCode website."
)
&
return
MarkdownApp
end
"updates"
,
"Changes in this release include:"
&
return
end
BaseCreateUpdates
/*
Build up a datastructure containing all the (raw) data gathered
from the target directory. The return value is a nested array:
{
"<version>": {
"<filename>": {
"basename": "<filename without suffix or path>",
"markdown": "<file content>",
"metadata": { <metadata key-value pairs> }
}
}
}
*/
private
command
NotesScan
pType, @xScan
local
tTags
,
tNumTags
put
GitGetRelevantTags(
pType
)
into
tTags
put
the
number
of
lines
in
tTags
into
tNumTags
local
tVersion
,
tBaseVersion
,
tPrevVersion
,
tTagOffset
local
tAllFiles
,
tVersionFiles
,
tFile
put
line
1
of
tTags
into
tBaseVersion
put
tBaseVersion
into
tVersion
--
Get a list of all files to be considered
put
GitGetChangedFiles(
pType
,
tBaseVersion
,
line
-
1
of
tTags
)
into
tAllFiles
put
2
into
tTagOffset
repeat
while
tTagOffset
<=
tNumTags
put
tVersion
into
tPrevVersion
put
line
tTagOffset
of
tTags
into
tVersion
--
Figure out which files should be considered for this version
put
empty
into
tVersionFiles
repeat
for
each
line
tFile
in
GitGetChangedFiles(
pType
,
tPrevVersion
,
tVersion
)
if
tFile
is among
the
lines
of
tAllFiles
then
put
tFile
&
return
after
tVersionFiles
end if
end repeat
NotesScanVersi
on
pType
,
tVersion
,
tVersionFiles
, xScan
add
1
to
tTagOffset
end repeat
end
NotesScan
private
command
NotesScanVersion
pType, pVersion, pFiles, @xScan
local
tFile
,
tOldFile
,
tContents
,
tError
,
tFileInfo
,
tVersion
,
tBasename
repeat
for
each
line
tFile
in
pFiles
--
If this file was already processed once before, delete its
--
record (we'll generate a new one)
repeat
for
each
key
tVersion
in
xScan
if
tFile
is among
the
keys
of
xScan[
tVersion
]
then
delete variable
xScan[
tVersion
][
tFile
]
end if
end repeat
try
put
builderFileGetUTF8Contents(
tFile
)
into
tContents
catch
tError
builderLog
"report"
,
tERror
next
repeat
end try
--
Extract metadata & markdown sections
MarkdownSplitMetadata
tContents
,
tFileInfo
[
"markdown"
],
tFileInfo
[
"metadata"
]
--
Allow automatically-generated information to be overwritten by metadata
put
tFileInfo
[
"metadata"
][
"version"
]
into
tVersion
if
tVersion
is
empty
then
put
pVersion
into
tVersion
else
--
filter out touched files with version headers
set
the
itemDelimiter
to
"-"
if
item
1
of
tVersion
is not
item
1
of
pVersion
then
builderLog
"report"
,
"Filtering touched file with version header"
&&
tFile
next
repeat
end if
end if
put
tFileInfo
[
"metadata"
][
"basename"
]
into
tBasename
if
tBasename
is
empty
then
put
FileGetBasename(
tFile
)
into
tBasename
end if
put
tBasename
into
tFileInfo
[
"basename"
]
put
tFileInfo
into
xScan[
tVersion
][
tFile
]
end repeat
end
NotesScanVersion
--
--------------------------------------------------------------
--
New-style notes
--
--------------------------------------------------------------
/*
Create a tree of section information from the results of scanning
the release notes:
{
"__count": <number of child sections>,
"__markdown": "<text>",
"__name": "<title of section>",
1: {
"__count": ...,
"__markdown" ...,
"__name", ...,
...
},
2: {
...
},
}
*/
private
command
NotesCollate
pType, pScanInfo, @xCollated, @xBugInfo
local
tTags
,
tFile
,
tTagCount
,
tVersion
--
Collate notes in descending order of version, so newest appear at the top
put
the
keys
of
pScanInfo
into
tTags
GitSortTags
tTags
put
the
number
of
elements
in
pScanInfo
into
tTagCount
repeat
tTagCount
times
put
line
tTagCount
of
tTags
into
tVersion
repeat
for
each
key
tFile
in
pScanInfo
[
tVersion
]
NotesCollateFile
pType
,
tVersion
,
pScanInfo
[
tVersion
][
tFile
], xCollated, xBugInfo
end repeat
subtract
1
from
tTagCount
end repeat
end
NotesCollate
private
command
NotesCollateFile
pType, pVersion, pFileInfo, @xCollated, @xBugInfo
local
tLine
,
tSectionPath
,
tBasename
put
pFileInfo
[
"basename"
]
into
tBasename
local
tBugId
,
tBugDesc
,
tBugPath
local
tLevel
,
tName
,
tOldLevel
,
tHaveContent
put
0
into
tLevel
put
0
into
tOldLevel
put
false
into
tHaveContent
local
tLineCount
put
the
number
of
lines
of
pFileInfo
[
"markdown"
]
into
tLineCount
repeat
for
each
line
tLine
in
pFileInfo
[
"markdown"
]
--
First check if this is a bug info line
local
tOnlyAddBug
NotesExtractBugInfo
tBasename
,
tLine
,
tLineCount
,
tBugId
,
tBugDesc
put
it
into
tOnlyAddBug
if
tBugId
is not
empty
then
BugAddInfo xBugInfo,
pVersion
,
tBugId
,
tBugDesc
if
tOnlyAddBug
then
next
repeat
else
put
empty
into
tBugId
put
empty
into
tBugDesc
end if
end if
--
Second, check if it's a section control line
put
tLevel
into
tOldLevel
NotesExtractSectionInfo
tLine
,
tLevel
,
tName
if
tLevel
is not
empty
then
if
tName
is
empty
then
builderLog
"warning"
,
merge
(
"Invalid section name in [[pType]] note [[tBasename]]"
)
next
repeat
end if
--
If changing to a section that's the same level or
--
higher than the current section but without any
--
intervening content, generate a warning
if
(not
tHaveContent
)
and
tLevel
<=
tOldLevel
then
builderLog
"warning"
,
merge
(
"Section without content in [[pType]] note '[[tBasename]]'"
)
end if
NotesUpdateSectionPath
tLevel
,
tName
, xCollated,
tSectionPath
put
false
into
tHaveContent
next
repeat
end if
--
Otherwise, just add it to the current section of the
--
collated notes
put
tLine
&
return
after
xCollated[
tSectionPath
][
"__markdown"
]
put
pVersion
into
xCollated[
tSectionPath
][
"__version"
]
if
word
1
to
-
1
of
tLine
is not
empty
then
put
true
into
tHaveContent
end if
end repeat
end
NotesCollateFile
private
command
NotesUpdateSectionPath
pLevel, pName, @xCollated, @xSectionPath
if
pLevel
is
0
then
exit NotesUpdateSectionPath
end if
if
not xSectionPath
is an
array
then
put
1
into
xSectionPath[
1
]
delete variable
xSectionPath[
1
]
end if
--
Truncate the path to the level before the current one
repeat
while
the
number
of
elements
in
xSectionPath
>=
pLevel
delete variable
xSectionPath[
the
number
of
elements
in
xSectionPath]
end repeat
--
Find out how many subsections there already are at this level.
--
It's necessary to do a few contortions to cope with the case that
--
the truncated path is empty.
local
tPath
,
tCount
put
xSectionPath
into
tPath
put
"__count"
into
tPath
[
pLevel
]
put
xCollated[
tPath
]
into
tCount
--
Check to see if there is already a subsection with the specified name
local
tId
repeat
with
tId
=
1
to
tCount
put
tId
into
tPath
[
pLevel
]
if
xCollated[
tPath
][
"__name"
]
is
pName
then
put
tId
into
xSectionPath[
pLevel
]
exit NotesUpdateSectionPath
end if
end repeat
--
No existing section matches, so add a new one. Do the "cope with
--
empty array" dance again.
put
"__count"
into
tPath
[
pLevel
]
add
1
to
xCollated[
tPath
]
put
xCollated[
tPath
]
into
tId
--
Initialise the new section record
put
tId
into
xSectionPath[
pLevel
]
put
pName
into
xCollated[xSectionPath][
"__name"
]
put
0
into
xCollated[xSectionPath][
"__count"
]
end
NotesUpdateSectionPath
private
command
NotesExtractBugInfo
pBaseName, pLine, pLineCount, @rId, @rDesc
--
v2 notes are `# [int] description`
if
matchText
(
pLine
,
"^\s*#\s+\[(\w*)\]\s+(.*)$"
, rId, rDesc)
then
return
true
for
value
end if
--
check if it's a v1 single line bugfix note
split
pBaseName
with
"-"
if
pBaseName
[
2
]
is an
integer
and
\
word
1
of
pLine
is
"#"
then
put
pBaseName
[
2
]
into
rId
put
word
2
to
-
1
of
pLine
into
rDesc
end if
return
pLineCount
is
1
for
value
end
NotesExtractBugInfo
private
command
NotesExtractSectionInfo
pLine, @rLevel, @rName
local
tPrefix
get
matchText
(
pLine
,
"^\s*(#*)\s+(.*)$"
,
tPrefix
, rName)
if
tPrefix
is not
empty
then
put
the
number
of
chars
in
tPrefix
into
rLevel
else
put
empty
into
rLevel
end if
end
NotesExtractSectionInfo
private
command
NotesMerge
pLeftCollated, @xRightCollated
if
pLeftCollated
is not an
array
then
exit NotesMerge
end if
if
word
1
to
-
1
of
pLeftCollated
[
"__markdown"
]
is not
empty
then
if
xRightCollated[
"__markdown"
]
is
empty
then
put
return
&
return
after
xRightCollated[
"__markdown"
]
end if
put
pLeftCollated
[
"__markdown"
]
after
xRightCollated[
"__markdown"
]
end if
local
tLeftID
,
tRightID
repeat
with
tLeftID
=
1
to
pLeftCollated
[
"__count"
]
local
tNameFound
put
false
into
tNameFound
repeat
with
tRightID
=
1
to
xRightCollated[
"__count"
]
if
pLeftCollated
[
tLeftID
][
"__name"
]
is
xRightCollated[
tRightID
][
"__name"
]
then
NotesMerge
pLeftCollated
[
tLeftID
], xRightCollated[
tRightID
]
put
true
into
tNameFound
end if
end repeat
if
not
tNameFound
then
add
1
to
xRightCollated[
"__count"
]
put
pLeftCollated
[
tLeftID
]
into
xRightCollated[xRightCollated[
"__count"
]]
end if
end repeat
end
NotesMerge
private
function
NotesHaveContent
pCollated, pBugInfo
if
pCollated
is an
array
then
if
(
word
1
to
-
1
of
pCollated
[
"__markdown"
])
is not
empty
then
return
true
end if
--
Recurse into child nodes
local
tId
repeat
with
tId
=
1
to
pCollated
[
"__count"
]
if
NotesHaveContent(
pCollated
[
tId
])
then
return
true
end if
end repeat
end if
if
pBugInfo
is an
array
and
the
number
of
elements
in
pBugInfo
>
0
then
return
true
end if
return
false
end
NotesHaveContent
private
command
NotesGenerate
pType, pCollated, pLevel
MarkdownApp
end
"notes"
, NotesGenerateContent(
pType
,
pCollated
,
pLevel
)
MarkdownApp
end
"updates"
, NotesGenerateContent(
pType
,
pCollated
,
pLevel
)
end
NotesGenerate
--
If <pOnlyCurrent> is true, then only generate content that's brand new in
--
the release that notes are being generated for
private
function
NotesGenerateContent
pType, pCollated, pLevel
--
Compute the content from this node + all child nodes
local
tContent
if
(
word
1
to
-
1
of
pCollated
[
"__markdown"
])
is not
empty
then
put
pCollated
[
"__markdown"
]
into
tContent
if
the
last
char
of
tContent
is not
return
then
put
return
after
tContent
end if
end if
--
Recurse into all child nodes
local
tSectionContent
,
tHeader
repeat
with
tId
=
1
to
pCollated
[
"__count"
]
put
NotesGenerateContent(
pType
,
pCollated
[
tId
],
pLevel
+
1
)
into
tSectionContent
--
Only generate a subsection header if the subsection (and all
--
the subsections it contains) doesn't contain any notes
if
tSectionContent
is not
empty
then
put
"#"
into
tHeader
repeat
pLevel
times
put
"#"
after
tHeader
end repeat
put
" "
&
pCollated
[
tId
][
"__name"
]
&
return
after
tHeader
put
return
&
tHeader
after
tContent
put
tSectionContent
after
tContent
end if
end repeat
return
tContent
end
NotesGenerateContent
private
function
ExtensionsGetSectionName
pExtPath
local
tName
,
tType
,
tTypeOffset
,
tPrettyType
set
the
itemdelimiter
to
slash
put
item
-
2
of
pExtPath
into
tType
set
the
itemdelimiter
to
comma
put
itemoffset
(
tType
,
kExtensionLcbTypes
)
into
tTypeOffset
put
item
tTypeOffset
of
kExtensionLcbStrings
into
tPrettyType
put
ExtensionsGetName(
pExtPath
)
into
tName
if
word
-
1
of
tName
is not
tPrettyType
then
put
space
&
tPrettyType
after
tName
end if
return
tName
end
ExtensionsGetSectionName
private
function
ExtensionsGetName
pExtPath
if
there is a
file
ExtensionsGetManifestPath(
pExtPath
)
then
return ExtensionsGetLCBName(
pExtPath
)
else
if
there is a
file
ExtensionsGetDocPath(
pExtPath
)
then
--
Script library
return ExtensionsGetLCSName(
pExtPath
)
end if
return
empty
end
ExtensionsGetName
private
function
ExtensionsGetLCSName
pExtPath
return ExtensionGetSingleLineElement(
pExtPath
,
"Title"
)
end
ExtensionsGetLCSName
private
function
ExtensionsGetEdition
pExtPath
if
there is a
file
ExtensionsGetDocPath(
pExtPath
)
then
return ExtensionGetSingleLineElement(
pExtPath
,
"Edition"
)
end if
return
empty
end
ExtensionsGetEdition
private
function
ExtensionGetSingleLineElement
pExtPath, pElement
local
tDoc
put
builderFileGetContents(ExtensionsGetDocPath(
pExtPath
))
into
tDoc
local
tRegex
put
"(?i)^"
&
pElement
&
":\s+(.*)"
into
tRegex
local
tValue
repeat
for
each
line
tLine
in
tDoc
get
matchText
(
word
1
to
-
1
of
tLine
,
tRegex
,
tValue
)
if
tValue
is not
empty
then
return
tValue
end if
end repeat
return
empty
end
ExtensionGetSingleLineElement
private
function
ExtensionsGetLCBName
pExtPath
local
tManifest
,
tXmlId
put
builderFileGetContents(ExtensionsGetManifestPath(
pExtPath
))
into
tManifest
put
revXMLCreateTree(
tManifest
,
true
,
true
,
false
)
into
tXmlId
if
tXmlId
begins with
"xmlerr"
then
throw
"Invalid extension manifest XML in [[tManifestFile]]"
end if
local
tTargetName
put
textDecode
(
revXMLNodeContents
(
tXmlId
,
"/package/title"
),
"UTF-8"
)
into
tTargetName
revXMLDeleteTree
tXmlId
if
tTargetName
begins with
"xmlerr"
then
return
empty
end if
return
tTargetName
end
ExtensionsGetLCBName
private
function
ExtensionsGetKind
pExtPath
--
Horrible-ish hack for extracting the "real" name of the LiveCode
--
module. See also tools/build-extensions.sh.
local
tShortName
set
the
itemdelimiter
to
slash
put
item
-
1
of
pExtPath
into
tShortName
if
there is no
file
merge
(
"[[pExtPath]]/[[tShortName]].lcb"
)
then
return ExtensionsGetLCSKind(
pExtPath
,
tShortName
)
else
return ExtensionsGetLCBKind(
pExtPath
,
tShortName
)
end if
end
ExtensionsGetKind
private
function
ExtensionsGetLCSKind
pExtPath, pShortName
local
tSource
,
tLine
,
tName
if
there is no
file
merge
(
"[[pExtPath]]/[[pShortName]].livecodescript"
)
then
return
empty
end if
put
builderFileGetUTF8Contents(
merge
(
"[[pExtPath]]/[[pShortName]].livecodescript"
))
into
tSource
repeat
for
each
line
tLine
in
tSource
get
matchText
(
tLine
,
"(?i)^script"
&&
quote
&
"(.*)"
&
quote
,
tName
)
if
tName
is not
empty
then
exit
repeat
end if
end repeat
return
tName
end
ExtensionsGetLCSKind
private
function
ExtensionsGetLCBKind
pExtPath, pShortName
local
tLcbSource
,
tLine
,
tModuleName
put
builderFileGetUTF8Contents(
merge
(
"[[pExtPath]]/[[pShortName]].lcb"
))
into
tLcbSource
repeat
for
each
line
tLine
in
tLcbSource
get
matchText
(
tLine
,
"(?i)^\s*(?:module|widget|library)\s+([\w.]*)"
,
tModuleName
)
if
tModuleName
is not
empty
then
exit
repeat
end if
end repeat
return
tModuleName
end
ExtensionsGetLCBKind
private
function
ExtensionsGetManifestPath
pExtPath
local
tManifestFile
put
FileGetPath(
"built-extensions"
)
into
tManifestFile
put
slash
&
ExtensionsGetKind(
pExtPath
)
after
tManifestFile
put
slash
&
"manifest.xml"
after
tManifestFile
return
tManifestFile
end
ExtensionsGetManifestPath
private
function
ExtensionsGetDocPath
pExtPath
local
tDocFile
put
FileGetPath(
"built-extensions"
)
into
tDocFile
put
slash
&
ExtensionsGetKind(
pExtPath
)
after
tDocFile
put
slash
&
"api.lcdoc"
after
tDocFile
return
tDocFile
end
ExtensionsGetDocPath
private
command
ScanAndCollatePath
pExtPath, @xCollated, @xBugInfo
local
tNotesPath
put
merge
(
"[[pExtPath]]/notes"
)
into
tNotesPath
if
there is not a
folder
tNotesPath
then
exit ScanAndCollatePath
end if
local
tScan
NotesScan
tNotesPath
,
tScan
NotesCollate
pExtPath
,
tScan
, xCollated, xBugInfo
end
ScanAndCollatePath
--
--------------------------------------------------------------
--
Dictionary change generation
--
--------------------------------------------------------------
private
command
DictionaryCreate
pComponents
builderLog
"report"
,
"Creating dictionary release notes"
local
tAdded
,
tModified
DictionaryScan
pComponents
,
tAdded
,
tModified
View remainder of file in raw view
Back
|
FazBrowse Home
|
New Git URL