-
Notifications
You must be signed in to change notification settings - Fork 5
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
- Loading branch information
Showing
7 changed files
with
186 additions
and
102 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,5 +1,5 @@ | ||
require_relative '../../../inferno/dsl/fhir_evaluation/evaluator' | ||
require_relative '../../../inferno/dsl/ig' | ||
require_relative '../../../inferno/entities' | ||
require_relative '../../utils/ig_downloader' | ||
|
||
require 'tempfile' | ||
|
@@ -12,15 +12,7 @@ class Evaluate < Thor::Group | |
|
||
def evaluate(ig_path, data_path, _log_level) | ||
validate_args(ig_path, data_path) | ||
|
||
if File.file?(ig_path) | ||
ig = Inferno::DSL::IG.from_file(ig_path) | ||
else | ||
Tempfile.create('package.tgz') do |temp_file| | ||
load_ig(ig_path, nil, { force: true }, temp_file.path) | ||
ig = Inferno::DSL::IG.from_file(temp_file.path) | ||
end | ||
end | ||
_ig = get_ig(ig_path) | ||
|
||
# Rule execution, and result output below will be integrated soon. | ||
|
||
|
@@ -45,6 +37,32 @@ def validate_args(ig_path, data_path) | |
raise "Provided path '#{data_path}' is not a directory" | ||
end | ||
|
||
def get_ig(ig_path) | ||
if File.exist?(ig_path) | ||
ig = Inferno::Entities::IG.from_file(ig_path) | ||
elsif in_user_package_cache?(ig_path.sub('@', '#')) | ||
# NPM syntax for a package identifier is id@version (eg, [email protected]) | ||
# but in the cache the separator is # (hl7.fhir.us.core#3.1.1) | ||
cache_directory = File.join(user_package_cache, ig_path.sub('@', '#')) | ||
ig = Inferno::Entities::IG.from_file(cache_directory) | ||
else | ||
Tempfile.create('package.tgz') do |temp_file| | ||
load_ig(ig_path, nil, { force: true }, temp_file.path) | ||
ig = Inferno::Entities::IG.from_file(temp_file.path) | ||
end | ||
end | ||
ig.add_self_to_repository | ||
ig | ||
end | ||
|
||
def user_package_cache | ||
File.join(Dir.home, '.fhir', 'packages') | ||
end | ||
|
||
def in_user_package_cache?(ig_identifier) | ||
File.directory?(File.join(user_package_cache, ig_identifier)) | ||
end | ||
|
||
def output_results(results, output) | ||
if output&.end_with?('json') | ||
oo = FhirEvaluator::EvaluationResult.to_operation_outcome(results) | ||
|
This file was deleted.
Oops, something went wrong.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,147 @@ | ||
# frozen_string_literal: true | ||
|
||
require 'fhir_models' | ||
require 'rubygems/package' | ||
require 'zlib' | ||
|
||
require_relative '../repositories/igs' | ||
|
||
module Inferno | ||
module Entities | ||
# IG is a wrapper class around the relevant concepts inside an IG. | ||
# Not everything within an IG is currently used by Inferno. | ||
class IG < Entity | ||
ATTRIBUTES = [ | ||
:id, | ||
:profiles, | ||
:extensions, | ||
:value_sets, | ||
:search_params, | ||
:examples | ||
].freeze | ||
|
||
include Inferno::Entities::Attributes | ||
|
||
def initialize(params) | ||
super(params, ATTRIBUTES) | ||
|
||
@profiles = [] | ||
@extensions = [] | ||
@value_sets = [] | ||
@examples = [] | ||
@search_params = [] | ||
end | ||
|
||
def self.from_file(ig_path) | ||
raise "#{ig_path} does not exist" unless File.exist?(ig_path) | ||
|
||
# fhir_models by default logs the entire content of non-FHIR files | ||
# which could be things like a package.json | ||
original_logger = FHIR.logger | ||
FHIR.logger = Logger.new('/dev/null') | ||
|
||
if File.directory?(ig_path) | ||
from_directory(ig_path) | ||
elsif ig_path.end_with? '.tgz' | ||
from_tgz(ig_path) | ||
else | ||
raise "Unable to load #{ig_path} as it does not appear to be a directory or a .tgz file" | ||
end | ||
ensure | ||
FHIR.logger = original_logger if defined? original_logger | ||
end | ||
|
||
def self.from_tgz(ig_path) | ||
tar = Gem::Package::TarReader.new( | ||
Zlib::GzipReader.open(ig_path) | ||
) | ||
|
||
ig = IG.new({}) | ||
|
||
tar.each do |entry| | ||
next if skip_item?(entry.full_name, entry.directory?) | ||
|
||
begin | ||
resource = FHIR::Json.from_json(entry.read) | ||
next if resource.nil? | ||
|
||
ig.handle_resource(resource, entry.full_name) | ||
rescue StandardError | ||
next | ||
end | ||
end | ||
ig | ||
end | ||
|
||
def self.from_directory(ig_path) | ||
ig = IG.new({}) | ||
|
||
Dir.glob("#{ig_path}/**/*") do |f| | ||
next if skip_item?(f, File.directory?(f)) | ||
|
||
begin | ||
resource = FHIR::Json.from_json(File.read(f)) | ||
next if resource.nil? | ||
|
||
ig.handle_resource(resource, f) | ||
rescue StandardError | ||
next | ||
end | ||
end | ||
ig | ||
end | ||
|
||
# These files aren't FHIR resources | ||
FILES_TO_SKIP = ['package.json', 'validation-summary.json'].freeze | ||
|
||
def self.skip_item?(relative_path, is_directory) | ||
return true if is_directory | ||
|
||
file_name = relative_path.split('/').last | ||
|
||
# TODO: consider making these regexes we can iterate over in a single loop | ||
return true unless file_name.end_with? '.json' | ||
return true unless relative_path.start_with? 'package/' | ||
|
||
return true if file_name.start_with? '.' # ignore hidden files | ||
return true if file_name.end_with? '.openapi.json' | ||
return true if FILES_TO_SKIP.include? file_name | ||
|
||
false | ||
end | ||
|
||
def handle_resource(resource, relative_path) | ||
case resource.resourceType | ||
when 'StructureDefinition' | ||
if resource.type == 'Extension' | ||
extensions.push resource | ||
else | ||
profiles.push resource | ||
end | ||
when 'ValueSet' | ||
value_sets.push resource | ||
when 'SearchParameter' | ||
search_params.push resource | ||
when 'ImplementationGuide' | ||
@id = extract_package_id(resource) | ||
else | ||
examples.push(resource) if relative_path.start_with? 'package/example' | ||
end | ||
end | ||
|
||
def extract_package_id(ig_resource) | ||
"#{ig_resource.id}##{ig_resource.version || 'current'}" | ||
end | ||
|
||
# @private | ||
def add_self_to_repository | ||
repository.insert(self) | ||
end | ||
|
||
# @private | ||
def repository | ||
Inferno::Repositories::IGs.new | ||
end | ||
end | ||
end | ||
end |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,9 @@ | ||
require_relative 'in_memory_repository' | ||
|
||
module Inferno | ||
module Repositories | ||
# Repository that deals with persistence for the `IG` entity. | ||
class IGs < InMemoryRepository | ||
end | ||
end | ||
end |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters