1*9bb1b549SSpandan Das// Copyright 2018 The Bazel Authors. All rights reserved. 2*9bb1b549SSpandan Das// 3*9bb1b549SSpandan Das// Licensed under the Apache License, Version 2.0 (the "License"); 4*9bb1b549SSpandan Das// you may not use this file except in compliance with the License. 5*9bb1b549SSpandan Das// You may obtain a copy of the License at 6*9bb1b549SSpandan Das// 7*9bb1b549SSpandan Das// http://www.apache.org/licenses/LICENSE-2.0 8*9bb1b549SSpandan Das// 9*9bb1b549SSpandan Das// Unless required by applicable law or agreed to in writing, software 10*9bb1b549SSpandan Das// distributed under the License is distributed on an "AS IS" BASIS, 11*9bb1b549SSpandan Das// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12*9bb1b549SSpandan Das// See the License for the specific language governing permissions and 13*9bb1b549SSpandan Das// limitations under the License. 14*9bb1b549SSpandan Das 15*9bb1b549SSpandan Das// stdlib builds the standard library in the appropriate mode into a new goroot. 16*9bb1b549SSpandan Daspackage main 17*9bb1b549SSpandan Das 18*9bb1b549SSpandan Dasimport ( 19*9bb1b549SSpandan Das "fmt" 20*9bb1b549SSpandan Das "io" 21*9bb1b549SSpandan Das "os" 22*9bb1b549SSpandan Das "path/filepath" 23*9bb1b549SSpandan Das) 24*9bb1b549SSpandan Das 25*9bb1b549SSpandan Dastype replicateMode int 26*9bb1b549SSpandan Das 27*9bb1b549SSpandan Dasconst ( 28*9bb1b549SSpandan Das copyMode replicateMode = iota 29*9bb1b549SSpandan Das hardlinkMode 30*9bb1b549SSpandan Das softlinkMode 31*9bb1b549SSpandan Das) 32*9bb1b549SSpandan Das 33*9bb1b549SSpandan Dastype replicateOption func(*replicateConfig) 34*9bb1b549SSpandan Dastype replicateConfig struct { 35*9bb1b549SSpandan Das removeFirst bool 36*9bb1b549SSpandan Das fileMode replicateMode 37*9bb1b549SSpandan Das dirMode replicateMode 38*9bb1b549SSpandan Das paths []string 39*9bb1b549SSpandan Das} 40*9bb1b549SSpandan Das 41*9bb1b549SSpandan Dasfunc replicatePaths(paths ...string) replicateOption { 42*9bb1b549SSpandan Das return func(config *replicateConfig) { 43*9bb1b549SSpandan Das config.paths = append(config.paths, paths...) 44*9bb1b549SSpandan Das } 45*9bb1b549SSpandan Das} 46*9bb1b549SSpandan Das 47*9bb1b549SSpandan Das// replicatePrepare is the common preparation steps for a replication entry 48*9bb1b549SSpandan Dasfunc replicatePrepare(dst string, config *replicateConfig) error { 49*9bb1b549SSpandan Das dir := filepath.Dir(dst) 50*9bb1b549SSpandan Das if err := os.MkdirAll(dir, 0755); err != nil { 51*9bb1b549SSpandan Das return fmt.Errorf("Failed to make %s: %v", dir, err) 52*9bb1b549SSpandan Das } 53*9bb1b549SSpandan Das if config.removeFirst { 54*9bb1b549SSpandan Das _ = os.Remove(dst) 55*9bb1b549SSpandan Das } 56*9bb1b549SSpandan Das return nil 57*9bb1b549SSpandan Das} 58*9bb1b549SSpandan Das 59*9bb1b549SSpandan Das// replicateFile is called internally by replicate to map a single file from src into dst. 60*9bb1b549SSpandan Dasfunc replicateFile(src, dst string, config *replicateConfig) error { 61*9bb1b549SSpandan Das if err := replicatePrepare(dst, config); err != nil { 62*9bb1b549SSpandan Das return err 63*9bb1b549SSpandan Das } 64*9bb1b549SSpandan Das switch config.fileMode { 65*9bb1b549SSpandan Das case copyMode: 66*9bb1b549SSpandan Das in, err := os.Open(src) 67*9bb1b549SSpandan Das if err != nil { 68*9bb1b549SSpandan Das return err 69*9bb1b549SSpandan Das } 70*9bb1b549SSpandan Das defer in.Close() 71*9bb1b549SSpandan Das out, err := os.Create(dst) 72*9bb1b549SSpandan Das if err != nil { 73*9bb1b549SSpandan Das return err 74*9bb1b549SSpandan Das } 75*9bb1b549SSpandan Das _, err = io.Copy(out, in) 76*9bb1b549SSpandan Das closeerr := out.Close() 77*9bb1b549SSpandan Das if err != nil { 78*9bb1b549SSpandan Das return err 79*9bb1b549SSpandan Das } 80*9bb1b549SSpandan Das if closeerr != nil { 81*9bb1b549SSpandan Das return closeerr 82*9bb1b549SSpandan Das } 83*9bb1b549SSpandan Das s, err := os.Stat(src) 84*9bb1b549SSpandan Das if err != nil { 85*9bb1b549SSpandan Das return err 86*9bb1b549SSpandan Das } 87*9bb1b549SSpandan Das if err := os.Chmod(dst, s.Mode()); err != nil { 88*9bb1b549SSpandan Das return err 89*9bb1b549SSpandan Das } 90*9bb1b549SSpandan Das return nil 91*9bb1b549SSpandan Das case hardlinkMode: 92*9bb1b549SSpandan Das return os.Link(src, dst) 93*9bb1b549SSpandan Das case softlinkMode: 94*9bb1b549SSpandan Das return os.Symlink(src, dst) 95*9bb1b549SSpandan Das default: 96*9bb1b549SSpandan Das return fmt.Errorf("Invalid replication mode %d", config.fileMode) 97*9bb1b549SSpandan Das } 98*9bb1b549SSpandan Das} 99*9bb1b549SSpandan Das 100*9bb1b549SSpandan Das// replicateDir makes a tree of files visible in a new location. 101*9bb1b549SSpandan Das// It is allowed to take any efficient method of doing so. 102*9bb1b549SSpandan Dasfunc replicateDir(src, dst string, config *replicateConfig) error { 103*9bb1b549SSpandan Das if err := replicatePrepare(dst, config); err != nil { 104*9bb1b549SSpandan Das return err 105*9bb1b549SSpandan Das } 106*9bb1b549SSpandan Das switch config.dirMode { 107*9bb1b549SSpandan Das case copyMode: 108*9bb1b549SSpandan Das return filepath.Walk(src, func(path string, f os.FileInfo, err error) error { 109*9bb1b549SSpandan Das if f.IsDir() { 110*9bb1b549SSpandan Das return nil 111*9bb1b549SSpandan Das } 112*9bb1b549SSpandan Das relative, err := filepath.Rel(src, path) 113*9bb1b549SSpandan Das if err != nil { 114*9bb1b549SSpandan Das return err 115*9bb1b549SSpandan Das } 116*9bb1b549SSpandan Das return replicateFile(path, filepath.Join(dst, relative), config) 117*9bb1b549SSpandan Das }) 118*9bb1b549SSpandan Das case hardlinkMode: 119*9bb1b549SSpandan Das return os.Link(src, dst) 120*9bb1b549SSpandan Das case softlinkMode: 121*9bb1b549SSpandan Das return os.Symlink(src, dst) 122*9bb1b549SSpandan Das default: 123*9bb1b549SSpandan Das return fmt.Errorf("Invalid replication mode %d", config.fileMode) 124*9bb1b549SSpandan Das } 125*9bb1b549SSpandan Das} 126*9bb1b549SSpandan Das 127*9bb1b549SSpandan Das// replicateTree is called for each single src dst pair. 128*9bb1b549SSpandan Dasfunc replicateTree(src, dst string, config *replicateConfig) error { 129*9bb1b549SSpandan Das if err := os.RemoveAll(dst); err != nil { 130*9bb1b549SSpandan Das return fmt.Errorf("Failed to remove file at destination %s: %v", dst, err) 131*9bb1b549SSpandan Das } 132*9bb1b549SSpandan Das if l, err := filepath.EvalSymlinks(src); err != nil { 133*9bb1b549SSpandan Das return err 134*9bb1b549SSpandan Das } else { 135*9bb1b549SSpandan Das src = l 136*9bb1b549SSpandan Das } 137*9bb1b549SSpandan Das if s, err := os.Stat(src); err != nil { 138*9bb1b549SSpandan Das return err 139*9bb1b549SSpandan Das } else if s.IsDir() { 140*9bb1b549SSpandan Das return replicateDir(src, dst, config) 141*9bb1b549SSpandan Das } 142*9bb1b549SSpandan Das return replicateFile(src, dst, config) 143*9bb1b549SSpandan Das} 144*9bb1b549SSpandan Das 145*9bb1b549SSpandan Das// replicate makes a tree of files visible in a new location. 146*9bb1b549SSpandan Das// You control how it does so using options, by default it presumes the entire tree 147*9bb1b549SSpandan Das// of files rooted at src must be visible at dst, and that it should do so by copying. 148*9bb1b549SSpandan Das// src is allowed to be a file, in which case just the one file is copied. 149*9bb1b549SSpandan Dasfunc replicate(src, dst string, options ...replicateOption) error { 150*9bb1b549SSpandan Das config := replicateConfig{ 151*9bb1b549SSpandan Das removeFirst: true, 152*9bb1b549SSpandan Das } 153*9bb1b549SSpandan Das for _, option := range options { 154*9bb1b549SSpandan Das option(&config) 155*9bb1b549SSpandan Das } 156*9bb1b549SSpandan Das if len(config.paths) == 0 { 157*9bb1b549SSpandan Das return replicateTree(src, dst, &config) 158*9bb1b549SSpandan Das } 159*9bb1b549SSpandan Das for _, base := range config.paths { 160*9bb1b549SSpandan Das from := filepath.Join(src, base) 161*9bb1b549SSpandan Das to := filepath.Join(dst, base) 162*9bb1b549SSpandan Das if err := replicateTree(from, to, &config); err != nil { 163*9bb1b549SSpandan Das return err 164*9bb1b549SSpandan Das } 165*9bb1b549SSpandan Das } 166*9bb1b549SSpandan Das return nil 167*9bb1b549SSpandan Das} 168