| ... | @@ -779,21 +779,11 @@ fn runResource( | ... | @@ -779,21 +779,11 @@ fn runResource( |
| 779 | | 779 | |
| 780 | if (remote_hash) |declared_hash| { | 780 | if (remote_hash) |declared_hash| { |
| 781 | const hash_tok = f.hash_tok.unwrap().?; | 781 | const hash_tok = f.hash_tok.unwrap().?; |
| 782 | if (declared_hash.isOld()) { | 782 | if (!computed_package_hash.eql(&declared_hash)) { |
| 783 | const actual_hex = Package.multiHashHexDigest(f.computed_hash.digest); | 783 | return f.fail(hash_tok, try eb.printString( |
| 784 | if (!std.mem.eql(u8, declared_hash.toSlice(), &actual_hex)) { | 784 | "hash mismatch: manifest declares '{s}' but the fetched package has '{s}'", |
| 785 | return f.fail(hash_tok, try eb.printString( | 785 | .{ declared_hash.toSlice(), computed_package_hash.toSlice() }, |
| 786 | "hash mismatch: manifest declares '{s}' but the fetched package has '{s}'", | 786 | )); |
| 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 | } | | |
| 797 | } | 787 | } |
| 798 | } else if (!f.omit_missing_hash_error) { | 788 | } else if (!f.omit_missing_hash_error) { |
| 799 | const notes_len = 1; | 789 | const notes_len = 1; |
| ... | @@ -2239,207 +2229,6 @@ const UnpackResult = struct { | ... | @@ -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 | test { | 2232 | test { |
| 2444 | _ = Filter; | 2233 | _ = Filter; |
| 2445 | _ = FileType; | 2234 | _ = FileType; |