mirror of
https://github.com/ipfs/kubo.git
synced 2025-10-25 10:27:01 +08:00
0-to-1 fsrepo migration
This commit is contained in:
4
Godeps/Godeps.json
generated
4
Godeps/Godeps.json
generated
@ -159,6 +159,10 @@
|
||||
"ImportPath": "github.com/jbenet/go-logging",
|
||||
"Rev": "74bec4b83f6d45d1402c1e9d94c0c29e39f6e0ea"
|
||||
},
|
||||
{
|
||||
"ImportPath": "github.com/jbenet/go-migrate",
|
||||
"Rev": "593be6b4b24a87e4d380e54339721ad4b4c6543c"
|
||||
},
|
||||
{
|
||||
"ImportPath": "github.com/jbenet/go-msgio",
|
||||
"Rev": "dbae89193876910c736b2ce1291fa8bbcf299d77"
|
||||
|
||||
21
Godeps/_workspace/src/github.com/jbenet/go-migrate/LICENSE
generated
vendored
Normal file
21
Godeps/_workspace/src/github.com/jbenet/go-migrate/LICENSE
generated
vendored
Normal file
@ -0,0 +1,21 @@
|
||||
The MIT License (MIT)
|
||||
|
||||
Copyright (c) 2014 Juan Batiz-Benet
|
||||
|
||||
Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
of this software and associated documentation files (the "Software"), to deal
|
||||
in the Software without restriction, including without limitation the rights
|
||||
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
copies of the Software, and to permit persons to whom the Software is
|
||||
furnished to do so, subject to the following conditions:
|
||||
|
||||
The above copyright notice and this permission notice shall be included in
|
||||
all copies or substantial portions of the Software.
|
||||
|
||||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
||||
THE SOFTWARE.
|
||||
11
Godeps/_workspace/src/github.com/jbenet/go-migrate/README.md
generated
vendored
Normal file
11
Godeps/_workspace/src/github.com/jbenet/go-migrate/README.md
generated
vendored
Normal file
@ -0,0 +1,11 @@
|
||||
# go-migrate
|
||||
|
||||
This is a very simple migration framework. See "Migrations" in https://github.com/jbenet/random-ideas/issues/33
|
||||
|
||||
This package includes:
|
||||
|
||||
- `migrate` package -- lib to write migration programs
|
||||
|
||||
## The model
|
||||
|
||||
The idea here is that we have some thing -- usually a directory -- that needs to be migrated between different representation versions. This may be because there has been an upgrade.
|
||||
51
Godeps/_workspace/src/github.com/jbenet/go-migrate/cli.go
generated
vendored
Normal file
51
Godeps/_workspace/src/github.com/jbenet/go-migrate/cli.go
generated
vendored
Normal file
@ -0,0 +1,51 @@
|
||||
package migrate
|
||||
|
||||
import (
|
||||
"flag"
|
||||
"fmt"
|
||||
"os"
|
||||
)
|
||||
|
||||
type Flags struct {
|
||||
Force bool
|
||||
Revert bool
|
||||
Path string // file path to migrate for fs based migrations
|
||||
}
|
||||
|
||||
func (f *Flags) Setup() {
|
||||
flag.BoolVar(&f.Force, "f", false, "whether to force a migration (ignores warnings)")
|
||||
flag.BoolVar(&f.Revert, "revert", false, "whether to apply the migration backwards")
|
||||
flag.StringVar(&f.Path, "path", "", "file path to migrate for fs based migrations")
|
||||
}
|
||||
|
||||
func (f *Flags) Parse() {
|
||||
flag.Parse()
|
||||
}
|
||||
|
||||
func Run(m Migration) error {
|
||||
f := Flags{}
|
||||
f.Setup()
|
||||
f.Parse()
|
||||
|
||||
if !m.Reversible() {
|
||||
if f.Revert {
|
||||
return fmt.Errorf("migration %d is irreversible", m.Versions())
|
||||
}
|
||||
if !f.Force {
|
||||
return fmt.Errorf("migration %d is irreversible (use -f to proceed)", m.Versions())
|
||||
}
|
||||
}
|
||||
|
||||
if f.Revert {
|
||||
return m.Revert(Options{f})
|
||||
} else {
|
||||
return m.Apply(Options{f})
|
||||
}
|
||||
}
|
||||
|
||||
func Main(m Migration) {
|
||||
if err := Run(m); err != nil {
|
||||
fmt.Fprintf(os.Stderr, "error: %s\n", err)
|
||||
os.Exit(1)
|
||||
}
|
||||
}
|
||||
2
Godeps/_workspace/src/github.com/jbenet/go-migrate/doc.go
generated
vendored
Normal file
2
Godeps/_workspace/src/github.com/jbenet/go-migrate/doc.go
generated
vendored
Normal file
@ -0,0 +1,2 @@
|
||||
// Package migrate is used to write migrations between representations of things.
|
||||
package migrate
|
||||
37
Godeps/_workspace/src/github.com/jbenet/go-migrate/migrate.go
generated
vendored
Normal file
37
Godeps/_workspace/src/github.com/jbenet/go-migrate/migrate.go
generated
vendored
Normal file
@ -0,0 +1,37 @@
|
||||
package migrate
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
)
|
||||
|
||||
// Options are migration options. For now all flags are options.
|
||||
type Options struct {
|
||||
Flags
|
||||
}
|
||||
|
||||
// Migration represents
|
||||
type Migration interface {
|
||||
|
||||
// Versions is the "v-to-v" version string.
|
||||
Versions() string
|
||||
|
||||
// Reversible returns whether this migration can be reverted.
|
||||
// Endeavor to make them all reversible. This is here only to warn users
|
||||
// in case this is not the case.
|
||||
Reversible() bool
|
||||
|
||||
// Apply applies the migration in question.
|
||||
Apply(Options) error
|
||||
|
||||
// Revert un-applies the migration in question. This should be best-effort.
|
||||
// Some migrations are definitively one-way. If so, return an error.
|
||||
Revert(Options) error
|
||||
}
|
||||
|
||||
func SplitVersion(s string) (from int, to int) {
|
||||
_, err := fmt.Scanf(s, "%d-to-%d", &from, &to)
|
||||
if err != nil {
|
||||
panic(err.Error())
|
||||
}
|
||||
return
|
||||
}
|
||||
69
repo/fsrepo/migrations/0-to-1/main.go
Normal file
69
repo/fsrepo/migrations/0-to-1/main.go
Normal file
@ -0,0 +1,69 @@
|
||||
package main
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"os"
|
||||
"strings"
|
||||
|
||||
migrate "github.com/ipfs/go-ipfs/Godeps/_workspace/src/github.com/jbenet/go-migrate"
|
||||
mfsr "github.com/ipfs/go-ipfs/repo/fsrepo/migrations"
|
||||
)
|
||||
|
||||
type migration struct {
|
||||
}
|
||||
|
||||
// Version is the int version number. This could be a string
|
||||
// in future versions
|
||||
func (m migration) Versions() string {
|
||||
return "0-to-1"
|
||||
}
|
||||
|
||||
// Reversible returns whether this migration can be reverted.
|
||||
// Endeavor to make them all reversible. This is here only to warn users
|
||||
// in case this is not the case.
|
||||
func (m migration) Reversible() bool {
|
||||
return true
|
||||
}
|
||||
|
||||
// Apply applies the migration in question.
|
||||
// This migration merely adds a version file.
|
||||
func (m migration) Apply(opts migrate.Options) error {
|
||||
repo := mfsr.RepoPath(opts.Path)
|
||||
|
||||
// first, check if there is a version file.
|
||||
// if there is, bail out.
|
||||
if v, err := repo.Version(); err == nil {
|
||||
return fmt.Errorf("repo at %s is version %s (not 0)", opts.Path, v)
|
||||
} else if !strings.Contains(err.Error(), "no version file in repo") {
|
||||
return err
|
||||
}
|
||||
|
||||
// add the version file
|
||||
if err := repo.WriteVersion("1"); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
// Revert un-applies the migration in question. This should be best-effort.
|
||||
// Some migrations are definitively one-way. If so, return an error.
|
||||
func (m migration) Revert(opts migrate.Options) error {
|
||||
repo := mfsr.RepoPath(opts.Path)
|
||||
|
||||
if err := repo.CheckVersion("1"); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
// remove the version file
|
||||
if err := os.Remove(repo.VersionFile()); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
func main() {
|
||||
m := migration{}
|
||||
migrate.Main(&m)
|
||||
}
|
||||
56
repo/fsrepo/migrations/mfsr.go
Normal file
56
repo/fsrepo/migrations/mfsr.go
Normal file
@ -0,0 +1,56 @@
|
||||
package mfsr
|
||||
|
||||
import (
|
||||
"errors"
|
||||
"fmt"
|
||||
"io/ioutil"
|
||||
"os"
|
||||
"path"
|
||||
"strings"
|
||||
)
|
||||
|
||||
const VersionFile = "version"
|
||||
|
||||
type RepoPath string
|
||||
|
||||
func (rp RepoPath) VersionFile() string {
|
||||
return path.Join(string(rp), VersionFile)
|
||||
}
|
||||
|
||||
func (rp RepoPath) Version() (string, error) {
|
||||
if rp == "" {
|
||||
return "", fmt.Errorf("invalid repo path \"%s\"", rp)
|
||||
}
|
||||
|
||||
fn := rp.VersionFile()
|
||||
if _, err := os.Stat(fn); os.IsNotExist(err) {
|
||||
return "", errors.New("no version file in repo at " + string(rp))
|
||||
}
|
||||
|
||||
c, err := ioutil.ReadFile(fn)
|
||||
if err != nil {
|
||||
return "", err
|
||||
}
|
||||
|
||||
s := string(c)
|
||||
s = strings.TrimSpace(s)
|
||||
return s, nil
|
||||
}
|
||||
|
||||
func (rp RepoPath) CheckVersion(version string) error {
|
||||
v, err := rp.Version()
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
if v != version {
|
||||
return fmt.Errorf("versions differ (expected: %s, actual:%s)", version, v)
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
func (rp RepoPath) WriteVersion(version string) error {
|
||||
fn := rp.VersionFile()
|
||||
return ioutil.WriteFile(fn, []byte(version+"\n"), 0644)
|
||||
}
|
||||
Reference in New Issue
Block a user