tangled
alpha
login
or
join now
jon.recoil.org
/
day10
0
fork
atom
A fork of mtelver's day10 project
0
fork
atom
overview
issues
pulls
pipelines
Network handling plus improved hardlink copy
Mark Elvers
8 months ago
de12ea87
765720dd
+86
-13
2 changed files
expand all
collapse all
unified
split
bin
main.ml
os.ml
+23
-8
bin/main.ml
···
10
10
package : string;
11
11
directory : string option;
12
12
md : string option;
13
13
+
network : string option;
13
14
}
14
15
15
16
let hostname = "builder"
16
16
-
let network = "35b0b92b-d2a7-429b-92ad-4671880d25f2"
17
17
+
18
18
+
let create_network () = match Sys.win32 with
19
19
+
| true -> Os.run "hcn-namespace create" |> String.trim
20
20
+
| false -> ""
21
21
+
22
22
+
let delete_network = function
23
23
+
| Some n -> Os.exec ["hcn-namespace"; "delete"; n]
24
24
+
| None -> 0
17
25
18
26
let env =
19
27
[
···
109
117
let mounts_json = Os.path [ temp_dir; "mounts.json" ] in
110
118
let _ = Os.retry_exec ~stdout:mounts_json [ "ctr"; "snapshot"; "prepare"; "--mounts"; Filename.basename temp_dir; "sha256:6f75278129ccaff6084617218cb8a28e8acc1748beeaae2946dfa92c5ca425ee" ] in
111
119
let layers = Json_layers.read_layers mounts_json in
112
112
-
let config = Json_config.make_ctr ~layers ~cwd:"c:\\" ~argv ~hostname ~uid:0 ~gid:0 ~env:win_env ~mounts ~network in
120
120
+
let config = Json_config.make_ctr ~layers ~cwd:"c:\\" ~argv ~hostname ~uid:0 ~gid:0 ~env:win_env ~mounts ~network:(Option.value ~default:"" config.network) in
113
121
let config_json = Os.path [ temp_dir; "config.json" ] in
114
122
let () = Os.write_to_file config_json (Yojson.Safe.pretty_to_string config) in
115
123
let result = Os.exec ~stdout:build_log ~stderr:build_log [ "ctr"; "run"; "--cni"; "--rm"; "--config"; config_json; Filename.basename temp_dir ] in
124
124
+
let _ = Os.rm (Os.path [ rootfs; "lock" ] ) in
125
125
+
let _ = Os.rm (Os.path [ rootfs; "conf.lock" ] ) in
126
126
+
let _ = Os.rm (Os.path [ rootfs; "default"; ".opam-switch"; "lock" ] ) in
116
127
let _ = Os.rm (Os.path [ rootfs; "repo"; "state-33BF9E46.cache" ] ) in
117
117
-
let _ = Os.rm (Os.path [ rootfs; "default"; ".opam-switch"; "lock" ] ) in
128
128
+
let _ = Os.rm (Os.path [ rootfs; "repo"; "conf.lock" ] ) in
118
129
let () = Os.write_to_file (Os.path [ temp_dir; "status" ]) (string_of_int result) in
119
130
let _ = Os.exec [ "ctr"; "snapshot"; "rm"; Filename.basename temp_dir ] in
120
131
Unix.rename temp_dir target_dir
···
372
383
let mounts_json = Os.path [ temp_dir; "mounts.json" ] in
373
384
let _ = Os.retry_exec ~stdout:mounts_json [ "ctr"; "snapshot"; "prepare"; "--mounts"; Filename.basename temp_dir; "sha256:6f75278129ccaff6084617218cb8a28e8acc1748beeaae2946dfa92c5ca425ee" ] in
374
385
let layers = Json_layers.read_layers mounts_json in
375
375
-
let config = Json_config.make_ctr ~layers ~cwd:"c:\\" ~argv ~hostname ~uid:0 ~gid:0 ~env:win_env ~mounts ~network in
386
386
+
let config = Json_config.make_ctr ~layers ~cwd:"c:\\" ~argv ~hostname ~uid:0 ~gid:0 ~env:win_env ~mounts ~network:(Option.value ~default:"" config.network) in
376
387
let config_json = Os.path [ temp_dir; "config.json" ] in
377
388
let () = Os.write_to_file config_json (Yojson.Safe.pretty_to_string config) in
378
389
let result = Os.exec ~stdout:build_log ~stderr:build_log [ "ctr"; "run"; "--cni"; "--rm"; "--config"; config_json; Filename.basename temp_dir ] in
···
405
416
406
417
let build config ocaml_version package =
407
418
let solution = solve config ocaml_version package in
408
408
-
let _ = Dot_solution.save ((OpamPackage.to_string package) ^ ".dot") solution in
419
419
+
(* let _ = Dot_solution.save ((OpamPackage.to_string package) ^ ".dot") solution in *)
409
420
if OpamPackage.Map.is_empty solution then
410
421
[ No_solution ]
411
422
else
412
423
let ordered_installation = topological_sort solution in
413
424
let dependencies = pkg_deps solution ordered_installation in
414
425
let solution = reduce dependencies solution in
415
415
-
let _ = Dot_solution.save ((OpamPackage.to_string package) ^ ".reduced.dot") solution in
426
426
+
(* let _ = Dot_solution.save ((OpamPackage.to_string package) ^ ".reduced.dot") solution in *)
416
427
List.fold_left
417
428
(fun lst pkg ->
418
429
match lst with
···
467
478
let run_ci config =
468
479
init config;
469
480
let package = OpamPackage.of_string (config.package ^ ".dev") in
481
481
+
let config = { config with network = Some (create_network ()) } in
470
482
let results = build config ocaml_version package in
483
483
+
let _ = delete_network config.network in
471
484
output config results
472
485
473
486
let run_health_check config =
474
487
init config;
475
488
let package = OpamPackage.of_string config.package in
489
489
+
let config = { config with network = Some (create_network ()) } in
476
490
let results = build config ocaml_version package in
491
491
+
let _ = delete_network config.network in
477
492
output config results
478
493
479
494
let cache_dir_term =
···
501
516
in
502
517
let ci_term =
503
518
Term.(
504
504
-
const (fun dir opam_repository directory md -> run_ci { dir; opam_repository; package = List.hd (find_opam_files directory); directory = Some directory; md })
519
519
+
const (fun dir opam_repository directory md -> run_ci { dir; opam_repository; package = List.hd (find_opam_files directory); directory = Some directory; md; network = None })
505
520
$ cache_dir_term $ opam_repository_term $ directory_arg $ md_term)
506
521
in
507
522
let ci_info = Cmd.info "ci" ~doc:"Run CI tests on a directory" in
···
514
529
in
515
530
let health_check_term =
516
531
Term.(
517
517
-
const (fun dir opam_repository package md -> run_health_check { dir; opam_repository; package; directory = None; md })
532
532
+
const (fun dir opam_repository package md -> run_health_check { dir; opam_repository; package; directory = None; md; network = None })
518
533
$ cache_dir_term $ opam_repository_term $ package_arg $ md_term)
519
534
in
520
535
let health_check_info = Cmd.info "health-check" ~doc:"Run health check on a package" in
+63
-5
bin/os.ml
···
90
90
try Unix.unlink lock_file with
91
91
| _ -> ()
92
92
93
93
+
exception Copy_error of string
94
94
+
95
95
+
let cp ?(buffer_size = 65536) ?(preserve_permissions = true) ?(preserve_times = true) src dst =
96
96
+
let safe_close fd = try Unix.close fd with _ -> () in
97
97
+
let src_stats =
98
98
+
try Unix.stat src
99
99
+
with Unix.Unix_error (err, _, _) ->
100
100
+
raise (Copy_error (Printf.sprintf "Cannot stat source file '%s': %s" src (Unix.error_message err)))
101
101
+
in
102
102
+
if src_stats.st_kind <> S_REG then
103
103
+
raise (Copy_error (Printf.sprintf "Source '%s' is not a regular file" src));
104
104
+
let src_fd =
105
105
+
try Unix.openfile src [O_RDONLY] 0
106
106
+
with Unix.Unix_error (err, _, _) ->
107
107
+
raise (Copy_error (Printf.sprintf "Cannot open source file '%s': %s" src (Unix.error_message err)))
108
108
+
in
109
109
+
let dst_fd =
110
110
+
try Unix.openfile dst [O_WRONLY; O_CREAT; O_TRUNC] src_stats.st_perm
111
111
+
with Unix.Unix_error (err, _, _) ->
112
112
+
safe_close src_fd;
113
113
+
raise (Copy_error (Printf.sprintf "Cannot open destination file '%s': %s" dst (Unix.error_message err)))
114
114
+
in
115
115
+
let buffer = Bytes.create buffer_size in
116
116
+
let rec copy_loop () =
117
117
+
try
118
118
+
match (Unix.read src_fd buffer 0 buffer_size) with
119
119
+
| 0 -> ()
120
120
+
| bytes_read ->
121
121
+
let rec write_all pos remaining =
122
122
+
if remaining > 0 then
123
123
+
let bytes_written = Unix.write dst_fd buffer pos remaining in
124
124
+
write_all (pos + bytes_written) (remaining - bytes_written)
125
125
+
in
126
126
+
write_all 0 bytes_read;
127
127
+
copy_loop ()
128
128
+
with Unix.Unix_error (err, _, _) ->
129
129
+
safe_close src_fd;
130
130
+
safe_close dst_fd;
131
131
+
raise (Copy_error (Printf.sprintf "Error during copy: %s" (Unix.error_message err)))
132
132
+
in
133
133
+
copy_loop ();
134
134
+
safe_close src_fd;
135
135
+
safe_close dst_fd;
136
136
+
if preserve_permissions then begin
137
137
+
try Unix.chmod dst src_stats.st_perm
138
138
+
with Unix.Unix_error (err, _, _) ->
139
139
+
Printf.eprintf "Warning: Could not preserve permissions: %s\n" (Unix.error_message err)
140
140
+
end;
141
141
+
if preserve_times then begin
142
142
+
try Unix.utimes dst src_stats.st_atime src_stats.st_mtime
143
143
+
with Unix.Unix_error (err, _, _) ->
144
144
+
Printf.eprintf "Warning: Could not preserve timestamps: %s\n" (Unix.error_message err)
145
145
+
end
146
146
+
93
147
let hardlink_tree ~source ~target =
94
148
let rec process_directory current_source current_target =
95
149
let entries = Sys.readdir current_source in
···
97
151
let source = Filename.concat current_source entry in
98
152
let target = Filename.concat current_target entry in
99
153
try
100
100
-
let stat = Unix.stat source in
154
154
+
let stat = Unix.lstat source in
101
155
match stat.st_kind with
102
102
-
| Unix.S_LNK
156
156
+
| Unix.S_LNK ->
157
157
+
if not (Sys.file_exists target) then
158
158
+
Unix.symlink (Unix.readlink source) target
103
159
| Unix.S_REG ->
104
160
if not (Sys.file_exists target) then
105
161
Unix.link source target
106
162
| Unix.S_DIR ->
107
163
mkdir target;
108
164
process_directory source target
109
109
-
| _ ->
165
165
+
| S_CHR | S_BLK | S_FIFO | S_SOCK ->
110
166
()
111
167
with
112
112
-
| Unix.Unix_error _ ->
113
113
-
()
168
168
+
| Unix.Unix_error (Unix.EMLINK, _, _) ->
169
169
+
cp source target
170
170
+
| Unix.Unix_error (err, _, _) ->
171
171
+
Printf.eprintf "Warning: %s -> %s = %s\n" source target (Unix.error_message err);
114
172
) entries
115
173
in
116
174
process_directory source target