diff --git a/.gitignore b/.gitignore
index 67cdec9..f6920ad 100644
--- a/.gitignore
+++ b/.gitignore
@@ -1 +1,2 @@
rs-backup.json
+build/
\ No newline at end of file
diff --git a/Makefile b/Makefile
new file mode 100644
index 0000000..2acdf67
--- /dev/null
+++ b/Makefile
@@ -0,0 +1,32 @@
+.PHONY: all
+all: build_linux_amd64 build_darwin_amd64 build_windows_amd64 checksums
+
+.PHONY: build_linux_amd64
+build_linux_amd64:
+ GOOS=linux GOARCH=amd64 go build -v -a -gcflags=-trimpath=$$PWD -asmflags=-trimpath=$$PWD -o build/rs-backup-linux-amd64
+
+.PHONY: build_linux_i386
+build_linux_i386:
+ GOOS=linux GOARCH=386 go build -v -a -gcflags=-trimpath=$$PWD -asmflags=-trimpath=$$PWD -o build/rs-backup-linux-i386
+
+.PHONY: build_darwin_amd64
+build_darwin_amd64:
+ GOOS=darwin GOARCH=amd64 go build -v -a -gcflags=-trimpath=$$PWD -asmflags=-trimpath=$$PWD -o build/rs-backup-darwin-amd64
+
+.PHONY: build_darwin_i386
+build_darwin_i386:
+ GOOS=darwin GOARCH=386 go build -v -a -gcflags=-trimpath=$$PWD -asmflags=-trimpath=$$PWD -o build/rs-backup-darwin-i386
+
+.PHONY: build_windows_amd64
+build_windows_amd64:
+ CC=/usr/local/bin/x86_64-w64-mingw32-gcc GOOS=windows GOARCH=amd64 go build -v -a -gcflags=-trimpath=$$PWD -asmflags=-trimpath=$$PWD -o build/rs-backup-windows-amd64.exe
+
+.PHONY: build_windows_i386
+build_windows_i386:
+ CC=/usr/local/bin/x86_64-w64-mingw32-gcc GOOS=windows GOARCH=386 go build -v -a -gcflags=-trimpath=$$PWD -asmflags=-trimpath=$$PWD -o build/rs-backup-windows-i386.exe
+
+.PHONY: checksums
+checksums:
+ shasum -a 256 build/* > build/checksum.txt
+
+test:
diff --git a/README.md b/README.md
index 0ffa871..3aa0666 100644
--- a/README.md
+++ b/README.md
@@ -1,3 +1,11 @@
## rs-backup
-A simple wrapper around rsync written in Go with mail sending possibilities.
\ No newline at end of file
+A simple wrapper around rsync written in Go with mail sending possibilities.
+
+The config is minimalistic, set the flags to true which you would like to be included in the command.
+
+If you set `log` to true, the app will create a temporary file in the system tmp folder and will log the rsync output to that file and will attach this in the email sent at the end.
+
+If the process is complete, there will be an email sent to the specified to adresses in the config. (accepts multiple adresses i.e. array of strings).
+
+If there are any questions or bugs, please feel free to open an issue.
\ No newline at end of file
diff --git a/helpers/file.go b/helpers/file.go
new file mode 100644
index 0000000..a4d0595
--- /dev/null
+++ b/helpers/file.go
@@ -0,0 +1,15 @@
+package helpers
+
+import (
+ "fmt"
+ "io/ioutil"
+)
+
+func ReadFileContent(fileName string) []byte {
+ b, err := ioutil.ReadFile(fileName) // just pass the file name
+ if err != nil {
+ fmt.Print(err)
+ }
+
+ return b
+}
diff --git a/rs-backup.go b/rs-backup.go
index e0a1497..b0051bf 100644
--- a/rs-backup.go
+++ b/rs-backup.go
@@ -1,14 +1,26 @@
package main
import (
+ "encoding/base64"
"fmt"
+ "github.com/0x111/rs-backup/helpers"
"github.com/spf13/viper"
+ "io/ioutil"
"log"
+ "net/smtp"
+ "os"
"os/exec"
+ "strconv"
+ "strings"
+ _ "text/template"
+ "time"
)
func main() {
var err error
+ // log start time
+ start := time.Now()
+ log.Printf("Starting backup process %s", start)
// load config
viper.SetConfigName("rs-backup") // name of config file (without extension)
viper.AddConfigPath("/etc/rs-backup/") // path to look for the config file in
@@ -27,12 +39,117 @@ func main() {
log.Fatal("We could not find rsync in your path!")
}
- fmt.Println(path)
-
// cmd
+ var args []string
+ // Dynamically append arguments to the args
+ if viper.GetBool("show_progress") == true {
+ args = append(args, "--progress")
+ }
+
+ if viper.GetBool("force_ipv4") == true {
+ args = append(args, "--ipv4")
+ }
+
+ if viper.GetBool("archive") == true {
+ args = append(args, "--archive")
+ }
+
+ if viper.GetBool("verbose") == true {
+ args = append(args, "--verbose")
+ }
+
+ if viper.GetBool("compress") == true {
+ args = append(args, "--compress")
+ }
+
+ remoteShellCommand := viper.GetString("remote_shell_command")
+
+ if remoteShellCommand != "" && len(remoteShellCommand) > 0 {
+ args = append(args, "--rsh")
+ sshCmd := fmt.Sprintf("%s", remoteShellCommand)
+ args = append(args, sshCmd)
+ }
+
+ // create a temporary file
+ file, err := ioutil.TempFile("", "rs-backup")
+ logFileName := file.Name() + ".log"
+ if err != nil {
+ log.Fatal(err)
+ }
+
+ defer os.Remove(logFileName)
+
+ if viper.GetBool("log") == true {
+ args = append(args, "--log-file="+logFileName)
+ }
+
+ localDirectoryPath := viper.GetString("local_directory_path")
+
+ if localDirectoryPath != "" && len(localDirectoryPath) > 0 {
+ args = append(args, localDirectoryPath)
+ }
+
+ remoteDirectoryPath := viper.GetString("remote_directory_path")
+
+ if remoteDirectoryPath != "" && len(remoteDirectoryPath) > 0 {
+ args = append(args, remoteDirectoryPath)
+ }
- cmd := exec.Command("sleep", "5")
log.Println("Running command and waiting for it to finish...")
- err = cmd.Run()
- log.Printf("Command finished with error: %v", err)
+ _, err = exec.Command(path, args...).Output()
+
+ if err != nil {
+ //log.Fatal(fmt.Printf("Command finished with error: %v", err))
+ fmt.Println("asd")
+ }
+
+ sendTo := viper.GetStringSlice("mail.to")
+ // Content-Type: text/html; charset="UTF-8";
+ fileContent := helpers.ReadFileContent(logFileName)
+ mailBody := `From: %s
+To: %s
+Subject: Backup run at %s
+Content-Type: multipart/mixed; boundary=_rssbckkgthbscrpt14467_
+Content-Transfer-Encoding: 7bit
+--_rssbckkgthbscrpt14467_
+MIME-Version: 1.0
+Content-Type: text/html; charset="UTF-8";
+Content-Transfer-Encoding: 7bit
+
+Backup started at: %s
+Backup ended at: %s
+Backup took: %s
+Find the contents of the rsync log in the attached log file.
+
+
+Mailed by 0x111/rs-backup.
+--_rssbckkgthbscrpt14467_
+Content-Type: application/octet-stream; name="rsync.log"
+Content-Disposition: attachment; filename="rsync.log"
+Content-Transfer-Encoding: base64
+
+%s
+--_rssbckkgthbscrpt14467_
+`
+
+ // variables to make ExamplePlainAuth compile, without adding
+ // unnecessary noise there.
+ var (
+ from = viper.GetString("mail.from")
+ recipients = sendTo
+ )
+
+ end := time.Now().Format(time.RFC822)
+ mailBody = fmt.Sprintf(mailBody, from, strings.Join(sendTo, ","), start.Format(time.RFC822), start.Format(time.RFC822), end, time.Since(start), base64.StdEncoding.EncodeToString(fileContent))
+ msg := []byte(mailBody)
+
+ // hostname is used by PlainAuth to validate the TLS certificate.
+ hostname := viper.GetString("smtp.host")
+ port := strconv.Itoa(viper.GetInt("smtp.port"))
+ auth := smtp.PlainAuth("", viper.GetString("smtp.user"), viper.GetString("smtp.password"), hostname)
+
+ err = smtp.SendMail(hostname+":"+port, auth, from, recipients, msg)
+ if err != nil {
+ log.Fatal(err)
+ }
}
diff --git a/rs-backup.sample.json b/rs-backup.sample.json
new file mode 100644
index 0000000..c30163e
--- /dev/null
+++ b/rs-backup.sample.json
@@ -0,0 +1,24 @@
+{
+ "show_progress": true,
+ "force_ipv4": true,
+ "archive": true,
+ "verbose": true,
+ "compress": true,
+ "log": true,
+ "local_directory_path": "/path/to/the/directory",
+ "remote_directory_path": "remote_user@remote_host:/remote_path/to/directory",
+ "remote_shell_command": "ssh -p23",
+ "mail": {
+ "from": "from@domain.com",
+ "to": [
+ "to@email.com",
+ "to2@email.com"
+ ]
+ },
+ "smtp": {
+ "host": "mailhost.com",
+ "user": "username@domain.com",
+ "password": "password",
+ "port": 25
+ }
+}
\ No newline at end of file