entangled-cli 2.1.6__tar.gz → 2.1.8__tar.gz

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (42) hide show
  1. {entangled_cli-2.1.6 → entangled_cli-2.1.8}/PKG-INFO +53 -3
  2. {entangled_cli-2.1.6 → entangled_cli-2.1.8}/README.md +52 -2
  3. {entangled_cli-2.1.6 → entangled_cli-2.1.8}/entangled/commands/__init__.py +0 -1
  4. {entangled_cli-2.1.6 → entangled_cli-2.1.8}/entangled/commands/tangle.py +16 -8
  5. {entangled_cli-2.1.6 → entangled_cli-2.1.8}/entangled/filedb.py +11 -0
  6. {entangled_cli-2.1.6 → entangled_cli-2.1.8}/entangled/hooks/task.py +6 -2
  7. {entangled_cli-2.1.6 → entangled_cli-2.1.8}/entangled/transaction.py +36 -5
  8. {entangled_cli-2.1.6 → entangled_cli-2.1.8}/pyproject.toml +1 -1
  9. {entangled_cli-2.1.6 → entangled_cli-2.1.8}/LICENSE +0 -0
  10. {entangled_cli-2.1.6 → entangled_cli-2.1.8}/entangled/__init__.py +0 -0
  11. {entangled_cli-2.1.6 → entangled_cli-2.1.8}/entangled/code_reader.py +0 -0
  12. {entangled_cli-2.1.6 → entangled_cli-2.1.8}/entangled/commands/brei.py +0 -0
  13. {entangled_cli-2.1.6 → entangled_cli-2.1.8}/entangled/commands/new.py +0 -0
  14. {entangled_cli-2.1.6 → entangled_cli-2.1.8}/entangled/commands/status.py +0 -0
  15. {entangled_cli-2.1.6 → entangled_cli-2.1.8}/entangled/commands/stitch.py +0 -0
  16. {entangled_cli-2.1.6 → entangled_cli-2.1.8}/entangled/commands/sync.py +0 -0
  17. {entangled_cli-2.1.6 → entangled_cli-2.1.8}/entangled/commands/watch.py +0 -0
  18. {entangled_cli-2.1.6 → entangled_cli-2.1.8}/entangled/config/__init__.py +0 -0
  19. {entangled_cli-2.1.6 → entangled_cli-2.1.8}/entangled/config/language.py +0 -0
  20. {entangled_cli-2.1.6 → entangled_cli-2.1.8}/entangled/config/templates.py +0 -0
  21. {entangled_cli-2.1.6 → entangled_cli-2.1.8}/entangled/config/version.py +0 -0
  22. {entangled_cli-2.1.6 → entangled_cli-2.1.8}/entangled/construct.py +0 -0
  23. {entangled_cli-2.1.6 → entangled_cli-2.1.8}/entangled/document.py +0 -0
  24. {entangled_cli-2.1.6 → entangled_cli-2.1.8}/entangled/errors/__init__.py +0 -0
  25. {entangled_cli-2.1.6 → entangled_cli-2.1.8}/entangled/errors/internal.py +0 -0
  26. {entangled_cli-2.1.6 → entangled_cli-2.1.8}/entangled/errors/user.py +0 -0
  27. {entangled_cli-2.1.6 → entangled_cli-2.1.8}/entangled/hooks/__init__.py +0 -0
  28. {entangled_cli-2.1.6 → entangled_cli-2.1.8}/entangled/hooks/base.py +0 -0
  29. {entangled_cli-2.1.6 → entangled_cli-2.1.8}/entangled/hooks/build.py +0 -0
  30. {entangled_cli-2.1.6 → entangled_cli-2.1.8}/entangled/hooks/quarto_attributes.py +0 -0
  31. {entangled_cli-2.1.6 → entangled_cli-2.1.8}/entangled/hooks/shebang.py +0 -0
  32. {entangled_cli-2.1.6 → entangled_cli-2.1.8}/entangled/logging.py +0 -0
  33. {entangled_cli-2.1.6 → entangled_cli-2.1.8}/entangled/main.py +0 -0
  34. {entangled_cli-2.1.6 → entangled_cli-2.1.8}/entangled/markdown_reader.py +0 -0
  35. {entangled_cli-2.1.6 → entangled_cli-2.1.8}/entangled/parsing.py +0 -0
  36. {entangled_cli-2.1.6 → entangled_cli-2.1.8}/entangled/properties.py +0 -0
  37. {entangled_cli-2.1.6 → entangled_cli-2.1.8}/entangled/py.typed +0 -0
  38. {entangled_cli-2.1.6 → entangled_cli-2.1.8}/entangled/status.py +0 -0
  39. {entangled_cli-2.1.6 → entangled_cli-2.1.8}/entangled/tangle.py +0 -0
  40. {entangled_cli-2.1.6 → entangled_cli-2.1.8}/entangled/text_location.py +0 -0
  41. {entangled_cli-2.1.6 → entangled_cli-2.1.8}/entangled/utility.py +0 -0
  42. {entangled_cli-2.1.6 → entangled_cli-2.1.8}/entangled/version.py +0 -0
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.1
2
2
  Name: entangled-cli
