zarchitect 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.
@@ -0,0 +1,7 @@
1
+ ---
2
+ SHA256:
3
+ metadata.gz: 607e19ad07725bebd0ded8af4ab4ee37759e67b5648a0e5906cf542e9606cef8
4
+ data.tar.gz: 05f141c29c6521b1132a16730140034d16e1367415ef7ae2c5f991320e6c24d5
5
+ SHA512:
6
+ metadata.gz: e550cbd2afe69837e0d3da6036c109f119bec7c2d2288bfcc749d504984515036622938267660ea1b0680fa3f6ecc05f401da7e18f16f28d5bb6de5c529f52b0
7
+ data.tar.gz: 9df3edff73bba15843381649827d0f97a12804fc1df8ff7bccb63a3de00a5b429afe389a89a0027a8328944a97a53f28aed854cb533c18fe237d6e9e7aabf72d
@@ -0,0 +1,3 @@
1
+ #!/usr/bin/env ruby
2
+ require 'zarchitect'
3
+ Zarchitect.new.main
@@ -0,0 +1,22 @@
1
+ --- # zarchitect website config file
2
+ url: http://www.example.com
3
+ email: user@example.com
4
+ site_name: example.com
5
+ site_slogan: the best exampled
6
+ site_description: "a short description of this website"
7
+ admin: webmaster_name
8
+ origin_year: 2020 # can be used for dynamic copyright notices
9
+ title_sep: " | " # separator used in the html title meta tag
10
+ site_keywords: keyA, keyB # keywords for meta tag, string
11
+ thumbl: [640,480] # size for large thumbnails
12
+ thumbs: [320, 240] # size for small thumbnails
13
+ image_limit: 20.0 # MB
14
+ audio_limit: 20.0
15
+ video_limit: 40.0
16
+ rss_size: 10 # number of items in rss feed
17
+ scss_enabled: # root is _assets/ | list of scss files to be turned into css
18
+ - "example.scss"
19
+ exclude_assets: # files with these extensions don't get copied into html tree
20
+ - .scss
21
+ - .scss.swp
22
+ - .css.map
@@ -0,0 +1,16 @@
1
+ # header
2
+ ---
3
+ id: <%= @id %>
4
+ title: <%= @title %>
5
+ date: <%= @date %>
6
+ <% unless @category.nil? %>
7
+ category: <%= @category.key %>
8
+ <% end %>
9
+ author: <%= @author %>
10
+ keywords:
11
+ draft: yes
12
+
13
+
14
+ # content
15
+ ---
16
+
@@ -0,0 +1,179 @@
1
+ require 'gpi'
2
+ require 'yaml'
3
+ require 'erb'
4
+ require 'sanitize'
5
+ require 'rss'
6
+ require 'nokogiri'
7
+
8
+ class Zarchitect
9
+
10
+ HTMLDIR = "_html"
11
+ BUILDIR = "_build"
12
+ FILEDIR = "_files"
13
+ ASSETDIR = "_assets"
14
+ DRAFTDIR = "_drafts"
15
+ LAYOUTDIR = "_layouts"
16
+ CONFIGDIR = "_config"
17
+
18
+ FILESDIR = "files"
19
+ SHARESDIR = "share" # directory under _files that doesn't have thumbnails
20
+ ASSETSDIR = "assets"
21
+ DEBUGSDIR = "debug"
22
+
23
+ def initialize
24
+ @@sections = Array.new
25
+ GPI.app_name = "zarchitect"
26
+ GPI.extend(:dir)
27
+ GPI.extend(:file)
28
+ GPI.extend(:hash)
29
+ GPI.extend(:numeric)
30
+ GPI.extend(:string)
31
+ GPI::CLU.init
32
+ # Command name | range of parameter num | options
33
+ GPI::CLU.use_command("u", [0], "rvqdD")
34
+ GPI::CLU.use_command("update", [0], "rvqdD")
35
+
36
+ GPI::CLU.use_command("ua", [0], "v")
37
+ GPI::CLU.use_command("update-assets", [0], "v")
38
+
39
+ GPI::CLU.use_command("uf", [0], "v")
40
+ GPI::CLU.use_command("update-files", [0], "v")
41
+ GPI::CLU.use_command("setup", [0], "v")
42
+
43
+ GPI::CLU.use_command("new", 2..3, "v")
44
+ #app_command(0..2, "r") # appname = command.name
45
+ GPI::CLU.process_args
46
+ @@rss = ZRSS.new
47
+ end
48
+
49
+ def main
50
+ if GPI::CLU.check_option('v')
51
+ GPI.print "Verbose Mode"
52
+ else
53
+ GPI.print "Non-verbose Mode"
54
+ end
55
+ # Load config
56
+ case GPI::CLU.command
57
+ when "new" # create md file for new web page
58
+ load_conf
59
+ cmd = CMD::New.new
60
+ cmd.run
61
+ when "update","u"
62
+ load_conf
63
+ cmd = CMD::Update.new
64
+ cmd.run
65
+ when "sync"
66
+ # draw data from mastodon / twitter api
67
+ when "update-assets","ua"
68
+ load_conf
69
+ CMD::Misc.update_assets
70
+ when "update-files","uf"
71
+ load_conf
72
+ CMD::Misc.update_files
73
+ when "setup"
74
+ CMD::Misc.setup
75
+ end
76
+ end
77
+
78
+ def rss
79
+ @@rss
80
+ end
81
+
82
+ private
83
+
84
+ def self.rebuild
85
+ # delete all contents of _html
86
+ Dir[ File.join(HTMLDIR, "**", "*") ].reverse.reject do |fullpath|
87
+ if File.directory?(fullpath)
88
+ GPI.print "deleting dir #{fullpath}"
89
+ Dir.delete(fullpath)
90
+ GPI.print "deleted dir #{fullpath}"
91
+ else
92
+ GPI.print "deleting file #{fullpath}"
93
+ File.delete(fullpath)
94
+ GPI.print "deleted file #{fullpath}"
95
+ end
96
+ end
97
+ end
98
+
99
+ def self.setup_html_tree
100
+ Util.mkdir(HTMLDIR)
101
+ Util.mkdir(File.join(HTMLDIR, ASSETSDIR))
102
+ Util.mkdir(File.join(HTMLDIR, FILESDIR))
103
+ Util.mkdir(File.join(BUILDDIR, DEBUGSDIR)) if GPI::CLU.check_option('d')
104
+ end
105
+
106
+ def load_conf
107
+ @@zr_config = Config.new("_config/_zarchitect.yaml", "configuration")
108
+ @@zr_config.validate_zrconf
109
+ @@zr_config.setup
110
+ @@index_config = Config.new("_config/_index.yaml", "index")
111
+ @@index_config.validate
112
+ @@index_config.setup
113
+ @@sec_config = Array.new
114
+ Dir.files("_config").each do |f|
115
+ next if f[0] == "." # don't read swap files
116
+ next if f == "_zarchitect.yaml"
117
+ next if f == "_index.yaml"
118
+ n = f.sub(".yaml", "")
119
+ @@sec_config.push Config.new("_config/#{f}", n)
120
+ @@sec_config.last.validate
121
+ @@sec_config.last.setup
122
+ end
123
+ end
124
+
125
+ def Zarchitect.conf
126
+ @@zr_config
127
+ end
128
+
129
+ def Zarchitect.iconf
130
+ @@index_config
131
+ end
132
+
133
+ def Zarchitect.sconf
134
+ @@sec_config
135
+ end
136
+
137
+ def Zarchitect.add_section(conf)
138
+ #@@sections[conf.key] = Section.new(conf)
139
+ @@sections.push Section.new(conf)
140
+ end
141
+
142
+ def Zarchitect.sections
143
+ @@sections
144
+ end
145
+
146
+ def Zarchitect.section(key)
147
+ @@sections.each do |s|
148
+ return s if s.key == key
149
+ end
150
+ nil
151
+ end
152
+
153
+ end
154
+
155
+ require 'zarchitect/assets.rb'
156
+ require 'zarchitect/audio.rb'
157
+ require 'zarchitect/category.rb'
158
+ require 'zarchitect/config.rb'
159
+ require 'zarchitect/content.rb'
160
+ require 'zarchitect/file_manager.rb'
161
+ require 'zarchitect/html.rb'
162
+ require 'zarchitect/htmltable.rb'
163
+ require 'zarchitect/image.rb'
164
+ require 'zarchitect/image_set.rb'
165
+ require 'zarchitect/index.rb'
166
+ require 'zarchitect/cmd_misc.rb'
167
+ require 'zarchitect/cmd_new.rb'
168
+ require 'zarchitect/cmd_update.rb'
169
+ require 'zarchitect/misc_file.rb'
170
+ require 'zarchitect/post.rb'
171
+ require 'zarchitect/paginator.rb'
172
+ require 'zarchitect/rouge_html.rb'
173
+ require 'zarchitect/rss.rb'
174
+ require 'zarchitect/scss.rb'
175
+ require 'zarchitect/section.rb'
176
+ require 'zarchitect/tag.rb'
177
+ require 'zarchitect/util.rb'
178
+ require 'zarchitect/video.rb'
179
+ require 'zarchitect/zerb.rb'
@@ -0,0 +1,50 @@
1
+ require 'gpi'
2
+
3
+ class Assets < Zarchitect
4
+
5
+ def initialize
6
+ @from = ASSETDIR
7
+ @to = File.join(HTMLDIR, ASSETSDIR)
8
+ end
9
+
10
+ def update
11
+ Dir[ File.join(@from, '**', '*') ].reject do |fullpath|
12
+ path = fullpath[(@from.length)..-1]
13
+ if path.include?(HTMLDIR)
14
+ realpath = path[1..-1]
15
+ else
16
+ realpath = File.join(@to, path)
17
+ Util.mkdir(realpath) if File.directory?(fullpath)
18
+ end
19
+
20
+ next if File.directory?(fullpath)
21
+
22
+ if File.exist?(realpath)
23
+ if File.stat(fullpath).mtime > File.stat(realpath).mtime
24
+ copy_file(fullpath, realpath)
25
+ end
26
+ else
27
+ copy_file(fullpath, realpath)
28
+ end
29
+ end
30
+ end
31
+
32
+ def cpdirs
33
+ Dir[ File.join(@from, '**', '*') ].reject do |fullpath|
34
+ path = fullpath[(@from.length)..-1]
35
+ if path.include?(HTMLDIR)
36
+ realpath = path[1..-1]
37
+ else
38
+ realpath = File.join(@to, path)
39
+ Util.mkdir(realpath) if File.directory?(fullpath)
40
+ end
41
+
42
+ end
43
+ end
44
+
45
+ def copy_file(a, b)
46
+ GPI.print "Copying from #{a} to #{b}.", GPI::CLU.check_option('v')
47
+ File.copy(a, b)
48
+ end
49
+
50
+ end
@@ -0,0 +1,31 @@
1
+ class Audio < Zarchitect
2
+ attr_reader :size, :type, :url
3
+
4
+ def initialize(path)
5
+ @path = path
6
+ @url = path.clone
7
+ @url[0] = "/"
8
+ @size = File.size(path)
9
+ @type = "audio/" << File.extname(path)[1..-1]
10
+
11
+ if @size > Zarchitect.conf.audio_limit.to_f.mib_to_bytes
12
+ GPI.print "Error: File #{path} too large "\
13
+ "(#{@size.bytes_to_mib.to_f.round(2)}MiB)."\
14
+ " Allowed size: #{Zarchitect.conf.audio_limit.to_f.mb_to_mib.round(2)}"
15
+ GPI.quit
16
+ end
17
+ end
18
+
19
+ def self.is_valid?(filename)
20
+ [".mp3",".ogg"].include?(File.extname(filename))
21
+ end
22
+
23
+ def self.find(k, v)
24
+ ObjectSpace.each_object(Audio) do |a|
25
+ str = a.send(k)
26
+ return a if str == v
27
+ end
28
+ nil
29
+ end
30
+
31
+ end
@@ -0,0 +1,62 @@
1
+ class Category < Zarchitect
2
+ attr_reader :key, :name, :section, :url, :tags
3
+
4
+ def initialize(key, name, section)
5
+ @key = key
6
+ @name = name
7
+ @section = section
8
+ @url = "/#{@section.key}/#{@key}/index.html"
9
+
10
+ create_dir
11
+ end
12
+
13
+ def build_html
14
+ if @tags
15
+ @tags.each do |t|
16
+ t.build_html
17
+ end
18
+ end
19
+ @index.build_html
20
+ end
21
+
22
+ def write_html
23
+ if @tags
24
+ @tags.each do |t|
25
+ t.write_html
26
+ end
27
+ end
28
+ @index.write_html
29
+ end
30
+
31
+ def fetch_tags
32
+ # after fetch_pages is implemented
33
+ ar = Array.new
34
+ posts.each do |p|
35
+ if p.conf.has_option?("tags")
36
+ p.conf.tags.each { |t| ar.push t }
37
+ end
38
+ end
39
+ ar.sort!.uniq!
40
+ if ar.count == 0
41
+ @tags = nil
42
+ else
43
+ @tags = Array.new
44
+ ar.each { |v| @tags.push Tag.new(v, self) }
45
+ end
46
+ end
47
+
48
+ def posts
49
+ @section.posts.select { |p| p.category == self }
50
+ end
51
+
52
+ def setup_index
53
+ @index = Index.new(self)
54
+ end
55
+
56
+ private
57
+
58
+ def create_dir
59
+ Util.mkdir(File.join(HTMLDIR, @section.key, @key))
60
+ end
61
+
62
+ end
@@ -0,0 +1,34 @@
1
+ module CMD
2
+
3
+ class Misc < Zarchitect
4
+
5
+ def self.setup
6
+ Zarchitect.setup_html_tree
7
+ Util.mkdir(FILEDIR)
8
+ Util.mkdir(ASSETDIR)
9
+ Util.mkdir(LAYOUTDIR)
10
+ Util.mkdir(CONFIGDIR)
11
+
12
+ a = File.join(Util.path_to_data, "_zarchitect.yaml")
13
+ b = File.join(CONFIGDIR, "_zarchitect.yaml")
14
+
15
+ File.copy(File.join(Util.path_to_data, "_zarchitect.yaml"), File.join(
16
+ CONFIGDIR, "_zarchitect.yaml"))
17
+ end
18
+
19
+ def self.update_files
20
+ @files = FileManager.new
21
+ @files.run
22
+ end
23
+
24
+ def self.update_assets
25
+ Util.mkdir(File.join(HTMLDIR, ASSETSDIR))
26
+ SCSS.run
27
+ @assets = Assets.new
28
+ @assets.cpdirs
29
+ @assets.update
30
+ end
31
+
32
+ end
33
+
34
+ end
@@ -0,0 +1,75 @@
1
+ module CMD
2
+
3
+ class New < Zarchitect
4
+
5
+ def initialize
6
+ Zarchitect.sconf.each { |s| Zarchitect.add_section(s) }
7
+ @section = Zarchitect.section(GPI::CLU.parameters[0])
8
+ if @section.nil?
9
+ GPI.print "Error: Section with key #{GPI::CLU.parameters[0]} does " +
10
+ "not exist."
11
+ GPI.quit
12
+ end
13
+ if GPI::CLU.parameters.size > 2
14
+ @category = nil
15
+ @category = @section.find_category(GPI::CLU.parameters[1])
16
+ if @category.nil?
17
+ GPI.print "Error: category with key #{GPI::CLU.parameters[1]} " +
18
+ "not found in #{@section}."
19
+ GPI.quit
20
+ end
21
+ @title = GPI::CLU.parameters[2]
22
+ @dir = File.join(@section.key, @category.key)
23
+ else
24
+ @title = GPI::CLU.parameters[1]
25
+ @dir = File.join(@section.key)
26
+ end
27
+ end
28
+
29
+ def run
30
+ @id = get_id
31
+ # write file
32
+ a = ZERB.new(File.join(Util.path_to_data, "post.md.erb"))
33
+ data = Hash.new
34
+ data["title"] = @title
35
+ data["date"] = Time.now
36
+ data["author"] = Zarchitect.conf.admin
37
+ data["id"] = @id
38
+ data["category"] = @category
39
+ a.handle_data(data)
40
+ a.prepare
41
+ a.render
42
+ str = a.output
43
+ @dest = File.join(@dir, "#{@id}-#{@title}.md")
44
+ GPI.print "Writing #{@dest}"
45
+ if File.exist?(@dest)
46
+ GPI.print "Error: File at #{@dest} already exists!"
47
+ GPI.quit
48
+ end
49
+ File.open(@dest, "w") { |f| f.write(str) }
50
+ GPI.print "Wrote #{@dest}"
51
+ end
52
+
53
+ private
54
+
55
+ def get_id
56
+ t = Time.now.to_i
57
+ id = t.to_s(16).downcase
58
+
59
+ idlist = Array.new
60
+ Zarchitect.sections.each do |s|
61
+ s.all_posts.each do |p|
62
+ idlist.push p.conf.id if p.conf.has_option?("id")
63
+ end
64
+ end
65
+
66
+ i = 1
67
+ while idlist.include?(id) do
68
+ id = (t+i).to_s(16).upcase
69
+ i += 1
70
+ end
71
+ id
72
+ end
73
+
74
+ end
75
+ end