| // Copyright (C) 2015 The Android Open Source Project |
| // |
| // 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 build |
| |
| import ( |
| "fmt" |
| "io" |
| "os" |
| "os/exec" |
| "path/filepath" |
| |
| "android.googlesource.com/platform/tools/gpu/maker" |
| ) |
| |
| // File represents the path to a file or directory. |
| type File string |
| |
| // Path returns a File formed from the joined path segments. |
| func Path(segments ...string) File { |
| return File(filepath.Join(segments...)) |
| } |
| |
| // Join returns a File formed from joining this File with ext. |
| func (f File) Join(ext ...string) File { |
| return File(filepath.Join(append([]string{string(f)}, ext...)...)) |
| } |
| |
| // RelativeTo returns the path of this File relative to base. |
| func (f File) RelativeTo(base File) string { |
| rel, err := filepath.Rel(string(base), string(f)) |
| if err != nil { |
| panic(err) |
| } |
| return rel |
| } |
| |
| // Absolute returns the absolute path of this File. |
| func (f File) Absolute() string { |
| abs, err := filepath.Abs(string(f)) |
| if err != nil { |
| panic(fmt.Errorf("filepath.Abs(%s) returned error: %v", f, err)) |
| } |
| return abs |
| } |
| |
| // Exists returns true if this File exists. |
| func (f File) Exists() bool { |
| _, err := os.Stat(string(f.Absolute())) |
| return err == nil |
| } |
| |
| // Contains returns true if this directory contains the file f. |
| func (d File) Contains(f File) bool { |
| a := d.Absolute() |
| b := f.Absolute() |
| if len(b) <= len(a)+1 { |
| return false |
| } |
| return b[:len(a)] == a && b[len(a)] == filepath.Separator |
| } |
| |
| // Name returns the name part of the File (without directories). |
| func (f File) Name() string { |
| return filepath.Base(string(f)) |
| } |
| |
| // Dir returns the directory part of the File (without filename). |
| func (f File) Dir() string { |
| return filepath.Dir(string(f)) |
| } |
| |
| // Ext returns the extension of the file, including the '.', or an empty string |
| // if the file has no extension. |
| func (f File) Ext() string { |
| return filepath.Ext(string(f)) |
| } |
| |
| // ChangeExt returns a new File with the extension changed to ext. |
| func (f File) ChangeExt(ext string) File { |
| prev := filepath.Ext(string(f)) |
| noext := f[:len(f)-len(prev)] |
| return noext + File(ext) |
| } |
| |
| // Glob returns a FileSet of all files matching any of the specified patterns. |
| func (f File) Glob(patterns ...string) FileSet { |
| fs := FileSet{} |
| for _, patten := range patterns { |
| glob, err := filepath.Glob(string(f.Join(patten))) |
| if err != nil { |
| panic(err) |
| } |
| files := make(FileSet, len(glob)) |
| for i := range glob { |
| files[i] = File(glob[i]) |
| } |
| fs = fs.Append(files...) |
| } |
| return fs |
| } |
| |
| // Matches returns true if the File matches any of the patterns. |
| func (f File) Matches(patterns ...string) bool { |
| abs := filepath.Base(f.Absolute()) |
| for _, pattern := range patterns { |
| matched, err := filepath.Match(pattern, abs) |
| if err != nil { |
| panic(err) |
| } |
| if matched { |
| return true |
| } |
| } |
| return false |
| } |
| |
| // MkdirAll creates the directory hierarchy to hold this File. |
| func (f File) MkdirAll() { |
| abs := f.Absolute() |
| dir, _ := filepath.Split(abs) |
| if len(dir) > 0 { |
| if err := os.MkdirAll(dir, os.ModePerm); err != nil { |
| panic(err) |
| } |
| } |
| } |
| |
| // CopyTo copied this File to dst, replacing any existing file at dst. |
| func (f File) CopyTo(dst File) error { |
| s, err := os.Open(f.Absolute()) |
| if err != nil { |
| return fmt.Errorf("Open copy source failed: %v", err) |
| } |
| defer s.Close() |
| |
| fi, err := s.Stat() |
| if err != nil { |
| return fmt.Errorf("Stat copy source failed: %v", err) |
| } |
| |
| d, err := os.OpenFile(dst.Absolute(), os.O_CREATE|os.O_TRUNC|os.O_WRONLY, fi.Mode()) |
| if err != nil { |
| return fmt.Errorf("Create copy target failed: %v", err) |
| } |
| defer d.Close() |
| |
| if _, err = io.Copy(d, s); err != nil { |
| return fmt.Errorf("Copy file data failed: %v", err) |
| } |
| return nil |
| } |
| |
| // Exec executes this File with the specified arguments. |
| func (f File) Exec(env Environment, args ...string) error { |
| path, err := f.LookPath() |
| if err != nil { |
| return err |
| } |
| return f.ExecAt(env, File(path.Dir()), args...) |
| } |
| |
| // ExecAt executes this File with the specified arguments with the working |
| // directory set to wd. |
| func (f File) ExecAt(env Environment, wd File, args ...string) error { |
| if !wd.Exists() { |
| return fmt.Errorf("The working directory '%s' does not exist", wd) |
| } |
| path, err := f.LookPath() |
| if err != nil { |
| return err |
| } |
| verbose := 0 |
| if env.Verbose { |
| verbose = 1 |
| } |
| return maker.ExecAt(wd.Absolute(), verbose, path.Absolute(), args...) |
| } |
| |
| // LookPath returns the path to f, searching the system PATHs. |
| func (f File) LookPath() (File, error) { |
| if f.Exists() { |
| return f, nil |
| } else { |
| path, err := exec.LookPath(string(f)) |
| return File(path), err |
| } |
| } |