Version 1.0.0
This commit is contained in:
parent
4b7701ea0d
commit
815b15840c
9
CorrectPath.go
Normal file
9
CorrectPath.go
Normal file
@ -0,0 +1,9 @@
|
|||||||
|
package main
|
||||||
|
|
||||||
|
func correctPath(path string) string {
|
||||||
|
if path[len(path)-1:] == `/` || path[len(path)-1:] == `\` {
|
||||||
|
return path[:len(path)-1]
|
||||||
|
} else {
|
||||||
|
return path
|
||||||
|
}
|
||||||
|
}
|
34
Main.go
34
Main.go
@ -12,7 +12,7 @@ import (
|
|||||||
func main() {
|
func main() {
|
||||||
|
|
||||||
// Show the current version:
|
// Show the current version:
|
||||||
fmt.Println(`Sync v1.0.0`)
|
log.Println(`Sync v1.0.0`)
|
||||||
|
|
||||||
// Allow Go to use all CPUs:
|
// Allow Go to use all CPUs:
|
||||||
runtime.GOMAXPROCS(runtime.NumCPU())
|
runtime.GOMAXPROCS(runtime.NumCPU())
|
||||||
@ -26,6 +26,21 @@ func main() {
|
|||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Should I use the current working dir?
|
||||||
|
if localDir == `.` {
|
||||||
|
if currentWD, currentWDError := os.Getwd(); currentWDError != nil {
|
||||||
|
log.Println("Cannot use the current working directory as local directory: " + currentWDError.Error())
|
||||||
|
return
|
||||||
|
} else {
|
||||||
|
log.Println("I use the current working directory as local directory: " + currentWD)
|
||||||
|
localDir = currentWD
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Remove trailing separators from both directories
|
||||||
|
localDir = correctPath(localDir)
|
||||||
|
remoteDir = correctPath(remoteDir)
|
||||||
|
|
||||||
// Check if local dir exist
|
// Check if local dir exist
|
||||||
if dirInfo, dirError := os.Stat(localDir); dirError != nil {
|
if dirInfo, dirError := os.Stat(localDir); dirError != nil {
|
||||||
log.Println("There is an error with the local directory: " + dirError.Error())
|
log.Println("There is an error with the local directory: " + dirError.Error())
|
||||||
@ -41,13 +56,26 @@ func main() {
|
|||||||
for true {
|
for true {
|
||||||
if password == `` {
|
if password == `` {
|
||||||
// Promt for the password:
|
// Promt for the password:
|
||||||
fmt.Println(`Please provide the password for the connection:`)
|
fmt.Print(`Please provide the password for the connection: `)
|
||||||
fmt.Scanln(&password)
|
fmt.Scanln(&password)
|
||||||
} else {
|
} else {
|
||||||
break
|
break
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Give some information about the state
|
||||||
|
if supervised {
|
||||||
|
log.Println("I use the supervised mode.")
|
||||||
|
} else {
|
||||||
|
log.Println("I do not use the supervised mode.")
|
||||||
|
}
|
||||||
|
|
||||||
|
if pushOnly {
|
||||||
|
log.Println("I use the push only mode i.e. backup mode. Any remote change will be ignored.")
|
||||||
|
} else {
|
||||||
|
log.Println("I use the full mode and consider also remote changes.")
|
||||||
|
}
|
||||||
|
|
||||||
// Create the SSH configuration:
|
// Create the SSH configuration:
|
||||||
Sync.SetPassword4Callback(password)
|
Sync.SetPassword4Callback(password)
|
||||||
config := &ssh.ClientConfig{
|
config := &ssh.ClientConfig{
|
||||||
@ -67,6 +95,6 @@ func main() {
|
|||||||
}
|
}
|
||||||
|
|
||||||
defer ssh.Close()
|
defer ssh.Close()
|
||||||
Sync.Synchronise(ssh, supervised, localDir, remoteDir)
|
Sync.Synchronise(ssh, supervised, pushOnly, localDir, remoteDir)
|
||||||
log.Println("Synchronising done.")
|
log.Println("Synchronising done.")
|
||||||
}
|
}
|
||||||
|
@ -8,8 +8,9 @@ func readFlags() {
|
|||||||
flag.StringVar(&serverAddrString, `server`, `127.0.0.1:22`, `The (remote) SSH server, e.g. 'my.host.com', 'my.host.com:22', '127.0.0.1:22', 'localhost:22'.`)
|
flag.StringVar(&serverAddrString, `server`, `127.0.0.1:22`, `The (remote) SSH server, e.g. 'my.host.com', 'my.host.com:22', '127.0.0.1:22', 'localhost:22'.`)
|
||||||
flag.StringVar(&username, `user`, `username`, `The user's name for the SSH server.`)
|
flag.StringVar(&username, `user`, `username`, `The user's name for the SSH server.`)
|
||||||
flag.StringVar(&password, `pwd`, ``, `The user's password for the SSH server. You can omit these argument. Thus, the program asks for the password on demand.`)
|
flag.StringVar(&password, `pwd`, ``, `The user's password for the SSH server. You can omit these argument. Thus, the program asks for the password on demand.`)
|
||||||
flag.StringVar(&localDir, `localDir`, ``, `The local directory which should be synced.`)
|
flag.StringVar(&localDir, `localDir`, `.`, `The local directory which should be synced. Use . for the current working directory.`)
|
||||||
flag.StringVar(&remoteDir, `remoteDir`, ``, `The remote directory which should be synced.`)
|
flag.StringVar(&remoteDir, `remoteDir`, ``, `The remote directory which should be synced.`)
|
||||||
flag.BoolVar(&supervised, `supervised`, true, `Use the supervised mode? The algorithm asks you before any change.`)
|
flag.BoolVar(&supervised, `supervised`, true, `Use the supervised mode? The algorithm asks you before any change.`)
|
||||||
|
flag.BoolVar(&pushOnly, `pushOnly`, true, `Use the push only mode, i.e. backup mode. Ignore any change on the remote side!`)
|
||||||
flag.Parse()
|
flag.Parse()
|
||||||
}
|
}
|
||||||
|
@ -1,18 +1,7 @@
|
|||||||
package Sync
|
package Sync
|
||||||
|
|
||||||
import (
|
|
||||||
"path/filepath"
|
|
||||||
"strings"
|
|
||||||
)
|
|
||||||
|
|
||||||
func comparePath(localBase, localPath, remoteBase, remotePath string) bool {
|
func comparePath(localBase, localPath, remoteBase, remotePath string) bool {
|
||||||
localCompare := normalisePath(localBase, localPath)
|
localCompare := normalisePath(localBase, localPath)
|
||||||
remoteCompare := normalisePath(remoteBase, remotePath)
|
remoteCompare := normalisePath(remoteBase, remotePath)
|
||||||
return localCompare == remoteCompare
|
return localCompare == remoteCompare
|
||||||
}
|
}
|
||||||
|
|
||||||
func normalisePath(base, path string) string {
|
|
||||||
result := strings.Replace(path, base, ``, 1)
|
|
||||||
result = filepath.ToSlash(result)
|
|
||||||
return strings.ToLower(result)
|
|
||||||
}
|
|
||||||
|
12
Sync/NormalisePath.go
Normal file
12
Sync/NormalisePath.go
Normal file
@ -0,0 +1,12 @@
|
|||||||
|
package Sync
|
||||||
|
|
||||||
|
import (
|
||||||
|
"path/filepath"
|
||||||
|
"strings"
|
||||||
|
)
|
||||||
|
|
||||||
|
func normalisePath(base, path string) string {
|
||||||
|
result := strings.Replace(path, base, ``, 1)
|
||||||
|
result = filepath.ToSlash(result)
|
||||||
|
return strings.ToLower(result)
|
||||||
|
}
|
23
Sync/ReadYesNoAnswer.go
Normal file
23
Sync/ReadYesNoAnswer.go
Normal file
@ -0,0 +1,23 @@
|
|||||||
|
package Sync
|
||||||
|
|
||||||
|
import (
|
||||||
|
"fmt"
|
||||||
|
"strings"
|
||||||
|
)
|
||||||
|
|
||||||
|
func readYesNoAnswer(defaultAnswer bool) bool { // true := yes
|
||||||
|
answer := ``
|
||||||
|
if _, scanError := fmt.Scan(&answer); scanError != nil {
|
||||||
|
return defaultAnswer
|
||||||
|
}
|
||||||
|
|
||||||
|
if answer == `` || answer == ` ` {
|
||||||
|
return defaultAnswer
|
||||||
|
}
|
||||||
|
|
||||||
|
if strings.ToLower(answer) == `y` {
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
|
||||||
|
return false
|
||||||
|
}
|
@ -13,11 +13,7 @@ import (
|
|||||||
"time"
|
"time"
|
||||||
)
|
)
|
||||||
|
|
||||||
var (
|
func Synchronise(ssh *ssh.Client, supervised, pushOnly bool, localDir, remoteDir string) {
|
||||||
test string = ""
|
|
||||||
)
|
|
||||||
|
|
||||||
func Synchronise(ssh *ssh.Client, supervised bool, localDir, remoteDir string) {
|
|
||||||
/*
|
/*
|
||||||
Algorithm:
|
Algorithm:
|
||||||
- Get all local files and dirs
|
- Get all local files and dirs
|
||||||
@ -65,11 +61,8 @@ func Synchronise(ssh *ssh.Client, supervised bool, localDir, remoteDir string) {
|
|||||||
log.Printf("Found %d local files.\n", len(localFiles))
|
log.Printf("Found %d local files.\n", len(localFiles))
|
||||||
|
|
||||||
//
|
//
|
||||||
// Read the remote files ============================================================================================
|
// Connect to the server ============================================================================================
|
||||||
//
|
//
|
||||||
log.Println("Try to read all remote files now...")
|
|
||||||
remoteFiles = make(map[string]os.FileInfo)
|
|
||||||
|
|
||||||
sftp, sftpError := sftp.NewClient(ssh)
|
sftp, sftpError := sftp.NewClient(ssh)
|
||||||
if sftpError != nil {
|
if sftpError != nil {
|
||||||
log.Println("Was not able to connect to the server: " + sftpError.Error())
|
log.Println("Was not able to connect to the server: " + sftpError.Error())
|
||||||
@ -78,6 +71,11 @@ func Synchronise(ssh *ssh.Client, supervised bool, localDir, remoteDir string) {
|
|||||||
|
|
||||||
defer sftp.Close()
|
defer sftp.Close()
|
||||||
|
|
||||||
|
//
|
||||||
|
// Read the remote files ============================================================================================
|
||||||
|
//
|
||||||
|
log.Println("Try to read all remote files now...")
|
||||||
|
remoteFiles = make(map[string]os.FileInfo)
|
||||||
counterRemoteFile := 0
|
counterRemoteFile := 0
|
||||||
walker := sftp.Walk(remoteDir)
|
walker := sftp.Walk(remoteDir)
|
||||||
for walker.Step() {
|
for walker.Step() {
|
||||||
@ -213,66 +211,68 @@ func Synchronise(ssh *ssh.Client, supervised bool, localDir, remoteDir string) {
|
|||||||
//
|
//
|
||||||
// Free local space ============================================================================================
|
// Free local space ============================================================================================
|
||||||
//
|
//
|
||||||
deleteLocalFiles := make([]string, 0)
|
if !pushOnly {
|
||||||
for localFileNormalised, localFileInfo := range localFilesNormalised {
|
deleteLocalFiles := make([]string, 0)
|
||||||
remoteFileNormaliesed := remoteFilesNormalised[localFileNormalised]
|
for localFileNormalised, localFileInfo := range localFilesNormalised {
|
||||||
if remoteFileNormaliesed == nil {
|
remoteFileNormaliesed := remoteFilesNormalised[localFileNormalised]
|
||||||
if localFileInfo.ModTime().UTC().Before(ndr) {
|
if remoteFileNormaliesed == nil {
|
||||||
deleteLocalFiles = append(deleteLocalFiles, localFileNormalised)
|
if localFileInfo.ModTime().UTC().Before(ndr) {
|
||||||
|
deleteLocalFiles = append(deleteLocalFiles, localFileNormalised)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
|
||||||
log.Printf("Found %d local files to delete.\n", len(deleteLocalFiles))
|
log.Printf("Found %d local files to delete.\n", len(deleteLocalFiles))
|
||||||
|
|
||||||
if len(deleteLocalFiles) > 0 {
|
if len(deleteLocalFiles) > 0 {
|
||||||
sort.Strings(deleteLocalFiles)
|
sort.Strings(deleteLocalFiles)
|
||||||
shouldDeleteLocalFiles := true
|
shouldDeleteLocalFiles := true
|
||||||
if supervised {
|
if supervised {
|
||||||
fmt.Println(`=================================================================`)
|
fmt.Println(`=================================================================`)
|
||||||
for _, file := range deleteLocalFiles {
|
for _, file := range deleteLocalFiles {
|
||||||
fmt.Println(normalised2localFiles[file])
|
fmt.Println(normalised2localFiles[file])
|
||||||
|
}
|
||||||
|
|
||||||
|
fmt.Print("Should I delete these local files? <y|n> ")
|
||||||
|
shouldDeleteLocalFiles = readYesNoAnswer(false)
|
||||||
}
|
}
|
||||||
|
|
||||||
fmt.Print("Should I delete these local files? <y|n> ")
|
if shouldDeleteLocalFiles {
|
||||||
shouldDeleteLocalFiles = readYesNoAnswer(false)
|
for _, localFileNormalised := range deleteLocalFiles {
|
||||||
}
|
|
||||||
|
|
||||||
if shouldDeleteLocalFiles {
|
// Skip all directories:
|
||||||
for _, localFileNormalised := range deleteLocalFiles {
|
if localFilesNormalised[localFileNormalised].IsDir() {
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
|
||||||
// Skip all directories:
|
removeError := os.Remove(normalised2localFiles[localFileNormalised])
|
||||||
if localFilesNormalised[localFileNormalised].IsDir() {
|
if removeError != nil {
|
||||||
continue
|
log.Printf("Was not able to delete the local file %s: %s\n", normalised2localFiles[localFileNormalised], removeError.Error())
|
||||||
|
} else {
|
||||||
|
log.Printf("Deleted the local file %s\n", normalised2localFiles[localFileNormalised])
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
removeError := os.Remove(normalised2localFiles[localFileNormalised])
|
for _, localFileNormalised := range deleteLocalFiles {
|
||||||
if removeError != nil {
|
|
||||||
log.Printf("Was not able to delete the local file %s: %s\n", normalised2localFiles[localFileNormalised], removeError.Error())
|
|
||||||
} else {
|
|
||||||
log.Printf("Deleted the local file %s\n", normalised2localFiles[localFileNormalised])
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
for _, localFileNormalised := range deleteLocalFiles {
|
// Skip all files:
|
||||||
|
if !localFilesNormalised[localFileNormalised].IsDir() {
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
|
||||||
// Skip all files:
|
removeError := os.Remove(normalised2localFiles[localFileNormalised])
|
||||||
if !localFilesNormalised[localFileNormalised].IsDir() {
|
if removeError != nil {
|
||||||
continue
|
log.Printf("Was not able to delete the local directory %s: %s\n", normalised2localFiles[localFileNormalised], removeError.Error())
|
||||||
|
} else {
|
||||||
|
log.Printf("Deleted the local directory %s\n", normalised2localFiles[localFileNormalised])
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
removeError := os.Remove(normalised2localFiles[localFileNormalised])
|
for _, localFileNormalised := range deleteLocalFiles {
|
||||||
if removeError != nil {
|
delete(localFiles, normalised2localFiles[localFileNormalised])
|
||||||
log.Printf("Was not able to delete the local directory %s: %s\n", normalised2localFiles[localFileNormalised], removeError.Error())
|
delete(localFilesNormalised, localFileNormalised)
|
||||||
} else {
|
|
||||||
log.Printf("Deleted the local directory %s\n", normalised2localFiles[localFileNormalised])
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
for _, localFileNormalised := range deleteLocalFiles {
|
|
||||||
delete(localFiles, normalised2localFiles[localFileNormalised])
|
|
||||||
delete(localFilesNormalised, localFileNormalised)
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -280,81 +280,83 @@ func Synchronise(ssh *ssh.Client, supervised bool, localDir, remoteDir string) {
|
|||||||
// Download new files ============================================================================================
|
// Download new files ============================================================================================
|
||||||
//
|
//
|
||||||
|
|
||||||
downloadRemoteFiles := make([]string, 0)
|
if !pushOnly {
|
||||||
for remoteFileNormalised, _ := range remoteFilesNormalised {
|
downloadRemoteFiles := make([]string, 0)
|
||||||
localFileNormaliesed := localFilesNormalised[remoteFileNormalised]
|
for remoteFileNormalised, _ := range remoteFilesNormalised {
|
||||||
if localFileNormaliesed == nil {
|
localFileNormaliesed := localFilesNormalised[remoteFileNormalised]
|
||||||
downloadRemoteFiles = append(downloadRemoteFiles, remoteFileNormalised)
|
if localFileNormaliesed == nil {
|
||||||
}
|
downloadRemoteFiles = append(downloadRemoteFiles, remoteFileNormalised)
|
||||||
}
|
|
||||||
|
|
||||||
log.Printf("Found %d new remote files to download.\n", len(downloadRemoteFiles))
|
|
||||||
|
|
||||||
if len(downloadRemoteFiles) > 0 {
|
|
||||||
sort.Strings(downloadRemoteFiles)
|
|
||||||
shouldDownloadRemoteFiles := true
|
|
||||||
if supervised {
|
|
||||||
fmt.Println(`=================================================================`)
|
|
||||||
for _, file := range downloadRemoteFiles {
|
|
||||||
fmt.Println(normalised2remoteFiles[file])
|
|
||||||
}
|
}
|
||||||
|
|
||||||
fmt.Print("Should I download these new remote files? <y|n> ")
|
|
||||||
shouldDownloadRemoteFiles = readYesNoAnswer(false)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
if shouldDownloadRemoteFiles {
|
log.Printf("Found %d new remote files to download.\n", len(downloadRemoteFiles))
|
||||||
|
|
||||||
// 1. Create all new directories
|
if len(downloadRemoteFiles) > 0 {
|
||||||
for _, remoteFileNormalised := range downloadRemoteFiles {
|
sort.Strings(downloadRemoteFiles)
|
||||||
|
shouldDownloadRemoteFiles := true
|
||||||
// Skip all files
|
if supervised {
|
||||||
if !remoteFilesNormalised[remoteFileNormalised].IsDir() {
|
fmt.Println(`=================================================================`)
|
||||||
continue
|
for _, file := range downloadRemoteFiles {
|
||||||
|
fmt.Println(normalised2remoteFiles[file])
|
||||||
}
|
}
|
||||||
|
|
||||||
newLocalDir := filepath.Join(localDir, strings.Replace(normalised2remoteFiles[remoteFileNormalised], remoteDir, ``, 1))
|
fmt.Print("Should I download these new remote files? <y|n> ")
|
||||||
log.Printf("Try to create the new local directory %s...\n", newLocalDir)
|
shouldDownloadRemoteFiles = readYesNoAnswer(false)
|
||||||
if mkdirError := os.MkdirAll(newLocalDir, os.ModeDir); mkdirError != nil {
|
|
||||||
log.Printf("Was not able to create the local directory %s: %s\n", newLocalDir, mkdirError.Error())
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// 2. All new files
|
if shouldDownloadRemoteFiles {
|
||||||
for _, remoteFileNormalised := range downloadRemoteFiles {
|
|
||||||
|
|
||||||
// Skip all directories
|
// 1. Create all new directories
|
||||||
if remoteFilesNormalised[remoteFileNormalised].IsDir() {
|
for _, remoteFileNormalised := range downloadRemoteFiles {
|
||||||
continue
|
|
||||||
|
// Skip all files
|
||||||
|
if !remoteFilesNormalised[remoteFileNormalised].IsDir() {
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
|
||||||
|
newLocalDir := filepath.Join(localDir, strings.Replace(normalised2remoteFiles[remoteFileNormalised], remoteDir, ``, 1))
|
||||||
|
log.Printf("Try to create the new local directory %s...\n", newLocalDir)
|
||||||
|
if mkdirError := os.MkdirAll(newLocalDir, os.ModeDir); mkdirError != nil {
|
||||||
|
log.Printf("Was not able to create the local directory %s: %s\n", newLocalDir, mkdirError.Error())
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
log.Printf("Try to download the new remote file %s...\n", normalised2remoteFiles[remoteFileNormalised])
|
// 2. All new files
|
||||||
remoteFileHandle, remoteFileHandleError := sftp.Open(normalised2remoteFiles[remoteFileNormalised])
|
for _, remoteFileNormalised := range downloadRemoteFiles {
|
||||||
if remoteFileHandleError != nil {
|
|
||||||
log.Printf("Was not able to open the remote file %s: %s\n", normalised2remoteFiles[remoteFileNormalised], remoteFileHandleError.Error())
|
|
||||||
continue
|
|
||||||
}
|
|
||||||
|
|
||||||
_, filename := filepath.Split(normalised2remoteFiles[remoteFileNormalised])
|
// Skip all directories
|
||||||
path, _ := filepath.Split(strings.Replace(normalised2remoteFiles[remoteFileNormalised], remoteDir, ``, 1))
|
if remoteFilesNormalised[remoteFileNormalised].IsDir() {
|
||||||
newLocalFile := filepath.Join(localDir, path, filename)
|
continue
|
||||||
localFileHandle, localFileHandleError := os.Create(newLocalFile)
|
}
|
||||||
if localFileHandleError != nil {
|
|
||||||
log.Printf("Was not able to create the local file %s: %s\n", newLocalFile, localFileHandleError.Error())
|
log.Printf("Try to download the new remote file %s...\n", normalised2remoteFiles[remoteFileNormalised])
|
||||||
remoteFileHandle.Close()
|
remoteFileHandle, remoteFileHandleError := sftp.Open(normalised2remoteFiles[remoteFileNormalised])
|
||||||
continue
|
if remoteFileHandleError != nil {
|
||||||
}
|
log.Printf("Was not able to open the remote file %s: %s\n", normalised2remoteFiles[remoteFileNormalised], remoteFileHandleError.Error())
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
|
||||||
|
_, filename := filepath.Split(normalised2remoteFiles[remoteFileNormalised])
|
||||||
|
path, _ := filepath.Split(strings.Replace(normalised2remoteFiles[remoteFileNormalised], remoteDir, ``, 1))
|
||||||
|
newLocalFile := filepath.Join(localDir, path, filename)
|
||||||
|
localFileHandle, localFileHandleError := os.Create(newLocalFile)
|
||||||
|
if localFileHandleError != nil {
|
||||||
|
log.Printf("Was not able to create the local file %s: %s\n", newLocalFile, localFileHandleError.Error())
|
||||||
|
remoteFileHandle.Close()
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
|
||||||
|
_, copyError := io.Copy(localFileHandle, remoteFileHandle)
|
||||||
|
if copyError != nil {
|
||||||
|
log.Printf("Was not able to download the new remote file %s to the local file %s: %s\n", normalised2remoteFiles[remoteFileNormalised], newLocalFile, copyError.Error())
|
||||||
|
remoteFileHandle.Close()
|
||||||
|
localFileHandle.Close()
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
|
||||||
_, copyError := io.Copy(localFileHandle, remoteFileHandle)
|
|
||||||
if copyError != nil {
|
|
||||||
log.Printf("Was not able to download the new remote file %s to the local file %s: %s\n", normalised2remoteFiles[remoteFileNormalised], newLocalFile, copyError.Error())
|
|
||||||
remoteFileHandle.Close()
|
remoteFileHandle.Close()
|
||||||
localFileHandle.Close()
|
localFileHandle.Close()
|
||||||
continue
|
|
||||||
}
|
}
|
||||||
|
|
||||||
remoteFileHandle.Close()
|
|
||||||
localFileHandle.Close()
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -447,60 +449,62 @@ func Synchronise(ssh *ssh.Client, supervised bool, localDir, remoteDir string) {
|
|||||||
// Changed files on the remote side ============================================================================================
|
// Changed files on the remote side ============================================================================================
|
||||||
//
|
//
|
||||||
|
|
||||||
changedRemoteFiles := make([]string, 0)
|
if !pushOnly {
|
||||||
for remoteFileNormalised, remoteFileInfo := range remoteFilesNormalised {
|
changedRemoteFiles := make([]string, 0)
|
||||||
localFileNormaliesed := localFilesNormalised[remoteFileNormalised]
|
for remoteFileNormalised, remoteFileInfo := range remoteFilesNormalised {
|
||||||
if localFileNormaliesed != nil && !localFileNormaliesed.IsDir() {
|
localFileNormaliesed := localFilesNormalised[remoteFileNormalised]
|
||||||
if remoteFileInfo.ModTime().UTC().After(localFileNormaliesed.ModTime().UTC()) {
|
if localFileNormaliesed != nil && !localFileNormaliesed.IsDir() {
|
||||||
changedRemoteFiles = append(changedRemoteFiles, remoteFileNormalised)
|
if remoteFileInfo.ModTime().UTC().After(localFileNormaliesed.ModTime().UTC()) {
|
||||||
|
changedRemoteFiles = append(changedRemoteFiles, remoteFileNormalised)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
|
||||||
log.Printf("Found %d remote files which are changed.\n", len(changedRemoteFiles))
|
log.Printf("Found %d remote files which are changed.\n", len(changedRemoteFiles))
|
||||||
|
|
||||||
if len(changedRemoteFiles) > 0 {
|
if len(changedRemoteFiles) > 0 {
|
||||||
sort.Strings(changedRemoteFiles)
|
sort.Strings(changedRemoteFiles)
|
||||||
shouldDownloadRemoteFiles := true
|
shouldDownloadRemoteFiles := true
|
||||||
if supervised {
|
if supervised {
|
||||||
fmt.Println(`=================================================================`)
|
fmt.Println(`=================================================================`)
|
||||||
for _, file := range changedRemoteFiles {
|
for _, file := range changedRemoteFiles {
|
||||||
fmt.Println(normalised2remoteFiles[file])
|
fmt.Println(normalised2remoteFiles[file])
|
||||||
|
}
|
||||||
|
|
||||||
|
fmt.Print("Should I download these changed remote files? <y|n> ")
|
||||||
|
shouldDownloadRemoteFiles = readYesNoAnswer(false)
|
||||||
}
|
}
|
||||||
|
|
||||||
fmt.Print("Should I download these changed remote files? <y|n> ")
|
if shouldDownloadRemoteFiles {
|
||||||
shouldDownloadRemoteFiles = readYesNoAnswer(false)
|
for _, remoteFileNormalised := range changedRemoteFiles {
|
||||||
}
|
log.Printf("Try to download the changed remote file %s...\n", normalised2remoteFiles[remoteFileNormalised])
|
||||||
|
remoteFileHandle, remoteFileHandleError := sftp.Open(normalised2remoteFiles[remoteFileNormalised])
|
||||||
|
if remoteFileHandleError != nil {
|
||||||
|
log.Printf("Was not able to open the remote file %s: %s\n", normalised2remoteFiles[remoteFileNormalised], remoteFileHandleError.Error())
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
|
||||||
if shouldDownloadRemoteFiles {
|
_, filename := filepath.Split(normalised2remoteFiles[remoteFileNormalised])
|
||||||
for _, remoteFileNormalised := range changedRemoteFiles {
|
path, _ := filepath.Split(strings.Replace(normalised2remoteFiles[remoteFileNormalised], remoteDir, ``, 1))
|
||||||
log.Printf("Try to download the changed remote file %s...\n", normalised2remoteFiles[remoteFileNormalised])
|
existingLocalFile := filepath.Join(localDir, path, filename)
|
||||||
remoteFileHandle, remoteFileHandleError := sftp.Open(normalised2remoteFiles[remoteFileNormalised])
|
localFileHandle, localFileHandleError := os.Create(existingLocalFile)
|
||||||
if remoteFileHandleError != nil {
|
if localFileHandleError != nil {
|
||||||
log.Printf("Was not able to open the remote file %s: %s\n", normalised2remoteFiles[remoteFileNormalised], remoteFileHandleError.Error())
|
log.Printf("Was not able to overwrite the local file %s: %s\n", existingLocalFile, localFileHandleError.Error())
|
||||||
continue
|
remoteFileHandle.Close()
|
||||||
}
|
continue
|
||||||
|
}
|
||||||
|
|
||||||
_, filename := filepath.Split(normalised2remoteFiles[remoteFileNormalised])
|
_, copyError := io.Copy(localFileHandle, remoteFileHandle)
|
||||||
path, _ := filepath.Split(strings.Replace(normalised2remoteFiles[remoteFileNormalised], remoteDir, ``, 1))
|
if copyError != nil {
|
||||||
existingLocalFile := filepath.Join(localDir, path, filename)
|
log.Printf("Was not able to download the changed remote file %s to the local file %s: %s\n", normalised2remoteFiles[remoteFileNormalised], existingLocalFile, copyError.Error())
|
||||||
localFileHandle, localFileHandleError := os.Create(existingLocalFile)
|
remoteFileHandle.Close()
|
||||||
if localFileHandleError != nil {
|
localFileHandle.Close()
|
||||||
log.Printf("Was not able to overwrite the local file %s: %s\n", existingLocalFile, localFileHandleError.Error())
|
continue
|
||||||
remoteFileHandle.Close()
|
}
|
||||||
continue
|
|
||||||
}
|
|
||||||
|
|
||||||
_, copyError := io.Copy(localFileHandle, remoteFileHandle)
|
|
||||||
if copyError != nil {
|
|
||||||
log.Printf("Was not able to download the changed remote file %s to the local file %s: %s\n", normalised2remoteFiles[remoteFileNormalised], existingLocalFile, copyError.Error())
|
|
||||||
remoteFileHandle.Close()
|
remoteFileHandle.Close()
|
||||||
localFileHandle.Close()
|
localFileHandle.Close()
|
||||||
continue
|
|
||||||
}
|
}
|
||||||
|
|
||||||
remoteFileHandle.Close()
|
|
||||||
localFileHandle.Close()
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -568,25 +572,3 @@ func Synchronise(ssh *ssh.Client, supervised bool, localDir, remoteDir string) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func walkerlocal(path string, info os.FileInfo, err error) error {
|
|
||||||
localFiles[path] = info
|
|
||||||
return nil
|
|
||||||
}
|
|
||||||
|
|
||||||
func readYesNoAnswer(defaultAnswer bool) bool { // true := yes
|
|
||||||
answer := ``
|
|
||||||
if _, scanError := fmt.Scan(&answer); scanError != nil {
|
|
||||||
return defaultAnswer
|
|
||||||
}
|
|
||||||
|
|
||||||
if answer == `` || answer == ` ` {
|
|
||||||
return defaultAnswer
|
|
||||||
}
|
|
||||||
|
|
||||||
if strings.ToLower(answer) == `y` {
|
|
||||||
return true
|
|
||||||
}
|
|
||||||
|
|
||||||
return false
|
|
||||||
}
|
|
||||||
|
10
Sync/WalkerLocal.go
Normal file
10
Sync/WalkerLocal.go
Normal file
@ -0,0 +1,10 @@
|
|||||||
|
package Sync
|
||||||
|
|
||||||
|
import (
|
||||||
|
"os"
|
||||||
|
)
|
||||||
|
|
||||||
|
func walkerlocal(path string, info os.FileInfo, err error) error {
|
||||||
|
localFiles[path] = info
|
||||||
|
return nil
|
||||||
|
}
|
@ -7,4 +7,5 @@ var (
|
|||||||
localDir = `` // The local directory
|
localDir = `` // The local directory
|
||||||
remoteDir = `` // The remote directory
|
remoteDir = `` // The remote directory
|
||||||
supervised = true // Should the tool work supervised?
|
supervised = true // Should the tool work supervised?
|
||||||
|
pushOnly = true // Pushes only local changes to the remote i.e. backup mode
|
||||||
)
|
)
|
||||||
|
Loading…
Reference in New Issue
Block a user