1
0
mirror of https://github.com/gilbertchen/duplicacy synced 2025-12-10 05:13:17 +00:00

First steps -pref-dir

This commit is contained in:
Etienne Charlier
2017-06-05 23:16:11 +02:00
parent 36044e13c0
commit c88e148d59
10 changed files with 194 additions and 31 deletions

3
.gitignore vendored Normal file
View File

@@ -0,0 +1,3 @@
.idea
duplicacy_main

View File

@@ -72,7 +72,8 @@ func CreateBackupManager(snapshotID string, storage Storage, top string, passwor
// directory
func (manager *BackupManager) SetupSnapshotCache(top string, storageName string) bool {
cacheDir := path.Join(top, DUPLICACY_DIRECTORY, "cache", storageName)
duplicacyDirectory := GetDotDuplicacyPathName(top)
cacheDir := path.Join(duplicacyDirectory, "cache", storageName)
storage, err := CreateFileStorage(cacheDir, 1)
if err != nil {
@@ -600,6 +601,7 @@ func (manager *BackupManager) Restore(top string, revision int, inPlace bool, qu
}
}
// How will behave restore when repo created using -repo-dir ,??
err = os.Mkdir(path.Join(top, DUPLICACY_DIRECTORY), 0744)
if err != nil && !os.IsExist(err) {
LOG_ERROR("RESTORE_MKDIR", "Failed to create the preference directory: %v", err)
@@ -979,7 +981,8 @@ func (manager *BackupManager) RestoreFile(chunkDownloader *ChunkDownloader, chun
var existingFile, newFile *os.File
var err error
temporaryPath := path.Join(top, DUPLICACY_DIRECTORY, "temporary")
duplicacyDirectory := GetDotDuplicacyPathName(top)
temporaryPath := path.Join(duplicacyDirectory, "temporary")
fullPath := joinPath(top, entry.Path)
defer func() {

View File

@@ -22,6 +22,7 @@ import (
// This is the hidden directory in the repository for storing various files.
var DUPLICACY_DIRECTORY = ".duplicacy"
var DUPLICACY_FILE = ".duplicacy"
// Regex for matching 'StartChunk:StartOffset:EndChunk:EndOffset'
var contentRegex = regexp.MustCompile(`^([0-9]+):([0-9]+):([0-9]+):([0-9]+)`)

View File

@@ -9,6 +9,7 @@ import (
"path"
"io/ioutil"
"reflect"
"os"
)
// Preference stores options for each storage.
@@ -25,9 +26,52 @@ type Preference struct {
var Preferences [] Preference
// Compute .duplicacy directory path name:
// - if .duplicacy is a directory -> compute absolute path name and return it
// - if .duplicacy is a file -> assumed this file contains the real path name of .duplicacy
// - if pointed directory does not exits... return error
func GetDotDuplicacyPathName( repository string) (duplicacyDirectory string){
dotDuplicacy := path.Join(repository, DUPLICACY_DIRECTORY) //TOKEEP
stat, err := os.Stat(dotDuplicacy)
if err != nil && !os.IsNotExist(err) {
LOG_ERROR("DOT_DUPLICACY_PATH", "Failed to retrieve the information about the directory %s: %v",
repository, err)
return ""
}
if stat != nil && stat.IsDir() {
// $repository/.duplicacy exists and is a directory --> we found the .duplicacy directory
return path.Clean(dotDuplicacy)
}
if stat != nil && stat.Mode().IsRegular() {
b, err := ioutil.ReadFile(dotDuplicacy) // just pass the file name
if err != nil {
LOG_ERROR("DOT_DUPLICACY_PATH", "Failed to read file %s: %v",
dotDuplicacy, err)
return ""
}
dot_duplicacy := string(b) // convert content to a 'string'
stat, err := os.Stat(dot_duplicacy)
if err != nil && !os.IsNotExist(err) {
LOG_ERROR("DOT_DUPLICACY_PATH", "Failed to retrieve the information about the directory %s: %v",
repository, err)
return ""
}
if stat != nil && stat.IsDir() {
// If expression read from .duplicacy file is a directory --> we found the .duplicacy directory
return path.Clean( dot_duplicacy)
}
}
return ""
}
func LoadPreferences(repository string) (bool) {
description, err := ioutil.ReadFile(path.Join(repository, DUPLICACY_DIRECTORY, "preferences"))
duplicacyDirectory := GetDotDuplicacyPathName(repository)
description, err := ioutil.ReadFile(path.Join(duplicacyDirectory, "preferences"))
if err != nil {
LOG_ERROR("PREFERENCE_OPEN", "Failed to read the preference file from repository %s: %v", repository, err)
return false
@@ -53,8 +97,9 @@ func SavePreferences(repository string) (bool) {
LOG_ERROR("PREFERENCE_MARSHAL", "Failed to marshal the repository preferences: %v", err)
return false
}
duplicacyDirectory := GetDotDuplicacyPathName(repository)
preferenceFile := path.Join(duplicacyDirectory, "/preferences")
preferenceFile := path.Join(repository, DUPLICACY_DIRECTORY, "/preferences")
err = ioutil.WriteFile(preferenceFile, description, 0644)
if err != nil {
LOG_ERROR("PREFERENCE_WRITE", "Failed to save the preference file %s: %v", preferenceFile, err)

View File

@@ -510,7 +510,10 @@ func CreateShadowCopy(top string, shadowCopy bool) (shadowTop string) {
snapshotPath := uint16ArrayToString(properties.SnapshotDeviceObject)
shadowLink = path.Join(top, DUPLICACY_DIRECTORY) + "\\shadow"
duplicacyDirectory := GetDotDuplicacyPathName(top)
shadowLink = path.Join(duplicacyDirectory, "shadow")
// FIXME: Not using path.Join : is this intentional ?
//shadowLink = path.Join(top, DUPLICACY_DIRECTORY) + "\\shadow"
os.Remove(shadowLink)
err = os.Symlink(snapshotPath + "\\", shadowLink)
if err != nil {

View File

@@ -67,7 +67,9 @@ func CreateSnapshotFromDirectory(id string, top string) (snapshot *Snapshot, ski
}
var patterns []string
patternFile, err := ioutil.ReadFile(path.Join(top, DUPLICACY_DIRECTORY, "filters"))
duplicacyDirectory := GetDotDuplicacyPathName(top)
patternFile, err := ioutil.ReadFile(path.Join(duplicacyDirectory, "filters"))
if err == nil {
for _, pattern := range strings.Split(string(patternFile), "\n") {
pattern = strings.TrimSpace(pattern)

View File

@@ -1511,7 +1511,8 @@ func (manager *SnapshotManager) PruneSnapshots(top string, selfID string, snapsh
LOG_WARN("DELETE_OPTIONS", "Tags or retention policy will be ignored if at least one revision is specified")
}
logDir := path.Join(top, DUPLICACY_DIRECTORY, "logs")
duplicacyDirectory := GetDotDuplicacyPathName(top)
logDir := path.Join(duplicacyDirectory, "logs")
os.Mkdir(logDir, 0700)
logFileName := path.Join(logDir, time.Now().Format("prune-log-20060102-150405"))
logFile, err := os.OpenFile(logFileName, os.O_WRONLY | os.O_CREATE | os.O_TRUNC, 0600)

View File

@@ -81,7 +81,7 @@ func checkHostKey(repository string, hostname string, remote net.Addr, key ssh.P
return nil
}
duplicacyDirectory := path.Join(repository, DUPLICACY_DIRECTORY)
duplicacyDirectory := GetDotDuplicacyPathName(repository)
hostFile := path.Join(duplicacyDirectory, "knowns_hosts")
file, err := os.OpenFile(hostFile, os.O_RDWR | os.O_CREATE, 0600)
if err != nil {

80
integration_tests/test.sh Executable file
View File

@@ -0,0 +1,80 @@
#!/bin/bash
set -x
get_abs_filename() {
# $1 : relative filename
echo "$(cd "$(dirname "$1")" && pwd)/$(basename "$1")"
}
DUPLICACY=$(get_abs_filename ../duplicacy_main)
TEST_ZONE=$HOME/DUPLICACY_TEST_ZONE
TEST_REPO=$TEST_ZONE/TEST_REPO
TEST_STORAGE=$TEST_ZONE/TEST_STORAGE
TEST_DOT_DUPLICACY=$TEST_ZONE/TEST_DOT_DUPLICACY
TEST_RESTORE_POINT=$TEST_ZONE/RESTORE_POINT
function fixture()
{
# clean TEST_RESTORE_POINT
rm -rf $TEST_RESTORE_POINT
mkdir -p $TEST_RESTORE_POINT
# clean TEST_STORAGE
rm -rf $TEST_STORAGE
mkdir -p $TEST_STORAGE
# clean TEST_DOT_DUPLICACY
rm -rf $TEST_DOT_DUPLICACY
mkdir -p $TEST_DOT_DUPLICACY
# Create test repository
rm -rf $TEST_REPO
mkdir -p $TEST_REPO
pushd $TEST_REPO
echo "file1" > file1
mkdir dir1
echo "file2 >dir1/file2"
popd
}
function init_repo()
{
pushd $TEST_REPO
$DUPLICACY init integration-tests $TEST_STORAGE
$DUPLICACY backup
popd
}
function init_repo_pref_dir()
{
pushd $TEST_REPO
$DUPLICACY init -pref-dir "$TEST_ZONE/TEST_DOT_DUPLICACY" integration-tests $TEST_STORAGE
$DUPLICACY backup
popd
}
function backup()
{
pushd $TEST_REPO
NOW=`date`
echo $NOW > "file-$NOW"
$DUPLICACY backup
popd
}
function restore()
{
pushd $TEST_REPO
$DUPLICACY restore -r 2 -delete
popd
}
fixture
init_repo_pref_dir
backup
backup
backup
restore

View File

@@ -18,6 +18,8 @@ import (
"github.com/gilbertchen/cli"
"github.com/gilbertchen/duplicacy"
"io/ioutil"
)
const (
@@ -26,6 +28,7 @@ const (
var ScriptEnabled bool
func getRepositoryPreference(context *cli.Context, storageName string) (repository string,
preference *duplicacy.Preference) {
@@ -34,16 +37,15 @@ func getRepositoryPreference(context *cli.Context, storageName string) (reposito
duplicacy.LOG_ERROR("REPOSITORY_PATH", "Failed to retrieve the current working directory: %v", err)
return "", nil
}
for {
stat, err := os.Stat(path.Join(repository, duplicacy.DUPLICACY_DIRECTORY))
stat, err := os.Stat(path.Join(repository, duplicacy.DUPLICACY_DIRECTORY)) //TOKEEP
if err != nil && !os.IsNotExist(err) {
duplicacy.LOG_ERROR("REPOSITORY_PATH", "Failed to retrieve the information about the directory %s: %v",
repository, err)
return "", nil
}
if stat != nil && stat.IsDir() {
if stat != nil && (stat.IsDir() || stat.Mode().IsRegular()) {
break
}
@@ -54,10 +56,10 @@ func getRepositoryPreference(context *cli.Context, storageName string) (reposito
}
repository = parent
}
duplicacy.LoadPreferences(repository)
duplicacy.SetKeyringFile(path.Join(repository, duplicacy.DUPLICACY_DIRECTORY, "keyring"))
duplicacyDirectory := duplicacy.GetDotDuplicacyPathName(repository)
duplicacy.SetKeyringFile(path.Join(duplicacyDirectory, "keyring"))
if storageName == "" {
storageName = context.String("storage")
@@ -143,7 +145,8 @@ func runScript(context *cli.Context, repository string, storageName string, phas
return false
}
scriptDir, _ := filepath.Abs(path.Join(repository, duplicacy.DUPLICACY_DIRECTORY, "scripts"))
duplicacyDirectory := duplicacy.GetDotDuplicacyPathName(repository)
scriptDir, _ := filepath.Abs(path.Join(duplicacyDirectory, "scripts"))
scriptName := phase + "-" + context.Command.Name
script := path.Join(scriptDir, scriptName)
@@ -174,14 +177,14 @@ func runScript(context *cli.Context, repository string, storageName string, phas
}
func initRepository(context *cli.Context) {
configRespository(context, true)
configRepository(context, true)
}
func addStorage(context *cli.Context) {
configRespository(context, false)
configRepository(context, false)
}
func configRespository(context *cli.Context, init bool) {
func configRepository(context *cli.Context, init bool) {
setGlobalOptions(context)
defer duplicacy.CatchLogException()
@@ -221,7 +224,14 @@ func configRespository(context *cli.Context, init bool) {
return
}
duplicacyDirectory := path.Join(repository, duplicacy.DUPLICACY_DIRECTORY)
duplicacyDirectory := context.String("pref-dir")
if duplicacyDirectory == "" {
duplicacyDirectory = path.Join(repository, duplicacy.DUPLICACY_DIRECTORY) // TOKEEP
}
duplicacy.LOG_INFO("PREF_PATH", "-pref-dir value: --|%s|-- ", duplicacyDirectory)
if stat, _ := os.Stat(path.Join(duplicacyDirectory, "preferences")); stat != nil {
duplicacy.LOG_ERROR("REPOSITORY_INIT", "The repository %s has already been initialized", repository)
return
@@ -230,10 +240,20 @@ func configRespository(context *cli.Context, init bool) {
err = os.Mkdir(duplicacyDirectory, 0744)
if err != nil && !os.IsExist(err) {
duplicacy.LOG_ERROR("REPOSITORY_INIT", "Failed to create the directory %s: %v",
duplicacy.DUPLICACY_DIRECTORY, err)
duplicacyDirectory, err)
return
}
if context.String("pref-dir") != "" {
// out of tree preference file
// write real path into .duplicacy file inside repository
duplicacyFileName := path.Join(repository, duplicacy.DUPLICACY_FILE)
d1 := []byte(duplicacyDirectory)
err = ioutil.WriteFile(duplicacyFileName, d1, 0644)
if err != nil {
duplicacy.LOG_ERROR("REPOSITORY_PATH", "Failed to write %s file inside repository %v", duplicacyFileName, err)
return
}
}
duplicacy.SetKeyringFile(path.Join(duplicacyDirectory, "keyring"))
} else {
@@ -547,7 +567,6 @@ func changePassword(context *cli.Context) {
duplicacy.LOG_INFO("STORAGE_SET", "The password for storage %s has been changed", preference.StorageURL)
}
func backupRepository(context *cli.Context) {
setGlobalOptions(context)
defer duplicacy.CatchLogException()
@@ -1071,7 +1090,8 @@ func infoStorage(context *cli.Context) {
repository := context.String("repository")
if repository != "" {
duplicacy.SetKeyringFile(path.Join(repository, duplicacy.DUPLICACY_DIRECTORY, "keyring"))
duplicacyDirectory := duplicacy.GetDotDuplicacyPathName(repository)
duplicacy.SetKeyringFile(path.Join(duplicacyDirectory, "keyring"))
}
isEncrypted := context.Bool("e")
@@ -1132,6 +1152,11 @@ func main() {
Usage: "the minimum size of chunks (defaults to chunk-size / 4)",
Argument: "1M",
},
cli.StringFlag{
Name: "pref-dir",
Usage: "Specify alternate location for .duplicacy preferences directory (absolute or relative to current directory)",
Argument: "<preference directory path>",
},
},
Usage: "Initialize the storage if necessary and the current directory as the repository",
ArgsUsage: "<snapshot id> <storage url>",