fig 1.13.0 → 1.14.0

Sign up to get free protection for your applications and to get access to all the features.
data/Changes CHANGED
@@ -1,3 +1,16 @@
1
+ v1.14.0 - 2014/2/10
2
+
3
+ New features:
4
+
5
+ - The return of SSH support, thanks to Alexey Klimkin. Note that this uses
6
+ external "ssh" and "scp" commands locally and expects to be able to run
7
+ "find", GNU "stat", and "mkdir" remotely.
8
+
9
+ v1.13.1.beta.2 - 2014/1/31
10
+ v1.13.1.beta.1 - 2014/1/30
11
+
12
+ - Test releases.
13
+
1
14
  v1.13.0 - 2013/12/3
2
15
 
3
16
  Bug fixes:
data/lib/fig.rb CHANGED
@@ -1,3 +1,3 @@
1
1
  module Fig
2
- VERSION = '1.13.0'
2
+ VERSION = '1.14.0'
3
3
  end
@@ -14,6 +14,7 @@ require 'fig/protocol/file'
14
14
  require 'fig/protocol/ftp'
15
15
  require 'fig/protocol/http'
16
16
  require 'fig/protocol/sftp'
17
+ require 'fig/protocol/ssh'
17
18
  require 'fig/repository_error'
18
19
  require 'fig/url'
19
20
  require 'fig/user_input_error'
@@ -64,6 +65,7 @@ class Fig::OperatingSystem
64
65
  @protocols['ftp'] = Fig::Protocol::FTP.new login
65
66
  @protocols['http'] = Fig::Protocol::HTTP.new
66
67
  @protocols['sftp'] = Fig::Protocol::SFTP.new
68
+ @protocols['ssh'] = Fig::Protocol::SSH.new
67
69
  end
68
70
 
69
71
  def list(dir)
@@ -19,7 +19,14 @@ class Fig::Protocol::File
19
19
  return packages if ! ::File.exist?(unescaped_path)
20
20
 
21
21
  ls = ''
22
- Find.find(unescaped_path) { |file| ls << file.to_s; ls << "\n" }
22
+ Find.find(unescaped_path) {
23
+ |file|
24
+
25
+ if FileTest.directory? file
26
+ ls << file.to_s
27
+ ls << "\n"
28
+ end
29
+ }
23
30
 
24
31
  strip_paths_for_list(ls, packages, unescaped_path)
25
32
 
