webmake 1.1.0
Sign up to get free protection for your applications and to get access to all the features.
- data/lib/ftp.rb +175 -0
- data/lib/wake.rb +149 -0
- data/sample/Wakefile +20 -0
- data/wake +15 -0
- metadata +105 -0
data/lib/ftp.rb
ADDED
@@ -0,0 +1,175 @@
|
|
1
|
+
require 'net/ftp'
|
2
|
+
require 'net/sftp'
|
3
|
+
|
4
|
+
class Ftp
|
5
|
+
|
6
|
+
def initialize(config)
|
7
|
+
@config = config
|
8
|
+
connect
|
9
|
+
end
|
10
|
+
|
11
|
+
def connect
|
12
|
+
if @config["sftp"]
|
13
|
+
@connection = Net::SFTP.start(@config["host"], @config["username"], :password => @config["password"])
|
14
|
+
else
|
15
|
+
@connection = Net::FTP.new(@config["host"])
|
16
|
+
@connection.login(@config["username"], @config["password"])
|
17
|
+
end
|
18
|
+
|
19
|
+
true
|
20
|
+
rescue
|
21
|
+
false
|
22
|
+
end
|
23
|
+
|
24
|
+
def close
|
25
|
+
@connection.close unless @config["sftp"]
|
26
|
+
true
|
27
|
+
end
|
28
|
+
|
29
|
+
def connected?
|
30
|
+
! @connection.nil?
|
31
|
+
end
|
32
|
+
|
33
|
+
def list(dir)
|
34
|
+
if @config["sftp"]
|
35
|
+
files = []
|
36
|
+
@connection.dir.foreach(dir) do |entry|
|
37
|
+
permissions = entry.longname.split(" ")[0]
|
38
|
+
files << [entry.name, !entry.longname.starts_with("d"), permissions_from_string(permissions)] unless [".", ".."].include? entry.name
|
39
|
+
end
|
40
|
+
files
|
41
|
+
else
|
42
|
+
@connection.chdir(dir)
|
43
|
+
list = []
|
44
|
+
@connection.ls("-a").each do |file|
|
45
|
+
if file.size() > 8
|
46
|
+
filename = ""
|
47
|
+
filehold = file.split(" ")[8..-1] # get filename or directory name
|
48
|
+
filehold.each {|name_segment| filename += " #{name_segment}" }
|
49
|
+
filename.lstrip!
|
50
|
+
|
51
|
+
# if this is a directory a d or ASCII 100 will be the first character
|
52
|
+
# 45 means its just a file
|
53
|
+
# anything else is garbage
|
54
|
+
unless [".", ".."].include? filename
|
55
|
+
if file[0] == 45
|
56
|
+
list << [filename, true]
|
57
|
+
elsif file[0] == 100
|
58
|
+
list << [filename, false]
|
59
|
+
end
|
60
|
+
end
|
61
|
+
end
|
62
|
+
end
|
63
|
+
|
64
|
+
list
|
65
|
+
end
|
66
|
+
rescue
|
67
|
+
[]
|
68
|
+
end
|
69
|
+
|
70
|
+
def publish(path, create_dirs_on_failure = true)
|
71
|
+
remote_path = prepare_remote_path(path)
|
72
|
+
|
73
|
+
if @config["sftp"]
|
74
|
+
@connection.upload!(path, remote_path)
|
75
|
+
else
|
76
|
+
@connection.put(path, remote_path)
|
77
|
+
end
|
78
|
+
|
79
|
+
true
|
80
|
+
rescue
|
81
|
+
if create_dirs_on_failure
|
82
|
+
create_directories(remote_path)
|
83
|
+
return publish(path, false)
|
84
|
+
end
|
85
|
+
|
86
|
+
false
|
87
|
+
end
|
88
|
+
|
89
|
+
def create_directories(path)
|
90
|
+
segments = File.dirname(path).gsub(/^\/?(.+?)\/?$/, "\\1").split("/")
|
91
|
+
|
92
|
+
dir = ""
|
93
|
+
dir = "/" if path[0, 1] == "/"
|
94
|
+
|
95
|
+
segments.each do |segment|
|
96
|
+
dir << "#{segment}/"
|
97
|
+
|
98
|
+
begin
|
99
|
+
@connection.mkdir(dir)
|
100
|
+
rescue
|
101
|
+
# This dir already exist, move on.
|
102
|
+
end
|
103
|
+
end
|
104
|
+
end
|
105
|
+
|
106
|
+
def create_dir(path)
|
107
|
+
path = prepare_remote_path(path)
|
108
|
+
|
109
|
+
create_directories(path)
|
110
|
+
@connection.mkdir(path)
|
111
|
+
true
|
112
|
+
rescue
|
113
|
+
false
|
114
|
+
end
|
115
|
+
|
116
|
+
def delete_file(path)
|
117
|
+
path = prepare_remote_path(path) unless path.match(/^#{Regexp.escape(@config["root"])}/)
|
118
|
+
|
119
|
+
if @config["sftp"]
|
120
|
+
@connection.remove!(path)
|
121
|
+
true
|
122
|
+
else
|
123
|
+
@connection.delete(path)
|
124
|
+
true
|
125
|
+
end
|
126
|
+
rescue
|
127
|
+
false
|
128
|
+
end
|
129
|
+
|
130
|
+
def delete_dir(path)
|
131
|
+
path = prepare_remote_path(path) unless path.match(/^#{Regexp.escape(@config["root"])}/)
|
132
|
+
|
133
|
+
if @config["sftp"]
|
134
|
+
@connection.dir.entries(path).each do |entry|
|
135
|
+
next if entry.name == '.' or entry.name == '..'
|
136
|
+
|
137
|
+
child_path = File.join(path, entry.name)
|
138
|
+
|
139
|
+
if @connection.stat!(child_path).directory?
|
140
|
+
delete_dir(child_path)
|
141
|
+
else
|
142
|
+
delete_file(child_path)
|
143
|
+
end
|
144
|
+
end
|
145
|
+
|
146
|
+
@connection.rmdir!(path)
|
147
|
+
true
|
148
|
+
else
|
149
|
+
file_list = list(path)
|
150
|
+
|
151
|
+
file_list.each do |thefile|
|
152
|
+
filename = thefile[0]
|
153
|
+
# Files are True
|
154
|
+
if thefile[1]
|
155
|
+
delete_file(File.join(path, filename))
|
156
|
+
else
|
157
|
+
if filename != "." and filename != ".."
|
158
|
+
delete_dir(File.join(path, filename))
|
159
|
+
end
|
160
|
+
end
|
161
|
+
end
|
162
|
+
|
163
|
+
@connection.rmdir(path)
|
164
|
+
true
|
165
|
+
end
|
166
|
+
rescue
|
167
|
+
false
|
168
|
+
end
|
169
|
+
|
170
|
+
def prepare_remote_path(local_path)
|
171
|
+
path = local_path.gsub(/^#{Regexp.escape(Dir.pwd)}\//, "")
|
172
|
+
File.join(@config["root"], path)
|
173
|
+
end
|
174
|
+
|
175
|
+
end
|
data/lib/wake.rb
ADDED
@@ -0,0 +1,149 @@
|
|
1
|
+
require 'rubygems'
|
2
|
+
require 'find'
|
3
|
+
require 'yaml'
|
4
|
+
require "#{File.expand_path("..", __FILE__)}/ftp"
|
5
|
+
require 'fileutils'
|
6
|
+
|
7
|
+
module Wake
|
8
|
+
|
9
|
+
def self.public_methods
|
10
|
+
['help', 'init', 'sync', 'set_synced']
|
11
|
+
end
|
12
|
+
|
13
|
+
# ----------------------------------------------------------------------
|
14
|
+
# Callable methods
|
15
|
+
# ----------------------------------------------------------------------
|
16
|
+
|
17
|
+
def self.help(e = nil)
|
18
|
+
puts "Wake only has three basic commands."
|
19
|
+
puts " init - Initializes a new Wake project and creates a sample Wakefile."
|
20
|
+
puts " sync - Publishes any changes in the filetree (including deletes)."
|
21
|
+
puts " set_synced - Set the project as synchronized without publishing changes."
|
22
|
+
end
|
23
|
+
|
24
|
+
def self.init(e = nil)
|
25
|
+
config_file = File.join(Dir.pwd, "Wakefile")
|
26
|
+
release_dir = File.join(Dir.pwd, ".wake")
|
27
|
+
|
28
|
+
FileUtils.mkdir release_dir unless File.exists? release_dir
|
29
|
+
|
30
|
+
unless File.exists? config_file
|
31
|
+
wakefile_sample = File.expand_path("..", __FILE__)+"/../sample/Wakefile"
|
32
|
+
FileUtils.cp wakefile_sample, Dir.pwd
|
33
|
+
end
|
34
|
+
end
|
35
|
+
|
36
|
+
def self.set_synced(environment = "development")
|
37
|
+
self.get_tree_diff(environment)
|
38
|
+
puts "Environment #{environment} is now set as synced."
|
39
|
+
end
|
40
|
+
|
41
|
+
def self.sync(environment = "development")
|
42
|
+
config_file = File.join(Dir.pwd, "Wakefile")
|
43
|
+
|
44
|
+
unless File.exists? config_file
|
45
|
+
puts "This project has no Wakefile."
|
46
|
+
return
|
47
|
+
end
|
48
|
+
|
49
|
+
config = YAML::load(File.open(config_file).read)
|
50
|
+
|
51
|
+
unless config.has_key? environment
|
52
|
+
puts "#{environment.capitalize} environment is not defined in Wakefile."
|
53
|
+
end
|
54
|
+
|
55
|
+
synchronize(environment, config[environment])
|
56
|
+
end
|
57
|
+
|
58
|
+
def self.synchronize(environment, config)
|
59
|
+
diff_tree = self.get_tree_diff(environment)
|
60
|
+
|
61
|
+
ftp = Ftp.new(config)
|
62
|
+
diff_tree.each do |filename, stats|
|
63
|
+
if stats[:is_dir]
|
64
|
+
ftp.delete_dir(filename) if stats[:status] == :delete
|
65
|
+
ftp.create_dir(filename) if stats[:status] == :publish
|
66
|
+
else
|
67
|
+
ftp.delete_file(filename) if stats[:status] == :delete
|
68
|
+
ftp.publish(filename) if stats[:status] == :publish
|
69
|
+
end
|
70
|
+
end
|
71
|
+
end
|
72
|
+
|
73
|
+
# ----------------------------------------------------------------------
|
74
|
+
# "Private" methods
|
75
|
+
# ----------------------------------------------------------------------
|
76
|
+
|
77
|
+
def self.get_tree_diff(environment)
|
78
|
+
old_tree = self.get_old_tree(environment)
|
79
|
+
current_tree = self.get_current_tree
|
80
|
+
|
81
|
+
last_release = self.get_last_release_date(environment)
|
82
|
+
|
83
|
+
diff_tree = {}
|
84
|
+
|
85
|
+
# Find out if any files have been added or updated since the last release.
|
86
|
+
current_tree.each do |filename, is_dir|
|
87
|
+
if File.ctime(filename) > last_release
|
88
|
+
diff_tree[filename] = {
|
89
|
+
:is_dir => is_dir,
|
90
|
+
:status => :publish
|
91
|
+
}
|
92
|
+
end
|
93
|
+
end
|
94
|
+
|
95
|
+
# Find out if any files have been removed since the last release.
|
96
|
+
old_tree.each do |filename, is_dir|
|
97
|
+
unless current_tree.has_key? filename
|
98
|
+
diff_tree[filename] = {
|
99
|
+
:is_dir => is_dir,
|
100
|
+
:status => :delete
|
101
|
+
}
|
102
|
+
end
|
103
|
+
end
|
104
|
+
|
105
|
+
self.write_tree(environment, current_tree)
|
106
|
+
|
107
|
+
diff_tree
|
108
|
+
end
|
109
|
+
|
110
|
+
def self.get_last_release_date(environment)
|
111
|
+
tree_file = File.join(Dir.pwd, ".wake/#{environment}")
|
112
|
+
|
113
|
+
if File.exists? tree_file
|
114
|
+
return File.ctime tree_file
|
115
|
+
end
|
116
|
+
|
117
|
+
Time.at(0)
|
118
|
+
end
|
119
|
+
|
120
|
+
def self.get_old_tree(environment)
|
121
|
+
tree = {}
|
122
|
+
|
123
|
+
tree_file = File.join(Dir.pwd, ".wake/#{environment}")
|
124
|
+
if File.exists? tree_file
|
125
|
+
tree = YAML::load(File.open(tree_file).read)
|
126
|
+
end
|
127
|
+
|
128
|
+
tree
|
129
|
+
end
|
130
|
+
|
131
|
+
def self.get_current_tree
|
132
|
+
tree = {}
|
133
|
+
|
134
|
+
path = Dir.pwd
|
135
|
+
Find.find(path) do |file|
|
136
|
+
tree[file] = File.directory? file unless (file == path or file.match(/(Wakefile|\.wake)/))
|
137
|
+
end
|
138
|
+
|
139
|
+
tree
|
140
|
+
end
|
141
|
+
|
142
|
+
def self.write_tree(environment, tree)
|
143
|
+
tree_file = File.join(Dir.pwd, ".wake/#{environment}")
|
144
|
+
File.open(tree_file, 'w') do |f|
|
145
|
+
f.write YAML::dump(tree)
|
146
|
+
end
|
147
|
+
end
|
148
|
+
|
149
|
+
end
|
data/sample/Wakefile
ADDED
@@ -0,0 +1,20 @@
|
|
1
|
+
development:
|
2
|
+
sftp: false
|
3
|
+
host: "ftp.example.com"
|
4
|
+
username: "dev"
|
5
|
+
password: "dev"
|
6
|
+
root: "/var/www/dev/"
|
7
|
+
|
8
|
+
test:
|
9
|
+
sftp: false
|
10
|
+
host: "ftp.example.com"
|
11
|
+
username: "test"
|
12
|
+
password: "test"
|
13
|
+
root: "/var/www/test/"
|
14
|
+
|
15
|
+
production:
|
16
|
+
sftp: true
|
17
|
+
host: "sftp.example.com"
|
18
|
+
username: "prod"
|
19
|
+
password: "prod"
|
20
|
+
root: "/var/www/production/"
|
data/wake
ADDED
@@ -0,0 +1,15 @@
|
|
1
|
+
#!/usr/bin/env ruby
|
2
|
+
require "#{File.expand_path("..", __FILE__)}/lib/wake"
|
3
|
+
|
4
|
+
unless ARGV[0].nil?
|
5
|
+
command = ARGV[0]
|
6
|
+
|
7
|
+
if Wake.public_methods.include? command
|
8
|
+
environment = "development"
|
9
|
+
environment = ARGV[1] if ["development", "test", "production"].include? ARGV[1]
|
10
|
+
|
11
|
+
Wake.send(command, environment)
|
12
|
+
else
|
13
|
+
puts "Wake does not respond to \"#{command}\". Run \"wake help\" for more information."
|
14
|
+
end
|
15
|
+
end
|
metadata
ADDED
@@ -0,0 +1,105 @@
|
|
1
|
+
--- !ruby/object:Gem::Specification
|
2
|
+
name: webmake
|
3
|
+
version: !ruby/object:Gem::Version
|
4
|
+
hash: 19
|
5
|
+
prerelease:
|
6
|
+
segments:
|
7
|
+
- 1
|
8
|
+
- 1
|
9
|
+
- 0
|
10
|
+
version: 1.1.0
|
11
|
+
platform: ruby
|
12
|
+
authors:
|
13
|
+
- Christoffer Lejdborg
|
14
|
+
autorequire:
|
15
|
+
bindir: .
|
16
|
+
cert_chain: []
|
17
|
+
|
18
|
+
date: 2011-01-21 00:00:00 +01:00
|
19
|
+
default_executable: wake
|
20
|
+
dependencies:
|
21
|
+
- !ruby/object:Gem::Dependency
|
22
|
+
name: net-ssh
|
23
|
+
prerelease: false
|
24
|
+
requirement: &id001 !ruby/object:Gem::Requirement
|
25
|
+
none: false
|
26
|
+
requirements:
|
27
|
+
- - ">="
|
28
|
+
- !ruby/object:Gem::Version
|
29
|
+
hash: 11
|
30
|
+
segments:
|
31
|
+
- 2
|
32
|
+
- 1
|
33
|
+
- 0
|
34
|
+
version: 2.1.0
|
35
|
+
type: :runtime
|
36
|
+
version_requirements: *id001
|
37
|
+
- !ruby/object:Gem::Dependency
|
38
|
+
name: net-sftp
|
39
|
+
prerelease: false
|
40
|
+
requirement: &id002 !ruby/object:Gem::Requirement
|
41
|
+
none: false
|
42
|
+
requirements:
|
43
|
+
- - ">="
|
44
|
+
- !ruby/object:Gem::Version
|
45
|
+
hash: 5
|
46
|
+
segments:
|
47
|
+
- 2
|
48
|
+
- 0
|
49
|
+
- 5
|
50
|
+
version: 2.0.5
|
51
|
+
type: :runtime
|
52
|
+
version_requirements: *id002
|
53
|
+
description: Wake is a very simplistic synchronisation tool for web applications. You can set up three envioronments (test, development and production) and use wither FTP or SFTP to sync your sites.
|
54
|
+
email: hello@9muses.se
|
55
|
+
executables:
|
56
|
+
- wake
|
57
|
+
extensions: []
|
58
|
+
|
59
|
+
extra_rdoc_files: []
|
60
|
+
|
61
|
+
files:
|
62
|
+
- lib/ftp.rb
|
63
|
+
- lib/wake.rb
|
64
|
+
- sample/Wakefile
|
65
|
+
- ./wake
|
66
|
+
has_rdoc: true
|
67
|
+
homepage: http://github.com/Lejdborg/Wake
|
68
|
+
licenses: []
|
69
|
+
|
70
|
+
post_install_message:
|
71
|
+
rdoc_options: []
|
72
|
+
|
73
|
+
require_paths:
|
74
|
+
- lib
|
75
|
+
required_ruby_version: !ruby/object:Gem::Requirement
|
76
|
+
none: false
|
77
|
+
requirements:
|
78
|
+
- - ">="
|
79
|
+
- !ruby/object:Gem::Version
|
80
|
+
hash: 57
|
81
|
+
segments:
|
82
|
+
- 1
|
83
|
+
- 8
|
84
|
+
- 7
|
85
|
+
version: 1.8.7
|
86
|
+
required_rubygems_version: !ruby/object:Gem::Requirement
|
87
|
+
none: false
|
88
|
+
requirements:
|
89
|
+
- - ">="
|
90
|
+
- !ruby/object:Gem::Version
|
91
|
+
hash: 23
|
92
|
+
segments:
|
93
|
+
- 1
|
94
|
+
- 3
|
95
|
+
- 6
|
96
|
+
version: 1.3.6
|
97
|
+
requirements: []
|
98
|
+
|
99
|
+
rubyforge_project:
|
100
|
+
rubygems_version: 1.4.2
|
101
|
+
signing_key:
|
102
|
+
specification_version: 3
|
103
|
+
summary: FTP/SFTP sync tool.
|
104
|
+
test_files: []
|
105
|
+
|