@@ -62,6 +62,7 @@ func mainerr() (retErr error) {
6262 mainUsage (os .Stderr )
6363 }
6464 var envVars envVarsFlag
65+ fUpdate := fs .Bool ("u" , false , "update archive file if a cmp fails" )
6566 fWork := fs .Bool ("work" , false , "print temporary work directory and do not remove when done" )
6667 fVerbose := fs .Bool ("v" , false , "run tests verbosely" )
6768 fs .Var (& envVars , "e" , "pass through environment variable to script (can appear multiple times)" )
@@ -84,6 +85,20 @@ func mainerr() (retErr error) {
8485 files = []string {"-" }
8586 }
8687
88+ // If we are only reading from stdin, -u cannot be specified. It seems a bit
89+ // bizarre to invoke testscript with '-' and a regular file, but hey. In
90+ // that case the -u flag will only apply to the regular file and we assume
91+ // the user knows it.
92+ onlyReadFromStdin := true
93+ for _ , f := range files {
94+ if f != "-" {
95+ onlyReadFromStdin = false
96+ }
97+ }
98+ if onlyReadFromStdin && * fUpdate {
99+ return fmt .Errorf ("cannot use -u when reading from stdin" )
100+ }
101+
87102 dirNames := make (map [string ]int )
88103 for _ , filename := range files {
89104 // TODO make running files concurrent by default? If we do, note we'll need to do
@@ -103,7 +118,7 @@ func mainerr() (retErr error) {
103118 if err := os .Mkdir (runDir , 0777 ); err != nil {
104119 return fmt .Errorf ("failed to create a run directory within %v for %v: %v" , td , renderFilename (filename ), err )
105120 }
106- if err := run (runDir , filename , * fVerbose , envVars .vals ); err != nil {
121+ if err := run (runDir , filename , * fUpdate , * fVerbose , envVars .vals ); err != nil {
107122 return err
108123 }
109124 }
@@ -162,7 +177,11 @@ func renderFilename(filename string) string {
162177 return filename
163178}
164179
165- func run (runDir , filename string , verbose bool , envVars []string ) error {
180+ // run runs the testscript archive in filename within the temporary runDir.
181+ // verbose causes the output to be verbose (akin to go test -v) and update
182+ // sets the UpdateScripts parameter passed to testscript.Run such that any
183+ // updates to the archive get written back to filename
184+ func run (runDir , filename string , update bool , verbose bool , envVars []string ) error {
166185 var ar * txtar.Archive
167186 var err error
168187
@@ -204,12 +223,15 @@ func run(runDir, filename string, verbose bool, envVars []string) error {
204223 return fmt .Errorf ("failed to write .gomodproxy files: %v" , err )
205224 }
206225
207- if err := ioutil .WriteFile (filepath .Join (runDir , "script.txt" ), txtar .Format (& script ), 0666 ); err != nil {
208- return fmt .Errorf ("failed to write script for %v: %v" , filename , err )
226+ scriptFile := filepath .Join (runDir , "script.txt" )
227+
228+ if err := ioutil .WriteFile (scriptFile , txtar .Format (& script ), 0666 ); err != nil {
229+ return fmt .Errorf ("failed to write script for %v: %v" , renderFilename (filename ), err )
209230 }
210231
211232 p := testscript.Params {
212- Dir : runDir ,
233+ Dir : runDir ,
234+ UpdateScripts : update ,
213235 }
214236
215237 if _ , err := exec .LookPath ("go" ); err == nil {
@@ -282,5 +304,28 @@ func run(runDir, filename string, verbose bool, envVars []string) error {
282304 return fmt .Errorf ("error running %v in %v\n " , renderFilename (filename ), runDir )
283305 }
284306
307+ if update && filename != "-" {
308+ // Parse the (potentially) updated scriptFile as an archive, then merge
309+ // with the original archive, retaining order. Then write the archive
310+ // back to the source file
311+ source , err := ioutil .ReadFile (scriptFile )
312+ if err != nil {
313+ return fmt .Errorf ("failed to read from script file %v for -update: %v" , scriptFile , err )
314+ }
315+ updatedAr := txtar .Parse (source )
316+ updatedFiles := make (map [string ]txtar.File )
317+ for _ , f := range updatedAr .Files {
318+ updatedFiles [f .Name ] = f
319+ }
320+ for i , f := range ar .Files {
321+ if newF , ok := updatedFiles [f .Name ]; ok {
322+ ar .Files [i ] = newF
323+ }
324+ }
325+ if err := ioutil .WriteFile (filename , txtar .Format (ar ), 0666 ); err != nil {
326+ return fmt .Errorf ("failed to write script back to %v for -update: %v" , renderFilename (filename ), err )
327+ }
328+ }
329+
285330 return nil
286331}
0 commit comments