slicecraft 0.1.0
Sign up to get free protection for your applications and to get access to all the features.
- data/README.md +25 -0
- data/bin/slicecraft +58 -0
- data/config.yml +7 -0
- data/lib/slicecraft.rb +117 -0
- data/spec/lib/slicecraft_spec.rb +161 -0
- metadata +130 -0
data/README.md
ADDED
@@ -0,0 +1,25 @@
|
|
1
|
+
# SliceCraft
|
2
|
+
|
3
|
+
SliceCraft commands for generating, previewing and delivering a project.
|
4
|
+
|
5
|
+
Download the latest gemfile in the [downloads](https://github.com/80beans/slicecraft/downloads) section, then run `gem install /.[gemfile name]` in your console to install the gem.
|
6
|
+
|
7
|
+
## Commands
|
8
|
+
|
9
|
+
````
|
10
|
+
slicecraft new [projectname]
|
11
|
+
````
|
12
|
+
|
13
|
+
Creates a new project folder with middleman template in your current folder.
|
14
|
+
|
15
|
+
````
|
16
|
+
slicecraft preview
|
17
|
+
````
|
18
|
+
|
19
|
+
Run this in your project folder to create a preview and upload it to the server.
|
20
|
+
|
21
|
+
````
|
22
|
+
slicecraft deliver
|
23
|
+
````
|
24
|
+
|
25
|
+
Run this in your project folder to deliver the project, a zip of the build and source is uploaded to the server.
|
data/bin/slicecraft
ADDED
@@ -0,0 +1,58 @@
|
|
1
|
+
#!/usr/bin/env ruby
|
2
|
+
|
3
|
+
require 'rubygems'
|
4
|
+
require 'commander/import'
|
5
|
+
require File.expand_path(File.dirname(__FILE__) + '/../lib/slicecraft')
|
6
|
+
|
7
|
+
program :version, '0.0.1'
|
8
|
+
program :description, "The 80beans SliceCraft gem. Run 'slicecraft new [projectname]' to create a new SliceCraft project."
|
9
|
+
|
10
|
+
command :new do |c|
|
11
|
+
c.syntax = 'slicecraft new [projectname]'
|
12
|
+
c.summary = 'Initialize a new project.'
|
13
|
+
c.description = 'Enter a project name to create a folder with that name and generate the 80beans middleman template.'
|
14
|
+
c.action do |args, options|
|
15
|
+
if args.first
|
16
|
+
c.when_called Slicecraft::Project.create(:directory => args.first)
|
17
|
+
say "Project '#{args.first}' successfully created, have fun slicing!"
|
18
|
+
else
|
19
|
+
say "Error: Enter a projectname (slicecraft new [projectname])"
|
20
|
+
end
|
21
|
+
end
|
22
|
+
end
|
23
|
+
|
24
|
+
command :preview do |c|
|
25
|
+
c.syntax = 'slicecraft preview'
|
26
|
+
c.summary = 'Ships the project to the preview server'
|
27
|
+
c.description = 'When in a folder containing a middleman project run this to sync a preview to the server.'
|
28
|
+
c.option '--url', String, 'Instead of building the preview this only shows the preview url'
|
29
|
+
c.action do |args, options|
|
30
|
+
if options.url
|
31
|
+
say "Preview url: #{Slicecraft::Preview.new(:directory => Dir.pwd).result_url}"
|
32
|
+
else
|
33
|
+
c.when_called Slicecraft::Project.build
|
34
|
+
preview = Slicecraft::Preview.new(:directory => Dir.pwd)
|
35
|
+
preview.process
|
36
|
+
say "Shipped to: #{preview.result_url}"
|
37
|
+
say "Pages:"
|
38
|
+
preview.result_urls.each{ |r| say r }
|
39
|
+
end
|
40
|
+
end
|
41
|
+
end
|
42
|
+
|
43
|
+
command :deliver do |c|
|
44
|
+
c.syntax = 'slicecraft deliver'
|
45
|
+
c.summary = 'Delivers a project zip'
|
46
|
+
c.description = 'When in a folder containing a middleman project run this to deliver a project zip containing the build and source to the server.'
|
47
|
+
c.option '--url', String, 'Instead of delivering the zip this only shows the zip url'
|
48
|
+
c.action do |args, options|
|
49
|
+
if options.url
|
50
|
+
say "Zip url: #{Slicecraft::Delivery.new(:directory => Dir.pwd).result_url}"
|
51
|
+
else
|
52
|
+
c.when_called Slicecraft::Project.build
|
53
|
+
delivery = Slicecraft::Delivery.new(:directory => Dir.pwd)
|
54
|
+
delivery.process
|
55
|
+
say "Zipped to: #{delivery.result_url}"
|
56
|
+
end
|
57
|
+
end
|
58
|
+
end
|
data/config.yml
ADDED
data/lib/slicecraft.rb
ADDED
@@ -0,0 +1,117 @@
|
|
1
|
+
require 'net/scp'
|
2
|
+
require 'yaml'
|
3
|
+
require 'zip/zip'
|
4
|
+
|
5
|
+
module Slicecraft
|
6
|
+
|
7
|
+
class Project
|
8
|
+
|
9
|
+
def self.create(options)
|
10
|
+
@location = options[:directory]
|
11
|
+
|
12
|
+
system "git clone #{self.template_repo} #{@location}"
|
13
|
+
FileUtils.rm_rf "#{@location}/.git"
|
14
|
+
end
|
15
|
+
|
16
|
+
def self.build
|
17
|
+
result = system "middleman build"
|
18
|
+
raise 'Middleman could not build' unless result
|
19
|
+
end
|
20
|
+
|
21
|
+
def self.template_repo
|
22
|
+
YAML.load_file(File.expand_path(File.join(File.dirname(__FILE__), '../config.yml')))['template_repo']
|
23
|
+
end
|
24
|
+
|
25
|
+
end
|
26
|
+
|
27
|
+
class Syncer
|
28
|
+
attr_accessor :path
|
29
|
+
attr_accessor :settings
|
30
|
+
|
31
|
+
def initialize(options)
|
32
|
+
@path = options[:directory]
|
33
|
+
end
|
34
|
+
|
35
|
+
def hashed_path
|
36
|
+
"#{project_name}_#{Digest::SHA1.hexdigest('12RThh' + project_name)}"
|
37
|
+
end
|
38
|
+
|
39
|
+
def result_url
|
40
|
+
"#{settings['result_url']}/#{hashed_path}"
|
41
|
+
end
|
42
|
+
|
43
|
+
def project_name
|
44
|
+
@path.split('/').last
|
45
|
+
end
|
46
|
+
|
47
|
+
def build_path
|
48
|
+
"#{@path}/build/"
|
49
|
+
end
|
50
|
+
|
51
|
+
def settings
|
52
|
+
@settings ||= YAML.load_file(File.expand_path(File.join(File.dirname(__FILE__), '../config.yml')))['server']
|
53
|
+
end
|
54
|
+
|
55
|
+
end
|
56
|
+
|
57
|
+
|
58
|
+
class Preview < Syncer
|
59
|
+
|
60
|
+
def result_urls
|
61
|
+
results = Dir.entries(build_path).select{ |file| file.end_with?('.html') }.map{ |r| "#{result_url}/#{r}" }
|
62
|
+
FileUtils.rm_rf build_path if File.exists? build_path
|
63
|
+
results
|
64
|
+
end
|
65
|
+
|
66
|
+
def process
|
67
|
+
system "rsync -ave ssh #{build_path} #{settings['user']}@#{settings['url']}:#{"#{settings['preview_path']}#{hashed_path}"}"
|
68
|
+
end
|
69
|
+
|
70
|
+
end
|
71
|
+
|
72
|
+
class Delivery < Syncer
|
73
|
+
|
74
|
+
def process
|
75
|
+
zip
|
76
|
+
sync
|
77
|
+
end
|
78
|
+
|
79
|
+
def zip
|
80
|
+
if File.exists?('zip/source.zip')
|
81
|
+
File.delete('zip/source.zip')
|
82
|
+
else
|
83
|
+
FileUtils.mkdir('zip') unless File.exists?('zip')
|
84
|
+
end
|
85
|
+
Zip::ZipFile.open(File.join(zip_path, 'source.zip'), Zip::ZipFile::CREATE) do |zipfile|
|
86
|
+
add_folder_to_zipfile(zipfile, 'source')
|
87
|
+
add_folder_to_zipfile(zipfile, 'build')
|
88
|
+
end
|
89
|
+
end
|
90
|
+
|
91
|
+
def add_folder_to_zipfile(zipfile, folder)
|
92
|
+
Dir["#{path}/#{folder}/**/**"].each do |file|
|
93
|
+
zipfile.add(file.sub(path+'/',''),file)
|
94
|
+
end
|
95
|
+
end
|
96
|
+
|
97
|
+
def zip_path
|
98
|
+
"#{@path}/zip/"
|
99
|
+
end
|
100
|
+
|
101
|
+
def result_url
|
102
|
+
super + '/source.zip'
|
103
|
+
end
|
104
|
+
|
105
|
+
def hashed_path
|
106
|
+
super + '/zip'
|
107
|
+
end
|
108
|
+
|
109
|
+
def sync
|
110
|
+
system "rsync -ave ssh #{zip_path} #{settings['user']}@#{settings['url']}:#{"#{settings['preview_path']}#{hashed_path}"}"
|
111
|
+
FileUtils.rm_rf zip_path if File.exists? zip_path
|
112
|
+
FileUtils.rm_rf build_path if File.exists? build_path
|
113
|
+
end
|
114
|
+
|
115
|
+
end
|
116
|
+
|
117
|
+
end
|
@@ -0,0 +1,161 @@
|
|
1
|
+
require 'rspec'
|
2
|
+
require File.expand_path(File.dirname(__FILE__) + '/../../lib/slicecraft')
|
3
|
+
|
4
|
+
describe Slicecraft::Project do
|
5
|
+
|
6
|
+
context ".create" do
|
7
|
+
|
8
|
+
it "should create a project" do
|
9
|
+
Slicecraft::Project.should_receive(:system).with("git clone git@github.com:80beans/slicecraft_template.git /slice_this")
|
10
|
+
FileUtils.should_receive(:rm_rf).with("/slice_this/.git")
|
11
|
+
|
12
|
+
Slicecraft::Project.create(:directory => "/slice_this")
|
13
|
+
end
|
14
|
+
|
15
|
+
end
|
16
|
+
|
17
|
+
context ".build" do
|
18
|
+
|
19
|
+
it "should build a project" do
|
20
|
+
Slicecraft::Project.should_receive(:system).with("middleman build").and_return(true)
|
21
|
+
|
22
|
+
Slicecraft::Project.build
|
23
|
+
end
|
24
|
+
|
25
|
+
end
|
26
|
+
|
27
|
+
end
|
28
|
+
|
29
|
+
describe Slicecraft::Syncer do
|
30
|
+
|
31
|
+
let(:syncer) { Slicecraft::Syncer.new(:directory => '/slice_this') }
|
32
|
+
|
33
|
+
context "#settings" do
|
34
|
+
|
35
|
+
it "should have settings" do
|
36
|
+
syncer.settings.should == {
|
37
|
+
"url" => "slicecraft.nl",
|
38
|
+
"user" => "slicecraft",
|
39
|
+
"preview_path" => "/home/slicecraft/previews/",
|
40
|
+
"result_url" => "http://preview.slicecraft.nl"
|
41
|
+
}
|
42
|
+
end
|
43
|
+
|
44
|
+
end
|
45
|
+
|
46
|
+
context "#project_name" do
|
47
|
+
|
48
|
+
it "project_name should be current folder name" do
|
49
|
+
syncer.project_name.should == 'slice_this'
|
50
|
+
end
|
51
|
+
|
52
|
+
context "with longer path" do
|
53
|
+
|
54
|
+
let(:syncer) { Slicecraft::Syncer.new(:directory => '/this/path/is/long/slice_this') }
|
55
|
+
|
56
|
+
it "project_name should be current folder name" do
|
57
|
+
syncer.project_name.should == 'slice_this'
|
58
|
+
end
|
59
|
+
|
60
|
+
end
|
61
|
+
|
62
|
+
end
|
63
|
+
|
64
|
+
context "#hashed_path" do
|
65
|
+
|
66
|
+
it "should return a path with an id hash in it" do
|
67
|
+
syncer.hashed_path.should == 'slice_this_240999fa70d7f05b158bd1170ff932ac0503bea2'
|
68
|
+
end
|
69
|
+
|
70
|
+
end
|
71
|
+
|
72
|
+
context "#result_url" do
|
73
|
+
|
74
|
+
it "should return the correct result_url" do
|
75
|
+
syncer.result_url.should == "http://preview.slicecraft.nl/slice_this_240999fa70d7f05b158bd1170ff932ac0503bea2"
|
76
|
+
end
|
77
|
+
|
78
|
+
end
|
79
|
+
|
80
|
+
end
|
81
|
+
|
82
|
+
describe Slicecraft::Preview do
|
83
|
+
|
84
|
+
let(:preview) { Slicecraft::Preview.new(:directory => '/slice_this') }
|
85
|
+
|
86
|
+
context "#build_path" do
|
87
|
+
|
88
|
+
it "should return the build path" do
|
89
|
+
preview.build_path.should == '/slice_this/build/'
|
90
|
+
end
|
91
|
+
|
92
|
+
end
|
93
|
+
|
94
|
+
context "#process" do
|
95
|
+
|
96
|
+
it "should process the preview" do
|
97
|
+
preview.should_receive(:system).
|
98
|
+
with("rsync -ave ssh /slice_this/build/ slicecraft@slicecraft.nl:/home/slicecraft/previews/slice_this_240999fa70d7f05b158bd1170ff932ac0503bea2")
|
99
|
+
|
100
|
+
preview.process
|
101
|
+
end
|
102
|
+
|
103
|
+
end
|
104
|
+
|
105
|
+
end
|
106
|
+
|
107
|
+
describe Slicecraft::Delivery do
|
108
|
+
|
109
|
+
let(:delivery) { Slicecraft::Delivery.new(:directory => '/slice_this') }
|
110
|
+
|
111
|
+
context "#zip_path" do
|
112
|
+
|
113
|
+
it "should return the zip path" do
|
114
|
+
delivery.zip_path.should == '/slice_this/zip/'
|
115
|
+
end
|
116
|
+
|
117
|
+
end
|
118
|
+
|
119
|
+
context "#sync" do
|
120
|
+
|
121
|
+
it "should sync the zip" do
|
122
|
+
delivery.should_receive(:system).
|
123
|
+
with("rsync -ave ssh /slice_this/zip/ slicecraft@slicecraft.nl:/home/slicecraft/previews/slice_this_240999fa70d7f05b158bd1170ff932ac0503bea2/zip")
|
124
|
+
|
125
|
+
delivery.sync
|
126
|
+
end
|
127
|
+
|
128
|
+
end
|
129
|
+
|
130
|
+
context "#zip" do
|
131
|
+
|
132
|
+
it "should create zip folder and file" do
|
133
|
+
Zip::ZipFile.should_receive('open')
|
134
|
+
FileUtils.should_receive('mkdir').with('zip')
|
135
|
+
|
136
|
+
delivery.zip
|
137
|
+
end
|
138
|
+
|
139
|
+
context "with existing zip file" do
|
140
|
+
|
141
|
+
before do
|
142
|
+
FileUtils.mkdir('zip')
|
143
|
+
FileUtils.touch('zip/source.zip')
|
144
|
+
end
|
145
|
+
|
146
|
+
it "should delete the zip folder and file when a zip file exists" do
|
147
|
+
Zip::ZipFile.should_receive('open')
|
148
|
+
File.should_receive('delete').with('zip/source.zip')
|
149
|
+
|
150
|
+
delivery.zip
|
151
|
+
end
|
152
|
+
|
153
|
+
after do
|
154
|
+
FileUtils.rm_rf('zip')
|
155
|
+
end
|
156
|
+
|
157
|
+
end
|
158
|
+
|
159
|
+
end
|
160
|
+
|
161
|
+
end
|
metadata
ADDED
@@ -0,0 +1,130 @@
|
|
1
|
+
--- !ruby/object:Gem::Specification
|
2
|
+
name: slicecraft
|
3
|
+
version: !ruby/object:Gem::Version
|
4
|
+
version: 0.1.0
|
5
|
+
prerelease:
|
6
|
+
platform: ruby
|
7
|
+
authors:
|
8
|
+
- Ron Cadier
|
9
|
+
autorequire:
|
10
|
+
bindir: bin
|
11
|
+
cert_chain: []
|
12
|
+
date: 2012-10-25 00:00:00.000000000 Z
|
13
|
+
dependencies:
|
14
|
+
- !ruby/object:Gem::Dependency
|
15
|
+
name: commander
|
16
|
+
requirement: !ruby/object:Gem::Requirement
|
17
|
+
none: false
|
18
|
+
requirements:
|
19
|
+
- - ! '>='
|
20
|
+
- !ruby/object:Gem::Version
|
21
|
+
version: 4.1.2
|
22
|
+
type: :runtime
|
23
|
+
prerelease: false
|
24
|
+
version_requirements: !ruby/object:Gem::Requirement
|
25
|
+
none: false
|
26
|
+
requirements:
|
27
|
+
- - ! '>='
|
28
|
+
- !ruby/object:Gem::Version
|
29
|
+
version: 4.1.2
|
30
|
+
- !ruby/object:Gem::Dependency
|
31
|
+
name: middleman
|
32
|
+
requirement: !ruby/object:Gem::Requirement
|
33
|
+
none: false
|
34
|
+
requirements:
|
35
|
+
- - ! '>='
|
36
|
+
- !ruby/object:Gem::Version
|
37
|
+
version: 3.0.0
|
38
|
+
type: :runtime
|
39
|
+
prerelease: false
|
40
|
+
version_requirements: !ruby/object:Gem::Requirement
|
41
|
+
none: false
|
42
|
+
requirements:
|
43
|
+
- - ! '>='
|
44
|
+
- !ruby/object:Gem::Version
|
45
|
+
version: 3.0.0
|
46
|
+
- !ruby/object:Gem::Dependency
|
47
|
+
name: rubyzip
|
48
|
+
requirement: !ruby/object:Gem::Requirement
|
49
|
+
none: false
|
50
|
+
requirements:
|
51
|
+
- - ! '>='
|
52
|
+
- !ruby/object:Gem::Version
|
53
|
+
version: 0.9.9
|
54
|
+
type: :runtime
|
55
|
+
prerelease: false
|
56
|
+
version_requirements: !ruby/object:Gem::Requirement
|
57
|
+
none: false
|
58
|
+
requirements:
|
59
|
+
- - ! '>='
|
60
|
+
- !ruby/object:Gem::Version
|
61
|
+
version: 0.9.9
|
62
|
+
- !ruby/object:Gem::Dependency
|
63
|
+
name: net-scp
|
64
|
+
requirement: !ruby/object:Gem::Requirement
|
65
|
+
none: false
|
66
|
+
requirements:
|
67
|
+
- - ! '>='
|
68
|
+
- !ruby/object:Gem::Version
|
69
|
+
version: 1.0.4
|
70
|
+
type: :runtime
|
71
|
+
prerelease: false
|
72
|
+
version_requirements: !ruby/object:Gem::Requirement
|
73
|
+
none: false
|
74
|
+
requirements:
|
75
|
+
- - ! '>='
|
76
|
+
- !ruby/object:Gem::Version
|
77
|
+
version: 1.0.4
|
78
|
+
- !ruby/object:Gem::Dependency
|
79
|
+
name: rspec
|
80
|
+
requirement: !ruby/object:Gem::Requirement
|
81
|
+
none: false
|
82
|
+
requirements:
|
83
|
+
- - ! '>='
|
84
|
+
- !ruby/object:Gem::Version
|
85
|
+
version: '0'
|
86
|
+
type: :development
|
87
|
+
prerelease: false
|
88
|
+
version_requirements: !ruby/object:Gem::Requirement
|
89
|
+
none: false
|
90
|
+
requirements:
|
91
|
+
- - ! '>='
|
92
|
+
- !ruby/object:Gem::Version
|
93
|
+
version: '0'
|
94
|
+
description: A commandline tool specific for the SliceCraft project flow
|
95
|
+
email: ron@80beans.com
|
96
|
+
executables:
|
97
|
+
- slicecraft
|
98
|
+
extensions: []
|
99
|
+
extra_rdoc_files: []
|
100
|
+
files:
|
101
|
+
- lib/slicecraft.rb
|
102
|
+
- spec/lib/slicecraft_spec.rb
|
103
|
+
- bin/slicecraft
|
104
|
+
- README.md
|
105
|
+
- config.yml
|
106
|
+
homepage: http://80beans.com
|
107
|
+
licenses: []
|
108
|
+
post_install_message:
|
109
|
+
rdoc_options: []
|
110
|
+
require_paths:
|
111
|
+
- lib
|
112
|
+
required_ruby_version: !ruby/object:Gem::Requirement
|
113
|
+
none: false
|
114
|
+
requirements:
|
115
|
+
- - ! '>='
|
116
|
+
- !ruby/object:Gem::Version
|
117
|
+
version: '0'
|
118
|
+
required_rubygems_version: !ruby/object:Gem::Requirement
|
119
|
+
none: false
|
120
|
+
requirements:
|
121
|
+
- - ! '>='
|
122
|
+
- !ruby/object:Gem::Version
|
123
|
+
version: '0'
|
124
|
+
requirements: []
|
125
|
+
rubyforge_project:
|
126
|
+
rubygems_version: 1.8.19
|
127
|
+
signing_key:
|
128
|
+
specification_version: 3
|
129
|
+
summary: Internal tool for SliceCraft
|
130
|
+
test_files: []
|