Skip to content

Commit efdff96

Browse files
snowblock.Snowblock API implementation
Implemented the `pkg/api/snowblock.Snowblock` interface (designed in GH-70) that represents a snowblock. It stores task data and metadata of a snowblock, validates it and dispatches the tasks to a registered `TaskRunner` (designed in GH-70) if one matches the task name, otherwise skips the unknown task. Epic GH-33 Resolves GH-72
1 parent f68ec43 commit efdff96

File tree

1 file changed

+140
-0
lines changed

1 file changed

+140
-0
lines changed

pkg/snowblock/snowblock.go

Lines changed: 140 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,140 @@
1+
// Copyright (C) 2017-present Arctic Ice Studio <[email protected]>
2+
// Copyright (C) 2017-present Sven Greb <[email protected]>
3+
//
4+
// Project: snowsaw
5+
// Repository: https://github.com/arcticicestudio/snowsaw
6+
// License: MIT
7+
8+
// Author: Arctic Ice Studio <[email protected]>
9+
// Author: Sven Greb <[email protected]>
10+
// Since: 0.4.0
11+
12+
// Package snowblock provides the implementation of the snowblock API.
13+
package snowblock
14+
15+
import (
16+
"fmt"
17+
"io/ioutil"
18+
"path/filepath"
19+
20+
"github.com/fatih/color"
21+
22+
api "github.com/arcticicestudio/snowsaw/pkg/api/snowblock"
23+
"github.com/arcticicestudio/snowsaw/pkg/config/encoder"
24+
"github.com/arcticicestudio/snowsaw/pkg/config/encoder/json"
25+
"github.com/arcticicestudio/snowsaw/pkg/config/source/file"
26+
"github.com/arcticicestudio/snowsaw/pkg/prt"
27+
"github.com/arcticicestudio/snowsaw/pkg/util/filesystem"
28+
)
29+
30+
// Configuration i
31+
type Configuration []map[string]interface{}
32+
33+
// Snowblock represents the state and actions of a snowblock.
34+
// It implements the snowblock API interface.
35+
type Snowblock struct {
36+
// IsValid indicates if this snowblock is valid.
37+
IsValid bool
38+
39+
// Path is the path of this snowblock.
40+
Path string
41+
42+
// TaskObjects is a list of task objects this snowblock configuration consists of.
43+
TaskObjects []api.Task
44+
45+
// TaskRunnerMapping contains the assignments from task objects to a matching task runner.
46+
TaskRunnerMapping map[api.TaskRunner]api.TaskConfiguration
47+
48+
// UnsupportedTasks is a list of task names that are not supported by an registered task runner.
49+
UnsupportedTasks []api.TaskConfiguration
50+
}
51+
52+
// NewSnowblock returns a new snowblock.
53+
func NewSnowblock(path string) *Snowblock {
54+
return &Snowblock{
55+
Path: path,
56+
TaskObjects: make([]api.Task, 0),
57+
TaskRunnerMapping: make(map[api.TaskRunner]api.TaskConfiguration),
58+
}
59+
}
60+
61+
// Dispatch handles the processing of the snowblock by dispatching the configured tasks to a registered runner that can
62+
// handle it.
63+
func (s *Snowblock) Dispatch() error {
64+
for runner, instructions := range s.TaskRunnerMapping {
65+
if err := runner.Run(instructions, s.Path); err != nil {
66+
return err
67+
}
68+
}
69+
70+
return nil
71+
}
72+
73+
// Validate ensures the snowblock and the configuration file exist.
74+
// It returns false along with an corresponding error if the snowblock path doesn't exist or is not a directory.
75+
// The snowblock is also not valid either when the given directory does not contain a configuration file or the file
76+
// is not parsable.
77+
// Defined tasks that are not supported by any of the given task runners are filtered into the separate array.
78+
func (s *Snowblock) Validate(taskRunner map[string]api.TaskRunner) error {
79+
// Expand the given snowblock path and convert it into an absolute path.
80+
expandedPath, expPathErr := filesystem.ExpandPath(s.Path)
81+
if expPathErr != nil {
82+
return fmt.Errorf("could not dissolve path: %v", expPathErr)
83+
}
84+
expandedAbsPath, expAbsPathErr := filepath.Abs(expandedPath)
85+
if expAbsPathErr != nil {
86+
return fmt.Errorf("could not convert into absolute path: %v", expAbsPathErr)
87+
}
88+
89+
// Ensure the path is a directory and exists.
90+
dirExists, dirExistsErr := filesystem.DirExists(expandedAbsPath)
91+
if dirExistsErr != nil {
92+
return dirExistsErr
93+
}
94+
if !dirExists {
95+
return fmt.Errorf("no such directory: %s", expandedAbsPath)
96+
}
97+
s.Path = expandedAbsPath
98+
99+
// Try to read and encode the task objects when the directory contains a configuration file.
100+
configFilePath := filepath.Join(s.Path, fmt.Sprintf("%s.%s", api.ConfigurationFileName, encoder.ExtensionsJson))
101+
if configLoadErr := loadConfigFile(configFilePath, &s.TaskObjects); configLoadErr != nil {
102+
prt.Debugf("Ignoring snowblock directory %s without valid configuration file: %s: %v",
103+
color.CyanString(filepath.Base(s.Path)), color.BlueString(configFilePath), configLoadErr)
104+
return nil
105+
}
106+
107+
// Assign each task object to a registered task runner when matching, otherwise add to list of unsupported tasks.
108+
for _, taskObject := range s.TaskObjects {
109+
for taskName, taskConfigMap := range taskObject {
110+
runner, exists := taskRunner[taskName]
111+
if exists {
112+
s.TaskRunnerMapping[runner] = taskConfigMap
113+
continue
114+
}
115+
s.UnsupportedTasks = append(s.UnsupportedTasks, taskName)
116+
prt.Debugf("Ignoring task without registered runner: %s", color.RedString(taskName))
117+
}
118+
}
119+
120+
s.IsValid = true
121+
return nil
122+
}
123+
124+
func loadConfigFile(absPath string, tasks *[]api.Task) error {
125+
f := file.NewFile(absPath).WithEncoder(json.NewJsonEncoder())
126+
// Check if the file exists...
127+
if exists, _ := filesystem.FileExists(f.Path); !exists {
128+
return fmt.Errorf("no such snowblock configuration file: %s", color.RedString(f.Path))
129+
}
130+
// ...and decode the file content with the given tasks using the assigned encoder.
131+
content, err := ioutil.ReadFile(f.Path)
132+
if err != nil {
133+
return err
134+
}
135+
if encErr := f.Encoder.Decode(content, tasks); encErr != nil {
136+
return fmt.Errorf("could not load snowblock configuration file: %s: %v", f.Path, encErr)
137+
}
138+
139+
return nil
140+
}

0 commit comments

Comments
 (0)