photish 0.3.3 → 0.3.4

Sign up to get free protection for your applications and to get access to all the features.
@@ -3,8 +3,8 @@ module Photish
3
3
  class FileConfigLocation
4
4
  FILE_NAME = 'config.yml'
5
5
 
6
- def initialize(site_dir)
7
- @site_dir = site_dir
6
+ def initialize(config_dir)
7
+ @config_dir = config_dir
8
8
  end
9
9
 
10
10
  def path
@@ -13,10 +13,10 @@ module Photish
13
13
 
14
14
  private
15
15
 
16
- attr_reader :site_dir
16
+ attr_reader :config_dir
17
17
 
18
18
  def directory
19
- site_dir || Dir.pwd
19
+ config_dir || Dir.pwd
20
20
  end
21
21
 
22
22
  def config_file_name
@@ -1,10 +1,10 @@
1
1
  module Photish
2
2
  module Gallery
3
3
  class Album
4
- include Photish::Gallery::Traits::Urlable
5
- include Photish::Gallery::Traits::Albumable
6
- include Photish::Gallery::Traits::Metadatable
7
- include Photish::Gallery::Traits::Breadcrumbable
4
+ include Traits::Urlable
5
+ include Traits::Albumable
6
+ include Traits::Metadatable
7
+ include Traits::Breadcrumbable
8
8
  include Photish::Plugin::Pluginable
9
9
 
10
10
  delegate :qualities,
@@ -25,8 +25,8 @@ module Photish
25
25
  @photos ||= Dir.entries(path)
26
26
  .reject { |file| ['.', '..'].include?(file) }
27
27
  .map { |file| File.join(path, file) }
28
- .reject { |file| !File.file?(file) }
29
- .reject { |file| !FileMagic.new(FileMagic::MAGIC_MIME).file(file).match(formats) }
28
+ .reject { |file| !File.file?(file) ||
29
+ !image_format?(file) }
30
30
  .map { |file| Photo.new(self, file) }
31
31
  end
32
32
 
@@ -41,6 +41,14 @@ module Photish
41
41
 
42
42
  alias_method :base_url_name, :name
43
43
 
44
+ def image_format?(file)
45
+ extension = File.extname(file).split('.').last.try(:downcase)
46
+ return if extension.nil?
47
+ MIME::Types.type_for(extension).any? do
48
+ |mime| mime.to_s.match(formats)
49
+ end
50
+ end
51
+
44
52
  def album_class
45
53
  self.class
46
54
  end
@@ -1,10 +1,10 @@
1
1
  module Photish
2
2
  module Gallery
3
3
  class Collection
4
- include Photish::Gallery::Traits::Urlable
5
- include Photish::Gallery::Traits::Albumable
6
- include Photish::Gallery::Traits::Metadatable
7
- include Photish::Gallery::Traits::Breadcrumbable
4
+ include Traits::Urlable
5
+ include Traits::Albumable
6
+ include Traits::Metadatable
7
+ include Traits::Breadcrumbable
8
8
  include Photish::Plugin::Pluginable
9
9
 
10
10
  attr_reader :qualities,
@@ -29,11 +29,11 @@ module Photish
29
29
  Photish::Plugin::Type::Collection
30
30
  end
31
31
 
32
- def all_url_paths
33
- @all_url_paths ||= [url_path,
34
- all_albums.map(&:url_path),
35
- all_photos.map(&:url_path),
36
- all_images.map(&:url_path)].flatten
32
+ def all_url_parts
33
+ @all_url_parts ||= [url_parts,
34
+ all_albums.map(&:url_parts),
35
+ all_photos.map(&:url_parts),
36
+ all_images.map(&:url_parts)].flatten(1)
37
37
  end
38
38
 
39
39
  private
@@ -1,7 +1,7 @@
1
1
  module Photish
2
2
  module Gallery
3
3
  class Image
4
- include Photish::Gallery::Traits::Urlable
4
+ include Traits::Urlable
5
5
  include Photish::Plugin::Pluginable
6
6
 
7
7
  delegate :name,
@@ -36,7 +36,7 @@ module Photish
36
36
  alias_method :base_url_name, :name
37
37
 
38
38
  def url_end
39
- "#{slugify(basename)}-#{slugify(quality_name)}#{extension}"
39
+ @url_end ||= "#{slugify(basename)}-#{slugify(quality_name)}#{extension}"
40
40
  end
41
41
 
42
42
  def basename
