Thanks to visit codestin.com
Credit goes to github.com

Skip to content

Commit edf2889

Browse files
authored
feat: check for .ps1 dotfiles scripts on windows (#16785)
1 parent 10f1e0b commit edf2889

File tree

4 files changed

+125
-56
lines changed

4 files changed

+125
-56
lines changed

cli/dotfiles.go

+17-18
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,7 @@ import (
77
"os"
88
"os/exec"
99
"path/filepath"
10+
"runtime"
1011
"strings"
1112
"time"
1213

@@ -41,16 +42,7 @@ func (r *RootCmd) dotfiles() *serpent.Command {
4142
dotfilesDir = filepath.Join(cfgDir, dotfilesRepoDir)
4243
// This follows the same pattern outlined by others in the market:
4344
// https://github.com/coder/coder/pull/1696#issue-1245742312
44-
installScriptSet = []string{
45-
"install.sh",
46-
"install",
47-
"bootstrap.sh",
48-
"bootstrap",
49-
"script/bootstrap",
50-
"setup.sh",
51-
"setup",
52-
"script/setup",
53-
}
45+
installScriptSet = installScriptFiles()
5446
)
5547

5648
if cfg == "" {
@@ -195,21 +187,28 @@ func (r *RootCmd) dotfiles() *serpent.Command {
195187

196188
_, _ = fmt.Fprintf(inv.Stdout, "Running %s...\n", script)
197189

198-
// Check if the script is executable and notify on error
199190
scriptPath := filepath.Join(dotfilesDir, script)
200-
fi, err := os.Stat(scriptPath)
201-
if err != nil {
202-
return xerrors.Errorf("stat %s: %w", scriptPath, err)
203-
}
204191

205-
if fi.Mode()&0o111 == 0 {
206-
return xerrors.Errorf("script %q does not have execute permissions", script)
192+
// Permissions checks will always fail on Windows, since it doesn't have
193+
// conventional Unix file system permissions.
194+
if runtime.GOOS != "windows" {
195+
// Check if the script is executable and notify on error
196+
fi, err := os.Stat(scriptPath)
197+
if err != nil {
198+
return xerrors.Errorf("stat %s: %w", scriptPath, err)
199+
}
200+
if fi.Mode()&0o111 == 0 {
201+
return xerrors.Errorf("script %q does not have execute permissions", script)
202+
}
207203
}
208204

209205
// it is safe to use a variable command here because it's from
210206
// a filtered list of pre-approved install scripts
211207
// nolint:gosec
212-
scriptCmd := exec.CommandContext(inv.Context(), filepath.Join(dotfilesDir, script))
208+
scriptCmd := exec.CommandContext(inv.Context(), scriptPath)
209+
if runtime.GOOS == "windows" {
210+
scriptCmd = exec.CommandContext(inv.Context(), "powershell", "-NoLogo", scriptPath)
211+
}
213212
scriptCmd.Dir = dotfilesDir
214213
scriptCmd.Stdout = inv.Stdout
215214
scriptCmd.Stderr = inv.Stderr

cli/dotfiles_other.go

+20
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,20 @@
1+
//go:build !windows
2+
3+
package cli
4+
5+
func installScriptFiles() []string {
6+
return []string{
7+
"install.sh",
8+
"install",
9+
"bootstrap.sh",
10+
"bootstrap",
11+
"setup.sh",
12+
"setup",
13+
"script/install.sh",
14+
"script/install",
15+
"script/bootstrap.sh",
16+
"script/bootstrap",
17+
"script/setup.sh",
18+
"script/setup",
19+
}
20+
}

cli/dotfiles_test.go

+76-38
Original file line numberDiff line numberDiff line change
@@ -116,11 +116,65 @@ func TestDotfiles(t *testing.T) {
116116
require.NoError(t, staterr)
117117
require.True(t, stat.IsDir())
118118
})
119+
t.Run("SymlinkBackup", func(t *testing.T) {
120+
t.Parallel()
121+
_, root := clitest.New(t)
122+
testRepo := testGitRepo(t, root)
123+
124+
// nolint:gosec
125+
err := os.WriteFile(filepath.Join(testRepo, ".bashrc"), []byte("wow"), 0o750)
126+
require.NoError(t, err)
127+
128+
// add a conflicting file at destination
129+
// nolint:gosec
130+
err = os.WriteFile(filepath.Join(string(root), ".bashrc"), []byte("backup"), 0o750)
131+
require.NoError(t, err)
132+
133+
c := exec.Command("git", "add", ".bashrc")
134+
c.Dir = testRepo
135+
err = c.Run()
136+
require.NoError(t, err)
137+
138+
c = exec.Command("git", "commit", "-m", `"add .bashrc"`)
139+
c.Dir = testRepo
140+
out, err := c.CombinedOutput()
141+
require.NoError(t, err, string(out))
142+
143+
inv, _ := clitest.New(t, "dotfiles", "--global-config", string(root), "--symlink-dir", string(root), "-y", testRepo)
144+
err = inv.Run()
145+
require.NoError(t, err)
146+
147+
b, err := os.ReadFile(filepath.Join(string(root), ".bashrc"))
148+
require.NoError(t, err)
149+
require.Equal(t, string(b), "wow")
150+
151+
// check for backup file
152+
b, err = os.ReadFile(filepath.Join(string(root), ".bashrc.bak"))
153+
require.NoError(t, err)
154+
require.Equal(t, string(b), "backup")
155+
156+
// check for idempotency
157+
inv, _ = clitest.New(t, "dotfiles", "--global-config", string(root), "--symlink-dir", string(root), "-y", testRepo)
158+
err = inv.Run()
159+
require.NoError(t, err)
160+
b, err = os.ReadFile(filepath.Join(string(root), ".bashrc"))
161+
require.NoError(t, err)
162+
require.Equal(t, string(b), "wow")
163+
b, err = os.ReadFile(filepath.Join(string(root), ".bashrc.bak"))
164+
require.NoError(t, err)
165+
require.Equal(t, string(b), "backup")
166+
})
167+
}
168+
169+
func TestDotfilesInstallScriptUnix(t *testing.T) {
170+
t.Parallel()
171+
172+
if runtime.GOOS == "windows" {
173+
t.Skip()
174+
}
175+
119176
t.Run("InstallScript", func(t *testing.T) {
120177
t.Parallel()
121-
if runtime.GOOS == "windows" {
122-
t.Skip("install scripts on windows require sh and aren't very practical")
123-
}
124178
_, root := clitest.New(t)
125179
testRepo := testGitRepo(t, root)
126180

@@ -149,9 +203,6 @@ func TestDotfiles(t *testing.T) {
149203

150204
t.Run("NestedInstallScript", func(t *testing.T) {
151205
t.Parallel()
152-
if runtime.GOOS == "windows" {
153-
t.Skip("install scripts on windows require sh and aren't very practical")
154-
}
155206
_, root := clitest.New(t)
156207
testRepo := testGitRepo(t, root)
157208

@@ -183,9 +234,6 @@ func TestDotfiles(t *testing.T) {
183234

184235
t.Run("InstallScriptChangeBranch", func(t *testing.T) {
185236
t.Parallel()
186-
if runtime.GOOS == "windows" {
187-
t.Skip("install scripts on windows require sh and aren't very practical")
188-
}
189237
_, root := clitest.New(t)
190238
testRepo := testGitRepo(t, root)
191239

@@ -227,53 +275,43 @@ func TestDotfiles(t *testing.T) {
227275
require.NoError(t, err)
228276
require.Equal(t, string(b), "wow\n")
229277
})
230-
t.Run("SymlinkBackup", func(t *testing.T) {
278+
}
279+
280+
func TestDotfilesInstallScriptWindows(t *testing.T) {
281+
t.Parallel()
282+
283+
if runtime.GOOS != "windows" {
284+
t.Skip()
285+
}
286+
287+
t.Run("InstallScript", func(t *testing.T) {
231288
t.Parallel()
232289
_, root := clitest.New(t)
233290
testRepo := testGitRepo(t, root)
234291

235292
// nolint:gosec
236-
err := os.WriteFile(filepath.Join(testRepo, ".bashrc"), []byte("wow"), 0o750)
293+
err := os.WriteFile(filepath.Join(testRepo, "install.ps1"), []byte("echo \"hello, computer!\" > "+filepath.Join(string(root), "greeting.txt")), 0o750)
237294
require.NoError(t, err)
238295

239-
// add a conflicting file at destination
240-
// nolint:gosec
241-
err = os.WriteFile(filepath.Join(string(root), ".bashrc"), []byte("backup"), 0o750)
242-
require.NoError(t, err)
243-
244-
c := exec.Command("git", "add", ".bashrc")
296+
c := exec.Command("git", "add", "install.ps1")
245297
c.Dir = testRepo
246298
err = c.Run()
247299
require.NoError(t, err)
248300

249-
c = exec.Command("git", "commit", "-m", `"add .bashrc"`)
301+
c = exec.Command("git", "commit", "-m", `"add install.ps1"`)
250302
c.Dir = testRepo
251-
out, err := c.CombinedOutput()
252-
require.NoError(t, err, string(out))
303+
err = c.Run()
304+
require.NoError(t, err)
253305

254306
inv, _ := clitest.New(t, "dotfiles", "--global-config", string(root), "--symlink-dir", string(root), "-y", testRepo)
255307
err = inv.Run()
256308
require.NoError(t, err)
257309

258-
b, err := os.ReadFile(filepath.Join(string(root), ".bashrc"))
259-
require.NoError(t, err)
260-
require.Equal(t, string(b), "wow")
261-
262-
// check for backup file
263-
b, err = os.ReadFile(filepath.Join(string(root), ".bashrc.bak"))
310+
b, err := os.ReadFile(filepath.Join(string(root), "greeting.txt"))
264311
require.NoError(t, err)
265-
require.Equal(t, string(b), "backup")
266-
267-
// check for idempotency
268-
inv, _ = clitest.New(t, "dotfiles", "--global-config", string(root), "--symlink-dir", string(root), "-y", testRepo)
269-
err = inv.Run()
270-
require.NoError(t, err)
271-
b, err = os.ReadFile(filepath.Join(string(root), ".bashrc"))
272-
require.NoError(t, err)
273-
require.Equal(t, string(b), "wow")
274-
b, err = os.ReadFile(filepath.Join(string(root), ".bashrc.bak"))
275-
require.NoError(t, err)
276-
require.Equal(t, string(b), "backup")
312+
// If you squint, it does in fact say "hello, computer!" in here, but in
313+
// UTF-16 and with a byte-order-marker at the beginning. Windows!
314+
require.Equal(t, b, []byte("\xff\xfeh\x00e\x00l\x00l\x00o\x00,\x00 \x00c\x00o\x00m\x00p\x00u\x00t\x00e\x00r\x00!\x00\r\x00\n\x00"))
277315
})
278316
}
279317

cli/dotfiles_windows.go

+12
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,12 @@
1+
package cli
2+
3+
func installScriptFiles() []string {
4+
return []string{
5+
"install.ps1",
6+
"bootstrap.ps1",
7+
"setup.ps1",
8+
"script/install.ps1",
9+
"script/bootstrap.ps1",
10+
"script/setup.ps1",
11+
}
12+
}

0 commit comments

Comments
 (0)