@@ -15,8 +15,41 @@ julia_bin_path() = joinpath(first(DEPOT_PATH), "bin")
1515
1616app_context () = Context (env= EnvCache (joinpath (app_env_folder (), " Project.toml" )))
1717
18+ function validate_app_name (name:: AbstractString )
19+ if isempty (name)
20+ error (" App name cannot be empty" )
21+ end
22+ if ! occursin (r" ^[a-zA-Z][a-zA-Z0-9_-]*$" , name)
23+ error (" App name must start with a letter and contain only letters, numbers, underscores, and hyphens" )
24+ end
25+ if occursin (r" \.\. " , name) || occursin (r" [/\\ ]" , name)
26+ error (" App name cannot contain path traversal sequences or path separators" )
27+ end
28+ end
29+
30+ function validate_package_name (name:: AbstractString )
31+ if isempty (name)
32+ error (" Package name cannot be empty" )
33+ end
34+ if ! occursin (r" ^[a-zA-Z][a-zA-Z0-9_]*$" , name)
35+ error (" Package name must start with a letter and contain only letters, numbers, and underscores" )
36+ end
37+ end
38+
39+ function validate_submodule_name (name:: Union{AbstractString,Nothing} )
40+ if name != = nothing
41+ if isempty (name)
42+ error (" Submodule name cannot be empty" )
43+ end
44+ if ! occursin (r" ^[a-zA-Z][a-zA-Z0-9_]*$" , name)
45+ error (" Submodule name must start with a letter and contain only letters, numbers, and underscores" )
46+ end
47+ end
48+ end
49+
1850
1951function rm_shim (name; kwargs... )
52+ validate_app_name (name)
2053 Base. rm (joinpath (julia_bin_path (), name * (Sys. iswindows () ? " .bat" : " " )); kwargs... )
2154end
2255
@@ -38,6 +71,30 @@ function overwrite_file_if_different(file, content)
3871 end
3972end
4073
74+ function check_apps_in_path (apps)
75+ for app_name in keys (apps)
76+ which_result = Sys. which (app_name)
77+ if which_result === nothing
78+ @warn """
79+ App '$app_name ' was installed but is not available in PATH.
80+ Consider adding '$(julia_bin_path ()) ' to your PATH environment variable.
81+ """ maxlog= 1
82+ break # Only show warning once per installation
83+ else
84+ # Check for collisions
85+ expected_path = joinpath (julia_bin_path (), app_name * (Sys. iswindows () ? " .bat" : " " ))
86+ if which_result != expected_path
87+ @warn """
88+ App '$app_name ' collision detected:
89+ Expected: $expected_path
90+ Found: $which_result
91+ Another application with the same name exists in PATH.
92+ """
93+ end
94+ end
95+ end
96+ end
97+
4198function get_max_version_register (pkg:: PackageSpec , regs)
4299 max_v = nothing
43100 tree_hash = nothing
@@ -157,6 +214,7 @@ function add(pkg::PackageSpec)
157214 precompile (pkg. name)
158215
159216 @info " For package: $(pkg. name) installed apps $(join (keys (project. apps), " ," )) "
217+ check_apps_in_path (project. apps)
160218end
161219
162220function develop (pkg:: Vector{PackageSpec} )
@@ -192,6 +250,7 @@ function develop(pkg::PackageSpec)
192250 _resolve (manifest, pkg. name)
193251 precompile (pkg. name)
194252 @info " For package: $(pkg. name) installed apps: $(join (keys (project. apps), " ," )) "
253+ check_apps_in_path (project. apps)
195254end
196255
197256
@@ -205,6 +264,7 @@ function update(pkgs_or_apps::Vector)
205264 end
206265end
207266
267+ # XXX : Is updating an app ever different from rm-ing and adding it from scratch?
208268function update (pkg:: Union{PackageSpec, Nothing} = nothing )
209269 ctx = app_context ()
210270 manifest = ctx. env. manifest
@@ -385,21 +445,30 @@ const SHIM_VERSION = 1.0
385445const SHIM_HEADER = """ $SHIM_COMMENT This file is generated by the Julia package manager.
386446 $SHIM_COMMENT Shim version: $SHIM_VERSION """
387447
388-
389448function generate_shims_for_apps (pkgname, apps, env, julia)
390449 for (_, app) in apps
391450 generate_shim (pkgname, app, env, julia)
392451 end
393452end
394453
395454function generate_shim (pkgname, app:: AppInfo , env, julia)
455+ validate_package_name (pkgname)
456+ validate_app_name (app. name)
457+ validate_submodule_name (app. submodule)
458+
459+ module_spec = app. submodule === nothing ? pkgname : " $(pkgname) .$(app. submodule) "
460+
396461 filename = app. name * (Sys. iswindows () ? " .bat" : " " )
397462 julia_bin_filename = joinpath (julia_bin_path (), filename)
398- mkpath (dirname (filename ))
463+ mkpath (dirname (julia_bin_filename ))
399464 content = if Sys. iswindows ()
400- windows_shim (pkgname, app, julia, env)
465+ julia_escaped = " \" $(Base. shell_escape_wincmd (julia)) \" "
466+ module_spec_escaped = " \" $(Base. shell_escape_wincmd (module_spec)) \" "
467+ windows_shim (julia_escaped, module_spec_escaped, env)
401468 else
402- bash_shim (pkgname, app, julia, env)
469+ julia_escaped = Base. shell_escape (julia)
470+ module_spec_escaped = Base. shell_escape (module_spec)
471+ bash_shim (julia_escaped, module_spec_escaped, env)
403472 end
404473 overwrite_file_if_different (julia_bin_filename, content)
405474 if Sys. isunix ()
@@ -408,24 +477,22 @@ function generate_shim(pkgname, app::AppInfo, env, julia)
408477end
409478
410479
411- function bash_shim (pkgname, app:: AppInfo , julia:: String , env)
412- module_spec = app. submodule === nothing ? pkgname : " $(pkgname) .$(app. submodule) "
480+ function bash_shim (julia_escaped:: String , module_spec_escaped:: String , env)
413481 return """
414482 #!/usr/bin/env bash
415483
416484 $SHIM_HEADER
417485
418486 export JULIA_LOAD_PATH=$(repr (env))
419487 export JULIA_DEPOT_PATH=$(repr (join (DEPOT_PATH , ' :' )))
420- exec $julia \\
488+ exec $julia_escaped \\
421489 --startup-file=no \\
422- -m $(module_spec) \\
490+ -m $module_spec_escaped \\
423491 "\$ @"
424492 """
425493end
426494
427- function windows_shim (pkgname, app:: AppInfo , julia:: String , env)
428- module_spec = app. submodule === nothing ? pkgname : " $(pkgname) .$(app. submodule) "
495+ function windows_shim (julia_escaped:: String , module_spec_escaped:: String , env)
429496 return """
430497 @echo off
431498
@@ -435,9 +502,9 @@ function windows_shim(pkgname, app::AppInfo, julia::String, env)
435502 set JULIA_LOAD_PATH=$env
436503 set JULIA_DEPOT_PATH=$(join (DEPOT_PATH , ' ;' ))
437504
438- $julia ^
505+ $julia_escaped ^
439506 --startup-file=no ^
440- -m $(module_spec) ^
507+ -m $module_spec_escaped ^
441508 %*
442509 """
443510end
0 commit comments