sutty-migration 0.4.0rc0 → 0.4.0rc1

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 CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: 33b04f68ec23be8ad61143db87c0496fc1a01a84fdb3351b9f76a2782f79342f
4
- data.tar.gz: 411e0050ee48d300c7bcda874f1943b33d867f4c090f72650c0122a69027faa2
3
+ metadata.gz: 41536e494891ca8e5b5a6ea4f98dcf2cdd780bb8f1a16cdfc10bcee9f5195eb6
4
+ data.tar.gz: d73e41285e4bfd4080aad2beb3b9b3a29332ee0f31e64b4438fd0bcc7a479952
5
5
  SHA512:
6
- metadata.gz: 708dff82c233c3819acbe9ccf3901d8345463282ba9df953adb8ac0f15f9646560e514c87499921d13ac6bfa2693c71b0d634e03e1f04e87d0e148174bd91c50
7
- data.tar.gz: 0faa1dc6c107f0999d8a52b7c28b08ad1540e44cff8fd488bfcfae55d2d22548fe0afe61fb54520f4b1d8552674079ba65d617a361139cbb1a5c761581e6df7f
6
+ metadata.gz: b7e64d51403a731be28d4eae8385747dee6abc99e3e5c7b8220240a673b1dee555584706ef0d10f203751eacb51b89022c02ec1d9019b3854a547650f9489e1d
7
+ data.tar.gz: f7ae65bde83caa3404d7de2b825fe751fdc0490fda3c399f4c98f2cf320e037323172b065ec82e9e7af4a5e09ecc5c27e095f3b955c19268e1fe0cc55522a557
data/README.md CHANGED
@@ -119,48 +119,17 @@ a backup, put them there so the plugin finds them.
119
119
  ### WordPress XML
120
120
 
121
121
  If you have the XML dump from a WordPress site, you can migrate content
122
- by writing a migration plugin.
122
+ by using the XML migration plugin and hooking to its steps.
123
123
 
124
124
  ```ruby
125
+ # _plugins/wordpress.rb
125
126
  # frozen_string_literal: true
126
127
 
127
- require 'sutty_migration/jekyll/document_creator'
128
- require 'sutty_migration/wordpress_xml'
129
- require 'jekyll-write-and-commit-changes'
130
- require 'securerandom'
131
-
132
- # Run after reading the site
133
- Jekyll::Hooks.register :site, :post_read do |site|
134
- # Put the XML dump at _files/wordpress.xml
135
- xml = SuttyMigration::WordpressXml.new site: site, file: '_files/wordpress.xml'
136
-
137
- # Download all files
138
- xml.attachments.values.map(&:download)
139
-
140
- # Migrate posts. You can move metadata around and recover
141
- # relationships or any info your theme requires.
142
- xml.posts.values.each do |post|
143
- # Update documents already migrated.
144
- doc = Jekyll::Document.find_or_create(site: site, collection: locale, title: post.title, slug: post.slug, date: post.date)
145
- # Don't change the UUIDv4
146
- d.data['uuid'] ||= SecureRandom.uuid
147
- d.data['draft'] = post.draft?
148
- d.data['layout'] = 'post'
149
- d.data['last_modified_at'] = post.last_modified_at
150
-
151
- d.data['categories'] = post.categories.map { |c| c[:title] }
152
- d.data['tags'] = post.tags.map { |t| t[:title] }
153
-
154
- d.data['author'] = post.author[:email]
155
- d.data['description'] = post.description
156
- d.content = post.content
157
-
158
- doc.save
159
- rescue => e
160
- Jekyll.logger.warn "Couldn't migrate #{post.title}"
161
- end
162
-
163
- exit # Stop here
128
+ require 'jekyll-wordpress-xml-migration'
129
+ require 'pry'
130
+
131
+ Jekyll::Hooks.register :wordpress_post, :post_init do |item|
132
+ binding.pry
164
133
  end
165
134
  ```
166
135
 
@@ -10,10 +10,79 @@
10
10
  # can use `wordpress_url`.
11
11
  #
12
12
  # JEKYLL_ENV=migration bundle exec jekyll build
13
- Jekyll::Hooks.register :site, :post_read, priority: :high do |_site|
13
+ Jekyll::Hooks.register :site, :post_read, priority: :high do |site|
14
14
  next unless Jekyll.env == 'migration'
