Skip to content

Commit

Permalink
Merge pull request #7857 from ipfs/fix/separate-migrations-bins
Browse files Browse the repository at this point in the history
  • Loading branch information
aschmahmann committed Mar 31, 2021
2 parents 2000384 + b75d823 commit bb8260a
Show file tree
Hide file tree
Showing 16 changed files with 1,622 additions and 363 deletions.
6 changes: 4 additions & 2 deletions cmd/ipfs/daemon.go
Original file line number Diff line number Diff line change
Expand Up @@ -26,7 +26,7 @@ import (
libp2p "github.com/ipfs/go-ipfs/core/node/libp2p"
nodeMount "github.com/ipfs/go-ipfs/fuse/node"
fsrepo "github.com/ipfs/go-ipfs/repo/fsrepo"
migrate "github.com/ipfs/go-ipfs/repo/fsrepo/migrations"
"github.com/ipfs/go-ipfs/repo/fsrepo/migrations"
sockets "github.com/libp2p/go-socket-activation"

cmds "github.com/ipfs/go-ipfs-cmds"
Expand Down Expand Up @@ -288,7 +288,9 @@ func daemonFunc(req *cmds.Request, re cmds.ResponseEmitter, env cmds.Environment
return fmt.Errorf("fs-repo requires migration")
}

err = migrate.RunMigration(fsrepo.RepoVersion)
// Fetch migrations from current distribution, or location from environ
fetcher := migrations.NewHttpFetcher(migrations.GetDistPathEnv(migrations.CurrentIpfsDist), "", "go-ipfs", 0)
err = migrations.RunMigration(cctx.Context(), fetcher, fsrepo.RepoVersion, "", false)
if err != nil {
fmt.Println("The migrations of fs-repo failed:")
fmt.Printf(" %s\n", err)
Expand Down
6 changes: 3 additions & 3 deletions repo/fsrepo/fsrepo.go
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,7 @@ import (
keystore "github.com/ipfs/go-ipfs-keystore"
repo "github.com/ipfs/go-ipfs/repo"
"github.com/ipfs/go-ipfs/repo/common"
mfsr "github.com/ipfs/go-ipfs/repo/fsrepo/migrations"
"github.com/ipfs/go-ipfs/repo/fsrepo/migrations"
dir "github.com/ipfs/go-ipfs/thirdparty/dir"

ds "github.com/ipfs/go-datastore"
Expand Down Expand Up @@ -142,7 +142,7 @@ func open(repoPath string) (repo.Repo, error) {
}()

// Check version, and error out if not matching
ver, err := mfsr.RepoPath(r.path).Version()
ver, err := migrations.RepoVersion(r.path)
if err != nil {
if os.IsNotExist(err) {
return nil, ErrNoVersion
Expand Down Expand Up @@ -291,7 +291,7 @@ func Init(repoPath string, conf *config.Config) error {
return err
}

if err := mfsr.RepoPath(repoPath).WriteVersion(RepoVersion); err != nil {
if err := migrations.WriteRepoVersion(repoPath, RepoVersion); err != nil {
return err
}

Expand Down
172 changes: 172 additions & 0 deletions repo/fsrepo/migrations/fetch.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,172 @@
package migrations

import (
"bufio"
"bytes"
"context"
"fmt"
"io"
"io/ioutil"
"os"
"os/exec"
"path/filepath"
"runtime"
"strings"
)

// FetchBinary downloads an archive from the distribution site and unpacks it.
//
// The base name of the binary inside the archive may differ from the base
// archive name. If it does, then specify binName. For example, the following
// is needed because the archive "go-ipfs_v0.7.0_linux-amd64.tar.gz" contains a
// binary named "ipfs"
//
// FetchBinary(ctx, fetcher, "go-ipfs", "v0.7.0", "ipfs", tmpDir)
//
// If out is a directory, then the binary is written to that directory with the
// same name it has inside the archive. Otherwise, the binary file is written
// to the file named by out.
func FetchBinary(ctx context.Context, fetcher Fetcher, dist, ver, binName, out string) (string, error) {
// The archive file name is the base of dist. This is to support a possible subdir in
// dist, for example: "ipfs-repo-migrations/fs-repo-11-to-12"
arcName := filepath.Base(dist)
// If binary base name is not specified, then it is same as archive base name.
if binName == "" {
binName = arcName
}

// Name of binary that exists inside archive
binName = ExeName(binName)

// Return error if file exists or stat fails for reason other than not
// exists. If out is a directory, then write extracted binary to that dir.
fi, err := os.Stat(out)
if !os.IsNotExist(err) {
if err != nil {
return "", err
}
if !fi.IsDir() {
return "", &os.PathError{
Op: "FetchBinary",
Path: out,
Err: os.ErrExist,
}
}
// out exists and is a directory, so compose final name
out = filepath.Join(out, binName)
// Check if the binary already exists in the directory
_, err = os.Stat(out)
if !os.IsNotExist(err) {
if err != nil {
return "", err
}
return "", &os.PathError{
Op: "FetchBinary",
Path: out,
Err: os.ErrExist,
}
}
}

// Create temp directory to store download
tmpDir, err := ioutil.TempDir("", arcName)
if err != nil {
return "", err
}
defer os.RemoveAll(tmpDir)

atype := "tar.gz"
if runtime.GOOS == "windows" {
atype = "zip"
}

arcDistPath, arcFullName := makeArchivePath(dist, arcName, ver, atype)

// Create a file to write the archive data to
arcPath := filepath.Join(tmpDir, arcFullName)
arcFile, err := os.Create(arcPath)
if err != nil {
return "", err
}
defer arcFile.Close()

// Open connection to download archive from ipfs path
rc, err := fetcher.Fetch(ctx, arcDistPath)
if err != nil {
return "", err
}
defer rc.Close()

// Write download data
_, err = io.Copy(arcFile, rc)
if err != nil {
return "", err
}
arcFile.Close()

// Unpack the archive and write binary to out
err = unpackArchive(arcPath, atype, dist, binName, out)
if err != nil {
return "", err
}

// Set mode of binary to executable
err = os.Chmod(out, 0755)
if err != nil {
return "", err
}

return out, nil
}

// osWithVariant returns the OS name with optional variant.
// Currently returns either runtime.GOOS, or "linux-musl".
func osWithVariant() (string, error) {
if runtime.GOOS != "linux" {
return runtime.GOOS, nil
}

// ldd outputs the system's kind of libc.
// - on standard ubuntu: ldd (Ubuntu GLIBC 2.23-0ubuntu5) 2.23
// - on alpine: musl libc (x86_64)
//
// we use the combined stdout+stderr,
// because ldd --version prints differently on different OSes.
// - on standard ubuntu: stdout
// - on alpine: stderr (it probably doesn't know the --version flag)
//
// we suppress non-zero exit codes (see last point about alpine).
out, err := exec.Command("sh", "-c", "ldd --version || true").CombinedOutput()
if err != nil {
return "", err
}

// now just see if we can find "musl" somewhere in the output
scan := bufio.NewScanner(bytes.NewBuffer(out))
for scan.Scan() {
if strings.Contains(scan.Text(), "musl") {
return "linux-musl", nil
}
}

return "linux", nil
}

// makeArchivePath composes the path, relative to the distribution site, from which to
// download a binary. The path returned does not contain the distribution site path,
// e.g. "/ipns/dist.ipfs.io/", since that is know to the fetcher.
//
// Returns the archive path and the base name.
//
// The ipfs path format is: distribution/version/archiveName
// - distribution is the name of a distribution, such as "go-ipfs"
// - version is the version to fetch, such as "v0.8.0-rc2"
// - archiveName is formatted as name_version_osv-GOARCH.atype, such as
// "go-ipfs_v0.8.0-rc2_linux-amd64.tar.gz"
//
// This would form the path:
// go-ipfs/v0.8.0/go-ipfs_v0.8.0_linux-amd64.tar.gz
func makeArchivePath(dist, name, ver, atype string) (string, string) {
arcName := fmt.Sprintf("%s_%s_%s-%s.%s", name, ver, runtime.GOOS, runtime.GOARCH, atype)
return fmt.Sprintf("%s/%s/%s", dist, ver, arcName), arcName
}
Loading

0 comments on commit bb8260a

Please sign in to comment.