Version 1.0.0

This commit is contained in:
Thorsten Sommer 2015-09-28 21:06:09 +02:00
parent 83f958f0d9
commit cd58325ee3
10 changed files with 246 additions and 0 deletions

58
Main.go Normal file
View File

@ -0,0 +1,58 @@
package main
import (
"fmt"
"github.com/SommerEngineering/Sync/Sync"
"golang.org/x/crypto/ssh"
"log"
"runtime"
)
func main() {
// Show the current version:
fmt.Println(`Sync v1.0.0`)
// Allow Go to use all CPUs:
runtime.GOMAXPROCS(runtime.NumCPU())
// Read the configuration from the command-line args:
readFlags()
// Check if the directories are provided:
if localDir == `` || remoteDir == `` {
log.Println(`Please provide the local and remote directory.`)
return
}
// Check if the password was provided:
for true {
if password == `` {
// Promt for the password:
fmt.Println(`Please provide the password for the connection:`)
fmt.Scanln(&password)
} else {
break
}
}
// Create the SSH configuration:
Sync.SetPassword4Callback(password)
config := &ssh.ClientConfig{
User: username,
Auth: []ssh.AuthMethod{
ssh.Password(password),
ssh.PasswordCallback(Sync.PasswordCallback),
ssh.KeyboardInteractive(Sync.KeyboardInteractiveChallenge),
},
}
// Connect to the SSH server:
ssh := Sync.ConnectSSH(config, serverAddrString)
if ssh == nil {
log.Println(`It was not possible to connect to the SSH server.`)
return
}
defer ssh.Close()
}

15
ReadFlags.go Normal file
View File

@ -0,0 +1,15 @@
package main
import (
"flag"
)
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(&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(&localDir, `localDir`, ``, `The local 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.Parse()
}

18
Sync/ComparePath.go Normal file
View File

@ -0,0 +1,18 @@
package Sync
import (
"path/filepath"
"strings"
)
func comparePath(localBase, localPath, remoteBase, remotePath string) bool {
localCompare := normalisePath(localBase, localPath)
remoteCompare := normalisePath(remoteBase, remotePath)
return localCompare == remoteCompare
}
func normalisePath(base, path string) string {
result := strings.Replace(path, base, ``, 1)
result = filepath.ToSlash(result)
return strings.ToLower(result)
}

42
Sync/Connect.go Normal file
View File

@ -0,0 +1,42 @@
package Sync
import (
"golang.org/x/crypto/ssh"
"log"
"time"
)
func ConnectSSH(config *ssh.ClientConfig, serverAddrString string) (sshClientConnection *ssh.Client) {
currentRetriesServer := 0
// Loop for retries:
for {
// Try to connect to the SSH server:
if sshClientConn, err := ssh.Dial(`tcp`, serverAddrString, config); err != nil {
// Failed:
currentRetriesServer++
log.Printf("Was not able to connect with the SSH server %s: %s\n", serverAddrString, err.Error())
// Is a retry alowed?
if currentRetriesServer < maxRetriesServer {
log.Println(`Retry...`)
time.Sleep(1 * time.Second)
} else {
// After the return, this thread is closed down. The client can try it again...
log.Println(`No more retries for connecting the SSH server.`)
return
}
} else {
// Success:
log.Println(`Connected to the SSH server ` + serverAddrString)
sshClientConnection = sshClientConn
return
}
}
}

5
Sync/Constants.go Normal file
View File

@ -0,0 +1,5 @@
package Sync
const (
maxRetriesServer = 16 // How many retries are allowed to create the SSH server's connection?
)

View File

@ -0,0 +1,35 @@
package Sync
import (
"log"
)
// Another auth. method.
func KeyboardInteractiveChallenge(user, instruction string, questions []string, echos []bool) (answers []string, err error) {
// Log all the provided data:
log.Println(`User: ` + user)
log.Println(`Instruction: ` + instruction)
log.Println(`Questions:`)
for q := range questions {
log.Println(q)
}
// How many questions are asked?
countQuestions := len(questions)
if countQuestions == 1 {
// We expect that in this case (only one question is asked), that the server want to know the password ;-)
answers = make([]string, countQuestions, countQuestions)
answers[0] = callbackPassword
} else if countQuestions > 1 {
// After logging, this call will exit the whole program:
log.Fatalln(`The SSH server is asking multiple questions! This program cannot handle this case.`)
}
err = nil
return
}

10
Sync/PasswordCallback.go Normal file
View File

@ -0,0 +1,10 @@
package Sync
// Just a callback function for the password request.
func PasswordCallback() (string, error) {
return callbackPassword, nil
}
func SetPassword4Callback(password string) {
callbackPassword = password
}

48
Sync/Synchronise.go Normal file
View File

@ -0,0 +1,48 @@
package Sync
import (
"github.com/pkg/sftp"
"golang.org/x/crypto/ssh"
)
func Synchronise(ssh *ssh.Client, supervised bool, localDir, remoteDir string) {
/*
Algorithm:
- Get all local files and dirs
- Get all remote files and dirs
- Determine: ndl := newest mod time of all local files
- Determine: ndr := newest mod time of all remote files
- Free remote space
- Are remote files present, which are locally not present
and these remote files are older than ndl?
- Meaning: You have worked locally and remotely are older files which are not locally present.
Interpretation of change: You have deleted these files locally, because you own local
files which are newer that these files.
- delete these remote files! (may ask the user)
- Free local space
- Are local files present, which are remotely not present
and these local files are older than ndr?
- Meaning: You have worked remotely (or have synced with another PC), thus, local files are older
and these are not present remotely. Interpretation of change: You have delete these files
remotely, because your remotely files are newer that these files.
- delete these local files! (may ask the user)
- Download any new files
- Are remote files present, which are locally not present
and these remote files are newer than ndl?
- Meaning: These files are new to the local side
- Download these files! (may ask the user)
- Upload any new files
- Are local files present, which are remotely not present
and these local files are newer than ndr?
- Meaning: These files are new to the remote side
- Upload these files! (may ask the user)
- Changed remote files
- Are remote and local files present, where the remote file is newer?
- Meaning: These files are changed on the remote side
- Download these files and replace the local copies (may ask the user)
- Changed local files
- Are local and remote files present, where the local file is newer?
- Meaning: These files are changed on the local side
- Upload these files and replace the remote copies (may ask the user)
*/
}

5
Sync/Variables.go Normal file
View File

@ -0,0 +1,5 @@
package Sync
var (
callbackPassword = ``
)

10
Variables.go Normal file
View File

@ -0,0 +1,10 @@
package main
var (
username = `` // The SSH user's name
password = `` // The user's password
serverAddrString = `` // The SSH server address
localDir = `` // The local directory
remoteDir = `` // The remote directory
supervised = true // Should the tool work supervised?
)