gift 0.0.5

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,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
+