@@ -0,0 +1,164 @@
1
+ require 'cgi'
2
+
3
+ require 'fig/logging'
4
+ require 'fig/network_error'
5
+ require 'fig/protocol'
6
+
7
+ module Fig; end
8
+ module Fig::Protocol; end
9
+
10
+ # File transfers using external ssh and scp programs
11
+ class Fig::Protocol::SSH
12
+ include Fig::Protocol
13
+
14
+ def download_list(uri)
15
+ packages = []
16
+ unescaped_path = CGI.unescape uri.path
17
+
18
+ ls = ssh(uri.host, 'find', unescaped_path, '-type', 'd') {
19
+ |error_message|
20
+
21
+ raise Fig::NetworkError.new error_message
22
+ }
23
+
24
+ strip_paths_for_list(ls, packages, unescaped_path)
25
+
26
+ return packages
27
+ end
28
+
29
+ # Determine whether we need to update something. Returns nil to indicate
30
+ # "don't know".
31
+ def path_up_to_date?(uri, path, prompt_for_login)
32
+ unescaped_path = CGI.unescape uri.path
33
+
34
+ size_mtime = ssh(uri.host, 'stat', '--format="%s %Z"', unescaped_path) {
35
+ |error_message|
36
+
37
+ raise Fig::NetworkError.new(
38
+ "Unable to get size and modification time for remote path #{path}: #{error_message}",
39
+ )
40
+ }
41
+
42
+ remote_size, remote_mtime = size_mtime.split
43
+ remote_size = remote_size.to_i
44
+ remote_mtime = remote_mtime.to_i
45
+
46
+ if remote_size != ::File.size(path)
47
+ return false
48
+ end
49
+
50
+ if remote_mtime <= ::File.mtime(path).to_i
51
+ return true
52
+ end
53
+
54
+ return false
55
+ end
56
+
57
+ # Returns whether the file was not downloaded because the file already
58
+ # exists and is already up-to-date.
59
+ def download(uri, path, prompt_for_login)
60
+ unescaped_path = CGI.unescape uri.path
61
+
62
+ exists = remote_path_exists(uri.host, unescaped_path) {
63
+ |error_message|
64
+
65
+ raise Fig::NetworkError.new(
66
+ "Unable to determine whether #{uri} exists: #{error_message}",
67
+ )
68
+ }
69
+ if not exists
70
+ raise Fig::FileNotFoundError.new "#{uri} doesn't exist.", uri
71
+ end
72
+
73
+ scp("#{uri.host}:#{unescaped_path}", path) {
74
+ |error_message|
75
+
76
+ raise Fig::NetworkError.new(
77
+ "Unable to copy remote file to #{path}: #{error_message}",
78
+ )
79
+ }
80
+
81
+ return true
82
+ end
83
+
84
+ def upload(local_file, uri)
85
+ unescaped_path = CGI.unescape uri.path
86
+
87
+ ssh(uri.host, 'mkdir', '-p', ::File.dirname(unescaped_path)) {
88
+ |error_message|
89
+
90
+ raise Fig::NetworkError.new(
91
+ "Unable to create directory on remote: #{error_message}",
92
+ )
93
+ }
94
+
95
+ scp(local_file, "#{uri.host}:#{unescaped_path}") {
96
+ |error_message|
97
+
98
+ raise Fig::NetworkError.new(
99
+ "Unable to copy #{local_file} to remote: #{error_message}",
100
+ )
101
+ }
102
+
103
+ return
104
+ end
105
+
106
+ private
107
+
108
+ # Execute command on remote host with external ssh program.
109
+ def ssh(host, *command, &error_block)
110
+ ssh_command = ['ssh', '-n', host, *command]
111
+ begin
112
+ output, errors, result = Fig::ExternalProgram.capture ssh_command
113
+ rescue Errno::ENOENT => error
114
+ yield %Q<Could not run "#{ssh_command.join ' '}": #{error.message}.>
115
+
116
+ return
117
+ end
118
+
119
+ if result && ! result.success?
120
+ yield %Q<Could not run "#{ssh_command.join ' '}": #{result}: #{errors}>
121
+
122
+ return
123
+ end
124
+
125
+ return output
126
+ end
127
+
128
+ def remote_path_exists(host, path, &error_block)
129
+ ssh_command = ['ssh', '-n', host, 'test', '-e', path]
130
+ begin
131
+ *, result = Fig::ExternalProgram.capture ssh_command
132
+ rescue Errno::ENOENT => error
133
+ yield %Q<Could not run "#{ssh_command.join ' '}": #{error.message}.>
134
+
135
+ return
136
+ end
137
+
138
+ if result && ! result.success?
139
+ return false
140
+ end
141
+
142
+ return true
143
+ end
144
+
145
+ # Use external scp program to copy a file.
146
+ def scp(from, to, &error_block)
147
+ command = ['scp', from, to]
148
+ begin
149
+ output, errors, result = Fig::ExternalProgram.capture command
150
+ rescue Errno::ENOENT => error
151
+ yield %Q<Could not run "#{command.join ' '}": #{error.message}.>
152
+
153
+ return
154
+ end
155
+
156
+ if result && ! result.success?
157
+ yield %Q<Could not run "#{command.join ' '}": #{result}: #{errors}>
158
+
159
+ return
160
+ end
161
+
162
+ return output
163
+ end
164
+ end
metadata CHANGED
@@ -1,7 +1,7 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: fig
3
3
  version: !ruby/object:Gem::Version
4
- version: 1.13.0
4
+ version: 1.14.0
5
5
  prerelease:
6
6
  platform: ruby
7
7
  authors:
@@ -9,11 +9,11 @@ authors:
9
9
  autorequire:
10
10
  bindir: bin
11
11
  cert_chain: []
12
- date: 2013-12-03 00:00:00.000000000 Z
12
+ date: 2014-02-10 00:00:00.000000000 Z
13
13
  dependencies:
14
14
  - !ruby/object:Gem::Dependency
15
15
  name: colorize
16
- requirement: &15094580 !ruby/object:Gem::Requirement
16
+ requirement: &24265280 !ruby/object:Gem::Requirement
17
17
  none: false
18
18
  requirements:
19
19
  - - ! '>='
@@ -21,10 +21,10 @@ dependencies:
21
21
  version: 0.5.8
