Skip to content

Commit c5dd536

Browse files
committed
zig build: support install for zig artifacts
also make os.copyFile atomic closes #332
1 parent 943dbe5 commit c5dd536

File tree

3 files changed

+103
-60
lines changed

3 files changed

+103
-60
lines changed

std/build.zig

Lines changed: 76 additions & 55 deletions
Original file line numberDiff line numberDiff line change
@@ -552,20 +552,20 @@ pub const Builder = struct {
552552
};
553553
}
554554

555-
pub fn installCLibrary(self: &Builder, lib: &CLibExeObjStep) {
556-
self.getInstallStep().dependOn(&self.addInstallCLibrary(lib).step);
555+
pub fn installArtifact(self: &Builder, artifact: &LibExeObjStep) {
556+
self.getInstallStep().dependOn(&self.addInstallArtifact(artifact).step);
557557
}
558558

559-
pub fn addInstallCLibrary(self: &Builder, lib: &CLibExeObjStep) -> &InstallCArtifactStep {
560-
return InstallCArtifactStep.create(self, lib);
559+
pub fn addInstallArtifact(self: &Builder, artifact: &LibExeObjStep) -> &InstallArtifactStep(LibExeObjStep) {
560+
return InstallArtifactStep(LibExeObjStep).create(self, artifact);
561561
}
562562

563-
pub fn installCExecutable(self: &Builder, exe: &CLibExeObjStep) {
564-
self.getInstallStep().dependOn(&self.addInstallCExecutable(exe).step);
563+
pub fn installCArtifact(self: &Builder, artifact: &CLibExeObjStep) {
564+
self.getInstallStep().dependOn(&self.addInstallCArtifact(artifact).step);
565565
}
566566

567-
pub fn addInstallCExecutable(self: &Builder, exe: &CLibExeObjStep) -> &InstallCArtifactStep {
568-
return InstallCArtifactStep.create(self, exe);
567+
pub fn addInstallCArtifact(self: &Builder, artifact: &CLibExeObjStep) -> &InstallArtifactStep(CLibExeObjStep) {
568+
return InstallArtifactStep(CLibExeObjStep).create(self, artifact);
569569
}
570570

571571
///::dest_rel_path is relative to prefix path or it can be an absolute path
@@ -588,14 +588,24 @@ pub const Builder = struct {
588588
%%self.installed_files.append(full_path);
589589
}
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+
592600
const dirname = os.path.dirname(dest_path);
593601
const abs_source_path = self.pathFromRoot(source_path);
594602
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;
596605
};
597-
os.copyFile(self.allocator, abs_source_path, dest_path) %% |err| {
598-
debug.panic("Unable to copy {} to {}: {}", abs_source_path, dest_path, @errorName(err));
606+
os.copyFileMode(self.allocator, abs_source_path, dest_path, mode) %% |err| {
607+
%%io.stderr.printf("Unable to copy {} to {}: {}\n", abs_source_path, dest_path, @errorName(err));
608+
return err;
599609
};
600610
}
601611

@@ -664,8 +674,8 @@ pub const LibExeObjStep = struct {
664674
version: Version,
665675
out_h_filename: []const u8,
666676
out_filename: []const u8,
667-
out_filename_major_only: []const u8,
668-
out_filename_name_only: []const u8,
677+
major_only_filename: []const u8,
678+
name_only_filename: []const u8,
669679
object_files: List([]const u8),
670680
assembly_files: List([]const u8),
671681

@@ -721,8 +731,8 @@ pub const LibExeObjStep = struct {
721731
.version = *ver,
722732
.out_filename = undefined,
723733
.out_h_filename = builder.fmt("{}.h", name),
724-
.out_filename_major_only = undefined,
725-
.out_filename_name_only = undefined,
734+
.major_only_filename = undefined,
735+
.name_only_filename = undefined,
726736
.object_files = List([]const u8).init(builder.allocator),
727737
.assembly_files = List([]const u8).init(builder.allocator),
728738
};
@@ -744,8 +754,8 @@ pub const LibExeObjStep = struct {
744754
} else {
745755
self.out_filename = self.builder.fmt("lib{}.so.{d}.{d}.{d}",
746756
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);
748-
self.out_filename_name_only = self.builder.fmt("lib{}.so", self.name);
757+
self.major_only_filename = self.builder.fmt("lib{}.so.{d}", self.name, self.version.major);
758+
self.name_only_filename = self.builder.fmt("lib{}.so", self.name);
749759
}
750760
},
751761
}
@@ -934,8 +944,8 @@ pub const LibExeObjStep = struct {
934944
%return builder.spawnChild(builder.zig_exe, zig_args.toSliceConst());
935945

936946
if (self.kind == Kind.Lib and !self.static) {
937-
%return doAtomicSymLinks(builder.allocator, output_path, self.out_filename_major_only,
938-
self.out_filename_name_only);
947+
%return doAtomicSymLinks(builder.allocator, output_path, self.major_only_filename,
948+
self.name_only_filename);
939949
}
940950
}
941951
};
@@ -1424,45 +1434,56 @@ pub const CommandStep = struct {
14241434
}
14251435
};
14261436

