Fleshed out how projects will be loaded and run

Started on datastores
This commit is contained in:
Tim Shannon 2016-03-30 21:48:52 +00:00
parent 8475ac6049
commit cb883bc528
4 changed files with 154 additions and 5 deletions

View File

@ -1,5 +1,5 @@
MIT License MIT License
Copyright (c) <year> <copyright holders> Copyright (c) 2016 Tim Shannon
Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions: Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions:

6
datastore/ds.go Normal file
View File

@ -0,0 +1,6 @@
// Copyright 2016 Tim Shannon. All rights reserved.
// Use of this source code is governed by the MIT license
// that can be found in the LICENSE file.
// Package datastore manages the bolt data files and the reading and writing data to them
package datastore

16
main.go
View File

@ -1,3 +1,7 @@
// Copyright 2016 Tim Shannon. All rights reserved.
// Use of this source code is governed by the MIT license
// that can be found in the LICENSE file.
package main package main
import ( import (
@ -10,8 +14,8 @@ import (
//settings //settings
var ( var (
projectDir = "./projects" // /etc/ projectDir = "./projects" // /etc/ironsmith/
dataDir = "./data" dataDir = "./data" // /var/ironsmith/
address = "http://localhost:8026" address = "http://localhost:8026"
certFile = "" certFile = ""
keyFile = "" keyFile = ""
@ -37,12 +41,12 @@ func main() {
keyFile = cfg.String("keyFile", keyFile) keyFile = cfg.String("keyFile", keyFile)
//prep dirs //prep dirs
err = os.MkdirAll(filepath.Join(projectDir, enabledProjectDir), os.ModeDir) err = os.MkdirAll(filepath.Join(projectDir, enabledProjectDir), 0777)
if err != nil { if err != nil {
log.Fatalf("Error Creating project directory at %s: %s", projectDir, err) log.Fatalf("Error Creating project directory at %s: %s", projectDir, err)
} }
err = os.MkdirAll(dataDir, os.ModeDir) err = os.MkdirAll(dataDir, 0777)
if err != nil { if err != nil {
log.Fatalf("Error Creating project data directory at %s: %s", dataDir, err) log.Fatalf("Error Creating project data directory at %s: %s", dataDir, err)
} }
@ -53,5 +57,9 @@ func main() {
} }
//load projects //load projects
err = projects.load()
if err != nil {
log.Fatalf("Error loading projects: %s", err)
}
//start server //start server
} }

View File

@ -1,14 +1,31 @@
// Copyright 2016 Tim Shannon. All rights reserved.
// Use of this source code is governed by the MIT license
// that can be found in the LICENSE file.
package main package main
import ( import (
"encoding/json" "encoding/json"
"fmt"
"io/ioutil"
"os" "os"
"path/filepath" "path/filepath"
"strings"
"sync"
"time"
) )
const enabledProjectDir = "enabled" const enabledProjectDir = "enabled"
// Project is an ironsmith project that contains how to fetch, build, test, and release a project // Project is an ironsmith project that contains how to fetch, build, test, and release a project
/*
The project lifecycle goes like this, each step calling the next if successful
(Load Project file) -> (Fetch) -> (Build) -> (Test) -> (Release) - > (Sleep for polling period) ->
(Reload Project File) -> (Fetch) -> etc...
Changes the project file will be reloaded on every poll / trigger
If a project file is deleted then the cycle will finish it's current poll and stop at the load phase
*/
type Project struct { type Project struct {
Name string `json:"name"` // name of the project Name string `json:"name"` // name of the project
@ -22,6 +39,9 @@ type Project struct {
ReleaseFile string `json:"releaseFile"` ReleaseFile string `json:"releaseFile"`
PollInterval string `json:"pollInterval"` // if not poll interval is specified, this project is trigger only PollInterval string `json:"pollInterval"` // if not poll interval is specified, this project is trigger only
TriggerSecret string `json:"triggerSecret"` //secret to be included with a trigger call TriggerSecret string `json:"triggerSecret"` //secret to be included with a trigger call
filename string
poll time.Duration
} }
const projectTemplateFilename = "template.project.json" const projectTemplateFilename = "template.project.json"
@ -69,3 +89,118 @@ func prepTemplateProject() error {
return nil return nil
} }
func (p *Project) load() error {
if p.filename == "" {
return fmt.Errorf("Invalid project file name")
}
if !projects.exists(p.filename) {
// project has been deleted
// don't continue polling
// TODO: Clean up Project data folder?
return nil
}
data, err := ioutil.ReadFile(filepath.Join(projectDir, enabledProjectDir, p.filename))
if err != nil {
return err
}
err = json.Unmarshal(data, p)
if err != nil {
return err
}
err = p.prepData()
if err != nil {
return err
}
if p.PollInterval != "" {
p.poll, err = time.ParseDuration(p.PollInterval)
if err != nil {
//TODO: Log pollInterval parse failure in project store
p.poll = 0
}
}
if p.poll > 0 {
//start polling
}
return nil
}
// prepData makes sure the project's data folder and data store is created
/*
folder structure
projectDataFolder/<project-name>/<project-version>
*/
func (p *Project) prepData() error {
var dirName = strings.TrimSuffix(p.filename, filepath.Ext(p.filename))
err := os.MkdirAll(filepath.Join(dataDir, dirName), 0777)
if err != nil {
return err
}
//TODO: Create data store
}
type projectList struct {
sync.RWMutex
data map[string]*Project
}
var projects = projectList{
data: make(map[string]*Project),
}
func (p *projectList) load() error {
p.Lock()
defer p.Unlock()
dir, err := os.Open(filepath.Join(projectDir, enabledProjectDir))
defer func() {
if cerr := dir.Close(); cerr != nil && err == nil {
err = cerr
}
}()
if err != nil {
return err
}
files, err := dir.Readdir(0)
if err != nil {
return err
}
for i := range files {
if !files[i].IsDir() && filepath.Ext(files[i].Name()) == ".json" {
prj := &Project{filename: files[i].Name()}
p.data[files[i].Name()] = prj
err = prj.load()
if err != nil {
delete(p, files[i].Name())
return err
}
}
}
return nil
}
func (p *projectList) exists(name string) bool {
p.RLock()
defer p.RUnlock()
_, ok := p.data[name]
return ok
}
// startProjectLoader polls for new projects
func startProjectLoader() {
}