Skip to content

Commit ff2a7ea

Browse files
committed
feat: multi shell implementation
1 parent b0b7f88 commit ff2a7ea

8 files changed

Lines changed: 315 additions & 11 deletions

File tree

README.md

Lines changed: 25 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -27,9 +27,8 @@ To make `phpvm` available in your terminal, you need to add its binary directory
2727
Add the following lines to your shell configuration file (e.g., `~/.zshrc`, `~/.bash_profile`, `~/.config/fish/config.fish`):
2828

2929
```bash
30-
export PATH="$HOME/.phpvm/bin:$HOME/.phpvm/sbin:$PATH"
3130
eval "$(phpvm completion <your_shell>)" # Replace <your_shell> with your shell (e.g., zsh, bash)
32-
phpvm default
31+
eval "$(phpvm env <your_shell>)"
3332
```
3433

3534
After adding these lines, reload your shell configuration:
@@ -38,6 +37,7 @@ After adding these lines, reload your shell configuration:
3837
source ~/.zshrc # Or your shell config file
3938
```
4039

40+
4141
## Usage
4242

4343
```
@@ -54,6 +54,28 @@ Available Commands:
5454
-h, --help help for phpvm
5555
```
5656

57+
58+
### `php env [shell]`
59+
60+
Sets up the env variables for the specified shell.
61+
62+
```
63+
Print and set up required environment variables for bash, zsh, fish
64+
65+
Usage:
66+
phpvm env [shell] [flags]
67+
68+
Flags:
69+
-h, --help help for env
70+
-m, --multi-shell Different phpversion per shell
71+
-n, --now run phpvm use now
72+
-c, --use-on-cd Use phpvm cd on cd
73+
```
74+
75+
e.g `phpvm env zsh --use-on-cd --multi-shell`
76+
```
77+
```
78+
5779
### `phpvm cd`
5880

5981
Takes the php value from `composer.json`'s `require` section and attempts to switch to a compatible PHP version.
@@ -148,4 +170,4 @@ install 8.4 and set it as the default and set it to using.
148170
149171
```sh
150172
phpvm install -ud 8.4
151-
```
173+
```

cmd/cd.go

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,8 @@ Copyright © 2025 Jerome Duncan <jerome@jrmd.dev>
44
package cmd
55

66
import (
7+
"fmt"
8+
79
"github.com/jrmd/phpvm/utils"
810
"github.com/spf13/cobra"
911
)
@@ -13,6 +15,7 @@ var cdCmd = &cobra.Command{
1315
Use: "cd",
1416
Short: "Use composer php requirements",
1517
Run: func(cmd *cobra.Command, args []string) {
18+
fmt.Println("cd called")
1619
utils.SetAppropriateVersion()
1720
},
1821
}

cmd/env.go

