diff --git a/.github/workflows/test.yml b/.github/workflows/test.yml index c9970bdb..8e38d9c2 100644 --- a/.github/workflows/test.yml +++ b/.github/workflows/test.yml @@ -1,7 +1,7 @@ name: Tests env: - GO: 1.16 + GO: 1.18 on: push: diff --git a/fs-repo-12-to-13/Makefile b/fs-repo-12-to-13/Makefile new file mode 100644 index 00000000..3797aca4 --- /dev/null +++ b/fs-repo-12-to-13/Makefile @@ -0,0 +1,7 @@ +.PHONY: build clean + +build: + go build -mod=vendor + +clean: + go clean diff --git a/fs-repo-12-to-13/atomicfile/atomicfile.go b/fs-repo-12-to-13/atomicfile/atomicfile.go new file mode 100644 index 00000000..9294460d --- /dev/null +++ b/fs-repo-12-to-13/atomicfile/atomicfile.go @@ -0,0 +1,59 @@ +// Package atomicfile provides the ability to write a file with an eventual +// rename on Close (using os.Rename). This allows for a file to always be in a +// consistent state and never represent an in-progress write. +// +// NOTE: `os.Rename` may not be atomic on your operating system. +package atomicfile + +import ( + "io/ioutil" + "os" + "path/filepath" +) + +// File behaves like os.File, but does an atomic rename operation at Close. +type File struct { + *os.File + path string +} + +// New creates a new temporary file that will replace the file at the given +// path when Closed. +func New(path string, mode os.FileMode) (*File, error) { + f, err := ioutil.TempFile(filepath.Dir(path), filepath.Base(path)) + if err != nil { + return nil, err + } + if err := os.Chmod(f.Name(), mode); err != nil { + f.Close() + os.Remove(f.Name()) + return nil, err + } + return &File{File: f, path: path}, nil +} + +// Close the file replacing the configured file. +func (f *File) Close() error { + if err := f.File.Close(); err != nil { + os.Remove(f.File.Name()) + return err + } + if err := os.Rename(f.Name(), f.path); err != nil { + return err + } + return nil +} + +// Abort closes the file and removes it instead of replacing the configured +// file. This is useful if after starting to write to the file you decide you +// don't want it anymore. +func (f *File) Abort() error { + if err := f.File.Close(); err != nil { + os.Remove(f.Name()) + return err + } + if err := os.Remove(f.Name()); err != nil { + return err + } + return nil +} diff --git a/fs-repo-12-to-13/go.mod b/fs-repo-12-to-13/go.mod new file mode 100644 index 00000000..27045dcd --- /dev/null +++ b/fs-repo-12-to-13/go.mod @@ -0,0 +1,5 @@ +module github.com/ipfs/fs-repo-migrations/fs-repo-12-to-13 + +go 1.18 + +require github.com/ipfs/fs-repo-migrations/tools v0.0.0-20211209222258-754a2dcb82ea diff --git a/fs-repo-12-to-13/go.sum b/fs-repo-12-to-13/go.sum new file mode 100644 index 00000000..a2960eed --- /dev/null +++ b/fs-repo-12-to-13/go.sum @@ -0,0 +1,2 @@ +github.com/ipfs/fs-repo-migrations/tools v0.0.0-20211209222258-754a2dcb82ea h1:lgfk2PMrJI3bh8FflcBTXyNi3rPLqa75J7KcoUfRJmc= +github.com/ipfs/fs-repo-migrations/tools v0.0.0-20211209222258-754a2dcb82ea/go.mod h1:fADeaHKxwS+SKhc52rsL0P1MUcnyK31a9AcaG0KcfY8= diff --git a/fs-repo-12-to-13/main.go b/fs-repo-12-to-13/main.go new file mode 100644 index 00000000..65d4c0f5 --- /dev/null +++ b/fs-repo-12-to-13/main.go @@ -0,0 +1,11 @@ +package main + +import ( + mg12 "github.com/ipfs/fs-repo-migrations/fs-repo-12-to-13/migration" + migrate "github.com/ipfs/fs-repo-migrations/tools/go-migrate" +) + +func main() { + m := mg12.Migration{} + migrate.Main(m) +} diff --git a/fs-repo-12-to-13/migration/generate_repotest.sh b/fs-repo-12-to-13/migration/generate_repotest.sh new file mode 100755 index 00000000..a457f4f7 --- /dev/null +++ b/fs-repo-12-to-13/migration/generate_repotest.sh @@ -0,0 +1,17 @@ +#!/bin/bash + +# This script can be used to generate the repotest folder that is used +# to test the migration, using go-ipfs v0.8.0. + +export IPFS_PATH=repotest + +# use server profile to have some no announces and filters in place +ipfs init -p server -e + +# add a forced announces as they must also be updated +ipfs config --json Addresses.Announce "[\"/ip4/1.2.3.4/tcp/1337\",\"/ip4/1.2.3.4/udp/1337/quic\"]" +ipfs config --json Addresses.NoAnnounce "[\"/ip4/1.2.3.4/tcp/1337\",\"/ip4/1.2.3.4/udp/1337/quic\"]" +ipfs config --json Addresses.AppendAnnounce "[\"/ip4/1.2.3.4/tcp/1337\",\"/ip4/1.2.3.4/udp/1337/quic\"]" + +# we only update the config, remove anything not config related to make the tree clearer +rm -rf repotest/{blocks,datastore,keystore} diff --git a/fs-repo-12-to-13/migration/migration.go b/fs-repo-12-to-13/migration/migration.go new file mode 100644 index 00000000..95e24a91 --- /dev/null +++ b/fs-repo-12-to-13/migration/migration.go @@ -0,0 +1,227 @@ +// package mg12 contains the code to perform 12-13 repository migration in Kubo. +// This just change some config fields to add webtransport listens on ones that quic uses. +package mg12 + +import ( + "encoding/json" + "io" + "os" + "path/filepath" + "strings" + + migrate "github.com/ipfs/fs-repo-migrations/tools/go-migrate" + mfsr "github.com/ipfs/fs-repo-migrations/tools/mfsr" + lock "github.com/ipfs/fs-repo-migrations/tools/repolock" + log "github.com/ipfs/fs-repo-migrations/tools/stump" + + "github.com/ipfs/fs-repo-migrations/fs-repo-12-to-13/atomicfile" +) + +const backupSuffix = ".12-to-13.bak" + +// Migration implements the migration described above. +type Migration struct{} + +// Versions returns the current version string for this migration. +func (m Migration) Versions() string { + return "12-to-13" +} + +// Reversible returns false, as you can just use the backup config file. +func (m Migration) Reversible() bool { + return true +} + +// Apply update the config. +func (m Migration) Apply(opts migrate.Options) error { + log.Verbose = opts.Verbose + log.Log("applying %s repo migration", m.Versions()) + + log.VLog("locking repo at %q", opts.Path) + lk, err := lock.Lock2(opts.Path) + if err != nil { + return err + } + defer lk.Close() + + repo := mfsr.RepoPath(opts.Path) + + log.VLog(" - verifying version is '12'") + if err := repo.CheckVersion("12"); err != nil { + return err + } + + log.Log("> Upgrading config to new format") + + path := filepath.Join(opts.Path, "config") + if err := convertFile(path); err != nil { + return err + } + + if err := repo.WriteVersion("13"); err != nil { + log.Error("failed to update version file to 13") + return err + } + + log.Log("updated version file") + + log.Log("Migration 12 to 13 succeeded") + return nil +} + +func (m Migration) Revert(opts migrate.Options) error { + log.Verbose = opts.Verbose + log.Log("reverting migration") + lk, err := lock.Lock2(opts.Path) + if err != nil { + return err + } + defer lk.Close() + + repo := mfsr.RepoPath(opts.Path) + if err := repo.CheckVersion("13"); err != nil { + return err + } + + cfg := filepath.Join(opts.Path, "config") + if err := os.Rename(cfg+backupSuffix, cfg); err != nil { + return err + } + + if err := repo.WriteVersion("12"); err != nil { + return err + } + if opts.Verbose { + log.Log("lowered version number to 12") + } + + return nil +} + +// convertFile converts a config file from 12 version to 13 +func convertFile(path string) error { + in, err := os.Open(path) + if err != nil { + return err + } + + // make backup + backup, err := atomicfile.New(path+backupSuffix, 0600) + if err != nil { + return err + } + if _, err := backup.ReadFrom(in); err != nil { + backup.Abort() + return err + } + if _, err := in.Seek(0, io.SeekStart); err != nil { + backup.Abort() + return err + } + + // Create a temp file to write the output to on success + out, err := atomicfile.New(path, 0600) + if err != nil { + in.Close() + backup.Abort() + return err + } + + err = convert(in, out) + + in.Close() + + if err != nil { + // There was an error so abort writing the output and clean up temp file + out.Abort() + backup.Abort() + } else { + // Write the output and clean up temp file + out.Close() + backup.Close() + } + + return err +} + +// convert converts the config from one version to another +func convert(in io.Reader, out io.Writer) error { + confMap := make(map[string]any) + if err := json.NewDecoder(in).Decode(&confMap); err != nil { + return err + } + + // run this first to avoid having both quic and quic-v1 webtransport addresses + runOnAllAddressFields(confMap, multiaddrPatternReplace(false, "/quic/webtransport", "/quic-v1/webtransport", "/p2p-circuit")) + runOnAllAddressFields(confMap, multiaddrPatternReplace(true, "/quic", "/quic-v1", "/p2p-circuit")) + runOnAllAddressFields(confMap, multiaddrPatternReplace(true, "/quic-v1", "/quic-v1/webtransport", "/p2p-circuit", "/webtransport")) + + fixed, err := json.MarshalIndent(confMap, "", " ") + if err != nil { + return err + } + + if _, err := out.Write(fixed); err != nil { + return err + } + _, err = out.Write([]byte("\n")) + return err +} + +func multiaddrPatternReplace(add bool, old, new string, notBefore ...string) func(in []any) (out []any) { + return func(in []any) (out []any) { + for _, w := range in { + if add { + out = append(out, w) + } + + v, ok := w.(string) + if !ok { + continue + } + + var r string + last := len(v) + ScanLoop: + for i := len(v); i != 0; { + i-- + if hasPrefixAndEndsOrSlash(v[i:], old) { + r = new + v[i+len(old):last] + r + last = i + } + for _, not := range notBefore { + if hasPrefixAndEndsOrSlash(v[i:], not) { + break ScanLoop + } + } + } + r = v[:last] + r + + // always append if we didn't appended previously + if !add || r != v { + out = append(out, r) + } + } + return + } +} + +func hasPrefixAndEndsOrSlash(s, prefix string) bool { + return strings.HasPrefix(s, prefix) && (len(prefix) == len(s) || s[len(prefix)] == '/') +} + +func runOnAllAddressFields[T any, O any](m map[string]any, transformer func(T) O) { + applyChangeOnLevelPlusOnes(m, transformer, "Addresses", "Announce", "AppendAnnounce", "NoAnnounce", "Swarm") + applyChangeOnLevelPlusOnes(m, transformer, "Swarm", "AddrFilters") +} + +// this walk one step in m, then walk all of vs, then try to cast to T, if all of this succeeded for thoses elements, pass it through transform +func applyChangeOnLevelPlusOnes[T any, O any, K comparable, V comparable](m map[K]any, transform func(T) O, l0 K, vs ...V) { + if addresses, ok := m[l0].(map[V]any); ok { + for _, v := range vs { + if addrs, ok := addresses[v].(T); ok { + addresses[v] = transform(addrs) + } + } + } +} diff --git a/fs-repo-12-to-13/migration/repotest/config b/fs-repo-12-to-13/migration/repotest/config new file mode 100644 index 00000000..8001a9c3 --- /dev/null +++ b/fs-repo-12-to-13/migration/repotest/config @@ -0,0 +1,183 @@ +{ + "API": { + "HTTPHeaders": {} + }, + "Addresses": { + "API": "/ip4/127.0.0.1/tcp/5001", + "Announce": [ + "/ip4/1.2.3.4/tcp/1337", + "/ip4/1.2.3.4/udp/1337/quic" + ], + "AppendAnnounce": [ + "/ip4/1.2.3.4/tcp/1337", + "/ip4/1.2.3.4/udp/1337/quic" + ], + "Gateway": "/ip4/127.0.0.1/tcp/8080", + "NoAnnounce": [ + "/ip4/1.2.3.4/tcp/1337", + "/ip4/1.2.3.4/udp/1337/quic" + ], + "Swarm": [ + "/ip4/0.0.0.0/tcp/4001", + "/ip6/::/tcp/4001", + "/ip4/0.0.0.0/udp/4001/quic", + "/ip6/::/udp/4001/quic" + ] + }, + "AutoNAT": {}, + "Bootstrap": [ + "/dnsaddr/bootstrap.libp2p.io/p2p/QmcZf59bWwK5XFi76CZX8cbJ4BhTzzA3gU1ZjYZcYW3dwt", + "/ip4/104.131.131.82/tcp/4001/p2p/QmaCpDMGvV2BGHeYERUEnRQAwe3N8SzbUtfsmvsqQLuvuJ", + "/ip4/104.131.131.82/udp/4001/quic/p2p/QmaCpDMGvV2BGHeYERUEnRQAwe3N8SzbUtfsmvsqQLuvuJ", + "/dnsaddr/bootstrap.libp2p.io/p2p/QmNnooDu7bfjPFoTZYxMNLWUQJyrVwtbZg5gBMjTezGAJN", + "/dnsaddr/bootstrap.libp2p.io/p2p/QmQCU2EcMqAqQPR2i9bChDtGNJchTbq5TbXJJ16u19uLTa", + "/dnsaddr/bootstrap.libp2p.io/p2p/QmbLHAnMoJPWSCR5Zhtx6BHJX9KiKNN6tpvbUcqanj75Nb" + ], + "DNS": { + "Resolvers": {} + }, + "Datastore": { + "BloomFilterSize": 0, + "GCPeriod": "1h", + "HashOnRead": false, + "Spec": { + "mounts": [ + { + "child": { + "path": "blocks", + "shardFunc": "/repo/flatfs/shard/v1/next-to-last/2", + "sync": true, + "type": "flatfs" + }, + "mountpoint": "/blocks", + "prefix": "flatfs.datastore", + "type": "measure" + }, + { + "child": { + "compression": "none", + "path": "datastore", + "type": "levelds" + }, + "mountpoint": "/", + "prefix": "leveldb.datastore", + "type": "measure" + } + ], + "type": "mount" + }, + "StorageGCWatermark": 90, + "StorageMax": "10GB" + }, + "Discovery": { + "MDNS": { + "Enabled": false + } + }, + "Experimental": { + "AcceleratedDHTClient": false, + "FilestoreEnabled": false, + "GraphsyncEnabled": false, + "Libp2pStreamMounting": false, + "P2pHttpProxy": false, + "StrategicProviding": false, + "UrlstoreEnabled": false + }, + "Gateway": { + "APICommands": [], + "HTTPHeaders": { + "Access-Control-Allow-Headers": [ + "X-Requested-With", + "Range", + "User-Agent" + ], + "Access-Control-Allow-Methods": [ + "GET" + ], + "Access-Control-Allow-Origin": [ + "*" + ] + }, + "NoDNSLink": false, + "NoFetch": false, + "PathPrefixes": [], + "PublicGateways": null, + "RootRedirect": "", + "Writable": false + }, + "Identity": { + "PeerID": "12D3KooWNh3e1oBiTEqUcNsz1n46XPpnqGSFJ8QGs9ohzTZV2MpS", + "PrivKey": "CAESQOiHDkwtQiypb6yqfc0T6sI7CAwS8PEszJVbBVGjf8BVv0fpoqZBxyIj1dMBk8sHsJ+YPDqAZ9/9hrLbb6dzGnc=" + }, + "Internal": {}, + "Ipns": { + "RecordLifetime": "", + "RepublishPeriod": "", + "ResolveCacheSize": 128 + }, + "Migration": { + "DownloadSources": [], + "Keep": "" + }, + "Mounts": { + "FuseAllowOther": false, + "IPFS": "/ipfs", + "IPNS": "/ipns" + }, + "Peering": { + "Peers": null + }, + "Pinning": { + "RemoteServices": {} + }, + "Plugins": { + "Plugins": null + }, + "Provider": { + "Strategy": "" + }, + "Pubsub": { + "DisableSigning": false, + "Router": "" + }, + "Reprovider": { + "Interval": "12h", + "Strategy": "all" + }, + "Routing": { + "Methods": null, + "Routers": null, + "Type": "dht" + }, + "Swarm": { + "AddrFilters": [ + "/ip4/10.0.0.0/ipcidr/8", + "/ip4/100.64.0.0/ipcidr/10", + "/ip4/169.254.0.0/ipcidr/16", + "/ip4/172.16.0.0/ipcidr/12", + "/ip4/192.0.0.0/ipcidr/24", + "/ip4/192.0.2.0/ipcidr/24", + "/ip4/192.168.0.0/ipcidr/16", + "/ip4/198.18.0.0/ipcidr/15", + "/ip4/198.51.100.0/ipcidr/24", + "/ip4/203.0.113.0/ipcidr/24", + "/ip4/240.0.0.0/ipcidr/4", + "/ip6/100::/ipcidr/64", + "/ip6/2001:2::/ipcidr/48", + "/ip6/2001:db8::/ipcidr/32", + "/ip6/fc00::/ipcidr/7", + "/ip6/fe80::/ipcidr/10" + ], + "ConnMgr": {}, + "DisableBandwidthMetrics": false, + "DisableNatPortMap": true, + "RelayClient": {}, + "RelayService": {}, + "ResourceMgr": {}, + "Transports": { + "Multiplexers": {}, + "Network": {}, + "Security": {} + } + } +} \ No newline at end of file diff --git a/fs-repo-12-to-13/migration/repotest/datastore_spec b/fs-repo-12-to-13/migration/repotest/datastore_spec new file mode 100644 index 00000000..7bf9626c --- /dev/null +++ b/fs-repo-12-to-13/migration/repotest/datastore_spec @@ -0,0 +1 @@ +{"mounts":[{"mountpoint":"/blocks","path":"blocks","shardFunc":"/repo/flatfs/shard/v1/next-to-last/2","type":"flatfs"},{"mountpoint":"/","path":"datastore","type":"levelds"}],"type":"mount"} \ No newline at end of file diff --git a/fs-repo-12-to-13/migration/repotest/version b/fs-repo-12-to-13/migration/repotest/version new file mode 100644 index 00000000..48082f72 --- /dev/null +++ b/fs-repo-12-to-13/migration/repotest/version @@ -0,0 +1 @@ +12 diff --git a/fs-repo-12-to-13/vendor/github.com/ipfs/fs-repo-migrations/tools/LICENSE b/fs-repo-12-to-13/vendor/github.com/ipfs/fs-repo-migrations/tools/LICENSE new file mode 100644 index 00000000..0e323020 --- /dev/null +++ b/fs-repo-12-to-13/vendor/github.com/ipfs/fs-repo-migrations/tools/LICENSE @@ -0,0 +1,21 @@ +The MIT License (MIT) + +Copyright (c) 2016 Protocol Labs, Inc. + +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. diff --git a/fs-repo-12-to-13/vendor/github.com/ipfs/fs-repo-migrations/tools/go-migrate/LICENSE b/fs-repo-12-to-13/vendor/github.com/ipfs/fs-repo-migrations/tools/go-migrate/LICENSE new file mode 100644 index 00000000..c7386b3c --- /dev/null +++ b/fs-repo-12-to-13/vendor/github.com/ipfs/fs-repo-migrations/tools/go-migrate/LICENSE @@ -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. diff --git a/fs-repo-12-to-13/vendor/github.com/ipfs/fs-repo-migrations/tools/go-migrate/README.md b/fs-repo-12-to-13/vendor/github.com/ipfs/fs-repo-migrations/tools/go-migrate/README.md new file mode 100644 index 00000000..cf96be81 --- /dev/null +++ b/fs-repo-12-to-13/vendor/github.com/ipfs/fs-repo-migrations/tools/go-migrate/README.md @@ -0,0 +1,12 @@ +# 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. + diff --git a/fs-repo-12-to-13/vendor/github.com/ipfs/fs-repo-migrations/tools/go-migrate/cli.go b/fs-repo-12-to-13/vendor/github.com/ipfs/fs-repo-migrations/tools/go-migrate/cli.go new file mode 100644 index 00000000..2a843597 --- /dev/null +++ b/fs-repo-12-to-13/vendor/github.com/ipfs/fs-repo-migrations/tools/go-migrate/cli.go @@ -0,0 +1,79 @@ +package migrate + +import ( + "flag" + "fmt" + "os" +) + +type Flags struct { + Force bool + Revert bool + Path string // file path to migrate for fs based migrations + Verbose bool + Help bool + NoRevert bool +} + +func SetupFlags() Flags { + f := Flags{} + 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.BoolVar(&f.Verbose, "verbose", false, "enable verbose logging") + flag.BoolVar(&f.Help, "help", false, "display help message") + flag.StringVar(&f.Path, "path", "", "file path to migrate for fs based migrations (required)") + flag.BoolVar(&f.NoRevert, "no-revert", false, "do not attempt to automatically revert on failure") + + flag.Parse() + return f +} + +var SupportNoRevert = map[string]bool{ + "4-to-5": true, +} + +func Run(m Migration) error { + f := SetupFlags() + + if f.Help { + flag.Usage() + os.Exit(0) + } + + if f.Path == "" { + flag.Usage() + return fmt.Errorf("missing or empty path; flag '-path ' is required") + } + + if !m.Reversible() { + if f.Revert { + return fmt.Errorf("migration %s is irreversible", m.Versions()) + } + if !f.Force { + return fmt.Errorf("migration %s is irreversible (use -f to proceed)", m.Versions()) + } + } + + if f.NoRevert && !SupportNoRevert[m.Versions()] { + return fmt.Errorf("migration %s does not support the '-no-revert' option", m.Versions()) + } + + if f.Revert { + return m.Revert(Options{ + Flags: f, + Verbose: f.Verbose, + }) + } + + return m.Apply(Options{ + Flags: f, + Verbose: f.Verbose, + }) +} + +func Main(m Migration) { + if err := Run(m); err != nil { + fmt.Fprintf(os.Stderr, "error: %s\n", err) + os.Exit(1) + } +} diff --git a/fs-repo-12-to-13/vendor/github.com/ipfs/fs-repo-migrations/tools/go-migrate/doc.go b/fs-repo-12-to-13/vendor/github.com/ipfs/fs-repo-migrations/tools/go-migrate/doc.go new file mode 100644 index 00000000..29e607a1 --- /dev/null +++ b/fs-repo-12-to-13/vendor/github.com/ipfs/fs-repo-migrations/tools/go-migrate/doc.go @@ -0,0 +1,2 @@ +// Package migrate is used to write migrations between representations of things. +package migrate diff --git a/fs-repo-12-to-13/vendor/github.com/ipfs/fs-repo-migrations/tools/go-migrate/migrate.go b/fs-repo-12-to-13/vendor/github.com/ipfs/fs-repo-migrations/tools/go-migrate/migrate.go new file mode 100644 index 00000000..19d3f93e --- /dev/null +++ b/fs-repo-12-to-13/vendor/github.com/ipfs/fs-repo-migrations/tools/go-migrate/migrate.go @@ -0,0 +1,38 @@ +package migrate + +import ( + "fmt" +) + +// Options are migration options. For now all flags are options. +type Options struct { + Flags + Verbose bool +} + +// 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 +} diff --git a/fs-repo-12-to-13/vendor/github.com/ipfs/fs-repo-migrations/tools/lock/.gitignore b/fs-repo-12-to-13/vendor/github.com/ipfs/fs-repo-migrations/tools/lock/.gitignore new file mode 100644 index 00000000..b25c15b8 --- /dev/null +++ b/fs-repo-12-to-13/vendor/github.com/ipfs/fs-repo-migrations/tools/lock/.gitignore @@ -0,0 +1 @@ +*~ diff --git a/fs-repo-12-to-13/vendor/github.com/ipfs/fs-repo-migrations/tools/lock/COPYING b/fs-repo-12-to-13/vendor/github.com/ipfs/fs-repo-migrations/tools/lock/COPYING new file mode 100644 index 00000000..d6456956 --- /dev/null +++ b/fs-repo-12-to-13/vendor/github.com/ipfs/fs-repo-migrations/tools/lock/COPYING @@ -0,0 +1,202 @@ + + Apache License + Version 2.0, January 2004 + http://www.apache.org/licenses/ + + TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION + + 1. Definitions. + + "License" shall mean the terms and conditions for use, reproduction, + and distribution as defined by Sections 1 through 9 of this document. + + "Licensor" shall mean the copyright owner or entity authorized by + the copyright owner that is granting the License. + + "Legal Entity" shall mean the union of the acting entity and all + other entities that control, are controlled by, or are under common + control with that entity. For the purposes of this definition, + "control" means (i) the power, direct or indirect, to cause the + direction or management of such entity, whether by contract or + otherwise, or (ii) ownership of fifty percent (50%) or more of the + outstanding shares, or (iii) beneficial ownership of such entity. + + "You" (or "Your") shall mean an individual or Legal Entity + exercising permissions granted by this License. + + "Source" form shall mean the preferred form for making modifications, + including but not limited to software source code, documentation + source, and configuration files. + + "Object" form shall mean any form resulting from mechanical + transformation or translation of a Source form, including but + not limited to compiled object code, generated documentation, + and conversions to other media types. + + "Work" shall mean the work of authorship, whether in Source or + Object form, made available under the License, as indicated by a + copyright notice that is included in or attached to the work + (an example is provided in the Appendix below). + + "Derivative Works" shall mean any work, whether in Source or Object + form, that is based on (or derived from) the Work and for which the + editorial revisions, annotations, elaborations, or other modifications + represent, as a whole, an original work of authorship. For the purposes + of this License, Derivative Works shall not include works that remain + separable from, or merely link (or bind by name) to the interfaces of, + the Work and Derivative Works thereof. + + "Contribution" shall mean any work of authorship, including + the original version of the Work and any modifications or additions + to that Work or Derivative Works thereof, that is intentionally + submitted to Licensor for inclusion in the Work by the copyright owner + or by an individual or Legal Entity authorized to submit on behalf of + the copyright owner. For the purposes of this definition, "submitted" + means any form of electronic, verbal, or written communication sent + to the Licensor or its representatives, including but not limited to + communication on electronic mailing lists, source code control systems, + and issue tracking systems that are managed by, or on behalf of, the + Licensor for the purpose of discussing and improving the Work, but + excluding communication that is conspicuously marked or otherwise + designated in writing by the copyright owner as "Not a Contribution." + + "Contributor" shall mean Licensor and any individual or Legal Entity + on behalf of whom a Contribution has been received by Licensor and + subsequently incorporated within the Work. + + 2. Grant of Copyright License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + copyright license to reproduce, prepare Derivative Works of, + publicly display, publicly perform, sublicense, and distribute the + Work and such Derivative Works in Source or Object form. + + 3. Grant of Patent License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + (except as stated in this section) patent license to make, have made, + use, offer to sell, sell, import, and otherwise transfer the Work, + where such license applies only to those patent claims licensable + by such Contributor that are necessarily infringed by their + Contribution(s) alone or by combination of their Contribution(s) + with the Work to which such Contribution(s) was submitted. If You + institute patent litigation against any entity (including a + cross-claim or counterclaim in a lawsuit) alleging that the Work + or a Contribution incorporated within the Work constitutes direct + or contributory patent infringement, then any patent licenses + granted to You under this License for that Work shall terminate + as of the date such litigation is filed. + + 4. Redistribution. You may reproduce and distribute copies of the + Work or Derivative Works thereof in any medium, with or without + modifications, and in Source or Object form, provided that You + meet the following conditions: + + (a) You must give any other recipients of the Work or + Derivative Works a copy of this License; and + + (b) You must cause any modified files to carry prominent notices + stating that You changed the files; and + + (c) You must retain, in the Source form of any Derivative Works + that You distribute, all copyright, patent, trademark, and + attribution notices from the Source form of the Work, + excluding those notices that do not pertain to any part of + the Derivative Works; and + + (d) If the Work includes a "NOTICE" text file as part of its + distribution, then any Derivative Works that You distribute must + include a readable copy of the attribution notices contained + within such NOTICE file, excluding those notices that do not + pertain to any part of the Derivative Works, in at least one + of the following places: within a NOTICE text file distributed + as part of the Derivative Works; within the Source form or + documentation, if provided along with the Derivative Works; or, + within a display generated by the Derivative Works, if and + wherever such third-party notices normally appear. The contents + of the NOTICE file are for informational purposes only and + do not modify the License. You may add Your own attribution + notices within Derivative Works that You distribute, alongside + or as an addendum to the NOTICE text from the Work, provided + that such additional attribution notices cannot be construed + as modifying the License. + + You may add Your own copyright statement to Your modifications and + may provide additional or different license terms and conditions + for use, reproduction, or distribution of Your modifications, or + for any such Derivative Works as a whole, provided Your use, + reproduction, and distribution of the Work otherwise complies with + the conditions stated in this License. + + 5. Submission of Contributions. Unless You explicitly state otherwise, + any Contribution intentionally submitted for inclusion in the Work + by You to the Licensor shall be under the terms and conditions of + this License, without any additional terms or conditions. + Notwithstanding the above, nothing herein shall supersede or modify + the terms of any separate license agreement you may have executed + with Licensor regarding such Contributions. + + 6. Trademarks. This License does not grant permission to use the trade + names, trademarks, service marks, or product names of the Licensor, + except as required for reasonable and customary use in describing the + origin of the Work and reproducing the content of the NOTICE file. + + 7. Disclaimer of Warranty. Unless required by applicable law or + agreed to in writing, Licensor provides the Work (and each + Contributor provides its Contributions) on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or + implied, including, without limitation, any warranties or conditions + of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A + PARTICULAR PURPOSE. You are solely responsible for determining the + appropriateness of using or redistributing the Work and assume any + risks associated with Your exercise of permissions under this License. + + 8. Limitation of Liability. In no event and under no legal theory, + whether in tort (including negligence), contract, or otherwise, + unless required by applicable law (such as deliberate and grossly + negligent acts) or agreed to in writing, shall any Contributor be + liable to You for damages, including any direct, indirect, special, + incidental, or consequential damages of any character arising as a + result of this License or out of the use or inability to use the + Work (including but not limited to damages for loss of goodwill, + work stoppage, computer failure or malfunction, or any and all + other commercial damages or losses), even if such Contributor + has been advised of the possibility of such damages. + + 9. Accepting Warranty or Additional Liability. While redistributing + the Work or Derivative Works thereof, You may choose to offer, + and charge a fee for, acceptance of support, warranty, indemnity, + or other liability obligations and/or rights consistent with this + License. However, in accepting such obligations, You may act only + on Your own behalf and on Your sole responsibility, not on behalf + of any other Contributor, and only if You agree to indemnify, + defend, and hold each Contributor harmless for any liability + incurred by, or claims asserted against, such Contributor by reason + of your accepting any such warranty or additional liability. + + END OF TERMS AND CONDITIONS + + APPENDIX: How to apply the Apache License to your work. + + To apply the Apache License to your work, attach the following + boilerplate notice, with the fields enclosed by brackets "[]" + replaced with your own identifying information. (Don't include + the brackets!) The text should be enclosed in the appropriate + comment syntax for the file format. We also recommend that a + file or class name and description of purpose be included on the + same "printed page" as the copyright notice for easier + identification within third-party archives. + + Copyright [yyyy] [name of copyright owner] + + Licensed under the Apache License, Version 2.0 (the "License"); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. diff --git a/fs-repo-12-to-13/vendor/github.com/ipfs/fs-repo-migrations/tools/lock/README.txt b/fs-repo-12-to-13/vendor/github.com/ipfs/fs-repo-migrations/tools/lock/README.txt new file mode 100644 index 00000000..a9eeb33d --- /dev/null +++ b/fs-repo-12-to-13/vendor/github.com/ipfs/fs-repo-migrations/tools/lock/README.txt @@ -0,0 +1,3 @@ +File locking library. + +See http://godoc.org/github.com/camlistore/lock diff --git a/fs-repo-12-to-13/vendor/github.com/ipfs/fs-repo-migrations/tools/lock/lock.go b/fs-repo-12-to-13/vendor/github.com/ipfs/fs-repo-migrations/tools/lock/lock.go new file mode 100644 index 00000000..6268527b --- /dev/null +++ b/fs-repo-12-to-13/vendor/github.com/ipfs/fs-repo-migrations/tools/lock/lock.go @@ -0,0 +1,158 @@ +/* +Copyright 2013 The Go Authors + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. +*/ + +package lock + +import ( + "encoding/json" + "fmt" + "io" + "os" + "path/filepath" + "sync" +) + +// Lock locks the given file, creating the file if necessary. If the +// file already exists, it must have zero size or an error is returned. +// The lock is an exclusive lock (a write lock), but locked files +// should neither be read from nor written to. Such files should have +// zero size and only exist to co-ordinate ownership across processes. +// +// A nil Closer is returned if an error occurred. Otherwise, close that +// Closer to release the lock. +// +// On Linux, FreeBSD and OSX, a lock has the same semantics as fcntl(2)'s +// advisory locks. In particular, closing any other file descriptor for the +// same file will release the lock prematurely. +// +// Attempting to lock a file that is already locked by the current process +// has undefined behavior. +// +// On other operating systems, lock will fallback to using the presence and +// content of a file named name + '.lock' to implement locking behavior. +func Lock(name string) (io.Closer, error) { + return lockFn(name) +} + +var lockFn = lockPortable + +// Portable version not using fcntl. Doesn't handle crashes as gracefully, +// since it can leave stale lock files. +// TODO: write pid of owner to lock file and on race see if pid is +// still alive? +func lockPortable(name string) (io.Closer, error) { + absName, err := filepath.Abs(name) + if err != nil { + return nil, fmt.Errorf("can't Lock file %q: can't find abs path: %v", name, err) + } + fi, err := os.Stat(absName) + if err == nil && fi.Size() > 0 { + if isStaleLock(absName) { + os.Remove(absName) + } else { + return nil, fmt.Errorf("can't Lock file %q: has non-zero size", name) + } + } + f, err := os.OpenFile(absName, os.O_RDWR|os.O_CREATE|os.O_TRUNC|os.O_EXCL, 0666) + if err != nil { + return nil, fmt.Errorf("failed to create lock file %s %v", absName, err) + } + if err := json.NewEncoder(f).Encode(&pidLockMeta{OwnerPID: os.Getpid()}); err != nil { + return nil, err + } + return &lockCloser{f: f, abs: absName}, nil +} + +type pidLockMeta struct { + OwnerPID int +} + +func isStaleLock(path string) bool { + f, err := os.Open(path) + if err != nil { + return false + } + defer f.Close() + var meta pidLockMeta + if json.NewDecoder(f).Decode(&meta) != nil { + return false + } + if meta.OwnerPID == 0 { + return false + } + p, err := os.FindProcess(meta.OwnerPID) + if err != nil { + // e.g. on Windows + return true + } + // On unix, os.FindProcess always is true, so we have to send + // it a signal to see if it's alive. + if signalZero != nil { + if p.Signal(signalZero) != nil { + return true + } + } + return false +} + +var signalZero os.Signal // nil or set by lock_sigzero.go + +type lockCloser struct { + f *os.File + abs string + once sync.Once + err error +} + +func (lc *lockCloser) Close() error { + lc.once.Do(lc.close) + return lc.err +} + +func (lc *lockCloser) close() { + if err := lc.f.Close(); err != nil { + lc.err = err + } + if err := os.Remove(lc.abs); err != nil { + lc.err = err + } +} + +var ( + lockmu sync.Mutex + locked = map[string]bool{} // abs path -> true +) + +// unlocker is used by the darwin and linux implementations with fcntl +// advisory locks. +type unlocker struct { + f *os.File + abs string +} + +func (u *unlocker) Close() error { + lockmu.Lock() + // Remove is not necessary but it's nice for us to clean up. + // If we do do this, though, it needs to be before the + // u.f.Close below. + os.Remove(u.abs) + if err := u.f.Close(); err != nil { + return err + } + delete(locked, u.abs) + lockmu.Unlock() + return nil +} diff --git a/fs-repo-12-to-13/vendor/github.com/ipfs/fs-repo-migrations/tools/lock/lock_appengine.go b/fs-repo-12-to-13/vendor/github.com/ipfs/fs-repo-migrations/tools/lock/lock_appengine.go new file mode 100644 index 00000000..ab4cad6a --- /dev/null +++ b/fs-repo-12-to-13/vendor/github.com/ipfs/fs-repo-migrations/tools/lock/lock_appengine.go @@ -0,0 +1,32 @@ +// +build appengine + +/* +Copyright 2013 The Go Authors + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. +*/ + +package lock + +import ( + "errors" + "io" +) + +func init() { + lockFn = lockAppEngine +} + +func lockAppEngine(name string) (io.Closer, error) { + return nil, errors.New("Lock not available on App Engine") +} diff --git a/fs-repo-12-to-13/vendor/github.com/ipfs/fs-repo-migrations/tools/lock/lock_darwin_amd64.go b/fs-repo-12-to-13/vendor/github.com/ipfs/fs-repo-migrations/tools/lock/lock_darwin_amd64.go new file mode 100644 index 00000000..9fea51fe --- /dev/null +++ b/fs-repo-12-to-13/vendor/github.com/ipfs/fs-repo-migrations/tools/lock/lock_darwin_amd64.go @@ -0,0 +1,80 @@ +// +build darwin,amd64 +// +build !appengine + +/* +Copyright 2013 The Go Authors + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. +*/ + +package lock + +import ( + "fmt" + "io" + "os" + "path/filepath" + "syscall" + "unsafe" +) + +func init() { + lockFn = lockFcntl +} + +func lockFcntl(name string) (io.Closer, error) { + abs, err := filepath.Abs(name) + if err != nil { + return nil, err + } + lockmu.Lock() + if locked[abs] { + lockmu.Unlock() + return nil, fmt.Errorf("file %q already locked", abs) + } + locked[abs] = true + lockmu.Unlock() + + fi, err := os.Stat(name) + if err == nil && fi.Size() > 0 { + return nil, fmt.Errorf("can't Lock file %q: has non-zero size", name) + } + + f, err := os.Create(name) + if err != nil { + return nil, fmt.Errorf("Lock Create of %s (abs: %s) failed: %v", name, abs, err) + } + + // This type matches C's "struct flock" defined in /usr/include/sys/fcntl.h. + // TODO: move this into the standard syscall package. + k := struct { + Start uint64 // sizeof(off_t): 8 + Len uint64 // sizeof(off_t): 8 + Pid uint32 // sizeof(pid_t): 4 + Type uint16 // sizeof(short): 2 + Whence uint16 // sizeof(short): 2 + }{ + Type: syscall.F_WRLCK, + Whence: uint16(os.SEEK_SET), + Start: 0, + Len: 0, // 0 means to lock the entire file. + Pid: uint32(os.Getpid()), + } + + _, _, errno := syscall.Syscall(syscall.SYS_FCNTL, f.Fd(), uintptr(syscall.F_SETLK), uintptr(unsafe.Pointer(&k))) + if errno != 0 { + f.Close() + return nil, errno + } + return &unlocker{f, abs}, nil +} diff --git a/fs-repo-12-to-13/vendor/github.com/ipfs/fs-repo-migrations/tools/lock/lock_freebsd.go b/fs-repo-12-to-13/vendor/github.com/ipfs/fs-repo-migrations/tools/lock/lock_freebsd.go new file mode 100644 index 00000000..d3835d62 --- /dev/null +++ b/fs-repo-12-to-13/vendor/github.com/ipfs/fs-repo-migrations/tools/lock/lock_freebsd.go @@ -0,0 +1,79 @@ +/* +Copyright 2013 The Go Authors + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. +*/ + +package lock + +import ( + "fmt" + "io" + "os" + "path/filepath" + "syscall" + "unsafe" +) + +func init() { + lockFn = lockFcntl +} + +func lockFcntl(name string) (io.Closer, error) { + abs, err := filepath.Abs(name) + if err != nil { + return nil, err + } + lockmu.Lock() + if locked[abs] { + lockmu.Unlock() + return nil, fmt.Errorf("file %q already locked", abs) + } + locked[abs] = true + lockmu.Unlock() + + fi, err := os.Stat(name) + if err == nil && fi.Size() > 0 { + return nil, fmt.Errorf("can't Lock file %q: has non-zero size", name) + } + + f, err := os.Create(name) + if err != nil { + return nil, err + } + + // This type matches C's "struct flock" defined in /usr/include/fcntl.h. + // TODO: move this into the standard syscall package. + k := struct { + Start int64 /* off_t starting offset */ + Len int64 /* off_t len = 0 means until end of file */ + Pid int32 /* pid_t lock owner */ + Type int16 /* short lock type: read/write, etc. */ + Whence int16 /* short type of l_start */ + Sysid int32 /* int remote system id or zero for local */ + }{ + Start: 0, + Len: 0, // 0 means to lock the entire file. + Pid: int32(os.Getpid()), + Type: syscall.F_WRLCK, + Whence: int16(os.SEEK_SET), + Sysid: 0, + } + + _, _, errno := syscall.Syscall(syscall.SYS_FCNTL, f.Fd(), uintptr(syscall.F_SETLK), uintptr(unsafe.Pointer(&k))) + if errno != 0 { + f.Close() + return nil, errno + } + return &unlocker{f, abs}, nil +} diff --git a/fs-repo-12-to-13/vendor/github.com/ipfs/fs-repo-migrations/tools/lock/lock_linux_amd64.go b/fs-repo-12-to-13/vendor/github.com/ipfs/fs-repo-migrations/tools/lock/lock_linux_amd64.go new file mode 100644 index 00000000..3a7eb00a --- /dev/null +++ b/fs-repo-12-to-13/vendor/github.com/ipfs/fs-repo-migrations/tools/lock/lock_linux_amd64.go @@ -0,0 +1,80 @@ +// +build linux,amd64 +// +build !appengine + +/* +Copyright 2013 The Go Authors + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. +*/ + +package lock + +import ( + "fmt" + "io" + "os" + "path/filepath" + "syscall" + "unsafe" +) + +func init() { + lockFn = lockFcntl +} + +func lockFcntl(name string) (io.Closer, error) { + abs, err := filepath.Abs(name) + if err != nil { + return nil, err + } + lockmu.Lock() + if locked[abs] { + lockmu.Unlock() + return nil, fmt.Errorf("file %q already locked", abs) + } + locked[abs] = true + lockmu.Unlock() + + fi, err := os.Stat(name) + if err == nil && fi.Size() > 0 { + return nil, fmt.Errorf("can't Lock file %q: has non-zero size", name) + } + + f, err := os.Create(name) + if err != nil { + return nil, err + } + + // This type matches C's "struct flock" defined in /usr/include/bits/fcntl.h. + // TODO: move this into the standard syscall package. + k := struct { + Type uint32 + Whence uint32 + Start uint64 + Len uint64 + Pid uint32 + }{ + Type: syscall.F_WRLCK, + Whence: uint32(os.SEEK_SET), + Start: 0, + Len: 0, // 0 means to lock the entire file. + Pid: uint32(os.Getpid()), + } + + _, _, errno := syscall.Syscall(syscall.SYS_FCNTL, f.Fd(), uintptr(syscall.F_SETLK), uintptr(unsafe.Pointer(&k))) + if errno != 0 { + f.Close() + return nil, errno + } + return &unlocker{f, abs}, nil +} diff --git a/fs-repo-12-to-13/vendor/github.com/ipfs/fs-repo-migrations/tools/lock/lock_linux_arm.go b/fs-repo-12-to-13/vendor/github.com/ipfs/fs-repo-migrations/tools/lock/lock_linux_arm.go new file mode 100644 index 00000000..c2a0a102 --- /dev/null +++ b/fs-repo-12-to-13/vendor/github.com/ipfs/fs-repo-migrations/tools/lock/lock_linux_arm.go @@ -0,0 +1,81 @@ +// +build linux,arm +// +build !appengine + +/* +Copyright 2013 The Go Authors + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. +*/ + +package lock + +import ( + "fmt" + "io" + "os" + "path/filepath" + "syscall" + "unsafe" +) + +func init() { + lockFn = lockFcntl +} + +func lockFcntl(name string) (io.Closer, error) { + abs, err := filepath.Abs(name) + if err != nil { + return nil, err + } + lockmu.Lock() + if locked[abs] { + lockmu.Unlock() + return nil, fmt.Errorf("file %q already locked", abs) + } + locked[abs] = true + lockmu.Unlock() + + fi, err := os.Stat(name) + if err == nil && fi.Size() > 0 { + return nil, fmt.Errorf("can't Lock file %q: has non-zero size", name) + } + + f, err := os.Create(name) + if err != nil { + return nil, err + } + + // This type matches C's "struct flock" defined in /usr/include/bits/fcntl.h. + // TODO: move this into the standard syscall package. + k := struct { + Type uint16 + Whence uint16 + Start uint32 + Len uint32 + Pid uint32 + }{ + Type: syscall.F_WRLCK, + Whence: uint16(os.SEEK_SET), + Start: 0, + Len: 0, // 0 means to lock the entire file. + Pid: uint32(os.Getpid()), + } + + const F_SETLK = 6 // actual value. syscall package is wrong: golang.org/issue/7059 + _, _, errno := syscall.Syscall(syscall.SYS_FCNTL, f.Fd(), uintptr(F_SETLK), uintptr(unsafe.Pointer(&k))) + if errno != 0 { + f.Close() + return nil, errno + } + return &unlocker{f, abs}, nil +} diff --git a/fs-repo-12-to-13/vendor/github.com/ipfs/fs-repo-migrations/tools/lock/lock_plan9.go b/fs-repo-12-to-13/vendor/github.com/ipfs/fs-repo-migrations/tools/lock/lock_plan9.go new file mode 100644 index 00000000..bdf4e229 --- /dev/null +++ b/fs-repo-12-to-13/vendor/github.com/ipfs/fs-repo-migrations/tools/lock/lock_plan9.go @@ -0,0 +1,55 @@ +/* +Copyright 2013 The Go Authors + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. +*/ + +package lock + +import ( + "fmt" + "io" + "os" + "path/filepath" +) + +func init() { + lockFn = lockPlan9 +} + +func lockPlan9(name string) (io.Closer, error) { + var f *os.File + abs, err := filepath.Abs(name) + if err != nil { + return nil, err + } + lockmu.Lock() + if locked[abs] { + lockmu.Unlock() + return nil, fmt.Errorf("file %q already locked", abs) + } + locked[abs] = true + lockmu.Unlock() + + fi, err := os.Stat(name) + if err == nil && fi.Size() > 0 { + return nil, fmt.Errorf("can't Lock file %q: has non-zero size", name) + } + + f, err = os.OpenFile(name, os.O_RDWR|os.O_CREATE, os.ModeExclusive|0644) + if err != nil { + return nil, fmt.Errorf("Lock Create of %s (abs: %s) failed: %v", name, abs, err) + } + + return &unlocker{f, abs}, nil +} diff --git a/fs-repo-12-to-13/vendor/github.com/ipfs/fs-repo-migrations/tools/lock/lock_sigzero.go b/fs-repo-12-to-13/vendor/github.com/ipfs/fs-repo-migrations/tools/lock/lock_sigzero.go new file mode 100644 index 00000000..fd3ba2db --- /dev/null +++ b/fs-repo-12-to-13/vendor/github.com/ipfs/fs-repo-migrations/tools/lock/lock_sigzero.go @@ -0,0 +1,26 @@ +// +build !appengine +// +build linux darwin freebsd openbsd netbsd dragonfly + +/* +Copyright 2013 The Go Authors + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. +*/ + +package lock + +import "syscall" + +func init() { + signalZero = syscall.Signal(0) +} diff --git a/fs-repo-12-to-13/vendor/github.com/ipfs/fs-repo-migrations/tools/mfsr/mfsr.go b/fs-repo-12-to-13/vendor/github.com/ipfs/fs-repo-migrations/tools/mfsr/mfsr.go new file mode 100644 index 00000000..c591f67e --- /dev/null +++ b/fs-repo-12-to-13/vendor/github.com/ipfs/fs-repo-migrations/tools/mfsr/mfsr.go @@ -0,0 +1,61 @@ +package mfsr + +import ( + "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 "", VersionFileNotFound(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) +} + +type VersionFileNotFound string + +func (v VersionFileNotFound) Error() string { + return "no version file in repo at " + string(v) +} diff --git a/fs-repo-12-to-13/vendor/github.com/ipfs/fs-repo-migrations/tools/repolock/lock.go b/fs-repo-12-to-13/vendor/github.com/ipfs/fs-repo-migrations/tools/repolock/lock.go new file mode 100644 index 00000000..41a19a0f --- /dev/null +++ b/fs-repo-12-to-13/vendor/github.com/ipfs/fs-repo-migrations/tools/repolock/lock.go @@ -0,0 +1,40 @@ +package lock + +import ( + "fmt" + "io" + "os" + "path" + + "github.com/ipfs/fs-repo-migrations/tools/lock" +) + +var errRepoLock = `failed to acquire repo lock at %s/%s +Is a daemon running? please stop it before running migration` + +// LockFile is the filename of the daemon lock, relative to config dir +// lock changed names. +const ( + LockFile1 = "daemon.lock" + LockFile2 = "repo.lock" +) + +func Lock1(confdir string) (io.Closer, error) { + c, err := lock.Lock(path.Join(confdir, LockFile1)) + if err != nil { + return nil, fmt.Errorf(errRepoLock, confdir, LockFile1) + } + return c, nil +} + +func Remove1(confdir string) error { + return os.Remove(path.Join(confdir, LockFile1)) +} + +func Lock2(confdir string) (io.Closer, error) { + c, err := lock.Lock(path.Join(confdir, LockFile2)) + if err != nil { + return nil, fmt.Errorf(errRepoLock, confdir, LockFile2) + } + return c, nil +} diff --git a/fs-repo-12-to-13/vendor/github.com/ipfs/fs-repo-migrations/tools/stump/LICENSE b/fs-repo-12-to-13/vendor/github.com/ipfs/fs-repo-migrations/tools/stump/LICENSE new file mode 100644 index 00000000..1a976e72 --- /dev/null +++ b/fs-repo-12-to-13/vendor/github.com/ipfs/fs-repo-migrations/tools/stump/LICENSE @@ -0,0 +1,21 @@ +The MIT License (MIT) + +Copyright (c) 2015 Jeromy Johnson + +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. diff --git a/fs-repo-12-to-13/vendor/github.com/ipfs/fs-repo-migrations/tools/stump/README.md b/fs-repo-12-to-13/vendor/github.com/ipfs/fs-repo-migrations/tools/stump/README.md new file mode 100644 index 00000000..ea469730 --- /dev/null +++ b/fs-repo-12-to-13/vendor/github.com/ipfs/fs-repo-migrations/tools/stump/README.md @@ -0,0 +1,57 @@ +# Stump +A simple log library, for when you don't really care to have super fancy logs. + +Stump has four main log functions, `Log`, `VLog`, `Error` and `Fatal`. + +`Log` is a basic log that always is shown. + +`VLog` is only shown when `stump.Verbose` is set to true. + +`Error` prints a prefix of `ERROR: ` before your log message, +the prefix is configurable by setting `stump.ErrorPrefix`. + +`Fatal` is an error log that also calls `os.Exit` right afterwards. + +## Installation +``` +$ go get -u github.com/whyrusleeping/stump +``` + +## Usage + +```go +import "github.com/whyrusleeping/stump" + +func main() { + stump.Log("Hello World!") + + name := GetName() + stump.Log("My name is %s, do you like it?", name) + + err := DoThing() + if err != nil { + stump.Error(err) + // or + stump.Error("Got an error doing thing: ", err) + // or + stump.Error("Got error '%s' doing thing.", err) + } + + err = DoImportantThing() + if err != nil { + Fatal(err) + } +} +``` + +## Tips +While generally frowned upon, I like importing stump into my packages namespace like so: +``` +import . "github.com/whyrusleeping/stump" +``` + +This allows you to call all the logging functions without the package prefix. +(eg. just `Log("hello")` instead of `stump.Log("hello")`) + +## License +MIT diff --git a/fs-repo-12-to-13/vendor/github.com/ipfs/fs-repo-migrations/tools/stump/log.go b/fs-repo-12-to-13/vendor/github.com/ipfs/fs-repo-migrations/tools/stump/log.go new file mode 100644 index 00000000..8b90f90a --- /dev/null +++ b/fs-repo-12-to-13/vendor/github.com/ipfs/fs-repo-migrations/tools/stump/log.go @@ -0,0 +1,62 @@ +package stump + +import ( + "fmt" + "io" + "os" + "strings" +) + +var Verbose bool + +var ErrorPrefix = "ERROR: " + +var LogOut io.Writer = os.Stdout +var ErrOut io.Writer = os.Stdout + +func Error(args ...interface{}) { + log(ErrOut, ErrorPrefix, args) +} + +func Fatal(args ...interface{}) { + Error(args...) + os.Exit(1) +} + +func Log(args ...interface{}) { + log(LogOut, "", args) +} + +func VLog(args ...interface{}) { + if Verbose { + log(LogOut, "", args) + } +} + +func log(out io.Writer, prefix string, args []interface{}) { + writelog := func(format string, args ...interface{}) { + n := strings.Count(format, "%") + if n < len(args) { + format += strings.Repeat(" %s", len(args)-n) + } + if !strings.HasSuffix(format, "\n") { + format += "\n" + } + fmt.Fprintf(out, format, args...) + } + + if len(args) == 0 { + writelog(prefix) + return + } + + switch s := args[0].(type) { + case string: + writelog(prefix+s, args[1:]...) + case fmt.Stringer: + writelog(prefix+s.String(), args[1:]...) + default: + format := strings.Repeat("%s ", len(args)) + writelog(prefix+format, args...) + } +} diff --git a/fs-repo-12-to-13/vendor/modules.txt b/fs-repo-12-to-13/vendor/modules.txt new file mode 100644 index 00000000..d5ef54e8 --- /dev/null +++ b/fs-repo-12-to-13/vendor/modules.txt @@ -0,0 +1,7 @@ +# github.com/ipfs/fs-repo-migrations/tools v0.0.0-20211209222258-754a2dcb82ea +## explicit; go 1.14 +github.com/ipfs/fs-repo-migrations/tools/go-migrate +github.com/ipfs/fs-repo-migrations/tools/lock +github.com/ipfs/fs-repo-migrations/tools/mfsr +github.com/ipfs/fs-repo-migrations/tools/repolock +github.com/ipfs/fs-repo-migrations/tools/stump