1427-
pub const InstallCArtifactStep = struct {
1428-
step: Step,
1429-
builder: &Builder,
1430-
artifact: &CLibExeObjStep,
1431-
dest_file: []const u8,
1432-
1433-
pub fn create(builder: &Builder, artifact: &CLibExeObjStep) -> &InstallCArtifactStep {
1434-
const self = %%builder.allocator.create(InstallCArtifactStep);
1435-
const dest_dir = switch (artifact.kind) {
1436-
CLibExeObjStep.Kind.Obj => unreachable,
1437-
CLibExeObjStep.Kind.Exe => builder.exe_dir,
1438-
CLibExeObjStep.Kind.Lib => builder.lib_dir,
1439-
};
1440-
*self = InstallCArtifactStep {
1441-
.builder = builder,
1442-
.step = Step.init(builder.fmt("install {}", artifact.step.name), builder.allocator, make),
1443-
.artifact = artifact,
1444-
.dest_file = %%os.path.join(builder.allocator, builder.lib_dir, artifact.out_filename),
1445-
};
1446-
self.step.dependOn(&artifact.step);
1447-
builder.pushInstalledFile(self.dest_file);
1448-
if (self.artifact.kind == CLibExeObjStep.Kind.Lib and !self.artifact.static) {
1449-
builder.pushInstalledFile(%%os.path.join(builder.allocator, builder.lib_dir, artifact.major_only_filename));
1450-
builder.pushInstalledFile(%%os.path.join(builder.allocator, builder.lib_dir, artifact.name_only_filename));
1437+
fn InstallArtifactStep(comptime Artifact: type) -> type {
1438+
struct {
1439+
step: Step,
1440+
builder: &Builder,
1441+
artifact: &Artifact,
1442+
dest_file: []const u8,
1443+
1444+
const Self = this;
1445+
1446+
pub fn create(builder: &Builder, artifact: &Artifact) -> &Self {
1447+
const self = %%builder.allocator.create(Self);
1448+
const dest_dir = switch (artifact.kind) {
1449+
Artifact.Kind.Obj => unreachable,
1450+
Artifact.Kind.Exe => builder.exe_dir,
1451+
Artifact.Kind.Lib => builder.lib_dir,
1452+
};
1453+
*self = Self {
1454+
.builder = builder,
1455+
.step = Step.init(builder.fmt("install {}", artifact.step.name), builder.allocator, make),
1456+
.artifact = artifact,
1457+
.dest_file = %%os.path.join(builder.allocator, dest_dir, artifact.out_filename),
1458+
};
1459+
self.step.dependOn(&artifact.step);
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;
14511468
}
1452-
return self;
1453-
}
14541469

1455-
fn make(step: &Step) -> %void {
1456-
const self = @fieldParentPtr(InstallCArtifactStep, "step", step);
1457-
const builder = self.builder;
1470+
fn make(step: &Step) -> %void {
1471+
const self = @fieldParentPtr(Self, "step", step);
1472+
const builder = self.builder;
14581473

1459-
builder.copyFile(self.artifact.getOutputPath(), self.dest_file);
1460-
if (self.artifact.kind == CLibExeObjStep.Kind.Lib and !self.artifact.static) {
1461-
%return doAtomicSymLinks(builder.allocator, self.dest_file,
1462-
self.artifact.major_only_filename, self.artifact.name_only_filename);
1474+
const mode = switch (self.artifact.kind) {
1475+
Artifact.Kind.Obj => unreachable,
1476+
Artifact.Kind.Exe => usize(0o755),
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+
}
14631484
}
14641485
}
1465-
};
1486+
}
14661487

14671488
pub const InstallFileStep = struct {
14681489
step: Step,
@@ -1481,7 +1502,7 @@ pub const InstallFileStep = struct {
14811502

14821503
fn make(step: &Step) -> %void {
14831504
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);
14851506
}
14861507
};
14871508

std/io.zig

Lines changed: 8 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -67,16 +67,22 @@ pub const OutStream = struct {
6767
buffer: [os.page_size]u8,
6868
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+
7076
/// `path` may need to be copied in memory to add a null terminating byte. In this case
7177
/// a fixed size buffer of size std.os.max_noalloc_path_len is an attempted solution. If the fixed
7278
/// size buffer is too small, and the provided allocator is null, error.NameTooLong is returned.
7379
/// otherwise if the fixed size buffer is too small, allocator is used to obtain the needed memory.
7480
/// 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 {
7682
switch (@compileVar("os")) {
7783
Os.linux, Os.darwin, Os.macosx, Os.ios => {
7884
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);
8086
return OutStream {
8187
.fd = fd,
8288
.index = 0,

std/os/index.zig

Lines changed: 19 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -491,19 +491,35 @@ pub fn deleteFile(allocator: &Allocator, file_path: []const u8) -> %void {
491491
}
492492
}
493493

494+
/// Calls ::copyFileMode with 0o666 for the mode.
494495
pub 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.
501+
pub 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+
495513
var in_stream = %return io.InStream.open(source_path, allocator);
496514
defer in_stream.close();
497-
var out_stream = %return io.OutStream.open(dest_path, allocator);
498-
defer out_stream.close();
499515

500516
const buf = out_stream.buffer[0...];
501517
while (true) {
502518
const amt = %return in_stream.read(buf);
503519
out_stream.index = amt;
504520
%return out_stream.flush();
505521
if (amt != out_stream.buffer.len)
506-
return;
522+
return rename(allocator, tmp_path, dest_path);
507523
}
508524
}
509525

0 commit comments

Comments
 (0)