siteleaf 0.9.23 → 1.0.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.
- checksums.yaml +4 -4
- data/.gitignore +3 -0
- data/.rbenv-vars +2 -0
- data/README.md +21 -3
- data/bin/siteleaf +102 -7
- data/lib/patches/time_with_zone_encode_with.rb +12 -0
- data/lib/siteleaf.rb +3 -0
- data/lib/siteleaf/page.rb +36 -0
- data/lib/siteleaf/post.rb +16 -0
- data/lib/siteleaf/site.rb +69 -1
- data/lib/siteleaf/version.rb +1 -1
- metadata +13 -11
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA1:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 75e7b85ae46ef7e9a4acb9f91e7cfa6aad12d461
|
4
|
+
data.tar.gz: f3fad5f5f09556a6d2e850300ea5f3a5ebb75483
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: ae362f7cba5c44002055e3eb7ac4110003738a34780af46f3e2f0509d33b780e6562f968ab8716e775a79aff119ca2849741aa8b60d4ecd88d7fef47bbb63e88
|
7
|
+
data.tar.gz: c19eace8a1bf47b3e4e079cbc2f021bc47e05eb26a8f3148234d75b7f37c30526ab7e774cb051a011f2516c48c9e56cce671dce34699bc340b30e4afecfd46f3
|
data/.gitignore
CHANGED
data/.rbenv-vars
ADDED
data/README.md
CHANGED
@@ -2,12 +2,14 @@ Siteleaf Gem
|
|
2
2
|
============
|
3
3
|
|
4
4
|
- [Installation](#installation)
|
5
|
-
- [
|
5
|
+
- [Using the CLI](#using-the-cli)
|
6
6
|
- [Using this gem in your application](#using-this-gem-in-your-application)
|
7
7
|
- [Using the API](#using-the-api)
|
8
|
+
- [Exporting your site](#exporting-your-site)
|
8
9
|
- [Troubleshooting](#troubleshooting)
|
9
10
|
- [Contributing](#contributing)
|
10
11
|
|
12
|
+
|
11
13
|
Installation
|
12
14
|
------------
|
13
15
|
|
@@ -16,8 +18,10 @@ The Siteleaf gem is available for installation on [Rubygems](https://rubygems.or
|
|
16
18
|
gem install siteleaf
|
17
19
|
|
18
20
|
|
19
|
-
|
20
|
-
|
21
|
+
Using the CLI
|
22
|
+
-------------
|
23
|
+
|
24
|
+
Important: if using a Gemfile, make sure to prepend all commands with bundle exec (e.g. bundle exec siteleaf auth).
|
21
25
|
|
22
26
|
The Siteleaf gem allows you to test and develop your sites locally. If using [Pow](http://pow.cx) or [Anvil](http://anvilformac.com), your local website will be automatically set up and can be accessed at `http://yoursite.dev`.
|
23
27
|
|
@@ -86,6 +90,7 @@ To use this gem in your application, add the following to your Gemfile:
|
|
86
90
|
gem 'siteleaf', :git => 'git://github.com/siteleaf/siteleaf-gem.git'
|
87
91
|
|
88
92
|
|
93
|
+
|
89
94
|
Using the API
|
90
95
|
-------------
|
91
96
|
|
@@ -166,6 +171,19 @@ post.delete
|
|
166
171
|
Siteleaf::Page.delete('519719ddcc85910626000001')
|
167
172
|
```
|
168
173
|
|
174
|
+
|
175
|
+
Exporting your site
|
176
|
+
---------------------------------
|
177
|
+
|
178
|
+
You can backup or export your Siteleaf content to Jekyll-compatible format by running the following command:
|
179
|
+
|
180
|
+
siteleaf export
|
181
|
+
|
182
|
+
You will be asked to enter your main posts path, this is typically `posts` (default) or `blog` (if your posts are located at `/blog/hello-world` for example). If your site does not have any posts, leave blank to use the default.
|
183
|
+
|
184
|
+
All content including Pages, Posts, Site Metadata, and Assets will be exported to a sub-folder called `export`. Theme files are not included in the export.
|
185
|
+
|
186
|
+
|
169
187
|
Troubleshooting
|
170
188
|
------------
|
171
189
|
|
data/bin/siteleaf
CHANGED
@@ -17,6 +17,7 @@ Commands:
|
|
17
17
|
pull theme Pulls theme files for configured site from Siteleaf
|
18
18
|
push theme Pushes all files in dir as theme to configured site
|
19
19
|
publish Publish website to hosting provider
|
20
|
+
export Exports site content to Jekyll-compatible format
|
20
21
|
help Prints this help document
|
21
22
|
version Prints the siteleaf gem version
|
22
23
|
|
@@ -88,13 +89,13 @@ def get_theme_assets(site_id)
|
|
88
89
|
if assets = Siteleaf::Theme.assets_by_site_id(site_id)
|
89
90
|
updated_count = 0
|
90
91
|
assets.each do |asset|
|
91
|
-
if File.exist?(asset.filename) && (asset.checksum == Digest::MD5.hexdigest(
|
92
|
+
if File.exist?(asset.filename) && (asset.checksum == Digest::MD5.hexdigest(IO.binread(asset.filename)))
|
92
93
|
# file is up to date
|
93
94
|
else
|
94
95
|
print "Downloading #{asset.filename}..."
|
95
|
-
file = open(asset.file['url'],
|
96
|
+
file = open(asset.file['url'], 'r:UTF-8') { |f| f.read }
|
96
97
|
FileUtils.mkdir_p(File.dirname(asset.filename))
|
97
|
-
File.open(asset.filename,
|
98
|
+
File.open(asset.filename, 'w:UTF-8') { |f| f.write(file) }
|
98
99
|
updated_count += 1
|
99
100
|
print "complete.\n"
|
100
101
|
end
|
@@ -109,13 +110,13 @@ def put_theme_assets(site_id)
|
|
109
110
|
updated_count = 0
|
110
111
|
ignore_paths = ['config.ru', '.*']
|
111
112
|
ignore_paths += File.read('.siteleafignore').split(/\r?\n/) if File.exists?('.siteleafignore')
|
112
|
-
|
113
|
+
|
113
114
|
# upload files
|
114
115
|
paths = Dir.glob("**/*")
|
115
116
|
paths.each do |path|
|
116
117
|
if !File.directory?(path) && !ignore_paths.any?{|i| File.fnmatch?(i, path, File::FNM_CASEFOLD) || File.fnmatch?(i, File.basename(path), File::FNM_CASEFOLD) }
|
117
118
|
asset = assets.find{|a| a.filename == path }
|
118
|
-
if asset.nil? || (asset && asset.checksum != Digest::MD5.hexdigest(
|
119
|
+
if asset.nil? || (asset && asset.checksum != Digest::MD5.hexdigest(IO.binread(path)))
|
119
120
|
print "Uploading #{path}..."
|
120
121
|
asset.delete if asset
|
121
122
|
if response = Siteleaf::Asset.create({:site_id => site_id, :theme_id => theme.id, :file => File.new(path), :filename => path})
|
@@ -128,10 +129,10 @@ def put_theme_assets(site_id)
|
|
128
129
|
end
|
129
130
|
end
|
130
131
|
end
|
131
|
-
|
132
|
+
|
132
133
|
# check for old files
|
133
134
|
missing_assets = []
|
134
|
-
assets.each do |asset|
|
135
|
+
assets.each do |asset|
|
135
136
|
missing_assets << asset if !paths.include?(asset.filename)
|
136
137
|
end
|
137
138
|
if missing_assets.empty?
|
@@ -171,6 +172,90 @@ def publish(site_id, quiet = true)
|
|
171
172
|
end
|
172
173
|
end
|
173
174
|
|
175
|
+
def export(site_id, posts_path = "posts")
|
176
|
+
FileUtils.mkdir_p 'export'
|
177
|
+
posts_path = "posts" if posts_path == ""
|
178
|
+
|
179
|
+
site = Siteleaf::Site.find(site_id)
|
180
|
+
site.posts_path = posts_path
|
181
|
+
|
182
|
+
export_uploads(site)
|
183
|
+
export_content(site)
|
184
|
+
export_config(site)
|
185
|
+
end
|
186
|
+
|
187
|
+
def export_config(site)
|
188
|
+
filename = site.filename
|
189
|
+
print "Exporting #{filename}..."
|
190
|
+
|
191
|
+
filename = File.join("export", filename)
|
192
|
+
open(filename, 'w:UTF-8') do |f|
|
193
|
+
f.puts site.to_file
|
194
|
+
end
|
195
|
+
|
196
|
+
print "complete.\n"
|
197
|
+
end
|
198
|
+
|
199
|
+
def export_content(site)
|
200
|
+
pages = site.pages
|
201
|
+
|
202
|
+
pages.each do |page|
|
203
|
+
# export non-blank pages
|
204
|
+
unless page.body.to_s == "" and page.meta.empty?
|
205
|
+
filename = page.filename
|
206
|
+
print "Exporting #{filename}..."
|
207
|
+
|
208
|
+
filename = File.join("export", filename)
|
209
|
+
FileUtils.mkdir_p File.dirname(filename)
|
210
|
+
open(filename, 'w:UTF-8') do |f|
|
211
|
+
f.puts page.to_file
|
212
|
+
end
|
213
|
+
|
214
|
+
print "complete.\n"
|
215
|
+
end
|
216
|
+
|
217
|
+
page.posts.each do |post|
|
218
|
+
filename = post.filename(site.posts_path)
|
219
|
+
print "Exporting #{filename}..."
|
220
|
+
|
221
|
+
filename = File.join("export", filename)
|
222
|
+
FileUtils.mkdir_p File.dirname(filename)
|
223
|
+
open(filename, 'w:UTF-8') do |f|
|
224
|
+
f.puts post.to_file
|
225
|
+
end
|
226
|
+
|
227
|
+
print "complete.\n"
|
228
|
+
end
|
229
|
+
end
|
230
|
+
end
|
231
|
+
|
232
|
+
def export_uploads(site)
|
233
|
+
FileUtils::mkdir_p 'export/_uploads'
|
234
|
+
|
235
|
+
if assets = site.assets
|
236
|
+
assets.each do |asset|
|
237
|
+
filename = File.join("export", "_uploads", asset.filename)
|
238
|
+
arr_path = filename.split('/')
|
239
|
+
|
240
|
+
# Make subdirectories if needed
|
241
|
+
if arr_path.length > 3
|
242
|
+
subdir = arr_path[0..(arr_path.length - 2)].join('/')
|
243
|
+
FileUtils::mkdir_p subdir
|
244
|
+
end
|
245
|
+
|
246
|
+
if !File.exist?(filename) or (asset.checksum != Digest::MD5.hexdigest(IO.binread(filename)))
|
247
|
+
print "Exporting #{filename}..."
|
248
|
+
|
249
|
+
file = open(asset.file['url'], 'r:UTF-8') { |f| f.read }
|
250
|
+
FileUtils.mkdir_p(File.dirname(filename))
|
251
|
+
File.open(filename, 'w:UTF-8') { |f| f.write(file) }
|
252
|
+
|
253
|
+
print "complete.\n"
|
254
|
+
end
|
255
|
+
end
|
256
|
+
end
|
257
|
+
end
|
258
|
+
|
174
259
|
case ARGV[0]
|
175
260
|
when '-v', '--version', 'version'
|
176
261
|
puts Siteleaf::VERSION
|
@@ -239,6 +324,16 @@ when 'publish'
|
|
239
324
|
puts "Site not configured, run `siteleaf config yoursite.com`.\n"
|
240
325
|
end
|
241
326
|
end
|
327
|
+
when 'export'
|
328
|
+
if auth != false
|
329
|
+
if site_id = get_site_id
|
330
|
+
print 'Enter your main posts path (default "posts"): '
|
331
|
+
posts_path = $stdin.gets.chomp
|
332
|
+
export(site_id, posts_path)
|
333
|
+
else
|
334
|
+
puts "Site not configured, run `siteleaf config yoursite.com`.\n"
|
335
|
+
end
|
336
|
+
end
|
242
337
|
else
|
243
338
|
puts "`#{ARGV[0]}` command not found.\n"
|
244
339
|
puts help
|
@@ -0,0 +1,12 @@
|
|
1
|
+
class Time
|
2
|
+
def encode_with(coder)
|
3
|
+
label =
|
4
|
+
if utc?
|
5
|
+
usec.zero? ? '%Y-%m-%d %H:%M:%S Z' : '%Y-%m-%d %H:%M:%S.%9N Z'
|
6
|
+
else
|
7
|
+
usec.zero? ? '%Y-%m-%d %H:%M:%S %:z' : '%Y-%m-%d %H:%M:%S.%9N %:z'
|
8
|
+
end
|
9
|
+
|
10
|
+
coder.represent_scalar(nil, strftime(label))
|
11
|
+
end
|
12
|
+
end
|
data/lib/siteleaf.rb
CHANGED
data/lib/siteleaf/page.rb
CHANGED
@@ -31,5 +31,41 @@ module Siteleaf
|
|
31
31
|
Page.find(self.parent_id) if self.parent_id
|
32
32
|
end
|
33
33
|
|
34
|
+
def draft?
|
35
|
+
visibility == 'draft'
|
36
|
+
end
|
37
|
+
|
38
|
+
def published?
|
39
|
+
visibility == 'visible'
|
40
|
+
end
|
41
|
+
|
42
|
+
def filename
|
43
|
+
"#{url.sub('/','')}.markdown"
|
44
|
+
end
|
45
|
+
|
46
|
+
def to_file
|
47
|
+
assets = Dir.glob("export/_uploads/**/*").each_with_object({}) { |var, hash| hash[var.sub('export/_uploads','/assets')] = var.sub('export/_uploads','/uploads') }
|
48
|
+
(frontmatter + "---\n\n".freeze + body.to_s).gsub(Regexp.union(assets.keys), assets)
|
49
|
+
end
|
50
|
+
|
51
|
+
protected
|
52
|
+
|
53
|
+
def frontmatter
|
54
|
+
attrs = {}
|
55
|
+
attrs['title'] = title
|
56
|
+
attrs['date'] = Time.parse(published_at).utc
|
57
|
+
attrs['published'] = false if !published?
|
58
|
+
|
59
|
+
meta.each{|m| attrs[m['key']] = m['value'].to_s.gsub("\r\n","\n")} unless meta.nil?
|
60
|
+
|
61
|
+
if defined?(taxonomy) && !taxonomy.nil?
|
62
|
+
taxonomy.each do |t|
|
63
|
+
attrs[t['key']] = t['values'].map{|v| v['value']} unless t['values'].empty?
|
64
|
+
end
|
65
|
+
end
|
66
|
+
|
67
|
+
attrs.empty? ? "---\n".freeze : attrs.to_yaml
|
68
|
+
end
|
69
|
+
|
34
70
|
end
|
35
71
|
end
|
data/lib/siteleaf/post.rb
CHANGED
@@ -16,5 +16,21 @@ module Siteleaf
|
|
16
16
|
result.map { |r| Asset.new(r) } if result
|
17
17
|
end
|
18
18
|
|
19
|
+
def filename(posts_path = 'posts')
|
20
|
+
paths = url.sub('/','').split('/')
|
21
|
+
basename = "#{paths.pop}.markdown"
|
22
|
+
path = paths.join('_')
|
23
|
+
if path == posts_path
|
24
|
+
if draft?
|
25
|
+
path = 'drafts'
|
26
|
+
else
|
27
|
+
path = 'posts'
|
28
|
+
date = Time.parse(published_at).strftime('%Y-%m-%d')
|
29
|
+
basename = "#{date}-#{basename}"
|
30
|
+
end
|
31
|
+
end
|
32
|
+
"_#{path}/#{basename}"
|
33
|
+
end
|
34
|
+
|
19
35
|
end
|
20
36
|
end
|
data/lib/siteleaf/site.rb
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
module Siteleaf
|
2
2
|
class Site < Entity
|
3
3
|
|
4
|
-
attr_accessor :title, :domain, :timezone, :meta
|
4
|
+
attr_accessor :title, :domain, :timezone, :meta, :posts_path
|
5
5
|
attr_reader :id, :user_id, :created_at, :updated_at
|
6
6
|
|
7
7
|
def self.find_by_domain(domain)
|
@@ -27,6 +27,11 @@ module Siteleaf
|
|
27
27
|
result.map { |r| Page.new(r) } if result
|
28
28
|
end
|
29
29
|
|
30
|
+
def posts
|
31
|
+
result = Client.get "sites/#{self.id}/posts"
|
32
|
+
result.map { |r| Post.new(r) } if result
|
33
|
+
end
|
34
|
+
|
30
35
|
def resolve(url = '/')
|
31
36
|
Client.get "sites/#{self.id}/resolve", {"url" => url}
|
32
37
|
end
|
@@ -40,5 +45,68 @@ module Siteleaf
|
|
40
45
|
Job.new(id: result.parsed_response["job_id"]) if result
|
41
46
|
end
|
42
47
|
|
48
|
+
def posts_path
|
49
|
+
@posts_path || 'posts'
|
50
|
+
end
|
51
|
+
|
52
|
+
def filename
|
53
|
+
"_config.yml"
|
54
|
+
end
|
55
|
+
|
56
|
+
def to_file
|
57
|
+
assets = Dir.glob("export/_uploads/**/*").each_with_object({}) { |var, hash| hash[var.sub('export/_uploads','/assets')] = var.sub('export/_uploads','/uploads') }
|
58
|
+
config.gsub(Regexp.union(assets.keys), assets)
|
59
|
+
end
|
60
|
+
|
61
|
+
protected
|
62
|
+
|
63
|
+
def config
|
64
|
+
attrs = {}
|
65
|
+
attrs['title'] = title
|
66
|
+
attrs['url'] = "http://#{domain}"
|
67
|
+
|
68
|
+
meta.each{|m| attrs[m['key']] = m['value'].to_s.gsub("\r\n","\n")} unless meta.nil?
|
69
|
+
|
70
|
+
attrs['timezone'] = timezone
|
71
|
+
attrs['permalink'] = 'pretty'
|
72
|
+
|
73
|
+
# output uploads using v1 /assets path
|
74
|
+
attrs['collections'] = {
|
75
|
+
'uploads' => {
|
76
|
+
'title' => 'Uploads',
|
77
|
+
'output' => true
|
78
|
+
}
|
79
|
+
}
|
80
|
+
|
81
|
+
# use collections for any set of posts not called "posts"
|
82
|
+
pages.each do |page|
|
83
|
+
path = page.url.sub('/','').gsub('/','_')
|
84
|
+
if path != posts_path && page.posts.size > 0
|
85
|
+
attrs['collections'][path] = {'output' => true}
|
86
|
+
# output permalink for non-standard urls (e.g. posts inside sub-pages)
|
87
|
+
attrs['collections'][path]['permalink'] = "#{page.url}/:path" if path != page.slug
|
88
|
+
end
|
89
|
+
end
|
90
|
+
|
91
|
+
# set permalink style for posts
|
92
|
+
attrs['defaults'] = {
|
93
|
+
'scope' => {
|
94
|
+
'path' => '',
|
95
|
+
'type' => 'posts'
|
96
|
+
},
|
97
|
+
'values' => {
|
98
|
+
'permalink' => "/#{posts_path}/:title/"
|
99
|
+
}
|
100
|
+
}
|
101
|
+
|
102
|
+
# markdown defaults to match v1 rendering
|
103
|
+
attrs['markdown'] = 'redcarpet'
|
104
|
+
attrs['redcarpet'] = {
|
105
|
+
'extensions' => ['autolink', 'fenced_code_blocks', 'lax_spacing', 'strikethrough', 'superscript', 'tables', 'footnotes', 'highlight']
|
106
|
+
}
|
107
|
+
|
108
|
+
attrs.empty? ? "---\n".freeze : attrs.to_yaml
|
109
|
+
end
|
110
|
+
|
43
111
|
end
|
44
112
|
end
|
data/lib/siteleaf/version.rb
CHANGED
metadata
CHANGED
@@ -1,55 +1,55 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: siteleaf
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.
|
4
|
+
version: 1.0.0
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Siteleaf
|
8
8
|
autorequire:
|
9
9
|
bindir: bin
|
10
10
|
cert_chain: []
|
11
|
-
date: 2015-
|
11
|
+
date: 2015-10-08 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: httparty
|
15
15
|
requirement: !ruby/object:Gem::Requirement
|
16
16
|
requirements:
|
17
|
-
- -
|
17
|
+
- - ">="
|
18
18
|
- !ruby/object:Gem::Version
|
19
19
|
version: 0.13.3
|
20
20
|
type: :runtime
|
21
21
|
prerelease: false
|
22
22
|
version_requirements: !ruby/object:Gem::Requirement
|
23
23
|
requirements:
|
24
|
-
- -
|
24
|
+
- - ">="
|
25
25
|
- !ruby/object:Gem::Version
|
26
26
|
version: 0.13.3
|
27
27
|
- !ruby/object:Gem::Dependency
|
28
28
|
name: httmultiparty
|
29
29
|
requirement: !ruby/object:Gem::Requirement
|
30
30
|
requirements:
|
31
|
-
- -
|
31
|
+
- - ">="
|
32
32
|
- !ruby/object:Gem::Version
|
33
33
|
version: 0.3.13
|
34
34
|
type: :runtime
|
35
35
|
prerelease: false
|
36
36
|
version_requirements: !ruby/object:Gem::Requirement
|
37
37
|
requirements:
|
38
|
-
- -
|
38
|
+
- - ">="
|
39
39
|
- !ruby/object:Gem::Version
|
40
40
|
version: 0.3.13
|
41
41
|
- !ruby/object:Gem::Dependency
|
42
42
|
name: rack
|
43
43
|
requirement: !ruby/object:Gem::Requirement
|
44
44
|
requirements:
|
45
|
-
- -
|
45
|
+
- - ">="
|
46
46
|
- !ruby/object:Gem::Version
|
47
47
|
version: '0'
|
48
48
|
type: :runtime
|
49
49
|
prerelease: false
|
50
50
|
version_requirements: !ruby/object:Gem::Requirement
|
51
51
|
requirements:
|
52
|
-
- -
|
52
|
+
- - ">="
|
53
53
|
- !ruby/object:Gem::Version
|
54
54
|
version: '0'
|
55
55
|
description: A Ruby interface and command line utility for the Siteleaf API.
|
@@ -60,12 +60,14 @@ executables:
|
|
60
60
|
extensions: []
|
61
61
|
extra_rdoc_files: []
|
62
62
|
files:
|
63
|
-
- .gitignore
|
63
|
+
- ".gitignore"
|
64
|
+
- ".rbenv-vars"
|
64
65
|
- Gemfile
|
65
66
|
- LICENSE.txt
|
66
67
|
- README.md
|
67
68
|
- Rakefile
|
68
69
|
- bin/siteleaf
|
70
|
+
- lib/patches/time_with_zone_encode_with.rb
|
69
71
|
- lib/siteleaf.rb
|
70
72
|
- lib/siteleaf/asset.rb
|
71
73
|
- lib/siteleaf/client.rb
|
@@ -89,12 +91,12 @@ require_paths:
|
|
89
91
|
- lib
|
90
92
|
required_ruby_version: !ruby/object:Gem::Requirement
|
91
93
|
requirements:
|
92
|
-
- -
|
94
|
+
- - ">="
|
93
95
|
- !ruby/object:Gem::Version
|
94
96
|
version: 1.9.3
|
95
97
|
required_rubygems_version: !ruby/object:Gem::Requirement
|
96
98
|
requirements:
|
97
|
-
- -
|
99
|
+
- - ">="
|
98
100
|
- !ruby/object:Gem::Version
|
99
101
|
version: '0'
|
100
102
|
requirements: []
|