22
22
  type: :runtime
23
23
  prerelease: false
24
- version_requirements: *15094580
24
+ version_requirements: *24265280
25
25
  - !ruby/object:Gem::Dependency
26
26
  name: highline
27
- requirement: &15094120 !ruby/object:Gem::Requirement
27
+ requirement: &24264820 !ruby/object:Gem::Requirement
28
28
  none: false
29
29
  requirements:
30
30
  - - ! '>='
@@ -32,10 +32,10 @@ dependencies:
32
32
  version: 1.6.19
33
33
  type: :runtime
34
34
  prerelease: false
35
- version_requirements: *15094120
35
+ version_requirements: *24264820
36
36
  - !ruby/object:Gem::Dependency
37
37
  name: json
38
- requirement: &15093660 !ruby/object:Gem::Requirement
38
+ requirement: &24264360 !ruby/object:Gem::Requirement
39
39
  none: false
40
40
  requirements:
41
41
  - - ! '>='
@@ -43,10 +43,10 @@ dependencies:
43
43
  version: '1.8'
44
44
  type: :runtime
45
45
  prerelease: false
46
- version_requirements: *15093660
46
+ version_requirements: *24264360
47
47
  - !ruby/object:Gem::Dependency
48
48
  name: libarchive-static
49
- requirement: &15093200 !ruby/object:Gem::Requirement
49
+ requirement: &24263900 !ruby/object:Gem::Requirement
50
50
  none: false
51
51
  requirements:
52
52
  - - ! '>='
@@ -54,10 +54,10 @@ dependencies:
54
54
  version: 1.0.0
55
55
  type: :runtime
56
56
  prerelease: false
57
- version_requirements: *15093200
57
+ version_requirements: *24263900
58
58
  - !ruby/object:Gem::Dependency
59
59
  name: log4r
60
- requirement: &15092740 !ruby/object:Gem::Requirement
60
+ requirement: &24263440 !ruby/object:Gem::Requirement
61
61
  none: false
62
62
  requirements:
63
63
  - - ! '>='
@@ -65,10 +65,10 @@ dependencies:
65
65
  version: 1.1.5
66
66
  type: :runtime
67
67
  prerelease: false
68
- version_requirements: *15092740
68
+ version_requirements: *24263440
69
69
  - !ruby/object:Gem::Dependency
70
70
  name: net-netrc
71
- requirement: &15092280 !ruby/object:Gem::Requirement
71
+ requirement: &24262980 !ruby/object:Gem::Requirement
72
72
  none: false
73
73
  requirements:
74
74
  - - ! '>='
@@ -76,10 +76,10 @@ dependencies:
76
76
  version: 0.2.2
77
77
  type: :runtime
78
78
  prerelease: false
79
- version_requirements: *15092280
79
+ version_requirements: *24262980
80
80
  - !ruby/object:Gem::Dependency
81
81
  name: net-sftp
82
- requirement: &15091820 !ruby/object:Gem::Requirement
82
+ requirement: &24262520 !ruby/object:Gem::Requirement
83
83
  none: false
84
84
  requirements:
85
85
  - - ! '>='
@@ -87,10 +87,10 @@ dependencies:
87
87
  version: 2.1.2
88
88
  type: :runtime
89
89
  prerelease: false
90
- version_requirements: *15091820
90
+ version_requirements: *24262520
91
91
  - !ruby/object:Gem::Dependency
92
92
  name: net-ssh
93
- requirement: &15091360 !ruby/object:Gem::Requirement
93
+ requirement: &24262060 !ruby/object:Gem::Requirement
94
94
  none: false
95
95
  requirements:
96
96
  - - ! '>='
@@ -98,10 +98,10 @@ dependencies:
98
98
  version: 2.6.7
99
99
  type: :runtime
100
100
  prerelease: false
101
- version_requirements: *15091360
101
+ version_requirements: *24262060
102
102
  - !ruby/object:Gem::Dependency
103
103
  name: open4
104
- requirement: &15090900 !ruby/object:Gem::Requirement
104
+ requirement: &24261600 !ruby/object:Gem::Requirement
105
105
  none: false
106
106
  requirements:
107
107
  - - ! '>='
@@ -109,10 +109,10 @@ dependencies:
109
109
  version: 1.0.1
110
110
  type: :runtime
111
111
  prerelease: false
