octopress-deploy 1.0.0.alpha.2 → 1.0.0.alpha.3

Sign up to get free protection for your applications and to get access to all the features.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA1:
3
- metadata.gz: 170e6e1991b426a98b1638fb45687b7016a9fc53
4
- data.tar.gz: 9b9a154ac981bc45b2e01c7c46d171176f7f61de
3
+ metadata.gz: 5e4a09550ef9b0543cffbf51047b99ef82efa4c9
4
+ data.tar.gz: 8bebda9735365b81fc5bd5feb7171bd91ffec4fe
5
5
  SHA512:
6
- metadata.gz: e6a9439fa388b44668239362ad0ccb3fab3cfb878a17f355f90bed8c5c92258fabd25321f81dcd06dc47bf0f89daf484b8b133ed7ed4f6b4c784c46878574641
7
- data.tar.gz: 17df7f348642dbb83c89b563390fa1b2e8cd8ab778e5d0a9e36682e9ba5669d6fa21e1281928971339268e7d527f1b8da5dfaa787d6dfc5511e7c5e9d0cff0d9
6
+ metadata.gz: 868c3859731c91f5cfefeb0507564d2c9bfda7d6c51209901aa8f6cffa7cd4099aa9a5c79074090deb395b3aad587f98a3cb92f03c62469e0184af393f5453ff
7
+ data.tar.gz: a887ef627c3c0f4d8e90d8594670b4bb32686a4406192b5ca19a423aede8840539912a1845c487ec6a3713592d5f84fc0e5383674be3042624737872a49294d3
data/.gitignore CHANGED
@@ -16,3 +16,13 @@ test/tmp
16
16
  test/version_tmp
17
17
  tmp
18
18
  test/.deploy
