diff --git a/CLAUDE.md b/CLAUDE.md index bd32ad4..f0a3712 100644 --- a/CLAUDE.md +++ b/CLAUDE.md @@ -224,7 +224,8 @@ The CLI provides Julia installation and execution with JuliaHub configuration: - Installs latest stable Julia version ### Julia Credentials -- **Authentication file**: Automatically creates `~/.julia/servers//auth.toml` +- **Authentication file**: Automatically creates `$JULIA_DEPOT_PATH/servers//auth.toml` (or `~/.julia/servers//auth.toml` if `JULIA_DEPOT_PATH` is not set) +- **Depot path detection**: Respects `JULIA_DEPOT_PATH` environment variable, uses first path if multiple are specified - **Atomic writes**: Uses temporary file + rename for safe credential updates - **Automatic updates**: Credentials are automatically refreshed when: - User runs `jh auth login` @@ -252,7 +253,7 @@ jh run -- --project=. --threads=4 script.jl # Run with flags ```bash jh run setup ``` -- Creates/updates `~/.julia/servers//auth.toml` with current credentials +- Creates/updates `$JULIA_DEPOT_PATH/servers//auth.toml` with current credentials (or `~/.julia/servers//auth.toml` if not set) - Does not start Julia - Useful for explicitly updating credentials @@ -265,6 +266,7 @@ jh run setup - File uploads use multipart form data with proper content types - Julia auth files use TOML format with `preferred_username` from JWT claims - Julia auth files use atomic writes (temp file + rename) to prevent corruption +- Julia credentials respect `JULIA_DEPOT_PATH` environment variable (uses first path if multiple are specified) - Julia credentials are automatically updated after login and token refresh - Git commands use `http.extraHeader` for authentication and pass through all arguments - Git credential helper provides seamless authentication for standard Git commands @@ -281,7 +283,9 @@ jh run setup The Julia credentials system consists of three main functions: 1. **`createJuliaAuthFile(server, token)`**: - - Creates `~/.julia/servers//auth.toml` with TOML-formatted credentials + - Determines depot path from `JULIA_DEPOT_PATH` environment variable (uses first path if multiple) + - Falls back to `~/.julia` if `JULIA_DEPOT_PATH` is not set + - Creates `{depot}/servers//auth.toml` with TOML-formatted credentials - Uses atomic writes: writes to temporary file, syncs, then renames - Includes all necessary fields: tokens, expiration, refresh URL, user info - Called by `setupJuliaCredentials()` and `updateJuliaCredentialsIfNeeded()` @@ -306,7 +310,8 @@ The Julia credentials system consists of three main functions: The `updateJuliaCredentialsIfNeeded(server, token)` function: - Called automatically by `ensureValidToken()` after token refresh -- Checks if `~/.julia/servers//auth.toml` exists +- Determines depot path from `JULIA_DEPOT_PATH` (same logic as `createJuliaAuthFile`) +- Checks if `{depot}/servers//auth.toml` exists - If exists, updates it with refreshed token - If not exists, does nothing (user hasn't used Julia integration yet) - Errors are silently ignored to avoid breaking token operations diff --git a/README.md b/README.md index e896a05..59ca34a 100644 --- a/README.md +++ b/README.md @@ -270,7 +270,7 @@ jh run -- --project=. --threads=4 script.jl ``` Note: Arguments after `--` are passed directly to Julia. The `jh run` command: -1. Sets up JuliaHub credentials in `~/.julia/servers//auth.toml` +1. Sets up JuliaHub credentials in `$JULIA_DEPOT_PATH/servers//auth.toml` (or `~/.julia/servers//auth.toml` if `JULIA_DEPOT_PATH` is not set) 2. Configures `JULIA_PKG_SERVER` environment variable 3. Starts Julia with your specified arguments diff --git a/auth.go b/auth.go index f8e2528..3430860 100644 --- a/auth.go +++ b/auth.go @@ -339,13 +339,14 @@ func ensureValidToken() (*StoredToken, error) { // updateJuliaCredentialsIfNeeded updates Julia credentials if the auth file exists // This is called after token refresh to keep credentials in sync func updateJuliaCredentialsIfNeeded(server string, token *StoredToken) error { - homeDir, err := os.UserHomeDir() + // Determine Julia depot path + depotPath, err := getJuliaDepotPath() if err != nil { return err } // Check if the auth.toml file exists - authFilePath := filepath.Join(homeDir, ".julia", "servers", server, "auth.toml") + authFilePath := filepath.Join(depotPath, "servers", server, "auth.toml") if _, err := os.Stat(authFilePath); os.IsNotExist(err) { // File doesn't exist, so user hasn't used Julia integration yet return nil diff --git a/run.go b/run.go index 764c6ed..c1ddce3 100644 --- a/run.go +++ b/run.go @@ -7,15 +7,36 @@ import ( "path/filepath" ) +func getJuliaDepotPath() (string, error) { + var depotPath string + if juliaDepot := os.Getenv("JULIA_DEPOT_PATH"); juliaDepot != "" { + // Use first path from JULIA_DEPOT_PATH (paths are separated by : on Unix, ; on Windows) + depotPaths := filepath.SplitList(juliaDepot) + if len(depotPaths) > 0 { + depotPath = depotPaths[0] + } + } + + // Fall back to ~/.julia if JULIA_DEPOT_PATH is not set + if depotPath == "" { + homeDir, err := os.UserHomeDir() + if err != nil { + return "", fmt.Errorf("failed to get user home directory: %w", err) + } + depotPath = filepath.Join(homeDir, ".julia") + } + + return depotPath, nil +} + func createJuliaAuthFile(server string, token *StoredToken) error { - // Get user home directory - homeDir, err := os.UserHomeDir() + depotPath, err := getJuliaDepotPath() if err != nil { - return fmt.Errorf("failed to get user home directory: %w", err) + return err } - // Create ~/.julia/servers/{server}/ directory - serverDir := filepath.Join(homeDir, ".julia", "servers", server) + // Create {depot}/servers/{server}/ directory + serverDir := filepath.Join(depotPath, "servers", server) if err := os.MkdirAll(serverDir, 0755); err != nil { return fmt.Errorf("failed to create server directory: %w", err) }