@@ -31,6 +31,47 @@ static CARGO_MANIFEST_DIR: Lazy<PathBuf> = Lazy::new(|| {
3131 PathBuf :: from ( env:: var_os ( "CARGO_MANIFEST_DIR" ) . expect ( "CARGO_MANIFEST_DIR is not present" ) )
3232} ) ;
3333
34+ fn is_git_symlink ( path : & Path ) -> bool {
35+ use std:: io:: { BufRead , BufReader } ;
36+ use std:: process:: { Command , Stdio } ;
37+ let res = path. parent ( ) . and_then ( |dir| {
38+ let child = Command :: new ( "git" )
39+ . arg ( "-C" )
40+ . arg ( dir)
41+ . arg ( "ls-files" )
42+ . arg ( "-s" )
43+ . stdin ( Stdio :: null ( ) )
44+ . stdout ( Stdio :: piped ( ) )
45+ . stderr ( Stdio :: piped ( ) )
46+ . spawn ( )
47+ . ok ( ) ?;
48+ let git_root = Command :: new ( "git" )
49+ . arg ( "-C" )
50+ . arg ( dir)
51+ . arg ( "rev-parse" )
52+ . arg ( "--show-toplevel" )
53+ . output ( )
54+ . ok ( ) ?
55+ . stdout ;
56+ let git_root = Path :: new ( std:: str:: from_utf8 ( & git_root) . unwrap ( ) . trim ( ) ) ;
57+ let stdout = BufReader :: new ( child. stdout . unwrap ( ) ) ;
58+ let lines = stdout
59+ . lines ( )
60+ . filter_map ( |line| line. ok ( ) )
61+ . filter ( |line| line. starts_with ( "120000" ) ) ;
62+ let path = path. canonicalize ( ) . ok ( ) ?;
63+ for line in lines {
64+ let link_path = line. splitn ( 2 , '\t' ) . nth ( 1 ) . unwrap ( ) ;
65+ let link_path = git_root. join ( link_path) . canonicalize ( ) . ok ( ) ?;
66+ if link_path == path {
67+ return Some ( true ) ;
68+ }
69+ }
70+ Some ( false )
71+ } ) ;
72+ res. unwrap_or ( false )
73+ }
74+
3475enum CompilationSourceKind {
3576 /// Source is a File (Path)
3677 File ( PathBuf ) ,
@@ -115,9 +156,20 @@ impl CompilationSource {
115156 mode : compile:: Mode ,
116157 ) -> Result < HashMap < String , FrozenModule > , Diagnostic > {
117158 let mut code_map = HashMap :: new ( ) ;
118- let paths = fs:: read_dir ( & path) . map_err ( |err| {
119- Diagnostic :: spans_error ( self . span , format ! ( "Error listing dir {:?}: {}" , path, err) )
120- } ) ?;
159+ let paths = fs:: read_dir ( path)
160+ . or_else ( |e| {
161+ // handle git symlinks - git for windows will make it just a text file containing
162+ // the target
163+ if cfg ! ( windows) && is_git_symlink ( path) {
164+ if let Ok ( real_path) = fs:: read_to_string ( path) {
165+ return fs:: read_dir ( real_path. trim ( ) ) ;
166+ }
167+ }
168+ Err ( e)
169+ } )
170+ . map_err ( |err| {
171+ Diagnostic :: spans_error ( self . span , format ! ( "Error listing dir {:?}: {}" , path, err) )
172+ } ) ?;
121173 for path in paths {
122174 let path = path. map_err ( |err| {
123175 Diagnostic :: spans_error ( self . span , format ! ( "Failed to list file: {}" , err) )
@@ -133,12 +185,6 @@ impl CompilationSource {
133185 mode,
134186 ) ?) ;
135187 } else if file_name. ends_with ( ".py" ) {
136- let source = fs:: read_to_string ( & path) . map_err ( |err| {
137- Diagnostic :: spans_error (
138- self . span ,
139- format ! ( "Error reading file {:?}: {}" , path, err) ,
140- )
141- } ) ?;
142188 let stem = path. file_stem ( ) . unwrap ( ) . to_str ( ) . unwrap ( ) ;
143189 let is_init = stem == "__init__" ;
144190 let module_name = if is_init {
@@ -148,15 +194,34 @@ impl CompilationSource {
148194 } else {
149195 format ! ( "{}.{}" , parent, stem)
150196 } ;
197+
198+ let compile_path = |src_path : & Path | {
199+ let source = fs:: read_to_string ( src_path) . map_err ( |err| {
200+ Diagnostic :: spans_error (
201+ self . span ,
202+ format ! ( "Error reading file {:?}: {}" , path, err) ,
203+ )
204+ } ) ?;
205+ self . compile_string ( & source, mode, module_name. clone ( ) , || {
206+ path. strip_prefix ( & * CARGO_MANIFEST_DIR )
207+ . ok ( )
208+ . unwrap_or ( & path)
209+ . display ( )
210+ } )
211+ } ;
212+ let code = compile_path ( & path) . or_else ( |e| {
213+ if cfg ! ( windows) && is_git_symlink ( & path) {
214+ if let Ok ( real_path) = fs:: read_to_string ( & path) {
215+ return compile_path ( real_path. trim ( ) . as_ref ( ) ) ;
216+ }
217+ }
218+ Err ( e)
219+ } ) ?;
220+
151221 code_map. insert (
152- module_name. clone ( ) ,
222+ module_name,
153223 FrozenModule {
154- code : self . compile_string ( & source, mode, module_name, || {
155- path. strip_prefix ( & * CARGO_MANIFEST_DIR )
156- . ok ( )
157- . unwrap_or ( & path)
158- . display ( )
159- } ) ?,
224+ code,
160225 package : is_init,
161226 } ,
162227 ) ;
0 commit comments