19
+ deploy_target
20
+ _s3_deploy.yml
21
+ _rsync_deploy.yml
22
+ _git_deploy.yml
23
+ pull-git
24
+ pull-rsync
25
+ pull-s3
26
+ _site
27
+ local-git
28
+ local-rsync
data/History.markdown ADDED
@@ -0,0 +1,13 @@
1
+ ## HEAD
2
+
3
+ ### Major Enhancements
4
+
5
+ ### Minor Enhancements
6
+
7
+ * Ask user if they would like to ignore the `_deploy.yml` file & automate (#7)
8
+
9
+ ### Bug Fixes
10
+
11
+ * Symbolize all incoming keys to `Octopress::Deploy.init_config` (#4)
12
+
13
+ ### Development Fixes
data/README.md CHANGED
@@ -2,7 +2,7 @@
2
2
 
3
3
  Deployment tools for Octopress and Jekyll blogs (or really any static site).
4
4
 
5
- Currently this supports deploying through Git and Rsync. Requests for other
5
+ Currently this supports deploying through S3, Git and Rsync. Requests for other
6
6
  deployment methods are welcome.
7
7
 
8
8
  ## Installation
@@ -23,46 +23,83 @@ Or install it yourself as:
23
23
 
24
24
  To deploy your site run:
25
25
 
26
- ```ruby
27
- Octopress::Deploy.push()
26
+ ```bash
27
+ $ octopress deploy
28
28
  ```
29
29
 
30
30
  This will read from your configuration file `_deploy.yml` and deploy your site. If your site has no configuration file, you will be asked if you want to generate one and what deployment method you want to use.
31
31
 
32
- You can also generate a configuration by running:
32
+ You can also generate a `./_deploy.yml` configuration file by running:
33
33
 
34
- ```ruby
35
- Octopress::Deploy.init_cofig('git') # or 'rsync'
34
+ ```bash
35
+ $ octopress deploy --init git # or 'rsync' or 's3'
36
36
  ```
37
37
 
38
- This will generate a '_deploy.yml' file in your current directory.
38
+ Once you've deployed your site, you can also pull it back down into a local directory. This is mostly useful for checking the results of a deploy. This will create the directory if it doesn't already exist.
39
+
40
+ ```ruby
41
+ Octopress::Deploy.pull('some_directory')
42
+ ```
39
43
 
40
44
  ### Configuration options
41
45
 
42
46
  Configurations should be added to a `_deploy.yml` file in your project's root directory. You can pass options as a hash directy to the `push` method as well. Passed options will override options set in the config file.
43
47
 
44
- | option | Description | Default
48
+ | Config | Description | Default
45
49
  |:--------------|:-------------------------------------------------|:---------------|
46
50
  | `config_file` | Path to the config file. | _config.yml |
47
51
  | `site_dir` | Path to comipled site files. | _site |
48
52
 
49
53
 
50
- ### Git options
54
+ #### Amazon S3
55
+
56
+ Important: when using S3, you must add your _deploy.yml to your .gitignore to prevent accidentally sharing
57
+ account access information. Octopress Deploy will offer to do it for you. If you don't, you won't be able to deploy.`
58
+
59
+ | Config | Description | Default
60
+ |:--------------------|:-----------------------------------------|:-------------|
61
+ | `bucket_name` | S3 bucket name | |
62
+ | `access_key_id` | AWS access key | |
63
+ | `secret_access_key` | AWS secret key | |
64
+ | `remote_path` | Directory files should be synced to. | / |
65
+ | `delete` | Delete files to create a 1:1 file sync. | false |
66
+ | `verbose` | Display all file actions during deploy. | true |
67
+ | `region` | Region for your AWS bucket | us-east-1 |
68
+
69
+ If you choose a bucket which doesn't yet exist, Octopress Deploy will offer to create it for you, and offer to configure it as a static website.
70
+
71
+ ##### ENV config
72
+
73
+ For the following configurations you can set environment vars instead of adding items to your config file.
74
+
75
+ | Config | ENV var |
76
+ |:--------------------|:-------------------------------|
77
+ | `access_key_id` | AWS_ACCESS_KEY_ID |
78
+ | `secret_access_key` | AWS_SECRET_ACCESS_KEY |
79
+ | `region` | AWS_DEFAULT_REGIONS |
80
+
81
+
82
+ ##### Deleting files from S3
83
+
84
+ If the `delete` option is true, files in the `remote_path` on the bucket will be removed if they do not match local site files.
85
+ If `remote_path` is a subdirectory, only files in that subdirectory will be evaluated for deletion.
86
+
87
+ #### Git
51
88
 
52
- Only git_url is required. Other options will default as shown below.
89
+ Only `git_url` is required. Other options will default as shown below.
53
90
 
54
- | option | Description | Default
91
+ | Config | Description | Default
55
92
  |:--------------|:-------------------------------------------------|:---------------|
56
93
  | `git_url` | Url for remote git repository. | |
57
94
  | `git_branch` | Deployment branch for git repository. | master |
58
95
  | `deploy_dir` | Directory where deployment files are staged. | .deploy |
59
96
  | `remote` | Name of git remote. | deploy |
60
97
 
61
- ### Rsync options
98
+ #### Rsync
62
99
 
63
100
  Only `remote_path` is required. If `user` is not present, Rsync will sync between two locally available directories. Do this if your site root is mounted locally.
64
101
 
65
- | option | Description | Default
102
+ | Config | Description | Default
66
103
  |:---------------|:--------------------------------------------------|:---------------|
67
104
  | `user` | ssh user, e.g user@host.com | |
68
105
  | `port` | ssh port | 22 |
@@ -1,18 +1,26 @@
1
- require "octopress-deploy/version"
2
- require "octopress-deploy/core_ext"
3
- require "YAML"
1
+ $LOAD_PATH.unshift File.expand_path("../", __FILE__)
2
+
3
+ require 'octopress-deploy/version'
4
+ require 'octopress-deploy/core_ext'
4
5
  require 'colorator'
5
- require 'open3'
6
+ require 'yaml'
7
+ require 'pathname'
8
+
9
+ if defined? Octopress::Command
10
+ require 'octopress-deploy/commands'
11
+ end
6
12
 
7
13
 
8
14
  module Octopress
9
15
  module Deploy
10
16
  autoload :Git, 'octopress-deploy/git'
11
17
  autoload :Rsync, 'octopress-deploy/rsync'
18
+ autoload :S3, 'octopress-deploy/s3'
12
19
 
13
20
  METHODS = {
14
21
  'git'=> Git,
15
- 'rsync'=> Rsync
22
+ 'rsync'=> Rsync,
23
+ 's3'=> S3
16
24
  }
17
25
 
18
26
  def self.push(options={})
@@ -25,6 +33,19 @@ module Octopress
25
33
  end
26
34
  end
27
35
 
36
+ def self.pull(dir='site-pull', options={})
37
+ init_options(options)
38
+ if !File.exists? @options[:config_file]
39
+ init_config if ask_bool("Deployment config file not found. Create #{@options[:config_file]}?")
40
+ else
41
+ parse_options
42
+ if !File.exists? @options[:pull_dir] = dir
43
+ FileUtils.mkdir_p @options[:pull_dir]
44
+ end
45
+ deploy_method.new(@options).pull()
46
+ end
47
+ end
48
+
28
49
  def self.parse_options
29
50
  config = YAML.load(File.open(@options[:config_file])).to_symbol_keys
30
51
  @options = @options.to_symbol_keys
@@ -32,7 +53,7 @@ module Octopress
32
53
  end
33
54
 
34
55
  def self.init_options(options={})
35
- @options ||= options
56
+ @options = options.to_symbol_keys
36
57
  @options[:config_file] ||= '_deploy.yml'
37
58
  @options[:site_dir] ||= site_dir
38
59
  end
@@ -51,53 +72,100 @@ module Octopress
51
72
 
52
73
  # Create a config file
53
74
  #
54
- def self.init_config(method=nil, options={})
55
- init_options unless @options
56
- @options ||= options
57
- @options[:method] ||= method
75
+ def self.init_config(method=nil, options=nil)
76
+ if options
77
+ options[:method] = method
78
+ init_options(options)
79
+ end
80
+
58
81
  unless @options[:method]
59
82
  @options[:method] = ask("How would you like to deploy your site?", METHODS.keys)
60
83
  end
61
- config = <<-FILE
62
- method: #{@options[:method]}
63
- site_dir: #{@options[:site_dir]}
64
- FILE
65
- config += deploy_method.default_config(options)
66
84
 
67
- if File.exist? @options[:config_file]
68
- unless ask_bool("A config file already exists at #{@options[:config_file]}. Overwrite?")
69
- abort "No config file written."
85
+ write_config
86
+ check_gitignore
87
+ end
88
+
89
+ def self.write_config
90
+ if !@options[:force_write_config]
91
+ if File.exist?(@options[:config_file]) &&
92
+ !ask_bool("A config file already exists at #{@options[:config_file]}. Overwrite?")
93
+ return puts "No config file written."
70
94
  end
71
95
  end
96
+
97
+ config = get_config.strip
72
98
  File.open(@options[:config_file], 'w') { |f| f.write(config) }
73
99
  puts "File #{@options[:config_file]} created.".green
74
100
  puts "------------------"
75
- puts "#{config.yellow}------------------"
101
+ puts "#{config.yellow}"
102
+ puts "------------------"
76
103
  puts "Please add your configurations to this file."
77
104
  end
78
105
 
106
+ def self.get_config
107
+ <<-FILE
108
+ method: #{@options[:method]}
109
+ site_dir: #{@options[:site_dir]}
110
+ #{deploy_method.default_config(@options)}
111
+ FILE
112
+ end
113
+
114
+ def self.check_gitignore
115
+ gitignore = File.join(`git rev-parse --show-toplevel`.strip, ".gitignore")
116
+ if !File.exist?(gitignore) ||
117
+ Pathname.new(gitignore).read.match(/^#{@options[:config_file]}/i).nil?
118
+ if ask_bool("Do you want to add #{@options[:config_file]} to your .gitignore?")
119
+ git_ignore_config_file gitignore
120
+ return true
121
+ end
122
+ else
123
+ return true
124
+ end
125
+ end
126
+
127
+ def self.git_ignore_config_file(gitignore)
128
+ File.open(gitignore, 'a') { |f| f.write(@options[:config_file]) }
129
+ end
130
+
79
131
  def self.ask_bool(message)
80
- ask(message, ['y','n']) == 'y'
132
+ ask_or_default(true, message) do
133
+ ask(message, ['y','n']) == 'y'
134
+ end
81
135
  end
82
136
 
83
137
  def self.ask(message, valid_options)
84
- if valid_options
85
- options = valid_options.join '/'
86
- answer = get_stdin("#{message} [#{options}]: ").downcase.strip
87
- if valid_options.map{|o| o.downcase}.include?(answer)
88
- return answer
138
+ ask_or_default(false, message) do
139
+ if valid_options
140
+ options = valid_options.join '/'
141
+ answer = get_stdin("#{message} [#{options}]: ").downcase.strip
142
+ if valid_options.map{|o| o.downcase}.include?(answer)
143
+ return answer
144
+ else
145
+ return false
146
+ end
89
147
  else
90
- return false
148
+ answer = get_stdin("#{message}: ")
91
149
  end
92
- else
93
- answer = get_stdin("#{message}: ")
150
+ answer
94
151
  end
95
- answer
96
152
  end
97
153
 
98
154
  def self.get_stdin(message)
99
155
  print message
100
156
  STDIN.gets.chomp
101
157
  end
158
+
159
+ def self.should_ask?
160
+ !ENV['NO_ASK']
161
+ end
162
+
163
+ def self.ask_or_default(default, message)
164
+ if should_ask?
165
+ yield
166
+ else
167
+ puts "Assuming '#{default}' for '#{message}'."
168
+ end
169
+ end
102
170
  end
103
171
  end
@@ -0,0 +1,26 @@
1
+ module Octopress
2
+ module Deploy
3
+ class Commands < Octopress::Command
4
+ def self.init_with_program(p)
5
+ p.command(:deploy) do |c|
6
+ c.syntax "octopress deploy [options]"
7
+ c.description "Deploy your Octopress site."
8
+ c.option "using", "--using METHOD", "Define the push method to use, overriding your configuration file's setting"
9
+ c.option "config_file", "--config FILE", "The path to your config file (default: _deploy.yml)"
10
+ c.option "init", "--init METHOD", "Initialize a config file with the options for the given method."
11
+ c.option "pull", "--pull DIRECTORY", "Pull down the published copy of your site into a directory (default: ./site-pull)"
12
+
13
+ c.action do |_, options|
14
+ if options["init"] and options["init"].is_a?(String)
15
+ Octopress::Deploy.init_config(options["init"], options)
16
+ elsif options["pull"] and options["pull"].is_a?(String)
17
+ Octopress::Deploy.pull(options["pull"], options)
18
+ else
19
+ Octopress::Deploy.push(options)
20
+ end
21
+ end
22
+ end
23
+ end
24
+ end
25
+ end
26
+ end
@@ -3,89 +3,106 @@ module Octopress
3
3
  class Git
4
4
 
5
5
  def initialize(options={})
6
- @options = options
7
- @repo = @options[:git_url]
8
- @branch = @options[:git_branch]
9
- @site_dir = @options[:site_dir]
10
- @remote = @options[:remote] || 'deploy'
11
- @deploy_dir = @options[:deploy_dir] || '.deploy'
12
- abort "Deploy Failed: You must provide a repository URL before deploying. Check your #{@options[:config_file]}.".red if @repo.nil?
6
+ @options = options
7
+ @repo = @options[:git_url]
8
+ @branch = @options[:git_branch]
9
+ @remote = @options[:remote] || 'deploy'
10
+ @remote_path = @options[:remote_path] || ''
11
+ @remote_path = @remote_path.sub(/^\//,'') #remove leading slash
12
+ @site_dir = File.expand_path(@options[:site_dir])
13
+ @deploy_dir = File.expand_path(@options[:deploy_dir] || '.deploy')
14
+ @pull_dir = @options[:pull_dir]
15
+ abort "Deploy Failed: Configure a git_url in #{@options[:config_file]} before deploying.".red if @repo.nil?
13
16
  end
14
17
 
15
18
  # Initialize, pull, copy and deploy.
16
- # This is the method you're looking for.
17
19
  #
18
20
  def push
19
- init_repo unless check_repo
20
- git_pull
21
- copy_site
22
- git_push
21
+ init_repo
22
+ puts "Syncing #{@site_dir.sub(`pwd`.strip+'/', '')} files to #{@repo}."
23
+ FileUtils.cd @deploy_dir do
24
+ git_pull
25
+ clean_deploy
26
+ copy_site
27
+ git_push
28
+ end
23
29
  end
24
30
 
25
- # Check to see if local deployment dir configured to deploy
31
+ def pull
32
+ `git clone -b #{@branch} #{@repo} #{@pull_dir}`
33
+ end
34
+
35
+ # Check to see if local deployment dir is configured to deploy.
26
36
  #
27
37
  def check_repo
28
- return unless Dir.exist? @deploy_dir
29
- FileUtils.cd @deploy_dir do
30
- return `git remote -v`.include? @repo
38
+ if Dir.exist? @deploy_dir
39
+ FileUtils.cd @deploy_dir do
40
+ return `git remote -v`.include? @repo
41
+ end
31
42
  end
32
43
  end
33
44
 
34
45
  def self.default_config(options={})
35
- config = <<-CONFIG
46
+ <<-CONFIG
36
47
  git_url: #{options[:git_url]}
37
48
  git_branch: #{options[:git_branch] || 'master'}
38
49
  CONFIG
39
50
  end
40
51
 
41
- # If necessary create deploy directory and initialize it with deployment remote
52
+ # If necessary create deploy directory and initialize it with deployment remote.
42
53
  #
43
54
  def init_repo
55
+ return if check_repo
44
56
  FileUtils.mkdir_p @deploy_dir
45
57
  FileUtils.cd @deploy_dir do
46
58
  if Dir[@deploy_dir+'/*'].empty?
47
59
 
48
- # Attempt to clone from the remote
60
+ # initialize the repository and add the remote.
61
+ #
62
+ `git init; git remote add #{@remote} #{@repo}`
63
+
64
+ # Attempt to pull from the remote.
49
65
  #
50
- cmd = "git clone #{@repo} --origin #{@remote} --branch #{@branch} ."
51
- puts cmd
52
- Open3.popen3(cmd) do |stdin, stdout, stderr, wait_thr|
53
- exit_status = wait_thr.value
66
+ if git_pull
67
+ `git branch -m #{@branch}`
54
68
 
55
- # If cloning fails, initialize the directory manually
56
- # This will occur if a remote has no commits
57
- #
58
- unless exit_status.success?
59
- `git init; git remote add #{@remote} #{@repo}`
60
- `echo "initialize deploy repo" > _`
61
- `git add .; git commit -m 'initial commit'`
62
- `git branch -m #{@branch}`
63
- `git rm _; git add -u; git commit -m 'cleanup'`
64
- end
69
+ # If no branch exists on remote, create one locally.
70
+ else
71
+ `echo "initialize deploy repo" > _`
72
+ `git add .; git commit -m 'initial commit'`
73
+ `git branch -m #{@branch}`
74
+ `git rm _; git add -u; git commit -m 'cleanup'`
65
75
  end
66
76
  end
67
77
  end
68
78
  end
69
79
 
70
80
  def git_push
71
- FileUtils.cd @deploy_dir do
72
- `git push #{@remote} #{@branch}`
73
- end
81
+ `git push #{@remote} #{@branch}`
74
82
  end
75
83
 
84
+ # Attempt to pull from the remote branch
85
+ #
76
86
  def git_pull
77
- FileUtils.cd @deploy_dir do
78
- output, error = Open3.capture3"git pull #{@remote} #{@branch}"
79
- FileUtils.rm_rf(Dir.glob('*'), secure: true) if error.empty?
87
+ if `git branch -a` =~ /remotes\/#{@remote}\/#{@branch}/ ||
88
+ `git ls-remote #{@remote}` =~ /refs\/heads\/#{@branch}/
89
+ `git pull #{@remote} #{@branch}`
80
90
  end
81
91
  end
82
92
 
93
+ # Remove files in deploy dir, ensuring a 1:1 site files deployment.
94
+ #
95
+ def clean_deploy
96
+ FileUtils.rm_rf(Dir.glob('*'), secure: true)
97
+ end
98
+
99
+ # Copy site files into deploy dir.
100
+ #
83
101
  def copy_site
84
- FileUtils.cp_r @site_dir + '/.', @deploy_dir
85
- FileUtils.cd @deploy_dir do
86
- message = "Site updated at: #{Time.now.utc}"
87
- `git add --all :/; git commit -m '#{message}'`
88
- end
102
+ target_dir = File.join(@deploy_dir, @remote_path).sub(/\/$/,'')
103
+ FileUtils.cp_r @site_dir + '/.', target_dir
104
+ message = "Site updated at: #{Time.now.utc}"
105
+ `git add --all :/; git commit -m '#{message}'`
89
106
  end
90
107
  end
91
108
  end
@@ -3,48 +3,57 @@ module Octopress
3
3
  class Rsync
4
4
 
5
5
  def initialize(options)
6
- @user = options[:user]
7
- @port = options[:port] || "22"
8
- @local = options[:site_dir]
9
- @remote = options[:remote_path]
10
- @exclude = options[:exclude]
11
- @exclude_file = options[:exclude_file]
12
- @include = options[:include]
13
- @delete = options[:delete]
6
+ @options = options
7
+ @user = @options[:user]
8
+ @port = @options[:port]
9
+ @local = @options[:site_dir]
10
+ @remote_path = @options[:remote_path]
11
+ @exclude = @options[:exclude]
12
+ @exclude_file = @options[:exclude_file]
13
+ @exclude_file = File.expand_path(@exclude_file) if @exclude_file
14
+ @include = @options[:include]
15
+ @delete = @options[:delete]
16
+ @remote_path = @remote_path.sub(/^\//,'') #remove leading slash
17
+ @pull_dir = @options[:pull_dir]
14
18
  end
15
19
 
16
20
  def push
17
- cmd = "rsync -avz"
18
- if @exclude || @exclude_file
19
- cmd << "e"
20
- if @exclude_file
21
- cmd << " --exclude-from #{@exclude_file}"
22
- else
23
- cmd << " --exclude #{@exclude}"
24
- end
25
- end
26
- if @include
27
- cmd << " --include #{@include}"
28
- end
29
- if @user
30
- cmd << " ssh -p #{@port}"
31
- end
32
- if @delete
33
- cmd << " --delete"
34
- end
35
- cmd += " #{File.join(@local, '')} "
36
- if @user
37
- cmd << "#{@user}:"
38
- end
39
- cmd << "#{@remote}"
21
+ puts "Syncing #{@local} files to #{@remote_path} with rsync."
22
+ system cmd
23
+ end
40
24
 
25
+ def pull
26
+ puts "Syncing #{@remote_path} files to #{@pull_dir} with rsync."
41
27
  system cmd
42
28
  end
43
29
 
30
+ def cmd
31
+ local = ''
32
+ remote = ''
33
+
34
+ cmd = "rsync -avz "
35
+ cmd << " -e " if @exclude_file || @exclude
36
+ cmd << " --exclude-from #{@exclude_file} " if @exclude_file
37
+ cmd << " --exclude #{@exclude} " if @exclude
38
+ cmd << " --include #{@include} " if @include
39
+ cmd << " --rsh='ssh -p#{@port}' " if @user && @port
40
+ cmd << " --delete " if @delete
41
+
42
+ local << " #{File.join(@local, '')} "
43
+ remote << " #{@user}:" if @user
44
+ remote << "#{@remote_path}"
45
+
46
+ if @pull_dir
47
+ cmd << remote+'/ ' << @pull_dir
48
+ else
49
+ cmd << local << remote
50
+ end
51
+ end
52
+
44
53
  def self.default_config(options={})
45
- config = <<-CONFIG
54
+ <<-CONFIG
46
55
  user: #{options[:user]}
47
- port: #{options[:port] || '22'}
56
+ port: #{options[:port]}
48
57
  remote_path: #{options[:remote_path]}
49
58
  delete: #{options[:delete]}
50
59
  CONFIG
@@ -0,0 +1,177 @@
1
+ require 'find'
2
+ require 'fileutils'
3
+ require 'aws-sdk'
4
+
5
+ module Octopress
6
+ module Deploy
7
+ class S3
8
+
9
+ def initialize(options)
10
+ @local = options[:site_dir]
11
+ @bucket_name = options[:bucket_name]
12
+ @access_key = options[:access_key_id] || ENV['AWS_ACCESS_KEY_ID']
13
+ @secret_key = options[:secret_access_key] || ENV['AWS_SECRET_ACCESS_KEY']
14
+ @region = options[:region] || ENV['AWS_DEFAULT_REGION'] || 'us-east-1'
15
+ @remote_path = (options[:remote_path] || '/').sub(/^\//,'')
16
+ @verbose = options[:verbose] || true
17
+ @delete = options[:delete]
18
+ @remote_path = @remote_path.sub(/^\//,'') # remove leading slash
19
+ @pull_dir = options[:pull_dir]
20
+ connect
21
+ end
22
+
23
+ def push
24
+ abort "Seriously, you should. Quitting..." unless Deploy.check_gitignore
25
+ puts "Syncing #{@local} files to #{@bucket_name} on S3."
26
+ write_files
27
+ delete_files if delete_files?
28
+ status_message
29
+ end
30
+
31
+ def pull
32
+ puts "Syncing #{@bucket_name} files to #{@pull_dir} on S3."
33
+ @bucket.objects.each do |object|
34
+ path = File.join(@pull_dir, object.key)
35
+ dir = File.dirname(path)
36
+ FileUtils.mkdir_p(dir) unless Dir.exist?(dir)
37
+ File.open(path, 'w') { |f| f.write(object.read) }
38
+ end
39
+ end
40
+
41
+ # Connect to S3 using the AWS SDK
42
+ # Retuns an aws bucket
43
+ def connect
44
+ AWS.config(access_key_id: @access_key, secret_access_key: @secret_key, region: @region)
45
+ s3 = AWS.s3
46
+ @bucket = s3.buckets[@bucket_name]
47
+ unless @bucket.exists? || create_bucket(s3.buckets)
48
+ abort "No bucket created. Change your config to point to an existing bucket."
49
+ end
50
+ end
51
+
52
+ # Write site files to the selected bucket
53
+ def write_files
54
+ puts "Writing #{pluralize('file', site_files.size)}:" if @verbose
55
+ site_files.each do |file|
56
+ o = @bucket.objects[remote_path(file)]
57
+ o.write(file: file)
58
+ if @verbose
59
+ puts "+ #{remote_path(file)}"
60
+ else
61
+ progress('+')
62
+ end
63
+ end
64
+ end
65
+
66
+ # Delete files from the bucket, to ensure a 1:1 match with site files
67
+ def delete_files
68
+ if deletable_files.size > 0
69
+ puts "Deleting #{pluralize('file', deletable_files.size)}:" if @verbose
70
+ deletable_files.each do |file|
71
+ @bucket.objects.delete(file)
72
+ if @verbose
73
+ puts "- #{file}"
74
+ else
75
+ progress('-')
76
+ end
77
+ end
78
+ end
79
+ end
80
+
81
+ def create_bucket(buckets)
82
+
83
+ if Deploy.ask_bool("S3 bucket '#{@bucket_name}' not found. Create one in region #{@region}?")
84
+ @bucket = buckets.create(@bucket_name)
85
+ puts "Created new bucket #{@bucket_name} in region #{@region}."
86
+
87
+ configure_bucket
88
+ true
89
+ end
90
+ end
91
+
92
+ def configure_bucket
93
+ error_page = remote_path('404.html')
94
+ index_page = remote_path('index.html')
95
+
96
+ if Deploy.ask_bool("Bucket is not currently configured as a static websites. Configure it with index_page: #{index_page} and error_page: #{error_page}?")
97
+ config = @bucket.configure_website do |cfg|
98
+ cfg.index_document_suffix = index_page
99
+ cfg.error_document_key = error_page
100
+ end
101
+ puts "Bucket configured with index_document: #{index_page} and error_document: #{error_page}."
102
+ else
103
+ puts "You'll want to configure your new bucket using the AWS management console."
104
+ end
105
+ end
106
+
107
+ def delete_files?
108
+ !!@delete
109
+ end
110
+
111
+ # local site files
112
+ def site_files
113
+ @site_files ||= Find.find(@local).to_a.reject do |f|
114
+ File.directory?(f)
115
+ end
116
+ end
117
+
118
+ # Destination paths for local site files.
119
+ def site_files_dest
120
+ @site_files_dest ||= site_files.map{|f| remote_path(f) }
121
+ end
122
+
123
+ # Replace local path with remote path
124
+ def remote_path(file)
125
+ File.join(@remote_path, file.sub(@local, '')).sub(/^\//, '')
126
+ end
127
+
128
+ # Files from the bucket which are deletable
129
+ # Only deletes files beneath the remote_path if specified
130
+ def deletable_files
131
+ return [] unless delete_files?
132
+ unless @deletable
133
+ @deletable = @bucket.objects.map(&:key) - site_files_dest
134
+ @deletable.reject!{|f| (f =~ /^#{@remote_path}/).nil? }
135
+ end
136
+ @deletable
137
+ end
138
+
139
+ # List written and deleted file counts
140
+ def status_message
141
+ uploaded = site_files.size
142
+ deleted = deletable_files.size
143
+
144
+ message = "\nSuccess:".green + " #{uploaded} #{pluralize('file', uploaded)} uploaded"
145
+ message << ", #{deleted} #{pluralize('file', deleted)} deleted."
146
+ puts message
147
+ configure_bucket unless @bucket.website?
148
+ end
149
+
150
+ # Print consecutive characters
151
+ def progress(str)
152
+ print str
153
+ $stdout.flush
154
+ end
155
+
156
+ def pluralize(str, num)
157
+ str << 's' if num != 1
158
+ str
159
+ end
160
+
161
+ # Return default configuration options for this deployment type
162
+ def self.default_config(options={})
163
+ <<-CONFIG
164
+ bucket_name: #{options[:bucket_name]}
165
+ access_key_id: #{options[:access_key_id]}
166
+ secret_access_key: #{options[:secret_access_key]}
167
+ region: #{options[:region] || 'us-east-1'}
168
+ remote_path: #{options[:remote_path] || '/'}
169
+ delete: #{options[:delete] || 'false'}
170
+ verbose: #{options[:verbose] || 'true'}
171
+ CONFIG
172
+ end
173
+
174
+ end
175
+ end
176
+ end
177
+
@@ -1,5 +1,5 @@
1
1
  module Octopress
2
2
  module Deploy
3
- VERSION = "1.0.0.alpha.2"
3
+ VERSION = "1.0.0.alpha.3"
4
4
  end
5
5
  end
@@ -18,6 +18,7 @@ Gem::Specification.new do |spec|
18
18
  spec.require_paths = ["lib"]
19
19
 
20
20
  spec.add_runtime_dependency "colorator"
21
+ spec.add_runtime_dependency "aws-sdk"
21
22
 
22
23
  spec.add_development_dependency "bundler", "~> 1.3"
23
24
  spec.add_development_dependency "rake"
data/test/.gitignore ADDED
@@ -0,0 +1 @@
1
+ _s3_deploy.yml
data/test/Gemfile CHANGED
@@ -1,7 +1,6 @@
1
1
  source 'https://rubygems.org'
2
2
 
3
- group :jekyll_plugins do
4
- gem "octopress-deploy", path: "../"
5
- end
6
-
3
+ gem "octopress", '~> 3.0.0.alpha.5'
4
+ gem "octopress-deploy", path: "../"
7
5
  gem "pry-debugger"
6
+ gem "aws-sdk"
@@ -0,0 +1,6 @@
1
+ method: rsync
2
+ site_dir: _site
3
+ user: imathis@imathis.com
4
+ port:
5
+ remote_path: ~/octopress-deploy/rsync/
6
+ delete:
@@ -0,0 +1,6 @@
1
+ method: rsync
2
+ site_dir: _site
3
+ user:
4
+ port:
5
+ remote_path: local-rsync
6
+ delete:
@@ -0,0 +1 @@
1
+ shh.. I'm hiding. Also ignore that garbage.
@@ -0,0 +1 @@
1
+ Amazingness. And yes, the garbage.
@@ -0,0 +1 @@
1
+ Ignore the follwing garbage:
data/test/test.rb CHANGED
@@ -1,22 +1,161 @@
1
- require 'octopress-deploy'
1
+ require File.expand_path("../../lib/octopress-deploy.rb", __FILE__)
2
+ require 'fileutils'
3
+ require 'find'
2
4
 
3
- def test_git
4
- FileUtils.mkdir 'deploy_target'
5
- FileUtils.cd 'deploy_target' do
6
- system 'git init --bare'
5
+ @has_failed = false
6
+ @failures = {}
7
+
8
+ def setup_tests
9
+ `rm -rf _site` # clean up from previous tests
10
+ generate_site
11
+ end
12
+
13
+ def generate_site
14
+ system "cp -r source/ _site"
15
+ Find.find('_site').to_a.each do |f|
16
+ system("echo '#{garbage}' >> #{f}") unless File.directory?(f)
17
+ end
18
+ end
19
+
20
+ def pout(str)
21
+ print str
22
+ $stdout.flush
23
+ end
24
+
25
+ def garbage
26
+ o = [('a'..'z'), ('A'..'Z')].map { |i| i.to_a }.flatten
27
+ (0...50).map { o[rand(o.length)] }.join
28
+ end
29
+
30
+ def diff_dir(dir1, dir2)
31
+ dir_files(dir1).each do |f1|
32
+ if diff = diff_file(f1, f1.sub(dir1, dir2))
33
+ @failures["#{@testing}: #{f1}"] = diff
34
+ pout "F".red
35
+ @has_failed = true
36
+ else
37
+ pout ".".green
38
+ end
7
39
  end
8
- Octopress::Deploy.init_config('git', git_url: File.expand_path("deploy_target"))
9
- Octopress::Deploy.push()
10
- FileUtils.rm_r 'deploy_target'
11
40
  end
12
41
 
13
- def test_rsync
14
- FileUtils.mkdir_p "deploy-rsync"
15
- Octopress::Deploy.init_config('rsync', remote_path: '.deploy')
16
- Octopress::Deploy.push()
17
- FileUtils.rm_r 'deploy-rsync'
42
+ def diff_file(file1, file2)
43
+ if File.exist?(file2)
44
+ diff = `diff #{file1} #{file2}`
45
+ if diff.size > 0
46
+ diff
47
+ else
48
+ false
49
+ end
50
+ else
51
+ "File: #{file2}: No such file or directory."
52
+ end
18
53
  end
19
54
 
20
- test_git
21
- test_rsync
55
+ def dir_files(dir)
56
+ Find.find(dir).to_a.reject!{|f| File.directory?(f) }
57
+ end
58
+
59
+ def test_remote_git
60
+ @testing = 'remote git'
61
+ repo = "git@github.com:octopress/deploy"
62
+ config = "_git_deploy.yml"
63
+
64
+ # Clean up from previous tests
65
+ #
66
+ `rm -rf .deploy pull-git`
67
+
68
+ # Test remote git deployment
69
+ #
70
+ Octopress::Deploy.init_config('git', config_file: config, force_write_config: true, git_branch: 'test_git_deploy', git_url: repo)
71
+ Octopress::Deploy.push(config_file: config)
72
+ Octopress::Deploy.pull('pull-git', config_file: config)
73
+ diff_dir('_site', 'pull-git')
74
+ end
75
+
76
+ def test_local_git
77
+ @testing = 'local git'
78
+ config = "_git_deploy.yml"
79
+
80
+ # Clean up from previous tests
81
+ #
82
+ `rm -rf .deploy local-git pull-git`
83
+ `git init --bare local-git`
84
+ repo = "local-git"
85
+
86
+ # Test local git deployment
87
+ #
88
+ Octopress::Deploy.push(config_file: config, git_url: File.expand_path(repo), remote_path: 'site')
89
+ Octopress::Deploy.pull('pull-git', config_file: config, git_url: File.expand_path(repo), remote_path: 'site')
90
+ diff_dir('_site', 'pull-git/site')
91
+ end
92
+
93
+ def test_remote_rsync
94
+ @testing = 'remote rsync'
95
+ config = '_rsync_deploy.yml'
96
+
97
+ # Clean up from previous tests
98
+ `rm -rf local-rsync pull-rsync`
99
+
100
+ # Test remote git deployment
101
+ #
102
+ Octopress::Deploy.init_config('rsync', config_file: config, force_write_config: true, user: 'imathis@imathis.com', remote_path: '~/octopress-deploy/rsync/')
103
+ Octopress::Deploy.push(config_file: config)
104
+ Octopress::Deploy.pull('pull-rsync', config_file: config)
105
+ diff_dir('_site', 'pull-rsync')
106
+
107
+ end
108
+
109
+ def test_local_rsync
110
+ @testing = 'local rsync'
111
+ config = '_rsync_deploy.yml'
112
+
113
+ # Clean up from previous tests
114
+ `rm -rf local-rsync pull-rsync`
115
+
116
+ # Test local git deployment
117
+ #
118
+ Octopress::Deploy.init_config('rsync', config_file: config, force_write_config: true, remote_path: 'local-rsync')
119
+ Octopress::Deploy.push(config_file: config)
120
+ Octopress::Deploy.pull('pull-rsync', config_file: config, user: false, remote_path: 'local-rsync')
121
+ diff_dir('_site', 'pull-rsync')
122
+ end
123
+
124
+ def test_s3
125
+ @testing = 's3'
126
+ config = "_s3_deploy.yml"
127
+ `rm -rf pull-s3`
128
+ Octopress::Deploy.push(config_file: config)
129
+ Octopress::Deploy.pull('pull-s3', config_file: config)
130
+ diff_dir('_site', 'pull-s3')
131
+ end
132
+
133
+ def print_test_results
134
+ puts "\n"
135
+ if @has_failed
136
+ @failures.each do |name, diff|
137
+ puts "Failure in #{name}:".red
138
+ puts "---------"
139
+ puts diff
140
+ puts "---------"
141
+ end
142
+ abort
143
+ else
144
+ puts "All passed!".green
145
+ end
146
+ end
147
+
148
+
149
+ setup_tests
150
+
151
+ # local tests
152
+ test_local_rsync
153
+ test_local_git
154
+
155
+ # remote tests
156
+ test_remote_git
157
+ test_remote_rsync
158
+ test_s3
159
+
160
+ print_test_results
22
161
 
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: octopress-deploy
3
3
  version: !ruby/object:Gem::Version
4
- version: 1.0.0.alpha.2
4
+ version: 1.0.0.alpha.3
5
5
  platform: ruby
6
6
  authors:
7
7
  - Brandon Mathis
8
8
  autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
- date: 2014-02-10 00:00:00.000000000 Z
11
+ date: 2014-02-20 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: colorator
@@ -24,6 +24,20 @@ dependencies:
24
24
  - - '>='
25
25
  - !ruby/object:Gem::Version
26
26
  version: '0'
27
+ - !ruby/object:Gem::Dependency
28
+ name: aws-sdk
29
+ requirement: !ruby/object:Gem::Requirement
30
+ requirements:
31
+ - - '>='
32
+ - !ruby/object:Gem::Version
33
+ version: '0'
34
+ type: :runtime
35
+ prerelease: false
36
+ version_requirements: !ruby/object:Gem::Requirement
37
+ requirements:
38
+ - - '>='
39
+ - !ruby/object:Gem::Version
40
+ version: '0'
27
41
  - !ruby/object:Gem::Dependency
28
42
  name: bundler
29
43
  requirement: !ruby/object:Gem::Requirement
@@ -61,19 +75,25 @@ extra_rdoc_files: []
61
75
  files:
62
76
  - .gitignore
63
77
  - Gemfile
78
+ - History.markdown
64
79
  - LICENSE.txt
65
80
  - README.md
66
81
  - Rakefile
67
82
  - lib/octopress-deploy.rb
83
+ - lib/octopress-deploy/commands.rb
68
84
  - lib/octopress-deploy/core_ext.rb
69
85
  - lib/octopress-deploy/git.rb
70
86
  - lib/octopress-deploy/rsync.rb
87
+ - lib/octopress-deploy/s3.rb
71
88
  - lib/octopress-deploy/version.rb
72
89
  - octopress-deploy.gemspec
90
+ - test/.gitignore
73
91
  - test/Gemfile
74
- - test/_deploy.yml
75
- - test/_site/foo
76
- - test/_site/test
92
+ - test/_deploy_rsync.yml
93
+ - test/_deploy_rsync_local.yml
94
+ - test/source/.hidden
95
+ - test/source/dir/file
96
+ - test/source/test_file
77
97
  - test/test.rb
78
98
  homepage: https://github.com/octopress/deploy
79
99
  licenses:
@@ -100,8 +120,11 @@ signing_key:
100
120
  specification_version: 4
101
121
  summary: Deploy Octopress and Jekyll sites easily
102
122
  test_files:
123
+ - test/.gitignore
103
124
  - test/Gemfile
104
- - test/_deploy.yml
105
- - test/_site/foo
106
- - test/_site/test
125
+ - test/_deploy_rsync.yml
126
+ - test/_deploy_rsync_local.yml
127
+ - test/source/.hidden
128
+ - test/source/dir/file
129
+ - test/source/test_file
107
130
  - test/test.rb
data/test/_deploy.yml DELETED
@@ -1,4 +0,0 @@
1
- method: git
2
- site_dir: _site
3
- git_url: /Users/imathis/workspace/octodev/deploy/test/deploy_target
4
- git_branch: master
data/test/_site/foo DELETED
@@ -1 +0,0 @@
1
- asdfasdf
data/test/_site/test DELETED
@@ -1 +0,0 @@
1
- fioobr