initialise repo
[debian/orchestra.git] / src / player / scores.go
1 // scores.go
2 //
3 // Score handling
4 //
5 // In here, we have the probing code that learns about scores, reads
6 // their configuration files, and does the heavy lifting for launching
7 // them, doing the privilege drop, etc.
8
9 package main
10
11 import (
12         "os"
13         "io"
14         "strings"
15         o "orchestra"
16         "path"
17         "github.com/kuroneko/configureit"
18 )
19
20 type ScoreInfo struct {
21         Name            string
22         Executable      string
23         InitialPwd      string
24         InitialEnv      map[string]string
25
26         Interface       string
27
28         Config          *configureit.Config
29 }
30
31 type ScoreExecution struct {
32         Score   *ScoreInfo
33         Task    *TaskRequest
34 }
35         
36
37 func NewScoreInfo() (si *ScoreInfo) {
38         si = new (ScoreInfo)
39         si.InitialEnv = make(map[string]string)
40
41         config := NewScoreInfoConfig()
42         si.updateFromConfig(config)
43
44         return si
45 }
46
47 func NewScoreInfoConfig() (config *configureit.Config) {
48         config = configureit.New()
49
50         config.Add("interface", configureit.NewStringOption("env"))
51         config.Add("dir", configureit.NewStringOption(""))
52         config.Add("path", configureit.NewStringOption("/usr/bin:/bin"))
53         config.Add("user", configureit.NewUserOption(""))
54
55         return config
56 }
57
58 func (si *ScoreInfo) updateFromConfig(config *configureit.Config) {
59         // propogate PATH overrides.
60         opt := config.Get("dir")
61         sopt, _ := opt.(*configureit.StringOption)
62         si.InitialEnv["PATH"] = sopt.Value
63
64         // set the interface type.
65         opt = config.Get("interface")
66         sopt, _ = opt.(*configureit.StringOption)
67         si.Interface = sopt.Value
68
69         // propogate initial Pwd
70         opt = config.Get("dir")
71         sopt, _ = opt.(*configureit.StringOption)
72         si.InitialPwd = sopt.Value      
73 }
74
75 var (
76         Scores          map[string]*ScoreInfo
77 )
78
79 func ScoreConfigure(si *ScoreInfo, r io.Reader) {
80         config := NewScoreInfoConfig()
81         err := config.Read(r, 1)
82         o.MightFail(err, "Error Parsing Score Configuration for %s", si.Name)
83         si.updateFromConfig(config)
84 }
85
86 func LoadScores() {
87         scoreDirectory := GetStringOpt("score directory")
88
89         dir, err := os.Open(scoreDirectory)
90         o.MightFail(err, "Couldn't open Score directory")
91         defer dir.Close()
92
93         Scores = make(map[string]*ScoreInfo)
94         
95         files, err := dir.Readdir(-1)
96         for i := range files {
97                 // skip ., .. and other dotfiles.
98                 if strings.HasPrefix(files[i].Name, ".") {
99                         continue
100                 }
101                 // emacs backup files.  ignore these.
102                 if strings.HasSuffix(files[i].Name, "~") || strings.HasPrefix(files[i].Name, "#") {
103                         continue
104                 }
105                 // .conf is reserved for score configurations.
106                 if strings.HasSuffix(files[i].Name, ".conf") {
107                         continue
108                 }
109                 if !files[i].IsRegular() && !files[i].IsSymlink() {
110                         continue
111                 }
112
113                 // check for the executionable bit
114                 if (files[i].Permission() & 0111) != 0 {
115                         fullpath := path.Join(scoreDirectory, files[i].Name)
116                         conffile := fullpath+".conf"
117                         o.Warn("Considering %s as score", files[i].Name)
118
119                         si := NewScoreInfo()
120                         si.Name = files[i].Name
121                         si.Executable = fullpath
122                 
123                         conf, err := os.Open(conffile)
124                         if err == nil {
125                                 o.Warn("Parsing configuration for %s", fullpath)
126                                 ScoreConfigure(si, conf)
127                                 conf.Close()
128                         } else {
129                                 o.Warn("Couldn't open config file for %s, assuming defaults: %s", files[i].Name, err)
130                         }
131                         Scores[files[i].Name] = si
132                 }
133         }
134 }