112
- version_requirements: *15090900
112
+ version_requirements: *24261600
113
113
  - !ruby/object:Gem::Dependency
114
114
  name: rdoc
115
- requirement: &15090440 !ruby/object:Gem::Requirement
115
+ requirement: &24261140 !ruby/object:Gem::Requirement
116
116
  none: false
117
117
  requirements:
118
118
  - - ! '>='
@@ -120,10 +120,10 @@ dependencies:
120
120
  version: '4'
121
121
  type: :runtime
122
122
  prerelease: false
123
- version_requirements: *15090440
123
+ version_requirements: *24261140
124
124
  - !ruby/object:Gem::Dependency
125
125
  name: treetop
126
- requirement: &15089980 !ruby/object:Gem::Requirement
126
+ requirement: &24260680 !ruby/object:Gem::Requirement
127
127
  none: false
128
128
  requirements:
129
129
  - - ! '>='
@@ -131,10 +131,10 @@ dependencies:
131
131
  version: 1.4.14
132
132
  type: :runtime
133
133
  prerelease: false
134
- version_requirements: *15089980
134
+ version_requirements: *24260680
135
135
  - !ruby/object:Gem::Dependency
136
136
  name: bundler
137
- requirement: &15089520 !ruby/object:Gem::Requirement
137
+ requirement: &24260220 !ruby/object:Gem::Requirement
138
138
  none: false
139
139
  requirements:
140
140
  - - ! '>='
@@ -142,10 +142,10 @@ dependencies:
142
142
  version: 1.0.15
143
143
  type: :development
144
144
  prerelease: false
145
- version_requirements: *15089520
145
+ version_requirements: *24260220
146
146
  - !ruby/object:Gem::Dependency
147
147
  name: rake
148
- requirement: &15089060 !ruby/object:Gem::Requirement
148
+ requirement: &24259760 !ruby/object:Gem::Requirement
149
149
  none: false
150
150
  requirements:
151
151
  - - ! '>='
@@ -153,10 +153,10 @@ dependencies:
153
153
  version: 0.8.7
154
154
  type: :development
155
155
  prerelease: false
156
- version_requirements: *15089060
156
+ version_requirements: *24259760
157
157
  - !ruby/object:Gem::Dependency
158
158
  name: rspec
159
- requirement: &15088600 !ruby/object:Gem::Requirement
159
+ requirement: &24259300 !ruby/object:Gem::Requirement
160
160
  none: false
161
161
  requirements:
162
162
  - - ~>
@@ -164,10 +164,10 @@ dependencies:
164
164
  version: '2'
165
165
  type: :development
166
166
  prerelease: false
167
- version_requirements: *15088600
167
+ version_requirements: *24259300
168
168
  - !ruby/object:Gem::Dependency
169
169
  name: simplecov
170
- requirement: &15128000 !ruby/object:Gem::Requirement
170
+ requirement: &24258840 !ruby/object:Gem::Requirement
171
171
  none: false
172
172
  requirements:
173
173
  - - ! '>='
@@ -175,10 +175,10 @@ dependencies:
175
175
  version: 0.6.2
176
176
  type: :development
177
177
  prerelease: false
178
- version_requirements: *15128000
178
+ version_requirements: *24258840
179
179
  - !ruby/object:Gem::Dependency
180
180
  name: simplecov-html
181
- requirement: &15127540 !ruby/object:Gem::Requirement
181
+ requirement: &24292180 !ruby/object:Gem::Requirement
182
182
  none: false
183
183
  requirements:
184
184
  - - ! '>='
@@ -186,7 +186,7 @@ dependencies:
186
186
  version: 0.5.3
187
187
  type: :development
188
188
  prerelease: false
189
- version_requirements: *15127540
189
+ version_requirements: *24292180
190
190
  description: Fig is a utility for configuring environments and managing dependencies
191
191
  across a team of developers. Given a list of packages and a command to run, Fig
192
192
  builds environment variables named in those packages (e.g., CLASSPATH), then executes
@@ -302,6 +302,7 @@ files:
302
302
  - lib/fig/protocol/http.rb
303
303
  - lib/fig/protocol/netrc_enabled.rb
304
304
  - lib/fig/protocol/sftp.rb
305
+ - lib/fig/protocol/ssh.rb
305
306
  - lib/fig/repository.rb
306
307
  - lib/fig/repository_error.rb
307
308
  - lib/fig/repository_package_publisher.rb