@@ -1,9 +1,9 @@
1
1
  module Photish
2
2
  module Gallery
3
3
  class Photo
4
- include Photish::Gallery::Traits::Urlable
5
- include Photish::Gallery::Traits::Metadatable
6
- include Photish::Gallery::Traits::Breadcrumbable
4
+ include Traits::Urlable
5
+ include Traits::Metadatable
6
+ include Traits::Breadcrumbable
7
7
  include Photish::Plugin::Pluginable
8
8
 
9
9
  delegate :qualities,
@@ -3,17 +3,13 @@ module Photish
3
3
  module Traits
4
4
  module Breadcrumbable
5
5
  def breadcrumbs
6
- doc = Nokogiri::HTML::DocumentFragment.parse("")
7
- Nokogiri::HTML::Builder.with(doc) do |doc|
8
- doc.ul(class: 'breadcrumbs') {
9
- parents_and_me.each_with_index do |level, index|
10
- doc.li(class: crumb_class(index)) {
11
- doc.a(level.name, href: level.url)
12
- }
13
- end
14
- }
6
+ html = "<ul class=\"breadcrumbs\">"
7
+ parents_and_me.each_with_index do |level, index|
8
+ html << "<li class=\"" << crumb_class(index) << "\">"
9
+ html << "<a href=\"" << level.url << "\">" << level.name << "</a>"
10
+ html << "</li>"
15
11
  end
16
- doc.to_html
12
+ html << "</ul>"
17
13
  end
18
14
 
19
15
  def parents_and_me
@@ -24,13 +20,12 @@ module Photish
24
20
  private
25
21
 
26
22
  def crumb_class(index)
27
- crumb_class = []
28
- crumb_class << 'breadcrumb'
29
- crumb_class << "crumb-#{index}"
30
- crumb_class << 'crumb-first' if index == 0
31
- crumb_class << 'crumb-last' if index == (parents_and_me.count - 1)
32
- crumb_class << 'crumb-only' if parents_and_me.count == 1
33
- crumb_class.join(' ')
23
+ crumb_class = 'breadcrumb'
24
+ crumb_class << ' crumb-' << index.to_s
25
+ crumb_class << ' crumb-first' if index == 0
26
+ crumb_class << ' crumb-last' if index == (parents_and_me.count - 1)
27
+ crumb_class << ' crumb-only' if parents_and_me.count == 1
28
+ crumb_class
34
29
  end
35
30
  end
36
31
  end
@@ -21,11 +21,7 @@ module Photish
21
21
  private
22
22
 
23
23
  def host
24
- @host ||= normalized_host || ''
25
- end
26
-
27
- def normalized_host
28
- url_info.host.try(:chomp, '/')
24
+ @host ||= url_info.host || ''
29
25
  end
30
26
 
31
27
  def slugify(word)
@@ -11,6 +11,7 @@ module Photish
11
11
 
12
12
  def setup_logging(config)
13
13
  return if setup_complete
14
+
14
15
  setup_color_scheme if colorize?(config)
15
16
  setup_stdout_output if output_to_stdout?(config)
16
17
  setup_file_output if output_to_file?(config)
@@ -22,7 +23,7 @@ module Photish
22
23
  private
23
24
 
24
25
  def logging_level(config)
25
- config.logging.level.to_sym
26
+ config.logging.level.try(:to_sym)
26
27
  end
27
28
 
28
29
  def colorize?(config)
@@ -55,7 +56,7 @@ module Photish
55
56
  stdout_appender = Logging.appenders.stdout(
56
57
  'stdout',
57
58
  layout: Logging.layouts.pattern(
58
- pattern: '[%d] %-5l %c: %m\n',
59
+ pattern: '[%d][%p][%t] %-5l %c: %m\n',
59
60
  color_scheme: 'bright'
60
61
  )
61
62
  )
@@ -67,7 +68,7 @@ module Photish
67
68
  file_appender = Logging.appenders.file(
68
69
  'log/photish.log',
69
70
  layout: Logging.layouts.pattern(
70
- pattern: '[%d] %-5l %c: %m\n',
71
+ pattern: '[%d][%p][%t] %-5l %c: %m\n',
71
72
  )
72
73
  )
73
74
  Logging.logger.root.add_appenders(file_appender)
@@ -1,39 +1,63 @@
1
1
  module Photish
2
2
  module Plugin
3
- module Repository
3
+ class Repository
4
+ include Singleton
5
+
4
6
  class << self
