1
0
mirror of https://github.com/rclone/rclone.git synced 2026-01-09 12:03:20 +00:00

Compare commits

..

3 Commits
v0.91 ... v0.92

Author SHA1 Message Date
Nick Craig-Wood
2a4c721794 Update config 2014-03-15 17:39:56 +00:00
Nick Craig-Wood
7d786204b4 Add -config option to specify a config file 2014-03-15 17:01:13 +00:00
Nick Craig-Wood
b3f1a45bbf Config fixes
* Fix empty config configuration
  * Alter menus when no remotes
  * Save config file after delete remote
2014-03-15 16:52:51 +00:00
2 changed files with 272 additions and 31 deletions

225
README.md
View File

@@ -3,14 +3,19 @@ Rclone
Sync files and directories to and from Sync files and directories to and from
* Openstack Swift * Openstack Swift / Rackspace cloud files / Memset Memstore
* Rackspace cloud files
* Amazon S3 * Amazon S3
* Google Drive * Google Drive
* The local filesystem * The local filesystem
FIXME Features
* MD5SUMs checked at all times for file integrity
* Timestamps preserved on files
* Partial syncs supported on a whole file basis
* Copy mode to just copy new/changed files
* Sync mode to make a directory identical
* Check mode to check all MD5SUMs
Install Install
------- -------
@@ -19,7 +24,7 @@ Rclone is a Go program and comes as a single binary file.
Download the relevant binary from Download the relevant binary from
- http://www.craig-wood.com/nick/pub/rclone/ * http://www.craig-wood.com/nick/pub/rclone/
Or alternatively if you have Go installed use Or alternatively if you have Go installed use
@@ -28,10 +33,213 @@ Or alternatively if you have Go installed use
and this will build the binary in `$GOPATH/bin`. You can then modify and this will build the binary in `$GOPATH/bin`. You can then modify
the source and submit patches. the source and submit patches.
Configure
---------
First you'll need to configure rclone. As the object storage systems
have quite complicated authentication these are kept in a config file
`.rclone.conf` in your home directory by default. (You can use the
-config option to choose a different config file.)
The easiest way to make the config is to run rclone with the config
option, Eg
rclone config
Here is an example of making an s3 configuration
```
No remotes found - make a new one
n) New remote
q) Quit config
n/q> n
name> remote
What type of source is it?
Choose a number from below
1) swift
2) s3
3) local
4) drive
type> 2
AWS Access Key ID.
access_key_id> accesskey
AWS Secret Access Key (password).
secret_access_key> secretaccesskey
Endpoint for S3 API.
Choose a number from below, or type in your own value
* The default endpoint - a good choice if you are unsure.
* US Region, Northern Virginia or Pacific Northwest.
* Leave location constraint empty.
1) https://s3.amazonaws.com/
* US Region, Northern Virginia only.
* Leave location constraint empty.
2) https://s3-external-1.amazonaws.com
* US West (Oregon) Region
* Needs location constraint us-west-2.
3) https://s3-us-west-2.amazonaws.com
[snip]
* South America (Sao Paulo) Region
* Needs location constraint sa-east-1.
9) https://s3-sa-east-1.amazonaws.com
endpoint> 1
Location constraint - must be set to match the Endpoint.
Choose a number from below, or type in your own value
* Empty for US Region, Northern Virginia or Pacific Northwest.
1)
* US West (Oregon) Region.
2) us-west-2
* US West (Northern California) Region.
3) us-west-1
[snip]
* South America (Sao Paulo) Region.
9) sa-east-1
location_constraint> 1
--------------------
[remote]
access_key_id = accesskey
secret_access_key = secretaccesskey
endpoint = https://s3.amazonaws.com/
location_constraint =
--------------------
y) Yes this is OK
e) Edit this remote
d) Delete this remote
y/e/d> y
Current remotes:
Name Type
==== ====
remote s3
e) Edit existing remote
n) New remote
d) Delete remote
q) Quit config
e/n/d/q> q
```
This can now be used like this
```
rclone lsd remote:// - see all buckets/containers
rclone ls remote:// - list a bucket
rclone sync /home/local/directory remote://bucket
```
Usage Usage
----- -----
FIXME Rclone syncs a directory tree from local to remote.
Its basic syntax is like this
Syntax: [options] subcommand <parameters> <parameters...>
Each subcommand looks like this. See below for how to specify the
source and destination paths.
rclone copy source://path dest://path
Copy the source to the destination. Doesn't transfer
unchanged files, testing first by modification time then by
MD5SUM. Doesn't delete files from the destination.
rclone sync source://path dest://path
Sync the source to the destination. Doesn't transfer
unchanged files, testing first by modification time then by
MD5SUM. Deletes any files that exist in source that don't
exist in destination. Since this can cause data loss, test
first with the -dry-run flag.
rclone ls [remote://path]
List all the objects in the the path.
rclone lsd [remote://path]
List all directoryes/objects/buckets in the the path.
rclone mkdir remote://path
Make the path if it doesn't already exist
rclone rmdir remote://path
Remove the path. Note that you can't remove a path with
objects in it, use purge for that.
rclone purge remote://path
Remove the path and all of its contents.
rclone check source://path dest://path
Checks the files in the source and destination match. It
compares sizes and MD5SUMs and prints a report of files which
don't match. It doesn't alter the source or destination.
General options:
-config Location of the config file
-transfers=4: Number of file transfers to run in parallel.
-checkers=8: Number of MD5SUM checkers to run in parallel.
-dry-run=false: Do a trial run with no permanent changes
-modify-window=1ns: Max time difference to be considered the same - this is automatically set usually
-quiet=false: Print as little stuff as possible
-stats=1m0s: Interval to print stats
-verbose=false: Print lots more stuff
Developer options:
-cpuprofile="": Write cpu profile to file
Local Filesystem
----------------
Paths are specified as normal filesystem paths, so
rclone sync /home/source /tmp/destination
Will sync source to destination
Swift / Rackspace cloudfiles / Memset Memstore
----------------------------------------------
Paths are specified as remote://container or remote:// for the lsd
command.
So to copy a local directory to a swift container called backup
rclone sync /home/source swift://backup
The modified time is stored as metadata on the object as
'X-Object-Meta-Mtime' as floating point since the epoch.
This is a defacto standard (used in the official python-swiftclient
amongst others) for storing the modification time (as read using
os.Stat) for an object.
Amazon S3
---------
Paths are specified as remote://bucket
So to copy a local directory to a s3 container called backup
rclone sync /home/source s3://backup
The modified time is stored as metadata on the object as
"X-Amz-Meta-Mtime" as floating point since the epoch.
Google drive
------------
Paths are specified as drive://path Drive paths may be as deep as required.
FIXME describe how to set up initially
So to copy a local directory to a drive directory called backup
rclone sync /home/source s3://backup
License License
------- -------
@@ -39,6 +247,13 @@ License
This is free software under the terms of MIT the license (check the This is free software under the terms of MIT the license (check the
COPYING file included in this package). COPYING file included in this package).
Bugs
----
Save the google drive auth in this config file too!
Describe how to do the google auth.
Contact and support Contact and support
------------------- -------------------

View File

@@ -25,18 +25,19 @@ const (
var ( var (
// Config file // Config file
ConfigFile *goconfig.ConfigFile ConfigFile *goconfig.ConfigFile
// Home directory
HomeDir = configHome()
// Config file path // Config file path
ConfigPath string ConfigPath = path.Join(HomeDir, configFileName)
// Global config // Global config
Config = &ConfigInfo{} Config = &ConfigInfo{}
// Home directory
HomeDir string
// Flags // Flags
verbose = flag.Bool("verbose", false, "Print lots more stuff") verbose = flag.Bool("verbose", false, "Print lots more stuff")
quiet = flag.Bool("quiet", false, "Print as little stuff as possible") quiet = flag.Bool("quiet", false, "Print as little stuff as possible")
modifyWindow = flag.Duration("modify-window", time.Nanosecond, "Max time diff to be considered the same") modifyWindow = flag.Duration("modify-window", time.Nanosecond, "Max time diff to be considered the same")
checkers = flag.Int("checkers", 8, "Number of checkers to run in parallel.") checkers = flag.Int("checkers", 8, "Number of checkers to run in parallel.")
transfers = flag.Int("transfers", 4, "Number of file transfers to run in parallel.") transfers = flag.Int("transfers", 4, "Number of file transfers to run in parallel.")
configFile = flag.String("config", ConfigPath, "Config file.")
) )
// Filesystem config options // Filesystem config options
@@ -48,6 +49,17 @@ type ConfigInfo struct {
Transfers int Transfers int
} }
// Find the config directory
func configHome() string {
// Find users home directory
usr, err := user.Current()
if err != nil {
log.Printf("Couldn't find home directory: %v", err)
return ""
}
return usr.HomeDir
}
// Loads the config file // Loads the config file
func LoadConfig() { func LoadConfig() {
// Read some flags if set // Read some flags if set
@@ -59,19 +71,17 @@ func LoadConfig() {
Config.Checkers = *checkers Config.Checkers = *checkers
Config.Transfers = *transfers Config.Transfers = *transfers
// Find users home directory ConfigPath = *configFile
usr, err := user.Current()
if err != nil {
log.Printf("Couldn't find home directory: %v", err)
return
}
HomeDir = usr.HomeDir
ConfigPath = path.Join(HomeDir, configFileName)
// Load configuration file. // Load configuration file.
var err error
ConfigFile, err = goconfig.LoadConfigFile(ConfigPath) ConfigFile, err = goconfig.LoadConfigFile(ConfigPath)
if err != nil { if err != nil {
log.Printf("Failed to load config file %v - using defaults", ConfigPath) log.Printf("Failed to load config file %v - using defaults", ConfigPath)
ConfigFile, err = goconfig.LoadConfigFile(os.DevNull)
if err != nil {
log.Fatalf("Failed to read null config file: %v", err)
}
} }
} }
@@ -84,8 +94,11 @@ func SaveConfig() {
} }
// Show an overview of the config file // Show an overview of the config file
func ShowConfig() { func ShowRemotes() {
remotes := ConfigFile.GetSectionList() remotes := ConfigFile.GetSectionList()
if len(remotes) == 0 {
return
}
sort.Strings(remotes) sort.Strings(remotes)
fmt.Printf("%-20s %s\n", "Name", "Type") fmt.Printf("%-20s %s\n", "Name", "Type")
fmt.Printf("%-20s %s\n", "====", "====") fmt.Printf("%-20s %s\n", "====", "====")
@@ -112,7 +125,7 @@ func ReadLine() string {
} }
// Command - choose one // Command - choose one
func Command(commands []string) int { func Command(commands []string) byte {
opts := []string{} opts := []string{}
for _, text := range commands { for _, text := range commands {
fmt.Printf("%c) %s\n", text[0], text[1:]) fmt.Printf("%c) %s\n", text[0], text[1:])
@@ -128,7 +141,7 @@ func Command(commands []string) int {
} }
i := strings.IndexByte(optString, result[0]) i := strings.IndexByte(optString, result[0])
if i >= 0 { if i >= 0 {
return i return result[0]
} }
} }
} }
@@ -179,11 +192,11 @@ func ShowRemote(name string) {
func OkRemote(name string) bool { func OkRemote(name string) bool {
ShowRemote(name) ShowRemote(name)
switch i := Command([]string{"yYes this is OK", "eEdit this remote", "dDelete this remote"}); i { switch i := Command([]string{"yYes this is OK", "eEdit this remote", "dDelete this remote"}); i {
case 0: case 'y':
return true return true
case 1: case 'e':
return false return false
case 2: case 'd':
ConfigFile.DeleteSection(name) ConfigFile.DeleteSection(name)
return true return true
default: default:
@@ -236,24 +249,37 @@ func EditRemote(name string) {
SaveConfig() SaveConfig()
} }
// Delete a remote
func DeleteRemote(name string) {
ConfigFile.DeleteSection(name)
SaveConfig()
}
// Edit the config file interactively // Edit the config file interactively
func EditConfig() { func EditConfig() {
for { for {
fmt.Printf("Current remotes:\n\n") haveRemotes := len(ConfigFile.GetSectionList()) != 0
ShowConfig() what := []string{"eEdit existing remote", "nNew remote", "dDelete remote", "qQuit config"}
fmt.Printf("\n") if haveRemotes {
switch i := Command([]string{"eEdit existing remote", "nNew remote", "dDelete remote", "qQuit config"}); i { fmt.Printf("Current remotes:\n\n")
case 0: ShowRemotes()
fmt.Printf("\n")
} else {
fmt.Printf("No remotes found - make a new one\n")
what = append(what[1:2], what[3])
}
switch i := Command(what); i {
case 'e':
name := ChooseRemote() name := ChooseRemote()
EditRemote(name) EditRemote(name)
case 1: case 'n':
fmt.Printf("name> ") fmt.Printf("name> ")
name := ReadLine() name := ReadLine()
NewRemote(name) NewRemote(name)
case 2: case 'd':
name := ChooseRemote() name := ChooseRemote()
ConfigFile.DeleteSection(name) DeleteRemote(name)
case 3: case 'q':
return return
} }
} }