Skip to content
Merged
Show file tree
Hide file tree
Changes from 1 commit
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
13 changes: 9 additions & 4 deletions CLAUDE.md
Original file line number Diff line number Diff line change
Expand Up @@ -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/<server>/auth.toml`
- **Authentication file**: Automatically creates `$JULIA_DEPOT_PATH/servers/<server>/auth.toml` (or `~/.julia/servers/<server>/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`
Expand Down Expand Up @@ -252,7 +253,7 @@ jh run -- --project=. --threads=4 script.jl # Run with flags
```bash
jh run setup
```
- Creates/updates `~/.julia/servers/<server>/auth.toml` with current credentials
- Creates/updates `$JULIA_DEPOT_PATH/servers/<server>/auth.toml` with current credentials (or `~/.julia/servers/<server>/auth.toml` if not set)
- Does not start Julia
- Useful for explicitly updating credentials

Expand All @@ -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
Expand All @@ -281,7 +283,9 @@ jh run setup
The Julia credentials system consists of three main functions:

1. **`createJuliaAuthFile(server, token)`**:
- Creates `~/.julia/servers/<server>/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/<server>/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()`
Expand All @@ -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/<server>/auth.toml` exists
- Determines depot path from `JULIA_DEPOT_PATH` (same logic as `createJuliaAuthFile`)
- Checks if `{depot}/servers/<server>/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
Expand Down
2 changes: 1 addition & 1 deletion README.md
Original file line number Diff line number Diff line change
Expand Up @@ -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/<server>/auth.toml`
1. Sets up JuliaHub credentials in `$JULIA_DEPOT_PATH/servers/<server>/auth.toml` (or `~/.julia/servers/<server>/auth.toml` if `JULIA_DEPOT_PATH` is not set)
2. Configures `JULIA_PKG_SERVER` environment variable
3. Starts Julia with your specified arguments

Expand Down
22 changes: 18 additions & 4 deletions auth.go
Original file line number Diff line number Diff line change
Expand Up @@ -339,13 +339,27 @@ 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()
if err != nil {
return err
// Determine Julia depot path
Copy link
Member

@vdayanand vdayanand Feb 6, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Maybe its simpler rely on Base.DEPOT_PATH?. Oops, Didnt realize this was go

var depotPath string
if juliaDepot := os.Getenv("JULIA_DEPOT_PATH"); juliaDepot != "" {
// Use first path from JULIA_DEPOT_PATH
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 err
}
depotPath = filepath.Join(homeDir, ".julia")
}

// 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
Expand Down
25 changes: 19 additions & 6 deletions run.go
Original file line number Diff line number Diff line change
Expand Up @@ -8,14 +8,27 @@ import (
)

func createJuliaAuthFile(server string, token *StoredToken) error {
// Get user home directory
homeDir, err := os.UserHomeDir()
if err != nil {
return fmt.Errorf("failed to get user home directory: %w", err)
// Determine Julia depot path
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")
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Can we make this a separate function so it can be reused ?

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

can we ruse getJuliaDepotPath in updateJuliaCredentialsIfNeeded?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

forgot to push earlier 😅 , updated

}

// 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)
}
Expand Down