blob: fe36bc88980edb79c64924391430b89d1e61be04 [file] [log] [blame]
/*
Copyright 2015 Runtime Inc.
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 cli
import (
"bufio"
"fmt"
"log"
"os"
"strings"
)
const TARGET_SECT_PREFIX = "_target_"
type Target struct {
Vars map[string]string
Identities []string
Capabilities []string
Dependencies []string
Cflags string
Lflags string
Aflags string
Name string
Arch string
Cdef string
Bsp string
Repo *Repo
}
// Check if the target specified by name exists for the Repo specified by
// r
func TargetExists(r *Repo, name string) bool {
_, err := r.GetConfig(TARGET_SECT_PREFIX+name, "name")
if err == nil {
return true
} else {
return false
}
}
func parseTargetStringSlice(str string) ([]string, error) {
slice := strings.Split(str, " ")
return slice, nil
}
func (t *Target) SetDefaults() error {
var err error
t.Name = t.Vars["name"]
if t.Vars["project"] != "" && t.Vars["egg"] != "" {
return NewNewtError("Target " + t.Vars["name"] + " cannot have a " +
"project and package set.")
}
// Must have an architecture set, default to sim.
if t.Vars["arch"] == "" {
t.Vars["arch"] = "sim"
t.Arch = "sim"
} else {
t.Arch = t.Vars["arch"]
}
t.Cdef = t.Vars["compiler_def"]
if t.Cdef == "" {
t.Cdef = "default"
}
t.Bsp = t.Vars["bsp"]
t.Cflags = t.Vars["cflags"]
t.Lflags = t.Vars["lflags"]
t.Identities, err = parseTargetStringSlice(t.Vars["identities"])
if err != nil {
return err
}
t.Capabilities, err = parseTargetStringSlice(t.Vars["capabilities"])
if err != nil {
return err
}
t.Dependencies, err = parseTargetStringSlice(t.Vars["dependencies"])
if err != nil {
return err
}
return nil
}
func (t *Target) HasIdentity(identity string) bool {
for _, cur := range t.Identities {
if cur == identity {
return true
}
}
return false
}
// Load the target specified by name for the repository specified by r
func LoadTarget(r *Repo, name string) (*Target, error) {
t := &Target{
Repo: r,
}
var err error
t.Vars, err = r.GetConfigSect(TARGET_SECT_PREFIX + name)
if err != nil {
return nil, err
}
// Cannot have both a project and package set
err = t.SetDefaults()
if err != nil {
return nil, err
}
return t, nil
}
// Export a target, or all targets. If exportAll is true, then all targets are exported, if false,
// then only the target represented by targetName is exported
func ExportTargets(r *Repo, name string, exportAll bool, fp *os.File) error {
targets, err := GetTargets(r)
if err != nil {
return err
}
for _, target := range targets {
log.Printf("[DEBUG] Exporting target %s", target.Name)
if !exportAll && target.Name != name {
continue
}
fmt.Fprintf(fp, "@target=%s\n", target.Name)
for k, v := range target.GetVars() {
fmt.Fprintf(fp, "%s=%s\n", k, v)
}
}
fmt.Fprintf(fp, "@endtargets\n")
return nil
}
func ImportTargets(r *Repo, name string, importAll bool, fp *os.File) error {
s := bufio.NewScanner(fp)
var currentTarget *Target = nil
targets := make([]*Target, 0, 10)
if importAll {
log.Printf("[DEBUG] Importing all targets from %s", fp.Name())
} else {
log.Printf("[DEBUG] Importing target %s from %s", name, fp.Name())
}
for s.Scan() {
line := s.Text()
// scan lines
// lines defining a target start with @
if idx := strings.Index(line, "@"); idx == 0 {
// save existing target if it exists
if currentTarget != nil {
targets = append(targets, currentTarget)
}
// look either for an end of target definitions, or a new target definition
if line == "@endtargets" {
break
} else {
// create a current target
elements := strings.SplitN(line, "=", 2)
// name is elements[0], and value is elements[1]
currentTarget = &Target{
Repo: r,
}
var err error
currentTarget.Vars = map[string]string{}
if err != nil {
return err
}
currentTarget.Vars["name"] = elements[1]
}
} else {
if currentTarget == nil {
return NewNewtError("No target present when variables being set in import file")
}
// target variables, set these on the current target
elements := strings.SplitN(line, "=", 2)
currentTarget.Vars[elements[0]] = elements[1]
}
}
if err := s.Err(); err != nil {
return err
}
for _, target := range targets {
if err := target.SetDefaults(); err != nil {
return err
}
if err := target.Save(); err != nil {
return err
}
}
return nil
}
// Get a list of targets for the repository specified by r
func GetTargets(r *Repo) ([]*Target, error) {
targets := []*Target{}
for sect, _ := range r.Config {
if strings.HasPrefix(sect, TARGET_SECT_PREFIX) {
target, err := LoadTarget(r, sect[len(TARGET_SECT_PREFIX):len(sect)])
if err != nil {
return nil, err
}
targets = append(targets, target)
}
}
return targets, nil
}
// Get a map[] of variables for this target
func (t *Target) GetVars() map[string]string {
return t.Vars
}
// Return the compiler definition file for this target
func (t *Target) GetCompiler() string {
path := t.Repo.BasePath + "/compiler/"
if t.Vars["compiler"] != "" {
path += t.Vars["compiler"]
} else {
path += t.Arch
}
path += "/"
return path
}
// Build the target
func (t *Target) Build() error {
if t.Vars["project"] != "" {
// Now load and build the project.
p, err := LoadProject(t.Repo, t, t.Vars["project"])
if err != nil {
return err
}
// The project is the target, and builds itself.
if err = p.Build(); err != nil {
return err
}
} else if t.Vars["egg"] != "" {
pm, err := NewEggMgr(t.Repo, t)
if err != nil {
return err
}
err = pm.Build(t, t.Vars["egg"], nil, nil)
if err != nil {
return err
}
}
return nil
}
func (t *Target) BuildClean(cleanAll bool) error {
if t.Vars["project"] != "" {
p, err := LoadProject(t.Repo, t, t.Vars["project"])
if err != nil {
return err
}
// The project is the target, and build cleans itself.
if err = p.BuildClean(cleanAll); err != nil {
return err
}
} else if t.Vars["egg"] != "" {
pm, err := NewEggMgr(t.Repo, t)
if err != nil {
return err
}
err = pm.BuildClean(t, t.Vars["egg"], cleanAll)
if err != nil {
return err
}
}
return nil
}
func (t *Target) Test(cmd string, flag bool) error {
if t.Vars["project"] != "" {
return NewNewtError("Tests not supported on projects, only packages")
}
pm, err := NewEggMgr(t.Repo, t)
if err != nil {
return err
}
switch cmd {
case "test":
err = pm.Test(t, t.Vars["egg"], flag)
case "testclean":
err = pm.TestClean(t, t.Vars["egg"], flag)
default:
err = NewNewtError("Unknown command to Test() " + cmd)
}
if err != nil {
return err
}
return nil
}
func (t *Target) DeleteVar(name string) error {
targetCfgSect := TARGET_SECT_PREFIX + t.Vars["name"]
if err := t.Repo.DelConfig(targetCfgSect, name); err != nil {
return err
}
return nil
}
// Save the target's configuration elements
func (t *Target) Save() error {
r := t.Repo
if _, ok := t.Vars["name"]; !ok {
return NewNewtError("Cannot save a target without a name")
}
targetCfg := TARGET_SECT_PREFIX + t.Vars["name"]
for k, v := range t.Vars {
if err := r.SetConfig(targetCfg, k, v); err != nil {
return err
}
}
return nil
}
func (t *Target) Remove() error {
r := t.Repo
if _, ok := t.Vars["name"]; !ok {
return NewNewtError("Cannot remove a target without a name")
}
cfgSect := TARGET_SECT_PREFIX + t.Vars["name"]
for k, _ := range t.Vars {
if err := r.DelConfig(cfgSect, k); err != nil {
return err
}
}
return nil
}