11package main
22
33import (
4+ "bufio"
45 "bytes"
56 "fmt"
67 "io/ioutil"
@@ -16,10 +17,16 @@ import (
1617 "github.com/twpayne/go-vfs/vfst"
1718
1819 "github.com/twpayne/chezmoi/cmd"
20+ "github.com/twpayne/chezmoi/internal/chezmoi"
1921)
2022
23+ // umask is the umask used in tests. The umask applies to the process and so
24+ // cannot be overridden in individual tests.
25+ const umask = 0o22
26+
2127//nolint:interfacer
2228func TestMain (m * testing.M ) {
29+ chezmoi .SetUmask (umask )
2330 os .Exit (testscript .RunMain (m , map [string ]func () int {
2431 "chezmoi" : func () int {
2532 if err := cmd .Execute (); err != nil {
@@ -37,16 +44,19 @@ func TestScript(t *testing.T) {
3744 testscript .Run (t , testscript.Params {
3845 Dir : filepath .Join ("testdata" , "scripts" ),
3946 Cmds : map [string ]func (* testscript.TestScript , bool , []string ){
40- "chhome" : cmdChHome ,
41- "cmpmod" : cmdCmpMod ,
42- "edit" : cmdEdit ,
43- "mkfile" : cmdMkFile ,
44- "mkhomedir" : cmdMkHomeDir ,
45- "mksourcedir" : cmdMkSourceDir ,
46- "unix2dos" : cmdUNIX2DOS ,
47+ "chhome" : cmdChHome ,
48+ "cmpmod" : cmdCmpMod ,
49+ "edit" : cmdEdit ,
50+ "mkfile" : cmdMkFile ,
51+ "mkhomedir" : cmdMkHomeDir ,
52+ "mksourcedir" : cmdMkSourceDir ,
53+ "rmfinalnewline" : cmdRmFinalNewline ,
54+ "unix2dos" : cmdUNIX2DOS ,
4755 },
4856 Condition : func (cond string ) (bool , error ) {
4957 switch cond {
58+ case "darwin" :
59+ return runtime .GOOS == "darwin" , nil
5060 case "windows" :
5161 return runtime .GOOS == "windows" , nil
5262 default :
@@ -88,7 +98,7 @@ func cmdCmpMod(ts *testscript.TestScript, neg bool, args []string) {
8898 ts .Fatalf ("usage: cmpmod mode path" )
8999 }
90100 mode64 , err := strconv .ParseUint (args [0 ], 8 , 32 )
91- if err != nil || os .FileMode (mode64 )& os . ModePerm != os .FileMode (mode64 ) {
101+ if err != nil || os .FileMode (mode64 ). Perm () != os .FileMode (mode64 ) {
92102 ts .Fatalf ("invalid mode: %s" , args [0 ])
93103 }
94104 if runtime .GOOS == "windows" {
@@ -98,12 +108,13 @@ func cmdCmpMod(ts *testscript.TestScript, neg bool, args []string) {
98108 if err != nil {
99109 ts .Fatalf ("%s: %v" , args [1 ], err )
100110 }
101- equal := info .Mode ()& os .ModePerm == os .FileMode (mode64 )
111+ umask := chezmoi .GetUmask ()
112+ equal := info .Mode ().Perm ()&^umask == os .FileMode (mode64 )&^umask
102113 if neg && equal {
103- ts .Fatalf ("%s unexpectedly has mode %03o" , args [1 ], info .Mode ()& os . ModePerm )
114+ ts .Fatalf ("%s unexpectedly has mode %03o" , args [1 ], info .Mode (). Perm () )
104115 }
105116 if ! neg && ! equal {
106- ts .Fatalf ("%s has mode %03o, expected %03o" , args [1 ], info .Mode ()& os . ModePerm , os .FileMode (mode64 ))
117+ ts .Fatalf ("%s has mode %03o, expected %03o" , args [1 ], info .Mode (). Perm () , os .FileMode (mode64 ))
107118 }
108119}
109120
@@ -171,14 +182,13 @@ func cmdMkHomeDir(ts *testscript.TestScript, neg bool, args []string) {
171182 workDir := ts .Getenv ("WORK" )
172183 relPath , err := filepath .Rel (workDir , path )
173184 ts .Check (err )
174- if err := vfst . NewBuilder ().Build (vfs .NewPathFS (vfs .OSFS , workDir ), map [string ]interface {}{
185+ if err := newBuilder ().Build (vfs .NewPathFS (vfs .OSFS , workDir ), map [string ]interface {}{
175186 relPath : map [string ]interface {}{
176187 ".bashrc" : "# contents of .bashrc\n " ,
177188 ".binary" : & vfst.File {
178- Perm : 0o755 ,
189+ Perm : 0o777 ,
179190 Contents : []byte ("#!/bin/sh\n " ),
180191 },
181- ".exists" : "# contents of .exists\n " ,
182192 ".gitconfig" : "" +
183193 "[core]\n " +
184194 " autocrlf = false\n " +
@@ -216,7 +226,7 @@ func cmdMkSourceDir(ts *testscript.TestScript, neg bool, args []string) {
216226 workDir := ts .Getenv ("WORK" )
217227 relPath , err := filepath .Rel (workDir , sourceDir )
218228 ts .Check (err )
219- err = vfst . NewBuilder ().Build (vfs .NewPathFS (vfs .OSFS , workDir ), map [string ]interface {}{
229+ err = newBuilder ().Build (vfs .NewPathFS (vfs .OSFS , workDir ), map [string ]interface {}{
220230 relPath : map [string ]interface {}{
221231 "dot_absent" : "" ,
222232 "empty_dot_hushlogin" : "" ,
@@ -239,6 +249,30 @@ func cmdMkSourceDir(ts *testscript.TestScript, neg bool, args []string) {
239249 }
240250}
241251
252+ // cmdRmFinalNewline removes final newlines.
253+ func cmdRmFinalNewline (ts * testscript.TestScript , neg bool , args []string ) {
254+ if neg {
255+ ts .Fatalf ("unsupported: ! rmfinalnewline" )
256+ }
257+ if len (args ) < 1 {
258+ ts .Fatalf ("usage: rmfinalnewline paths..." )
259+ }
260+ for _ , arg := range args {
261+ filename := ts .MkAbs (arg )
262+ data , err := ioutil .ReadFile (filename )
263+ if err != nil {
264+ ts .Fatalf ("%s: %v" , filename , err )
265+ }
266+ if len (data ) == 0 || data [len (data )- 1 ] != '\n' {
267+ continue
268+ }
269+ //nolint:gosec
270+ if err := ioutil .WriteFile (filename , data [:len (data )- 1 ], 0o666 ); err != nil {
271+ ts .Fatalf ("%s: %v" , filename , err )
272+ }
273+ }
274+ }
275+
242276// cmdUNIX2DOS converts files from UNIX line endings to DOS line endings.
243277func cmdUNIX2DOS (ts * testscript.TestScript , neg bool , args []string ) {
244278 if neg {
@@ -250,17 +284,24 @@ func cmdUNIX2DOS(ts *testscript.TestScript, neg bool, args []string) {
250284 for _ , arg := range args {
251285 filename := ts .MkAbs (arg )
252286 data , err := ioutil .ReadFile (filename )
253- if err != nil {
254- ts .Fatalf ("%s: %v" , filename , err )
255- }
256- data = bytes .Join (bytes .Split (data , []byte {'\n' }), []byte {'\r' , '\n' })
287+ ts .Check (err )
288+ dosData , err := unix2DOS (data )
289+ ts .Check (err )
257290 //nolint:gosec
258- if err := ioutil .WriteFile (filename , data , 0o666 ); err != nil {
291+ if err := ioutil .WriteFile (filename , dosData , 0666 ); err != nil {
259292 ts .Fatalf ("%s: %v" , filename , err )
260293 }
261294 }
262295}
263296
297+ func newBuilder () * vfst.Builder {
298+ return vfst .NewBuilder (vfst .BuilderUmask (umask ))
299+ }
300+
301+ func prependDirToPath (dir , path string ) string {
302+ return strings .Join (append ([]string {dir }, filepath .SplitList (path )... ), string (os .PathListSeparator ))
303+ }
304+
264305func setup (env * testscript.Env ) error {
265306 var (
266307 binDir = filepath .Join (env .WorkDir , "bin" )
@@ -299,29 +340,43 @@ func setup(env *testscript.Env) error {
299340 "editor" : & vfst.File {
300341 Perm : 0o755 ,
301342 Contents : []byte (strings .Join ([]string {
302- ` #!/bin/sh` ,
303- `` ,
304- ` for filename in $*; do` ,
305- ` echo " # edited" >> $filename` ,
306- ` done` ,
343+ " #!/bin/sh" ,
344+ "" ,
345+ " for filename in $*; do" ,
346+ " echo ' # edited' >> $filename" ,
347+ " done" ,
307348 }, "\n " )),
308349 },
309350 // shell is a non-interactive script that appends the directory in
310351 // which it was launched to $WORK/shell.log.
311352 "shell" : & vfst.File {
312353 Perm : 0o755 ,
313354 Contents : []byte (strings .Join ([]string {
314- ` #!/bin/sh` ,
315- `` ,
316- ` echo $PWD >> ` + filepath .Join (env .WorkDir , "shell.log" ),
355+ " #!/bin/sh" ,
356+ "" ,
357+ " echo $PWD >> '" + filepath .Join (env .WorkDir , "shell.log" ) + "'" ,
317358 }, "\n " )),
318359 },
319360 }
320361 }
321362
322- return vfst . NewBuilder ().Build (vfs .NewPathFS (vfs .OSFS , env .WorkDir ), root )
363+ return newBuilder ().Build (vfs .NewPathFS (vfs .OSFS , env .WorkDir ), root )
323364}
324365
325- func prependDirToPath (dir , path string ) string {
326- return strings .Join (append ([]string {dir }, filepath .SplitList (path )... ), string (os .PathListSeparator ))
366+ // unix2DOS returns data with UNIX line endings converted to DOS line endings.
367+ func unix2DOS (data []byte ) ([]byte , error ) {
368+ sb := & strings.Builder {}
369+ s := bufio .NewScanner (bytes .NewReader (data ))
370+ for s .Scan () {
371+ if _ , err := sb .Write (s .Bytes ()); err != nil {
372+ return nil , err
373+ }
374+ if _ , err := sb .WriteString ("\r \n " ); err != nil {
375+ return nil , err
376+ }
377+ }
378+ if err := s .Err (); err != nil {
379+ return nil , err
380+ }
381+ return []byte (sb .String ()), nil
327382}
0 commit comments