mirror of
https://github.com/tailscale/tailscale.git
synced 2024-11-29 21:15:39 +00:00
91 lines
2.3 KiB
Go
91 lines
2.3 KiB
Go
|
// Copyright (c) Tailscale Inc & AUTHORS
|
||
|
// SPDX-License-Identifier: BSD-3-Clause
|
||
|
|
||
|
package main
|
||
|
|
||
|
import (
|
||
|
"errors"
|
||
|
"fmt"
|
||
|
"io"
|
||
|
"io/fs"
|
||
|
"os"
|
||
|
"path/filepath"
|
||
|
)
|
||
|
|
||
|
// makeGoroot constructs a GOROOT-like file structure in outPath,
|
||
|
// which consists of toolchainRoot except for the `go` binary, which
|
||
|
// points to gocross.
|
||
|
//
|
||
|
// It's useful for integrating with tooling that expects to be handed
|
||
|
// a GOROOT, like the Goland IDE or depaware.
|
||
|
func makeGoroot(toolchainRoot, outPath string) error {
|
||
|
self, err := os.Executable()
|
||
|
if err != nil {
|
||
|
return fmt.Errorf("getting gocross's path: %v", err)
|
||
|
}
|
||
|
|
||
|
os.RemoveAll(outPath)
|
||
|
if err := os.MkdirAll(filepath.Join(outPath, "bin"), 0750); err != nil {
|
||
|
return fmt.Errorf("making %q: %v", outPath, err)
|
||
|
}
|
||
|
if err := os.Symlink(self, filepath.Join(outPath, "bin/go")); err != nil {
|
||
|
return fmt.Errorf("linking gocross into outpath: %v", err)
|
||
|
}
|
||
|
|
||
|
if err := linkFarm(toolchainRoot, outPath); err != nil {
|
||
|
return fmt.Errorf("creating GOROOT link farm: %v", err)
|
||
|
}
|
||
|
if err := linkFarm(filepath.Join(toolchainRoot, "bin"), filepath.Join(outPath, "bin")); err != nil {
|
||
|
return fmt.Errorf("creating GOROOT/bin link farm: %v", err)
|
||
|
}
|
||
|
|
||
|
return nil
|
||
|
}
|
||
|
|
||
|
func copyFile(src, dst string) error {
|
||
|
s, err := os.Open(src)
|
||
|
if err != nil {
|
||
|
return fmt.Errorf("opening %q: %v", src, err)
|
||
|
}
|
||
|
defer s.Close()
|
||
|
|
||
|
d, err := os.OpenFile(dst, os.O_RDWR|os.O_CREATE, 0755)
|
||
|
if err != nil {
|
||
|
return fmt.Errorf("opening %q: %v", dst, err)
|
||
|
}
|
||
|
|
||
|
if _, err := io.Copy(d, s); err != nil {
|
||
|
d.Close()
|
||
|
return fmt.Errorf("copying %q to %q: %v", src, dst, err)
|
||
|
}
|
||
|
|
||
|
if err := d.Close(); err != nil {
|
||
|
return fmt.Errorf("closing %q: %v", dst, err)
|
||
|
}
|
||
|
|
||
|
return nil
|
||
|
}
|
||
|
|
||
|
// linkFarm symlinks every entry in srcDir into outDir, unless that
|
||
|
// directory entry already exists.
|
||
|
func linkFarm(srcDir, outDir string) error {
|
||
|
ents, err := os.ReadDir(srcDir)
|
||
|
if err != nil {
|
||
|
return fmt.Errorf("reading %q: %v", srcDir, err)
|
||
|
}
|
||
|
|
||
|
for _, ent := range ents {
|
||
|
dst := filepath.Join(outDir, ent.Name())
|
||
|
_, err := os.Lstat(dst)
|
||
|
if errors.Is(err, fs.ErrNotExist) {
|
||
|
if err := os.Symlink(filepath.Join(srcDir, ent.Name()), dst); err != nil {
|
||
|
return fmt.Errorf("symlinking %q to %q: %v", ent.Name(), outDir, err)
|
||
|
}
|
||
|
} else if err != nil {
|
||
|
return fmt.Errorf("stat-ing %q: %v", dst, err)
|
||
|
}
|
||
|
}
|
||
|
|
||
|
return nil
|
||
|
}
|