@@ -2839,34 +2839,111 @@ impl RunningActionImpl {
28392839 . err_tip ( || format ! ( "Uploading directory {}" , full_path. display( ) ) ) ?,
28402840 ) )
28412841 } else if metadata. is_symlink ( ) {
2842- let output_symlink = upload_symlink ( & full_path, work_directory)
2842+ // Resolve the symlink to determine what it points to.
2843+ // Symlinks created by DirectoryCache (absolute paths into
2844+ // the cache directory) must NOT be uploaded as symlinks —
2845+ // the target path is worker-local and meaningless to the
2846+ // client. Instead, follow the symlink and upload the
2847+ // resolved content (file or directory).
2848+ let target = fs:: read_link ( & full_path)
28432849 . await
2844- . map ( |mut symlink_info| {
2845- symlink_info. name_or_path = NameOrPath :: Path ( entry) ;
2846- symlink_info
2847- } )
2848- . err_tip ( || format ! ( "Uploading symlink {}" , full_path. display( ) ) ) ?;
2849- match fs:: metadata ( & full_path) . await {
2850- Ok ( metadata) => {
2851- if metadata. is_dir ( ) {
2852- Ok ( OutputType :: DirectorySymlink ( output_symlink) )
2853- } else {
2854- // Note: If it's anything but directory we put it as a file symlink.
2855- Ok ( OutputType :: FileSymlink ( output_symlink) )
2850+ . err_tip ( || format ! ( "Reading symlink target for {}" , full_path. display( ) ) ) ?;
2851+ let is_absolute_symlink = Path :: new ( & target) . is_absolute ( ) ;
2852+
2853+ if is_absolute_symlink {
2854+ // Absolute symlink — resolve and upload contents.
2855+ match fs:: metadata ( & full_path) . await {
2856+ Ok ( resolved_meta) => {
2857+ if resolved_meta. is_dir ( ) {
2858+ // Upload as directory (Tree proto).
2859+ Ok ( OutputType :: Directory (
2860+ upload_directory (
2861+ cas_store. as_pin ( ) ,
2862+ & full_path,
2863+ work_directory,
2864+ hasher,
2865+ digest_uploaders,
2866+ )
2867+ . and_then ( |( root_dir, children) | async move {
2868+ let tree = ProtoTree {
2869+ root : Some ( root_dir) ,
2870+ children : children. into ( ) ,
2871+ } ;
2872+ let tree_digest = serialize_and_upload_message (
2873+ & tree,
2874+ cas_store. as_pin ( ) ,
2875+ & mut hasher. hasher ( ) ,
2876+ )
2877+ . await
2878+ . err_tip ( || format ! ( "While processing {entry}" ) ) ?;
2879+ Ok ( DirectoryInfo {
2880+ path : entry,
2881+ tree_digest,
2882+ } )
2883+ } )
2884+ . await
2885+ . err_tip ( || format ! ( "Uploading symlinked directory {}" , full_path. display( ) ) ) ?,
2886+ ) )
2887+ } else {
2888+ // Upload as file (follow symlink).
2889+ Ok ( OutputType :: File (
2890+ upload_file (
2891+ cas_store. as_pin ( ) ,
2892+ & full_path,
2893+ hasher,
2894+ resolved_meta,
2895+ digest_uploaders,
2896+ )
2897+ . await
2898+ . map ( |mut file_info| {
2899+ file_info. name_or_path = NameOrPath :: Path ( entry) ;
2900+ file_info
2901+ } )
2902+ . err_tip ( || format ! ( "Uploading symlinked file {}" , full_path. display( ) ) ) ?,
2903+ ) )
2904+ }
2905+ }
2906+ Err ( e) => {
2907+ if e. code != Code :: NotFound {
2908+ return Err ( e) . err_tip ( || {
2909+ format ! (
2910+ "While resolving absolute symlink {}" ,
2911+ full_path. display( )
2912+ )
2913+ } ) ;
2914+ }
2915+ Ok ( OutputType :: None )
28562916 }
28572917 }
2858- Err ( e) => {
2859- if e. code != Code :: NotFound {
2860- return Err ( e) . err_tip ( || {
2861- format ! (
2862- "While querying target symlink metadata for {}" ,
2863- full_path. display( )
2864- )
2865- } ) ;
2918+ } else {
2919+ // Relative symlink — action intentionally created it.
2920+ // Upload as a proper symlink.
2921+ let output_symlink = upload_symlink ( & full_path, work_directory)
2922+ . await
2923+ . map ( |mut symlink_info| {
2924+ symlink_info. name_or_path = NameOrPath :: Path ( entry) ;
2925+ symlink_info
2926+ } )
2927+ . err_tip ( || format ! ( "Uploading symlink {}" , full_path. display( ) ) ) ?;
2928+ match fs:: metadata ( & full_path) . await {
2929+ Ok ( metadata) => {
2930+ if metadata. is_dir ( ) {
2931+ Ok ( OutputType :: DirectorySymlink ( output_symlink) )
2932+ } else {
2933+ Ok ( OutputType :: FileSymlink ( output_symlink) )
2934+ }
2935+ }
2936+ Err ( e) => {
2937+ if e. code != Code :: NotFound {
2938+ return Err ( e) . err_tip ( || {
2939+ format ! (
2940+ "While querying target symlink metadata for {}" ,
2941+ full_path. display( )
2942+ )
2943+ } ) ;
2944+ }
2945+ Ok ( OutputType :: FileSymlink ( output_symlink) )
28662946 }
2867- // If the file doesn't exist, we consider it a file. Even though the
2868- // file doesn't exist we still need to populate an entry.
2869- Ok ( OutputType :: FileSymlink ( output_symlink) )
28702947 }
28712948 }
28722949 } else {
0 commit comments