15
15
 
16
- wordpress_xml = '_files/wordpress.xml'
16
+ file = '_files/wordpress.xml'
17
17
 
18
- Jekyll.logger.abort_with 'Migration:', "#{wordpress_xml} is missing!" unless File.exists wordpress_xml
18
+ Jekyll.logger.abort_with 'Migration:', "#{file} is missing!" unless File.exist? file
19
+
20
+ require 'sutty_migration/wordpress_xml'
21
+ require 'sutty_migration/jekyll/document_creator'
22
+ require 'jekyll-write-and-commit-changes'
23
+
24
+ wordpress = SuttyMigration::WordpressXml.new(site:, file:)
25
+ migrated_posts = []
26
+
27
+ Jekyll::Hooks.trigger :migration, :post_init, wordpress
28
+
29
+ wordpress.attachments.values.uniq.each do |attachment|
30
+ Jekyll::Hooks.trigger :wordpress_attachment, :post_init, attachment.item
31
+
32
+ Jekyll::Hooks.trigger :wordpress_attachment, :pre_render, attachment
33
+ # Download and convert to Sutty's public/
34
+ attachment.public_path
35
+ Jekyll::Hooks.trigger :wordpress_attachment, :post_convert, attachment
36
+ Jekyll::Hooks.trigger :wordpress_attachment, :post_render, attachment
37
+ Jekyll::Hooks.trigger :wordpress_attachment, :post_write, attachment
38
+ end
39
+
40
+ wordpress.posts.each_value do |post|
41
+ Jekyll::Hooks.trigger :wordpress_post, :post_init, post.item
42
+ Jekyll::Hooks.trigger :wordpress_post, :pre_render, post
43
+ Jekyll::Document.find_or_create(site:, slug: post.slug, title: post.title, date: post.date,
44
+ collection: 'posts').tap do |doc|
45
+ # If you want to customize the layout, change it with a :post_init
46
+ # hook.
47
+ doc.data['layout'] = 'post'
48
+ doc.data['permalink'] = post.permalink
49
+ doc.data['created_at'] = post.date
50
+ doc.data['last_modified_at'] = post.last_modified_at&.localtime
51
+ doc.data['uuid'] ||= SecureRandom.uuid
52
+ doc.data['categories'] = post.categories.map { _1[:title] }
53
+ doc.data['tags'] = post.tags.map { _1[:title] }
54
+ doc.data['draft'] = post.draft?
55
+
56
+ unless (attachment_id = post.meta['_thumbnail_id'].to_i).zero?
57
+ attachment = wordpress.attachments[attachment_id]
58
+
59
+ if attachment
60
+ doc.data['image'] = {
61
+ 'path' => attachment.public_path,
62
+ 'description' => ''
63
+ }
64
+ end
65
+ end
66
+
67
+ Jekyll::Hooks.trigger :wordpress_post, :post_convert, doc
68
+
69
+ doc.content = post.beautiful_content
70
+
71
+ Jekyll::Hooks.trigger :wordpress_post, :post_render, doc
72
+
73
+ migrated_posts << doc
74
+ end
75
+ end
76
+
77
+ Jekyll::Hooks.trigger :migration, :post_convert, wordpress
78
+ Jekyll::Hooks.trigger :migration, :post_render, migrated_posts
79
+
80
+ # Save them all at the end
81
+ migrated_posts.each do |doc|
82
+ doc.save
83
+
84
+ Jekyll::Hooks.trigger :wordpress_post, :post_write, doc
85
+ end
86
+
87
+ Jekyll::Hooks.trigger :migration, :post_write, migrated_posts
19
88
  end
@@ -17,11 +17,19 @@ module SuttyMigration
17
17
  @attachment_url ||= attribute_value('attachment_url') || attribute_value('guid')
18
18
  end
19
19
 
20
+ def parsed_url
21
+ @parsed_url ||= Addressable::URI.parse(attachment_url)
22
+ end
23
+
24
+ def normalized_url
25
+ @normalized_url ||= parsed_url.normalize
26
+ end
27
+
20
28
  # File destination
21
29
  #
22
30
  # @return [String]
23
31
  def dest
