@@ -835,11 +835,108 @@ pub fn shellLookupCommand(allocator: std.mem.Allocator, dir: []const u8) !Comman
835835}
836836
837837/// Shell activate command (for shell integration)
838- pub fn shellActivateCommand (_ : std.mem.Allocator , dir : []const u8 ) ! CommandResult {
839- std .debug .print ("Activating environment for {s}...\n " , .{dir });
838+ pub fn shellActivateCommand (allocator : std.mem.Allocator , dir : []const u8 ) ! CommandResult {
839+ const detector = @import ("../deps/detector.zig" );
840+ const parser = @import ("../deps/parser.zig" );
841+
842+ // Find dependency file
843+ const deps_file = (try detector .findDepsFile (allocator , dir )) orelse {
844+ // No dependency file found
845+ return .{ .exit_code = 1 };
846+ };
847+ defer allocator .free (deps_file .path );
848+
849+ // Calculate environment hash from dependency file path
850+ const hash = string .hashDependencyFile (deps_file .path );
851+ const hash_hex = try string .hashToHex (hash , allocator );
852+ defer allocator .free (hash_hex );
853+
854+ // Check environment cache first
855+ var env_cache = cache .EnvCache .init (allocator );
856+ defer env_cache .deinit ();
857+
858+ if (try env_cache .get (hash )) | entry | {
859+ // Cache hit - output cached shell code
860+ std .debug .print ("export PATH=\" {s}:$PATH\" \n " , .{entry .path });
861+ return .{ .exit_code = 0 };
862+ }
863+
864+ std .debug .print ("Found dependency file: {s} (hash: {s})\n " , .{ deps_file .path , hash_hex });
865+
866+ // Parse dependency file (auto-detects format)
867+ const deps = try parser .inferDependencies (allocator , deps_file );
868+ defer {
869+ for (deps ) | * dep | {
870+ var d = dep .* ;
871+ d .deinit (allocator );
872+ }
873+ allocator .free (deps );
874+ }
875+
876+ if (deps .len == 0 ) {
877+ std .debug .print ("No dependencies found\n " , .{});
878+ return .{ .exit_code = 0 };
879+ }
880+
881+ // Initialize package cache and installer
882+ var pkg_cache = try cache .PackageCache .init (allocator );
883+ defer pkg_cache .deinit ();
884+
885+ var installer = try install .Installer .init (allocator , & pkg_cache );
886+ defer installer .deinit ();
887+
888+ std .debug .print ("Installing {d} package(s)...\n " , .{deps .len });
889+
890+ // Install each dependency
891+ for (deps ) | dep | {
892+ std .debug .print (" → {s}@{s}..." , .{ dep .name , dep .version });
893+
894+ const spec = lib.packages.PackageSpec {
895+ .name = dep .name ,
896+ .version = dep .version ,
897+ };
898+
899+ var result = installer .install (spec , .{}) catch | err | {
900+ std .debug .print (" failed: {}\n " , .{err });
901+ continue ;
902+ };
903+ defer result .deinit (allocator );
904+
905+ if (result .from_cache ) {
906+ std .debug .print (" done (cached, {d}ms)\n " , .{result .install_time_ms });
907+ } else {
908+ std .debug .print (" done ({d}ms)\n " , .{result .install_time_ms });
909+ }
910+ }
911+
912+ // Output shell code to add bin directory to PATH
913+ const bin_dir = try std .fmt .allocPrint (
914+ allocator ,
915+ "{s}/bin" ,
916+ .{installer .data_dir },
917+ );
918+ defer allocator .free (bin_dir );
919+
920+ // Cache this environment for fast lookup next time
921+ const mtime = blk : {
922+ const file_stat = std .fs .cwd ().statFile (deps_file .path ) catch break :blk 0 ;
923+ break :blk @as (i64 , @intCast (file_stat .mtime ));
924+ };
925+
926+ const entry = try allocator .create (cache .env_cache .Entry );
927+ const env_vars = std .StringHashMap ([]const u8 ).init (allocator );
928+ entry .* = .{
929+ .hash = hash ,
930+ .dep_file = try allocator .dupe (u8 , deps_file .path ),
931+ .dep_mtime = @as (i128 , @intCast (mtime )),
932+ .path = try allocator .dupe (u8 , bin_dir ),
933+ .env_vars = env_vars ,
934+ .created_at = std .time .timestamp (),
935+ };
936+ try env_cache .put (entry );
937+
938+ std .debug .print ("\n export PATH=\" {s}:$PATH\" \n " , .{bin_dir });
840939
841- // TODO: Detect dependency files, install packages, generate shell code
842- // For now, return success
843940 return .{ .exit_code = 0 };
844941}
845942
0 commit comments