5
7
  def reload(log, site_dir)
6
- log.info "Loading plugins..."
7
- Dir[File.join(site_dir, '_plugins', '*.rb')].each do |file|
8
- load file
9
- end
10
-
11
- all_plugins.each do |plugin|
12
- log.info "Found plugin #{plugin}"
13
- end
8
+ self.instance.reload(log, site_dir)
14
9
  end
15
10
 
16
11
  def plugins_for(type)
17
- all_plugins.reject { |m| !m.is_for?(type) }
12
+ self.instance.plugins_for(type)
18
13
  end
19
14
 
20
- def all_plugins
21
- Photish::Plugin.constants.map { |m| constantize(m) }
22
- .reject { |m| ignored_modules.include?(m) }
15
+ def loaded?
16
+ self.instance.loaded?
23
17
  end
24
-
25
- private
18
+ end
26
19
 
27
- def ignored_modules
28
- [Photish::Plugin::Repository,
29
- Photish::Plugin::Pluginable,
30
- Photish::Plugin::Type]
20
+ def reload(log, site_dir)
21
+ log.info "Loading plugins..."
22
+ Dir[File.join(site_dir, '_plugins', '*.rb')].each do |file|
23
+ load file
31
24
  end
32
25
 
33
- def constantize(symbol)
34
- Kernel.const_get("Photish::Plugin::#{symbol}")
26
+ @all_plugins = nil
27
+
28
+ all_plugins.each do |plugin|
29
+ log.info "Found plugin #{plugin}"
35
30
  end
36
31
  end
32
+
33
+ def plugins_for(type)
34
+ all_plugins.reject { |m| !m.is_for?(type) }
35
+ end
36
+
37
+ def all_plugins
38
+ @all_plugins ||= constants.map { |m| constantize(m) }
39
+ .reject { |m| ignored_modules.include?(m) }
40
+ end
41
+
42
+ def loaded?
43
+ @all_plugins.present?
44
+ end
45
+
46
+ private
47
+
48
+ def constants
49
+ Photish::Plugin.constants
50
+ end
51
+
52
+ def ignored_modules
53
+ [Photish::Plugin::Repository,
54
+ Photish::Plugin::Pluginable,
55
+ Photish::Plugin::Type]
56
+ end
57
+
58
+ def constantize(symbol)
59
+ Kernel.const_get("Photish::Plugin::#{symbol}")
60
+ end
37
61
  end
38
62
  end
39
63
  end
@@ -1,30 +1,20 @@
1
1
  module Photish
2
2
  module Render
3
3
  class ImageConversion
4
- def initialize(output_dir, max_workers)
4
+ def initialize(output_dir, worker_index, version_hash, threads)
5
5
  @output_dir = output_dir
6
- @max_workers = max_workers
6
+ @worker_index = worker_index
7
+ @version_hash = version_hash
8
+ @threads = threads
7
9
  @log = Logging.logger[self]
8
10
  end
9
11
 
10
12
  def render(images)
11
- image_queue = to_queue(images)
12
-
13
- log.info "Rendering #{images.count} images across #{max_workers} threads"
13
+ log.info "Rendering #{images.count} images across #{threads} threads"
14
14
 
15
15
  change_manifest.preload
16
- workers = (0...max_workers).map do
17
- Thread.new do
18
- begin
19
- while image = image_queue.pop(true)
20
- convert(image) if changed?(image.url_path, image.path)
21
- end
22
- rescue ThreadError => e
23
- log.info "Expected exception, queue is empty #{e.class} \"#{e.message}\" #{e.backtrace.join("\n")}"
24
- end
25
- end
26
- end
27
- workers.map(&:join)
16
+ threads = spawn_thread_instances(to_queue(images))
17
+ threads.map(&:join)
28
18
  flush_to_disk
29
19
  end
30
20
 
@@ -32,16 +22,32 @@ module Photish
32
22
 
33
23
  attr_reader :output_dir,
34
24
  :log,
35
- :max_workers
25
+ :worker_index,
26
+ :version_hash,
27
+ :threads
36
28
 
37
29
  delegate :record,
38
30
  :changed?,
39
31
  :flush_to_disk,
32
+ :preload,
40
33
  to: :change_manifest
41
34
 
