| ... | ... | @@ -779,21 +779,11 @@ fn runResource( |
| 779 | 779 | |
| 780 | 780 | if (remote_hash) |declared_hash| { |
| 781 | 781 | const hash_tok = f.hash_tok.unwrap().?; |
| 782 | | if (declared_hash.isOld()) { |
| 783 | | const actual_hex = Package.multiHashHexDigest(f.computed_hash.digest); |
| 784 | | if (!std.mem.eql(u8, declared_hash.toSlice(), &actual_hex)) { |
| 785 | | return f.fail(hash_tok, try eb.printString( |
| 786 | | "hash mismatch: manifest declares '{s}' but the fetched package has '{s}'", |
| 787 | | .{ declared_hash.toSlice(), actual_hex }, |
| 788 | | )); |
| 789 | | } |
| 790 | | } else { |
| 791 | | if (!computed_package_hash.eql(&declared_hash)) { |
| 792 | | return f.fail(hash_tok, try eb.printString( |
| 793 | | "hash mismatch: manifest declares '{s}' but the fetched package has '{s}'", |
| 794 | | .{ declared_hash.toSlice(), computed_package_hash.toSlice() }, |
| 795 | | )); |
| 796 | | } |
| 782 | if (!computed_package_hash.eql(&declared_hash)) { |
| 783 | return f.fail(hash_tok, try eb.printString( |
| 784 | "hash mismatch: manifest declares '{s}' but the fetched package has '{s}'", |
| 785 | .{ declared_hash.toSlice(), computed_package_hash.toSlice() }, |
| 786 | )); |
| 797 | 787 | } |
| 798 | 788 | } else if (!f.omit_missing_hash_error) { |
| 799 | 789 | const notes_len = 1; |
| ... | ... | @@ -2239,207 +2229,6 @@ const UnpackResult = struct { |
| 2239 | 2229 | } |
| 2240 | 2230 | }; |
| 2241 | 2231 | |
| 2242 | | test "set executable bit based on file content" { |
| 2243 | | if (!Io.File.Permissions.has_executable_bit) return error.SkipZigTest; |
| 2244 | | const gpa = std.testing.allocator; |
| 2245 | | const io = std.testing.io; |
| 2246 | | |
| 2247 | | var tmp = std.testing.tmpDir(.{}); |
| 2248 | | defer tmp.cleanup(); |
| 2249 | | |
| 2250 | | const tarball_name = "executables.tar.gz"; |
| 2251 | | try saveEmbedFile(io, tarball_name, tmp.dir); |
| 2252 | | const tarball_path = try std.fmt.allocPrint(gpa, ".zig-cache/tmp/{s}/{s}", .{ tmp.sub_path, tarball_name }); |
| 2253 | | defer gpa.free(tarball_path); |
| 2254 | | |
| 2255 | | // $ tar -tvf executables.tar.gz |
| 2256 | | // drwxrwxr-x 0 executables/ |
| 2257 | | // -rwxrwxr-x 170 executables/hello |
| 2258 | | // lrwxrwxrwx 0 executables/hello_ln -> hello |
| 2259 | | // -rw-rw-r-- 0 executables/file1 |
| 2260 | | // -rw-rw-r-- 17 executables/script_with_shebang_without_exec_bit |
| 2261 | | // -rwxrwxr-x 7 executables/script_without_shebang |
| 2262 | | // -rwxrwxr-x 17 executables/script |
| 2263 | | |
| 2264 | | var fb: TestFetchBuilder = undefined; |
| 2265 | | var fetch = try fb.build(gpa, io, tmp.dir, tarball_path); |
| 2266 | | defer fb.deinit(); |
| 2267 | | |
| 2268 | | try fetch.run(); |
| 2269 | | try std.testing.expectEqualStrings( |
| 2270 | | "1220fecb4c06a9da8673c87fe8810e15785f1699212f01728eadce094d21effeeef3", |
| 2271 | | &Package.multiHashHexDigest(fetch.computed_hash.digest), |
| 2272 | | ); |
| 2273 | | |
| 2274 | | var out = try fb.packageDir(); |
| 2275 | | defer out.close(io); |
| 2276 | | const S = std.posix.S; |
| 2277 | | // expect executable bit not set |
| 2278 | | try std.testing.expect((try out.statFile(io, "file1", .{})).permissions.toMode() & S.IXUSR == 0); |
| 2279 | | try std.testing.expect((try out.statFile(io, "script_without_shebang", .{})).permissions.toMode() & S.IXUSR == 0); |
| 2280 | | // expect executable bit set |
| 2281 | | try std.testing.expect((try out.statFile(io, "hello", .{})).permissions.toMode() & S.IXUSR != 0); |
| 2282 | | try std.testing.expect((try out.statFile(io, "script", .{})).permissions.toMode() & S.IXUSR != 0); |
| 2283 | | try std.testing.expect((try out.statFile(io, "script_with_shebang_without_exec_bit", .{})).permissions.toMode() & S.IXUSR != 0); |
| 2284 | | try std.testing.expect((try out.statFile(io, "hello_ln", .{})).permissions.toMode() & S.IXUSR != 0); |
| 2285 | | |
| 2286 | | // |
| 2287 | | // $ ls -al zig-cache/tmp/OCz9ovUcstDjTC_U/zig-global-cache/p/1220fecb4c06a9da8673c87fe8810e15785f1699212f01728eadce094d21effeeef3 |
| 2288 | | // -rw-rw-r-- 1 0 Apr file1 |
| 2289 | | // -rwxrwxr-x 1 170 Apr hello |
| 2290 | | // lrwxrwxrwx 1 5 Apr hello_ln -> hello |
| 2291 | | // -rwxrwxr-x 1 17 Apr script |
| 2292 | | // -rw-rw-r-- 1 7 Apr script_without_shebang |
| 2293 | | // -rwxrwxr-x 1 17 Apr script_with_shebang_without_exec_bit |
| 2294 | | } |
| 2295 | | |
| 2296 | | fn saveEmbedFile(io: Io, comptime tarball_name: []const u8, dir: Io.Dir) !void { |
| 2297 | | //const tarball_name = "duplicate_paths_excluded.tar.gz"; |
| 2298 | | const tarball_content = @embedFile("Fetch/testdata/" ++ tarball_name); |
| 2299 | | var tmp_file = try dir.createFile(io, tarball_name, .{}); |
| 2300 | | defer tmp_file.close(io); |
| 2301 | | try tmp_file.writeStreamingAll(io, tarball_content); |
| 2302 | | } |
| 2303 | | |
| 2304 | | // Builds Fetch with required dependencies, clears dependencies on deinit(). |
| 2305 | | const TestFetchBuilder = struct { |
| 2306 | | http_client: std.http.Client, |
| 2307 | | global_cache_directory: Cache.Directory, |
| 2308 | | local_cache_path: Cache.Path, |
| 2309 | | job_queue: Fetch.JobQueue, |
| 2310 | | fetch: Fetch, |
| 2311 | | |
| 2312 | | fn build( |
| 2313 | | self: *TestFetchBuilder, |
| 2314 | | allocator: std.mem.Allocator, |
| 2315 | | io: Io, |
| 2316 | | cache_parent_dir: std.Io.Dir, |
| 2317 | | path_or_url: []const u8, |
| 2318 | | ) !*Fetch { |
| 2319 | | const global_cache_dir = try cache_parent_dir.createDirPathOpen(io, "zig-global-cache", .{}); |
| 2320 | | const package_root_dir = try cache_parent_dir.createDirPathOpen(io, "local-project-root", .{}); |
| 2321 | | |
| 2322 | | self.http_client = .{ .allocator = allocator, .io = io }; |
| 2323 | | self.global_cache_directory = .{ .handle = global_cache_dir, .path = "zig-global-cache" }; |
| 2324 | | self.local_cache_path = .{ |
| 2325 | | .root_dir = .{ .handle = package_root_dir, .path = "local-project-root" }, |
| 2326 | | .sub_path = ".zig-cache", |
| 2327 | | }; |
| 2328 | | |
| 2329 | | self.job_queue = .{ |
| 2330 | | .io = io, |
| 2331 | | .http_client = &self.http_client, |
| 2332 | | .global_cache = self.global_cache_directory, |
| 2333 | | .local_cache = self.local_cache_path, |
| 2334 | | .root_pkg_path = .{ |
| 2335 | | .root_dir = .{ .handle = package_root_dir, .path = "local-project-root" }, |
| 2336 | | .sub_path = "zig-pkg", |
| 2337 | | }, |
| 2338 | | .recursive = false, |
| 2339 | | .read_only = false, |
| 2340 | | .debug_hash = false, |
| 2341 | | .mode = .needed, |
| 2342 | | .prog_node = std.Progress.Node.none, |
| 2343 | | }; |
| 2344 | | |
| 2345 | | self.fetch = .{ |
| 2346 | | .arena = std.heap.ArenaAllocator.init(allocator), |
| 2347 | | .location = .{ .path_or_url = path_or_url }, |
| 2348 | | .location_tok = 0, |
| 2349 | | .hash_tok = .none, |
| 2350 | | .name_tok = 0, |
| 2351 | | .lazy_status = .eager, |
| 2352 | | .parent_package_root = .{ .root_dir = .{ .handle = package_root_dir, .path = null } }, |
| 2353 | | .parent_manifest_ast = null, |
| 2354 | | .prog_node = std.Progress.Node.none, |
| 2355 | | .job_queue = &self.job_queue, |
| 2356 | | .omit_missing_hash_error = true, |
| 2357 | | .allow_missing_paths_field = false, |
| 2358 | | .use_latest_commit = true, |
| 2359 | | |
| 2360 | | .package_root = undefined, |
| 2361 | | .error_bundle = undefined, |
| 2362 | | .manifest = undefined, |
| 2363 | | .manifest_ast = undefined, |
| 2364 | | .have_manifest = false, |
| 2365 | | .computed_hash = undefined, |
| 2366 | | .has_build_zig = false, |
| 2367 | | .oom_flag = false, |
| 2368 | | .latest_commit = null, |
| 2369 | | |
| 2370 | | .module = null, |
| 2371 | | }; |
| 2372 | | return &self.fetch; |
| 2373 | | } |
| 2374 | | |
| 2375 | | fn deinit(self: *TestFetchBuilder) void { |
| 2376 | | const io = self.job_queue.io; |
| 2377 | | self.fetch.deinit(); |
| 2378 | | self.job_queue.deinit(); |
| 2379 | | self.fetch.prog_node.end(); |
| 2380 | | self.global_cache_directory.handle.close(io); |
| 2381 | | self.http_client.deinit(); |
| 2382 | | } |
| 2383 | | |
| 2384 | | fn packageDir(self: *TestFetchBuilder) !Io.Dir { |
| 2385 | | const io = self.job_queue.io; |
| 2386 | | const root = self.fetch.package_root; |
| 2387 | | return try root.root_dir.handle.openDir(io, root.sub_path, .{ .iterate = true }); |
| 2388 | | } |
| 2389 | | |
| 2390 | | // Test helper, asserts thet package dir constains expected_files. |
| 2391 | | // expected_files must be sorted. |
| 2392 | | fn expectPackageFiles(self: *TestFetchBuilder, expected_files: []const []const u8) !void { |
| 2393 | | const io = self.job_queue.io; |
| 2394 | | const gpa = std.testing.allocator; |
| 2395 | | |
| 2396 | | var package_dir = try self.packageDir(); |
| 2397 | | defer package_dir.close(io); |
| 2398 | | |
| 2399 | | var actual_files: std.ArrayList([]u8) = .empty; |
| 2400 | | defer actual_files.deinit(gpa); |
| 2401 | | defer for (actual_files.items) |file| gpa.free(file); |
| 2402 | | var walker = try package_dir.walk(gpa); |
| 2403 | | defer walker.deinit(); |
| 2404 | | while (try walker.next(io)) |entry| { |
| 2405 | | if (entry.kind != .file) continue; |
| 2406 | | const path = try gpa.dupe(u8, entry.path); |
| 2407 | | errdefer gpa.free(path); |
| 2408 | | std.mem.replaceScalar(u8, path, std.fs.path.sep, '/'); |
| 2409 | | try actual_files.append(gpa, path); |
| 2410 | | } |
| 2411 | | std.mem.sortUnstable([]u8, actual_files.items, {}, struct { |
| 2412 | | fn lessThan(_: void, a: []u8, b: []u8) bool { |
| 2413 | | return std.mem.lessThan(u8, a, b); |
| 2414 | | } |
| 2415 | | }.lessThan); |
| 2416 | | |
| 2417 | | try std.testing.expectEqual(expected_files.len, actual_files.items.len); |
| 2418 | | for (expected_files, 0..) |file_name, i| { |
| 2419 | | try std.testing.expectEqualStrings(file_name, actual_files.items[i]); |
| 2420 | | } |
| 2421 | | try std.testing.expectEqualDeep(expected_files, actual_files.items); |
| 2422 | | } |
| 2423 | | |
| 2424 | | // Test helper, asserts that fetch has failed with `msg` error message. |
| 2425 | | fn expectFetchErrors(self: *TestFetchBuilder, notes_len: usize, msg: []const u8) !void { |
| 2426 | | const gpa = std.testing.allocator; |
| 2427 | | |
| 2428 | | var errors = try self.fetch.error_bundle.toOwnedBundle(""); |
| 2429 | | defer errors.deinit(gpa); |
| 2430 | | |
| 2431 | | const em = errors.getErrorMessage(errors.getMessages()[0]); |
| 2432 | | try std.testing.expectEqual(1, em.count); |
| 2433 | | if (notes_len > 0) { |
| 2434 | | try std.testing.expectEqual(notes_len, em.notes_len); |
| 2435 | | } |
| 2436 | | var aw: Io.Writer.Allocating = .init(gpa); |
| 2437 | | defer aw.deinit(); |
| 2438 | | try errors.renderToWriter(.{}, &aw.writer); |
| 2439 | | try std.testing.expectEqualStrings(msg, aw.written()); |
| 2440 | | } |
| 2441 | | }; |
| 2442 | | |
| 2443 | 2232 | test { |
| 2444 | 2233 | _ = Filter; |
| 2445 | 2234 | _ = FileType; |