24
- @dest ||= CGI.unescape(Addressable::URI.parse(attachment_url).path.sub(%r{\A/}, '').unicode_normalize)
32
+ @dest ||= CGI.unescape(parsed_url.path.sub(%r{\A/}, '').unicode_normalize)
25
33
  end
26
34
 
27
35
  # Metadata, with file information as a Hash
@@ -41,32 +49,30 @@ module SuttyMigration
41
49
  def download(progress: true)
42
50
  return true if File.exist? dest
43
51
 
44
- ::Jekyll.logger.info 'Downloading:', dest
45
-
46
52
  FileUtils.mkdir_p File.dirname(dest)
47
53
 
48
54
  File.open(dest, 'w') do |f|
49
- head = Faraday.head(attachment_url)
55
+ head = Faraday.head(normalized_url)
50
56
 
51
57
  if head.status > 399
52
- ::Jekyll.logger.warn 'Error:', head.status.to_s
58
+ ::Jekyll.logger.warn 'Error:', "#{head.status} #{normalized_url}"
53
59
  return false
54
60
  end
55
61
 
56
62
  content_length = head.headers['content-length'].to_i
57
63
 
58
64
  if content_length.zero?
59
- ::Jekyll.logger.warn 'Error:', 'Content length is zero'
65
+ ::Jekyll.logger.warn 'Error:', "Content length is zero for #{normalized_url}"
60
66
  return false
61
67
  end
62
68
 
63
- if progress
64
- progress_bar = ProgressBar.create(title: File.basename(dest), total: content_length,
65
- output: $stderr)
66
- end
69
+ ::Jekyll.logger.info 'Downloading:', dest
70
+
71
+ progress_bar =
72
+ (ProgressBar.create(title: File.basename(dest), total: content_length, output: $stderr) if progress)
67
73
 
68
74
  begin
69
- Faraday.get(attachment_url) do |req|
75
+ Faraday.get(normalized_url) do |req|
70
76
  req.options.on_data = proc do |chunk, downloaded_bytes|
71
77
  if downloaded_bytes > content_length
72
78
  raise Faraday::Error, 'File is bigger than informed, aborting download'
@@ -74,15 +80,16 @@ module SuttyMigration
74
80
 
75
81
  f.write chunk
76
82
 
77
- progress_bar.progress = downloaded_bytes if progress
83
+ progress_bar&.progress = downloaded_bytes
78
84
  end
79
85
  end
80
86
  rescue Faraday::Error => e
81
87
  ::Jekyll.logger.warn 'Error:', e.message
82
88
  end
89
+
90
+ progress_bar&.stop
83
91
  end
84
92
 
85
- progress_bar.stop if progress
86
93
  File.exist? dest
87
94
  end
88
95
 
@@ -94,6 +101,8 @@ module SuttyMigration
94
101
  #
95
102
  # @return [String]
96
103
  def public_path
104
+ return unless digest
105
+
97
106
  @public_path ||= File.join('public', digest[..27], dest.split('/').last).tap do
98
107
  next if File.exist? _1
99
108
 
@@ -102,8 +111,8 @@ module SuttyMigration
102
111
  # or old thumbnails.
103
112
  dir = File.dirname(_1)
104
113
  if File.directory?(dir) && !Dir.empty?(dir)
105
- Jekyll::Logger.warn 'Migration:',
106
- "#{dir} is not empty, you probably have the same file with different names"
114
+ ::Jekyll.logger.warn 'Migration:',
115
+ "#{dir} is not empty, you probably have the same file with different names"
107
116
  end
108
117
 
109
118
  FileUtils.mkdir_p(File.dirname(_1))
@@ -120,9 +129,7 @@ module SuttyMigration
120
129
  begin
121
130
  require 'digest'
122
131
 
123
- raise Faraday::Error unless download
124
-
125
- Digest::SHA2.file(dest).hexdigest
132
+ Digest::SHA2.file(dest).hexdigest if download
126
133
  end
127
134
  end
128
135
  end
@@ -25,7 +25,7 @@ module SuttyMigration
25
25
  data-turbo href id name referrerpolicy rel reversed rowspan src start target title type]
26
26
  # rubocop:enable Style/MutableConstant
27
27
  SLASH = '/'
28
- THUMBNAIL_PREFIX = /(-scaled)?(-\d+x\d+)?(\.....?)\z/
28
+ THUMBNAIL_PREFIX = /-\d+x\d+(\.....?)\z/
29
29
  # TODO: Move to wordpress-formatting