35
+ def spawn_thread_instances(image_queue)
36
+ (0...threads).map do
37
+ Thread.new { process_images(image_queue) }
38
+ end
39
+ end
40
+
41
+ def process_images(image_queue)
42
+ while !image_queue.empty?
43
+ image = image_queue.pop
44
+ convert(image) if changed?(image.url_path, image.path)
45
+ end
46
+ end
47
+
42
48
  def to_queue(images)
43
49
  image_queue = Queue.new
44
- Array(images).each { |image| image_queue << image }
50
+ Array(images).shuffle.each { |image| image_queue << image }
45
51
  image_queue
46
52
  end
47
53
 
@@ -69,7 +75,9 @@ module Photish
69
75
  end
70
76
 
71
77
  def change_manifest
72
- @change_manifest ||= ChangeManifest.new(output_dir)
78
+ @change_manifest ||= Cache::Manifest.new(output_dir,
79
+ worker_index,
80
+ version_hash)
73
81
  end
74
82
  end
75
83
  end
@@ -1,58 +1,44 @@
1
1
  module Photish
2
2
  module Render
3
3
  class Site
4
- def initialize(templates, site_dir, output_dir, max_workers)
5
- @templates = templates
6
- @site_dir = site_dir
7
- @output_dir = output_dir
8
- @max_workers = max_workers
4
+ def initialize(config)
5
+ @config = config
9
6
  end
10
7
 
11
8
  def all_for(collection)
12
- delete_unknown_files(collection.all_url_paths)
9
+ delete_unknown_files(collection.all_url_parts)
13
10
  move_non_ignored_site_contents
14
-
15
11
  collection_template.render(collection)
16
- album_template.render(collection.all_albums)
17
- photo_template.render(collection.all_photos)
18
-
19
- image_conversion.render(collection.all_images)
20
12
  end
21
13
 
22
14
  private
23
15
 
24
- attr_reader :templates,
25
- :site_dir,
26
- :output_dir,
27
- :max_workers
16
+ attr_reader :config
28
17
 
