Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
galaxyproject
GitHub Repository: galaxyproject/training-material
Path: blob/main/_plugins/gtn/ro-crate.rb
1677 views
1
# frozen_string_literal: true
2
require 'zip'
3
4
5
module Gtn
6
# Parse the git repo to get some facts
7
module RoCrate
8
GLOBAL_WORKFLOW_OFFSET = 0
9
10
def self.cache
11
@@cache ||= Jekyll::Cache.new('RoCrate')
12
end
13
14
def self.name2md(site, name)
15
return %Q([#{Gtn::Contributors.fetch_name(site, name)}](https://training.galaxyproject.org/training-material/hall-of-fame/#{name}/))
16
end
17
18
def self.write(site, dir, associated_material, workflow, url, baseurl, time_based_version: false)
19
wfname = workflow['wfname']
20
# {"workflow"=>"galaxy-workflow-mouse_novel_peptide_analysis.ga",
21
# "tests"=>false,
22
# "url"=>
23
# "http://0.0.0.0:4002/training-material/topics/.../workflows/galaxy-workflow-mouse_novel_peptide_analysis.ga",
24
# "path"=>
25
# "topics/proteomics/tutorials/.../galaxy-workflow-mouse_novel_peptide_analysis.ga",
26
# "wfid"=>"proteomics-proteogenomics-novel-peptide-analysis",
27
# "wfname"=>"galaxy-workflow-mouse_novel_peptide_analysis",
28
# "trs_endpoint"=>
29
# "http://0.0.0.0:4002/training-material/api/.../versions/galaxy-workflow-mouse_novel_peptide_analysis",
30
# "license"=>nil,
31
# "creators"=>[],
32
# "name"=>"GTN Proteogemics3 Novel Peptide Analysis",
33
# "test_results"=>nil,
34
# "modified"=>2023-06-07 12:09:36.12 +0200}
35
36
wfdir = File.join(dir, workflow['topic_id'], workflow['tutorial_id'], wfname)
37
FileUtils.mkdir_p(wfdir)
38
path = File.join(wfdir, 'ro-crate-metadata.json')
39
Jekyll.logger.debug "[GTN/API/WFRun] Writing #{path}"
40
# We have the `dot` graph code in a variable, we need to pass it to `dot -T png ` on the stdin
41
dot_path = File.join(wfdir, "graph.dot")
42
File.write(dot_path, workflow['graph_dot'])
43
Jekyll.logger.debug "[GTN/API/WFRun] dot -T png #{dot_path} > graph.png"
44
`dot -T png '#{dot_path}' > '#{File.join(wfdir, 'graph.png')}'`
45
46
# Our new workflow IDs
47
wfurlid = url + baseurl + '/' + workflow['path'].gsub(/.ga$/, '.html')
48
49
uuids = workflow['creators'].map do |c|
50
if c.key?('identifier') && !c['identifier'].empty?
51
if c['identifier'].start_with?('http')
52
c['identifier']
53
else
54
"https://orcid.org/#{c['identifier']}"
55
end
56
else
57
"##{SecureRandom.uuid}"
58
end
59
end
60
author_uuids = uuids.map { |u| { '@id' => u.to_s } }
61
author_linked = workflow['creators'].map.with_index do |c, i|
62
{
63
'@id' => (uuids[i]).to_s,
64
'@type' => c['class'],
65
'name' => c['name'],
66
}
67
end
68
wf_ga = JSON.parse(File.read(workflow['path']))
69
70
license = workflow['license'] ? "https://spdx.org/licenses/#{workflow['license']}" : 'https://spdx.org/licenses/CC-BY-4.0'
71
72
version = time_based_version ? Time.now.to_i.to_s : Gtn::ModificationTimes.obtain_modification_count(workflow['path']).to_s + ".#{GLOBAL_WORKFLOW_OFFSET}"
73
74
features = {
75
'Includes [Galaxy Workflow Tests](https://training.galaxyproject.org/training-material/faqs/gtn/workflow_run_test.html)' => workflow['tests'],
76
'Includes a [Galaxy Workflow Report](https://training.galaxyproject.org/training-material/faqs/galaxy/workflows_report_view.html)' => workflow['features']['report'],
77
'Uses [Galaxy Workflow Comments](https://training.galaxyproject.org/training-material/faqs/galaxy/workflows_comments.html)' => workflow['features']['comments'],
78
'Uses [subworkflows](https://training.galaxyproject.org/training-material/faqs/galaxy/workflows_subworkflows.html)' => workflow['features']['subworkflows'],
79
}
80
81
mat_contribs = [
82
['Workflow Author(s)', workflow['creators'].map { |c| c['name'] }],
83
['Tutorial Author(s)', Gtn::Contributors.get_authors(associated_material).map { |n| name2md(site, n) }],
84
['Tutorial Contributor(s)', Gtn::Contributors.get_non_authors(associated_material).map { |n| name2md(site, n) }],
85
['Funder(s)', Gtn::Contributors.get_funders(site, associated_material).map { |n| name2md(site, n) }],
86
['Grants(s)', Gtn::Contributors.get_grants(site, associated_material).map { |n| name2md(site, n) }],
87
].reject { |_, v| v.empty? }
88
89
description = %Q(
90
#{wf_ga['annotation']}
91
92
## Associated Tutorial
93
94
This 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)
95
96
#{"## Features" if features.values.any?}
97
98
#{features.select { |_, v| v }.keys.map { |f| "* #{f}" }.join("\n")}
99
100
## Thanks to...
101
102
#{mat_contribs.map { |k, v| "**#{k}**: #{v.join(', ')}" }.join("\n\n")}
103
104
[![gtn star logo followed by the word workflows](https://training.galaxyproject.org/training-material/assets/branding/gtn-workflows.png)](https://training.galaxyproject.org/training-material/)
105
).strip
106
107
crate = {
108
'@context' => ['https://w3id.org/ro/crate/1.1/context'],
109
'@graph' => [
110
{
111
'@id': 'ro-crate-metadata.json',
112
'@type': 'CreativeWork',
113
about: {
114
'@id': wfurlid,
115
},
116
conformsTo: {
117
'@id': 'https://w3id.org/ro/crate/1.1'
118
},
119
},
120
{
121
'@id': wfurlid,
122
'@type': 'Dataset',
123
name: workflow['name'],
124
description: description,
125
version: version,
126
license: license,
127
datePublished: workflow['modified'].strftime('%Y-%m-%dT%H:%M:%S.%L%:z'),
128
# hasPart: [
129
# {
130
# '@id': '#assembly-assembly-quality-control'
131
# }
132
# ],
133
mainEntity: {
134
'@id': "#{wfname}.ga"
135
},
136
hasPart: [
137
{
138
'@id': "#{wfname}.ga"
139
},
140
{
141
'@id': "graph.png"
142
},
143
]
144
},
145
{
146
'@id': "#{wfname}.ga",
147
'@type': %w[
148
File
149
SoftwareSourceCode
150
ComputationalWorkflow
151
],
152
author: author_uuids,
153
name: workflow['name'],
154
programmingLanguage: {
155
'@id': 'https://w3id.org/workflowhub/workflow-ro-crate#galaxy'
156
},
157
image: {
158
'@id': 'graph.png'
159
}
160
},
161
{
162
'@id': 'graph.png',
163
'@type': [
164
'File',
165
'ImageObject',
166
'WorkflowSketch'
167
],
168
contentSize: File.size(File.join(wfdir, 'graph.png')),
169
},
170
{
171
'@id': 'https://w3id.org/workflowhub/workflow-ro-crate#galaxy',
172
'@type': 'ComputerLanguage',
173
identifier: {
174
'@id': 'https://galaxyproject.org/'
175
},
176
name: 'Galaxy',
177
url: {
178
'@id': 'https://galaxyproject.org/'
179
},
180
version: '23.1'
181
}
182
]
183
}
184
crate['@graph'] += author_linked
185
File.write(path, JSON.pretty_generate(crate))
186
187
wf_ga['tags'].map! { |t| t.gsub('^name:', '').capitalize }
188
wf_ga['tags'].push('GTN')
189
wf_ga['tags'].push('Galaxy')
190
# TODO: Remove this after https://github.com/seek4science/seek/issues/1927
191
wf_ga.delete('creator')
192
193
File.write(File.join(wfdir, 'mod.ga'), JSON.pretty_generate(wf_ga))
194
195
zip_path = File.join(wfdir, 'rocrate.zip')
196
Jekyll.logger.info "[GTN/API/WFRun] Zipping #{zip_path}"
197
if File.exist?(zip_path)
198
File.delete(zip_path)
199
end
200
Zip::File.open(zip_path, create: true) do |zipfile|
201
# - The name of the file as it will appear in the archive
202
# - The original file, including the path to find it
203
zipfile.add('ro-crate-metadata.json', path)
204
zipfile.add('graph.png', File.join(wfdir, 'graph.png'))
205
zipfile.add("#{wfname}.ga", File.join(wfdir, 'mod.ga'))
206
end
207
end
208
end
209
end
210
211