github.com/opentofu/opentofu@v1.7.1/internal/genconfig/generate_config_write.go (about)

     1  // Copyright (c) The OpenTofu Authors
     2  // SPDX-License-Identifier: MPL-2.0
     3  // Copyright (c) 2023 HashiCorp, Inc.
     4  // SPDX-License-Identifier: MPL-2.0
     5  
     6  package genconfig
     7  
     8  import (
     9  	"fmt"
    10  	"io"
    11  	"os"
    12  
    13  	"github.com/opentofu/opentofu/internal/tfdiags"
    14  )
    15  
    16  func ShouldWriteConfig(out string) bool {
    17  	// No specified out file, so don't write anything.
    18  	return len(out) != 0
    19  }
    20  
    21  func ValidateTargetFile(out string) (diags tfdiags.Diagnostics) {
    22  	if _, err := os.Stat(out); !os.IsNotExist(err) {
    23  		diags = diags.Append(tfdiags.Sourceless(
    24  			tfdiags.Error,
    25  			"Target generated file already exists",
    26  			"OpenTofu can only write generated config into a new file. Either choose a different target location or move all existing configuration out of the target file, delete it and try again."))
    27  
    28  	}
    29  	return diags
    30  }
    31  
    32  type Change struct {
    33  	Addr            string
    34  	ImportID        string
    35  	GeneratedConfig string
    36  }
    37  
    38  func (c *Change) MaybeWriteConfig(writer io.Writer, out string) (io.Writer, bool, tfdiags.Diagnostics) {
    39  	var wroteConfig bool
    40  	var diags tfdiags.Diagnostics
    41  	if len(c.GeneratedConfig) > 0 {
    42  		if writer == nil {
    43  			// Lazily create the generated file, in case we have no
    44  			// generated config to create.
    45  			if w, err := os.Create(out); err != nil {
    46  				if os.IsPermission(err) {
    47  					diags = diags.Append(tfdiags.Sourceless(
    48  						tfdiags.Error,
    49  						"Failed to create target generated file",
    50  						fmt.Sprintf("OpenTofu did not have permission to create the generated file (%s) in the target directory. Please modify permissions over the target directory, and try again.", out)))
    51  					return nil, false, diags
    52  				}
    53  
    54  				diags = diags.Append(tfdiags.Sourceless(
    55  					tfdiags.Error,
    56  					"Failed to create target generated file",
    57  					fmt.Sprintf("OpenTofu could not create the generated file (%s) in the target directory: %v. Depending on the error message, this may be a bug in OpenTofu itself. If so, please report it!", out, err)))
    58  				return nil, false, diags
    59  			} else {
    60  				writer = w
    61  			}
    62  
    63  			header := "# __generated__ by OpenTofu\n# Please review these resources and move them into your main configuration files.\n"
    64  			// Missing the header from the file, isn't the end of the world
    65  			// so if this did return an error, then we will just ignore it.
    66  			_, _ = writer.Write([]byte(header))
    67  		}
    68  
    69  		header := "\n# __generated__ by OpenTofu"
    70  		if len(c.ImportID) > 0 {
    71  			header += fmt.Sprintf(" from %q", c.ImportID)
    72  		}
    73  		header += "\n"
    74  		if _, err := writer.Write([]byte(fmt.Sprintf("%s%s\n", header, c.GeneratedConfig))); err != nil {
    75  			diags = diags.Append(tfdiags.Sourceless(
    76  				tfdiags.Warning,
    77  				"Failed to save generated config",
    78  				fmt.Sprintf("OpenTofu encountered an error while writing generated config: %v. The config for %s must be created manually before applying. Depending on the error message, this may be a bug in OpenTofu itself. If so, please report it!", err, c.Addr)))
    79  		}
    80  		wroteConfig = true
    81  	}
    82  
    83  	return writer, wroteConfig, diags
    84  }