29
- def delete_unknown_files(expected_url_paths)
30
- files_to_delete = Dir["#{output_dir}/**/*"].select do |f|
31
- relative_file_path = f.gsub(/#{output_dir}\/?/, '')
32
- File.file?(f) && expected_url_paths.exclude?(relative_file_path)
33
- end
34
- FileUtils.rm_rf(files_to_delete)
35
- end
18
+ delegate :templates,
19
+ :site_dir,
20
+ :output_dir,
21
+ :worker_index,
22
+ to: :config
36
23
 
37
24
  def move_non_ignored_site_contents
38
25
  FileUtils.mkdir_p(output_dir)
39
26
  FileUtils.cp_r(non_ignored_site_contents, output_dir)
40
27
  end
41
28
 
42
- def image_conversion
43
- Photish::Render::ImageConversion.new(output_dir, max_workers)
44
- end
45
-
46
- def album_template
47
- Photish::Render::Page.new(layout_file, template_album_file, output_dir)
48
- end
49
-
50
- def photo_template
51
- Photish::Render::Page.new(layout_file, template_photo_file, output_dir)
29
+ def delete_unknown_files(url_parts)
30
+ do_not_delete = Set.new(url_parts.map { |url| File.join(output_dir, url) }
31
+ .map(&:to_s))
32
+ files_to_delete = Dir["#{output_dir}/**/*"].select do |f|
33
+ File.file?(f) && !do_not_delete.include?(f)
34
+ end
35
+ FileUtils.rm_rf(files_to_delete)
52
36
  end
53
37
 
54
38
  def collection_template
55
- Photish::Render::Page.new(layout_file, template_collection_file, output_dir)
39
+ Page.new(layout_file,
40
+ template_collection_file,
41
+ output_dir)
56
42
  end
57
43
 
58
44
  def non_ignored_site_contents
@@ -67,14 +53,6 @@ module Photish
67
53
  File.join(site_dir, templates_dir, templates.collection)
68
54
  end
69
55
 
70
- def template_album_file
71
- File.join(site_dir, templates_dir, templates.album)
72
- end
73
-
74
- def template_photo_file
75
- File.join(site_dir, templates_dir, templates.photo)
76
- end
77
-
78
56
  def templates_dir
79
57
  '_templates'
80
58
  end
@@ -0,0 +1,80 @@
1
+ module Photish
2
+ module Render
3
+ class SiteWorker
4
+ def initialize(config, version_hash)
5
+ @config = config
6
+ @version_hash = version_hash
7
+ end
8
+
9
+ def all_for(collection)
10
+ tasks(collection).shuffle.each(&:call)
11
+ end
12
+
13
+ private
14
+
15
+ attr_reader :config,
16
+ :version_hash
17
+
18
+ delegate :templates,
19
+ :site_dir,
20
+ :output_dir,
21
+ :workers,
22
+ :threads,
23
+ :worker_index,
24
+ to: :config
25
+
26
+ def tasks(collection)
27
+ [
28
+ ->{ album_template.render(subset(collection.all_albums)) },
29
+ ->{ photo_template.render(subset(collection.all_photos)) },
30
+ ->{ image_conversion.render(subset(collection.all_images)) },
31
+ ]
32
+ end
33
+
34
+ def subset(items)
35
+ worker_index_zeroed.step(items.count, workers)
36
+ .map { |i| items[i] }
37
+ .compact
38
+ end
39
+
40
+ def image_conversion
41
+ ImageConversion.new(output_dir,
42
+ worker_index,
43
+ version_hash,
44
+ threads)
45
+ end
46
+
47
+ def album_template
48
+ Page.new(layout_file,
49
+ template_album_file,
50
+ output_dir)
51
+ end
52
+
53
+ def photo_template
54
+ Page.new(layout_file,
55
+ template_photo_file,
56
+ output_dir)
57
+ end
58
+
59
+ def layout_file
60
+ File.join(site_dir, templates_dir, templates.layout)
61
+ end
62
+
63
+ def template_album_file
64
+ File.join(site_dir, templates_dir, templates.album)
65
+ end
66
+
67
+ def template_photo_file
68
+ File.join(site_dir, templates_dir, templates.photo)
69
+ end
70
+
71
+ def templates_dir
72
+ '_templates'
73
+ end
74
+
75
+ def worker_index_zeroed
76
+ worker_index - 1
77
+ end
78
+ end
79
+ end
80
+ end
@@ -1,3 +1,3 @@
1
1
  module Photish
2
- VERSION = "0.3.3"
2
+ VERSION = "0.3.4"
3
3
  end
data/lib/photish.rb CHANGED
@@ -10,16 +10,20 @@ require 'webrick'
10
10
  require 'listen'
11
11
  require 'yaml'
12
12
  require 'thor'
13
- require 'filemagic'
14
13
  require 'recursive_open_struct'
15
14
  require 'cgi'
16
15
  require 'facter'
16
+ require 'mime-types'
17
+ require 'thread'
18
+ require 'thwait'
19
+ require 'slim'
17
20
 
18
21
  # Photish
19
22
  require 'photish/plugin/type'
20
23
  require 'photish/plugin/pluginable'
21
24
  require 'photish/plugin/repository'
22
25
  require 'photish/command/base'
26
+ require 'photish/command/worker'
23
27
  require 'photish/command/generate'
24
28
  require 'photish/command/host'
25
29
  require 'photish/command/init'
@@ -43,8 +47,10 @@ require 'photish/gallery/image'
43
47
  require 'photish/gallery/collection'
44
48
  require 'photish/render/page'
45
49
  require 'photish/render/site'
50
+ require 'photish/render/site_worker'
46
51
  require 'photish/render/image_conversion'
47
- require 'photish/render/change_manifest'
52
+ require 'photish/cache/manifest'
53
+ require 'photish/cache/manifest_db_file'
48
54
  require 'photish/rake/task'
49
55
  require 'photish/version'
50
56
 
data/photish.gemspec CHANGED
@@ -27,13 +27,12 @@ Gem::Specification.new do |spec|
27
27
  spec.add_dependency "slim", "~> 3.0"
28
28
  spec.add_dependency "tilt", "~> 2.0"
29
29
  spec.add_dependency "mini_magick", "~> 4.3"
30
- spec.add_dependency "ruby-filemagic", "~> 0.7"
31
30
  spec.add_dependency "mini_exiftool", "~> 2.5"
32
31
  spec.add_dependency "recursive-open-struct", "~> 1.0"
33
- spec.add_dependency "nokogiri", "~> 1.6"
34
32
  spec.add_dependency "logging", "~> 2.0"
35
33
  spec.add_dependency "listen", "~> 3.0"
36
34
  spec.add_dependency "facter", "~> 2.4"
35
+ spec.add_dependency "mime-types", "~> 3.0"
37
36
 
38
37
  spec.add_development_dependency "anemone", "~> 0.7"
39
38
  spec.add_development_dependency "bundler", "~> 1.10"