authorgravatar for andrew@ziglang.orgAndrew Kelley <andrew@ziglang.org> 2017-04-30 22:09:44-04:00
committergravatar for andrew@ziglang.orgAndrew Kelley <andrew@ziglang.org> 2017-04-30 22:09:44-04:00
logc5dd536845cffdf9f0c22de0a67a89d84d078e24
tree3586c3f48a0a37bf8282769d75e420520327882b
parent943dbe5b5098b243cea5e174cc2238f24d884253

zig build: support install for zig artifacts

also make os.copyFile atomic closes #332

3 files changed, 103 insertions(+), 60 deletions(-)

std/build.zig+76-55
...@@ -552,20 +552,20 @@ pub const Builder = struct {...@@ -552,20 +552,20 @@ pub const Builder = struct {
552 };552 };
553 }553 }
554554
555 pub fn installCLibrary(self: &Builder, lib: &CLibExeObjStep) {555 pub fn installArtifact(self: &Builder, artifact: &LibExeObjStep) {
556 self.getInstallStep().dependOn(&self.addInstallCLibrary(lib).step);556 self.getInstallStep().dependOn(&self.addInstallArtifact(artifact).step);
557 }557 }
558558
559 pub fn addInstallCLibrary(self: &Builder, lib: &CLibExeObjStep) -> &InstallCArtifactStep {559 pub fn addInstallArtifact(self: &Builder, artifact: &LibExeObjStep) -> &InstallArtifactStep(LibExeObjStep) {
560 return InstallCArtifactStep.create(self, lib);560 return InstallArtifactStep(LibExeObjStep).create(self, artifact);
561 }561 }
562562
563 pub fn installCExecutable(self: &Builder, exe: &CLibExeObjStep) {563 pub fn installCArtifact(self: &Builder, artifact: &CLibExeObjStep) {
564 self.getInstallStep().dependOn(&self.addInstallCExecutable(exe).step);564 self.getInstallStep().dependOn(&self.addInstallCArtifact(artifact).step);
565 }565 }
566566
567 pub fn addInstallCExecutable(self: &Builder, exe: &CLibExeObjStep) -> &InstallCArtifactStep {567 pub fn addInstallCArtifact(self: &Builder, artifact: &CLibExeObjStep) -> &InstallArtifactStep(CLibExeObjStep) {
568 return InstallCArtifactStep.create(self, exe);568 return InstallArtifactStep(CLibExeObjStep).create(self, artifact);
569 }569 }
570570
571 ///::dest_rel_path is relative to prefix path or it can be an absolute path571 ///::dest_rel_path is relative to prefix path or it can be an absolute path
...@@ -588,14 +588,24 @@ pub const Builder = struct {...@@ -588,14 +588,24 @@ pub const Builder = struct {
588 %%self.installed_files.append(full_path);588 %%self.installed_files.append(full_path);
589 }589 }
590590
591 fn copyFile(self: &Builder, source_path: []const u8, dest_path: []const u8) {591 fn copyFile(self: &Builder, source_path: []const u8, dest_path: []const u8) -> %void {
592 return self.copyFileMode(source_path, dest_path, 0o666);
593 }
594
595 fn copyFileMode(self: &Builder, source_path: []const u8, dest_path: []const u8, mode: usize) -> %void {
596 if (self.verbose) {
597 %%io.stderr.printf("cp {} {}\n", source_path, dest_path);
598 }
599
592 const dirname = os.path.dirname(dest_path);600 const dirname = os.path.dirname(dest_path);
593 const abs_source_path = self.pathFromRoot(source_path);601 const abs_source_path = self.pathFromRoot(source_path);
594 os.makePath(self.allocator, dirname) %% |err| {602 os.makePath(self.allocator, dirname) %% |err| {
595 debug.panic("Unable to create path {}: {}", dirname, @errorName(err));603 %%io.stderr.printf("Unable to create path {}: {}\n", dirname, @errorName(err));
604 return err;
596 };605 };
597 os.copyFile(self.allocator, abs_source_path, dest_path) %% |err| {606 os.copyFileMode(self.allocator, abs_source_path, dest_path, mode) %% |err| {
598 debug.panic("Unable to copy {} to {}: {}", abs_source_path, dest_path, @errorName(err));607 %%io.stderr.printf("Unable to copy {} to {}: {}\n", abs_source_path, dest_path, @errorName(err));
608 return err;
599 };609 };
600 }610 }
601611
...@@ -664,8 +674,8 @@ pub const LibExeObjStep = struct {...@@ -664,8 +674,8 @@ pub const LibExeObjStep = struct {
664 version: Version,674 version: Version,
665 out_h_filename: []const u8,675 out_h_filename: []const u8,
666 out_filename: []const u8,676 out_filename: []const u8,
667 out_filename_major_only: []const u8,677 major_only_filename: []const u8,
668 out_filename_name_only: []const u8,678 name_only_filename: []const u8,
669 object_files: List([]const u8),679 object_files: List([]const u8),
670 assembly_files: List([]const u8),680 assembly_files: List([]const u8),
671681
...@@ -721,8 +731,8 @@ pub const LibExeObjStep = struct {...@@ -721,8 +731,8 @@ pub const LibExeObjStep = struct {
721 .version = *ver,731 .version = *ver,
722 .out_filename = undefined,732 .out_filename = undefined,
723 .out_h_filename = builder.fmt("{}.h", name),733 .out_h_filename = builder.fmt("{}.h", name),
724 .out_filename_major_only = undefined,734 .major_only_filename = undefined,
725 .out_filename_name_only = undefined,735 .name_only_filename = undefined,
726 .object_files = List([]const u8).init(builder.allocator),736 .object_files = List([]const u8).init(builder.allocator),
727 .assembly_files = List([]const u8).init(builder.allocator),737 .assembly_files = List([]const u8).init(builder.allocator),
728 };738 };
...@@ -744,8 +754,8 @@ pub const LibExeObjStep = struct {...@@ -744,8 +754,8 @@ pub const LibExeObjStep = struct {
744 } else {754 } else {
745 self.out_filename = self.builder.fmt("lib{}.so.{d}.{d}.{d}",755 self.out_filename = self.builder.fmt("lib{}.so.{d}.{d}.{d}",
746 self.name, self.version.major, self.version.minor, self.version.patch);756 self.name, self.version.major, self.version.minor, self.version.patch);
747 self.out_filename_major_only = self.builder.fmt("lib{}.so.{d}", self.name, self.version.major);757 self.major_only_filename = self.builder.fmt("lib{}.so.{d}", self.name, self.version.major);
748 self.out_filename_name_only = self.builder.fmt("lib{}.so", self.name);758 self.name_only_filename = self.builder.fmt("lib{}.so", self.name);
749 }759 }
750 },760 },
751 }761 }
...@@ -934,8 +944,8 @@ pub const LibExeObjStep = struct {...@@ -934,8 +944,8 @@ pub const LibExeObjStep = struct {
934 %return builder.spawnChild(builder.zig_exe, zig_args.toSliceConst());944 %return builder.spawnChild(builder.zig_exe, zig_args.toSliceConst());
935945
936 if (self.kind == Kind.Lib and !self.static) {946 if (self.kind == Kind.Lib and !self.static) {
937 %return doAtomicSymLinks(builder.allocator, output_path, self.out_filename_major_only,947 %return doAtomicSymLinks(builder.allocator, output_path, self.major_only_filename,
938 self.out_filename_name_only);948 self.name_only_filename);
939 }949 }
940 }950 }
941};951};
...@@ -1424,45 +1434,56 @@ pub const CommandStep = struct {...@@ -1424,45 +1434,56 @@ pub const CommandStep = struct {
1424 }1434 }
1425};1435};
14261436
1427pub const InstallCArtifactStep = struct {1437fn InstallArtifactStep(comptime Artifact: type) -> type {
1428 step: Step,1438 struct {
1429 builder: &Builder,1439 step: Step,
1430 artifact: &CLibExeObjStep,1440 builder: &Builder,
1431 dest_file: []const u8,1441 artifact: &Artifact,
14321442 dest_file: []const u8,
1433 pub fn create(builder: &Builder, artifact: &CLibExeObjStep) -> &InstallCArtifactStep {1443
1434 const self = %%builder.allocator.create(InstallCArtifactStep);1444 const Self = this;
1435 const dest_dir = switch (artifact.kind) {1445
1436 CLibExeObjStep.Kind.Obj => unreachable,1446 pub fn create(builder: &Builder, artifact: &Artifact) -> &Self {
1437 CLibExeObjStep.Kind.Exe => builder.exe_dir,1447 const self = %%builder.allocator.create(Self);
1438 CLibExeObjStep.Kind.Lib => builder.lib_dir,1448 const dest_dir = switch (artifact.kind) {
1439 };1449 Artifact.Kind.Obj => unreachable,
1440 *self = InstallCArtifactStep {1450 Artifact.Kind.Exe => builder.exe_dir,
1441 .builder = builder,1451 Artifact.Kind.Lib => builder.lib_dir,
1442 .step = Step.init(builder.fmt("install {}", artifact.step.name), builder.allocator, make),1452 };
1443 .artifact = artifact,1453 *self = Self {
1444 .dest_file = %%os.path.join(builder.allocator, builder.lib_dir, artifact.out_filename),1454 .builder = builder,
1445 };1455 .step = Step.init(builder.fmt("install {}", artifact.step.name), builder.allocator, make),
1446 self.step.dependOn(&artifact.step);1456 .artifact = artifact,
1447 builder.pushInstalledFile(self.dest_file);1457 .dest_file = %%os.path.join(builder.allocator, dest_dir, artifact.out_filename),
1448 if (self.artifact.kind == CLibExeObjStep.Kind.Lib and !self.artifact.static) {1458 };
1449 builder.pushInstalledFile(%%os.path.join(builder.allocator, builder.lib_dir, artifact.major_only_filename));1459 self.step.dependOn(&artifact.step);
1450 builder.pushInstalledFile(%%os.path.join(builder.allocator, builder.lib_dir, artifact.name_only_filename));1460 builder.pushInstalledFile(self.dest_file);
1461 if (self.artifact.kind == Artifact.Kind.Lib and !self.artifact.static) {
1462 builder.pushInstalledFile(%%os.path.join(builder.allocator, builder.lib_dir,
1463 artifact.major_only_filename));
1464 builder.pushInstalledFile(%%os.path.join(builder.allocator, builder.lib_dir,
1465 artifact.name_only_filename));
1466 }
1467 return self;
1451 }1468 }
1452 return self;
1453 }
14541469
1455 fn make(step: &Step) -> %void {1470 fn make(step: &Step) -> %void {
1456 const self = @fieldParentPtr(InstallCArtifactStep, "step", step);1471 const self = @fieldParentPtr(Self, "step", step);
1457 const builder = self.builder;1472 const builder = self.builder;
14581473
1459 builder.copyFile(self.artifact.getOutputPath(), self.dest_file);1474 const mode = switch (self.artifact.kind) {
1460 if (self.artifact.kind == CLibExeObjStep.Kind.Lib and !self.artifact.static) {1475 Artifact.Kind.Obj => unreachable,
1461 %return doAtomicSymLinks(builder.allocator, self.dest_file,1476 Artifact.Kind.Exe => usize(0o755),
1462 self.artifact.major_only_filename, self.artifact.name_only_filename);1477 Artifact.Kind.Lib => if (self.artifact.static) usize(0o666) else usize(0o755),
1478 };
1479 %return builder.copyFileMode(self.artifact.getOutputPath(), self.dest_file, mode);
1480 if (self.artifact.kind == Artifact.Kind.Lib and !self.artifact.static) {
1481 %return doAtomicSymLinks(builder.allocator, self.dest_file,
1482 self.artifact.major_only_filename, self.artifact.name_only_filename);
1483 }
1463 }1484 }
1464 }1485 }
1465};1486}
14661487
1467pub const InstallFileStep = struct {1488pub const InstallFileStep = struct {
1468 step: Step,1489 step: Step,
...@@ -1481,7 +1502,7 @@ pub const InstallFileStep = struct {...@@ -1481,7 +1502,7 @@ pub const InstallFileStep = struct {
14811502
1482 fn make(step: &Step) -> %void {1503 fn make(step: &Step) -> %void {
1483 const self = @fieldParentPtr(InstallFileStep, "step", step);1504 const self = @fieldParentPtr(InstallFileStep, "step", step);
1484 self.builder.copyFile(self.src_path, self.dest_path);1505 %return self.builder.copyFile(self.src_path, self.dest_path);
1485 }1506 }
1486};1507};
14871508
std/io.zig+8-2
...@@ -67,16 +67,22 @@ pub const OutStream = struct {...@@ -67,16 +67,22 @@ pub const OutStream = struct {
67 buffer: [os.page_size]u8,67 buffer: [os.page_size]u8,
68 index: usize,68 index: usize,
6969
70 /// Calls ::openMode with 0o666 for the mode.
71 pub fn open(path: []const u8, allocator: ?&mem.Allocator) -> %OutStream {
72 return openMode(path, 0o666, allocator);
73
74 }
75
70 /// `path` may need to be copied in memory to add a null terminating byte. In this case76 /// `path` may need to be copied in memory to add a null terminating byte. In this case
71 /// a fixed size buffer of size std.os.max_noalloc_path_len is an attempted solution. If the fixed77 /// a fixed size buffer of size std.os.max_noalloc_path_len is an attempted solution. If the fixed
72 /// size buffer is too small, and the provided allocator is null, error.NameTooLong is returned.78 /// size buffer is too small, and the provided allocator is null, error.NameTooLong is returned.
73 /// otherwise if the fixed size buffer is too small, allocator is used to obtain the needed memory.79 /// otherwise if the fixed size buffer is too small, allocator is used to obtain the needed memory.
74 /// Call close to clean up.80 /// Call close to clean up.
75 pub fn open(path: []const u8, allocator: ?&mem.Allocator) -> %OutStream {81 pub fn openMode(path: []const u8, mode: usize, allocator: ?&mem.Allocator) -> %OutStream {
76 switch (@compileVar("os")) {82 switch (@compileVar("os")) {
77 Os.linux, Os.darwin, Os.macosx, Os.ios => {83 Os.linux, Os.darwin, Os.macosx, Os.ios => {
78 const flags = system.O_LARGEFILE|system.O_WRONLY|system.O_CREAT|system.O_CLOEXEC|system.O_TRUNC;84 const flags = system.O_LARGEFILE|system.O_WRONLY|system.O_CREAT|system.O_CLOEXEC|system.O_TRUNC;
79 const fd = %return os.posixOpen(path, flags, 0o666, allocator);85 const fd = %return os.posixOpen(path, flags, mode, allocator);
80 return OutStream {86 return OutStream {
81 .fd = fd,87 .fd = fd,
82 .index = 0,88 .index = 0,
std/os/index.zig+19-3
...@@ -491,11 +491,27 @@ pub fn deleteFile(allocator: &Allocator, file_path: []const u8) -> %void {...@@ -491,11 +491,27 @@ pub fn deleteFile(allocator: &Allocator, file_path: []const u8) -> %void {
491 }491 }
492}492}
493493
494/// Calls ::copyFileMode with 0o666 for the mode.
494pub fn copyFile(allocator: &Allocator, source_path: []const u8, dest_path: []const u8) -> %void {495pub fn copyFile(allocator: &Allocator, source_path: []const u8, dest_path: []const u8) -> %void {
496 return copyFileMode(allocator, source_path, dest_path, 0o666);
497}
498
499// TODO instead of accepting a mode argument, use the mode from fstat'ing the source path once open
500/// Guaranteed to be atomic.
501pub fn copyFileMode(allocator: &Allocator, source_path: []const u8, dest_path: []const u8, mode: usize) -> %void {
502 var rand_buf: [12]u8 = undefined;
503 const tmp_path = %return allocator.alloc(u8, dest_path.len + base64.calcEncodedSize(rand_buf.len));
504 defer allocator.free(tmp_path);
505 mem.copy(u8, tmp_path[0...], dest_path);
506 %return getRandomBytes(rand_buf[0...]);
507 _ = base64.encodeWithAlphabet(tmp_path[dest_path.len...], rand_buf, b64_fs_alphabet);
508
509 var out_stream = %return io.OutStream.openMode(tmp_path, mode, allocator);
510 defer out_stream.close();
511 %defer _ = deleteFile(allocator, tmp_path);
512
495 var in_stream = %return io.InStream.open(source_path, allocator);513 var in_stream = %return io.InStream.open(source_path, allocator);
496 defer in_stream.close();514 defer in_stream.close();
497 var out_stream = %return io.OutStream.open(dest_path, allocator);
498 defer out_stream.close();
499515
500 const buf = out_stream.buffer[0...];516 const buf = out_stream.buffer[0...];
501 while (true) {517 while (true) {
...@@ -503,7 +519,7 @@ pub fn copyFile(allocator: &Allocator, source_path: []const u8, dest_path: []con...@@ -503,7 +519,7 @@ pub fn copyFile(allocator: &Allocator, source_path: []const u8, dest_path: []con
503 out_stream.index = amt;519 out_stream.index = amt;
504 %return out_stream.flush();520 %return out_stream.flush();
505 if (amt != out_stream.buffer.len)521 if (amt != out_stream.buffer.len)
506 return;522 return rename(allocator, tmp_path, dest_path);
507 }523 }
508}524}
509525