3
- Version: 2.1.6
3
+ Version: 2.1.8
4
4
  Summary: Literate Programming toolbox
5
5
  Home-page: https://entangled.github.io/
6
6
  License: Apache 2
@@ -26,6 +26,7 @@ Project-URL: Repository, https://github.com/entangled/entangled.py
26
26
  Description-Content-Type: text/markdown
27
27
 
28
28
  # Entangled
29
+
29
30
  [![Upload Python Package](https://github.com/entangled/entangled.py/actions/workflows/deploy.yml/badge.svg)](https://github.com/entangled/entangled.py/actions/workflows/deploy.yml)
30
31
  [![Python package](https://github.com/entangled/entangled.py/actions/workflows/python-package.yml/badge.svg)](https://github.com/entangled/entangled.py/actions/workflows/python-package.yml)
31
32
 
@@ -43,6 +44,7 @@ We’re trying to increase the visibility of Entangled. If you like Entangled, p
43
44
  ```
44
45
 
45
46
  ## Get started
47
+
46
48
  To install Entangled, all you need is a Python (version ≥3.11) installation. If you use [`poetry`](https://python-poetry.org), and you start a new project,
47
49
 
48
50
  ```
@@ -59,6 +61,7 @@ pip install entangled-cli
59
61
  ```
60
62
 
61
63
  ## Use
64
+
62
65
  Run the `entangled watch` daemon in the root of your project folder. By default all Markdown files are monitored for fenced code blocks like so:
63
66
 
64
67
  ~~~markdown
@@ -70,6 +73,7 @@ Run the `entangled watch` daemon in the root of your project folder. By default
70
73
  The syntax of code block properties is the same as CSS properties: `#hello` gives the block the `hello` identifier, `.rust` adds the `rust` class and the `file` attribute is set to `src/world.rs` (quotes are optional). For Entangled to know how to tangle this block, you need to specify a language and a target file. However, now comes the cool stuff. We can split our code in meaningful components by cross-refrences.
71
74
 
72
75
  ### Hello World in C++
76
+
73
77
  The combined code-blocks in this example compose a compilable source code for "Hello World". For didactic reasons we don't always give the listing of an entire source file in one go. In stead, we use a system of references known as *noweb* (after Ramsey 1994).
74
78
 
75
79
  Inside source fragments you may encounter a line with `<<...>>` marks like,
@@ -113,6 +117,7 @@ return EXIT_SUCCESS;
113
117
  These blocks of code can be *tangled* into source files.
114
118
 
115
119
  ### Configuring
120
+
116
121
  Entangled is configured by putting a `entangled.toml` in the root of your project.
117
122
 
118
123
  ```toml
@@ -176,7 +181,38 @@ identifiers = ["java"]
176
181
  comment = { open = "//" }
177
182
  ```
178
183
 
184
+ ## Working with Git
185
+
186
+ When using Entangled in conjunction with Git, there are a few tricks that you may want to know about.
187
+
188
+ ### Restoring files when both Markdown and code have changed
189
+
190
+ When you edited both Markdown and code without the daemon running, you may need to do some tricks to get back into a consistent state.
191
+
192
+ ```shell
193
+ git add .
194
+ git commit -m 'fixed everything' # save everything you did
195
+ entangled tangle --force # overwrites some changes you made
196
+ git restore src/brilliant_code.c # retrieve from latest commit
197
+ entangled stitch # apply changes back to markdown
198
+ git add .
199
+ git commit --amend # amend your commit to perfection
200
+ ```
201
+
202
+ There may be better/faster ways to do this.
203
+
204
+ ### Entangled conflicts after merging branches
205
+
206
+ Entangled can get confused when you merge, and there is a conflict on `.entangled/filedb.json`. This file keeps track of which files are sources for Entangled and which ones are generated by Entangled. That way, Entangled will never overwrite files it isn't supposed to, and the other way around, when you rename a target, the old one gets removed. It is very hard to merge this file though. When you need to, you can regenerate this file using:
207
+
208
+ ```shell
209
+ entangled tangle -r
210
+ ```
211
+
212
+ This will perform the tangle as if it is the first time, but it won't actually write files.
213
+
179
214
  ## Hooks
215
+
180
216
  Entangled has a system of *hooks*: these add actions to the tangling process:
181
217
 
182
218
  - `build` trigger actions in a generated `Makefile`
@@ -185,6 +221,7 @@ Entangled has a system of *hooks*: these add actions to the tangling process:
185
221
  - `shebang` takes the first line if it starts with `#!` and puts it at the top of the file.
186
222
 
187
223
  ### `build` hook
224
+
188
225
  You can enable this hook in `entangled.toml`:
189
226
 
190
227
  ```toml
@@ -253,6 +290,7 @@ plot.savefig("fig/plot.svg")
253
290
  The snippet for generating the data is given as a dependency for that data; to generate the figure, both `result.csv` and the code snippet are dependencies.
254
291
 
255
292
  ### `quarto_attributes` hook
293
+
256
294
  Sometimes using the `build` hook (or the `brei` hook, see below), leads to long header lines. It is then better to specify attributes in a header section of your code. The Quarto project came up with a syntax, having the header be indicated by a comment with a vertical bar, e.g. `#|` or `//|` etc. The `quarto_attributes` hook reads those attributes and adds them to the properties of the code block.
257
295
 
258
296
  Example with the `brei` hook:
@@ -301,6 +339,7 @@ if __name__ == "__main__":
301
339
  The `id` attribute is reserved for the code's identifier (normally indicated with `#`) and the `classes` attribute can be used to indicate a list of classes in addition to the language class already given.
302
340
 
303
341
  ## Brei
342
+
304
343
  Entangled has a small build engine (similar to GNU Make) embedded, called Brei. You may give it a list of tasks (specified in TOML) that may depend on one another. Brei will run these when dependencies are newer than the target. Execution is lazy and in parallel. Brei supports:
305
344
 
306
345
  - Running tasks by passing a script to any configured interpreter, e.g. Bash, Python, Lua etc.
@@ -313,6 +352,7 @@ Entangled has a small build engine (similar to GNU Make) embedded, called Brei.
313
352
  Brei is available as a separate package, see [the Brei documentation](https://entangled.github.io/brei).
314
353
 
315
354
  ### Examples
355
+
316
356
  To write out "Hello, World!" to a file `msg.txt`, we may do the following,
317
357
 
318
358
  ```toml
@@ -351,7 +391,8 @@ requires = ["msg.txt"]
351
391
  ```
352
392
 
353
393
  ### The `brei` hook
354
- The following example uses both `brei` and `quatro_attributes` hooks. To add a Brei task, tag a code block with the `.task` class.
394
+
395
+ The following example uses both `brei` and `quatro_attributes` hooks. To add a Brei task, tag a code block with the `.task` class.
355
396
 
356
397
  ~~~markdown
357
398
  First we generate some data.
@@ -403,9 +444,11 @@ entangled brei figures
403
444
  You can use `${variable}` syntax inside Brei tasks just as you would in a stand-alone Brei script.
404
445
 
405
446
  ## Support for Document Generators
447
+
406
448
  Entangled has been used successfully with the following document generators. Note that some of these examples were built using older versions of Entangled, but they should work just the same.
407
449
 
408
450
  ### Pandoc
451
+
409
452
  [Pandoc](https://pandoc.org/) is a very versatile tool for converting documents in any format. It specifically has very wide support for different forms of Markdown syntax out in the wild, including a filter system that lets you extend the workings of Pandoc. Those filters can be written in any language through an API, for instance Python filters can be written using `panflute`, but there is also native support for Lua.
410
453
 
411
454
  To work with Entangled style literate documents, there is a set of [Pandoc filters](https://github.com/entangled/filters) available. The major downside of Pandoc, is that it offers no help in making your output HTML look beautiful. One option is to use the [Bootstrap template](https://github.com/entangled/bootstrap), but you may wan't to try out others as well, or design your own. These days a lot can be done with a single well designed CSS file.
@@ -420,6 +463,7 @@ To work with Entangled style literate documents, there is a set of [Pandoc filte
420
463
  Example: [Hello World in C++](https://entangled.github.io/examples/hello-world.html)
421
464
 
422
465
  ### MkDocs
466
+
423
467
  [MkDocs](https://www.mkdocs.org/) is specifically taylored towards converting Markdown into good looking, easy to navigate HTML, especially when used in combination with the [`mkdocs-material`](https://squidfunk.github.io/mkdocs-material/) theme. To use Entangled style code blocks with MkDocs, you'll need to install the [`mkdocs-entangled-plugin`](https://github.com/entangled/mkdocs-plugin) as well.
424
468
 
425
469
  - :heavy_plus_sign: specifically designed for Markdown to HTML, i.e. software documentation
@@ -431,6 +475,7 @@ Example: [Hello World in C++](https://entangled.github.io/examples/hello-world.h
431
475
  Example: TBD
432
476
 
433
477
  ### Typst
478
+
434
479
  [Typst](https://typst.app/) has a syntax that is similar to Markdown when it comes to code blocks. Set the code block markers in `entangled.toml` like so:
435
480
 
436
481
  ```toml
@@ -444,27 +489,32 @@ close="^(?P<indent>\\s*)```\\s*$"
444
489
  ```
445
490
 
446
491
  ### Documenter.jl
492
+
447
493
  [Documenter.jl]() is the standard tool to write Julia documention in. It has internal support for evaluating code block contents.
448
494
 
449
495
  Example: [Intro to code generation in Julia](https://jhidding.github.io/MacroExercises.jl/dev/)
450
496
 
451
497
  ### PDoc
498
+
452
499
  [PDoc]() is a tool for documenting smaller Python projects. It grabs all documentation from the doc-strings in your Python library and generates a page from that. To have it include its own literate source, I had to use some very ugly hacks.
453
500
 
454
501
  Example: [check-deps, a Universal dependency checker in Python](https://jhidding.github.io/check-deps/checkdeps.html)
455
502
 
456
503
  ### Docsify
504
+
457
505
  [Docsify](https://docsify.js.org/#/) serves the markdown files and does the conversion to HTML in a Javascript library (in browser).
458
506
 
459
507
  Example: [Guide to C++ on the web through WASM](https://nlesc-jcer.github.io/cpp2wasm/#/)
460
508
 
461
509
  ## History
510
+
462
511
  This is a rewrite of Entangled in Python. Older versions were written in Haskell. The rewrite in Python was motivated by ease of installation, larger community and quite frankly, a fit of mental derangement.
463
512
 
464
513
  ## Contributing
514
+
465
515
  If you have an idea for improving Entangled, please file an issue before creating a pull request. Code in this repository is formatted using `black` and type checked using `mypy`.
466
516
 
467
517
  ## License
468
- Copyright 2023 Netherlands eScience Center, written by Johan Hidding, licensed under the Apache 2 license, see LICENSE.
469
518
 
519
+ Copyright 2023 Netherlands eScience Center, written by Johan Hidding, licensed under the Apache 2 license, see LICENSE.
470
520
 
@@ -1,4 +1,5 @@
1
1
  # Entangled
2
+
2
3
  [![Upload Python Package](https://github.com/entangled/entangled.py/actions/workflows/deploy.yml/badge.svg)](https://github.com/entangled/entangled.py/actions/workflows/deploy.yml)
3
4
  [![Python package](https://github.com/entangled/entangled.py/actions/workflows/python-package.yml/badge.svg)](https://github.com/entangled/entangled.py/actions/workflows/python-package.yml)
4
5
 
@@ -16,6 +17,7 @@ We’re trying to increase the visibility of Entangled. If you like Entangled, p
16
17
  ```
17
18
 
18
19
  ## Get started
20
+
19
21
  To install Entangled, all you need is a Python (version &ge;3.11) installation. If you use [`poetry`](https://python-poetry.org), and you start a new project,
20
22
 
21
23
  ```
@@ -32,6 +34,7 @@ pip install entangled-cli
32
34
  ```
33
35
 
34
36
  ## Use
37
+
35
38
  Run the `entangled watch` daemon in the root of your project folder. By default all Markdown files are monitored for fenced code blocks like so:
36
39
 
37
40
  ~~~markdown
@@ -43,6 +46,7 @@ Run the `entangled watch` daemon in the root of your project folder. By default
43
46
  The syntax of code block properties is the same as CSS properties: `#hello` gives the block the `hello` identifier, `.rust` adds the `rust` class and the `file` attribute is set to `src/world.rs` (quotes are optional). For Entangled to know how to tangle this block, you need to specify a language and a target file. However, now comes the cool stuff. We can split our code in meaningful components by cross-refrences.
44
47
 
45
48
  ### Hello World in C++
49
+
46
50
  The combined code-blocks in this example compose a compilable source code for "Hello World". For didactic reasons we don't always give the listing of an entire source file in one go. In stead, we use a system of references known as *noweb* (after Ramsey 1994).
47
51
 
48
52
  Inside source fragments you may encounter a line with `<<...>>` marks like,
@@ -86,6 +90,7 @@ return EXIT_SUCCESS;
86
90
  These blocks of code can be *tangled* into source files.
87
91
 
88
92
  ### Configuring
93
+
89
94
  Entangled is configured by putting a `entangled.toml` in the root of your project.
90
95
 
91
96
  ```toml
@@ -149,7 +154,38 @@ identifiers = ["java"]
149
154
  comment = { open = "//" }
150
155
  ```
151
156
 
157
+ ## Working with Git
158
+
159
+ When using Entangled in conjunction with Git, there are a few tricks that you may want to know about.
160
+
161
+ ### Restoring files when both Markdown and code have changed
162
+
163
+ When you edited both Markdown and code without the daemon running, you may need to do some tricks to get back into a consistent state.
164
+
165
+ ```shell
166
+ git add .
167
+ git commit -m 'fixed everything' # save everything you did
168
+ entangled tangle --force # overwrites some changes you made
169
+ git restore src/brilliant_code.c # retrieve from latest commit
170
+ entangled stitch # apply changes back to markdown
171
+ git add .
172
+ git commit --amend # amend your commit to perfection
173
+ ```
174
+
175
+ There may be better/faster ways to do this.
176
+
177
+ ### Entangled conflicts after merging branches
178
+
179
+ Entangled can get confused when you merge, and there is a conflict on `.entangled/filedb.json`. This file keeps track of which files are sources for Entangled and which ones are generated by Entangled. That way, Entangled will never overwrite files it isn't supposed to, and the other way around, when you rename a target, the old one gets removed. It is very hard to merge this file though. When you need to, you can regenerate this file using:
180
+
181
+ ```shell
182
+ entangled tangle -r
183
+ ```
184
+
185
+ This will perform the tangle as if it is the first time, but it won't actually write files.
186
+
152
187
  ## Hooks
188
+
153
189
  Entangled has a system of *hooks*: these add actions to the tangling process:
154
190
 
155
191
  - `build` trigger actions in a generated `Makefile`
@@ -158,6 +194,7 @@ Entangled has a system of *hooks*: these add actions to the tangling process:
158
194
  - `shebang` takes the first line if it starts with `#!` and puts it at the top of the file.
159
195
 
160
196
  ### `build` hook
197
+
161
198
  You can enable this hook in `entangled.toml`:
162
199
 
163
200
  ```toml
@@ -226,6 +263,7 @@ plot.savefig("fig/plot.svg")
226
263
  The snippet for generating the data is given as a dependency for that data; to generate the figure, both `result.csv` and the code snippet are dependencies.
227
264
 
228
265
  ### `quarto_attributes` hook
266
+
229
267
  Sometimes using the `build` hook (or the `brei` hook, see below), leads to long header lines. It is then better to specify attributes in a header section of your code. The Quarto project came up with a syntax, having the header be indicated by a comment with a vertical bar, e.g. `#|` or `//|` etc. The `quarto_attributes` hook reads those attributes and adds them to the properties of the code block.
230
268
 
231
269
  Example with the `brei` hook:
@@ -274,6 +312,7 @@ if __name__ == "__main__":
274
312
  The `id` attribute is reserved for the code's identifier (normally indicated with `#`) and the `classes` attribute can be used to indicate a list of classes in addition to the language class already given.
275
313
 
276
314
  ## Brei
315
+
277
316
  Entangled has a small build engine (similar to GNU Make) embedded, called Brei. You may give it a list of tasks (specified in TOML) that may depend on one another. Brei will run these when dependencies are newer than the target. Execution is lazy and in parallel. Brei supports:
278
317
 
279
318
  - Running tasks by passing a script to any configured interpreter, e.g. Bash, Python, Lua etc.
@@ -286,6 +325,7 @@ Entangled has a small build engine (similar to GNU Make) embedded, called Brei.
286
325
  Brei is available as a separate package, see [the Brei documentation](https://entangled.github.io/brei).
287
326
 
288
327
  ### Examples
328
+
289
329
  To write out "Hello, World!" to a file `msg.txt`, we may do the following,
290
330
 
291
331
  ```toml
@@ -324,7 +364,8 @@ requires = ["msg.txt"]
324
364
  ```
325
365
 
326
366
  ### The `brei` hook
327
- The following example uses both `brei` and `quatro_attributes` hooks. To add a Brei task, tag a code block with the `.task` class.
367
+
368
+ The following example uses both `brei` and `quatro_attributes` hooks. To add a Brei task, tag a code block with the `.task` class.
328
369
 
329
370
  ~~~markdown
330
371
  First we generate some data.
@@ -376,9 +417,11 @@ entangled brei figures
376
417
  You can use `${variable}` syntax inside Brei tasks just as you would in a stand-alone Brei script.
377
418
 
378
419
  ## Support for Document Generators
420
+
379
421
  Entangled has been used successfully with the following document generators. Note that some of these examples were built using older versions of Entangled, but they should work just the same.
380
422
 
381
423
  ### Pandoc
424
+
382
425
  [Pandoc](https://pandoc.org/) is a very versatile tool for converting documents in any format. It specifically has very wide support for different forms of Markdown syntax out in the wild, including a filter system that lets you extend the workings of Pandoc. Those filters can be written in any language through an API, for instance Python filters can be written using `panflute`, but there is also native support for Lua.
383
426
 
384
427
  To work with Entangled style literate documents, there is a set of [Pandoc filters](https://github.com/entangled/filters) available. The major downside of Pandoc, is that it offers no help in making your output HTML look beautiful. One option is to use the [Bootstrap template](https://github.com/entangled/bootstrap), but you may wan't to try out others as well, or design your own. These days a lot can be done with a single well designed CSS file.
@@ -393,6 +436,7 @@ To work with Entangled style literate documents, there is a set of [Pandoc filte
393
436
  Example: [Hello World in C++](https://entangled.github.io/examples/hello-world.html)
394
437
 
395
438
  ### MkDocs
439
+
396
440
  [MkDocs](https://www.mkdocs.org/) is specifically taylored towards converting Markdown into good looking, easy to navigate HTML, especially when used in combination with the [`mkdocs-material`](https://squidfunk.github.io/mkdocs-material/) theme. To use Entangled style code blocks with MkDocs, you'll need to install the [`mkdocs-entangled-plugin`](https://github.com/entangled/mkdocs-plugin) as well.
397
441
 
398
442
  - :heavy_plus_sign: specifically designed for Markdown to HTML, i.e. software documentation
@@ -404,6 +448,7 @@ Example: [Hello World in C++](https://entangled.github.io/examples/hello-world.h
404
448
  Example: TBD
405
449
 
406
450
  ### Typst
451
+
407
452
  [Typst](https://typst.app/) has a syntax that is similar to Markdown when it comes to code blocks. Set the code block markers in `entangled.toml` like so:
408
453
 
409
454
  ```toml
@@ -417,26 +462,31 @@ close="^(?P<indent>\\s*)```\\s*$"
417
462
  ```
418
463
 
419
464
  ### Documenter.jl
465
+
420
466
  [Documenter.jl]() is the standard tool to write Julia documention in. It has internal support for evaluating code block contents.
421
467
 
422
468
  Example: [Intro to code generation in Julia](https://jhidding.github.io/MacroExercises.jl/dev/)
423
469
 
424
470
  ### PDoc
471
+
425
472
  [PDoc]() is a tool for documenting smaller Python projects. It grabs all documentation from the doc-strings in your Python library and generates a page from that. To have it include its own literate source, I had to use some very ugly hacks.
426
473
 
427
474
  Example: [check-deps, a Universal dependency checker in Python](https://jhidding.github.io/check-deps/checkdeps.html)
428
475
 
429
476
  ### Docsify
477
+
430
478
  [Docsify](https://docsify.js.org/#/) serves the markdown files and does the conversion to HTML in a Javascript library (in browser).
431
479
 
432
480
  Example: [Guide to C++ on the web through WASM](https://nlesc-jcer.github.io/cpp2wasm/#/)
433
481
 
434
482
  ## History
483
+
435
484
  This is a rewrite of Entangled in Python. Older versions were written in Haskell. The rewrite in Python was motivated by ease of installation, larger community and quite frankly, a fit of mental derangement.
436
485
 
437
486
  ## Contributing
487
+
438
488
  If you have an idea for improving Entangled, please file an issue before creating a pull request. Code in this repository is formatted using `black` and type checked using `mypy`.
439
489
 
440
490
  ## License
441
- Copyright 2023 Netherlands eScience Center, written by Johan Hidding, licensed under the Apache 2 license, see LICENSE.
442
491
 
492
+ Copyright 2023 Netherlands eScience Center, written by Johan Hidding, licensed under the Apache 2 license, see LICENSE.
@@ -6,7 +6,6 @@ from .tangle import tangle
6
6
  from .watch import watch
7
7
  from .brei import brei
8
8
 
9
-
10
9
  __all__ = [
11
10
  "new",
12
11
  "brei",
@@ -12,6 +12,17 @@ from ..hooks import get_hooks
12
12
  from ..errors.user import UserError
13
13
 
14
14
 
15
+ def get_input_files() -> list[Path]:
16
+ include_file_list = chain.from_iterable(map(Path(".").glob, config.watch_list))
17
+ exclude_file_list = list(
18
+ chain.from_iterable(map(Path(".").glob, config.ignore_list))
19
+ )
20
+ input_file_list = [
21
+ path for path in include_file_list if not path in exclude_file_list
22
+ ]
23
+ return input_file_list
24
+
25
+
15
26
  @argh.arg(
16
27
  "-a",
17
28
  "--annotate",
@@ -20,7 +31,8 @@ from ..errors.user import UserError
20
31
  )
21
32
  @argh.arg("--force", help="force overwrite on conflict")
22
33
  @argh.arg("-s", "--show", help="only show, don't act")
23
- def tangle(*, annotate: Optional[str] = None, force: bool = False, show: bool = False):
34
+ @argh.arg("-r", "--reset-db", help="resets database")
35
+ def tangle(*, annotate: Optional[str] = None, force: bool = False, show: bool = False, reset_db = False):
24
36
  """Tangle codes from Markdown"""
25
37
  config.read()
26
38
 
@@ -33,13 +45,7 @@ def tangle(*, annotate: Optional[str] = None, force: bool = False, show: bool =
33
45
  else:
34
46
  annotation_method = AnnotationMethod[annotate.upper()]
35
47
 
36
- include_file_list = chain.from_iterable(map(Path(".").glob, config.watch_list))
37
- exclude_file_list = list(
38
- chain.from_iterable(map(Path(".").glob, config.ignore_list))
39
- )
40
- input_file_list = [
41
- path for path in include_file_list if not path in exclude_file_list
42
- ]
48
+ input_file_list = get_input_files()
43
49
 
44
50
  refs = ReferenceMap()
45
51
  hooks = get_hooks()
@@ -47,6 +53,8 @@ def tangle(*, annotate: Optional[str] = None, force: bool = False, show: bool =
47
53
 
48
54
  if show:
49
55
  mode = TransactionMode.SHOW
56
+ elif reset_db:
57
+ mode = TransactionMode.RESETDB
50
58
  elif force:
51
59
  mode = TransactionMode.FORCE
52
60
  else:
@@ -103,8 +103,19 @@ class FileDB:
103
103
  set(map(Path, raw["target"])),
104
104
  )
105
105
 
106
+ def clear(self):
107
+ self._files = {}
108
+ self._source = set()
109
+ self._target = set()
110
+
106
111
  @property
107
112
  def managed(self) -> set[Path]:
113
+ """List all managed files. These are files that can be reconstructed
114
+ from the sources, at least when things are in a consistent state.
115
+
116
+ For example: markdown sources cannot be reconstructed, so are not
117
+ listed here. However, generated code is first constructed from
118
+ the markdown, so is considered to be managed."""
108
119
  return self._target
109
120
 
110
121
  def write(self):
@@ -18,6 +18,10 @@ log = logger()
18
18
 
19
19
 
20
20
  def ensure_list(strs: str | list[str]) -> list[str]:
21
+ """Some options may be given either as a list or as a single string,
22
+ where the string is supposed to have a whitespace separated list.
23
+ This function converts from either to a list of strings.
24
+ """
21
25
  if isinstance(strs, str):
22
26
  return strs.split()
23
27
  elif isinstance(strs, list):
@@ -87,8 +91,8 @@ class Hook(HookBase):
87
91
  }
88
92
 
89
93
  record["runner"] = record["runner"] or runner
90
- record["creates"] = ensure_list(record["creates"].split()) if record["creates"] else None
91
- record["requires"] = ensure_list(record["requires"].split()) if record["requires"] else None
94
+ record["creates"] = ensure_list(record["creates"]) if record["creates"] else None
95
+ record["requires"] = ensure_list(record["requires"]) if record["requires"] else None
92
96
  record["ref"] = ref
93
97
 
94
98
  log.debug(f"task: {record}")
@@ -30,6 +30,10 @@ class Action:
30
30
  a file that is not managed by Entangled."""
31
31
  raise NotImplementedError()
32
32
 
33
+ def add_to_db(self, _: FileDB):
34
+ """Only perform the corresponding database action."""
35
+ raise NotImplementedError()
36
+
33
37
  def run(self, _: FileDB):
34
38
  """Run the action, if `interact` is `True` then confirmation is
35
39
  asked in case of a conflict."""
@@ -54,6 +58,11 @@ class Create(Action):
54
58
  return f"{self.target} is not managed by Entangled"
55
59
  return None
56
60
 
61
+ def add_to_db(self, db: FileDB):
62
+ db.update(self.target, self.sources)
63
+ if self.sources != []:
64
+ db.managed.add(self.target)
65
+
57
66
  def run(self, db: FileDB):
58
67
  self.target.parent.mkdir(parents=True, exist_ok=True)
59
68
  # Write to tmp file then replace with file name
@@ -67,9 +76,7 @@ class Create(Action):
67
76
  os.chmod(f.name, self.mode)
68
77
  os.fsync(f.fileno())
69
78
  os.replace(f.name, self.target)
70
- db.update(self.target, self.sources)
71
- if self.sources != []:
72
- db.managed.add(self.target)
79
+ self.add_to_db(db)
73
80
 
74
81
  def __str__(self):
75
82
  return f"create `{self.target}`"
@@ -98,6 +105,9 @@ class Write(Action):
98
105
  return f"`{self.target}` seems to be newer than `{newest_src.path}`"
99
106
  return None
100
107
 
108
+ def add_to_db(self, db: FileDB):
109
+ db.update(self.target, self.sources)
110
+
101
111
  def run(self, db: FileDB):
102
112
  # Write to tmp file then replace with file name
103
113
  tmp_dir = Path() / ".entangled" / "tmp"
@@ -110,7 +120,7 @@ class Write(Action):
110
120
  os.chmod(f.name, self.mode)
111
121
  os.fsync(f.fileno())
112
122
  os.replace(f.name, self.target)
113
- db.update(self.target, self.sources)
123
+ self.add_to_db(db)
114
124
 
115
125
  def __str__(self):
116
126
  return f"write `{self.target}`"
@@ -126,13 +136,16 @@ class Delete(Action):
126
136
  )
127
137
  return None
128
138
 
139
+ def add_to_db(self, db: FileDB):
140
+ del db[self.target]
141
+
129
142
  def run(self, db: FileDB):
130
143
  self.target.unlink()
131
144
  parent = self.target.parent
132
145
  while list(parent.iterdir()) == []:
133
146
  parent.rmdir()
134
147
  parent = parent.parent
135
- del db[self.target]
148
+ self.add_to_db(db)
136
149
 
137
150
  def __str__(self):
138
151
  return f"delete `{self.target}`"
@@ -190,17 +203,27 @@ class Transaction:
190
203
  for f in self.updates:
191
204
  self.db.update(f)
192
205
 
206
+ def updatedb(self):
207
+ for a in self.actions:
208
+ a.add_to_db(self.db)
209
+ for f in self.updates:
210
+ self.db.update(f)
211
+
193
212
 
194
213
  class TransactionMode(Enum):
195
214
  SHOW = 1
196
215
  FAIL = 2
197
216
  CONFIRM = 3
198
217
  FORCE = 4
218
+ RESETDB = 5
199
219
 
200
220
 
201
221
  @contextmanager
202
222
  def transaction(mode: TransactionMode = TransactionMode.FAIL):
203
223
  with file_db() as db:
224
+ if mode == TransactionMode.RESETDB:
225
+ db.clear()
226
+
204
227
  tr = Transaction(db)
205
228
 
206
229
  logging.debug("Open transaction")
@@ -212,17 +235,25 @@ def transaction(mode: TransactionMode = TransactionMode.FAIL):
212
235
  case TransactionMode.SHOW:
213
236
  logging.info("nothing is done")
214
237
  return
238
+
239
+ case TransactionMode.RESETDB:
240
+ logging.info("rebuilding database")
241
+ tr.updatedb()
242
+ return
243
+
215
244
  case TransactionMode.FAIL:
216
245
  if not tr.all_ok():
217
246
  logging.error(
218
247
  "conflicts found, breaking off (use `--force` to run anyway)"
219
248
  )
220
249
  return
250
+
221
251
  case TransactionMode.CONFIRM:
222
252
  if not tr.all_ok():
223
253
  reply = input("Ok to continue? (y/n) ")
224
254
  if not (reply == "y" or reply == "yes"):
225
255
  return
256
+
226
257
  case TransactionMode.FORCE:
227
258
  logging.warning("conflicts found, but continuing anyway")
228
259
 
@@ -1,6 +1,6 @@
1
1
  [tool.poetry]
2
2
  name = "entangled-cli"
3
- version = "2.1.6"
3
+ version = "2.1.8"
4
4
  description = "Literate Programming toolbox"
5
5
  repository = "https://github.com/entangled/entangled.py"
6
6
  homepage = "https://entangled.github.io/"
File without changes