1
0
mirror of https://github.com/smallstep/cli.git synced 2025-08-07 16:02:54 +03:00

Add flag --force on all commands using utils.WriteFile

Fixes smallstep/ca-component#121
This commit is contained in:
Mariano Cano
2018-11-27 17:36:27 -08:00
parent 1d001f5e28
commit 0cface6e9b
18 changed files with 95 additions and 240 deletions

View File

@@ -7,10 +7,12 @@ import (
"github.com/pkg/errors"
"github.com/smallstep/certificates/ca"
"github.com/smallstep/cli/command"
"github.com/smallstep/cli/config"
"github.com/smallstep/cli/crypto/pemutil"
"github.com/smallstep/cli/crypto/pki"
"github.com/smallstep/cli/errs"
"github.com/smallstep/cli/flags"
"github.com/smallstep/cli/utils"
"github.com/urfave/cli"
)
@@ -18,7 +20,7 @@ import (
func bootstrapCommand() cli.Command {
return cli.Command{
Name: "bootstrap",
Action: cli.ActionFunc(bootstrapAction),
Action: command.ActionFunc(bootstrapAction),
Usage: "initializes the environment to use the CA commands",
UsageText: "**step ca bootstrap** [**--ca-url**=<uri>] [**--fingerprint**=<fingerprint>]",
Description: `**step ca bootstrap** downloads the root certificate from the certificate
@@ -30,7 +32,7 @@ url, the root certificate location and its fingerprint.
After the bootstrap, ca commands do not need to specify the flags
--ca-url, --root or --fingerprint if we want to use the same environment.`,
Flags: []cli.Flag{caURLFlag, fingerprintFlag},
Flags: []cli.Flag{caURLFlag, fingerprintFlag, flags.Force},
}
}

View File

@@ -14,9 +14,11 @@ import (
"github.com/pkg/errors"
"github.com/smallstep/certificates/api"
"github.com/smallstep/certificates/ca"
"github.com/smallstep/cli/command"
"github.com/smallstep/cli/crypto/pemutil"
"github.com/smallstep/cli/crypto/pki"
"github.com/smallstep/cli/errs"
"github.com/smallstep/cli/flags"
"github.com/smallstep/cli/jose"
"github.com/smallstep/cli/ui"
"github.com/smallstep/cli/utils"
@@ -26,7 +28,7 @@ import (
func newCertificateCommand() cli.Command {
return cli.Command{
Name: "certificate",
Action: cli.ActionFunc(newCertificateAction),
Action: command.ActionFunc(newCertificateAction),
Usage: "generates a new certificate pair signed by the root certificate",
UsageText: `**step ca certificate** <hostname> <crt-file> <key-file>
[**--token**=<token>] [**--ca-url**=<uri>] [**--root**=<file>]
@@ -63,6 +65,7 @@ $ step ca certificate --token $TOKEN --not-after=1h internal.example.com interna
rootFlag,
notBeforeFlag,
notAfterFlag,
flags.Force,
},
}
}
@@ -70,7 +73,7 @@ $ step ca certificate --token $TOKEN --not-after=1h internal.example.com interna
func signCertificateCommand() cli.Command {
return cli.Command{
Name: "sign",
Action: cli.ActionFunc(signCertificateAction),
Action: command.ActionFunc(signCertificateAction),
Usage: "generates a new certificate signing a certificate request",
UsageText: `**step ca sign** <csr-file> <crt-file>
[**--token**=<token>] [**--ca-url**=<uri>] [**--root**=<file>]
@@ -104,6 +107,7 @@ $ step ca sign --token $TOKEN --not-after=1h internal.csr internal.crt
rootFlag,
notBeforeFlag,
notAfterFlag,
flags.Force,
},
}
}
@@ -111,7 +115,7 @@ $ step ca sign --token $TOKEN --not-after=1h internal.csr internal.crt
func renewCertificateCommand() cli.Command {
return cli.Command{
Name: "renew",
Action: cli.ActionFunc(renewCertificateAction),
Action: command.ActionFunc(renewCertificateAction),
Usage: "renew a valid certificate",
UsageText: `**step ca renew** <crt-file> <key-file>
[**--ca-url**=<uri>] [**--root**=<file>]
@@ -176,10 +180,7 @@ sequence of decimal numbers, each with optional fraction and a unit suffix, such
as "300ms", "-1.5h" or "2h45m". Valid time units are "ns", "us" (or "µs"), "ms",
"s", "m", "h".`,
},
cli.BoolFlag{
Name: "f,force",
Usage: "Force the overwrite of files without asking.",
},
flags.Force,
},
}
}
@@ -464,7 +465,7 @@ func renewCertificateAction(ctx *cli.Context) error {
}
data := append(pem.EncodeToMemory(serverBlock), pem.EncodeToMemory(caBlock)...)
if err := utils.WriteFileForce(outFile, data, 0600, ctx.Bool("force")); err != nil {
if err := utils.WriteFile(outFile, data, 0600); err != nil {
return errs.FileError(err, outFile)
}

View File

@@ -7,15 +7,17 @@ import (
"github.com/pkg/errors"
"github.com/smallstep/certificates/ca"
"github.com/smallstep/cli/command"
"github.com/smallstep/cli/crypto/pemutil"
"github.com/smallstep/cli/errs"
"github.com/smallstep/cli/flags"
"github.com/urfave/cli"
)
func rootComand() cli.Command {
return cli.Command{
Name: "root",
Action: cli.ActionFunc(rootAction),
Action: command.ActionFunc(rootAction),
Usage: "downloads and validates the root certificate",
UsageText: `**step ca root** <root-file>
[**--ca-url**=<uri>] [**--fingerprint**=<fingerprint>]`,
@@ -50,6 +52,7 @@ $ step ca root root_ca.crt \
Flags: []cli.Flag{
caURLFlag,
fingerprintFlag,
flags.Force,
},
}
}

View File

@@ -10,9 +10,11 @@ import (
"github.com/pkg/errors"
"github.com/smallstep/certificates/authority"
"github.com/smallstep/cli/command"
"github.com/smallstep/cli/crypto/pki"
"github.com/smallstep/cli/crypto/randutil"
"github.com/smallstep/cli/errs"
"github.com/smallstep/cli/flags"
"github.com/smallstep/cli/jose"
"github.com/smallstep/cli/token"
"github.com/smallstep/cli/token/provision"
@@ -30,7 +32,7 @@ type provisionersSelect struct {
func newTokenCommand() cli.Command {
return cli.Command{
Name: "token",
Action: cli.ActionFunc(newTokenAction),
Action: command.ActionFunc(newTokenAction),
Usage: "generates an OTT granting access to the CA",
UsageText: `**step ca token** <hostname>
[--**kid**=<kid>] [--**issuer**=<issuer>] [**--ca-url**=<uri>] [**--root**=<file>]
@@ -117,6 +119,7 @@ the certificate authority.`,
Usage: `Creates a token without contacting the certificate authority. Offline mode
requires the flags <--kid>, <--issuer>, <--key>, <--ca-url>, and <--root>.`,
},
flags.Force,
},
}
}

View File

@@ -5,14 +5,17 @@ import (
"io/ioutil"
"github.com/pkg/errors"
"github.com/smallstep/cli/command"
"github.com/smallstep/cli/errs"
"github.com/smallstep/cli/flags"
"github.com/smallstep/cli/utils"
"github.com/urfave/cli"
)
func bundleCommand() cli.Command {
return cli.Command{
Name: "bundle",
Action: cli.ActionFunc(bundleAction),
Action: command.ActionFunc(bundleAction),
Usage: `bundle a certificate with intermediate certificate(s) needed for certificate path validation.`,
UsageText: `**step certificate bundle** <crt_file> <ca> <bundle_file>`,
Description: `**step certificate bundle** bundles a certificate
@@ -41,6 +44,7 @@ Bundle a certificate with the intermediate certificate authority (issuer):
$ step certificate bundle foo.crt intermediate-ca.crt foo-bundle.crt
'''
`,
Flags: []cli.Flag{flags.Force},
}
}
@@ -70,7 +74,7 @@ func bundleAction(ctx *cli.Context) error {
}
chainFile := ctx.Args().Get(2)
if err := ioutil.WriteFile(chainFile,
if err := utils.WriteFile(chainFile,
append(pem.EncodeToMemory(crtBlock), pem.EncodeToMemory(caBlock)...), 0600); err != nil {
return errs.FileError(err, chainFile)
}

View File

@@ -4,13 +4,14 @@ import (
"crypto/rand"
"crypto/x509/pkix"
"encoding/pem"
"os"
"github.com/pkg/errors"
"github.com/smallstep/cli/command"
"github.com/smallstep/cli/crypto/keys"
"github.com/smallstep/cli/crypto/pemutil"
"github.com/smallstep/cli/crypto/x509util"
"github.com/smallstep/cli/errs"
"github.com/smallstep/cli/flags"
x509 "github.com/smallstep/cli/pkg/x509"
"github.com/smallstep/cli/utils"
"github.com/urfave/cli"
@@ -19,7 +20,7 @@ import (
func createCommand() cli.Command {
return cli.Command{
Name: "create",
Action: cli.ActionFunc(createAction),
Action: command.ActionFunc(createAction),
Usage: "create a certificate or certificate signing request",
UsageText: `**step certificate create** <subject> <crt_file> <key_file>
[**ca**=<issuer-cert>] [**ca-key**=<issuer-key>] [**--csr**]
@@ -192,6 +193,7 @@ unset, default is P-256 for EC keys and Ed25519 for OKP keys.
: Ed25519 Curve
`,
},
flags.Force,
},
}
}
@@ -320,8 +322,7 @@ func createAction(ctx *cli.Context) error {
return errs.NewError("unexpected type: %s", typ)
}
if err := utils.WriteFile(crtFile, pem.EncodeToMemory(pubPEM),
os.FileMode(0600)); err != nil {
if err := utils.WriteFile(crtFile, pem.EncodeToMemory(pubPEM), 0600); err != nil {
return errs.FileError(err, crtFile)
}

View File

@@ -7,7 +7,9 @@ import (
"os"
"github.com/pkg/errors"
"github.com/smallstep/cli/command"
"github.com/smallstep/cli/errs"
"github.com/smallstep/cli/flags"
"github.com/smallstep/cli/utils"
"github.com/urfave/cli"
)
@@ -15,7 +17,7 @@ import (
func formatCommand() cli.Command {
return cli.Command{
Name: "format",
Action: cli.ActionFunc(formatAction),
Action: command.ActionFunc(formatAction),
Usage: `reformat certificate.`,
UsageText: `**step certificate format** <crt_file> [**--out**=<path>]`,
Description: `**step certificate format** prints the certificate in
@@ -55,6 +57,7 @@ $ step certificate format foo.pem --out foo.der
Name: "out",
Usage: `Path to write the reformatted result.`,
},
flags.Force,
},
}
}

View File

@@ -20,6 +20,7 @@ import (
const IgnoreEnvVar = "STEP_IGNORE_ENV_VAR"
var cmds []cli.Command
var currentContext *cli.Context
func init() {
os.Unsetenv(IgnoreEnvVar)
@@ -40,6 +41,19 @@ func Retrieve() []cli.Command {
return cmds
}
// ActionFunc returns a cli.ActionFunc that stores the context.
func ActionFunc(fn cli.ActionFunc) cli.ActionFunc {
return func(ctx *cli.Context) error {
currentContext = ctx
return fn(ctx)
}
}
// IsForce returns if the force flag was passed
func IsForce() bool {
return currentContext != nil && currentContext.Bool("force")
}
// getConfigVars load the defaults.json file and sets the flags if they are not
// already set or the EnvVar is set to IgnoreEnvVar.
//

View File

@@ -9,8 +9,10 @@ import (
"github.com/pkg/errors"
"github.com/urfave/cli"
"github.com/smallstep/cli/command"
"github.com/smallstep/cli/crypto/pemutil"
"github.com/smallstep/cli/errs"
"github.com/smallstep/cli/flags"
"github.com/smallstep/cli/jose"
"github.com/smallstep/cli/utils"
)
@@ -18,7 +20,7 @@ import (
func changePassCommand() cli.Command {
return cli.Command{
Name: "change-pass",
Action: cli.ActionFunc(changePassAction),
Action: command.ActionFunc(changePassAction),
Usage: "Change password of an encrypted private key (PEM or JWK format)",
UsageText: `**step crypto change-pass** <key-file> [**--out**=<file>]`,
Description: `**step crypto change-pass** extracts the private key from
@@ -56,6 +58,7 @@ $ step crypto change-pass key.jwk --out new-key.jwk
Name: "out,output-file",
Usage: "The <file> new encrypted key path. Default to overwriting the <key> positional argument",
},
flags.Force,
},
}
}

View File

@@ -9,8 +9,10 @@ import (
"os"
"github.com/pkg/errors"
"github.com/smallstep/cli/command"
"github.com/smallstep/cli/crypto/randutil"
"github.com/smallstep/cli/errs"
"github.com/smallstep/cli/flags"
"github.com/smallstep/cli/jose"
"github.com/smallstep/cli/utils"
"github.com/urfave/cli"
@@ -26,7 +28,7 @@ const (
func createCommand() cli.Command {
return cli.Command{
Name: "create",
Action: cli.ActionFunc(createAction),
Action: command.ActionFunc(createAction),
Usage: "create a JWK (JSON Web Key)",
UsageText: `**step crypto jwk create** <public-jwk-file> <private-jwk-file>
[**--kty**=<type>] [**--alg**=<algorithm>] [**--use**=<use>]
@@ -397,12 +399,9 @@ existing <pem-file> instead of creating a new key.`,
key material will be written to disk unencrypted. This is not
recommended. Requires **--insecure** flag.`,
},
cli.BoolFlag{
Name: "subtle",
},
cli.BoolFlag{
Name: "insecure",
},
flags.Subtle,
flags.Insecure,
flags.Force,
},
}
}

View File

@@ -10,9 +10,10 @@ import (
"os"
"github.com/pkg/errors"
"github.com/smallstep/cli/command"
"github.com/smallstep/cli/crypto/pemutil"
"github.com/smallstep/cli/errs"
"github.com/smallstep/cli/flags"
"github.com/smallstep/cli/utils"
"github.com/urfave/cli"
)
@@ -20,7 +21,7 @@ import (
func formatCommand() cli.Command {
return cli.Command{
Name: "format",
Action: cli.ActionFunc(formatAction),
Action: command.ActionFunc(formatAction),
Usage: `reformat certificate.`,
UsageText: `**step crypto key format** <key_file> [**--out**=<path>]`,
Description: `**step crypto key format** prints the key in
@@ -66,6 +67,7 @@ $ step crypto key format foo-key.pem --out foo-key.der
Name: "password-file",
Usage: `location of file containing passphrase to decrypt private key`,
},
flags.Force,
},
}
}

View File

@@ -5,9 +5,11 @@ import (
"os"
"github.com/pkg/errors"
"github.com/smallstep/cli/command"
"github.com/smallstep/cli/crypto/keys"
"github.com/smallstep/cli/crypto/pemutil"
"github.com/smallstep/cli/errs"
"github.com/smallstep/cli/flags"
"github.com/smallstep/cli/jose"
"github.com/smallstep/cli/utils"
"github.com/urfave/cli"
@@ -16,7 +18,7 @@ import (
func createKeyPairCommand() cli.Command {
return cli.Command{
Name: "keypair",
Action: cli.ActionFunc(createAction),
Action: command.ActionFunc(createAction),
Usage: "generate a public / private keypair in PEM format.",
UsageText: `**step crypto keypair** <pub_file> <priv_file>
[**--curve**=<curve>] [**--no-password**] [**--size**=<size>]
@@ -135,6 +137,7 @@ existing <jwk-file> instead of creating a new key.`,
Sensitive key material will be written to disk unencrypted. This is not
recommended. Requires **--insecure** flag.`,
},
flags.Force,
},
}
}

View File

@@ -7,7 +7,9 @@ import (
"os"
"github.com/pkg/errors"
"github.com/smallstep/cli/command"
"github.com/smallstep/cli/errs"
"github.com/smallstep/cli/flags"
"github.com/smallstep/cli/utils"
"github.com/urfave/cli"
"golang.org/x/crypto/nacl/box"
@@ -93,7 +95,7 @@ message
func boxKeypairCommand() cli.Command {
return cli.Command{
Name: "keypair",
Action: cli.ActionFunc(boxKeypairAction),
Action: command.ActionFunc(boxKeypairAction),
Usage: "generate a key for use with seal and open",
UsageText: "**step crypto nacl box keypair** <pub-file> <priv-file>",
Description: `Generates a new public/private keypair suitable for use with seal and open.
@@ -110,6 +112,7 @@ For examples, see **step help crypto nacl box**.
<priv-file>
: The path to write the encrypted private key.`,
Flags: []cli.Flag{flags.Force},
}
}

View File

@@ -7,7 +7,9 @@ import (
"os"
"github.com/pkg/errors"
"github.com/smallstep/cli/command"
"github.com/smallstep/cli/errs"
"github.com/smallstep/cli/flags"
"github.com/smallstep/cli/utils"
"github.com/urfave/cli"
"golang.org/x/crypto/nacl/sign"
@@ -65,7 +67,7 @@ message
func signKeypairCommand() cli.Command {
return cli.Command{
Name: "keypair",
Action: cli.ActionFunc(signKeypairAction),
Action: command.ActionFunc(signKeypairAction),
Usage: "generates a pair for use with sign and open",
UsageText: "**step crypto nacl sign keypair** <pub-file> <priv-file>",
Description: `**step crypto nacl sign keypair** generates a secret key and a corresponding
@@ -74,6 +76,7 @@ public key valid for verifying and signing messages.
This command uses an implementation of NaCl's crypto_sign_keypair function.
For examples, see **step help crypto nacl sign**.`,
Flags: []cli.Flag{flags.Force},
}
}

View File

@@ -8,7 +8,9 @@ import (
"github.com/pquerna/otp"
"github.com/pquerna/otp/totp"
"github.com/smallstep/cli/command"
"github.com/smallstep/cli/errs"
"github.com/smallstep/cli/flags"
"github.com/smallstep/cli/utils"
"github.com/urfave/cli"
)
@@ -16,7 +18,7 @@ import (
func generateCommand() cli.Command {
return cli.Command{
Name: "generate",
Action: cli.ActionFunc(generateAction),
Action: command.ActionFunc(generateAction),
Usage: "one-time password",
UsageText: `**step crypto otp generate**`,
Description: `**step crypto otp generate** does TOTP and HTOP`,
@@ -61,6 +63,7 @@ https://github.com/google/google-authenticator/wiki/Key-Uri-Format`,
Name: "qr",
Usage: `Write a QR code to the specified path`,
},
flags.Force,
},
}
}

View File

@@ -6,7 +6,6 @@ import (
"encoding/json"
"encoding/pem"
"fmt"
"io/ioutil"
"os"
"path/filepath"
"strings"
@@ -300,7 +299,7 @@ func (p *PKI) Save() error {
return errors.Wrapf(err, "error marshalling %s", p.config)
}
if err = ioutil.WriteFile(p.config, b, 0666); err != nil {
if err = utils.WriteFile(p.config, b, 0666); err != nil {
return errs.FileError(err, p.config)
}

View File

@@ -1,206 +1,21 @@
package flags
import (
"fmt"
"strings"
"github.com/urfave/cli"
)
// OldPasswordFile returns a flag for receiving an old password
func OldPasswordFile(usage string) cli.Flag {
if usage == "" {
usage = "The path to the `FILE` containing the old encryption password"
// Subtle is the flag required for delicate operations.
var Subtle = cli.BoolFlag{
Name: "subtle",
}
return cli.StringFlag{
Name: "old-password-file, o",
Usage: usage,
EnvVar: "STEP_OLD_PASSWORD_FILE",
}
// Insecure is the flag required on insecure operations
var Insecure = cli.BoolFlag{
Name: "insecure",
}
// NewPasswordFile returns a flag for receiving a new password
func NewPasswordFile(usage string) cli.Flag {
if usage == "" {
usage = "The path to the `FILE` containing the new encryption password"
}
return cli.StringFlag{
Name: "new-password-file, n",
Usage: usage,
EnvVar: "STEP_NEW_PASSWORD_FILE",
}
}
// Bits returns a flag for receiving the number of bits in generating a key
func Bits(usage string, value int) cli.Flag {
if usage == "" {
usage = "Number of bits used to generate the private key"
}
if value == 0 {
value = 256
}
return cli.IntFlag{
Name: "bits, b",
Usage: usage,
EnvVar: "STEP_BITS",
Value: value,
}
}
// Action returns a flag for receiving an action out of several possibilities
func Action(usage string, possibilities []string, value string) cli.Flag {
usage = fmt.Sprintf("%s (Options: %s)", usage, strings.Join(possibilities, ", "))
return cli.StringFlag{
Name: "action, a",
Usage: usage,
EnvVar: "STEP_ACTION",
Value: value,
}
}
// Type returns a flag for receiving a type of thing to create out of several
// possibilties
func Type(usage string, possibilities []string, value string) cli.Flag {
usage = fmt.Sprintf("%s (Options: %s)", usage, strings.Join(possibilities, ", "))
return cli.StringFlag{
Name: "type, t",
Usage: usage,
EnvVar: "STEP_TYPE",
Value: value,
}
}
// Alg returns a flag for receiving the type of algorithm to use when performing an operation
func Alg(usage string, possibilities []string, value string) cli.Flag {
usage = fmt.Sprintf("%s (Options: %s)", usage, strings.Join(possibilities, ", "))
return cli.StringFlag{
Name: "alg",
Usage: usage,
EnvVar: "STEP_ALG",
Value: value,
}
}
// RootCertificate returns a flag for specifying the path to a root certificate
func RootCertificate(usage string) cli.Flag {
if usage == "" {
usage = "The file `PATH` to the root certificate"
}
return cli.StringFlag{
Name: "root, r",
Usage: usage,
EnvVar: "STEP_ROOT_CERTIFICATE",
}
}
// PasswordFile returns a flag for specifying the path to a file containing a password
func PasswordFile(usage string) cli.Flag {
if usage == "" {
usage = "Path to file containing a password"
}
return cli.StringFlag{
Name: "password-file, p",
Usage: usage,
EnvVar: "STEP_PASSWORD_FILE",
}
}
// OutputFile returns a flag for specifying the path inwhich to write output too
func OutputFile(usage string) cli.Flag {
if usage == "" {
usage = "Path to where the output should be written"
}
return cli.StringFlag{
Name: "output-file, o",
Usage: usage,
EnvVar: "STEP_OUTPUT_FILE",
}
}
// Number returns a flag for collecting the number of something to create
func Number(usage string) cli.Flag {
if usage == "" {
usage = "The `NUMBER` of entities to create"
}
return cli.StringFlag{
Name: "number, n",
Usage: usage,
EnvVar: "STEP_NUMBER",
}
}
// Prefix returns a flag for prefixing to the name of an entity during creation
func Prefix(usage, value string) cli.Flag {
if usage == "" {
usage = "The `PREFIX` to apply to the names of all created entities"
}
return cli.StringFlag{
Name: "prefix, p",
Usage: usage,
Value: value,
EnvVar: "STEP_PREFIX",
}
}
// OAuthProvider returns a flag for allowing the user to select an oauth provider
func OAuthProvider(usage string, providers []string, value string) cli.Flag {
usage = fmt.Sprintf("%s (Options: %s)", usage, strings.Join(providers, ", "))
return cli.StringFlag{
Name: "provider, idp",
Usage: usage,
Value: value,
EnvVar: "STEP_PROVIDER",
}
}
// Email returns a flag allowing the user to specify their email
func Email(usage string) cli.Flag {
if usage == "" {
usage = "Email to use"
}
return cli.StringFlag{
Name: "email, e",
Usage: usage,
EnvVar: "STEP_EMAIL",
}
}
// Console returns a flag allowing the user to specify whether or not they want
// to remain entirely in the console
func Console(usage string) cli.Flag {
if usage == "" {
usage = "Whether or not to remain entirely in the console to complete the action"
}
return cli.BoolFlag{
Name: "console, c",
Usage: usage,
EnvVar: "STEP_CONSOLE",
}
}
// Limit returns a flag for limiting the results return by a command
func Limit(usage string, value int) cli.Flag {
if usage == "" {
usage = "The maximum `NUMBER` of results to return"
}
if value == 0 {
value = 10
}
return cli.IntFlag{
Name: "limit, l",
Usage: usage,
Value: value,
}
// Force is a cli.Flag used to overwrite files.
var Force = cli.BoolFlag{
Name: "f,force",
Usage: "Force the overwrite of files without asking.",
}

View File

@@ -10,6 +10,7 @@ import (
"syscall"
"github.com/pkg/errors"
"github.com/smallstep/cli/command"
"golang.org/x/crypto/ssh/terminal"
)
@@ -21,19 +22,12 @@ var (
ErrIsDir = errors.New("file is a directory")
)
// WriteFile wraps ioutil.WriteFile with a prompt to overwrite a file if the
// file exists. It returns ErrFileExists if the user picks to not overwrite
// the file.
func WriteFile(filename string, data []byte, perm os.FileMode) error {
return WriteFileForce(filename, data, perm, false)
}
// WriteFileForce wraps ioutil.WriteFile with a prompt to overwrite a file if
// WriteFile wraps ioutil.WriteFile with a prompt to overwrite a file if
// the file exists. It returns ErrFileExists if the user picks to not overwrite
// the file. If force is set to true, the prompt will not be presented and the
// file if exists will be overwritten.
func WriteFileForce(filename string, data []byte, perm os.FileMode, force bool) error {
if force {
func WriteFile(filename string, data []byte, perm os.FileMode) error {
if command.IsForce() {
return ioutil.WriteFile(filename, data, perm)
}