vagrant-vaimo-unison 0.0.1
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +7 -0
- data/.gitignore +19 -0
- data/CHANGELOG.md +21 -0
- data/Gemfile +10 -0
- data/LICENSE +8 -0
- data/README.md +185 -0
- data/Rakefile +21 -0
- data/lib/vagrant-vaimo-unison/command.rb +168 -0
- data/lib/vagrant-vaimo-unison/config.rb +100 -0
- data/lib/vagrant-vaimo-unison/errors.rb +9 -0
- data/lib/vagrant-vaimo-unison/plugin.rb +103 -0
- data/lib/vagrant-vaimo-unison/shell_command.rb +117 -0
- data/lib/vagrant-vaimo-unison/ssh_command.rb +54 -0
- data/lib/vagrant-vaimo-unison/unison_paths.rb +24 -0
- data/lib/vagrant-vaimo-unison/unison_sync.rb +99 -0
- data/lib/vagrant-vaimo-unison/version.rb +5 -0
- data/lib/vagrant-vaimo-unison.rb +15 -0
- data/locales/en.yml +19 -0
- data/spec/vagrant-unison/config_spec.rb +32 -0
- data/vagrant-vaimo-unison.gemspec +55 -0
- metadata +119 -0
checksums.yaml
ADDED
@@ -0,0 +1,7 @@
|
|
1
|
+
---
|
2
|
+
SHA1:
|
3
|
+
metadata.gz: 665a6ac67e4fccd7dc7277186858488fbe94214f
|
4
|
+
data.tar.gz: a42e74a68dcd28324af7c9a0e01dbe97d7c76380
|
5
|
+
SHA512:
|
6
|
+
metadata.gz: d1681956f1bdd042532d52f5229e265a4d5c6592f04ef58cafd610b422f9c570c11ef826b708602483e88ed1619168f556b4d5e2753e9c9ee772a91cba067fa4
|
7
|
+
data.tar.gz: 9a71bcbfb28214619e303b7085317db6ebaec8d0b6d55b90fe9f1e5bc6992dfdad3ad65eaf245d20f6a58700c809ebc36b88c0d893a51f6cc50d4023e8dc5d91
|
data/.gitignore
ADDED
data/CHANGELOG.md
ADDED
@@ -0,0 +1,21 @@
|
|
1
|
+
# 1.0.2 (Feb 2016)
|
2
|
+
* fix the cleanup command to delete contents of directory in Vagrant but not the directory itself, because deleteing the directory can mess up e.g. a docker container that has that directory mounted.
|
3
|
+
|
4
|
+
# 1.0.1
|
5
|
+
* Small bugfix release
|
6
|
+
|
7
|
+
# 1.0.0 (Jan 2016)
|
8
|
+
|
9
|
+
* Breaking commit on dcosson fork
|
10
|
+
* Renames all of the `vagrant ___` commands to start with `unison`, e.g. `vagrant-unison-sync`
|
11
|
+
* Adds a command to sync once and exit, `vagrant unison-sync-once`
|
12
|
+
* Fix bug where cleanup tried to delete `~/.unison` as root, which resolved to wrong thing (at least in Virtualbox) and failed silently bc what we want to delete is `/home/vagrant/.unison`
|
13
|
+
* Pin to newer syntax of the listen gem and stop using a method that had been renamed.
|
14
|
+
|
15
|
+
# 0.0.17 (Jan 2016)
|
16
|
+
|
17
|
+
* Fix bug in validation. Previously, you couldn't run vagrant on a Vagrantfile that didn't use vagrant-unison if you had the plugin installed, because all the config args were required.
|
18
|
+
|
19
|
+
# 0.1.0 (March 2013)
|
20
|
+
|
21
|
+
* Initial release.
|
data/Gemfile
ADDED
@@ -0,0 +1,10 @@
|
|
1
|
+
source "https://rubygems.org"
|
2
|
+
|
3
|
+
gemspec
|
4
|
+
|
5
|
+
group :development do
|
6
|
+
# We depend on Vagrant for development, but we don't add it as a
|
7
|
+
# gem dependency because we expect to be installed within the
|
8
|
+
# Vagrant environment itself using `vagrant plugin`.
|
9
|
+
gem "vagrant", :git => "git://github.com/mitchellh/vagrant.git"
|
10
|
+
end
|
data/LICENSE
ADDED
@@ -0,0 +1,8 @@
|
|
1
|
+
The MIT License (MIT)
|
2
|
+
Copyright (c) 2013 Mitchell Hashimoto
|
3
|
+
|
4
|
+
Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions:
|
5
|
+
|
6
|
+
The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.
|
7
|
+
|
8
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
data/README.md
ADDED
@@ -0,0 +1,185 @@
|
|
1
|
+
# Vagrant Unison 2 Plugin
|
2
|
+
|
3
|
+
This is a [Vagrant](http://www.vagrantup.com) 1.7+ plugin that syncs files over SSH from a local folder
|
4
|
+
to your Vagrant VM (local or on AWS). Under the covers it uses [Unison](http://www.cis.upenn.edu/~bcpierce/unison/)
|
5
|
+
|
6
|
+
**NOTE:** This plugin requires Vagrant 1.7+,
|
7
|
+
|
8
|
+
## Features
|
9
|
+
|
10
|
+
* Unisoned folder support via `unison` over `ssh` -> will work with any vagrant provider, eg Virtualbox or AWS, though it's most tested on a local VM via Virtualbox.
|
11
|
+
|
12
|
+
## Usage
|
13
|
+
|
14
|
+
1. You must already have [Unison](http://www.cis.upenn.edu/~bcpierce/unison/) installed on your path on your host and guest machines, and it must be the same version of Unison on both.
|
15
|
+
* On Mac you can install this with Homebrew: `brew install unison`
|
16
|
+
* This will install unison 2.48.3
|
17
|
+
* On Ubuntu:
|
18
|
+
* [Xenial (16.04)](https://launchpad.net/ubuntu/xenial/+source/unison): `sudo apt-get install unison`
|
19
|
+
* Ubuntu Trusty (14.04):
|
20
|
+
* `sudo add-apt-repository ppa:eugenesan/ppa`
|
21
|
+
* `sudo apt-get update`
|
22
|
+
* `sudo apt-get install unison=2.48.3-1ubuntu1.02~eugenesan~trusty2`
|
23
|
+
* Other 64-bit Linux:
|
24
|
+
* Install package from `http://ftp5.gwdg.de/pub/linux/archlinux/extra/os/x86_64/unison-2.48.3-2-x86_64.pkg.tar.xz`. (Install at your own risk, this is a plain http link. If someone knows of a signed version, checksum, or https host let me know so I can update it).
|
25
|
+
* On Windows, download [2.48.3](http://www.pps.univ-paris-diderot.fr/~vouillon/unison/unison 2.48.3.zip), unzip, rename `unison-2.48.3 text.exe` to `unison.exe` and copy to somewhere in your path. Alternatively, install [using Chocolatey](https://chocolatey.org/packages/unison).
|
26
|
+
|
27
|
+
2. Install using standard Vagrant 1.1+ plugin installation methods.
|
28
|
+
* `vagrant plugin install vagrant-vaimo-unison`
|
29
|
+
|
30
|
+
3. Configure unison in your Vagrantfile, as shown below.
|
31
|
+
|
32
|
+
4. Start your vagrant box as normal (eg: `vagrant up`)
|
33
|
+
|
34
|
+
## Configuration
|
35
|
+
|
36
|
+
```ruby
|
37
|
+
Vagrant.configure("2") do |config|
|
38
|
+
config.vm.box = "dummy"
|
39
|
+
|
40
|
+
# Required configs
|
41
|
+
config.unison.host_folder = "src/" #relative to the folder your Vagrantfile is in
|
42
|
+
config.unison.guest_folder = "src/" #relative to the vagrant home folder (e.g. /home/vagrant)
|
43
|
+
|
44
|
+
# Optional configs
|
45
|
+
# File patterns to ignore when syncing. Ensure you don't have spaces between the commas!
|
46
|
+
config.unison.ignore = "Name {.DS_Store,.git,node_modules}" # Default: none
|
47
|
+
|
48
|
+
# SSH connection details for Vagrant to communicate with VM.
|
49
|
+
config.unison.ssh_host = "10.0.0.1" # Default: '127.0.0.1'
|
50
|
+
config.unison.ssh_port = 22 # Default: 2222
|
51
|
+
config.unison.ssh_user = "deploy" # Default: 'vagrant'
|
52
|
+
config.unison.perms = 0 # if you get "properties changed on both sides" error
|
53
|
+
|
54
|
+
# `vagrant unison-sync-polling` command will restart unison in VM if memory
|
55
|
+
# usage gets above this threshold (in MB).
|
56
|
+
config.unison.mem_cap_mb = 500 # Default: 200
|
57
|
+
|
58
|
+
# Change polling interval (in seconds) at which to sync changes
|
59
|
+
config.unison.repeat = 5 # Default: 1
|
60
|
+
end
|
61
|
+
```
|
62
|
+
|
63
|
+
|
64
|
+
## Start syncing Folders
|
65
|
+
|
66
|
+
Run `vagrant unison-sync-once` to run a single, non-interactive sync and then exit.
|
67
|
+
|
68
|
+
Run `vagrant unison-sync-polling` to start in bidirect monitor (repeat) mode - every second unison checks for changes on either side and syncs them.
|
69
|
+
|
70
|
+
## (Legacy) Sync using OSX inotify events
|
71
|
+
|
72
|
+
Run `vagrant unison-sync` to sync then start watching the local_folder for changes, and syncing these to your vagrang VM.
|
73
|
+
|
74
|
+
This uses the `watch` ruby gem and runs a one-off unison sync when it gets change events.
|
75
|
+
|
76
|
+
For some reason, this does not always get all the events immediately which can be frustrating. Since the polling mode (unison repeat mode) is not too resource intensive, I recommend that instead.
|
77
|
+
|
78
|
+
## Sync in interactive mode
|
79
|
+
|
80
|
+
Run `vagrant unison-sync-interactive` to start in interactive mode. The first time
|
81
|
+
it will ask what to do for every top-level file & directory, otherwise is asks
|
82
|
+
about changes. It allows solving conflicts in various ways. Press "?" in
|
83
|
+
interactive mode to see options for resolving.
|
84
|
+
|
85
|
+
This is a useful tool when the automatic sync sees a change in a file on both
|
86
|
+
sides and skips it.
|
87
|
+
|
88
|
+
## Cleanup unison database
|
89
|
+
Run `vagrant unison-cleanup` to clear the unison metadata from `~/Library/Application Support/Unison/` as well as all files.
|
90
|
+
|
91
|
+
## Error states
|
92
|
+
|
93
|
+
### Inconsistent state with unison metadata
|
94
|
+
|
95
|
+
When you get
|
96
|
+
```
|
97
|
+
Fatal error: Warning: inconsistent state.
|
98
|
+
The archive file is missing on some hosts.
|
99
|
+
For safety, the remaining copies should be deleted.
|
100
|
+
Archive arb126d8de1ef26a835b94cf51975c530f on host blablabla.local should be DELETED
|
101
|
+
Archive arbc6a36f85b3d1473c55565dd220acf68 on host blablabla is MISSING
|
102
|
+
Please delete archive files as appropriate and try again
|
103
|
+
or invoke Unison with -ignorearchives flag.
|
104
|
+
```
|
105
|
+
|
106
|
+
You should run a unison-cleanup
|
107
|
+
|
108
|
+
Running Unison with -ignorearchives flag is a bad idea, since it will produce conflicts.
|
109
|
+
|
110
|
+
### Uncaught exception `bad bigarray kind`
|
111
|
+
|
112
|
+
The error is:
|
113
|
+
```
|
114
|
+
Unison failed: Uncaught exception Failure("input_value: bad bigarray kind")
|
115
|
+
```
|
116
|
+
|
117
|
+
This is caused when the unison on your host and guest were compiled with different versions of ocaml. To fix ensure that
|
118
|
+
both are compiled with the same ocaml version. [More Info Here](https://gist.github.com/pch/aa1c9c4ec8522a11193b)
|
119
|
+
|
120
|
+
### Skipping files changed on both sides
|
121
|
+
|
122
|
+
This is most often caused in my experience by files that get changed by different users with different permissions.
|
123
|
+
|
124
|
+
For instance, if you're running an Ubuntu VM then the unison process is running
|
125
|
+
as the vagrant user. If you have the unison synced folder loaded as a volume in
|
126
|
+
a docker container and a new file gets created in the container, the vagrant
|
127
|
+
user in the VM won't own that file and this can keep unison from being able to
|
128
|
+
sync the file. (I'm looking for a way to fix this particular error case).
|
129
|
+
|
130
|
+
Running a unison-cleanup should fix this state.
|
131
|
+
|
132
|
+
### Properties changed on both sides
|
133
|
+
|
134
|
+
The error is:
|
135
|
+
```
|
136
|
+
Synchronization complete at 13:00:33 (0 item transferred, 1 skipped, 0 failed)
|
137
|
+
skipped: (properties changed on both sides)
|
138
|
+
props <-?-> props /
|
139
|
+
```
|
140
|
+
|
141
|
+
This can be caused by file permissions being synced. If you get this error set
|
142
|
+
the perms arg to 0 as in the [example configuration](#configuration).
|
143
|
+
|
144
|
+
See [perms documentation](http://www.cis.upenn.edu/~bcpierce/unison/download/releases/stable/unison-manual.html#perms) for more info.
|
145
|
+
|
146
|
+
|
147
|
+
## Development
|
148
|
+
|
149
|
+
To work on the `vagrant-unison` plugin, clone this repository out, and use
|
150
|
+
[Bundler](http://gembundler.com) to get the dependencies:
|
151
|
+
|
152
|
+
```
|
153
|
+
$ bundle
|
154
|
+
```
|
155
|
+
|
156
|
+
Once you have the dependencies, verify the unit tests pass with `rake`:
|
157
|
+
|
158
|
+
```
|
159
|
+
$ bundle exec rake
|
160
|
+
```
|
161
|
+
|
162
|
+
If those pass, you're ready to start developing the plugin. You can test
|
163
|
+
the plugin without installing it into your Vagrant environment by just
|
164
|
+
creating a `Vagrantfile` in the top level of this directory (it is gitignored)
|
165
|
+
that uses it, and uses bundler to execute Vagrant:
|
166
|
+
|
167
|
+
```
|
168
|
+
$ bundle exec vagrant up
|
169
|
+
$ bundle exec vagrant unison-sync
|
170
|
+
```
|
171
|
+
|
172
|
+
Or, install the plugin from your local build to use with an existing project's
|
173
|
+
Vagrantfile on your machine.
|
174
|
+
|
175
|
+
Build the plugin with
|
176
|
+
|
177
|
+
```
|
178
|
+
rake build
|
179
|
+
```
|
180
|
+
|
181
|
+
Now you'll see the built gem in a pkg directory. Install it with
|
182
|
+
|
183
|
+
```
|
184
|
+
vagrant plugin install pkg/vagrant-unison-VERSION.gem
|
185
|
+
```
|
data/Rakefile
ADDED
@@ -0,0 +1,21 @@
|
|
1
|
+
require 'rubygems'
|
2
|
+
require 'bundler/setup'
|
3
|
+
require 'rspec/core/rake_task'
|
4
|
+
|
5
|
+
# Immediately sync all stdout so that tools like buildbot can
|
6
|
+
# immediately load in the output.
|
7
|
+
$stdout.sync = true
|
8
|
+
$stderr.sync = true
|
9
|
+
|
10
|
+
# Change to the directory of this file.
|
11
|
+
Dir.chdir(File.expand_path("../", __FILE__))
|
12
|
+
|
13
|
+
# This installs the tasks that help with gem creation and
|
14
|
+
# publishing.
|
15
|
+
Bundler::GemHelper.install_tasks
|
16
|
+
|
17
|
+
# Install the `spec` task so that we can run tests.
|
18
|
+
RSpec::Core::RakeTask.new
|
19
|
+
|
20
|
+
# Default task is to run the unit tests
|
21
|
+
task :default => "spec"
|
@@ -0,0 +1,168 @@
|
|
1
|
+
require "log4r"
|
2
|
+
require "vagrant"
|
3
|
+
require "thread"
|
4
|
+
|
5
|
+
require_relative 'unison_paths'
|
6
|
+
require_relative 'ssh_command'
|
7
|
+
require_relative 'shell_command'
|
8
|
+
require_relative 'unison_sync'
|
9
|
+
|
10
|
+
module VagrantPlugins
|
11
|
+
module Unison
|
12
|
+
class CommandOnce < Vagrant.plugin("2", :command)
|
13
|
+
include UnisonSync
|
14
|
+
|
15
|
+
def self.synopsis
|
16
|
+
"sync the unison shared folder once"
|
17
|
+
end
|
18
|
+
|
19
|
+
def execute
|
20
|
+
status = nil
|
21
|
+
with_target_vms do |machine|
|
22
|
+
execute_sync_command(machine) do |command|
|
23
|
+
command.batch = true
|
24
|
+
command.terse = true
|
25
|
+
command = command.to_s
|
26
|
+
|
27
|
+
@env.ui.info "Running unison once"
|
28
|
+
@env.ui.info " #{command}"
|
29
|
+
|
30
|
+
status = system(command)
|
31
|
+
@env.ui.info "**** unison exited. success: #{status} ****"
|
32
|
+
end
|
33
|
+
end
|
34
|
+
if status
|
35
|
+
return 0
|
36
|
+
else
|
37
|
+
return 1
|
38
|
+
end
|
39
|
+
end
|
40
|
+
end
|
41
|
+
|
42
|
+
class CommandPolling < Vagrant.plugin("2", :command)
|
43
|
+
include UnisonSync
|
44
|
+
attr_accessor :bg_thread
|
45
|
+
|
46
|
+
def self.synopsis
|
47
|
+
"sync the unison shared folder forever, by polling for changes"
|
48
|
+
end
|
49
|
+
|
50
|
+
def execute
|
51
|
+
status = nil
|
52
|
+
with_target_vms do |machine|
|
53
|
+
@bg_thread = watch_vm_for_memory_leak(machine)
|
54
|
+
execute_sync_command(machine) do |command|
|
55
|
+
command.repeat = true
|
56
|
+
command.terse = true
|
57
|
+
command = command.to_s
|
58
|
+
|
59
|
+
@env.ui.info "Running #{command}"
|
60
|
+
|
61
|
+
# Re-run on a crash.
|
62
|
+
# On a sigint, wait 2 seconds before respawning command.
|
63
|
+
# If INT comes in again while waiting, program exits.
|
64
|
+
# If INT comes in after we've respanwned,
|
65
|
+
# will bring us back to this trap handler.
|
66
|
+
exit_on_next_sigint = false
|
67
|
+
while true
|
68
|
+
begin
|
69
|
+
sleep 2 if exit_on_next_sigint
|
70
|
+
exit_on_next_sigint = false
|
71
|
+
status = system(command)
|
72
|
+
@env.ui.info "**** unison exited. success: #{status} ****"
|
73
|
+
rescue Interrupt
|
74
|
+
if exit_on_next_sigint
|
75
|
+
Thread.kill(@bg_thread) if @bg_thread
|
76
|
+
exit 1
|
77
|
+
end
|
78
|
+
@env.ui.info '** Hit Ctrl + C again to kill. **'
|
79
|
+
exit_on_next_sigint = true
|
80
|
+
rescue Exception
|
81
|
+
@env.ui.info '** Sync crashed. Respawning. Hit Ctrl + C twice to kill. **'
|
82
|
+
end
|
83
|
+
end
|
84
|
+
end
|
85
|
+
end
|
86
|
+
if status
|
87
|
+
return 0
|
88
|
+
else
|
89
|
+
return 1
|
90
|
+
end
|
91
|
+
end
|
92
|
+
|
93
|
+
def watch_vm_for_memory_leak(machine)
|
94
|
+
ssh_command = SshCommand.new(machine)
|
95
|
+
Thread.new(ssh_command.ssh, machine.config.unison.mem_cap_mb) do |ssh_command_text, mem_cap_mb|
|
96
|
+
while true
|
97
|
+
sleep 15
|
98
|
+
total_mem = `#{ssh_command_text} 'free -m | egrep "^Mem:" | awk "{print \\$2}"' 2>/dev/null`
|
99
|
+
_unison_proc_returnval = (
|
100
|
+
`#{ssh_command_text} 'ps aux | grep "[u]nison -server" | awk "{print \\$2, \\$4}"' 2>/dev/null`
|
101
|
+
)
|
102
|
+
if _unison_proc_returnval == ''
|
103
|
+
puts "Unison not running in VM"
|
104
|
+
next
|
105
|
+
end
|
106
|
+
pid, mem_pct_unison = _unison_proc_returnval.strip.split(' ')
|
107
|
+
mem_unison = (total_mem.to_f * mem_pct_unison.to_f/100).round(1)
|
108
|
+
# Debugging: uncomment to log every loop tick
|
109
|
+
# puts "Unison running as #{pid} using #{mem_unison} mb"
|
110
|
+
if mem_unison > mem_cap_mb
|
111
|
+
puts "Unison using #{mem_unison}MB memory is over limit of #{mem_cap_mb}MB, restarting"
|
112
|
+
`#{ssh_command_text} kill -HUP #{pid} 2>/dev/null`
|
113
|
+
end
|
114
|
+
end
|
115
|
+
end
|
116
|
+
end
|
117
|
+
end
|
118
|
+
|
119
|
+
class CommandCleanup < Vagrant.plugin("2", :command)
|
120
|
+
def self.synopsis
|
121
|
+
"remove all unison supporting state on local and remote system"
|
122
|
+
end
|
123
|
+
|
124
|
+
def execute
|
125
|
+
with_target_vms do |machine|
|
126
|
+
guest_path = UnisonPaths.new(@env, machine).guest
|
127
|
+
|
128
|
+
command = "rm -rf ~/Library/'Application Support'/Unison/*"
|
129
|
+
@env.ui.info "Running #{command} on host"
|
130
|
+
system(command)
|
131
|
+
|
132
|
+
command = "rm -rf #{guest_path}/* #{guest_path}/..?* #{guest_path}/.[!.]*"
|
133
|
+
@env.ui.info "Running #{command} on guest VM (delete all files from directory including hidden ones)"
|
134
|
+
machine.communicate.sudo(command)
|
135
|
+
|
136
|
+
command = "rm -rf ~/.unison"
|
137
|
+
@env.ui.info "Running #{command} on guest VM"
|
138
|
+
machine.communicate.execute(command)
|
139
|
+
end
|
140
|
+
|
141
|
+
0
|
142
|
+
end
|
143
|
+
end
|
144
|
+
|
145
|
+
class CommandInteract < Vagrant.plugin("2", :command)
|
146
|
+
include UnisonSync
|
147
|
+
|
148
|
+
def self.synopsis
|
149
|
+
"run unison in interactive mode, to resolve conflicts"
|
150
|
+
end
|
151
|
+
|
152
|
+
def execute
|
153
|
+
with_target_vms do |machine|
|
154
|
+
execute_sync_command(machine) do |command|
|
155
|
+
command.terse = true
|
156
|
+
command = command.to_s
|
157
|
+
|
158
|
+
@env.ui.info "Running #{command}"
|
159
|
+
|
160
|
+
system(command)
|
161
|
+
end
|
162
|
+
end
|
163
|
+
|
164
|
+
0
|
165
|
+
end
|
166
|
+
end
|
167
|
+
end
|
168
|
+
end
|
@@ -0,0 +1,100 @@
|
|
1
|
+
require "vagrant"
|
2
|
+
|
3
|
+
module VagrantPlugins
|
4
|
+
module Unison
|
5
|
+
class Config < Vagrant.plugin("2", :config)
|
6
|
+
# Host Folder to Sync
|
7
|
+
#
|
8
|
+
# @return [String]
|
9
|
+
attr_accessor :host_folder
|
10
|
+
|
11
|
+
# Guest Folder to Sync.
|
12
|
+
#
|
13
|
+
# @return [String]
|
14
|
+
attr_accessor :guest_folder
|
15
|
+
|
16
|
+
# Pattern of files to ignore.
|
17
|
+
#
|
18
|
+
# @return [String, Array<String>]
|
19
|
+
attr_accessor :ignore
|
20
|
+
|
21
|
+
# Repeat speed.
|
22
|
+
#
|
23
|
+
# @return [String]
|
24
|
+
attr_accessor :repeat
|
25
|
+
|
26
|
+
# SSH host.
|
27
|
+
#
|
28
|
+
# @return [String]
|
29
|
+
attr_accessor :ssh_host
|
30
|
+
|
31
|
+
# SSH port.
|
32
|
+
#
|
33
|
+
# @return [String]
|
34
|
+
attr_accessor :ssh_port
|
35
|
+
|
36
|
+
# SSH user.
|
37
|
+
#
|
38
|
+
# @return [String]
|
39
|
+
attr_accessor :ssh_user
|
40
|
+
|
41
|
+
# Memory usage cap in MB
|
42
|
+
# Restart Unison in the VM when it's consuming more than this
|
43
|
+
# amount of memory (in MB)
|
44
|
+
# @return [int]
|
45
|
+
attr_accessor :mem_cap_mb
|
46
|
+
|
47
|
+
# perms arg value
|
48
|
+
#
|
49
|
+
# @return [int]
|
50
|
+
attr_accessor :perms
|
51
|
+
|
52
|
+
# Airlab-specific config option to leave off the Vagrant identity file, so
|
53
|
+
# SSH will just use ssh-agent
|
54
|
+
#
|
55
|
+
# @return [Boolean]
|
56
|
+
attr_accessor :ssh_use_agent
|
57
|
+
|
58
|
+
def initialize(region_specific = false)
|
59
|
+
@host_folder = UNSET_VALUE
|
60
|
+
@guest_folder = UNSET_VALUE
|
61
|
+
@ignore = UNSET_VALUE
|
62
|
+
@repeat = UNSET_VALUE
|
63
|
+
@ssh_host = UNSET_VALUE
|
64
|
+
@ssh_port = UNSET_VALUE
|
65
|
+
@ssh_user = UNSET_VALUE
|
66
|
+
@ssh_use_agent = UNSET_VALUE
|
67
|
+
@mem_cap_mb = UNSET_VALUE
|
68
|
+
@perms = UNSET_VALUE
|
69
|
+
end
|
70
|
+
|
71
|
+
def finalize!
|
72
|
+
# The access keys default to nil
|
73
|
+
@host_folder = nil if @host_folder == UNSET_VALUE
|
74
|
+
@guest_folder = nil if @guest_folder == UNSET_VALUE
|
75
|
+
@ignore = nil if @ignore == UNSET_VALUE
|
76
|
+
@repeat = 1 if @repeat == UNSET_VALUE
|
77
|
+
@ssh_host = '127.0.0.1' if @ssh_host == UNSET_VALUE
|
78
|
+
@ssh_port = 2222 if @ssh_port == UNSET_VALUE
|
79
|
+
@ssh_user = 'vagrant' if @ssh_user == UNSET_VALUE
|
80
|
+
@mem_cap_mb = 200 if @mem_cap_mb == UNSET_VALUE
|
81
|
+
@perms = nil if @perms == UNSET_VALUE
|
82
|
+
@ssh_use_agent = false if @ssh_use_agent == UNSET_VALUE
|
83
|
+
|
84
|
+
# Mark that we finalized
|
85
|
+
@__finalized = true
|
86
|
+
end
|
87
|
+
|
88
|
+
def validate(machine)
|
89
|
+
errors = []
|
90
|
+
|
91
|
+
if !(@host_folder.nil? && @guest_folder.nil?)
|
92
|
+
errors << I18n.t("vagrant_unison.config.unison_host_folder_required") if @host_folder.nil?
|
93
|
+
errors << I18n.t("vagrant_unison.config.unison_guest_folder_required") if @guest_folder.nil?
|
94
|
+
end
|
95
|
+
|
96
|
+
{ "Unison" => errors }
|
97
|
+
end
|
98
|
+
end
|
99
|
+
end
|
100
|
+
end
|
@@ -0,0 +1,103 @@
|
|
1
|
+
begin
|
2
|
+
require "vagrant"
|
3
|
+
rescue LoadError
|
4
|
+
raise "The vagrant-unison plugin must be run within Vagrant."
|
5
|
+
end
|
6
|
+
|
7
|
+
# This is a sanity check to make sure no one is attempting to install
|
8
|
+
# this into an early Vagrant version.
|
9
|
+
if Vagrant::VERSION < "1.1.0"
|
10
|
+
raise "The vagrant-unison plugin is only compatible with Vagrant 1.1+"
|
11
|
+
end
|
12
|
+
|
13
|
+
module VagrantPlugins
|
14
|
+
module Unison
|
15
|
+
class Plugin < Vagrant.plugin("2")
|
16
|
+
name "Unison"
|
17
|
+
description <<-DESC
|
18
|
+
This plugin syncs files over SSH from a local folder
|
19
|
+
to your Vagrant VM (local or on AWS).
|
20
|
+
DESC
|
21
|
+
|
22
|
+
config "unison" do
|
23
|
+
require_relative "config"
|
24
|
+
Config
|
25
|
+
end
|
26
|
+
|
27
|
+
command "unison-sync-once" do
|
28
|
+
setup_logging
|
29
|
+
setup_i18n
|
30
|
+
|
31
|
+
#Return the command
|
32
|
+
require_relative "command"
|
33
|
+
CommandOnce
|
34
|
+
end
|
35
|
+
|
36
|
+
command "unison-sync-interact" do
|
37
|
+
# Setup logging and i18n
|
38
|
+
setup_logging
|
39
|
+
setup_i18n
|
40
|
+
|
41
|
+
#Return the command
|
42
|
+
require_relative "command"
|
43
|
+
CommandInteract
|
44
|
+
end
|
45
|
+
|
46
|
+
|
47
|
+
command "unison-sync-polling" do
|
48
|
+
# Setup logging and i18n
|
49
|
+
setup_logging
|
50
|
+
setup_i18n
|
51
|
+
|
52
|
+
#Return the command
|
53
|
+
require_relative "command"
|
54
|
+
CommandPolling
|
55
|
+
end
|
56
|
+
|
57
|
+
command "unison-cleanup" do
|
58
|
+
# Setup logging and i18n
|
59
|
+
setup_logging
|
60
|
+
setup_i18n
|
61
|
+
|
62
|
+
#Return the command
|
63
|
+
require_relative "command"
|
64
|
+
CommandCleanup
|
65
|
+
end
|
66
|
+
|
67
|
+
# This initializes the internationalization strings.
|
68
|
+
def self.setup_i18n
|
69
|
+
I18n.load_path << File.expand_path("locales/en.yml", Unison.source_root)
|
70
|
+
I18n.reload!
|
71
|
+
end
|
72
|
+
|
73
|
+
# This sets up our log level to be whatever VAGRANT_LOG is.
|
74
|
+
def self.setup_logging
|
75
|
+
require "log4r"
|
76
|
+
|
77
|
+
level = nil
|
78
|
+
begin
|
79
|
+
level = Log4r.const_get(ENV["VAGRANT_LOG"].upcase)
|
80
|
+
rescue NameError
|
81
|
+
# This means that the logging constant wasn't found,
|
82
|
+
# which is fine. We just keep `level` as `nil`. But
|
83
|
+
# we tell the user.
|
84
|
+
level = nil
|
85
|
+
end
|
86
|
+
|
87
|
+
# Some constants, such as "true" resolve to booleans, so the
|
88
|
+
# above error checking doesn't catch it. This will check to make
|
89
|
+
# sure that the log level is an integer, as Log4r requires.
|
90
|
+
level = nil if !level.is_a?(Integer)
|
91
|
+
|
92
|
+
# Set the logging level on all "vagrant" namespaced
|
93
|
+
# logs as long as we have a valid level.
|
94
|
+
if level
|
95
|
+
logger = Log4r::Logger.new("vagrant_unison")
|
96
|
+
logger.outputters = Log4r::Outputter.stderr
|
97
|
+
logger.level = level
|
98
|
+
logger = nil
|
99
|
+
end
|
100
|
+
end
|
101
|
+
end
|
102
|
+
end
|
103
|
+
end
|
@@ -0,0 +1,117 @@
|
|
1
|
+
module VagrantPlugins
|
2
|
+
module Unison
|
3
|
+
class ShellCommand
|
4
|
+
def initialize(machine, unison_paths, ssh_command)
|
5
|
+
@machine = machine
|
6
|
+
@unison_paths = unison_paths
|
7
|
+
@ssh_command = ssh_command
|
8
|
+
end
|
9
|
+
|
10
|
+
attr_accessor :batch, :repeat, :terse
|
11
|
+
attr_accessor :force_remote, :force_local
|
12
|
+
attr_accessor :prefer_remote, :prefer_local
|
13
|
+
|
14
|
+
def to_a
|
15
|
+
args.map do |arg|
|
16
|
+
arg = arg[1...-1] if arg =~ /\A"(.*)"\z/
|
17
|
+
arg
|
18
|
+
end
|
19
|
+
end
|
20
|
+
|
21
|
+
def to_s
|
22
|
+
args.join(' ')
|
23
|
+
end
|
24
|
+
|
25
|
+
private
|
26
|
+
|
27
|
+
def args
|
28
|
+
_args = [
|
29
|
+
'unison',
|
30
|
+
local_root_arg,
|
31
|
+
remote_root_arg,
|
32
|
+
batch_arg,
|
33
|
+
terse_arg,
|
34
|
+
repeat_arg,
|
35
|
+
ignore_arg,
|
36
|
+
perms_arg,
|
37
|
+
force_arg,
|
38
|
+
prefer_arg,
|
39
|
+
ssh_args,
|
40
|
+
].flatten.compact
|
41
|
+
_args
|
42
|
+
end
|
43
|
+
|
44
|
+
def local_root_arg
|
45
|
+
@unison_paths.host
|
46
|
+
end
|
47
|
+
|
48
|
+
def remote_root_arg
|
49
|
+
@ssh_command.uri(@unison_paths)
|
50
|
+
end
|
51
|
+
|
52
|
+
def ssh_args
|
53
|
+
['-sshargs', %("#{@ssh_command.ssh_args}")]
|
54
|
+
end
|
55
|
+
|
56
|
+
def batch_arg
|
57
|
+
'-batch' if batch
|
58
|
+
end
|
59
|
+
|
60
|
+
def ignore_arg
|
61
|
+
patterns = []
|
62
|
+
if @machine.config.unison.ignore.is_a? ::Array
|
63
|
+
patterns += @machine.config.unison.ignore
|
64
|
+
elsif @machine.config.unison.ignore
|
65
|
+
patterns << @machine.config.unison.ignore
|
66
|
+
end
|
67
|
+
|
68
|
+
patterns.map do |pattern|
|
69
|
+
['-ignore', %("#{pattern}")]
|
70
|
+
end
|
71
|
+
end
|
72
|
+
|
73
|
+
def perms_arg
|
74
|
+
['-perms', @machine.config.unison.perms] if @machine.config.unison.perms
|
75
|
+
end
|
76
|
+
|
77
|
+
def repeat_arg
|
78
|
+
['-repeat', @machine.config.unison.repeat] if repeat && @machine.config.unison.repeat
|
79
|
+
end
|
80
|
+
|
81
|
+
def terse_arg
|
82
|
+
'-terse' if terse
|
83
|
+
end
|
84
|
+
|
85
|
+
# from the docs:
|
86
|
+
#
|
87
|
+
# Including the preference -force root causes Unison to resolve all
|
88
|
+
# differences (even non-conflicting changes) in favor of root. This
|
89
|
+
# effectively changes Unison from a synchronizer into a mirroring
|
90
|
+
# utility. You can also specify -force newer (or -force older) to force
|
91
|
+
# Unison to choose the file with the later (earlier) modtime. In this
|
92
|
+
# case, the -times preference must also be enabled. This preference is
|
93
|
+
# overridden by the forcepartial preference. This preference should be
|
94
|
+
# used only if you are sure you know what you are doing!
|
95
|
+
#
|
96
|
+
# soo. I'm not sure if I know what I'm doing. Need to make sure that this
|
97
|
+
# doesn't end up deleting .git or some other ignored but critical
|
98
|
+
# directory.
|
99
|
+
def force_arg
|
100
|
+
return ['-force', local_root_arg] if force_local
|
101
|
+
return ['-force', remote_root_arg] if force_remote
|
102
|
+
end
|
103
|
+
|
104
|
+
# from the docs, via Daniel Low (thx daniel):
|
105
|
+
#
|
106
|
+
# Including the preference -prefer root causes Unison always to resolve
|
107
|
+
# conflicts in favor of root, rather than asking for guidance from the
|
108
|
+
# user.
|
109
|
+
#
|
110
|
+
# This is much safer than -force
|
111
|
+
def prefer_arg
|
112
|
+
return ['-prefer', local_root_arg] if prefer_local
|
113
|
+
return ['-prefer', remote_root_arg] if prefer_remote
|
114
|
+
end
|
115
|
+
end
|
116
|
+
end
|
117
|
+
end
|
@@ -0,0 +1,54 @@
|
|
1
|
+
module VagrantPlugins
|
2
|
+
module Unison
|
3
|
+
class SshCommand
|
4
|
+
def initialize(machine)
|
5
|
+
@machine = machine
|
6
|
+
end
|
7
|
+
|
8
|
+
def ssh
|
9
|
+
%W(
|
10
|
+
ssh
|
11
|
+
#{@machine.config.unison.ssh_user}@#{@machine.config.unison.ssh_host}
|
12
|
+
#{ssh_args}
|
13
|
+
).compact.join(' ')
|
14
|
+
end
|
15
|
+
|
16
|
+
def ssh_args
|
17
|
+
%W(
|
18
|
+
-p #{@machine.config.unison.ssh_port}
|
19
|
+
#{proxy_command}
|
20
|
+
-o StrictHostKeyChecking=no
|
21
|
+
-o UserKnownHostsFile=/dev/null
|
22
|
+
#{identity}
|
23
|
+
).compact.join(' ')
|
24
|
+
end
|
25
|
+
|
26
|
+
def uri(unison_paths)
|
27
|
+
username = @machine.config.unison.ssh_user
|
28
|
+
host = @machine.config.unison.ssh_host
|
29
|
+
|
30
|
+
"ssh://#{username}@#{host}/#{unison_paths.guest}"
|
31
|
+
end
|
32
|
+
|
33
|
+
private
|
34
|
+
|
35
|
+
def proxy_command
|
36
|
+
command = @machine.ssh_info[:proxy_command]
|
37
|
+
return nil unless command
|
38
|
+
"-o ProxyCommand='#{command}'"
|
39
|
+
end
|
40
|
+
|
41
|
+
def identity
|
42
|
+
if @machine.config.unison.ssh_use_agent
|
43
|
+
''
|
44
|
+
else
|
45
|
+
(%w(-o IdentitiesOnly=yes) << key_paths).join(' ')
|
46
|
+
end
|
47
|
+
end
|
48
|
+
|
49
|
+
def key_paths
|
50
|
+
@machine.ssh_info[:private_key_path].map { |p| "-i #{p.shellescape}" }.join(' ')
|
51
|
+
end
|
52
|
+
end
|
53
|
+
end
|
54
|
+
end
|
@@ -0,0 +1,24 @@
|
|
1
|
+
module VagrantPlugins
|
2
|
+
module Unison
|
3
|
+
class UnisonPaths
|
4
|
+
def initialize(env, machine)
|
5
|
+
@env = env
|
6
|
+
@machine = machine
|
7
|
+
end
|
8
|
+
|
9
|
+
def guest
|
10
|
+
@machine.config.unison.guest_folder
|
11
|
+
end
|
12
|
+
|
13
|
+
def host
|
14
|
+
@host ||= begin
|
15
|
+
path = File.expand_path(@machine.config.unison.host_folder, @env.root_path)
|
16
|
+
|
17
|
+
# Make sure there is a trailing slash on the host path to
|
18
|
+
# avoid creating an additional directory with rsync
|
19
|
+
path = "#{path}/" if path !~ /\/$/
|
20
|
+
end
|
21
|
+
end
|
22
|
+
end
|
23
|
+
end
|
24
|
+
end
|
@@ -0,0 +1,99 @@
|
|
1
|
+
require "optparse"
|
2
|
+
|
3
|
+
module VagrantPlugins
|
4
|
+
module Unison
|
5
|
+
# mixin providing common functionality for our vagrant commands
|
6
|
+
module UnisonSync
|
7
|
+
def execute_sync_command(machine)
|
8
|
+
parse_options!
|
9
|
+
|
10
|
+
return unless machine.config.unison.host_folder
|
11
|
+
|
12
|
+
unison_paths = UnisonPaths.new(@env, machine)
|
13
|
+
guest_path = unison_paths.guest
|
14
|
+
host_path = unison_paths.host
|
15
|
+
|
16
|
+
@env.ui.info "Unisoning changes from {host}::#{host_path} --> {guest VM}::#{guest_path}"
|
17
|
+
|
18
|
+
# Create the guest path
|
19
|
+
machine.communicate.sudo("mkdir -p '#{guest_path}'")
|
20
|
+
machine.communicate.sudo("chown #{machine.config.unison.ssh_user} '#{guest_path}'")
|
21
|
+
|
22
|
+
ssh_command = SshCommand.new(machine)
|
23
|
+
shell_command = ShellCommand.new(machine, unison_paths, ssh_command)
|
24
|
+
|
25
|
+
shell_command.prefer_local = options[:prefer_local]
|
26
|
+
shell_command.prefer_remote = options[:prefer_remote]
|
27
|
+
shell_command.force_local = options[:force_local]
|
28
|
+
shell_command.force_remote = options[:force_remote]
|
29
|
+
|
30
|
+
yield shell_command
|
31
|
+
end
|
32
|
+
|
33
|
+
def parse_options!
|
34
|
+
# parse_options(option_parser) is provided by vagrant, but
|
35
|
+
# documentation is scarse. Best way to view the docs (imo) is to put
|
36
|
+
# a binding.pry in here and then type `? parse_options`
|
37
|
+
@parsed_argv ||= parse_options(options_parser)
|
38
|
+
|
39
|
+
if options[:verbose]
|
40
|
+
@env.ui.info "Options: #{options}"
|
41
|
+
end
|
42
|
+
|
43
|
+
# According to the docs:
|
44
|
+
# > If parse_options returns `nil`, then you should assume that
|
45
|
+
# > help was printed and parsing failed.
|
46
|
+
if @parsed_argv == nil
|
47
|
+
exit 1
|
48
|
+
end
|
49
|
+
end
|
50
|
+
|
51
|
+
def options
|
52
|
+
@options ||= {
|
53
|
+
:prefer_local => false,
|
54
|
+
:prefer_remote => false,
|
55
|
+
:force_local => false,
|
56
|
+
:force_remote => false,
|
57
|
+
:verbose => false,
|
58
|
+
}
|
59
|
+
end
|
60
|
+
|
61
|
+
def options_parser
|
62
|
+
@option_parser ||= OptionParser.new do |o|
|
63
|
+
o.banner = "Usage: vagrant #{ARGV[0]} [options]"
|
64
|
+
|
65
|
+
o.on('--push', 'prefer changes on the local machine.') do |flag|
|
66
|
+
options[:prefer_local] = flag
|
67
|
+
check_conflicting_options!
|
68
|
+
end
|
69
|
+
|
70
|
+
o.on('--pull', 'prefer changes on the remote machine.') do |flag|
|
71
|
+
options[:prefer_remote] = flag
|
72
|
+
check_conflicting_options!
|
73
|
+
end
|
74
|
+
|
75
|
+
o.on('--force-push', 'force-push changes to the remote machine. Dangerous!') do |flag|
|
76
|
+
options[:force_local] = flag
|
77
|
+
check_conflicting_options!
|
78
|
+
end
|
79
|
+
|
80
|
+
o.on('--force-pull', 'force-pull changes from the remote machine. Super dangerous!') do |flag|
|
81
|
+
options[:force_remote] = flag
|
82
|
+
check_conflicting_options!
|
83
|
+
end
|
84
|
+
|
85
|
+
o.on('--verbose', 'Print additional debug information') do |flag|
|
86
|
+
options[:verbose] = flag
|
87
|
+
end
|
88
|
+
end
|
89
|
+
end
|
90
|
+
|
91
|
+
def check_conflicting_options!
|
92
|
+
enabled = [:prefer_local, :prefer_remote, :force_local, :force_remote].select do |opt|
|
93
|
+
options[opt]
|
94
|
+
end
|
95
|
+
raise ArgumentError.new("Conflicting options: #{enabled.inspect}") if enabled.length > 1
|
96
|
+
end
|
97
|
+
end
|
98
|
+
end
|
99
|
+
end
|
@@ -0,0 +1,15 @@
|
|
1
|
+
require "pathname"
|
2
|
+
|
3
|
+
require "vagrant-vaimo-unison/plugin"
|
4
|
+
require "vagrant-vaimo-unison/errors"
|
5
|
+
|
6
|
+
module VagrantPlugins
|
7
|
+
module Unison
|
8
|
+
# This returns the path to the source of this plugin.
|
9
|
+
#
|
10
|
+
# @return [Pathname]
|
11
|
+
def self.source_root
|
12
|
+
@source_root ||= Pathname.new(File.expand_path("../../", __FILE__))
|
13
|
+
end
|
14
|
+
end
|
15
|
+
end
|
data/locales/en.yml
ADDED
@@ -0,0 +1,19 @@
|
|
1
|
+
en:
|
2
|
+
vagrant_unison:
|
3
|
+
|
4
|
+
config:
|
5
|
+
host_folder_required: |-
|
6
|
+
Host folder is required
|
7
|
+
guest_folder_required: |-
|
8
|
+
Guest folder is required
|
9
|
+
|
10
|
+
errors:
|
11
|
+
unison_error: |-
|
12
|
+
There was an error when attemping to sync folders using unison.
|
13
|
+
Please inspect the error message below for more info.
|
14
|
+
|
15
|
+
Host path: %{hostpath}
|
16
|
+
Guest path: %{guestpath}
|
17
|
+
Error: %{stderr}
|
18
|
+
Full command causing error:
|
19
|
+
%{command}
|
@@ -0,0 +1,32 @@
|
|
1
|
+
require "vagrant-vaimo-unison/config"
|
2
|
+
|
3
|
+
describe VagrantPlugins::Unison::Config do
|
4
|
+
let(:instance) { described_class.new }
|
5
|
+
|
6
|
+
describe "defaults" do
|
7
|
+
subject do
|
8
|
+
instance.tap do |o|
|
9
|
+
o.finalize!
|
10
|
+
end
|
11
|
+
end
|
12
|
+
|
13
|
+
its("host_folder") { should be_nil }
|
14
|
+
its("guest_folder") { should be_nil }
|
15
|
+
its("ignore") { should be_nil }
|
16
|
+
end
|
17
|
+
|
18
|
+
describe "overriding defaults" do
|
19
|
+
# I typically don't meta-program in tests, but this is a very
|
20
|
+
# simple boilerplate test, so I cut corners here. It just sets
|
21
|
+
# each of these attributes to "foo" in isolation, and reads the value
|
22
|
+
# and asserts the proper result comes back out.
|
23
|
+
[:host_folder, :guest_folder].each do |attribute|
|
24
|
+
|
25
|
+
it "should not default #{attribute} if overridden" do
|
26
|
+
instance.send("#{attribute}=".to_sym, "foo")
|
27
|
+
instance.finalize!
|
28
|
+
instance.send(attribute).should == "foo"
|
29
|
+
end
|
30
|
+
end
|
31
|
+
end
|
32
|
+
end
|
@@ -0,0 +1,55 @@
|
|
1
|
+
$:.unshift File.expand_path("../lib", __FILE__)
|
2
|
+
require "vagrant-vaimo-unison/version"
|
3
|
+
|
4
|
+
Gem::Specification.new do |s|
|
5
|
+
s.name = "vagrant-vaimo-unison"
|
6
|
+
s.version = VagrantPlugins::Unison::VERSION
|
7
|
+
s.platform = Gem::Platform::RUBY
|
8
|
+
s.authors = ["David Laing", "dmatora", "Danny Cosson"]
|
9
|
+
s.email = "dcosson@gmail.com"
|
10
|
+
s.homepage = "http://github.com/dcosson/vagrant-unison"
|
11
|
+
s.summary = "Vagrant 1.7+ plugin to sync local files to VM over SSH using Unison"
|
12
|
+
s.description = "Vagrant 1.7+ plugin to sync local files to VM over SSH using Unison"
|
13
|
+
|
14
|
+
s.required_rubygems_version = ">= 1.3.6"
|
15
|
+
|
16
|
+
s.add_development_dependency 'rake', '< 11.0'
|
17
|
+
s.add_development_dependency "rspec-core", "~> 2.12.2"
|
18
|
+
s.add_development_dependency "rspec-expectations", "~> 2.12.1"
|
19
|
+
s.add_development_dependency "rspec-mocks", "~> 2.12.1"
|
20
|
+
|
21
|
+
# The following block of code determines the files that should be included
|
22
|
+
# in the gem. It does this by reading all the files in the directory where
|
23
|
+
# this gemspec is, and parsing out the ignored files from the gitignore.
|
24
|
+
# Note that the entire gitignore(5) syntax is not supported, specifically
|
25
|
+
# the "!" syntax, but it should mostly work correctly.
|
26
|
+
root_path = File.dirname(__FILE__)
|
27
|
+
all_files = Dir.chdir(root_path) { Dir.glob("**/{*,.*}") }
|
28
|
+
all_files.reject! { |file| [".", ".."].include?(File.basename(file)) }
|
29
|
+
gitignore_path = File.join(root_path, ".gitignore")
|
30
|
+
gitignore = File.readlines(gitignore_path)
|
31
|
+
gitignore.map! { |line| line.chomp.strip }
|
32
|
+
gitignore.reject! { |line| line.empty? || line =~ /^(#|!)/ }
|
33
|
+
|
34
|
+
unignored_files = all_files.reject do |file|
|
35
|
+
# Ignore any directories, the gemspec only cares about files
|
36
|
+
next true if File.directory?(file)
|
37
|
+
|
38
|
+
# Ignore any paths that match anything in the gitignore. We do
|
39
|
+
# two tests here:
|
40
|
+
#
|
41
|
+
# - First, test to see if the entire path matches the gitignore.
|
42
|
+
# - Second, match if the basename does, this makes it so that things
|
43
|
+
# like '.DS_Store' will match sub-directories too (same behavior
|
44
|
+
# as git).
|
45
|
+
#
|
46
|
+
gitignore.any? do |ignore|
|
47
|
+
File.fnmatch(ignore, file, File::FNM_PATHNAME) ||
|
48
|
+
File.fnmatch(ignore, File.basename(file), File::FNM_PATHNAME)
|
49
|
+
end
|
50
|
+
end
|
51
|
+
|
52
|
+
s.files = unignored_files
|
53
|
+
s.executables = unignored_files.map { |f| f[/^bin\/(.*)/, 1] }.compact
|
54
|
+
s.require_path = 'lib'
|
55
|
+
end
|
metadata
ADDED
@@ -0,0 +1,119 @@
|
|
1
|
+
--- !ruby/object:Gem::Specification
|
2
|
+
name: vagrant-vaimo-unison
|
3
|
+
version: !ruby/object:Gem::Version
|
4
|
+
version: 0.0.1
|
5
|
+
platform: ruby
|
6
|
+
authors:
|
7
|
+
- David Laing
|
8
|
+
- dmatora
|
9
|
+
- Danny Cosson
|
10
|
+
autorequire:
|
11
|
+
bindir: bin
|
12
|
+
cert_chain: []
|
13
|
+
date: 2017-06-07 00:00:00.000000000 Z
|
14
|
+
dependencies:
|
15
|
+
- !ruby/object:Gem::Dependency
|
16
|
+
name: rake
|
17
|
+
requirement: !ruby/object:Gem::Requirement
|
18
|
+
requirements:
|
19
|
+
- - "<"
|
20
|
+
- !ruby/object:Gem::Version
|
21
|
+
version: '11.0'
|
22
|
+
type: :development
|
23
|
+
prerelease: false
|
24
|
+
version_requirements: !ruby/object:Gem::Requirement
|
25
|
+
requirements:
|
26
|
+
- - "<"
|
27
|
+
- !ruby/object:Gem::Version
|
28
|
+
version: '11.0'
|
29
|
+
- !ruby/object:Gem::Dependency
|
30
|
+
name: rspec-core
|
31
|
+
requirement: !ruby/object:Gem::Requirement
|
32
|
+
requirements:
|
33
|
+
- - "~>"
|
34
|
+
- !ruby/object:Gem::Version
|
35
|
+
version: 2.12.2
|
36
|
+
type: :development
|
37
|
+
prerelease: false
|
38
|
+
version_requirements: !ruby/object:Gem::Requirement
|
39
|
+
requirements:
|
40
|
+
- - "~>"
|
41
|
+
- !ruby/object:Gem::Version
|
42
|
+
version: 2.12.2
|
43
|
+
- !ruby/object:Gem::Dependency
|
44
|
+
name: rspec-expectations
|
45
|
+
requirement: !ruby/object:Gem::Requirement
|
46
|
+
requirements:
|
47
|
+
- - "~>"
|
48
|
+
- !ruby/object:Gem::Version
|
49
|
+
version: 2.12.1
|
50
|
+
type: :development
|
51
|
+
prerelease: false
|
52
|
+
version_requirements: !ruby/object:Gem::Requirement
|
53
|
+
requirements:
|
54
|
+
- - "~>"
|
55
|
+
- !ruby/object:Gem::Version
|
56
|
+
version: 2.12.1
|
57
|
+
- !ruby/object:Gem::Dependency
|
58
|
+
name: rspec-mocks
|
59
|
+
requirement: !ruby/object:Gem::Requirement
|
60
|
+
requirements:
|
61
|
+
- - "~>"
|
62
|
+
- !ruby/object:Gem::Version
|
63
|
+
version: 2.12.1
|
64
|
+
type: :development
|
65
|
+
prerelease: false
|
66
|
+
version_requirements: !ruby/object:Gem::Requirement
|
67
|
+
requirements:
|
68
|
+
- - "~>"
|
69
|
+
- !ruby/object:Gem::Version
|
70
|
+
version: 2.12.1
|
71
|
+
description: Vagrant 1.7+ plugin to sync local files to VM over SSH using Unison
|
72
|
+
email: dcosson@gmail.com
|
73
|
+
executables: []
|
74
|
+
extensions: []
|
75
|
+
extra_rdoc_files: []
|
76
|
+
files:
|
77
|
+
- ".gitignore"
|
78
|
+
- CHANGELOG.md
|
79
|
+
- Gemfile
|
80
|
+
- LICENSE
|
81
|
+
- README.md
|
82
|
+
- Rakefile
|
83
|
+
- lib/vagrant-vaimo-unison.rb
|
84
|
+
- lib/vagrant-vaimo-unison/command.rb
|
85
|
+
- lib/vagrant-vaimo-unison/config.rb
|
86
|
+
- lib/vagrant-vaimo-unison/errors.rb
|
87
|
+
- lib/vagrant-vaimo-unison/plugin.rb
|
88
|
+
- lib/vagrant-vaimo-unison/shell_command.rb
|
89
|
+
- lib/vagrant-vaimo-unison/ssh_command.rb
|
90
|
+
- lib/vagrant-vaimo-unison/unison_paths.rb
|
91
|
+
- lib/vagrant-vaimo-unison/unison_sync.rb
|
92
|
+
- lib/vagrant-vaimo-unison/version.rb
|
93
|
+
- locales/en.yml
|
94
|
+
- spec/vagrant-unison/config_spec.rb
|
95
|
+
- vagrant-vaimo-unison.gemspec
|
96
|
+
homepage: http://github.com/dcosson/vagrant-unison
|
97
|
+
licenses: []
|
98
|
+
metadata: {}
|
99
|
+
post_install_message:
|
100
|
+
rdoc_options: []
|
101
|
+
require_paths:
|
102
|
+
- lib
|
103
|
+
required_ruby_version: !ruby/object:Gem::Requirement
|
104
|
+
requirements:
|
105
|
+
- - ">="
|
106
|
+
- !ruby/object:Gem::Version
|
107
|
+
version: '0'
|
108
|
+
required_rubygems_version: !ruby/object:Gem::Requirement
|
109
|
+
requirements:
|
110
|
+
- - ">="
|
111
|
+
- !ruby/object:Gem::Version
|
112
|
+
version: 1.3.6
|
113
|
+
requirements: []
|
114
|
+
rubyforge_project:
|
115
|
+
rubygems_version: 2.6.12
|
116
|
+
signing_key:
|
117
|
+
specification_version: 4
|
118
|
+
summary: Vagrant 1.7+ plugin to sync local files to VM over SSH using Unison
|
119
|
+
test_files: []
|