github.com/bilus/oya@v0.0.3-0.20190301162104-da4acbd394c6/pkg/oyafile/oyafile.go (about)

     1  package oyafile
     2  
     3  import (
     4  	"io"
     5  	"os"
     6  	"path"
     7  	"path/filepath"
     8  	"strings"
     9  
    10  	log "github.com/sirupsen/logrus"
    11  
    12  	"github.com/bilus/oya/pkg/raw"
    13  	"github.com/bilus/oya/pkg/semver"
    14  	"github.com/bilus/oya/pkg/task"
    15  	"github.com/bilus/oya/pkg/template"
    16  	"github.com/bilus/oya/pkg/types"
    17  	"github.com/pkg/errors"
    18  )
    19  
    20  // OyaCmdOverride is used in tests, to override the path to the current oya executable.
    21  // It is used to invoke other tasks from a task body.
    22  // When tests are run, the current process executable path points to the test runner
    23  // so it has to be overridden (with 'go run oya.go', roughly speaking).
    24  var OyaCmdOverride *string
    25  
    26  type PackReference struct {
    27  	ImportPath types.ImportPath
    28  	Version    semver.Version
    29  	// ReplacementPath is a path relative to the root directory, when the replacement for the pack can be found, based on the Replace: directive.
    30  	ReplacementPath string
    31  }
    32  
    33  type PackReplacements map[types.ImportPath]string
    34  
    35  type Oyafile struct {
    36  	Dir      string
    37  	Path     string
    38  	RootDir  string
    39  	Shell    string
    40  	Imports  map[types.Alias]types.ImportPath
    41  	Tasks    task.Table
    42  	Values   template.Scope
    43  	Project  string   // Project is set for root Oyafile.
    44  	Ignore   []string // Ignore contains directory exclusion rules.
    45  	Requires []PackReference
    46  	// Replacements map packs to local paths relative to project root directory for development based on the Replace: directive.
    47  	Replacements PackReplacements
    48  	IsBuilt      bool
    49  
    50  	relPath string
    51  
    52  	OyaCmd string // OyaCmd contains the path to the current oya executable.
    53  }
    54  
    55  func New(oyafilePath string, rootDir string) (*Oyafile, error) {
    56  	var oyaCmd string
    57  	if OyaCmdOverride != nil {
    58  		oyaCmd = *OyaCmdOverride
    59  	} else {
    60  		var err error
    61  		oyaCmd, err = os.Executable()
    62  		if err != nil {
    63  			return nil, err
    64  		}
    65  	}
    66  
    67  	relPath, err := filepath.Rel(rootDir, oyafilePath)
    68  	log.Debug("Oyafile at ", oyafilePath)
    69  	if err != nil {
    70  		return nil, err
    71  	}
    72  	dir := path.Dir(oyafilePath)
    73  	return &Oyafile{
    74  		Dir:          filepath.Clean(dir),
    75  		Path:         filepath.Clean(oyafilePath),
    76  		RootDir:      filepath.Clean(rootDir),
    77  		Shell:        "/bin/bash",
    78  		Imports:      make(map[types.Alias]types.ImportPath),
    79  		Tasks:        task.NewTable(),
    80  		Values:       template.Scope{},
    81  		relPath:      relPath,
    82  		Replacements: make(PackReplacements),
    83  		OyaCmd:       oyaCmd,
    84  	}, nil
    85  }
    86  
    87  func Load(oyafilePath, rootDir string) (*Oyafile, bool, error) {
    88  	raw, found, err := raw.Load(oyafilePath, rootDir)
    89  	if err != nil || !found {
    90  		return nil, found, err
    91  	}
    92  	oyafile, err := Parse(raw)
    93  	if err != nil {
    94  		return nil, false, wrapLoadErr(err, oyafilePath)
    95  	}
    96  	return oyafile, true, nil
    97  }
    98  
    99  func LoadFromDir(dirPath, rootDir string) (*Oyafile, bool, error) {
   100  	raw, found, err := raw.LoadFromDir(dirPath, rootDir)
   101  	if err != nil || !found {
   102  		return nil, found, err
   103  	}
   104  	oyafile, err := Parse(raw)
   105  	if err != nil {
   106  		return nil, false, wrapLoadErr(err, raw.Path)
   107  	}
   108  	return oyafile, true, nil
   109  }
   110  
   111  func (oyafile Oyafile) RunTask(taskName task.Name, scope template.Scope, stdout, stderr io.Writer) (bool, error) {
   112  	if !oyafile.IsBuilt {
   113  		return false, errors.Errorf("Internal error: Oyafile has not been built")
   114  	}
   115  	task, ok := oyafile.Tasks.LookupTask(taskName)
   116  	if !ok {
   117  		return false, nil
   118  	}
   119  	tasks, err := oyafile.bindTasks(taskName, task, stdout, stderr)
   120  	if err != nil {
   121  		return true, err
   122  	}
   123  	scope["Tasks"] = tasks
   124  
   125  	render, err := oyafile.bindRender(taskName, stdout, stderr)
   126  	if err != nil {
   127  		return true, err
   128  	}
   129  	scope["Render"] = render
   130  
   131  	return true, task.Exec(oyafile.Dir, scope, stdout, stderr)
   132  }
   133  
   134  func (oyafile Oyafile) Equals(other Oyafile) bool {
   135  	// TODO: Far from perfect, we should ensure relative vs absolute paths work.
   136  	// The simplest thing is probably to ensure oyafile.Dir is always absolute.
   137  	return filepath.Clean(oyafile.Dir) == filepath.Clean(other.Dir)
   138  }
   139  
   140  func wrapLoadErr(err error, oyafilePath string) error {
   141  	return errors.Wrapf(err, "error loading Oyafile %v", oyafilePath)
   142  }
   143  
   144  func (o *Oyafile) Ignores() string {
   145  	return strings.Join(o.Ignore, "\n")
   146  }
   147  
   148  func (o *Oyafile) RelPath() string {
   149  	return o.relPath
   150  }