@@ -17,8 +17,10 @@ open Eio.Std
17
17
18
18
let ( / ) = Path.( / )
19
19
20
- let run fn =
20
+ let run ?clear:(paths = []) fn =
21
21
Eio_main.run @@ fun env ->
22
+ let cwd = Eio.Stdenv.cwd env in
23
+ List.iter (fun p -> Eio.Path.rmtree ~missing_ok:true (cwd / p)) paths;
22
24
fn env
23
25
24
26
let try_read_file path =
@@ -69,13 +71,26 @@ let try_rmtree ?missing_ok path =
69
71
let chdir path =
70
72
traceln "chdir %S" path;
71
73
Unix.chdir path
74
+
75
+ let try_stat path =
76
+ let stat ~follow =
77
+ match Eio.Path.stat ~follow path with
78
+ | info -> Fmt.str "@[<h>%a@]" Eio.File.Stat.pp_kind info.kind
79
+ | exception Eio.Io (e, _) -> Fmt.str "@[<h>%a@]" Eio.Exn.pp_err e
80
+ in
81
+ let a = stat ~follow:false in
82
+ let b = stat ~follow:true in
83
+ if a = b then
84
+ traceln "%a -> %s" Eio.Path.pp path a
85
+ else
86
+ traceln "%a -> %s / %s" Eio.Path.pp path a b
72
87
```
73
88
74
89
# Basic test cases
75
90
76
91
Creating a file and reading it back:
77
92
``` ocaml
78
- # run @@ fun env ->
93
+ # run ~clear:["test-file"] @@ fun env ->
79
94
let cwd = Eio.Stdenv.cwd env in
80
95
Path.save ~create:(`Exclusive 0o666) (cwd / "test-file") "my-data";
81
96
traceln "Got %S" @@ Path.load (cwd / "test-file");;
@@ -179,7 +194,7 @@ Appending to an existing file:
179
194
# Mkdir
180
195
181
196
``` ocaml
182
- # run @@ fun env ->
197
+ # run ~clear:["subdir"] @@ fun env ->
183
198
let cwd = Eio.Stdenv.cwd env in
184
199
try_mkdir (cwd / "subdir");
185
200
try_mkdir (cwd / "subdir/nested");
@@ -188,19 +203,18 @@ Appending to an existing file:
188
203
+mkdir <cwd:subdir> -> ok
189
204
+mkdir <cwd:subdir/nested> -> ok
190
205
- : unit = ()
191
- # Unix.unlink "subdir/nested/test-file"; Unix.rmdir "subdir/nested"; Unix.rmdir "subdir";;
206
+ # Unix.unlink "subdir/nested/test-file";
207
+ Unix.rmdir "subdir/nested";
208
+ Unix.rmdir "subdir";;
192
209
- : unit = ()
193
210
```
194
211
195
212
Creating directories with nesting, symlinks, etc:
196
213
``` ocaml
197
- # Unix.symlink "/" "to-root";;
198
- - : unit = ()
199
- # Unix.symlink "subdir" "to-subdir";;
200
- - : unit = ()
201
- # Unix.symlink "foo" "dangle";;
202
- - : unit = ()
203
- # run @@ fun env ->
214
+ # run ~clear:["to-subdir"; "to-root"; "dangle"] @@ fun env ->
215
+ Unix.symlink "/" "to-root";
216
+ Unix.symlink "subdir" "to-subdir";
217
+ Unix.symlink "foo" "dangle";
204
218
let cwd = Eio.Stdenv.cwd env in
205
219
try_mkdir (cwd / "subdir");
206
220
try_mkdir (cwd / "to-subdir/nested");
@@ -265,7 +279,7 @@ let split path = Eio.Path.split (fake_dir, path) |> Option.map (fun ((_, dirname
265
279
Recursively creating directories with ` mkdirs ` .
266
280
267
281
``` ocaml
268
- # run @@ fun env ->
282
+ # run ~clear:["subdir1"] @@ fun env ->
269
283
let cwd = Eio.Stdenv.cwd env in
270
284
let nested = cwd / "subdir1" / "subdir2" / "subdir3" in
271
285
try_mkdirs nested;
@@ -287,7 +301,7 @@ Recursively creating directories with `mkdirs`.
287
301
Some edge cases for ` mkdirs ` .
288
302
289
303
``` ocaml
290
- # run @@ fun env ->
304
+ # run ~clear:["test"] @@ fun env ->
291
305
let cwd = Eio.Stdenv.cwd env in
292
306
try_mkdirs (cwd / ".");
293
307
try_mkdirs (cwd / "././");
@@ -307,7 +321,7 @@ Some edge cases for `mkdirs`.
307
321
You can remove a file using unlink:
308
322
309
323
``` ocaml
310
- # run @@ fun env ->
324
+ # run ~clear:["file"; "subdir/file2"] @@ fun env ->
311
325
Switch.run @@ fun sw ->
312
326
let cwd = Eio.Stdenv.cwd env in
313
327
Path.save ~create:(`Exclusive 0o600) (cwd / "file") "data";
@@ -352,12 +366,67 @@ Removing something that doesn't exist or is out of scope:
352
366
- : unit = ()
353
367
```
354
368
369
+ Reads and writes follow symlinks, but unlink operates on the symlink itself:
370
+
371
+ ``` ocaml
372
+ # run ~clear:["link1"; "linkdir"; "linkroot"; "dir1"; "file2"] @@ fun env ->
373
+ Switch.run @@ fun sw ->
374
+ let cwd = Eio.Stdenv.cwd env in
375
+ let fs = Eio.Stdenv.fs env in
376
+
377
+ try_mkdir (cwd / "dir1");
378
+ let file1 = cwd / "dir1" / "file1" in
379
+ let file2 = cwd / "file2" in
380
+ try_write_file ~create:(`Exclusive 0o600) file1 "data1";
381
+ try_write_file ~create:(`Exclusive 0o400) file2 "data2";
382
+ Unix.symlink "dir1/file1" "link1";
383
+ Unix.symlink "../file2" "dir1/link2";
384
+ Unix.symlink "dir1" "linkdir";
385
+ Unix.symlink "/" "linkroot";
386
+ try_read_file file1;
387
+ try_read_file (cwd / "link1");
388
+ try_read_file (cwd / "linkdir" / "file1");
389
+
390
+ try_stat file1;
391
+ try_stat (cwd / "link1");
392
+ try_stat (cwd / "linkdir");
393
+ try_stat (cwd / "linkroot");
394
+ try_stat (fs / "linkroot");
395
+
396
+ Fun.protect ~finally:(fun () -> chdir "..") (fun () ->
397
+ chdir "dir1";
398
+ try_read_file (cwd / "file1");
399
+ (* Should remove link itself even though it's poiting outside of cwd *)
400
+ Path.unlink (cwd / "link2")
401
+ );
402
+ try_read_file file2;
403
+ Path.unlink (cwd / "link1");
404
+ Path.unlink (cwd / "linkdir");
405
+ Path.unlink (cwd / "linkroot")
406
+ +mkdir <cwd:dir1> -> ok
407
+ +write <cwd:dir1/file1> -> ok
408
+ +write <cwd:file2> -> ok
409
+ +read <cwd:dir1/file1> -> "data1"
410
+ +read <cwd:link1> -> "data1"
411
+ +read <cwd:linkdir/file1> -> "data1"
412
+ +<cwd:dir1/file1> -> regular file
413
+ +<cwd:link1> -> symbolic link / regular file
414
+ +<cwd:linkdir> -> symbolic link / directory
415
+ +<cwd:linkroot> -> symbolic link / Fs Permission_denied _
416
+ +<fs:linkroot> -> symbolic link / directory
417
+ +chdir "dir1"
418
+ +read <cwd:file1> -> "data1"
419
+ +chdir ".."
420
+ +read <cwd:file2> -> "data2"
421
+ - : unit = ()
422
+ ```
423
+
355
424
# Rmdir
356
425
357
426
Similar to ` unlink ` , but works on directories:
358
427
359
428
``` ocaml
360
- # run @@ fun env ->
429
+ # run ~clear:["d1"; "subdir/d2"; "subdir/d3"] @@ fun env ->
361
430
Switch.run @@ fun sw ->
362
431
let cwd = Eio.Stdenv.cwd env in
363
432
try_mkdir (cwd / "d1");
@@ -405,7 +474,7 @@ Removing something that doesn't exist or is out of scope:
405
474
# Recursive removal
406
475
407
476
``` ocaml
408
- # run @@ fun env ->
477
+ # run ~clear:["foo"] @@ fun env ->
409
478
Switch.run @@ fun sw ->
410
479
let cwd = Eio.Stdenv.cwd env in
411
480
let foo = cwd / "foo" in
@@ -431,7 +500,7 @@ Removing something that doesn't exist or is out of scope:
431
500
432
501
Create a sandbox, write a file with it, then read it from outside:
433
502
``` ocaml
434
- # run @@ fun env ->
503
+ # run ~clear:["sandbox"] @@ fun env ->
435
504
Switch.run @@ fun sw ->
436
505
let cwd = Eio.Stdenv.cwd env in
437
506
try_mkdir (cwd / "sandbox");
@@ -450,7 +519,7 @@ Create a sandbox, write a file with it, then read it from outside:
450
519
We create a directory and chdir into it.
451
520
Using ` cwd ` we can't access the parent, but using ` fs ` we can:
452
521
``` ocaml
453
- # run @@ fun env ->
522
+ # run ~clear:["fs-test"; "outside-cwd"] @@ fun env ->
454
523
let cwd = Eio.Stdenv.cwd env in
455
524
let fs = Eio.Stdenv.fs env in
456
525
try_mkdir (cwd / "fs-test");
@@ -476,7 +545,7 @@ Using `cwd` we can't access the parent, but using `fs` we can:
476
545
Reading directory entries under ` cwd ` and outside of ` cwd ` .
477
546
478
547
``` ocaml
479
- # run @@ fun env ->
548
+ # run ~clear:["readdir"] @@ fun env ->
480
549
let cwd = Eio.Stdenv.cwd env in
481
550
try_mkdir (cwd / "readdir");
482
551
Path.with_open_dir (cwd / "readdir") @@ fun tmpdir ->
@@ -499,7 +568,8 @@ Reading directory entries under `cwd` and outside of `cwd`.
499
568
An error from the underlying directory, not the sandbox:
500
569
501
570
``` ocaml
502
- # Unix.mkdir "test-no-access" 0;;
571
+ # run ~clear:["test-no-access"] @@ fun env ->
572
+ Unix.mkdir "test-no-access" 0;;
503
573
- : unit = ()
504
574
# run @@ fun env ->
505
575
let cwd = Eio.Stdenv.cwd env in
@@ -530,7 +600,7 @@ Exception: Eio.Io Fs Permission_denied _,
530
600
## Streamling lines
531
601
532
602
``` ocaml
533
- # run @@ fun env ->
603
+ # run ~clear:["test-data"] @@ fun env ->
534
604
let cwd = Eio.Stdenv.cwd env in
535
605
Path.save ~create:(`Exclusive 0o600) (cwd / "test-data") "one\ntwo\nthree";
536
606
Path.with_lines (cwd / "test-data") (fun lines ->
@@ -609,7 +679,7 @@ let try_rename t =
609
679
Confined:
610
680
611
681
``` ocaml
612
- # run @@ fun env -> try_rename env#cwd;;
682
+ # run ~clear:["tmp"; "dir"] @@ fun env -> try_rename env#cwd;;
613
683
+mkdir <cwd:tmp> -> ok
614
684
+rename <cwd:tmp> to <cwd:dir> -> ok
615
685
+write <cwd:foo> -> ok
@@ -639,22 +709,7 @@ Unconfined:
639
709
# Stat
640
710
641
711
``` ocaml
642
- let try_stat path =
643
- let stat ~follow =
644
- match Eio.Path.stat ~follow path with
645
- | info -> Fmt.str "@[<h>%a@]" Eio.File.Stat.pp_kind info.kind
646
- | exception Eio.Io (e, _) -> Fmt.str "@[<h>%a@]" Eio.Exn.pp_err e
647
- in
648
- let a = stat ~follow:false in
649
- let b = stat ~follow:true in
650
- if a = b then
651
- traceln "%a -> %s" Eio.Path.pp path a
652
- else
653
- traceln "%a -> %s / %s" Eio.Path.pp path a b
654
- ```
655
-
656
- ``` ocaml
657
- # run @@ fun env ->
712
+ # run ~clear:["stat_subdir"; "stat_reg"] @@ fun env ->
658
713
let cwd = Eio.Stdenv.cwd env in
659
714
Switch.run @@ fun sw ->
660
715
try_mkdir (cwd / "stat_subdir");
@@ -666,10 +721,10 @@ let try_stat path =
666
721
- : unit = ()
667
722
```
668
723
669
- Fstatat:
724
+ # Fstatat:
670
725
671
726
``` ocaml
672
- # run @@ fun env ->
727
+ # run ~clear:["stat_subdir2"; "symlink"; "broken-symlink"; "parent-symlink"] @@ fun env ->
673
728
let cwd = Eio.Stdenv.cwd env in
674
729
Switch.run @@ fun sw ->
675
730
try_mkdir (cwd / "stat_subdir2");
@@ -701,7 +756,7 @@ Fstatat:
701
756
Check reading and writing vectors at arbitrary offsets:
702
757
703
758
``` ocaml
704
- # run @@ fun env ->
759
+ # run ~clear:["test.txt"] @@ fun env ->
705
760
let cwd = Eio.Stdenv.cwd env in
706
761
let path = cwd / "test.txt" in
707
762
Path.with_open_out path ~create:(`Exclusive 0o600) @@ fun file ->
@@ -741,7 +796,7 @@ Reading at the end of a file:
741
796
Ensure reads can be cancelled promptly, even if there is no need to wait:
742
797
743
798
``` ocaml
744
- # Eio_main. run @@ fun env ->
799
+ # run @@ fun env ->
745
800
Eio.Path.with_open_out (env#fs / "/dev/zero") ~create:`Never @@ fun null ->
746
801
Fiber.both
747
802
(fun () ->
@@ -755,7 +810,7 @@ Exception: Failure "Simulated error".
755
810
# Native paths
756
811
757
812
``` ocaml
758
- # Eio_main. run @@ fun env ->
813
+ # run ~clear:["native-sub"] @@ fun env ->
759
814
let cwd = Sys.getcwd () ^ "/" in
760
815
let test x =
761
816
let native = Eio.Path.native x in
@@ -800,7 +855,7 @@ Exception: Failure "Simulated error".
800
855
# Seek, truncate and sync
801
856
802
857
``` ocaml
803
- # Eio_main. run @@ fun env ->
858
+ # run @@ fun env ->
804
859
Eio.Path.with_open_out (env#cwd / "seek-test") ~create:(`If_missing 0o700) @@ fun file ->
805
860
Eio.File.truncate file (Int63.of_int 10);
806
861
assert ((Eio.File.stat file).size = (Int63.of_int 10));
0 commit comments