@@ -26,9 +26,24 @@ struct ExplicitEnv
2626    # local_prefs::Union{Nothing, Dict{String, Any}}
2727end 
2828
29- function  ExplicitEnv (envpath:: String = Base. active_project ())
29+ ExplicitEnv () =  ExplicitEnv (Base. active_project ())
30+ function  ExplicitEnv (:: Nothing , envpath:: String = " " 
31+     ExplicitEnv (envpath,
32+         Dict {String, UUID} (),     #  project_deps
33+         Dict {String, UUID} (),     #  project_weakdeps
34+         Dict {String, UUID} (),     #  project_extras
35+         Dict {String, Vector{UUID}} (), #  project_extensions
36+         Dict {UUID, Vector{UUID}} (),   #  deps
37+         Dict {UUID, Vector{UUID}} (),   #  weakdeps
38+         Dict {UUID, Dict{String, Vector{UUID}}} (), #  extensions
39+         Dict {UUID, String} (),     #  names
40+         Dict {UUID, Union{SHA1, String, Nothing, Missing}} ())
41+ end 
42+ function  ExplicitEnv (envpath:: String )
43+     #  Handle missing project file by creating an empty environment
3044    if  ! isfile (envpath)
31-         error (" expected a project file at $(repr (envpath)) " 
45+         envpath =  abspath (envpath)
46+         return  ExplicitEnv (:: Nothing , envpath)
3247    end 
3348    envpath =  abspath (envpath)
3449    project_d =  parsed_toml (envpath)
@@ -468,6 +483,7 @@ function precompilepkgs(pkgs::Vector{String}=String[];
468483                        fancyprint:: Bool  =  can_fancyprint (io) &&  ! timing,
469484                        manifest:: Bool = false ,
470485                        ignore_loaded:: Bool = true )
486+     @debug  " precompilepkgs called with: pkgs=$(pkgs) , internal_call=$(internal_call) , strict=$(strict) , warn_loaded=$(warn_loaded) , timing=$(timing) , _from_loading=$( _from_loading) , configs=$(configs) , io=$(io) , fancyprint=$(fancyprint) , manifest=$(manifest) , ignore_loaded=$(ignore_loaded) " 
471487    #  monomorphize this to avoid latency problems
472488    _precompilepkgs (pkgs, internal_call, strict, warn_loaded, timing, _from_loading,
473489                   configs isa  Vector{Config} ?  configs :  [configs],
@@ -518,9 +534,12 @@ function _precompilepkgs(pkgs::Vector{String},
518534    #  inverse map of `parent_to_ext` above (ext → parent)
519535    ext_to_parent =  Dict {Base.PkgId, Base.PkgId} ()
520536
521-     function  describe_pkg (pkg:: PkgId , is_project_dep:: Bool , flags:: Cmd , cacheflags:: Base.CacheFlags )
537+     function  describe_pkg (pkg:: PkgId , is_project_dep:: Bool , is_serial_dep :: Bool ,  flags:: Cmd , cacheflags:: Base.CacheFlags )
522538        name =  full_name (ext_to_parent, pkg)
523539        name =  is_project_dep ?  name :  color_string (name, :light_black )
540+         if  is_serial_dep
541+             name *=  color_string ("  (serial)" :light_black )
542+         end 
524543        if  nconfigs >  1  &&  ! isempty (flags)
525544            config_str =  join (flags, "  " 
526545            name *=  color_string ("  `$config_str `" :light_black )
@@ -630,15 +649,28 @@ function _precompilepkgs(pkgs::Vector{String},
630649    end 
631650    @debug  " precompile: extensions collected" 
632651
652+     serial_deps =  Base. PkgId[] #  packages that are being precompiled in serial
653+ 
654+     if  _from_loading &&  ! isempty (requested_pkgs)
655+         #  if called from loading precompilation it may be a package from another environment stack
656+         #  where we don't have access to the dep graph, so just add as a single package and do serial
657+         #  precompilation of its deps within the job.
658+         for  pkg in  requested_pkgs #  In case loading asks for multiple packages
659+             pkgid =  Base. identify_package (pkg)
660+             pkgid ===  nothing  &&  continue 
661+             if  ! haskey (direct_deps, pkgid)
662+                 @debug  " precompile: package `$(pkgid) ` is outside of the environment, so adding as single package serial job" 
663+                 direct_deps[pkgid] =  Base. PkgId[] #  no deps, do them in serial in the job
664+                 push! (project_deps, pkgid) #  add to project_deps so it doesn't show up in gray
665+                 push! (serial_deps, pkgid)
666+             end 
667+         end 
668+     end 
669+ 
633670    #  return early if no deps
634671    if  isempty (direct_deps)
635672        if  isempty (pkgs)
636673            return 
637-         elseif  _from_loading
638-             #  if called from loading precompilation it may be a package from another environment stack so
639-             #  don't error and allow serial precompilation to try
640-             #  TODO : actually handle packages from other envs in the stack
641-             return 
642674        else 
643675            error (" No direct dependencies outside of the sysimage found matching $(pkgs) " 
644676        end 
@@ -846,7 +878,7 @@ function _precompilepkgs(pkgs::Vector{String},
846878                            dep, config =  pkg_config
847879                            loaded =  warn_loaded &&  haskey (Base. loaded_modules, dep)
848880                            flags, cacheflags =  config
849-                             name =  describe_pkg (dep, dep in  project_deps, flags, cacheflags)
881+                             name =  describe_pkg (dep, dep in  project_deps, dep  in  serial_deps,  flags, cacheflags)
850882                            line =  if  pkg_config in  precomperr_deps
851883                                string (color_string ("   ? " . warn_color ()), name)
852884                            elseif  haskey (failed_deps, pkg_config)
@@ -929,12 +961,13 @@ function _precompilepkgs(pkgs::Vector{String},
929961                    if  ! circular &&  is_stale
930962                        Base. acquire (parallel_limiter)
931963                        is_project_dep =  pkg in  project_deps
964+                         is_serial_dep =  pkg in  serial_deps
932965
933966                        #  std monitoring
934967                        std_pipe =  Base. link_pipe! (Pipe (); reader_supports_async= true , writer_supports_async= true )
935968                        t_monitor =  @async  monitor_std (pkg_config, std_pipe; single_requested_pkg)
936969
937-                         name =  describe_pkg (pkg, is_project_dep, flags, cacheflags)
970+                         name =  describe_pkg (pkg, is_project_dep, is_serial_dep,  flags, cacheflags)
938971                        @lock  print_lock begin 
939972                            if  ! fancyprint &&  isempty (pkg_queue)
940973                                printpkgstyle (io, :Precompiling , something (target[], " packages..." 
0 commit comments