mirror of
https://github.com/octoleo/restic.git
synced 2024-11-22 12:55:18 +00:00
Add method to create repository
Also disables automatic creation on open
This commit is contained in:
parent
f0287b2c9a
commit
03ca69407d
20
cmd/khepri/cmd_init.go
Normal file
20
cmd/khepri/cmd_init.go
Normal file
@ -0,0 +1,20 @@
|
|||||||
|
package main
|
||||||
|
|
||||||
|
import (
|
||||||
|
"fmt"
|
||||||
|
"os"
|
||||||
|
|
||||||
|
"github.com/fd0/khepri"
|
||||||
|
)
|
||||||
|
|
||||||
|
func commandInit(path string) error {
|
||||||
|
repo, err := khepri.CreateRepository(path)
|
||||||
|
if err != nil {
|
||||||
|
fmt.Fprintf(os.Stderr, "creating repository at %s failed: %v\n", path, err)
|
||||||
|
os.Exit(1)
|
||||||
|
}
|
||||||
|
|
||||||
|
fmt.Printf("created khepri repository at %s\n", repo.Path())
|
||||||
|
|
||||||
|
return nil
|
||||||
|
}
|
@ -4,15 +4,13 @@ import (
|
|||||||
"fmt"
|
"fmt"
|
||||||
"log"
|
"log"
|
||||||
"os"
|
"os"
|
||||||
"sort"
|
|
||||||
"strings"
|
|
||||||
|
|
||||||
"github.com/fd0/khepri"
|
"github.com/fd0/khepri"
|
||||||
"github.com/jessevdk/go-flags"
|
"github.com/jessevdk/go-flags"
|
||||||
)
|
)
|
||||||
|
|
||||||
var Opts struct {
|
var Opts struct {
|
||||||
Repo string `short:"r" long:"repo" description:"Repository directory to backup to/restor from"`
|
Repo string `short:"r" long:"repo" description:"Repository directory to backup to/restore from"`
|
||||||
}
|
}
|
||||||
|
|
||||||
func errx(code int, format string, data ...interface{}) {
|
func errx(code int, format string, data ...interface{}) {
|
||||||
@ -50,17 +48,16 @@ func main() {
|
|||||||
os.Exit(0)
|
os.Exit(0)
|
||||||
}
|
}
|
||||||
|
|
||||||
if len(args) == 0 {
|
cmd := args[0]
|
||||||
cmds := []string{}
|
|
||||||
for k := range commands {
|
if cmd == "init" {
|
||||||
cmds = append(cmds, k)
|
err = commandInit(Opts.Repo)
|
||||||
}
|
if err != nil {
|
||||||
sort.Strings(cmds)
|
errx(1, "error executing command %q: %v", cmd, err)
|
||||||
fmt.Printf("nothing to do, available commands: [%v]\n", strings.Join(cmds, "|"))
|
|
||||||
os.Exit(0)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
cmd := args[0]
|
return
|
||||||
|
}
|
||||||
|
|
||||||
f, ok := commands[cmd]
|
f, ok := commands[cmd]
|
||||||
if !ok {
|
if !ok {
|
||||||
@ -70,7 +67,7 @@ func main() {
|
|||||||
repo, err := khepri.NewRepository(Opts.Repo)
|
repo, err := khepri.NewRepository(Opts.Repo)
|
||||||
|
|
||||||
if err != nil {
|
if err != nil {
|
||||||
errx(1, "unable to create/open repo: %v", err)
|
errx(1, "unable to open repo: %v", err)
|
||||||
}
|
}
|
||||||
|
|
||||||
err = f(repo, args[1:])
|
err = f(repo, args[1:])
|
||||||
|
114
repository.go
114
repository.go
@ -1,7 +1,10 @@
|
|||||||
package khepri
|
package khepri
|
||||||
|
|
||||||
import (
|
import (
|
||||||
|
"crypto/rand"
|
||||||
"crypto/sha256"
|
"crypto/sha256"
|
||||||
|
"encoding/hex"
|
||||||
|
"encoding/json"
|
||||||
"errors"
|
"errors"
|
||||||
"fmt"
|
"fmt"
|
||||||
"hash"
|
"hash"
|
||||||
@ -18,6 +21,7 @@ const (
|
|||||||
blobPath = "blobs"
|
blobPath = "blobs"
|
||||||
refPath = "refs"
|
refPath = "refs"
|
||||||
tempPath = "tmp"
|
tempPath = "tmp"
|
||||||
|
configFileName = "config.json"
|
||||||
)
|
)
|
||||||
|
|
||||||
var (
|
var (
|
||||||
@ -36,8 +40,25 @@ type HashFunc func() hash.Hash
|
|||||||
type Repository struct {
|
type Repository struct {
|
||||||
path string
|
path string
|
||||||
hash HashFunc
|
hash HashFunc
|
||||||
|
config *Config
|
||||||
}
|
}
|
||||||
|
|
||||||
|
type Config struct {
|
||||||
|
Salt string
|
||||||
|
N uint
|
||||||
|
R uint `json:"r"`
|
||||||
|
P uint `json:"p"`
|
||||||
|
}
|
||||||
|
|
||||||
|
// TODO: figure out scrypt values on the fly depending on the current
|
||||||
|
// hardware.
|
||||||
|
const (
|
||||||
|
scrypt_N = 65536
|
||||||
|
scrypt_r = 8
|
||||||
|
scrypt_p = 1
|
||||||
|
scrypt_saltsize = 64
|
||||||
|
)
|
||||||
|
|
||||||
type Type int
|
type Type int
|
||||||
|
|
||||||
const (
|
const (
|
||||||
@ -67,15 +88,16 @@ func (t Type) String() string {
|
|||||||
panic(fmt.Sprintf("unknown type %d", t))
|
panic(fmt.Sprintf("unknown type %d", t))
|
||||||
}
|
}
|
||||||
|
|
||||||
// NewDirRepository creates a new dir-baked repository at the given path.
|
// NewRepository opens a dir-baked repository at the given path.
|
||||||
func NewRepository(path string) (*Repository, error) {
|
func NewRepository(path string) (*Repository, error) {
|
||||||
|
var err error
|
||||||
|
|
||||||
d := &Repository{
|
d := &Repository{
|
||||||
path: path,
|
path: path,
|
||||||
hash: sha256.New,
|
hash: sha256.New,
|
||||||
}
|
}
|
||||||
|
|
||||||
err := d.create()
|
d.config, err = d.read_config()
|
||||||
|
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
@ -83,22 +105,92 @@ func NewRepository(path string) (*Repository, error) {
|
|||||||
return d, nil
|
return d, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func (r *Repository) create() error {
|
func (r *Repository) read_config() (*Config, error) {
|
||||||
dirs := []string{
|
// try to open config file
|
||||||
r.path,
|
f, err := os.Open(path.Join(r.path, configFileName))
|
||||||
path.Join(r.path, blobPath),
|
if err != nil {
|
||||||
path.Join(r.path, refPath),
|
return nil, err
|
||||||
path.Join(r.path, tempPath),
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
cfg := new(Config)
|
||||||
|
buf, err := ioutil.ReadAll(f)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
|
||||||
|
err = json.Unmarshal(buf, cfg)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
|
||||||
|
return cfg, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// CreateRepository creates all the necessary files and directories for the
|
||||||
|
// Repository.
|
||||||
|
func CreateRepository(p string) (*Repository, error) {
|
||||||
|
dirs := []string{
|
||||||
|
p,
|
||||||
|
path.Join(p, blobPath),
|
||||||
|
path.Join(p, refPath),
|
||||||
|
path.Join(p, tempPath),
|
||||||
|
}
|
||||||
|
|
||||||
|
var configfile = path.Join(p, configFileName)
|
||||||
|
|
||||||
|
// test if repository directories or config file already exist
|
||||||
|
if _, err := os.Stat(configfile); err == nil {
|
||||||
|
return nil, fmt.Errorf("config file %s already exists", configfile)
|
||||||
|
}
|
||||||
|
|
||||||
|
for _, d := range dirs[1:] {
|
||||||
|
if _, err := os.Stat(d); err == nil {
|
||||||
|
return nil, fmt.Errorf("dir %s already exists", d)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// create initial json configuration
|
||||||
|
cfg := &Config{
|
||||||
|
N: scrypt_N,
|
||||||
|
R: scrypt_r,
|
||||||
|
P: scrypt_p,
|
||||||
|
}
|
||||||
|
|
||||||
|
// generate salt
|
||||||
|
buf := make([]byte, scrypt_saltsize)
|
||||||
|
n, err := rand.Read(buf)
|
||||||
|
if n != scrypt_saltsize || err != nil {
|
||||||
|
panic("unable to read enough random bytes for salt")
|
||||||
|
}
|
||||||
|
cfg.Salt = hex.EncodeToString(buf)
|
||||||
|
|
||||||
|
// create ps for blobs, refs and temp
|
||||||
for _, dir := range dirs {
|
for _, dir := range dirs {
|
||||||
err := os.MkdirAll(dir, dirMode)
|
err := os.MkdirAll(dir, dirMode)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return nil, err
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
return nil
|
// write config file
|
||||||
|
f, err := os.Create(configfile)
|
||||||
|
defer f.Close()
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
|
||||||
|
s, err := json.Marshal(cfg)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
|
||||||
|
_, err = f.Write(s)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
|
||||||
|
// open repository
|
||||||
|
return NewRepository(p)
|
||||||
}
|
}
|
||||||
|
|
||||||
// SetHash changes the hash function used for deriving IDs. Default is SHA256.
|
// SetHash changes the hash function used for deriving IDs. Default is SHA256.
|
||||||
|
@ -30,7 +30,7 @@ func setupRepo() (*khepri.Repository, error) {
|
|||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
|
|
||||||
repo, err := khepri.NewRepository(tempdir)
|
repo, err := khepri.CreateRepository(tempdir)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
|
@ -1,6 +1,7 @@
|
|||||||
set -e
|
set -e
|
||||||
|
|
||||||
prepare
|
prepare
|
||||||
|
run khepri init
|
||||||
run khepri backup "${BASE}/fake-data"
|
run khepri backup "${BASE}/fake-data"
|
||||||
run khepri restore "$(khepri list ref)" "${BASE}/fake-data-restore"
|
run khepri restore "$(khepri list ref)" "${BASE}/fake-data-restore"
|
||||||
dirdiff "${BASE}/fake-data" "${BASE}/fake-data-restore"
|
dirdiff "${BASE}/fake-data" "${BASE}/fake-data-restore"
|
||||||
|
Loading…
Reference in New Issue
Block a user