Skip to content

Commit 0892a1e

Browse files
committed
tbProjPacker: a contributed section of 5 pages (ProjPacker's Pack, Unpack and Test), with its snapshot, sample template and book chapter; its private modules' enums are excluded, as no project can name them
1 parent c16c684 commit 0892a1e

11 files changed

Lines changed: 1047 additions & 2 deletions

File tree

‎WIP.md‎

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -33,7 +33,7 @@ sibling. History goes nowhere: git keeps it.
3333

3434
Reference documentation is **complete** for all thirteen packages: VBA, VBRUN, VB, WebView2, Assert, CustomControls, CEF, WinEventLogLib, WinNamedPipesLib, WinServicesLib, tbIDE, WinNativeCommonCtls and AppGlobalClassObject. It is adapted from primary sources: Microsoft VBA-Docs (CC-BY-4.0) for the runtime library, `.twin` source for the twinBASIC-specific packages. The CEF and WebView2 packages also carry a tutorial set.
3535

36-
Twelve **contributed** packages from TWINSERV have sections under `docs/Reference/Contributed/`: FileProps, Fmt, OLEGuids, WinReg, TwinTimerPackage, TBMANLIB_ListBoxHScroll, TBMANLIB_RES, tbRegExp and VBA_JSON complete; AutoCompleteLib, BigNumberLib and VBComDlg their main class only. Fmt documents its test code (`HelloWorldClass`, `HelloWorldModule`, `Pootle`) in one paragraph of its landing page, which `exclude_from_docs` names; tbRegExp's `exclude_from_docs` names its private engine module, `StaticRegex`, whose one Public Enum the indexer counts as public; OLEGuids documents each interface's methods on the interface's page. tbRegExp is the first section drafted by the doc-draft workflow ([WIP.Indexer.md](WIP.Indexer.md#draft-and-the-doc-draft-workflow)), then reviewed against the sources, the package's README and VBScript's own **RegExp** under `cscript`. Each published one has a chapter in the book's Packages part. **BigNumberLib and WinReg are not published**: their packages do not compile on BETA 1005, so their pages are kept but excluded in `_config.yml`'s `exclude:` (owner, 2026-10-11), whose comment says how to bring one back.
36+
Thirteen **contributed** packages from TWINSERV have sections under `docs/Reference/Contributed/`: FileProps, Fmt, OLEGuids, WinReg, TwinTimerPackage, TBMANLIB_ListBoxHScroll, TBMANLIB_RES, tbProjPacker, tbRegExp and VBA_JSON complete; AutoCompleteLib, BigNumberLib and VBComDlg their main class only. Fmt documents its test code (`HelloWorldClass`, `HelloWorldModule`, `Pootle`) in one paragraph of its landing page, which `exclude_from_docs` names. tbRegExp's `exclude_from_docs` names its private engine module, `StaticRegex`, and tbProjPacker's its helper modules, `modPackUnpack` and `modWin32`: the indexer counts a Public Enum as public even inside a Private Module, because a built-in package's are reached through its library symbol written with an asterisk (`*WinNativeCommonCtls`, as `ImlDrawConstants` says). By its bare name no such enum is reachable, in a built-in or a contributed package (TB5079 on BETA 1005). OLEGuids documents each interface's methods on the interface's page. tbRegExp is the first section drafted by the doc-draft workflow ([WIP.Indexer.md](WIP.Indexer.md#draft-and-the-doc-draft-workflow)), then reviewed against the sources, the package's README and VBScript's own **RegExp** under `cscript`. Each published one has a chapter in the book's Packages part. **BigNumberLib and WinReg are not published**: their packages do not compile on BETA 1005, so their pages are kept but excluded in `_config.yml`'s `exclude:` (owner, 2026-10-11), whose comment says how to bring one back.
3737

3838
The rest of this file is the maintenance guide for updating existing pages or adding new ones: package surface notes, page conventions, and the integrity check.
3939

‎builder/page-baseline.json‎

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
{
22
"src": "docs",
3-
"pages": 1094,
3+
"pages": 1099,
44
"staticFiles": 794
55
}

‎docs/Reference/Contributed.md‎

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -18,6 +18,7 @@ Each package is versioned apart from twinBASIC, and its section says which versi
1818
- [**OLEGuids**](OLEGuids/) -- OLE and COM interfaces and structures in twinBASIC source, in place of `OLEGuids.tlb`
1919
- [**TBMANLIB_ListBoxHScroll**](TBMANLIB_ListBoxHScroll/) -- a horizontal scroll bar for a **ListBox**
2020
- [**TBMANLIB_RES**](TBMANLIB_RES/) -- resources embedded in an executable, as bytes, strings, hex, Base64 or pictures
21+
- [**tbProjPacker**](tbProjPacker/) -- a `.twinproj` or `.twinpack` file unpacked into a folder of source files, and packed again
2122
- [**tbRegExp**](tbRegExp/) -- regular expressions, in place of VBScript's **RegExp** object
2223
- [**TwinTimerPackage**](TwinTimerPackage/) -- a Win32 timer class that reports the elapsed time
2324
- [**VBA_JSON**](VBA_JSON/) -- JSON parsing and serialization, with UTC and ISO 8601 date conversion
Lines changed: 101 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,101 @@
1+
---
2+
title: Pack
3+
parent: ProjPacker
4+
permalink: /tB/Packages/Contributed/tbProjPacker/ProjPacker/Pack
5+
has_toc: false
6+
---
7+
8+
# Pack
9+
{: .no_toc }
10+
11+
Packs a folder, and everything in it, into a project file.
12+
13+
Syntax: *object*.**Pack** ( *inputDir*, *outputFile* [, *overwrite* [, *logFile* ]] ) **As Boolean**
14+
15+
*object*
16+
: *required* An object expression that evaluates to a **ProjPacker**.
17+
18+
*inputDir*
19+
: *required* A **String**, the folder to pack. It must exist, and it must hold a file named `Settings`.
20+
21+
*outputFile*
22+
: *required* A **String**, the project file to write. The name is used as given: **Pack** adds no extension and checks none.
23+
24+
*overwrite*
25+
: *optional* A **Boolean**. **True** replaces *outputFile* when it exists. The default is **False**, and the call then fails when anything exists at that path.
26+
27+
*logFile*
28+
: *optional* A **String**, the path of a [log file](.#the-log-file) for the lines the call prints. The default is an empty string, which writes no log.
29+
30+
Returns **True** when *outputFile* was written, and **False** when it was not. The method raises no error; [Results and errors](.#results-and-errors) describes how the reason is reported.
31+
32+
## What is packed
33+
34+
The root of the project file is named after the last folder of *inputDir*. Everything in *inputDir* is stored, in all its subfolders: hidden files, empty folders and a `.git` folder included. Keep the project's files in a folder of their own. The top folder of a Git repository would put the repository's own data into the project file.
35+
36+
Version 1.0.5.0 stores each file exactly as it is on disk. It does not convert line endings. The IDE stores `.twin`, `.bas` and `.cls` files with CR LF line endings, so a checkout that has changed them to LF is packed with LF.
37+
38+
Every project that the IDE exports has the folders `Resources`, `Sources`, `ImportedTypeLibraries`, `Miscellaneous` and `Packages`, even when they are empty. Git does not store an empty folder, so a folder checked out from a repository can lack some of them. **Pack** does not add the missing folders. It prints two lines after the summary line, and still returns **True**:
39+
40+
```
41+
note: expected folders not present on disk: Resources, Sources, ImportedTypeLibraries, Miscellaneous, Packages.
42+
twinBASIC should rebuild them on Open Project.
43+
```
44+
45+
## Refusals
46+
47+
**Pack** returns **False** and writes nothing in these cases:
48+
49+
- *inputDir* is not a folder. The line is `Pack failed: Not a directory: ` and the path.
50+
- *outputFile* exists and *overwrite* is **False**. The call makes this check before it reads the folder.
51+
- *inputDir* has no `Settings` file directly in it. The file holds the project's name, references, version and compile options, and a project file packed without it would open without them. A folder named `Settings` does not count, and the file name must be spelled exactly `Settings`. The line begins `Pack failed: Refusing to pack: no 'Settings' file at the top level of`.
52+
53+
The line for the second case reads `Output already exists: ` and the path, then `Refusing to overwrite it. Use the overwrite option (CLI: --force) to replace it.` **Pack** has no `--force`: the option the message means is the *overwrite* argument.
54+
55+
## Replacing a project file
56+
57+
With *overwrite* **True**, **Pack** deletes the existing file just before it writes the new one, after the folder has been read. Do not put *outputFile* inside *inputDir*. A project file left there by an earlier call is packed into the new one, and the file grows with each call.
58+
59+
## Output
60+
61+
On success **Pack** prints one summary line:
62+
63+
```
64+
Exported "MyApp-src" -> C:\Temp\MyApp.twinproj (170594 bytes, 18 files, 6 directories)
65+
```
66+
67+
The name is the root's name, the last folder of *inputDir*. The byte count is the size of the new file, and the file and folder counts do not include the root.
68+
69+
> [!NOTE]
70+
> The summary line of **Pack** begins `Exported`, and that of [**Unpack**](Unpack) begins `Imported`. The Import/export tool names the two directions the other way round: its `import` command packs a folder and its `export` command unpacks a project.
71+
72+
## Example
73+
74+
This example packs a folder into a project file in the TEMP folder and replaces the file if it exists.
75+
76+
```tb check_build
77+
Dim pp As New ProjPacker
78+
Dim src As String, outFile As String
79+
80+
src = Environ$("TEMP") & "\MyApp-src"
81+
outFile = Environ$("TEMP") & "\MyApp.twinproj"
82+
83+
If pp.Pack(src, outFile, True) Then
84+
Debug.Print "Packed " & outFile
85+
Else
86+
Debug.Print "Nothing was packed"
87+
End If
88+
```
89+
90+
Without *overwrite*, a second call with the same *outFile* fails and prints:
91+
92+
```
93+
Pack failed: Output already exists: "C:\Temp\MyApp.twinproj". Refusing to overwrite it. Use the overwrite option (CLI: --force) to replace it.
94+
```
95+
96+
## See Also
97+
98+
- [Unpack](Unpack) method -- unpacks a project file into a folder
99+
- [Test](Test) method -- runs the package's tests
100+
- [ProjPacker](./) class -- overview, the log file and the paths
101+
- [Import/export tool](../../../../../Features/Packages/Import-Export-Tool) -- the command-line programs that do the same
Lines changed: 94 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,94 @@
1+
---
2+
title: Test
3+
parent: ProjPacker
4+
permalink: /tB/Packages/Contributed/tbProjPacker/ProjPacker/Test
5+
has_toc: false
6+
---
7+
8+
# Test
9+
{: .no_toc }
10+
11+
Runs the package's own tests and returns whether they all passed.
12+
13+
Syntax: *object*.**Test** ( *samplePath* [, *logFile* ] ) **As Boolean**
14+
15+
*object*
16+
: *required* An object expression that evaluates to a **ProjPacker**.
17+
18+
*samplePath*
19+
: *required* A **String**, the path of a `.twinproj` or `.twinpack` file for the four tests that work on a real project. An empty string skips those four tests. A path to a file that does not exist makes the call fail.
20+
21+
*logFile*
22+
: *optional* A **String**, the path of a [log file](.#the-log-file) for the lines the call prints. The default is an empty string, which writes no log.
23+
24+
Returns **True** when no test failed, and **False** when a test failed or *samplePath* names a file that does not exist. A skipped test is not a failure. The method raises no error; [Results and errors](.#results-and-errors) describes how the reason is reported. The sample file is never changed.
25+
26+
## What the tests check
27+
28+
There are 23 tests. Each runs on its own, so a failure in one does not stop the others. The tests work in a new folder, named `impexp-test-` and a number, in the folder that the `TEMP` environment variable names. The folder is deleted when the tests end.
29+
30+
Four tests need the sample file:
31+
32+
- Parsing the sample, then writing the tree and parsing that copy, gives the same project name, file count and folder count.
33+
- A round trip in memory keeps every path and the content of every file.
34+
- Writing, parsing and writing again gives the same bytes both times.
35+
- Unpacking the sample, packing the folder and unpacking that file gives two folders with the same files and the same bytes.
36+
37+
Nineteen tests need no sample:
38+
39+
- **File format (6).** An empty project, a project with one file, the flags of the entries, Unicode names with their sort order, a file with a wrong magic number, and a file cut short.
40+
- **Long path (1).** A file whose path is longer than 260 characters survives a pack and an unpack.
41+
- **Pack (4).** [**Pack**](Pack) refuses a folder with no `Settings` file and accepts one with it. It refuses to replace an existing file, and replaces it when *overwrite* is **True**.
42+
- **Unpack with *cleanFirst* (6).** [**Unpack**](Unpack) removes leftover files, counts the levels of a path correctly, refuses a folder that has no `Settings` file and a folder whose `Settings` is a folder, and accepts a project folder and an empty folder.
43+
- **Other refusals (2).** **Pack** refuses a folder whose `Settings` is a folder. **Unpack** reports a project file that does not exist.
44+
45+
## Output
46+
47+
**Test** prints a heading, a line for each test and a summary. A test line is `[PASS]`, `[FAIL]` or `[SKIP]` and the test's name. A failed test is followed by a line with the reason. The first test also prints an `[INFO]` line with the project's name, its number of files and folders, and its size. The summary counts the passed tests against the passed and failed ones; skipped tests are not counted.
48+
49+
This is the output with a sample file, with the paths shortened:
50+
51+
```
52+
Self-test workdir: C:\...\impexp-test-78561008
53+
Sample: C:\...\imagestrip.twinproj
54+
55+
[INFO] root "imagestrip", 18 files, 6 directories, 170595 bytes
56+
[PASS] Parse sample (invariants + re-parse consistency)
57+
[PASS] In-memory round-trip (parse -> serialize -> re-parse)
58+
... 21 more lines, one for each of the other tests ...
59+
60+
23/23 tests passed.
61+
```
62+
63+
Without a sample, the four sample tests print `[SKIP]` and the summary ends with the number skipped:
64+
65+
```
66+
19/19 tests passed (4 skipped -- pass a .twinproj or .twinpack path to run them).
67+
```
68+
69+
A *samplePath* that does not exist prints `Sample not found: ` and the path. No test runs.
70+
71+
> [!NOTE]
72+
> An empty *samplePath* does not make the method fail. With 19 of the 19 tests that run passed and 4 skipped, it returns **True**. Pass a project file to run all 23.
73+
74+
## Example
75+
76+
This example runs all the tests against a project file, and writes the lines to a log.
77+
78+
```tb check_build
79+
Dim pp As New ProjPacker
80+
Dim ok As Boolean
81+
82+
ok = pp.Test(App.Path & "\MyApp.twinproj", Environ$("TEMP") & "\selftest.log")
83+
If ok Then
84+
Debug.Print "All tests passed"
85+
Else
86+
Debug.Print "A test failed; see selftest.log"
87+
End If
88+
```
89+
90+
## See Also
91+
92+
- [Pack](Pack) method -- packs a folder into a project file
93+
- [Unpack](Unpack) method -- unpacks a project file into a folder
94+
- [ProjPacker](./) class -- overview, the log file and the paths

0 commit comments

Comments
 (0)