From a692a5b50cc3d543e4c6fee207e22f84164a8fc3 Mon Sep 17 00:00:00 2001 From: MontrealSergiy Date: Thu, 7 Dec 2023 16:10:05 -0500 Subject: [PATCH 1/8] config's boutiques descriptor auto-refresh #1174 --- BrainPortal/app/models/tool_config.rb | 8 +++++++- BrainPortal/lib/boutiques_support.rb | 14 +++++++++++--- 2 files changed, 18 insertions(+), 4 deletions(-) diff --git a/BrainPortal/app/models/tool_config.rb b/BrainPortal/app/models/tool_config.rb index b6c5ba068..08f5af43e 100644 --- a/BrainPortal/app/models/tool_config.rb +++ b/BrainPortal/app/models/tool_config.rb @@ -625,15 +625,21 @@ def self.register_descriptor(descriptor, tool_name, tool_version) #:nodoc: def self.registered_boutiques_descriptor(tool_name, tool_version) #:nodoc: @_descriptors_ ||= {} key = [ tool_name, tool_version ] # two strings + @_descriptors_[key] = @_descriptors_[key]&.reload_if_file_timestamp_changed @_descriptors_[key] end def boutiques_descriptor + if @_descriptor_ + @_descriptor_ = @_descriptor_.reload_if_file_timestamp_changed + key = [ self.tool.name, self.version_name ] # two strings + @_descriptors_[key] = @_descriptor_ + return @_descriptor_ + end path = boutiques_descriptor_path.presence if ! path return self.class.registered_boutiques_descriptor(self.tool.name, self.version_name) end - return @_descriptor_ if @_descriptor_ path = Pathname.new(path) path = Pathname.new(CBRAIN::BoutiquesDescriptorsPlugins_Dir) + path if path.relative? @_descriptor_ = BoutiquesSupport::BoutiquesDescriptor.new_from_file(path) diff --git a/BrainPortal/lib/boutiques_support.rb b/BrainPortal/lib/boutiques_support.rb index f293624fc..5c1231e38 100644 --- a/BrainPortal/lib/boutiques_support.rb +++ b/BrainPortal/lib/boutiques_support.rb @@ -151,7 +151,7 @@ class ContainerImage < RestrictedHash ; end class BoutiquesDescriptor attr_accessor :from_file # not a hash attribute; a file name, for info - + attr_accessor :mtime_of_file # not a hash attribute, a file timestamp, for caching def initialize(hash={}) super(hash) @@ -175,10 +175,17 @@ def self.new_from_string(text) def self.new_from_file(path) obj = self.new_from_string(File.read(path)) - obj.from_file = path + obj.from_file = path + obj.mtime_of_file = File.mtime(path) obj end + def reload_if_file_timestamp_changed() + filepath = self.from_file + return self if filepath.blank? || File.mtime(filepath) == self.mtime_of_file + self.class.new_from_file(filepath) + end + def validate BoutiquesSupport.validate(self) # amazingly, the JSON validator also work with our descriptor class end @@ -186,7 +193,8 @@ def validate # When dup'ing, also copy the from_file attribute def dup #:nodoc: copy = super - copy.from_file = self.from_file + copy.from_file = self.from_file + copy.mtime_of_file = self.mtime_of_file copy end From af8a22c682f650ff4f7a374314fff2c882d408e0 Mon Sep 17 00:00:00 2001 From: MontrealSergiy Date: Tue, 1 Apr 2025 08:52:29 -0400 Subject: [PATCH 2/8] safegards for old boutiques and misc minor corrections --- BrainPortal/app/models/tool_config.rb | 12 ++++++------ BrainPortal/lib/boutiques_support.rb | 2 +- 2 files changed, 7 insertions(+), 7 deletions(-) diff --git a/BrainPortal/app/models/tool_config.rb b/BrainPortal/app/models/tool_config.rb index 08f5af43e..0d4d59a69 100644 --- a/BrainPortal/app/models/tool_config.rb +++ b/BrainPortal/app/models/tool_config.rb @@ -625,21 +625,21 @@ def self.register_descriptor(descriptor, tool_name, tool_version) #:nodoc: def self.registered_boutiques_descriptor(tool_name, tool_version) #:nodoc: @_descriptors_ ||= {} key = [ tool_name, tool_version ] # two strings - @_descriptors_[key] = @_descriptors_[key]&.reload_if_file_timestamp_changed + @_descriptors_[key] &&= @_descriptors_[key].try :reload_if_file_timestamp_changed # try to support old style boutiques @_descriptors_[key] end def boutiques_descriptor + path = boutiques_descriptor_path.presence + return self.class.registered_boutiques_descriptor(self.tool.name, self.version_name) if ! path + if @_descriptor_ - @_descriptor_ = @_descriptor_.reload_if_file_timestamp_changed + @_descriptor_ &&= @_descriptor_.try :reload_if_file_timestamp_changed key = [ self.tool.name, self.version_name ] # two strings @_descriptors_[key] = @_descriptor_ return @_descriptor_ end - path = boutiques_descriptor_path.presence - if ! path - return self.class.registered_boutiques_descriptor(self.tool.name, self.version_name) - end + path = Pathname.new(path) path = Pathname.new(CBRAIN::BoutiquesDescriptorsPlugins_Dir) + path if path.relative? @_descriptor_ = BoutiquesSupport::BoutiquesDescriptor.new_from_file(path) diff --git a/BrainPortal/lib/boutiques_support.rb b/BrainPortal/lib/boutiques_support.rb index 5c1231e38..4e226293d 100644 --- a/BrainPortal/lib/boutiques_support.rb +++ b/BrainPortal/lib/boutiques_support.rb @@ -182,7 +182,7 @@ def self.new_from_file(path) def reload_if_file_timestamp_changed() filepath = self.from_file - return self if filepath.blank? || File.mtime(filepath) == self.mtime_of_file + return self if filepath.blank? || (File.mtime(filepath) - self.mtime_of_file ).abs < 1 self.class.new_from_file(filepath) end From ef97e61eb4e727643e119444a0f99407e0c629cd Mon Sep 17 00:00:00 2001 From: MontrealSergiy Date: Wed, 2 Apr 2025 12:27:17 -0400 Subject: [PATCH 3/8] unroll old boutiques safeguards, add cache safeguard --- BrainPortal/app/models/tool_config.rb | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/BrainPortal/app/models/tool_config.rb b/BrainPortal/app/models/tool_config.rb index 0d4d59a69..5fe3fd4f6 100644 --- a/BrainPortal/app/models/tool_config.rb +++ b/BrainPortal/app/models/tool_config.rb @@ -625,7 +625,7 @@ def self.register_descriptor(descriptor, tool_name, tool_version) #:nodoc: def self.registered_boutiques_descriptor(tool_name, tool_version) #:nodoc: @_descriptors_ ||= {} key = [ tool_name, tool_version ] # two strings - @_descriptors_[key] &&= @_descriptors_[key].try :reload_if_file_timestamp_changed # try to support old style boutiques + @_descriptors_[key] = @_descriptors_[key]&.reload_if_file_timestamp_changed @_descriptors_[key] end @@ -634,8 +634,9 @@ def boutiques_descriptor return self.class.registered_boutiques_descriptor(self.tool.name, self.version_name) if ! path if @_descriptor_ - @_descriptor_ &&= @_descriptor_.try :reload_if_file_timestamp_changed + @_descriptor_ = @_descriptor_.reload_if_file_timestamp_changed key = [ self.tool.name, self.version_name ] # two strings + @_descriptors_ ||= {} @_descriptors_[key] = @_descriptor_ return @_descriptor_ end From 3a7ec969ca89892a76ece8a39e7d30bf22ea3c44 Mon Sep 17 00:00:00 2001 From: MontrealSergiy Date: Wed, 2 Apr 2025 12:43:06 -0400 Subject: [PATCH 4/8] unroll short form of if --- BrainPortal/app/models/tool_config.rb | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/BrainPortal/app/models/tool_config.rb b/BrainPortal/app/models/tool_config.rb index 5fe3fd4f6..945842098 100644 --- a/BrainPortal/app/models/tool_config.rb +++ b/BrainPortal/app/models/tool_config.rb @@ -631,7 +631,9 @@ def self.registered_boutiques_descriptor(tool_name, tool_version) #:nodoc: def boutiques_descriptor path = boutiques_descriptor_path.presence - return self.class.registered_boutiques_descriptor(self.tool.name, self.version_name) if ! path + if ! path + return self.class.registered_boutiques_descriptor(self.tool.name, self.version_name) + end if @_descriptor_ @_descriptor_ = @_descriptor_.reload_if_file_timestamp_changed From bb28861322f1ca49ab771389eb0a115e5d5c3b8a Mon Sep 17 00:00:00 2001 From: MontrealSergiy Date: Wed, 2 Apr 2025 13:59:14 -0400 Subject: [PATCH 5/8] put back an empty line in a BoutiquesSupport declaration --- BrainPortal/lib/boutiques_support.rb | 1 + 1 file changed, 1 insertion(+) diff --git a/BrainPortal/lib/boutiques_support.rb b/BrainPortal/lib/boutiques_support.rb index 4e226293d..3c72b39df 100644 --- a/BrainPortal/lib/boutiques_support.rb +++ b/BrainPortal/lib/boutiques_support.rb @@ -153,6 +153,7 @@ class BoutiquesDescriptor attr_accessor :from_file # not a hash attribute; a file name, for info attr_accessor :mtime_of_file # not a hash attribute, a file timestamp, for caching + def initialize(hash={}) super(hash) # The following re-assignments transforms hashes into subobjects (like OutputFile etc) From 251d3c004986f6e6ff549ffcefe8f4d6c2ee4502 Mon Sep 17 00:00:00 2001 From: MontrealSergiy Date: Thu, 8 May 2025 14:25:19 -0400 Subject: [PATCH 6/8] remove redundant brackets #1174 --- BrainPortal/lib/boutiques_support.rb | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/BrainPortal/lib/boutiques_support.rb b/BrainPortal/lib/boutiques_support.rb index 3c72b39df..a98a34ecf 100644 --- a/BrainPortal/lib/boutiques_support.rb +++ b/BrainPortal/lib/boutiques_support.rb @@ -181,7 +181,7 @@ def self.new_from_file(path) obj end - def reload_if_file_timestamp_changed() + def reload_if_file_timestamp_changed filepath = self.from_file return self if filepath.blank? || (File.mtime(filepath) - self.mtime_of_file ).abs < 1 self.class.new_from_file(filepath) From d9c125dd254dc847467eff32b8149c3b3cf9da9c Mon Sep 17 00:00:00 2001 From: MontrealSergiy Date: Thu, 8 May 2025 14:52:45 -0400 Subject: [PATCH 7/8] Drop auto-refresh support for descriptors with manually specified Boutiques paths, due to slated deprecation of paths field. #1174 --- BrainPortal/app/models/tool_config.rb | 13 ++++--------- 1 file changed, 4 insertions(+), 9 deletions(-) diff --git a/BrainPortal/app/models/tool_config.rb b/BrainPortal/app/models/tool_config.rb index 945842098..87582254f 100644 --- a/BrainPortal/app/models/tool_config.rb +++ b/BrainPortal/app/models/tool_config.rb @@ -629,20 +629,15 @@ def self.registered_boutiques_descriptor(tool_name, tool_version) #:nodoc: @_descriptors_[key] end + # This method returns a +BoutiquesDescriptor+ object associated with the + # with tool config either from cache, or if a specific path given from the corresponding file + # is specified from that file def boutiques_descriptor path = boutiques_descriptor_path.presence if ! path return self.class.registered_boutiques_descriptor(self.tool.name, self.version_name) end - - if @_descriptor_ - @_descriptor_ = @_descriptor_.reload_if_file_timestamp_changed - key = [ self.tool.name, self.version_name ] # two strings - @_descriptors_ ||= {} - @_descriptors_[key] = @_descriptor_ - return @_descriptor_ - end - + return @_descriptor_ if @_descriptor_ path = Pathname.new(path) path = Pathname.new(CBRAIN::BoutiquesDescriptorsPlugins_Dir) + path if path.relative? @_descriptor_ = BoutiquesSupport::BoutiquesDescriptor.new_from_file(path) From ff9b2b808e23cea624b7e153ffc490c212b0a781 Mon Sep 17 00:00:00 2001 From: MontrealSergiy Date: Thu, 8 May 2025 16:53:12 -0400 Subject: [PATCH 8/8] comments-docs #1174 --- BrainPortal/lib/boutiques_support.rb | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/BrainPortal/lib/boutiques_support.rb b/BrainPortal/lib/boutiques_support.rb index a98a34ecf..531f08357 100644 --- a/BrainPortal/lib/boutiques_support.rb +++ b/BrainPortal/lib/boutiques_support.rb @@ -181,6 +181,11 @@ def self.new_from_file(path) obj end + # Refreshes the descriptor from the file if the file has changed. + # Returns self if the file has not changed, or a new descriptor + # if the file has changed. This is useful for quickly updating the descriptor(s) + # for small corrections or updates. Presently it is used only for the + # boutiques present in boutiques-descriptor subdirectories. def reload_if_file_timestamp_changed filepath = self.from_file return self if filepath.blank? || (File.mtime(filepath) - self.mtime_of_file ).abs < 1