github.com/hwaf/hwaf@v0.0.0-20140814122253-5465f73b20f1/plugins/asetup/asetup.go (about)

     1  package asetup
     2  
     3  import (
     4  	"fmt"
     5  	"os"
     6  	"os/exec"
     7  	"path/filepath"
     8  	"runtime"
     9  	"sort"
    10  	"strings"
    11  
    12  	"github.com/gonuts/commander"
    13  	gocfg "github.com/gonuts/config"
    14  	"github.com/hwaf/hwaf/hwaflib"
    15  	"github.com/hwaf/hwaf/platform"
    16  )
    17  
    18  func path_exists(name string) bool {
    19  	_, err := os.Stat(name)
    20  	if err == nil {
    21  		return true
    22  	}
    23  	if os.IsNotExist(err) {
    24  		return false
    25  	}
    26  	return false
    27  }
    28  
    29  type asetup_t struct {
    30  	ctx     *hwaflib.Context
    31  	cmd     *commander.Command
    32  	args    []string
    33  	opts    options
    34  	verbose bool
    35  }
    36  
    37  type options struct {
    38  	projdir   string
    39  	variant   string
    40  	toolchain map[string]string // entries for the hwaf-toolchain section
    41  	env       map[string]string // entries for the hwaf-env section
    42  }
    43  
    44  func new_options() options {
    45  	return options{
    46  		toolchain: make(map[string]string),
    47  		env:       make(map[string]string),
    48  	}
    49  }
    50  
    51  func Run(ctx *hwaflib.Context, cmd *commander.Command, args []string) error {
    52  	cfg := asetup_t{
    53  		ctx:     ctx,
    54  		cmd:     cmd,
    55  		args:    args,
    56  		opts:    new_options(),
    57  		verbose: cmd.Flag.Lookup("v").Value.Get().(bool),
    58  	}
    59  	return cfg.run()
    60  }
    61  
    62  func (a *asetup_t) run() error {
    63  	var err error
    64  
    65  	n := "hwaf-" + a.cmd.Name()
    66  
    67  	if len(a.args) == 0 {
    68  		if a.verbose {
    69  			a.ctx.Infof("re-using previously asetup'ed workarea...\n")
    70  		}
    71  		// case where we reuse a previously already asetup'ed workarea
    72  		_, err = a.ctx.LocalCfg()
    73  		if err == nil {
    74  			if a.verbose {
    75  				a.ctx.Infof("re-using previously asetup'ed workarea... [done]\n")
    76  			}
    77  			return nil
    78  		}
    79  		err = fmt.Errorf("%v\n'hwaf asetup' called with no argument in a pristine workarea is NOT valid.", err)
    80  		if err != nil {
    81  			return err
    82  		}
    83  	}
    84  
    85  	args := make([]string, 0, len(a.args))
    86  	for _, arg := range a.args {
    87  		subarg := strings.Split(arg, ",")
    88  		for _, sarg := range subarg {
    89  			if sarg != "" {
    90  				args = append(args, sarg)
    91  			}
    92  		}
    93  	}
    94  
    95  	dirname, err := os.Getwd()
    96  	if err != nil {
    97  		return err
    98  	}
    99  
   100  	dirname, err = filepath.Abs(dirname)
   101  	if err != nil {
   102  		return err
   103  	}
   104  
   105  	// make sure 'hwaf init' was run at least once in this directory...
   106  	for _, dir := range []string{
   107  		filepath.Join(dirname, ".hwaf", "bin"),
   108  		filepath.Join(dirname, ".hwaf", "tools"),
   109  	} {
   110  		err = os.RemoveAll(dir)
   111  		if err != nil {
   112  			return err
   113  		}
   114  	}
   115  	{
   116  		sub := exec.Command("hwaf", "init", fmt.Sprintf("-v=%v", a.verbose), dirname)
   117  		sub.Stdin = os.Stdin
   118  		sub.Stdout = os.Stdout
   119  		sub.Stderr = os.Stderr
   120  		err = sub.Run()
   121  		if err != nil {
   122  			return err
   123  		}
   124  	}
   125  
   126  	err = a.process(args)
   127  	if err != nil {
   128  		return err
   129  	}
   130  
   131  	if a.verbose {
   132  		fmt.Printf("%s: asetup workarea [%s]...\n", n, dirname)
   133  		fmt.Printf("%s: projects=%v\n", n, a.opts.projdir)
   134  		// if cfg_fname != "" {
   135  		// 	fmt.Printf("%s: cfg-file=%s\n", n, cfg_fname)
   136  		// }
   137  	}
   138  
   139  	subcmd := exec.Command(
   140  		"hwaf", "setup",
   141  		fmt.Sprintf("-v=%v", a.verbose),
   142  		"-p", a.opts.projdir,
   143  	)
   144  	subcmd.Stdin = os.Stdin
   145  	subcmd.Stdout = os.Stdout
   146  	subcmd.Stderr = os.Stderr
   147  	err = subcmd.Run()
   148  	if err != nil {
   149  		return err
   150  	}
   151  
   152  	lcfg_fname := "local.conf"
   153  	if !path_exists(lcfg_fname) {
   154  		err = fmt.Errorf("%s: no such file [%s]", n, lcfg_fname)
   155  		if err != nil {
   156  			return err
   157  		}
   158  	}
   159  
   160  	lcfg, err := gocfg.ReadDefault(lcfg_fname)
   161  	if err != nil {
   162  		return err
   163  	}
   164  
   165  	err = a.handle_toolchain_section(lcfg, lcfg_fname)
   166  	if err != nil {
   167  		return err
   168  	}
   169  
   170  	err = a.handle_env_section(lcfg, lcfg_fname, dirname)
   171  	if err != nil {
   172  		return err
   173  	}
   174  
   175  	err = lcfg.WriteFile(lcfg_fname, 0600, "")
   176  	if err != nil {
   177  		return err
   178  	}
   179  
   180  	if a.verbose {
   181  		fmt.Printf("%s: asetup workarea [%s]... [ok]\n", n, dirname)
   182  	}
   183  	return err
   184  }
   185  
   186  func infer_version(arg, projname string, version *string) bool {
   187  	ok := false
   188  	proj_table := map[string]string{
   189  		"mana": "",
   190  		"lcg":  "LCG_",
   191  		"tdaq": "tdaq-common-",
   192  	}
   193  	prefix, haskey := proj_table[projname]
   194  	if !haskey {
   195  		return false
   196  	}
   197  	for _, p := range []string{
   198  		"0", "1", "2", "3", "4", "5", "6", "7", "8", "9",
   199  	} {
   200  		if strings.HasPrefix(arg, prefix+p) {
   201  			*version = arg
   202  			return true
   203  		}
   204  	}
   205  	return ok
   206  }
   207  
   208  // FIXME: this should be more thought out... and structured!
   209  func (a *asetup_t) process(args []string) error {
   210  	var err error
   211  	opts := new_options()
   212  
   213  	pinfos, err := platform.Infos()
   214  	if err != nil {
   215  		return err
   216  	}
   217  
   218  	//cfg_fname := a.cmd.Flag.Lookup("cfg").Value.Get().(string)
   219  	cli_variant := a.cmd.Flag.Lookup("variant").Value.Get().(string)
   220  	cli_arch := a.cmd.Flag.Lookup("arch").Value.Get().(string)
   221  	cli_comp := a.cmd.Flag.Lookup("comp").Value.Get().(string)
   222  	cli_os := a.cmd.Flag.Lookup("os").Value.Get().(string)
   223  	cli_type := a.cmd.Flag.Lookup("type").Value.Get().(string)
   224  
   225  	unprocessed := make([]string, 0, len(args))
   226  	projname := "mana-core"
   227  	version := ""
   228  	hwaf_os := pinfos.DistId()
   229  	// fold slX into slcX (ie: all Scientific Linuces are SLCs)
   230  	if pinfos.DistName == "sl" {
   231  		rel := strings.Split(pinfos.DistVers, ".")
   232  		major := rel[0]
   233  		hwaf_os = "slc" + major
   234  	}
   235  	hwaf_comp := "gcc"
   236  	hwaf_arch := ""
   237  	switch runtime.GOARCH {
   238  	case "amd64":
   239  		hwaf_arch = "x86_64"
   240  	case "386":
   241  		hwaf_arch = "i686"
   242  	default:
   243  		//hwaf_arch = "unknown"
   244  		panic(fmt.Sprintf("unknown architecture [%s]", hwaf_arch))
   245  	}
   246  	hwaf_bld := "opt"
   247  	for _, arg := range args {
   248  		has_prefix := func(prefix ...string) bool {
   249  			for _, p := range prefix {
   250  				ok := strings.HasPrefix(arg, p)
   251  				if ok {
   252  					return ok
   253  				}
   254  			}
   255  			return false
   256  		}
   257  		switch arg {
   258  		case "32b":
   259  			hwaf_arch = "i686"
   260  		case "64b":
   261  			hwaf_arch = "x86_64"
   262  		case "opt":
   263  			hwaf_bld = "opt"
   264  		case "dbg":
   265  			hwaf_bld = "dbg"
   266  		case "mana", "mana-core":
   267  			projname = "mana-core"
   268  		case "mana-ext", "lcg":
   269  			projname = arg
   270  		case "tdaq", "tdaq-common":
   271  			projname = "tdaq-common"
   272  		default:
   273  			if has_prefix(
   274  				"2012", "2013",
   275  				"0", "1", "2", "3", "4", "5", "6", "7", "8", "9",
   276  			) {
   277  				version = arg
   278  			} else if has_prefix("gcc") || has_prefix("clang") {
   279  				hwaf_comp = arg
   280  			} else if infer_version(arg, projname, &version) {
   281  				//version = version
   282  			} else {
   283  				unprocessed = append(unprocessed, arg)
   284  			}
   285  		}
   286  	}
   287  	if len(unprocessed) > 0 {
   288  		err = fmt.Errorf("unprocessed asetup options: %v", unprocessed)
   289  	}
   290  
   291  	// honour CLI args
   292  	for _, v := range [][]*string{
   293  		{&cli_arch, &hwaf_arch},
   294  		{&cli_os, &hwaf_os},
   295  		{&cli_comp, &hwaf_comp},
   296  		{&cli_type, &hwaf_bld},
   297  	} {
   298  		if *v[0] != "" {
   299  			*v[1] = *v[0]
   300  		}
   301  	}
   302  
   303  	sitedir := a.ctx.Sitedir()
   304  	if sitedir == "" {
   305  		sitedir = filepath.Join("", "opt", "sw", "atlas")
   306  		a.ctx.Warnf("no $HWAF_SITEDIR env. variable. will use [%s]\n", sitedir)
   307  	}
   308  
   309  	if a.verbose {
   310  		a.ctx.Infof("using sitedir: [%s]\n", sitedir)
   311  	}
   312  
   313  	if !path_exists(sitedir) {
   314  		err = fmt.Errorf("no such directory [%s]", sitedir)
   315  		return err
   316  	}
   317  
   318  	usr_variant := fmt.Sprintf("%s-%s-%s-%s", hwaf_arch, hwaf_os, hwaf_comp, hwaf_bld)
   319  	proj_root := filepath.Join(sitedir, projname)
   320  	if !path_exists(proj_root) {
   321  		err = fmt.Errorf("no such directory [%s]", proj_root)
   322  		return err
   323  	}
   324  
   325  	if a.verbose {
   326  		a.ctx.Infof("using project root [%s]\n", proj_root)
   327  	}
   328  
   329  	if version == "" {
   330  		// get the latest one.
   331  		var versions []string
   332  		versions, err = filepath.Glob(filepath.Join(proj_root, "*"))
   333  		if err != nil {
   334  			return err
   335  		}
   336  		sort.Strings(versions)
   337  		version = versions[len(versions)-1]
   338  		version, _ = filepath.Abs(version)
   339  		version = filepath.Base(version)
   340  	}
   341  	opts.projdir = filepath.Join(proj_root, version)
   342  	if !path_exists(opts.projdir) {
   343  		err = fmt.Errorf("no such directory [%s]", opts.projdir)
   344  		return err
   345  	}
   346  
   347  	if a.verbose {
   348  		a.ctx.Infof("using project dir [%s]\n", opts.projdir)
   349  	}
   350  
   351  	// dft_variant is a variation on DefaultVariant.
   352  	dft_variant := fmt.Sprintf(
   353  		"%s-%s-%s-%s",
   354  		hwaf_arch,
   355  		hwaf_os,
   356  		strings.Split(a.ctx.DefaultVariant(), "-")[2], // compiler
   357  		hwaf_bld,
   358  	)
   359  
   360  	found := false
   361  	for ii, variant := range []string{
   362  		cli_variant,
   363  		usr_variant,
   364  		a.ctx.Variant(),
   365  		a.ctx.DefaultVariant(),
   366  		dft_variant,
   367  	} {
   368  		if variant == "" {
   369  			continue
   370  		}
   371  		dir := filepath.Join(opts.projdir, variant)
   372  		if a.verbose {
   373  			fmt.Printf("---> (%03d) [%s]... ", ii, dir)
   374  		}
   375  		if !path_exists(dir) {
   376  			if a.verbose {
   377  				fmt.Printf("[err]\n")
   378  			}
   379  			continue
   380  		}
   381  		opts.projdir = dir
   382  		opts.variant = variant
   383  		if a.verbose {
   384  			fmt.Printf("[ok]\n")
   385  		}
   386  		found = true
   387  		break
   388  	}
   389  	if !found {
   390  		return fmt.Errorf("hwaf: could not find a suitable project")
   391  	}
   392  	a.opts = opts
   393  	return err
   394  }
   395  
   396  func (a *asetup_t) handle_toolchain_section(lcfg *gocfg.Config, lcfg_fname string) error {
   397  	var err error
   398  	n := "hwaf-" + a.cmd.Name()
   399  
   400  	section := "hwaf-toolchain"
   401  	if !lcfg.HasSection(section) {
   402  		if !lcfg.AddSection(section) {
   403  			err = fmt.Errorf("%s: could not create section [%s] in file [%s]",
   404  				n, section, lcfg_fname)
   405  			if err != nil {
   406  				return err
   407  			}
   408  		}
   409  	}
   410  	for k, v := range a.opts.toolchain {
   411  		if lcfg.HasOption(section, k) {
   412  			lcfg.RemoveOption(section, k)
   413  		}
   414  		ok := lcfg.AddOption(section, k, v)
   415  		if !ok {
   416  			err = fmt.Errorf(
   417  				"%s: could not add option [%s=%q] to file [%s]",
   418  				n, k, v, lcfg_fname,
   419  			)
   420  			if err != nil {
   421  				return err
   422  			}
   423  		}
   424  	}
   425  	return err
   426  }
   427  
   428  func (a *asetup_t) handle_env_section(lcfg *gocfg.Config, lcfg_fname, dirname string) error {
   429  	var err error
   430  	n := "hwaf-" + a.cmd.Name()
   431  
   432  	section := "hwaf-env"
   433  	if !lcfg.HasSection(section) {
   434  		if !lcfg.AddSection(section) {
   435  			err = fmt.Errorf("%s: could not create section [%s] in file [%s]",
   436  				n, section, lcfg_fname)
   437  			if err != nil {
   438  				return err
   439  			}
   440  		}
   441  	}
   442  	// add a few asetup defaults...
   443  	for k, v := range map[string]string{
   444  		"SVNGROUPS": "svn+ssh://svn.cern.ch/reps/atlasgroups",
   445  		"SVNGRP":    "svn+ssh://svn.cern.ch/reps/atlasgrp",
   446  		"SVNINST":   "svn+ssh://svn.cern.ch/reps/atlasinst",
   447  		"SVNOFF":    "svn+ssh://svn.cern.ch/reps/atlasoff",
   448  		"SVNPERF":   "svn+ssh://svn.cern.ch/reps/atlasperf",
   449  		"SVNPHYS":   "svn+ssh://svn.cern.ch/reps/atlasphys",
   450  		"SVNROOT":   "svn+ssh://svn.cern.ch/reps/atlasoff",
   451  		"SVNUSR":    "svn+ssh://svn.cern.ch/reps/atlasusr",
   452  		"TestArea":  dirname,
   453  	} {
   454  		a.opts.env[k] = v
   455  	}
   456  
   457  	for k, v := range a.opts.env {
   458  		if lcfg.HasOption(section, k) {
   459  			lcfg.RemoveOption(section, k)
   460  		}
   461  		ok := lcfg.AddOption(section, k, v)
   462  		if !ok {
   463  			err = fmt.Errorf(
   464  				"%s: could not add option [%s=%q] to file [%s]",
   465  				n, k, v, lcfg_fname,
   466  			)
   467  			if err != nil {
   468  				return err
   469  			}
   470  		}
   471  	}
   472  
   473  	return err
   474  }
   475  
   476  // EOF