gift 0.0.5

Sign up to get free protection for your applications and to get access to all the features.
@@ -0,0 +1,29 @@
1
+ --- !ruby/object:Gift::Recipient
2
+ connection: !ruby/object:Net::FTP
3
+ binary: true
4
+ debug_mode: false
5
+ last_response: |
6
+ 226-Options: -a
7
+ 226 3 matches total
8
+
9
+ last_response_code: "226"
10
+ mon_count: 0
11
+ mon_entering_queue: []
12
+
13
+ mon_owner:
14
+ mon_waiting_queue: []
15
+
16
+ passive: false
17
+ resume: false
18
+ sock: !ruby/object:TCPSocket {}
19
+
20
+ welcome: |
21
+ 230-User dev+involved.com.au has group access to: involved
22
+ 230 OK. Current restricted directory is /
23
+
24
+ host: involved.com.au
25
+ id: ftp-1
26
+ password: d8u2gy
27
+ path: gift-test
28
+ port: 21
29
+ username: dev+involved.com.au
@@ -0,0 +1,18 @@
1
+ # rcov generated
2
+ coverage
3
+
4
+ # jeweler generated
5
+ pkg
6
+
7
+ # yard generated
8
+ doc
9
+ .yardoc
10
+
11
+ # ctags generated
12
+ tags
13
+
14
+ # tmp directories used during testing
15
+ test/tmp
16
+ test/jeweler/version_tmp
17
+ test/version_tmp
18
+ tmp
@@ -0,0 +1,25 @@
1
+ h1. Gift - Git and FTP, the easy way
2
+
3
+ "We":http://www.involved.com.au recently adopted Ruby on Rails as our primary web application framework of choice. The marriage of Rails, Git and Heroku made for a carefree development, deployment and management strategy. Unfortunately, the reality is that we're not always able to use our favourite technologies. And more often than not often a client will have existing hosting arrangements that simply cannot (easily) support a Rails setup, or maybe we're just doing a simple Wordpress blog. Regardless - we wanted to have that same ease of deployment; a way to manage development in the style to which we have become accustomed.
4
+
5
+ So we made Gift.
6
+
7
+ h2. Usage
8
+
9
+ Install the gem:
10
+
11
+ <pre>
12
+ gem install gift
13
+ </pre>
14
+
15
+ Initialise your FTP server:
16
+
17
+ <pre>
18
+ gift wrap ftp://username:password@127.0.0.1:21
19
+ </pre>
20
+
21
+ Push your commits:
22
+
23
+ <pre>
24
+ gift deliver
25
+ </pre>
@@ -0,0 +1,17 @@
1
+ begin
2
+ require 'jeweler'
3
+ Jeweler::Tasks.new do |gemspec|
4
+ gemspec.name = "gift"
5
+ gemspec.summary = "Git and FTP, the easy way."
6
+ gemspec.description = "Gift provides a simple interface for pushing your site to a server that does not support git, via FTP."
7
+ gemspec.email = "nicholas@bruning.com.au"
8
+ gemspec.homepage = "http://github.com/thetron/gift"
9
+ gemspec.authors = ["Nicholas Bruning"]
10
+ gemspec.add_dependency('ptools', '>= 1.1.8')
11
+ gemspec.add_dependency('git', '>= 1.2.5')
12
+ gemspec.executables = ["gift"]
13
+ end
14
+ Jeweler::GemcutterTasks.new
15
+ rescue LoadError
16
+ puts "Jeweler not available. Install it with: gem install jeweler"
17
+ end
data/VERSION ADDED
@@ -0,0 +1 @@
1
+ 0.0.5
@@ -0,0 +1,40 @@
1
+ #!/usr/bin/env ruby
2
+
3
+ # == About
4
+ # Gift – Git and FTP, the easy way
5
+ # Gift provides a simple interface for pushing your site to a server that does not support git, via FTP.
6
+ #
7
+ # This version of Gift currenly only supports the master branch of a git repository.
8
+ #
9
+ # == Examples
10
+ # Start my initialising your FTP settings
11
+ # $ gift wrap ftp://username:password@127.0.0.1:21
12
+ #
13
+ # When you're ready to deploy, use:
14
+ # $ gift deliver
15
+ #
16
+ # == Usage
17
+ # $ gift wrap [server-name] ftp://username:password@127.0.0.1:21
18
+ # $ gift deliver [options]
19
+ #
20
+ # For help use: gift -h
21
+ #
22
+ # == Options
23
+ # -h, --help Displays help message
24
+ # -v, --version Display the version, then exit
25
+ # -q, --quiet Output as little as possible, overrides verbose
26
+ # -V, --verbose Verbose output
27
+ #
28
+ # == Author
29
+ # Nicholas Bruning
30
+ #
31
+ # == Copyright
32
+ # Copyright (c) 2010 Nicholas Bruning. Licensed under the MIT License:
33
+ # http://www.opensource.org/licenses/mit-license.php
34
+
35
+ # use this for testing:
36
+ # ruby lib/cli.rb wrap ftp://dev+involved.com.au:d8u2gy@involved.com.au:21/gift-test
37
+
38
+ $LOAD_PATH.unshift File.join(File.dirname(__FILE__), '..', 'lib')
39
+ require 'cli'
40
+ exit Gift::Cli.new(ARGV, STDIN).run
@@ -0,0 +1,53 @@
1
+ # Generated by jeweler
2
+ # DO NOT EDIT THIS FILE DIRECTLY
3
+ # Instead, edit Jeweler::Tasks in Rakefile, and run the gemspec command
4
+ # -*- encoding: utf-8 -*-
5
+
6
+ Gem::Specification.new do |s|
7
+ s.name = %q{gift}
8
+ s.version = "0.0.5"
9
+
10
+ s.required_rubygems_version = Gem::Requirement.new(">= 0") if s.respond_to? :required_rubygems_version=
11
+ s.authors = ["Nicholas Bruning"]
12
+ s.date = %q{2010-03-18}
13
+ s.default_executable = %q{gift}
14
+ s.description = %q{Gift provides a simple interface for pushing your site to a server that does not support git, via FTP.}
15
+ s.email = %q{nicholas@bruning.com.au}
16
+ s.executables = ["gift"]
17
+ s.extra_rdoc_files = [
18
+ "README.textile"
19
+ ]
20
+ s.files = [
21
+ ".gift/recipients.yml",
22
+ ".gitignore",
23
+ "README.textile",
24
+ "Rakefile",
25
+ "VERSION",
26
+ "bin/gift",
27
+ "gift.gemspec",
28
+ "lib/cli.rb",
29
+ "lib/recipient.rb"
30
+ ]
31
+ s.homepage = %q{http://github.com/thetron/gift}
32
+ s.rdoc_options = ["--charset=UTF-8"]
33
+ s.require_paths = ["lib"]
34
+ s.rubygems_version = %q{1.3.6}
35
+ s.summary = %q{Git and FTP, the easy way.}
36
+
37
+ if s.respond_to? :specification_version then
38
+ current_version = Gem::Specification::CURRENT_SPECIFICATION_VERSION
39
+ s.specification_version = 3
40
+
41
+ if Gem::Version.new(Gem::RubyGemsVersion) >= Gem::Version.new('1.2.0') then
42
+ s.add_runtime_dependency(%q<ptools>, [">= 1.1.8"])
43
+ s.add_runtime_dependency(%q<git>, [">= 1.2.5"])
44
+ else
45
+ s.add_dependency(%q<ptools>, [">= 1.1.8"])
46
+ s.add_dependency(%q<git>, [">= 1.2.5"])
47
+ end
48
+ else
49
+ s.add_dependency(%q<ptools>, [">= 1.1.8"])
50
+ s.add_dependency(%q<git>, [">= 1.2.5"])
51
+ end
52
+ end
53
+
@@ -0,0 +1,175 @@
1
+
2
+
3
+ require 'optparse'
4
+ require 'rdoc/usage'
5
+ require 'ostruct'
6
+ require 'date'
7
+ require 'uri'
8
+ require 'net/ftp'
9
+ require 'yaml'
10
+ require 'recipient'
11
+
12
+ module Gift
13
+ class Cli
14
+
15
+ attr_reader :options
16
+
17
+ def initialize(arguments, stdin)
18
+ @arguments = arguments
19
+ @stdin = stdin
20
+
21
+ # Set defaults
22
+ @options = OpenStruct.new
23
+ @options.verbose = false
24
+ @options.quiet = false
25
+ end
26
+
27
+ def run
28
+ if parsed_options?
29
+ puts "Start at #{DateTime.now}\n\n" if @options.verbose
30
+
31
+ output_options if @options.verbose # [Optional]
32
+
33
+ process_arguments
34
+ process_command
35
+
36
+ puts "\nFinished at #{DateTime.now}" if @options.verbose
37
+ else
38
+ output_usage
39
+ end
40
+
41
+ return 0
42
+ end
43
+
44
+ protected
45
+
46
+ def wrap
47
+ puts "Gift wrapping #{@server_address}"
48
+
49
+ #check a local git repository exists
50
+ @errors = fail(["No local git repository found"]) unless File.exists?(".git")
51
+
52
+ uri = URI.parse(@options.server_address)
53
+ recipient = Gift::Recipient.new
54
+
55
+ #recipient.id = @options.server_name
56
+ recipient.id = "ftp-1"
57
+ recipient.username = uri.userinfo.split(":")[0]
58
+ recipient.password = uri.userinfo.split(":")[1]
59
+ recipient.host = uri.host
60
+ recipient.port = uri.port
61
+ recipient.path = uri.path
62
+
63
+ begin
64
+ puts "Connected to #{recipient.host}" if recipient.valid_connection?
65
+
66
+ puts "Initialising remote files in #{recipient.host}/#{recipient.path}"
67
+ recipient.setup_remote_dirs
68
+ puts "Remote setup complete"
69
+
70
+ puts "Initialising local files"
71
+ recipient.setup_local_dirs
72
+ recipient.save
73
+ puts "Local setup complete"
74
+ rescue Exception => e
75
+ fail(["#{e} #{e.class}"])
76
+ end
77
+
78
+ #populate or refresh .gift/remotes.yml locally
79
+
80
+ end
81
+
82
+ def unwrap
83
+ #remove @server_name from local list
84
+
85
+ end
86
+
87
+ def deliver
88
+ recipient = Recipient.find_by_id(nil)
89
+ puts "Delivering gift to '#{recipient.id}'"
90
+ recipient.update_remote
91
+ end
92
+
93
+ def output_version
94
+ File.open(File.join(File.dirname(__FILE__), '..', 'VERSION'), "r") do |f|
95
+ f.each { |f| puts "Gift v#{f}" }
96
+ end
97
+ end
98
+
99
+ def output_help
100
+ output_version
101
+ RDoc::usage() #exits app
102
+ end
103
+
104
+ def output_usage()
105
+ RDoc::usage('usage') # gets usage from comments above
106
+ end
107
+
108
+ def fail(errors)
109
+ puts "The following errors occurred:"
110
+ puts "\t" + errors.join("\n\t") + "\t"
111
+ output_usage
112
+
113
+ exit 0;
114
+ end
115
+
116
+ def parsed_options?
117
+ # Specify options
118
+ opts = OptionParser.new
119
+
120
+ opts.on('-h', '--help') { output_help }
121
+ opts.on('-V', '--verbose') { @options.verbose = true }
122
+ opts.on('-q', '--quiet') { @options.quiet = true }
123
+
124
+ opts.on('-v', '--version') do |version|
125
+ output_version
126
+ exit 0
127
+ end
128
+
129
+ opts.parse!(@arguments) rescue return false
130
+
131
+ process_options
132
+ true
133
+ end
134
+
135
+ def process_options
136
+ @options.verbose = false if @options.quiet
137
+ end
138
+
139
+ def output_options
140
+ puts "Options:\n"
141
+
142
+ @options.marshal_dump.each do |name, val|
143
+ puts " #{name} = #{val}"
144
+ end
145
+ end
146
+
147
+ def arguments_valid?
148
+ if @command == :wrap
149
+ @options.server_address != nil
150
+ else
151
+ true
152
+ end
153
+ end
154
+
155
+ def process_arguments
156
+ @command = (@arguments.shift || 'help').to_sym
157
+
158
+ if(@command == :wrap)
159
+ @options.server_name = @arguments.shift if @arguments.length > 1
160
+ @options.server_address = @arguments.shift
161
+ elsif( [:unwrap, :delivery].include?(@command) )
162
+ @options.server_name = @arguments.shift
163
+ end
164
+ end
165
+
166
+ def process_command
167
+ if[:wrap, :unwrap, :deliver].include?(@command) && arguments_valid?
168
+ send(@command)
169
+ else
170
+ output_help
171
+ exit 0
172
+ end
173
+ end
174
+ end
175
+ end
@@ -0,0 +1,157 @@
1
+ require 'ftools'
2
+ require 'yaml'
3
+ require 'ptools'
4
+ require 'git'
5
+
6
+ module Gift
7
+ class Recipient
8
+ attr_accessor :id, :username, :password, :host, :port, :path
9
+
10
+ def valid_connection?
11
+ begin
12
+ connect
13
+ disconnect
14
+ true
15
+ rescue Exception => e
16
+ false
17
+ end
18
+ end
19
+
20
+ def setup_remote_dirs
21
+ connect
22
+ unless @connection.nlst.include?('.gift')
23
+ @connection.mkdir('.gift')
24
+ else
25
+ puts 'Remote gift directory already exists'
26
+ end
27
+
28
+ @connection.chdir('.gift')
29
+
30
+ unless @connection.nlst.include?('deliveries')
31
+ @connection.mkdir('deliveries')
32
+ else
33
+ puts 'Remote deliveries directory already exists'
34
+ end
35
+ disconnect
36
+ end
37
+
38
+ def setup_local_dirs
39
+ File.makedirs '.gift' unless File.exists?('.gift')
40
+ File.makedirs '.gift/deliveries' unless File.exists?('.gift/deliveries')
41
+ File.makedirs ".gift/deliveries/#{self.id}"# unless File.exists?(".gift/deliveries/#{self.id}")
42
+ end
43
+
44
+ def update_remote
45
+ repo = Git.open('./')
46
+
47
+ remote_commit = last_remote_commit
48
+ remote_commit = repo.log.to_a.last.sha if remote_commit == ""
49
+
50
+ file_count = 0
51
+
52
+ puts("Last remote commit: #{remote_commit} | Current local commit: #{repo.log.to_a.first.sha}")
53
+
54
+ connect
55
+ repo.diff(remote_commit, repo.log.to_a.first.sha).each do |file|
56
+ unless(file.path.split('/').first == ".gift")
57
+ if file.type == "deleted"
58
+ begin
59
+ size = @connection.size(file.path)
60
+ puts "Deleting #{file.path} [ ] 0%"
61
+ delete_remote_file(file.path)
62
+ rescue Exception => e
63
+ puts "Delete skipped #{file.path} (file not found)"
64
+ end
65
+ else
66
+ puts "Uploading #{file.path} [ ] 0%"
67
+ upload_file(file.path)
68
+ end
69
+ end
70
+ file_count += 1
71
+ end
72
+ disconnect
73
+
74
+ if file_count == 0
75
+ puts "Everything up to date!"
76
+ else
77
+ save_commit(repo.log.to_a.first.sha)
78
+ end
79
+ end
80
+
81
+ def last_remote_commit
82
+ sha = ""
83
+ connect
84
+ @connection.chdir('.gift/deliveries')
85
+ if @connection.nlst.length > 2
86
+ @connection.gettextfile(@connection.nlst.last) do |f|
87
+ sha = f
88
+ end
89
+ end
90
+ disconnect
91
+
92
+ sha
93
+ end
94
+
95
+ def save_commit(sha)
96
+ file_name = ".gift/deliveries/#{id}/#{Time.now.to_i.to_s}"
97
+ fp = File.open(file_name, "w")
98
+ fp.puts sha
99
+ fp.close
100
+
101
+ connect
102
+ @connection.chdir('.gift/deliveries')
103
+ @connection.puttextfile(file_name)
104
+ disconnect
105
+
106
+ puts "Remote state saved"
107
+ end
108
+
109
+ def save
110
+ unless self.id
111
+ self.id = "ftp-1"
112
+ end
113
+
114
+ yaml = YAML::dump(self)
115
+ fp = open('.gift/recipients.yml', 'w')
116
+ fp.write(yaml)
117
+ fp.close
118
+ end
119
+
120
+ def connect
121
+ @connection = Net::FTP.new(host, username, password)
122
+ @connection.chdir(path)
123
+ end
124
+
125
+ def disconnect
126
+ @connection.close
127
+ end
128
+
129
+ def self.find_by_id(id)
130
+ #search recipients.yml for id
131
+ YAML::load_file('.gift/recipients.yml')
132
+ end
133
+
134
+ def self.all
135
+ YAML::load_file('.gift/recipients.yml')
136
+ end
137
+
138
+ protected
139
+
140
+ def upload_file(filename)
141
+ #this will also have to create any missing dirs (unless they're handled the same as files)
142
+ connect
143
+ if File.binary?(filename)
144
+ @connection.putbinaryfile(filename)
145
+ else
146
+ @connection.puttextfile(filename)
147
+ end
148
+ disconnect
149
+ end
150
+
151
+ def delete_remote_file(filename)
152
+ connect
153
+ @connection.delete(filename)
154
+ disconnect
155
+ end
156
+ end
157
+ end
metadata ADDED
@@ -0,0 +1,97 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: gift
3
+ version: !ruby/object:Gem::Version
4
+ prerelease: false
5
+ segments:
6
+ - 0
7
+ - 0
8
+ - 5
9
+ version: 0.0.5
10
+ platform: ruby
11
+ authors:
12
+ - Nicholas Bruning
13
+ autorequire:
14
+ bindir: bin
15
+ cert_chain: []
16
+
17
+ date: 2010-03-18 00:00:00 +11:00
18
+ default_executable: gift
19
+ dependencies:
20
+ - !ruby/object:Gem::Dependency
21
+ name: ptools
22
+ prerelease: false
23
+ requirement: &id001 !ruby/object:Gem::Requirement
24
+ requirements:
25
+ - - ">="
26
+ - !ruby/object:Gem::Version
27
+ segments:
28
+ - 1
29
+ - 1
30
+ - 8
31
+ version: 1.1.8
32
+ type: :runtime
33
+ version_requirements: *id001
34
+ - !ruby/object:Gem::Dependency
35
+ name: git
36
+ prerelease: false
37
+ requirement: &id002 !ruby/object:Gem::Requirement
38
+ requirements:
39
+ - - ">="
40
+ - !ruby/object:Gem::Version
41
+ segments:
42
+ - 1
43
+ - 2
44
+ - 5
45
+ version: 1.2.5
46
+ type: :runtime
47
+ version_requirements: *id002
48
+ description: Gift provides a simple interface for pushing your site to a server that does not support git, via FTP.
49
+ email: nicholas@bruning.com.au
50
+ executables:
51
+ - gift
52
+ extensions: []
53
+
54
+ extra_rdoc_files:
55
+ - README.textile
56
+ files:
57
+ - .gift/recipients.yml
58
+ - .gitignore
59
+ - README.textile
60
+ - Rakefile
61
+ - VERSION
62
+ - bin/gift
63
+ - gift.gemspec
64
+ - lib/cli.rb
65
+ - lib/recipient.rb
66
+ has_rdoc: true
67
+ homepage: http://github.com/thetron/gift
68
+ licenses: []
69
+
70
+ post_install_message:
71
+ rdoc_options:
72
+ - --charset=UTF-8
73
+ require_paths:
74
+ - lib
75
+ required_ruby_version: !ruby/object:Gem::Requirement
76
+ requirements:
77
+ - - ">="
78
+ - !ruby/object:Gem::Version
79
+ segments:
80
+ - 0
81
+ version: "0"
82
+ required_rubygems_version: !ruby/object:Gem::Requirement
83
+ requirements:
84
+ - - ">="
85
+ - !ruby/object:Gem::Version
86
+ segments:
87
+ - 0
88
+ version: "0"
89
+ requirements: []
90
+
91
+ rubyforge_project:
92
+ rubygems_version: 1.3.6
93
+ signing_key:
94
+ specification_version: 3
95
+ summary: Git and FTP, the easy way.
96
+ test_files: []
97
+