2015-06-21 11:02:56 +00:00
package main
import (
2021-10-31 22:08:13 +00:00
"context"
2020-11-28 09:54:21 +00:00
"encoding/json"
2022-02-12 23:52:03 +00:00
"strconv"
2020-09-19 10:41:52 +00:00
"github.com/restic/chunker"
2020-03-20 22:52:27 +00:00
"github.com/restic/restic/internal/backend/location"
2017-07-23 12:21:03 +00:00
"github.com/restic/restic/internal/errors"
"github.com/restic/restic/internal/repository"
2022-02-12 23:52:03 +00:00
"github.com/restic/restic/internal/restic"
2016-09-17 10:36:05 +00:00
"github.com/spf13/cobra"
2015-06-21 11:02:56 +00:00
)
2016-09-17 10:36:05 +00:00
var cmdInit = & cobra . Command {
Use : "init" ,
2017-09-11 16:32:44 +00:00
Short : "Initialize a new repository" ,
2016-09-17 10:36:05 +00:00
Long : `
The "init" command initializes a new repository .
2019-11-05 06:03:38 +00:00
EXIT STATUS
== == == == == =
Exit status is 0 if the command was successful , and non - zero if there was any error .
2016-09-17 10:36:05 +00:00
` ,
2017-08-06 19:02:16 +00:00
DisableAutoGenTag : true ,
2016-09-17 10:36:05 +00:00
RunE : func ( cmd * cobra . Command , args [ ] string ) error {
2022-10-02 21:24:37 +00:00
return runInit ( cmd . Context ( ) , initOptions , globalOptions , args )
2016-09-17 10:36:05 +00:00
} ,
2015-06-21 11:02:56 +00:00
}
2020-09-19 10:41:52 +00:00
// InitOptions bundles all options for the init command.
type InitOptions struct {
secondaryRepoOptions
CopyChunkerParameters bool
2022-02-12 23:52:03 +00:00
RepositoryVersion string
2020-09-19 10:41:52 +00:00
}
var initOptions InitOptions
2016-09-17 10:36:05 +00:00
func init ( ) {
cmdRoot . AddCommand ( cmdInit )
2020-09-19 10:41:52 +00:00
f := cmdInit . Flags ( )
initSecondaryRepoOptions ( f , & initOptions . secondaryRepoOptions , "secondary" , "to copy chunker parameters from" )
f . BoolVar ( & initOptions . CopyChunkerParameters , "copy-chunker-params" , false , "copy chunker parameters from the secondary repository (useful with the copy command)" )
2022-02-12 23:52:03 +00:00
f . StringVar ( & initOptions . RepositoryVersion , "repository-version" , "stable" , "repository format version to use, allowed values are a format version, 'latest' and 'stable'" )
2016-09-17 10:36:05 +00:00
}
2021-10-31 22:08:13 +00:00
func runInit ( ctx context . Context , opts InitOptions , gopts GlobalOptions , args [ ] string ) error {
2023-05-18 17:48:20 +00:00
if len ( args ) > 0 {
return errors . Fatal ( "the init command expects no arguments, only options - please see `restic help init` for usage and flags" )
}
2022-02-12 23:52:03 +00:00
var version uint
if opts . RepositoryVersion == "latest" || opts . RepositoryVersion == "" {
version = restic . MaxRepoVersion
} else if opts . RepositoryVersion == "stable" {
version = restic . StableRepoVersion
} else {
v , err := strconv . ParseUint ( opts . RepositoryVersion , 10 , 32 )
if err != nil {
return errors . Fatal ( "invalid repository version" )
}
version = uint ( v )
}
if version < restic . MinRepoVersion || version > restic . MaxRepoVersion {
return errors . Fatalf ( "only repository versions between %v and %v are allowed" , restic . MinRepoVersion , restic . MaxRepoVersion )
}
2021-10-31 22:08:13 +00:00
chunkerPolynomial , err := maybeReadChunkerPolynomial ( ctx , opts , gopts )
2020-09-19 10:41:52 +00:00
if err != nil {
return err
}
2023-11-20 21:56:27 +00:00
gopts . Repo , err = ReadRepo ( gopts )
2020-08-30 21:20:57 +00:00
if err != nil {
return err
}
2017-07-24 21:15:31 +00:00
gopts . password , err = ReadPasswordTwice ( gopts ,
2018-01-20 08:51:49 +00:00
"enter password for new repository: " ,
2017-07-24 21:15:31 +00:00
"enter password again: " )
if err != nil {
return err
2015-06-21 11:02:56 +00:00
}
2023-11-20 21:56:27 +00:00
be , err := create ( ctx , gopts . Repo , gopts , gopts . extended )
2021-02-14 19:39:28 +00:00
if err != nil {
2023-06-08 11:04:34 +00:00
return errors . Fatalf ( "create repository at %s failed: %v\n" , location . StripPassword ( gopts . backends , gopts . Repo ) , err )
2021-02-14 19:39:28 +00:00
}
2022-07-02 21:30:26 +00:00
s , err := repository . New ( be , repository . Options {
Compression : gopts . Compression ,
2022-07-02 21:52:02 +00:00
PackSize : gopts . PackSize * 1024 * 1024 ,
2022-07-02 21:30:26 +00:00
} )
if err != nil {
2023-05-13 20:43:42 +00:00
return errors . Fatal ( err . Error ( ) )
2022-07-02 21:30:26 +00:00
}
2016-03-06 11:34:23 +00:00
2021-10-31 22:08:13 +00:00
err = s . Init ( ctx , version , gopts . password , chunkerPolynomial )
2015-06-21 11:02:56 +00:00
if err != nil {
2023-06-08 11:04:34 +00:00
return errors . Fatalf ( "create key in repository at %s failed: %v\n" , location . StripPassword ( gopts . backends , gopts . Repo ) , err )
2015-06-21 11:02:56 +00:00
}
2020-11-28 09:54:21 +00:00
if ! gopts . JSON {
2023-06-08 11:04:34 +00:00
Verbosef ( "created restic repository %v at %s" , s . Config ( ) . ID [ : 10 ] , location . StripPassword ( gopts . backends , gopts . Repo ) )
2023-04-09 21:59:07 +00:00
if opts . CopyChunkerParameters && chunkerPolynomial != nil {
Verbosef ( " with chunker parameters copied from secondary repository\n" )
} else {
Verbosef ( "\n" )
}
2020-11-28 09:54:21 +00:00
Verbosef ( "\n" )
Verbosef ( "Please note that knowledge of your password is required to access\n" )
Verbosef ( "the repository. Losing your password means that your data is\n" )
Verbosef ( "irrecoverably lost.\n" )
} else {
2022-10-21 20:32:11 +00:00
status := initSuccess {
2022-10-21 20:33:39 +00:00
MessageType : "initialized" ,
ID : s . Config ( ) . ID ,
2023-06-08 11:04:34 +00:00
Repository : location . StripPassword ( gopts . backends , gopts . Repo ) ,
2020-11-28 09:54:21 +00:00
}
2023-05-07 20:21:56 +00:00
return json . NewEncoder ( globalOptions . stdout ) . Encode ( status )
2020-11-28 09:54:21 +00:00
}
2015-06-21 11:02:56 +00:00
return nil
}
2020-09-19 10:41:52 +00:00
2021-10-31 22:08:13 +00:00
func maybeReadChunkerPolynomial ( ctx context . Context , opts InitOptions , gopts GlobalOptions ) ( * chunker . Pol , error ) {
2020-09-19 10:41:52 +00:00
if opts . CopyChunkerParameters {
2022-05-07 21:26:59 +00:00
otherGopts , _ , err := fillSecondaryGlobalOpts ( opts . secondaryRepoOptions , gopts , "secondary" )
2020-09-19 10:41:52 +00:00
if err != nil {
return nil , err
}
2021-10-31 22:08:13 +00:00
otherRepo , err := OpenRepository ( ctx , otherGopts )
2020-09-19 10:41:52 +00:00
if err != nil {
return nil , err
}
pol := otherRepo . Config ( ) . ChunkerPolynomial
return & pol , nil
}
2022-05-07 21:26:59 +00:00
if opts . Repo != "" || opts . RepositoryFile != "" || opts . LegacyRepo != "" || opts . LegacyRepositoryFile != "" {
2020-09-19 10:41:52 +00:00
return nil , errors . Fatal ( "Secondary repository must only be specified when copying the chunker parameters" )
}
return nil , nil
}
2022-10-21 20:32:11 +00:00
type initSuccess struct {
2022-10-21 20:33:39 +00:00
MessageType string ` json:"message_type" ` // "initialized"
ID string ` json:"id" `
Repository string ` json:"repository" `
2022-10-21 20:32:11 +00:00
}