webmake 1.1.0

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.
Files changed (5) hide show
  1. data/lib/ftp.rb +175 -0
  2. data/lib/wake.rb +149 -0
  3. data/sample/Wakefile +20 -0
  4. data/wake +15 -0
  5. metadata +105 -0
@@ -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
@@ -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
@@ -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
+