30
30
  WORDPRESS_ELEMENT_START = /\[(\w+ [^\]]+)\]/
31
31
  WORDPRESS_ELEMENT_END = %r{\[(/\w+)\]}
@@ -50,13 +50,13 @@ module SuttyMigration
50
50
 
51
51
  # Permalink. Absolute URL to the post.
52
52
  #
53
- # @return [String]
53
+ # @return [String, nil]
54
54
  def permalink
55
55
  @permalink ||=
56
56
  begin
57
- p = attribute_value('link')&.delete(wordpress.url)
57
+ p = attribute_value('link')&.sub(wordpress.url, '')&.split('?', 2)&.first
58
58
 
59
- unless p.nil?
59
+ unless p.nil? || p.blank?
60
60
  p << SLASH if !p.end_with?(SLASH) && File.extname(p).empty?
61
61
 
62
62
  p.squeeze(SLASH)
@@ -104,10 +104,10 @@ module SuttyMigration
104
104
  #
105
105
  # @return [Time, nil]
106
106
  def last_modified_at
107
- @last_modified_at ||=
108
- if (date = attribute_value('post_modified_gmt'))
109
- ::Jekyll::Utils.parse_date(date)
110
- end
107
+ @last_modified_at ||= %w[post_modified_gmt post_modified].map do |date_attr|
108
+ ::Jekyll::Utils.parse_date attribute_value(date_attr)
109
+ rescue StandardError
110
+ end.compact.first
111
111
  end
112
112
 
113
113
  # Content as an HTML string, converting Wordpress [tags] to <tags>
@@ -135,10 +135,17 @@ module SuttyMigration
135
135
  @parsed_content ||= Nokogiri::HTML.fragment(sanitized_content).tap do |html|
136
136
  html.css('[src]').each do |element|
137
137
  # Remove the thumbnail suffix, we only want the original files
138
- element['src'] = element['src'].sub(THUMBNAIL_PREFIX, '\\3')
138
+ element['src'] = element['src'].sub(THUMBNAIL_PREFIX, '\\1')
139
139
 
140
140
  if element['src'].start_with? wordpress.url
141
- element['src'] = wordpress.attachments[CGI.unescape element['src']].public_path
141
+ attachment = wordpress.attachments[CGI.unescape element['src']]
142
+
143
+ unless attachment
144
+ ::Jekyll.logger.warn 'Error:', "Not found #{element['src']}"
145
+ next
146
+ end
147
+
148
+ element['src'] = attachment.public_path
142
149
 
143
150
  # Move the element into a <figure> like our editor does
144
151
  unless element.parent && element.parent.name == '#document-fragment'
@@ -15,7 +15,13 @@ module SuttyMigration
15
15
  def initialize(site:, file:)
16
16
  @site = site
17
17
  @file = file
18
- @xml = Nokogiri::XML File.read(file)
18
+ @xml = Nokogiri::XML File.read(file).delete("\b").delete("\u0002")
19
+
20
+ if xml.errors.empty?
21
+ ::Jekyll.logger.info 'Migration:', "#{file} parsed correctly"
22
+ else
23
+ ::Jekyll.logger.warn 'Migration:', "#{xml.errors.count} parsing errors found on #{file}!"
24
+ end
19
25
 
20
26
  # Make things easier by removing namespaces.
21
27
  xml.remove_namespaces!
@@ -108,8 +114,8 @@ module SuttyMigration
108
114
  #
109
115
  # @return [Hash]
110
116
  def posts
111
- @posts ||= items_find_by('post_type', 'post').map do |post|
112
- { attribute_value(post, 'post_id').to_i => Post.new(wordpress: self, item: post) }
117
+ @posts ||= items_find_by('post_type', 'post').map do |item|
118
+ { attribute_value(item, 'post_id').to_i => Post.new(wordpress: self, item:) }
113
119
  end.reduce(&:merge)
114
120
  end
115
121
 
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: sutty-migration
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.4.0rc0
4
+ version: 0.4.0rc1
5
5
  platform: ruby
6
6
  authors:
7
7
  - f
8
8
  autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
- date: 2026-10-16 00:00:00.000000000 Z
11
+ date: 2026-10-21 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: jekyll