Lines changed: 187 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,187 @@
1+
/*
2+
Copyright © 2025 Jerome Duncan <jerome@jrmd.dev>
3+
*/
4+
package cmd
5+
6+
import (
7+
"fmt"
8+
"os"
9+
"time"
10+
11+
"github.com/jrmd/phpvm/utils"
12+
"github.com/spf13/cobra"
13+
)
14+
15+
type Env struct {
16+
Dir string
17+
UseOnCd bool
18+
MultiShell bool
19+
Now bool
20+
SessionId string
21+
}
22+
23+
func GenZSH(env Env) {
24+
script := ""
25+
26+
if env.UseOnCd {
27+
script += `
28+
function chpwd() {
29+
phpvm use &>/dev/null # run phpvm cd
30+
}
31+
`
32+
}
33+
34+
if env.MultiShell {
35+
script += fmt.Sprintf(`
36+
export PHPVM_SESSION="%s"
37+
`, env.SessionId)
38+
}
39+
40+
41+
script += fmt.Sprintf(`
42+
export PATH="%s/bin:%s/sbin:$PATH"
43+
`, env.Dir, env.Dir)
44+
45+
if env.Now {
46+
script += `
47+
phpvm use
48+
`
49+
} else {
50+
script += `
51+
phpvm default
52+
`
53+
}
54+
55+
fmt.Println(script)
56+
57+
}
58+
59+
60+
func GenBash(env Env) {
61+
script := ""
62+
63+
if env.UseOnCd {
64+
script += `
65+
__phpvmcd() {{
66+
\cd "$@" || return $?
67+
phpvm use
68+
}}
69+
70+
alias cd=__phpvmcd
71+
`
72+
}
73+
74+
if env.MultiShell {
75+
script += fmt.Sprintf(`
76+
export PHPVM_SESSION="%s"
77+
`, env.SessionId)
78+
}
79+
80+
81+
script += fmt.Sprintf(`
82+
export PATH="%s/bin:%s/sbin:$PATH"
83+
`, env.Dir, env.Dir)
84+
85+
if env.Now {
86+
script += `
87+
phpvm use
88+
`
89+
} else {
90+
script += `
91+
phpvm default
92+
`
93+
}
94+
95+
fmt.Println(script)
96+
}
97+
98+
func GenFish(env Env) {
99+
script := ""
100+
101+
if env.UseOnCd {
102+
script += `
103+
function __phpvmoncd --on-event cd
104+
phpvm use
105+
end
106+
`
107+
}
108+
109+
if env.MultiShell {
110+
script += fmt.Sprintf(`
111+
set -gx PHPVM_SESSION "%s"
112+
`, env.SessionId)
113+
}
114+
115+
116+
script += fmt.Sprintf(`
117+
set -gx PATH "%s/bin" "%s/sbin" $PATH
118+
`, env.Dir, env.Dir)
119+
120+
if env.Now {
121+
script += `
122+
phpvm use
123+
`
124+
} else {
125+
script += `
126+
phpvm default
127+
`
128+
}
129+
130+
fmt.Println(script)
131+
}
132+
133+
// envCmd represents the env command
134+
var envCmd = &cobra.Command{
135+
Use: "env [shell]",
136+
Short: "Print and set up required environment variables for",
137+
Run: func(cmd *cobra.Command, args []string) {
138+
useOnCd := cmd.Flag("use-on-cd").Value.String() == "true"
139+
multiShell := cmd.Flag("multi-shell").Value.String() == "true"
140+
now := cmd.Flag("multi-shell").Value.String() == "true"
141+
142+
session := fmt.Sprintf("%d_%d", os.Getpid(), time.Now().UnixMicro())
143+
144+
if multiShell {
145+
os.Setenv("PHPVM_SESSION", session)
146+
} else {
147+
os.Setenv("PHPVM_SESSION", "")
148+
}
149+
150+
dir, err := utils.GetEnvDir()
151+
152+
if err != nil {
153+
os.Exit(1)
154+
}
155+
env := Env {
156+
dir,
157+
useOnCd,
158+
multiShell,
159+
now,
160+
session,
161+
}
162+
163+
switch args[0] {
164+
case "zsh":
165+
GenZSH(env)
166+
case "bash":
167+
GenBash(env)
168+
case "fish":
169+
GenFish(env)
170+
}
171+
},
172+
}
173+
174+
func init() {
175+
rootCmd.AddCommand(envCmd)
176+
177+
// Here you will define your flags and configuration settings.
178+
179+
// Cobra supports Persistent Flags which will work for this command
180+
// and all subcommands, e.g.:
181+
182+
// Cobra supports local flags which will only run when this command
183+
// is called directly, e.g.:
184+
envCmd.Flags().BoolP("use-on-cd", "c", false, "Use phpvm cd on cd")
185+
envCmd.Flags().BoolP("multi-shell", "m", false, "Different phpversion per shell")
186+
envCmd.Flags().BoolP("now", "n", false, "run phpvm use now")
187+
}

cmd/use.go

Lines changed: 6 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -20,14 +20,18 @@ var useCmd = &cobra.Command{
2020
Run: func(cmd *cobra.Command, args []string) {
2121
var version string
2222
var err error
23-
23+
config := utils.GetConfig()
2424
if len(args) > 0 {
2525
version = args[0]
2626
} else {
2727
version, err = utils.GetAppropriateVersion()
2828

2929
if err != nil {
30-
os.Exit(1)
30+
if config.Default == "" {
31+
os.Exit(1)
32+
}
33+
34+
version = config.Default
3135
}
3236
}
3337

@@ -44,7 +48,6 @@ var useCmd = &cobra.Command{
4448

4549
fmt.Printf("Version %s set successfully\n", version)
4650

47-
config := utils.GetConfig()
4851
config.Versions = utils.UniqAppend(config.Versions, version)
4952

5053
if setDefault {

cmd/version.go

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -14,7 +14,7 @@ var versionCmd = &cobra.Command{
1414
Use: "version",
1515
Short: "Show current version",
1616
Run: func(cmd *cobra.Command, args []string) {
17-
fmt.Println("PHPVM version 1.0.0")
17+
fmt.Println("PHPVM version 1.1.0")
1818
},
1919
}
2020

utils/composer.go

Lines changed: 5 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -100,10 +100,12 @@ func GetAppropriateVersion() (string, error) {
100100
if err != nil {
101101
return "", err
102102
}
103-
config := GetConfig()
103+
current := GetCurrent()
104104

105-
if ok, _ := VersionMatches(config.Current); ok {
106-
return "", nil
105+
if current != "" {
106+
if ok, _ := VersionMatches(current); ok {
107+
return "", nil
108+
}
107109
}
108110

109111
versions := AvailableVersions()

utils/dirs.go

Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -28,3 +28,18 @@ func PhpVMPath() (string, error) {
2828

2929
return path.Join(home, ".phpvm"), nil
3030
}
31+
32+
func GetEnvDir() (string, error) {
33+
sess := os.Getenv("PHPVM_SESSION")
34+
35+
if sess == "" {
36+
return PhpVMPath()
37+
}
38+
39+
home, err := os.UserHomeDir()
40+
if err != nil {
41+
return "", err
42+
}
43+
44+
return path.Join(home, ".local/state/phpvm_multishell", sess), nil
45+
}

0 commit comments

Comments
 (0)