frank 1.0.9 → 1.0.10

Sign up to get free protection for your applications and to get access to all the features.
@@ -0,0 +1,80 @@
1
+ require 'frank/publish/base'
2
+ require 'net/ftptls'
3
+
4
+ module Frank
5
+ module Publish
6
+
7
+ class FTPTLS < Base
8
+
9
+ def initialize(options, &block)
10
+ super(options)
11
+ instance_eval(&block) if block_given?
12
+
13
+ @port ||= 21
14
+ @remote_path = remote_path.sub(/^\~\//, '').sub(/^\//, '')
15
+ end
16
+
17
+ private
18
+
19
+ ##
20
+ # Establishes a connection to the remote server
21
+ #
22
+ # Note:
23
+ # Since the FTP port is defined as a constant in the Net::FTP class, and
24
+ # might be required to change by the user, we dynamically remove and
25
+ # re-add the constant with the provided port value
26
+ def connection
27
+ if Net::FTPTLS.const_defined?(:FTP_PORT)
28
+ Net::FTPTLS.send(:remove_const, :FTP_PORT)
29
+ end; Net::FTPTLS.send(:const_set, :FTP_PORT, port)
30
+
31
+ Net::FTPTLS.open(hostname, username, password) do |ftp|
32
+ ftp.passive = true
33
+ yield ftp
34
+ end
35
+ end
36
+
37
+ ##
38
+ # Transfers the archived file to the specified remote server
39
+ def transfer!
40
+ connection do |ftp|
41
+ directories.each do |dir|
42
+ create_remote_path(File.join(remote_path, dir), ftp)
43
+ end
44
+
45
+ files_to_transfer.each do |file|
46
+ ok_message "Uploading #{file}", " - "
47
+ ftp.put(
48
+ File.join(local_path, file),
49
+ File.join(remote_path, file)
50
+ )
51
+ end
52
+ end
53
+ end
54
+
55
+ ##
56
+ # Creates (if they don't exist yet) all the directories on the remote
57
+ # server in order to upload the backup file. Net::FTP does not support
58
+ # paths to directories that don't yet exist when creating new
59
+ # directories. Instead, we split the parts up in to an array (for each
60
+ # '/') and loop through that to create the directories one by one.
61
+ # Net::FTP raises an exception when the directory it's trying to create
62
+ # already exists, so we have rescue it
63
+ def create_remote_path(remote_path, ftp)
64
+ path_parts = []
65
+ remote_path.split('/').each do |path_part|
66
+ path_parts << path_part
67
+ begin
68
+ dir = path_parts.join('/')
69
+ ftp.mkdir(dir) unless dir.empty?
70
+ rescue Net::FTPPermError;
71
+ end
72
+ end
73
+ end
74
+
75
+
76
+ end
77
+
78
+
79
+ end
80
+ end
@@ -0,0 +1,37 @@
1
+ require 'frank/publish/base'
2
+ require 'net/ssh'
3
+ require 'net/scp'
4
+
5
+
6
+ module Frank
7
+ module Publish
8
+ class SCP < Base
9
+
10
+ def initialize(options, &block)
11
+ super(options)
12
+ instance_eval(&block) if block_given?
13
+
14
+ @port ||= 22
15
+ end
16
+
17
+
18
+ def connection
19
+ Net::SCP.start(hostname, username, :password => password) do |scp|
20
+ yield scp
21
+ end
22
+ end
23
+
24
+ def transfer!
25
+ connection do |scp|
26
+ old_name = ''
27
+ scp.upload! local_path, remote_path do |ch, name|
28
+ if old_name != name
29
+ ok_message "Uploading #{name}", " - "
30
+ end
31
+ end
32
+ end
33
+ end
34
+
35
+ end
36
+ end
37
+ end
@@ -0,0 +1,37 @@
1
+ require 'frank/publish/base'
2
+ require 'net/ssh'
3
+ require 'net/sftp'
4
+
5
+
6
+ module Frank
7
+ module Publish
8
+ class SFTP < Base
9
+
10
+ def initialize(options, &block)
11
+ super(options)
12
+ instance_eval(&block) if block_given?
13
+
14
+ @port ||= 22
15
+ end
16
+
17
+
18
+ def connection
19
+ Net::SFTP.start(hostname, username, :password => password) do |scp|
20
+ yield scp
21
+ end
22
+ end
23
+
24
+ def transfer!
25
+ connection do |scp|
26
+ old_name = ''
27
+ scp.upload! local_path, remote_path do |ch, name|
28
+ if old_name != name
29
+ ok_message "Uploading #{name}", " - "
30
+ end
31
+ end
32
+ end
33
+ end
34
+
35
+ end
36
+ end
37
+ end
@@ -0,0 +1,29 @@
1
+ module Frank
2
+ module Publish
3
+
4
+ #TODO
5
+
6
+ class ShellSCP
7
+
8
+
9
+ def self.shell_copy(local_dir, remote_dir, options)
10
+
11
+ host = []
12
+ command = ["scp "]
13
+ command << "-P #{options[:port]} " if options[:port]
14
+ command << "-r #{local_dir}/* "
15
+ host << "#{options[:username]}" if options[:username]
16
+ host << ":#{options[:password]}" if options[:password]
17
+ host << "@#{options[:host]}:#{remote_dir}"
18
+
19
+ shell_command = "#{command.join('')}#{host.join('')}"
20
+ system(shell_command)
21
+
22
+ end
23
+
24
+
25
+ end
26
+
27
+
28
+ end
29
+ end
@@ -43,6 +43,7 @@ module Frank
43
43
  @publish.path = nil
44
44
  @publish.username = nil
45
45
  @publish.password = nil
46
+ @publish.mode = nil
46
47
 
47
48
  # setup folders
48
49
  @static_folder = "static"
@@ -1,3 +1,3 @@
1
1
  module Frank
2
- VERSION = '1.0.9'
2
+ VERSION = '1.0.10'
3
3
  end
@@ -53,7 +53,8 @@ Frank.export.path = "exported"
53
53
  # Publish settings:
54
54
  #
55
55
  # Frank can publish your exported project to
56
- # a server. All you have to do is tell Frank what host, path, and username.
56
+ # a remote server via scp (default) or ftp. All you have to do is tell Frank what host, path, and username.
57
+ # Depending on the chosen mode, you may need to install net-scp or net-sftp.
57
58
  # If you have ssh keys setup there is no need for a password.
58
59
  # Just uncomment the Publish settings below and
59
60
  # make the appropriate changes.
@@ -63,6 +64,8 @@ Frank.export.path = "exported"
63
64
  # Frank.publish.username = 'me'
64
65
  # Frank.publish.password = 'secret'
65
66
  # Frank.publish.port = 22
67
+ # Frank.publish.mode = :scp (or :ftp, :ftptls, :sftp) #no ftptls in ruby 1.9
68
+ #
66
69
  #
67
70
 
68
71
  # ----------------------
@@ -1,4 +1,4 @@
1
- require File.dirname(__FILE__) + '/helper'
1
+ require File.dirname(__FILE__) + '/spec_helper'
2
2
 
3
3
  describe Frank::Base do
4
4
  include Rack::Test::Methods
@@ -26,14 +26,14 @@ describe Frank::Base do
26
26
  get '/'
27
27
 
28
28
  last_response.should be_ok
29
- last_response.body.should == "<div id='p'>/</div>\n<div id='layout'>\n <h1>hello worlds</h1>\n <h2>/</h2>\n</div>\n"
29
+ last_response.body.strip.should == "<div id='p'>/</div>\n<div id='layout'>\n <h1>hello worlds</h1>\n <h2>/</h2>\n</div>"
30
30
  end
31
31
 
32
32
  it 'renders a page and uses a helper' do
33
33
  get '/helper_test'
34
34
 
35
35
  last_response.should be_ok
36
- last_response.body.should == "<div id='p'>/helper_test</div>\n<div id='layout'>\n <h1>hello from helper</h1>\n</div>\n"
36
+ last_response.body.strip.should == "<div id='p'>/helper_test</div>\n<div id='layout'>\n <h1>hello from helper</h1>\n</div>"
37
37
  end
38
38
 
39
39
  it 'renders a nested template given a request' do
@@ -51,7 +51,7 @@ describe Frank::Base do
51
51
  end
52
52
 
53
53
  it 'renders a 404 page if template not found' do
54
- get '/not_here.css'
54
+ capture_stdout { get '/not_here.css' }
55
55
 
56
56
  last_response.should_not be_ok
57
57
  last_response.content_type.should == 'text/html'
@@ -68,7 +68,7 @@ describe Frank::Base do
68
68
  it 'stubs out a project' do
69
69
  out = capture_stdout { Frank.stub('stubbed') }
70
70
  Dir.entries('stubbed').should == Dir.entries(File.join(LIBDIR, 'template'))
71
- response = "\nFrank is...\n - \e[32mCreating\e[0m your project 'stubbed'\n - \e[32mCopying\e[0m Frank template\n\n \e[32mCongratulations, 'stubbed' is ready to go!\e[0m\n"
71
+ response = "\nFrank is...\n - \e[32mCreating\e[0m your project 'stubbed'\n - \e[32mCopying\e[0m default Frank template\n\n \e[32mCongratulations, 'stubbed' is ready to go!\e[0m\n"
72
72
  out.string.should == response
73
73
  end
74
74
 
@@ -1,4 +1,4 @@
1
- require File.dirname(__FILE__) + '/helper'
1
+ require File.dirname(__FILE__) + '/spec_helper'
2
2
 
3
3
  describe Frank::Compile do
4
4
  include Rack::Test::Methods
@@ -14,6 +14,8 @@ describe Frank::Compile do
14
14
  end
15
15
 
16
16
  it 'creates the default export dir' do
17
+ Frank.bootstrap(proj_dir)
18
+
17
19
  Dir.chdir proj_dir do
18
20
  frank 'export'
19
21
 
@@ -0,0 +1,125 @@
1
+ # encoding: utf-8
2
+
3
+ require File.expand_path('../../spec_helper.rb', __FILE__)
4
+ require 'frank/publish/base'
5
+
6
+
7
+ describe Frank::Publish::Base do
8
+
9
+ let(:publisher) do
10
+ Frank::Publish::Base.new(Frank.publish)
11
+ end
12
+
13
+ before(:all) do
14
+ Frank.bootstrap(File.join(File.dirname(__FILE__), '..', 'template'))
15
+ end
16
+
17
+ describe '#initialize' do
18
+
19
+ it 'should set the correct values' do
20
+ publisher.username.should == 'test'
21
+ publisher.password.should == 'secret'
22
+ publisher.hostname.should == 'example.com'
23
+ publisher.remote_path.should == '/remote/path'
24
+ end
25
+
26
+ it 'should set the local export path' do
27
+ publisher.local_path =~ /\/tmp\/frank-publish-template-\d+\//
28
+ end
29
+
30
+ end
31
+
32
+ describe '#permform!' do
33
+
34
+ before do
35
+ publisher.stubs(:export!)
36
+ publisher.stubs(:transfer!)
37
+ publisher.stubs(:cleanup!)
38
+ end
39
+
40
+ it 'call export, transfer, cleanup ins that order' do
41
+ publisher.expects(:export!)
42
+ publisher.expects(:transfer!)
43
+ publisher.expects(:cleanup!)
44
+
45
+ publisher.perform!
46
+ end
47
+
48
+ end
49
+
50
+ describe '#files_to_transfer' do
51
+
52
+ it 'should list empty directories if export does not exists' do
53
+ publisher.send(:files_to_transfer).should be_empty
54
+ end
55
+
56
+ it 'should list all files' do
57
+ publisher.send(:export!)
58
+ publisher.send(:files_to_transfer).should have(26).elements
59
+ publisher.send(:files_to_transfer).should include("500.html")
60
+ publisher.send(:files_to_transfer).should_not include("files")
61
+ end
62
+
63
+ it 'should not list hidden files beginning with .' do
64
+ publisher.send(:export!)
65
+ publisher.send(:files_to_transfer).each do |elem|
66
+ elem.should_not =~ /^\./
67
+ end
68
+ end
69
+
70
+ after do
71
+ publisher.send(:cleanup!)
72
+ end
73
+
74
+ end
75
+
76
+ describe '#directories' do
77
+
78
+ it 'should list empty directories if export does not exists' do
79
+ publisher.send(:directories).should be_empty
80
+ end
81
+
82
+ it 'should list all directories' do
83
+ publisher.send(:export!)
84
+ publisher.send(:directories).should include("files", "nested", "nested/deeper", "stylesheets")
85
+ end
86
+
87
+ it 'should not list . or ..' do
88
+ publisher.send(:export!)
89
+ publisher.send(:directories).should_not include('.', '..')
90
+ end
91
+
92
+ after do
93
+ publisher.send(:cleanup!)
94
+ end
95
+
96
+ end
97
+
98
+ describe '#export!' do
99
+
100
+ it 'should export the project to the tmp folder' do
101
+ publisher.send(:export!)
102
+
103
+ publisher.local_path.should =~ /\/tmp\/frank-publish-template-\d+/
104
+ File.exist?(publisher.local_path).should be_true
105
+ end
106
+
107
+ after do
108
+ publisher.send(:cleanup!)
109
+ end
110
+
111
+ end
112
+
113
+ describe '#cleanup!' do
114
+
115
+ it 'should not leave the export folder in the tmp folder' do
116
+ publisher.send(:export!)
117
+ publisher.send(:cleanup!)
118
+
119
+ publisher.local_path.should =~ /\/tmp\/frank-publish-template-\d+/
120
+ File.exist?(publisher.local_path).should_not be_true
121
+ end
122
+
123
+ end
124
+
125
+ end
@@ -0,0 +1,143 @@
1
+ # encoding: utf-8
2
+
3
+ require File.expand_path('../../spec_helper.rb', __FILE__)
4
+ require 'frank/publish/ftp'
5
+
6
+ describe Frank::Publish::FTP do
7
+
8
+ let(:publisher) do
9
+ Frank::Publish::FTP.new(Frank.publish) do |ftp|
10
+ ftp.username = 'my_username'
11
+ ftp.password = 'my_password'
12
+ ftp.hostname = 'ftp.example.com'
13
+ ftp.local_path = '/local/path'
14
+ ftp.remote_path = '/remote/path'
15
+ end
16
+ end
17
+
18
+ before(:all) do
19
+ Frank.bootstrap(File.join(File.dirname(__FILE__), 'template'))
20
+ end
21
+
22
+ describe '#initialize' do
23
+ it 'should set the correct values' do
24
+ publisher.username.should == 'my_username'
25
+ publisher.password.should == 'my_password'
26
+ publisher.hostname.should == 'ftp.example.com'
27
+ publisher.port.should == 21
28
+ publisher.local_path.should == '/local/path'
29
+ publisher.remote_path.should == 'remote/path'
30
+
31
+ end
32
+
33
+ it 'should remove any preceeding tilde and slash from the path' do
34
+ publisher = Frank::Publish::FTP.new(Frank.publish) do |ftp|
35
+ ftp.remote_path = '~/my_backups/path'
36
+ end
37
+ publisher.remote_path.should == 'my_backups/path'
38
+ end
39
+
40
+ context 'when setting configuration defaults' do
41
+
42
+
43
+ end # context 'when setting configuration defaults'
44
+
45
+ end # describe '#initialize'
46
+
47
+ describe '#connection' do
48
+ let(:connection) { mock }
49
+
50
+ it 'should yield a connection to the remote server' do
51
+ Net::FTP.expects(:open).with(
52
+ 'ftp.example.com', 'my_username', 'my_password'
53
+ ).yields(connection)
54
+
55
+ connection.expects(:passive=).with(true)
56
+
57
+ publisher.send(:connection) do |ftp|
58
+ ftp.should be(connection)
59
+ end
60
+ end
61
+
62
+ it 'should set the Net::FTP_PORT constant' do
63
+ publisher.port = 40
64
+ Net::FTP.expects(:const_defined?).with(:FTP_PORT).returns(true)
65
+ Net::FTP.expects(:send).with(:remove_const, :FTP_PORT)
66
+ Net::FTP.expects(:send).with(:const_set, :FTP_PORT, 40)
67
+
68
+ Net::FTP.expects(:open)
69
+ publisher.send(:connection)
70
+ end
71
+
72
+ end # describe '#connection'
73
+
74
+ describe '#transfer!' do
75
+ let(:connection) { mock }
76
+ let(:package) { mock }
77
+ let(:files) { ["file1", "file2", "subdir1/file3", "subdir2/file4"] }
78
+ let(:dirs) { ["subdir1", "subdir2"] }
79
+ let(:s) { sequence '' }
80
+
81
+ before do
82
+ publisher.stubs(:connection).yields(connection)
83
+ publisher.stubs(:files_to_transfer).returns(files)
84
+ publisher.stubs(:directories).returns(dirs)
85
+ end
86
+
87
+ it 'should transfer the files' do
88
+
89
+
90
+ # connection.expects(:chdir).in_sequence(s).with('remote/path')
91
+
92
+ #publisher.expects(:directories).in_sequence(s)
93
+
94
+ publisher.expects(:create_remote_path).in_sequence(s).with('remote/path/subdir1', connection)
95
+ publisher.expects(:create_remote_path).in_sequence(s).with('remote/path/subdir2', connection)
96
+
97
+ connection.expects(:put).in_sequence(s).with(
98
+ File.join('/local/path', 'file1'),
99
+ File.join('remote/path', 'file1')
100
+ )
101
+
102
+ connection.expects(:put).in_sequence(s).with(
103
+ File.join('/local/path', 'file2'),
104
+ File.join('remote/path', 'file2')
105
+ )
106
+
107
+ connection.expects(:put).in_sequence(s).with(
108
+ File.join('/local/path', 'subdir1/file3'),
109
+ File.join('remote/path', 'subdir1/file3')
110
+ )
111
+
112
+ connection.expects(:put).in_sequence(s).with(
113
+ File.join('/local/path', 'subdir2/file4'),
114
+ File.join('remote/path', 'subdir2/file4')
115
+ )
116
+
117
+ publisher.send(:transfer!)
118
+ end
119
+ end # describe '#transfer!'
120
+
121
+
122
+ describe '#create_remote_path' do
123
+ let(:connection) { mock }
124
+ let(:remote_path) { 'remote/folder/another_folder' }
125
+ let(:s) { sequence '' }
126
+
127
+ context 'while properly creating remote directories one by one' do
128
+ it 'should rescue any FTPPermErrors and continue' do
129
+ connection.expects(:mkdir).in_sequence(s).
130
+ with("remote").raises(Net::FTPPermError)
131
+ connection.expects(:mkdir).in_sequence(s).
132
+ with("remote/folder")
133
+ connection.expects(:mkdir).in_sequence(s).
134
+ with("remote/folder/another_folder")
135
+
136
+ expect do
137
+ publisher.send(:create_remote_path, remote_path, connection)
138
+ end.not_to raise_error
139
+ end
140
+ end
141
+ end
142
+
143
+ end