blob: b69d93887202e4806e332f03ae50d51a8b8c09bf [file] [log] [blame]
/**
* Licensed to the Apache Software Foundation (ASF) under one
* or more contributor license agreements. See the NOTICE file
* distributed with this work for additional information
* regarding copyright ownership. The ASF licenses this file
* to you 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 target
import (
"os"
"path/filepath"
"sort"
"strings"
"mynewt.apache.org/newt/newt/pkg"
"mynewt.apache.org/newt/newt/project"
"mynewt.apache.org/newt/newt/repo"
"mynewt.apache.org/newt/util"
"mynewt.apache.org/newt/yaml"
)
const TARGET_FILENAME string = "target.yml"
const DEFAULT_BUILD_PROFILE string = "default"
var globalTargetMap map[string]*Target
type Target struct {
basePkg *pkg.LocalPackage
BspName string
AppName string
BuildProfile string
// target.yml configuration structure
Vars map[string]string
}
func NewTarget(basePkg *pkg.LocalPackage) *Target {
target := &Target{}
target.Init(basePkg)
return target
}
func LoadTarget(basePkg *pkg.LocalPackage) (*Target, error) {
target := NewTarget(basePkg)
if err := target.Load(basePkg); err != nil {
return nil, err
}
return target, nil
}
func (target *Target) Init(basePkg *pkg.LocalPackage) {
target.basePkg = basePkg
}
func (target *Target) Load(basePkg *pkg.LocalPackage) error {
v, err := util.ReadConfig(basePkg.BasePath(),
strings.TrimSuffix(TARGET_FILENAME, ".yml"))
if err != nil {
return err
}
target.Vars = map[string]string{}
settings := v.AllSettings()
for k, v := range settings {
target.Vars[k] = v.(string)
}
target.BspName = target.Vars["target.bsp"]
target.AppName = target.Vars["target.app"]
target.BuildProfile = target.Vars["target.build_profile"]
if target.BuildProfile == "" {
target.BuildProfile = DEFAULT_BUILD_PROFILE
}
// Note: App not required in the case of unit tests.
// Remember the name of the configuration file so that it can be specified
// as a dependency to the compiler.
target.basePkg.AddCfgFilename(basePkg.BasePath() + TARGET_FILENAME)
return nil
}
func (target *Target) Validate(appRequired bool) error {
if target.BspName == "" {
return util.NewNewtError("Target does not specify a BSP package " +
"(target.bsp)")
}
bsp := target.resolvePackageName(target.BspName)
if bsp == nil {
return util.FmtNewtError("Could not resolve BSP package: %s",
target.BspName)
}
if bsp.Type() != pkg.PACKAGE_TYPE_BSP {
return util.FmtNewtError("bsp package (%s) is not of "+
"type bsp; type is: %s\n", bsp.Name(),
pkg.PackageTypeNames[bsp.Type()])
}
if appRequired {
if target.AppName == "" {
return util.NewNewtError("Target does not specify an app " +
"package (target.app)")
}
app := target.resolvePackageName(target.AppName)
if app == nil {
return util.FmtNewtError("Could not resolve app package: %s",
target.AppName)
}
if app.Type() != pkg.PACKAGE_TYPE_APP {
return util.FmtNewtError("target.app package (%s) is not of "+
"type app; type is: %s\n", app.Name(),
pkg.PackageTypeNames[app.Type()])
}
}
return nil
}
func (target *Target) Package() *pkg.LocalPackage {
return target.basePkg
}
func (target *Target) Name() string {
return target.basePkg.Name()
}
func (target *Target) FullName() string {
return target.basePkg.FullName()
}
func (target *Target) ShortName() string {
return filepath.Base(target.Name())
}
func (target *Target) Clone(newRepo *repo.Repo, newName string) *Target {
// Clone the target.
newTarget := *target
newTarget.basePkg = target.basePkg.Clone(newRepo, newName)
// Insert the clone into the global target map.
GetTargets()[newTarget.FullName()] = &newTarget
return &newTarget
}
func (target *Target) resolvePackageName(name string) *pkg.LocalPackage {
dep, err := pkg.NewDependency(target.basePkg.Repo(), name)
if err != nil {
return nil
}
pack, ok := project.GetProject().ResolveDependency(dep).(*pkg.LocalPackage)
if !ok {
return nil
}
return pack
}
func (target *Target) App() *pkg.LocalPackage {
return target.resolvePackageName(target.AppName)
}
func (target *Target) Bsp() *pkg.LocalPackage {
return target.resolvePackageName(target.BspName)
}
func (target *Target) BinBasePath() string {
appPkg := target.App()
if appPkg == nil {
return ""
}
return appPkg.BasePath() + "/bin/" + target.Name() + "/" +
appPkg.Name()
}
func (target *Target) ElfPath() string {
return target.BinBasePath() + ".elf"
}
func (target *Target) ImagePath() string {
return target.BinBasePath() + ".img"
}
// Save the target's configuration elements
func (t *Target) Save() error {
if err := t.basePkg.Save(); err != nil {
return err
}
dirpath := t.basePkg.BasePath()
filepath := dirpath + "/" + TARGET_FILENAME
file, err := os.Create(filepath)
if err != nil {
return util.NewNewtError(err.Error())
}
defer file.Close()
file.WriteString("### Target: " + t.Name() + "\n")
keys := []string{}
for k, _ := range t.Vars {
keys = append(keys, k)
}
sort.Strings(keys)
for _, k := range keys {
file.WriteString(k + ": " + yaml.EscapeString(t.Vars[k]) + "\n")
}
return nil
}
func buildTargetMap() error {
globalTargetMap = map[string]*Target{}
packs := project.GetProject().PackagesOfType(pkg.PACKAGE_TYPE_TARGET)
for _, packItf := range packs {
pack := packItf.(*pkg.LocalPackage)
target, err := LoadTarget(pack)
if err != nil {
nerr := err.(*util.NewtError)
util.ErrorMessage(util.VERBOSITY_QUIET,
"Warning: failed to load target \"%s\": %s\n", pack.Name(),
nerr.Text)
} else {
globalTargetMap[pack.FullName()] = target
}
}
return nil
}
func GetTargets() map[string]*Target {
if globalTargetMap == nil {
err := buildTargetMap()
if err != nil {
panic(err.Error())
}
}
return globalTargetMap
}