diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..14322a4 --- /dev/null +++ b/.gitignore @@ -0,0 +1,95 @@ +# Created by .ignore support plugin (hsz.mobi) +### Go template +# Binaries for programs and plugins +*.exe +*.dll +*.so +*.dylib + +# Test binary, build with `go test -c` +*.test + +# Output of the go coverage tool, specifically when used with LiteIDE +*.out + +# Project-local glide cache, RE: https://github.com/Masterminds/glide/issues/736 +.glide/ +### Linux template +*~ + +# temporary files which can be created if a process still has a handle open of a deleted file +.fuse_hidden* + +# KDE directory preferences +.directory + +# Linux trash folder which might appear on any partition or disk +.Trash-* + +# .nfs files are created when an open file is removed but is still being accessed +.nfs* +### Windows template +# Windows thumbnail cache files +Thumbs.db +ehthumbs.db +ehthumbs_vista.db + +# Folder config file +Desktop.ini + +# Recycle Bin used on file shares +$RECYCLE.BIN/ + +# Windows Installer files +*.cab +*.msi +*.msm +*.msp + +# Windows shortcuts +*.lnk +### JetBrains template +# Covers JetBrains IDEs: IntelliJ, RubyMine, PhpStorm, AppCode, PyCharm, CLion, Android Studio and Webstorm +# Reference: https://intellij-support.jetbrains.com/hc/en-us/articles/206544839 + +# User-specific stuff: +.idea/**/workspace.xml +.idea/**/tasks.xml +.idea/dictionaries + +# Sensitive or high-churn files: +.idea/**/dataSources/ +.idea/**/dataSources.ids +.idea/**/dataSources.xml +.idea/**/dataSources.local.xml +.idea/**/sqlDataSources.xml +.idea/**/dynamic.xml +.idea/**/uiDesigner.xml + +# Gradle: +.idea/**/gradle.xml +.idea/**/libraries + +# Mongo Explorer plugin: +.idea/**/mongoSettings.xml + +## File-based project format: +*.iws + +## Plugin-specific files: + +# IntelliJ +/out/ + +# mpeltonen/sbt-idea plugin +.idea_modules/ + +# JIRA plugin +atlassian-ide-plugin.xml + +# Crashlytics plugin (for Android Studio and IntelliJ) +com_crashlytics_export_strings.xml +crashlytics.properties +crashlytics-build.properties +fabric.properties + diff --git a/example.yaml b/example.yaml new file mode 100644 index 0000000..804c37f --- /dev/null +++ b/example.yaml @@ -0,0 +1,8 @@ +scripts: + - name: "backup" + recurrence: "hourly" + commands: + - "borgocli run create /backup/config/borgocli.yaml" + - "borgocli run prune /backup/config/borgocli.yaml" + - "borgocli run check /backup/config/borgocli.yaml" + - name: "someOther" \ No newline at end of file diff --git a/main.go b/main.go new file mode 100644 index 0000000..871863c --- /dev/null +++ b/main.go @@ -0,0 +1,81 @@ +package main + +import ( + "os" + "gopkg.in/yaml.v2" + "io/ioutil" + "regexp" + "errors" +) + +type Config struct { + Scripts []Scripts +} + +type Scripts struct { + Name string + Recurrence string + Commands []string +} + +func main() { + var config Config + err := yaml.Unmarshal(readFile(os.Args[1]), &config) + check(err) + timeFolders := []string{"15min", "hourly", "daily", "weekly", "monthly"} + + //Check whether recurrence entries are valid + for i := 0; i < len(config.Scripts); i++ { + match, err := regexp.MatchString("15min|hourly|daily|weekly|monthly", config.Scripts[i].Recurrence) + check(err) + if !match { + panic(errors.New("Invalid recurrence.")) + } + } + //Remove old scripts + for j := 0; j < len(config.Scripts); j++ { + for i := 0; i < len(timeFolders); i++ { + path := "/etc/periodic/" + timeFolders[i] + "/" + config.Scripts[j].Name + if existsFile(path) { + os.Remove(path) + } + } + } + + for i := 0; i < len(config.Scripts); i++ { + fileContent := "#!/bin/sh\n" + for j := 0; j < len(config.Scripts[i].Commands); j++ { + fileContent += config.Scripts[i].Commands[j] + "\n" + } + path := "/etc/periodic/" + config.Scripts[i].Recurrence + "/" + config.Scripts[i].Name + file, err := os.Create(path) + check(err) + file.WriteString(fileContent) + file.Sync() + os.Chmod(file.Name(), 0755) + } + +} + +func existsFile(path string) (bool, error) { + _, err := os.Stat(path) + if err == nil { + return true, nil + } + if os.IsNotExist(err) { + return false, nil + } + return true, err +} + +func readFile(path string) []byte { + data, err := ioutil.ReadFile(path) + check(err) + return data +} + +func check(e error) { + if e != nil { + panic(e) + } +}