Path: blob/main/_plugins/gtn/ro-crate.rb
1677 views
# frozen_string_literal: true1require 'zip'234module Gtn5# Parse the git repo to get some facts6module RoCrate7GLOBAL_WORKFLOW_OFFSET = 089def self.cache10@@cache ||= Jekyll::Cache.new('RoCrate')11end1213def self.name2md(site, name)14return %Q([#{Gtn::Contributors.fetch_name(site, name)}](https://training.galaxyproject.org/training-material/hall-of-fame/#{name}/))15end1617def self.write(site, dir, associated_material, workflow, url, baseurl, time_based_version: false)18wfname = workflow['wfname']19# {"workflow"=>"galaxy-workflow-mouse_novel_peptide_analysis.ga",20# "tests"=>false,21# "url"=>22# "http://0.0.0.0:4002/training-material/topics/.../workflows/galaxy-workflow-mouse_novel_peptide_analysis.ga",23# "path"=>24# "topics/proteomics/tutorials/.../galaxy-workflow-mouse_novel_peptide_analysis.ga",25# "wfid"=>"proteomics-proteogenomics-novel-peptide-analysis",26# "wfname"=>"galaxy-workflow-mouse_novel_peptide_analysis",27# "trs_endpoint"=>28# "http://0.0.0.0:4002/training-material/api/.../versions/galaxy-workflow-mouse_novel_peptide_analysis",29# "license"=>nil,30# "creators"=>[],31# "name"=>"GTN Proteogemics3 Novel Peptide Analysis",32# "test_results"=>nil,33# "modified"=>2023-06-07 12:09:36.12 +0200}3435wfdir = File.join(dir, workflow['topic_id'], workflow['tutorial_id'], wfname)36FileUtils.mkdir_p(wfdir)37path = File.join(wfdir, 'ro-crate-metadata.json')38Jekyll.logger.debug "[GTN/API/WFRun] Writing #{path}"39# We have the `dot` graph code in a variable, we need to pass it to `dot -T png ` on the stdin40dot_path = File.join(wfdir, "graph.dot")41File.write(dot_path, workflow['graph_dot'])42Jekyll.logger.debug "[GTN/API/WFRun] dot -T png #{dot_path} > graph.png"43`dot -T png '#{dot_path}' > '#{File.join(wfdir, 'graph.png')}'`4445# Our new workflow IDs46wfurlid = url + baseurl + '/' + workflow['path'].gsub(/.ga$/, '.html')4748uuids = workflow['creators'].map do |c|49if c.key?('identifier') && !c['identifier'].empty?50if c['identifier'].start_with?('http')51c['identifier']52else53"https://orcid.org/#{c['identifier']}"54end55else56"##{SecureRandom.uuid}"57end58end59author_uuids = uuids.map { |u| { '@id' => u.to_s } }60author_linked = workflow['creators'].map.with_index do |c, i|61{62'@id' => (uuids[i]).to_s,63'@type' => c['class'],64'name' => c['name'],65}66end67wf_ga = JSON.parse(File.read(workflow['path']))6869license = workflow['license'] ? "https://spdx.org/licenses/#{workflow['license']}" : 'https://spdx.org/licenses/CC-BY-4.0'7071version = time_based_version ? Time.now.to_i.to_s : Gtn::ModificationTimes.obtain_modification_count(workflow['path']).to_s + ".#{GLOBAL_WORKFLOW_OFFSET}"7273features = {74'Includes [Galaxy Workflow Tests](https://training.galaxyproject.org/training-material/faqs/gtn/workflow_run_test.html)' => workflow['tests'],75'Includes a [Galaxy Workflow Report](https://training.galaxyproject.org/training-material/faqs/galaxy/workflows_report_view.html)' => workflow['features']['report'],76'Uses [Galaxy Workflow Comments](https://training.galaxyproject.org/training-material/faqs/galaxy/workflows_comments.html)' => workflow['features']['comments'],77'Uses [subworkflows](https://training.galaxyproject.org/training-material/faqs/galaxy/workflows_subworkflows.html)' => workflow['features']['subworkflows'],78}7980mat_contribs = [81['Workflow Author(s)', workflow['creators'].map { |c| c['name'] }],82['Tutorial Author(s)', Gtn::Contributors.get_authors(associated_material).map { |n| name2md(site, n) }],83['Tutorial Contributor(s)', Gtn::Contributors.get_non_authors(associated_material).map { |n| name2md(site, n) }],84['Funder(s)', Gtn::Contributors.get_funders(site, associated_material).map { |n| name2md(site, n) }],85['Grants(s)', Gtn::Contributors.get_grants(site, associated_material).map { |n| name2md(site, n) }],86].reject { |_, v| v.empty? }8788description = %Q(89#{wf_ga['annotation']}9091## Associated Tutorial9293This workflows is part of the tutorial [#{associated_material['title']}](#{url}#{baseurl}/topics/#{workflow['topic_id']}/tutorials/#{workflow['tutorial_id']}/tutorial.html), available in the [GTN](https://training.galaxyproject.org)9495#{"## Features" if features.values.any?}9697#{features.select { |_, v| v }.keys.map { |f| "* #{f}" }.join("\n")}9899## Thanks to...100101#{mat_contribs.map { |k, v| "**#{k}**: #{v.join(', ')}" }.join("\n\n")}102103[](https://training.galaxyproject.org/training-material/)104).strip105106crate = {107'@context' => ['https://w3id.org/ro/crate/1.1/context'],108'@graph' => [109{110'@id': 'ro-crate-metadata.json',111'@type': 'CreativeWork',112about: {113'@id': wfurlid,114},115conformsTo: {116'@id': 'https://w3id.org/ro/crate/1.1'117},118},119{120'@id': wfurlid,121'@type': 'Dataset',122name: workflow['name'],123description: description,124version: version,125license: license,126datePublished: workflow['modified'].strftime('%Y-%m-%dT%H:%M:%S.%L%:z'),127# hasPart: [128# {129# '@id': '#assembly-assembly-quality-control'130# }131# ],132mainEntity: {133'@id': "#{wfname}.ga"134},135hasPart: [136{137'@id': "#{wfname}.ga"138},139{140'@id': "graph.png"141},142]143},144{145'@id': "#{wfname}.ga",146'@type': %w[147File148SoftwareSourceCode149ComputationalWorkflow150],151author: author_uuids,152name: workflow['name'],153programmingLanguage: {154'@id': 'https://w3id.org/workflowhub/workflow-ro-crate#galaxy'155},156image: {157'@id': 'graph.png'158}159},160{161'@id': 'graph.png',162'@type': [163'File',164'ImageObject',165'WorkflowSketch'166],167contentSize: File.size(File.join(wfdir, 'graph.png')),168},169{170'@id': 'https://w3id.org/workflowhub/workflow-ro-crate#galaxy',171'@type': 'ComputerLanguage',172identifier: {173'@id': 'https://galaxyproject.org/'174},175name: 'Galaxy',176url: {177'@id': 'https://galaxyproject.org/'178},179version: '23.1'180}181]182}183crate['@graph'] += author_linked184File.write(path, JSON.pretty_generate(crate))185186wf_ga['tags'].map! { |t| t.gsub('^name:', '').capitalize }187wf_ga['tags'].push('GTN')188wf_ga['tags'].push('Galaxy')189# TODO: Remove this after https://github.com/seek4science/seek/issues/1927190wf_ga.delete('creator')191192File.write(File.join(wfdir, 'mod.ga'), JSON.pretty_generate(wf_ga))193194zip_path = File.join(wfdir, 'rocrate.zip')195Jekyll.logger.info "[GTN/API/WFRun] Zipping #{zip_path}"196if File.exist?(zip_path)197File.delete(zip_path)198end199Zip::File.open(zip_path, create: true) do |zipfile|200# - The name of the file as it will appear in the archive201# - The original file, including the path to find it202zipfile.add('ro-crate-metadata.json', path)203zipfile.add('graph.png', File.join(wfdir, 'graph.png'))204zipfile.add("#{wfname}.ga", File.join(wfdir, 'mod.ga'))205end206end207end208end209210211