Skip to content

Commit e82bb18

Browse files
authored
Merge pull request #61 from common-workflow-language/docker-requirement
Parse DockerRequirement and add DockerHub link to page
2 parents e850374 + fb0a126 commit e82bb18

File tree

7 files changed

+140
-2
lines changed

7 files changed

+140
-2
lines changed

LICENSE.md

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -212,3 +212,11 @@ been federally registered with the United States Copyright Office.
212212
All rights reserved.
213213

214214
Use rules apply: https://github.com/logos
215+
216+
---------------------------------------------------------
217+
218+
./src/main/resources/static/img/Docker-logo.png
219+
220+
Copyright 2013-2015 Docker, Inc. All rights reserved.
221+
222+
Use rules apply: https://www.docker.com/brand-guidelines

src/main/java/org/commonwl/viewer/domain/CWLCollection.java

Lines changed: 75 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -24,12 +24,15 @@
2424
import com.fasterxml.jackson.databind.node.ArrayNode;
2525
import com.fasterxml.jackson.databind.node.ObjectNode;
2626
import com.fasterxml.jackson.databind.node.TextNode;
27+
import org.commonwl.viewer.services.DockerService;
2728
import org.eclipse.egit.github.core.RepositoryContents;
2829
import org.commonwl.viewer.services.GitHubService;
2930
import org.yaml.snakeyaml.Yaml;
3031

3132
import java.io.IOException;
3233
import java.util.*;
34+
import java.util.regex.Matcher;
35+
import java.util.regex.Pattern;
3336

