frank 1.0.9 → 1.0.10

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -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