-
Notifications
You must be signed in to change notification settings - Fork 0
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
1 parent
bb0ef81
commit ee1889c
Showing
1 changed file
with
184 additions
and
4 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,13 +1,193 @@ | ||
package marshaler | ||
|
||
import "baryon/tool" | ||
import ( | ||
"baryon/tool" | ||
"fmt" | ||
"strings" | ||
) | ||
|
||
// Ensure bashMarshaler implements the Marshaler interface at compile-time. | ||
// Ensure PythonMarshaler implements the Marshaler interface at compile-time. | ||
var _ Marshaler = (*PythonMarshaler)(nil) | ||
|
||
type PythonMarshaler struct{} | ||
|
||
type PythonType struct { | ||
typeName string | ||
typeCheck string | ||
} | ||
|
||
// Obtain a PythonType from a typeName of a tool.Param. | ||
func (p PythonMarshaler) obtainType(typeName string, value string) (*PythonType, error) { | ||
switch typeName { | ||
case "text", "baseurl", "color", "file", "ftpfile", "hidden", "hidden_data": | ||
return &PythonType{ | ||
typeName: "str", | ||
typeCheck: fmt.Sprintf(`not isinstance(%s, str)`, value), | ||
}, nil | ||
case "integer": | ||
return &PythonType{ | ||
typeName: "int", | ||
typeCheck: fmt.Sprintf(`not isinstance(%s, int)`, value), | ||
}, nil | ||
case "float": | ||
return &PythonType{ | ||
typeName: "float", | ||
typeCheck: fmt.Sprintf(`not isinstance(%s, float)`, value), | ||
}, nil | ||
case "boolean": | ||
return &PythonType{ | ||
typeName: "bool", | ||
typeCheck: fmt.Sprintf(`%s not in [True, False]`, value), | ||
}, nil | ||
case "genomebuild", "select": | ||
return &PythonType{ | ||
typeName: "enum", | ||
typeCheck: fmt.Sprintf(`%s == ""`, value), | ||
}, nil | ||
case "data_column", "data", "data_collection", "drill_down": | ||
return &PythonType{ | ||
typeName: "file", | ||
typeCheck: fmt.Sprintf(`not os.path.isfile(%s)`, value), | ||
}, nil | ||
default: | ||
return nil, fmt.Errorf("unknown type: %s", typeName) | ||
} | ||
} | ||
|
||
// Marshal implements Marshaler. | ||
func (p PythonMarshaler) Marshal(*tool.Tool) ([]byte, error) { | ||
panic("unimplemented") | ||
func (p PythonMarshaler) Marshal(tool *tool.Tool) ([]byte, error) { | ||
buffer := []byte("") | ||
if out, err := p.marshalDescription(`"""%s"""`, tool.Description); err != nil { | ||
return nil, fmt.Errorf("[PythonMarshaler.Marshal]: %v", err) | ||
} else { | ||
buffer = append(buffer, out...) | ||
} | ||
|
||
if out, err := p.marshalInputs(tool.Inputs); err != nil { | ||
return nil, fmt.Errorf("[PythonMarshaler.Marshal]: %v", err) | ||
} else { | ||
buffer = append(buffer, out...) | ||
} | ||
|
||
if tool.Command == nil { | ||
return nil, fmt.Errorf("[PythonMarshaler.Marshal]: command not specified.") | ||
} | ||
if out, err := p.marshalContainerAndCommand( | ||
tool.Requirements.Container, | ||
*tool.Command, | ||
); err != nil { | ||
return nil, fmt.Errorf("[PythonMarshaler.Marshal]: %v", err) | ||
} else { | ||
buffer = append(buffer, out...) | ||
} | ||
|
||
return buffer, nil | ||
} | ||
|
||
func (p PythonMarshaler) marshalDescription(format string, description string) ([]byte, error) { | ||
buffer := []byte{} | ||
lines := strings.Split(description, "\n") | ||
for _, l := range lines { | ||
buffer = append(buffer, []byte(fmt.Sprintf(format, l))...) | ||
buffer = append(buffer, []byte("\n")...) | ||
} | ||
return buffer, nil | ||
} | ||
|
||
func (p PythonMarshaler) marshalInputs(inputs *tool.Inputs) ([]byte, error) { | ||
buffer := []byte("\n# Inputs\n") | ||
if out, err := p.processParams(inputs.Param); err != nil { | ||
return nil, fmt.Errorf("[PythonMarshaler.marshalInputs]: %v", err) | ||
} else { | ||
buffer = append(buffer, out...) | ||
} | ||
return append(buffer, []byte("\n# End Inputs\n")...), nil | ||
} | ||
|
||
func (p PythonMarshaler) processParams(params []tool.Param) ([]byte, error) { | ||
if len(params) == 0 { | ||
return nil, nil | ||
} | ||
marshaledParam, err := p.marshalParam(¶ms[0]) | ||
if err != nil { | ||
return nil, fmt.Errorf("[PythonMarshaler.processParams]: %v", err) | ||
} | ||
remainingBytes, err := p.processParams(params[1:]) | ||
if err != nil { | ||
return nil, fmt.Errorf("[PythonMarshaler.processParams]: %v", err) | ||
} | ||
return append(marshaledParam, remainingBytes...), nil | ||
} | ||
|
||
func (p PythonMarshaler) marshalParam(param *tool.Param) ([]byte, error) { | ||
if param == nil { | ||
return nil, fmt.Errorf("[PythonMarshaler.marshalParam]: Empty field") | ||
} | ||
|
||
pythonType, err := p.obtainType(param.Type, param.Name) | ||
if err != nil { | ||
return nil, fmt.Errorf("[PythonMarshaler.marshalParam]: %v", err) | ||
} | ||
|
||
buffer := []byte(fmt.Sprintf("# %s\n", param.Help)) | ||
buffer = append(buffer, []byte(fmt.Sprintf( | ||
`%s = None | ||
if "--%s=" in args: | ||
%s = args["--%s="] | ||
if %s: | ||
raise ValueError("%s is not of type %s")`, | ||
param.Name, | ||
param.Name, | ||
param.Name, | ||
param.Name, | ||
pythonType.typeCheck, | ||
param.Name, | ||
pythonType.typeName, | ||
))...) | ||
return buffer, nil | ||
} | ||
|
||
func (p PythonMarshaler) marshalContainerAndCommand( | ||
containers []tool.Container, | ||
command tool.Command, | ||
) ([]byte, error) { | ||
buffer := []byte("# Command\n") | ||
for _, container := range containers { | ||
if container.Type != "docker" { | ||
return nil, fmt.Errorf("Only docker is supported") | ||
} | ||
buffer = append(buffer, []byte( | ||
fmt.Sprintf("subprocess.run(['docker', 'run', '--rm', %s'%s', f\"%s\"], check=True)\n", | ||
p.marshalVolumes(container.Volumes), | ||
container.Value, | ||
p.marshalCommand(command), | ||
))...) | ||
} | ||
return buffer, nil | ||
} | ||
|
||
func (p PythonMarshaler) marshalCommand(command tool.Command) string { | ||
buffer := []byte{} | ||
for _, element := range strings.Split(command.Value, " ") { | ||
if strings.HasPrefix(element, "$") { | ||
buffer = append(buffer, []byte(fmt.Sprintf( | ||
"{%s}", strings.TrimLeft(element, "$"), | ||
))...) | ||
} else { | ||
buffer = append(buffer, []byte(element)...) | ||
} | ||
buffer = append(buffer, []byte(" ")...) | ||
} | ||
return string(buffer) | ||
} | ||
|
||
func (p PythonMarshaler) marshalVolumes(mappings []tool.VolumeMapping) string { | ||
buffer := []byte{} | ||
for _, mapping := range mappings { | ||
hostPath := strings.TrimLeft(mapping.HostPath, "$") | ||
buffer = append(buffer, []byte(fmt.Sprintf( | ||
"f\" -v {%s}:%s\", ", hostPath, mapping.GuestPath, | ||
))...) | ||
} | ||
return string(buffer) | ||
} |