3437
/**
3538
* Provides CWL parsing for workflows to gather an overview
@@ -74,6 +77,14 @@ public class CWLCollection {
7477
private final String ARRAY = "array";
7578
private final String ARRAY_ITEMS = "items";
7679
private final String LOCATION = "location";
80+
private final String REQUIREMENTS = "requirements";
81+
private final String HINTS = "hints";
82+
private final String DOCKER_REQUIREMENT = "DockerRequirement";
83+
private final String DOCKER_PULL = "dockerPull";
84+
85+
// URL validation for docker pull id
86+
private final String DOCKERHUB_ID_REGEX = "^([0-9a-z]{4,30})(?:\\/([a-zA-Z0-9_-]+))?(?:\\:[a-zA-Z0-9_-]+)?$";
87+
private final Pattern dockerhubPattern = Pattern.compile(DOCKERHUB_ID_REGEX);
7788

7889
/**
7990
* Creates a new collection of CWL files from a Github repository
@@ -197,7 +208,7 @@ public Workflow getWorkflow() {
197208
}
198209

199210
return new Workflow(label, extractDoc(mainWorkflow), getInputs(mainWorkflow),
200-
getOutputs(mainWorkflow), getSteps(mainWorkflow));
211+
getOutputs(mainWorkflow), getSteps(mainWorkflow), getDockerLink(mainWorkflow));
201212
}
202213

203214
/**
@@ -371,6 +382,69 @@ private CWLElement getDetails(JsonNode inputOutput) {
371382
return null;
372383
}
373384

385+
/**
386+
* Get the docker link from a workflow node
387+
* @param node The overall workflow node
388+
* @return A string with a dockerhub or image link
389+
*/
390+
private String getDockerLink(JsonNode node) {
391+
if (node != null) {
392+
if (node.has(REQUIREMENTS)) {
393+
String dockerLink = extractDockerLink(node.get(REQUIREMENTS));
394+
if (dockerLink != null) {
395+
return extractDockerLink(node.get(REQUIREMENTS));
396+
}
397+
}
398+
if (node.has(HINTS)) {
399+
String dockerLink = extractDockerLink(node.get(HINTS));
400+
if (dockerLink != null) {
401+
return extractDockerLink(node.get(HINTS));
402+
}
403+
}
404+
}
405+
return null;
406+
}
407+
408+
/**
409+
* Get the docker link from a workflow hints or requriements node
410+
* @param hintReq A hints or requirements node
411+
* @return A string with a dockerhub or image link
412+
*/
413+
private String extractDockerLink(JsonNode hintReq) {
414+
// ArrayNode syntax using yaml lists
415+
if (hintReq.getClass() == ArrayNode.class) {
416+
for (JsonNode requirement : hintReq) {
417+
if (requirement.has(CLASS)
418+
&& requirement.get(CLASS).asText().equals(DOCKER_REQUIREMENT)) {
419+
if (requirement.has(DOCKER_PULL)) {
420+
// Format dockerPull string as a dockerhub URL
421+
return DockerService.getDockerHubURL(requirement.get(DOCKER_PULL).asText());
422+
} else {
423+
// Indicate that the docker requirement exists, but we cannot
424+
// provide a link to dockerhub as docker pull is not used
425+
return "true";
426+
}
427+
}
428+
}
429+
// v1.0 object syntax with requirement class as key
430+
} else if (hintReq.getClass() == ObjectNode.class) {
431+
// Look for DockerRequirement
432+
if (hintReq.has(DOCKER_REQUIREMENT)) {
433+
JsonNode dockerReq = hintReq.get(DOCKER_REQUIREMENT);
434+
if (dockerReq.has(DOCKER_PULL)) {
435+
// Format dockerPull string as a dockerhub URL
436+
String dockerPull = dockerReq.get(DOCKER_PULL).asText();
437+
return DockerService.getDockerHubURL(dockerPull);
438+
} else {
439+
// Indicate that the docker requirement exists, but we cannot
440+
// provide a link to dockerhub as docker pull is not used
441+
return "true";
442+
}
443+
}
444+
}
445+
return null;
446+
}
447+
374448
/**
375449
* Extract the id from a node
376450
* @param node The node to have the id extracted from

src/main/java/org/commonwl/viewer/domain/Workflow.java

Lines changed: 13 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -65,16 +65,20 @@ public class Workflow {
6565
private Map<String, CWLElement> outputs;
6666
private Map<String, CWLStep> steps;
6767

68+
// Currently only DockerRequirement is parsed for this
69+
private String dockerLink;
70+
6871
// DOT graph of the contents
6972
private String dotGraph;
7073

7174
public Workflow(String label, String doc, Map<String, CWLElement> inputs,
72-
Map<String, CWLElement> outputs, Map<String, CWLStep> steps) {
75+
Map<String, CWLElement> outputs, Map<String, CWLStep> steps, String dockerLink) {
7376
this.label = label;
7477
this.doc = doc;
7578
this.inputs = inputs;
7679
this.outputs = outputs;
7780
this.steps = steps;
81+
this.dockerLink = dockerLink;
7882

7983
// Create a DOT graph for this workflow and store it
8084
StringWriter graphWriter = new StringWriter();
@@ -172,4 +176,12 @@ public String getLastCommit() {
172176
public void setLastCommit(String lastCommit) {
173177
this.lastCommit = lastCommit;
174178
}
179+
180+
public String getDockerLink() {
181+
return dockerLink;
182+
}
183+
184+
public void setDockerLink(String dockerLink) {
185+
this.dockerLink = dockerLink;
186+
}
175187
}
Lines changed: 32 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,32 @@
1+
package org.commonwl.viewer.services;
2+
3+
import java.util.regex.Matcher;
4+
import java.util.regex.Pattern;
5+
6+
/**
7+
* Handles DockerHub functionality
8+
*/
9+
public class DockerService {
10+
11+
// URL validation for docker pull id
12+
private static final String DOCKERHUB_ID_REGEX = "^([0-9a-z]{4,30})(?:\\/([a-zA-Z0-9_-]+))?(?:\\:[a-zA-Z0-9_-]+)?$";
13+
private static final Pattern dockerhubPattern = Pattern.compile(DOCKERHUB_ID_REGEX);
14+
15+
/**
16+
* Get a DockerHub URL from a dockerPull ID
17+
* @param dockerPull The repository and ID as a string
18+
* @return A docker hub link
19+
*/
20+
public static String getDockerHubURL(String dockerPull) {
21+
Matcher m = dockerhubPattern.matcher(dockerPull);
22+
if (m.find()) {
23+
if (m.group(1).isEmpty()) {
24+
return "https://hub.docker.com/r/_/" + m.group(2);
25+
} else {
26+
return "https://hub.docker.com/r/" + m.group(1) + "/" + m.group(2);
27+
}
28+
}
29+
return null;
30+
}
31+
32+
}

src/main/resources/static/css/main.css

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -55,6 +55,11 @@ body {
5555
margin-right: 5px;
5656
}
5757

58+
#dockerLogo {
59+
height: 75px;
60+
margin-left: 10px;
61+
}
62+
5863
#fullscreen-open, #fullscreen-close {
5964
cursor: pointer;
6065
font-size: 25px;
5.71 KB
Loading

src/main/resources/templates/workflow.html

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -151,6 +151,13 @@ <h2>Workflow: <span th:text="${workflow.label}">Workflow Name</span></h2>
151151
<img th:src="@{'/workflows/' + ${workflow.id} + '/graph/png'}" alt="workflow graph" />
152152
</object>
153153
</div>
154+
<div th:if="${workflow.dockerLink != null}">
155+
<h2 style="float:left;">Requires: </h2>
156+
<a th:unless="${workflow.dockerLink == 'true'}" th:href="${workflow.dockerLink}">
157+
<img id="dockerLogo" src="/img/Docker-logo.png" alt="docker logo" />
158+
</a>
159+
<img th:if="${workflow.dockerLink == 'true'}" id="dockerLogo" src="/img/Docker-logo.png" alt="docker logo" />
160+
</div>
154161
<h2>Inputs</h2>
155162
<div th:if="${workflow.inputs.isEmpty()}" class="alert alert-info">
156163
<p>There are no inputs in this workflow</p>

0 commit comments

Comments
 (0)