@@ -5,6 +5,7 @@ const Filter = @import("Fetch.zig").Filter;
5
5
6
6
allocator : std.mem.Allocator ,
7
7
root : fs.Dir ,
8
+ package_sub_path : ? []const u8 = null ,
8
9
errors : Errors ,
9
10
10
11
pub const Error = union (enum ) {
@@ -69,7 +70,7 @@ pub const Errors = struct {
69
70
} });
70
71
}
71
72
72
- pub fn filterWith (self : * Errors , filter : Filter ) ! void {
73
+ fn filterWith (self : * Errors , filter : Filter ) ! void {
73
74
var i = self .list .items .len ;
74
75
while (i > 0 ) {
75
76
i -= 1 ;
@@ -80,6 +81,25 @@ pub const Errors = struct {
80
81
}
81
82
}
82
83
}
84
+
85
+ fn stripRoot (self : * Errors ) ! void {
86
+ if (self .count () == 0 ) return ;
87
+
88
+ var old_list = self .list ;
89
+ self .list = .{};
90
+ for (old_list .items ) | item | {
91
+ switch (item ) {
92
+ .unable_to_create_sym_link = > | info | {
93
+ try self .symLink ("" , stripComponents (info .target_path , 1 ), info .sym_link_path , info .code );
94
+ },
95
+ .unable_to_create_file = > | info | {
96
+ try self .createFile ("" , stripComponents (info .file_name , 1 ), info .code );
97
+ },
98
+ }
99
+ self .free (item );
100
+ }
101
+ old_list .deinit (self .allocator );
102
+ }
83
103
};
84
104
85
105
pub fn init (allocator : std.mem.Allocator , root : fs.Dir ) Self {
@@ -92,13 +112,14 @@ pub fn init(allocator: std.mem.Allocator, root: fs.Dir) Self {
92
112
93
113
pub fn deinit (self : * Self ) void {
94
114
self .errors .deinit ();
115
+ if (self .package_sub_path ) | package_sub_path | {
116
+ self .allocator .free (package_sub_path );
117
+ }
95
118
}
96
119
97
120
const Self = @This ();
98
121
99
122
pub fn tarball (self : * Self , reader : anytype ) ! void {
100
- const strip_components = 1 ;
101
-
102
123
var file_name_buffer : [std .fs .MAX_PATH_BYTES ]u8 = undefined ;
103
124
var link_name_buffer : [std .fs .MAX_PATH_BYTES ]u8 = undefined ;
104
125
var iter = std .tar .iterator (reader , .{
@@ -114,22 +135,59 @@ pub fn tarball(self: *Self, reader: anytype) !void {
114
135
.directory = > {}, // skip empty
115
136
.file = > {
116
137
if (entry .size == 0 and entry .name .len == 0 ) continue ;
117
- const file_name = stripComponents (entry .name , strip_components );
118
- if (file_name .len == 0 ) return error .BadFileName ;
119
- if (try self .createFile ("" , file_name )) | file | {
138
+ if (try self .createFile ("" , entry .name )) | file | {
120
139
defer file .close ();
121
140
try entry .writeAll (file );
122
141
}
123
142
},
124
143
.sym_link = > {
125
- const file_name = stripComponents (entry .name , strip_components );
126
- if (file_name .len == 0 ) return error .BadFileName ;
127
- const link_name = entry .link_name ;
128
- try self .symLink ("" , link_name , file_name );
144
+ try self .symLink ("" , entry .link_name , entry .name );
129
145
},
130
146
}
131
147
} else break ;
132
148
}
149
+ try self .findPackageSubPath ();
150
+ }
151
+
152
+ fn findPackageSubPath (self : * Self ) ! void {
153
+ var iter = self .root .iterate ();
154
+ if (try iter .next ()) | entry | {
155
+ if (try iter .next () != null ) return ;
156
+ if (entry .kind == .directory ) { // single directory below root
157
+ self .package_sub_path = try self .allocator .dupe (u8 , entry .name );
158
+ try self .errors .stripRoot ();
159
+ }
160
+ }
161
+ }
162
+
163
+ test findPackageSubPath {
164
+ var tmp = testing .tmpDir (.{ .iterate = true });
165
+ defer tmp .cleanup ();
166
+
167
+ // folder1
168
+ // ├── folder2
169
+ // ├── file1
170
+ //
171
+ try tmp .dir .makePath ("folder1/folder2" );
172
+ (try tmp .dir .createFile ("folder1/file1" , .{})).close ();
173
+
174
+ var unpack = init (testing .allocator , tmp .dir );
175
+ try unpack .findPackageSubPath ();
176
+ // start at root returns folder1 as package root
177
+ try testing .expectEqualStrings ("folder1" , unpack .package_sub_path .? );
178
+ unpack .deinit ();
179
+
180
+ // start at folder1 returns null
181
+ unpack = init (testing .allocator , try tmp .dir .openDir ("folder1" , .{ .iterate = true }));
182
+ try unpack .findPackageSubPath ();
183
+ try testing .expect (unpack .package_sub_path == null );
184
+ unpack .deinit ();
185
+
186
+ // start at folder1/folder2 returns null
187
+ unpack = init (testing .allocator , try tmp .dir .openDir ("folder1/folder2" , .{ .iterate = true }));
188
+ try unpack .findPackageSubPath ();
189
+ try testing .expect (unpack .package_sub_path == null );
190
+ unpack .deinit ();
133
191
}
134
192
135
193
pub fn gitPack (self : * Self , commit_oid : git.Oid , reader : anytype ) ! void {
@@ -322,22 +380,36 @@ test tarball {
322
380
};
323
381
var buf : [paths .len * @sizeOf (TarHeader )]u8 = undefined ;
324
382
325
- // create tarball
326
- try createTarball (paths , & buf );
383
+ // tarball with leading root folder
384
+ {
385
+ try createTarball ("package_root" , paths , & buf );
386
+ var tmp = testing .tmpDir (.{ .iterate = true });
387
+ defer tmp .cleanup ();
327
388
328
- var tmp = testing .tmpDir (.{ .iterate = true });
329
- defer tmp .cleanup ();
389
+ var fbs = std .io .fixedBufferStream (& buf );
390
+
391
+ var unpack = Unpack .init (testing .allocator , tmp .dir );
392
+ defer unpack .deinit ();
393
+ try unpack .tarball (fbs .reader ());
394
+ try testing .expectEqualStrings ("package_root" , unpack .package_sub_path .? );
330
395
331
- // unpack tarball to tmp dir, will strip root dir
396
+ try expectDirFiles (try tmp .dir .openDir ("package_root" , .{ .iterate = true }), paths );
397
+ }
398
+ // tarball without root
332
399
{
400
+ try createTarball ("" , paths , & buf );
401
+ var tmp = testing .tmpDir (.{ .iterate = true });
402
+ defer tmp .cleanup ();
403
+
333
404
var fbs = std .io .fixedBufferStream (& buf );
334
405
335
406
var unpack = Unpack .init (testing .allocator , tmp .dir );
336
407
defer unpack .deinit ();
337
408
try unpack .tarball (fbs .reader ());
338
- }
409
+ try testing . expect ( unpack . package_sub_path == null );
339
410
340
- try expectDirFiles (tmp .dir , paths );
411
+ try expectDirFiles (tmp .dir , paths );
412
+ }
341
413
}
342
414
343
415
test directory {
@@ -357,14 +429,14 @@ test directory {
357
429
f .close ();
358
430
}
359
431
360
- var dest = testing .tmpDir (.{ .iterate = true });
361
- defer dest .cleanup ();
432
+ var tmp = testing .tmpDir (.{ .iterate = true });
433
+ defer tmp .cleanup ();
362
434
363
- var unpack = Unpack .init (testing .allocator , dest .dir );
435
+ var unpack = Unpack .init (testing .allocator , tmp .dir );
364
436
defer unpack .deinit ();
365
437
try unpack .directory (source .dir );
366
438
367
- try expectDirFiles (dest .dir , paths );
439
+ try expectDirFiles (tmp .dir , paths );
368
440
}
369
441
370
442
test "collect/filter errors" {
@@ -378,7 +450,7 @@ test "collect/filter errors" {
378
450
"dir1/file1" ,
379
451
};
380
452
var buf : [paths .len * @sizeOf (TarHeader )]u8 = undefined ;
381
- try createTarball (paths , & buf );
453
+ try createTarball ("package_root" , paths , & buf );
382
454
383
455
var tmp = testing .tmpDir (.{ .iterate = true });
384
456
defer tmp .cleanup ();
@@ -388,12 +460,12 @@ test "collect/filter errors" {
388
460
defer unpack .deinit ();
389
461
try unpack .tarball (fbs .reader ());
390
462
try testing .expect (unpack .hasErrors ());
391
-
392
- try expectDirFiles (tmp .dir , paths [0.. 2]);
463
+ try testing . expectEqualStrings ( "package_root" , unpack . package_sub_path .? );
464
+ try expectDirFiles (try tmp .dir . openDir ( "package_root" , .{ . iterate = true }) , paths [0.. 2]);
393
465
394
466
try testing .expectEqual (2 , unpack .errors .count ());
395
- try testing .expectEqualStrings (paths [ 2 ] , unpack .errors .list .items [0 ].unable_to_create_file .file_name );
396
- try testing .expectEqualStrings (paths [ 3 ] , unpack .errors .list .items [1 ].unable_to_create_file .file_name );
467
+ try testing .expectEqualStrings ("dir/file" , unpack .errors .list .items [0 ].unable_to_create_file .file_name );
468
+ try testing .expectEqualStrings ("dir1/file1" , unpack .errors .list .items [1 ].unable_to_create_file .file_name );
397
469
398
470
{
399
471
var filter : Filter = .{};
@@ -420,13 +492,17 @@ test "collect/filter errors" {
420
492
}
421
493
}
422
494
423
- fn createTarball (paths : []const []const u8 , buf : []u8 ) ! void {
495
+ fn createTarball (prefix : [] const u8 , paths : []const []const u8 , buf : []u8 ) ! void {
424
496
var fbs = std .io .fixedBufferStream (buf );
425
497
const writer = fbs .writer ();
426
498
for (paths ) | path | {
427
499
var hdr = TarHeader .init ();
428
500
hdr .typeflag = .regular ;
429
- try hdr .setPath ("stripped_root" , path );
501
+ if (prefix .len > 0 ) {
502
+ try hdr .setPath (prefix , path );
503
+ } else {
504
+ hdr .setName (path );
505
+ }
430
506
try hdr .updateChecksum ();
431
507
try writer .writeAll (std .mem .asBytes (& hdr ));
432
508
}
0 commit comments