Пример #1
0
func (s *Source) loadBackPANSource() error {
	log.Info("Loading BackPAN index: backpan-index")

	file, err := os.Open("backpan-index")
	if err != nil {
		log.Warn(err.Error())
		return nil
	}

	index, err := ioutil.ReadAll(file)
	file.Close()
	if err != nil {
		log.Fatal(err)
	}

	for _, p := range strings.Split(string(index), "\n") {
		if !strings.HasPrefix(p, "authors/id/") {
			continue
		}

		//log.Printf("Parsing: %s\n", p)
		m := s.ModuleFromBackPANIndex(p)
		if m != nil {
			s.ModuleList[m.Name+"-"+m.Version] = m
		}
	}

	log.Printf("Found %d packages for source: %s", len(s.ModuleList), s)
	return nil
}
func WatchConfig(configWrapper iConfigWrapper, configPath string) {
	watcherForConfigFile, err := fsnotify.NewWatcher()
	CheckError(err)

	go func() {
		for {
			select {
			case e := <-watcherForConfigFile.Event:
				if lastConfigModifiedTime.Add(1 * time.Second).After(time.Now()) {
					continue
				}
				lastConfigModifiedTime = time.Now()

				// log.Warn("Config '%s' modified, but NOT RELOADING YET.", e.Name)
				log.Warn("Config '%s' modified, now reloading (most of the) config settings.", e.Name)
				configWrapper.SetConfig(loadFile(configPath))
				configWrapper.ConfigReloaded()
				break
			case err := <-watcherForConfigFile.Error:
				log.Error("Error: %+v", err)
				break
			}
		}
	}()

	err = watcherForConfigFile.Watch(configPath)
	CheckError(err)
}
Пример #3
0
// ApplyCmds applies a map of known commands and their values.
func ApplyCmds(cmds map[string]string) {
	for cmd, val := range cmds {
		switch cmd {
		case "volume":
			v, err := strconv.ParseFloat(val, 32)
			if err != nil {
				log.Warn("Config parse error: %v", err)
				continue
			}
			SetVolume(v)
		case "brightness":
			v, err := strconv.ParseFloat(val, 32)
			if err != nil {
				log.Warn("Config parse error: %v", err)
				continue
			}
			SetBrightness(v)
		}
	}
}
Пример #4
0
func (s *Source) loadCPANSource() error {
	log.Info("Loading CPAN index: %s", s.Index)

	res, err := http.Get(s.Index)
	if err != nil {
		log.Warn("Error loading index: %s", err)
		return nil
	}

	// TODO optional gzip
	r, err := gzip.NewReader(res.Body)
	if err != nil {
		log.Warn(err.Error())
		b, _ := ioutil.ReadAll(res.Body)
		log.Info("%s", string(b))
		return nil
	}

	packages, err := ioutil.ReadAll(r)
	res.Body.Close()
	if err != nil {
		log.Warn(err)
		return nil
	}

	foundnl := false
	for _, p := range strings.Split(string(packages), "\n") {
		if !foundnl && len(p) == 0 {
			foundnl = true
			continue
		}
		if !foundnl || len(p) == 0 {
			continue
		}
		m := s.ModuleFromCPANIndex(p)
		s.ModuleList[m.Name] = m
	}

	log.Info("Found %d packages for source: %s", len(s.ModuleList), s)
	return nil
}
Пример #5
0
func Create(assetLoader func(string) ([]byte, error)) *Config {
	if assetLoader == nil {
		log.Warn("No asset loader provided; content loading will fail")
		assetLoader = func(asset string) ([]byte, error) {
			log.Warn("Attempted to load asset but no asset loader provided: %s", asset)
			return nil, errors.New("Not found")
		}
	}

	config := &Config{
		Listen:      ":7050",
		AssetLoader: assetLoader,
		Cache:       make(map[string]interface{}),
		Events:      &events.Emitter{},
		LeftDelim:   "{{",
		RightDelim:  "}}",
	}

	config.env()
	config.flags()

	return config
}
Пример #6
0
func (ws *Workspace) ExecFunction(task *Task, name string, args ...string) string {
	log.Info("Executing function %s: %s", name, args)
	var fn *Function
	if f, ok := ws.Functions[name]; ok {
		fn = f
	} else if f, ok := GlobalWorkspace.Functions[name]; ok {
		fn = f
	} else {
		log.Warn("Function not found: %s", name)
		return ""
	}

	argmap := make(map[string]string)
	for i, arg := range fn.Args {
		argmap[arg] = args[i]
	}

	for k, v := range argmap {
		log.Info("argmap: %s => %s", k, v)
		for t, m := range task.Metadata {
			log.Info("meta: %s => %s", t, m)
			v = strings.Replace(v, "$"+t, m, -1)
		}
		argmap[k] = v
	}

	c := fn.Command
	for k, v := range argmap {
		log.Info("ARG: %s => %s", k, v)
		c = strings.Replace(c, k, v, -1)
	}

	var funcEnvironment map[string]string
	if ws.InheritEnvironment {
		funcEnvironment = ws.Environment
	} else if GlobalWorkspace.InheritEnvironment {
		funcEnvironment = GlobalWorkspace.Environment
	} else {
		funcEnvironment = make(map[string]string)
	}

	tsk := NewTask(nil, "Function$"+name, fn.Executor, c, funcEnvironment, false, "", "", make(map[string]string), "")
	ch := tsk.Start()
	<-ch
	return tsk.TaskRuns[0].StdoutBuf.String()
}
Пример #7
0
func (s *Source) Find(d *Dependency) (*Module, error) {
	log.Debug("Finding dependency: %s", d)

	switch s.Type {
	case "SmartPAN":
		log.Debug("=> Using SmartPAN source")

		url := s.URL
		if !strings.HasSuffix(s.URL, "/") {
			url += "/"
		}
		url += "where/" + d.Name + "/" + d.Modifier + d.Version

		log.Info("Query: %s", url)
		res, err := http.Get(url)

		if err != nil {
			log.Error("Error querying SmartPAN: %s", err.Error())
			return nil, err
		}

		defer res.Body.Close()

		body, err := ioutil.ReadAll(res.Body)
		log.Trace("Got response: %s", string(body))

		if res.StatusCode != http.StatusOK {
			log.Info("Module not found in SmartPAN: %s", d.Name)
			return nil, nil
		}

		var v *WhereOutput
		if err = json.Unmarshal(body, &v); err != nil {
			log.Error("Error parsing JSON: %s", err.Error())
			return nil, err
		}

		log.Trace("Found module %s", v.Module)

		if len(v.Versions) == 0 {
			log.Info("Found module but no versions returned")
			return nil, nil
		}

		var lv *VersionOutput
		for _, ver := range v.Versions {
			if ver.Version == v.Latest {
				log.Info("Using latest version of %s: %f", v.Module, ver.Version)
				lv = ver
				break
			}
		}
		if lv == nil {
			log.Info("Couldn't find latest version, selecting first available")
			lv = v.Versions[0]
		}

		return &Module{
			Name:    d.Name,
			Version: fmt.Sprintf("%f", lv.Version),
			Source:  s,
			Url:     lv.URL,
		}, nil
	case "CPAN":
		log.Debug("=> Using CPAN source")
		if mod, ok := s.ModuleList[d.Name]; ok {
			log.Trace("=> Found in source: %s", mod)
			if d.Matches(mod) {
				log.Trace("=> Version (%s) matches dependency: %s", mod.Version, d)
				return mod, nil
			}
			log.Trace("=> Version (%s) doesn't match dependency: %s", mod.Version, d)
			return nil, nil
		}
	case "BackPAN":
		log.Debug("=> Using BackPAN source")
		// TODO better version matching - new backpan index?
		if mod, ok := s.ModuleList[d.Name+"-"+d.Version]; ok {
			log.Trace("=> Found in source: %s", mod)
			if d.Matches(mod) {
				log.Trace("=> Version (%s) matches dependency: %s", mod.Version, d)
				return mod, nil
			}
			log.Trace("=> Version (%s) doesn't match dependency: %s", mod.Version, d)
			return nil, nil
		}
	case "MetaCPAN":
		log.Debug("=> Using MetaCPAN source")

		var sout, serr bytes.Buffer
		var cpanm_args string = fmt.Sprintf("-L %s --info %s~\"%s%s\"", config.InstallDir, d.Name, d.Modifier, d.Version)

		cpanm_cache_dir, err := filepath.Abs(config.CacheDir)
		if err != nil {
			log.Error("Failed to get absolute path of gopan cache directory: %s", err)
			return nil, err
		}

		log.Trace("About to exec: cpanm %s", cpanm_args)
		os.Setenv("CPANM_INFO_ARGS", cpanm_args)
		os.Setenv("PERL_CPANM_HOME", cpanm_cache_dir)
		cmd := exec.Command("bash", "-c", `eval cpanm $CPANM_INFO_ARGS`)
		cmd.Stdout = &sout
		cmd.Stderr = &serr

		if err := cmd.Run(); err != nil {
			log.Error("cpanm %s: %s,\n%s\n", cpanm_args, err, serr.String())
			return nil, nil
		}

		if 0 == len(sout.String()) {
			log.Warn("No author/module from cpanm")
			return nil, nil
		}

		author_module := strings.TrimRight(sout.String(), "\n")
		mematches := metacpanRe.FindStringSubmatch(author_module)
		if nil == mematches {
			log.Error("Match failed for: %s", author_module)
			return nil, nil
		}

		log.Trace("Resolved: %s", author_module)
		for _, mesource := range config.MetaSources {

			meurl := fmt.Sprintf("authors/id/%s/%s/%s",
				mematches[1][0:1],
				mematches[1][0:2],
				mematches[0])

			archive_url := fmt.Sprintf("%s/%s", mesource.URL, meurl)

			log.Trace("Checking: " + archive_url)
			resp, err := http.Head(archive_url)
			if err != nil {
				log.Trace(err)
				continue
			}

			log.Trace("HEAD status code: %d", resp.StatusCode)
			if 200 == resp.StatusCode {
				// No module/version check since 'cpanm --info' may resolve to
				// archive and version that may not match source
				return &Module{
					Name:    mematches[2],
					Version: mematches[3],
					Source:  mesource,
					Url:     meurl,
				}, nil
			}

		}
		log.Error("Could not get archive URL via 'cpanm %s'", cpanm_args)
		return nil, nil
	default:
		log.Error("Unrecognised source type: %s", s.Type)
		return nil, errors.New(fmt.Sprintf("Unrecognised source: %s", s))
	}
	log.Trace("=> Not found in source")
	return nil, nil
}
Пример #8
0
func main() {
	log.Logger().SetAppender(NewAppender())

	global := "websysd.json"
	flag.StringVar(&global, "global", global, "global environment configuration")

	workspaces := make([]string, 0)
	flag.Var((*AppendSliceValue)(&workspaces), "workspace", "websysd workspace file (can be specified multiple times), defaults to './workspace.json'")

	// Create our Gotcha application
	var app = gotcha.Create(Asset)

	if len(workspaces) == 0 {
		workspaces = append(workspaces, "./workspace.json")
	}

	LoadConfig(global, workspaces)

	GlobalWorkspace = NewWorkspace(GlobalConfigWorkspace.Name, GlobalConfigWorkspace.Environment, make(map[string]map[string][]string), GlobalConfigWorkspace.InheritEnvironment)
	for fn, args := range GlobalConfigWorkspace.Functions {
		log.Info("=> Creating global function: %s", fn)
		GlobalWorkspace.Functions[fn] = &Function{
			Name:     fn,
			Args:     args.Args,
			Command:  args.Command,
			Executor: args.Executor,
		}
	}

	if GlobalWorkspace.InheritEnvironment {
		log.Info("=> Inheriting process environment into global workspace")
		for _, k := range os.Environ() {
			p := strings.SplitN(k, "=", 2)
			if strings.TrimSpace(p[0]) == "" {
				log.Warn("Skipping empty environment key")
				continue
			}
			log.Info("  %s = %s", p[0], p[1])
			// TODO variable subst for current env vars
			if _, ok := GlobalWorkspace.Environment[p[0]]; !ok {
				GlobalWorkspace.Environment[p[0]] = p[1]
			}
		}
	}

	for _, ws := range ConfigWorkspaces {
		log.Info("=> Creating workspace: %s", ws.Name)

		var workspace *Workspace
		if wks, ok := Workspaces[ws.Name]; ok {
			log.Warn("Workspace %s already exists, merging tasks and environment")
			workspace = wks
		} else {
			workspace = NewWorkspace(ws.Name, ws.Environment, ws.Columns, ws.InheritEnvironment)
			Workspaces[ws.Name] = workspace
		}

		workspace.IsLocked = ws.IsLocked

		if workspace.InheritEnvironment && !GlobalWorkspace.InheritEnvironment {
			log.Info("=> Inheriting process environment into workspace")
			for _, k := range os.Environ() {
				p := strings.SplitN(k, "=", 2)
				if strings.TrimSpace(p[0]) == "" {
					log.Warn("Skipping empty environment key")
					continue
				}
				log.Info("  %s = %s", p[0], p[1])
				// TODO variable subst for current env vars
				if _, ok := workspace.Environment[p[0]]; !ok {
					workspace.Environment[p[0]] = p[1]
				}
			}
		}

		for fn, args := range ws.Functions {
			log.Info("=> Creating workspace function: %s", fn)
			workspace.Functions[fn] = &Function{
				Name:     fn,
				Args:     args.Args,
				Command:  args.Command,
				Executor: args.Executor,
			}
		}

		for _, t := range ws.Tasks {
			log.Info("=> Creating task: %s", t.Name)

			if _, ok := workspace.Tasks[t.Name]; ok {
				log.Warn("Task %s already exists, overwriting")
			}

			env := make(map[string]string)
			for k, v := range GlobalWorkspace.Environment {
				env[k] = v
			}
			for k, v := range ws.Environment {
				env[k] = v
			}
			for k, v := range t.Environment {
				env[k] = v
			}

			task := NewTask(workspace, t.Name, t.Executor, t.Command, env, t.Service, t.Stdout, t.Stderr, t.Metadata, t.Pwd)
			workspace.Tasks[t.Name] = task
		}
	}

	// Get the router
	r := app.Router

	// Create some routes
	r.Get("/", list_workspaces)
	r.Get("/favicon.ico", r.Static("assets/favicon.ico"))
	r.Get("/log", show_log)
	r.Get("/workspace/(?P<workspace>[^/]+)", list_tasks)

	// Serve static content (but really use a CDN)
	r.Get("/images/(?P<file>.*)", r.Static("assets/images/{{file}}"))
	r.Get("/css/(?P<file>.*)", r.Static("assets/css/{{file}}"))

	r.Post("/workspace/(?P<workspace>[^/]+)/task/(?P<task>[^/]+)/start", startTask)
	r.Post("/workspace/(?P<workspace>[^/]+)/task/(?P<task>[^/]+)/stop", stopTask)
	r.Post("/workspace/(?P<workspace>[^/]+)/task/(?P<task>[^/]+)/enable", enableServiceTask)
	r.Post("/workspace/(?P<workspace>[^/]+)/task/(?P<task>[^/]+)/disable", disableServiceTask)
	r.Get("/workspace/(?P<workspace>[^/]+)/task/(?P<task>[^/]+)", taskHistory)

	r.Get("/workspace/(?P<workspace>[^/]+)/task/(?P<task>[^/]+)/run/(?P<run>\\d+)", taskRun)
	r.Get("/workspace/(?P<workspace>[^/]+)/task/(?P<task>[^/]+)/run/(?P<run>\\d+)/stdout", taskRunStdout)
	r.Get("/workspace/(?P<workspace>[^/]+)/task/(?P<task>[^/]+)/run/(?P<run>\\d+)/stderr", taskRunStderr)

	// Start our application
	app.Start()

	defer func() {
		for _, ws := range Workspaces {
			for _, t := range ws.Tasks {
				if t.ActiveTask != nil && t.ActiveTask.Cmd != nil && t.ActiveTask.Cmd.Process != nil {
					t.ActiveTask.Cmd.Process.Kill()
				}
			}
		}
	}()

	<-make(chan int)
}
Пример #9
0
func main() {
	configure()

	log.Logger().SetLevel(log.Stol(config.LogLevel))
	log.Info("Using log level: %s", config.LogLevel)

	indexes = make(map[string]map[string]*gopan.Source)
	if !config.NoCache {
		indexes[config.Index] = gopan.LoadIndex(config.CacheDir + "/" + config.Index)
	}

	if config.NoCache || config.Update {
		for _, s := range config.Sources {
			b := strings.SplitN(s, "=", 2)
			if len(b) < 2 {
				log.Error("Expected Name=URL pair, got: %s", s)
				return
			}

			if idx, ok := indexes[config.Index][b[0]]; ok {
				log.Warn("Index [%s] already exists with URL [%s], updating to [%s]", idx.URL, b[1])
				idx.URL = b[1]
			} else {
				indexes[config.Index][b[0]] = &gopan.Source{
					Name:    b[0],
					URL:     b[1],
					Authors: make(map[string]*gopan.Author, 0),
				}
			}
		}

		if len(config.Sources) == 0 && !config.CPAN && !config.BackPAN {
			log.Debug("No -source, -cpan, -backpan parameters, adding default CPAN/BackPAN")
			config.CPAN = true
			config.BackPAN = true
		}

		if config.CPAN {
			if _, ok := indexes[config.Index]["CPAN"]; !ok {
				log.Debug("Adding CPAN index")
				indexes[config.Index]["CPAN"] = gopan.CPANSource()
			} else {
				log.Debug("CPAN index already exists")
			}
		}

		if config.BackPAN {
			if _, ok := indexes[config.Index]["BackPAN"]; !ok {
				log.Debug("Adding BackPAN index")
				indexes[config.Index]["BackPAN"] = gopan.BackPANSource()
			} else {
				log.Debug("BackPAN index already exists")
			}
		}

		log.Info("Using sources:")
		for fname, _ := range indexes {
			log.Info("From %s", fname)
			for _, source := range indexes[fname] {
				log.Info("=> %s", source.String())
			}
		}

		newAuthors := getAuthors()
		newPackages := getPackages()

		os.MkdirAll(config.CacheDir, 0777)

		if !config.NoCache {
			gopan.SaveIndex(config.CacheDir+"/"+config.Index, indexes[config.Index])
		}

		if config.Update {
			log.Info("Found %d new packages by %d new authors", newAuthors, newPackages)
		}
	}

	nsrc, nauth, nmod, npkg := gopan.CountIndex(indexes)
	log.Info("Found %d packages in %d modules by %d authors from %d sources", npkg, nmod, nauth, nsrc)

	if !config.NoMirror {
		mirrorPan()
	}
}
Пример #10
0
func (r *Response) EventStream() chan []byte {
	c := make(chan []byte)

	r.IsEventStream = true
	r.Headers.Add("Content-Type", "text/event-stream")
	r.Headers.Add("Cache-Control", "no-cache")
	r.Headers.Add("Connection", "keep-alive")
	//r.Write([]byte("\n\n"))
	r.Send()

	hj, ok := r.writer.(nethttp.Hijacker)
	if !ok {
		log.Warn("Connection unsuitable for hijack")
		return nil
	}
	conn, bufrw, err := hj.Hijack()
	if err != nil {
		log.Warn("Connection hijack failed")
		return nil
	}

	r.esBufrw = bufrw
	r.esConn = conn

	go func() {
		for b := range c {
			if len(b) == 0 {
				log.Trace("Event stream ended")
				r.esConn.Close()
				break
			}

			lines := strings.Split(string(b), "\n")
			data := ""
			for _, l := range lines {
				data += "data: " + l + "\n"
			}
			data += "\n"

			sz := len(data) + 1
			log.Info("Event stream message is %d bytes", sz)
			size := fmt.Sprintf("%X", sz)
			r.esBufrw.Write([]byte(size + "\r\n"))

			lines = strings.Split(data, "\n")
			for _, ln := range lines {
				r.esBufrw.Write([]byte(ln + "\n"))
			}
			_, err := r.esBufrw.Write([]byte("\r\n"))

			if err != nil {
				log.Error("Error writing to connection: %s\n", err)
				r.esConn.Close()
				break
			}

			err = r.esBufrw.Flush()
			if err != nil {
				log.Error("Error flushing buffer: %s\n", err)
				r.esConn.Close()
				break
			}
		}
	}()
	return c
}