Skip to content
Snippets Groups Projects
Commit 365b1fec authored by Arnaud Levy's avatar Arnaud Levy
Browse files

clean refactor

parent ae141107
No related branches found
No related tags found
No related merge requests found
...@@ -31,6 +31,10 @@ class Communication::Website::GitFile < ApplicationRecord ...@@ -31,6 +31,10 @@ class Communication::Website::GitFile < ApplicationRecord
object.before_git_sync object.before_git_sync
git_file = where(website: website, about: object).first_or_create git_file = where(website: website, about: object).first_or_create
git_file.will_be_destroyed = destroy git_file.will_be_destroyed = destroy
# It is very important to go through this specific instance of the website,
# and not through each git_file.website, which would be different instances.
# Otherwise, we get 1 instance of git_repository per git_file,
# and it causes a huge amount of useless queries.
website.git_repository.add_git_file git_file website.git_repository.add_git_file git_file
end end
......
class Git::Analyzer
attr_accessor :git_file
attr_reader :repository
def initialize(repository)
@repository = repository
end
def should_create?
!should_destroy? &&
!exists_on_git? &&
(
!synchronized_with_git? ||
previous_path.nil? ||
previous_sha.nil?
)
end
def should_update?
!should_destroy? &&
(
previous_path != path ||
previous_sha != computed_sha
)
end
def should_destroy?
will_be_destroyed ||
path.nil?
end
protected
def path
git_file.path
end
def sha
git_file.sha
end
def computed_sha
repository.computed_sha(git_file.to_s)
end
def will_be_destroyed
git_file.will_be_destroyed
end
def previous_path
git_file.previous_path
end
def previous_sha
git_file.previous_sha
end
def exists_on_git?
repository.git_sha(git_file.previous_path).present? || # The file exists where it was last time
(
git_file.previous_path.nil? && # Never saved in the database
repository.git_sha(git_file.path).present? # but it exists in the git repo
)
end
def synchronized_with_git?
exists_on_git? && # File exists
git_file.previous_path == git_file.path && # at the same place
repository.git_sha(git_file.path) == git_file.previous_sha # with the same content
end
end
\ No newline at end of file
...@@ -9,7 +9,7 @@ class Git::Providers::Github < Git::Providers::Abstract ...@@ -9,7 +9,7 @@ class Git::Providers::Github < Git::Providers::Abstract
end end
def update_file(path, previous_path, content) def update_file(path, previous_path, content)
file = tree_item_for_path(previous_path) file = tree_item_at_path(previous_path)
return if file.nil? return if file.nil?
batch << { batch << {
path: previous_path, path: previous_path,
...@@ -26,7 +26,7 @@ class Git::Providers::Github < Git::Providers::Abstract ...@@ -26,7 +26,7 @@ class Git::Providers::Github < Git::Providers::Abstract
end end
def destroy_file(path) def destroy_file(path)
file = tree_item_for_path(path) file = tree_item_at_path(path)
return if file.nil? return if file.nil?
batch << { batch << {
path: path, path: path,
...@@ -41,6 +41,10 @@ class Git::Providers::Github < Git::Providers::Abstract ...@@ -41,6 +41,10 @@ class Git::Providers::Github < Git::Providers::Abstract
new_tree = client.create_tree repository, batch, base_tree: tree[:sha] new_tree = client.create_tree repository, batch, base_tree: tree[:sha]
commit = client.create_commit repository, commit_message, new_tree[:sha], branch_sha commit = client.create_commit repository, commit_message, new_tree[:sha], branch_sha
client.update_branch repository, default_branch, commit[:sha] client.update_branch repository, default_branch, commit[:sha]
# The repo changed, invalidate the tree
@tree = nil
@tree_items_by_path = nil
#
true true
end end
...@@ -53,15 +57,14 @@ class Git::Providers::Github < Git::Providers::Abstract ...@@ -53,15 +57,14 @@ class Git::Providers::Github < Git::Providers::Abstract
def git_sha(path) def git_sha(path)
return if path.nil? return if path.nil?
# Try to find in stored tree to avoid multiple queries # Try to find in stored tree to avoid multiple queries
return tree_item_for_path(path)&.dig(:sha) return tree_item_at_path(path)&.dig(:sha)
# This is still generating too many requests, so we try based only on the tree begin
# begin # The fast way, with no query, does not work.
# # The fast way, with no query, does not work. # Let's query the API.
# # Let's query the API. content = client.content repository, path: path
# content = client.content repository, path: path return content[:sha]
# return content[:sha] rescue
# rescue end
# end
nil nil
end end
...@@ -79,6 +82,10 @@ class Git::Providers::Github < Git::Providers::Abstract ...@@ -79,6 +82,10 @@ class Git::Providers::Github < Git::Providers::Abstract
@branch_sha ||= client.branch(repository, default_branch)[:commit][:sha] @branch_sha ||= client.branch(repository, default_branch)[:commit][:sha]
end end
def tree_item_at_path(path)
tree_items_by_path[path] if tree_items_by_path.has_key? path
end
def tree_items_by_path def tree_items_by_path
unless @tree_items_by_path unless @tree_items_by_path
@tree_items_by_path = {} @tree_items_by_path = {}
...@@ -98,7 +105,4 @@ class Git::Providers::Github < Git::Providers::Abstract ...@@ -98,7 +105,4 @@ class Git::Providers::Github < Git::Providers::Abstract
@tree ||= client.tree repository, branch_sha, recursive: true @tree ||= client.tree repository, branch_sha, recursive: true
end end
def tree_item_for_path(path)
tree_items_by_path[path] if tree_items_by_path.has_key? path
end
end end
...@@ -8,7 +8,8 @@ class Git::Repository ...@@ -8,7 +8,8 @@ class Git::Repository
def add_git_file(git_file) def add_git_file(git_file)
puts "Adding #{git_file.path}" puts "Adding #{git_file.path}"
if git_files.empty? if git_files.empty?
action = should_destroy_file?(git_file) ? "Destroy" : "Save" analyzer.git_file = git_file
action = analyzer.should_destroy? ? "Destroy" : "Save"
@commit_message = "[#{ git_file.about.class.name }] #{ action } #{ git_file.about }" @commit_message = "[#{ git_file.about.class.name }] #{ action } #{ git_file.about }"
end end
git_files << git_file git_files << git_file
...@@ -50,71 +51,37 @@ class Git::Repository ...@@ -50,71 +51,37 @@ class Git::Repository
@git_files ||= [] @git_files ||= []
end end
def analyzer
@analyzer ||= Git::Analyzer.new self
end
def sync_git_files def sync_git_files
git_files.each do |file| git_files.each do |git_file|
if should_create_file?(file) analyzer.git_file = git_file
puts "Syncing - Creating #{file.path}" if analyzer.should_create?
provider.create_file file.path, file.to_s puts "Syncing - Creating #{git_file.path}"
elsif should_update_file?(file) provider.create_file git_file.path, git_file.to_s
puts "Syncing - Updating #{file.path}" elsif analyzer.should_update?
provider.update_file file.path, file.previous_path, file.to_s puts "Syncing - Updating #{git_file.path}"
elsif should_destroy_file?(file) provider.update_file git_file.path, git_file.previous_path, git_file.to_s
puts "Syncing - Destroying #{file.previous_path}" elsif analyzer.should_destroy?
provider.destroy_file file.previous_path puts "Syncing - Destroying #{git_file.previous_path}"
provider.destroy_file git_file.previous_path
else else
puts "Syncing - Nothing to do with #{file.path}" puts "Syncing - Nothing to do with #{git_file.path}"
end end
end end
end end
# TODO Arnaud : Nettoyer / Rendre + élégant
def should_create_file?(file)
!should_destroy_file?(file) &&
!file_exists_on_git?(file) &&
(
!file_synchronized_with_git?(file) ||
file.previous_path.nil? ||
file.previous_sha.nil?
)
end
def should_update_file?(file)
!should_destroy_file?(file) &&
(
file.previous_path != file.path ||
file.previous_sha != computed_sha(file.to_s)
)
end
def should_destroy_file?(file)
file.will_be_destroyed ||
file.path.nil?
end
def file_exists_on_git?(file)
git_sha(file.previous_path).present? || # The file exists where it was last time
(
file.previous_path.nil? && # Never saved in the database
git_sha(file.path).present? # but it exists in the git repo
)
end
def file_synchronized_with_git?(file)
file_exists_on_git?(file) && # File exists
file.previous_path == file.path && # at the same place
git_sha(file.path) == file.previous_sha # with the same content
end
def mark_as_synced def mark_as_synced
puts "Marking as synced" puts "Marking as synced"
git_files.each do |git_file| git_files.each do |git_file|
if should_destroy_file?(git_file) analyzer.git_file = git_file
if analyzer.should_destroy?
path = nil path = nil
sha = nil sha = nil
else else
path = git_file.path path = git_file.path
# TODO Arnaud : Invalider le cache des tree et tree_items_by_path pour GitHub pour faire un appel API au lieu de N calculs de SHA
sha = computed_sha(git_file.to_s) sha = computed_sha(git_file.to_s)
end end
puts "Marking #{path}" puts "Marking #{path}"
......
0% Loading or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment