miniflow 0.0.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- checksums.yaml +7 -0
- data/LICENSE.txt +21 -0
- data/README.md +3 -0
- data/lib/miniflow.rb +11 -0
- data/lib/miniflow/filecheck.rb +43 -0
- data/lib/miniflow/flow.rb +127 -0
- data/lib/miniflow/tool.rb +54 -0
- data/lib/miniflow/tty_command.rb +57 -0
- data/lib/miniflow/version.rb +5 -0
- metadata +191 -0
checksums.yaml
ADDED
@@ -0,0 +1,7 @@
|
|
1
|
+
---
|
2
|
+
SHA256:
|
3
|
+
metadata.gz: a891bee3c3d611ddca2990643196bae2bd0c9b545e3234e3b67acb68e9661cf6
|
4
|
+
data.tar.gz: 1ce90004f51af85a58dce4e72fb59812d0714302967216b227b61d12901e934c
|
5
|
+
SHA512:
|
6
|
+
metadata.gz: ded8fa695a81f5021eb916943a718fdc0ea31efbe2ad8457fb50be66d43975e0254258a1b92243a7c0ec245f1314072d2e1403aa5fe10f5d9183731229708bb4
|
7
|
+
data.tar.gz: fbdf6fbf13522d926b80c441ba912a0e8cabf47f4f878108435fd605df4c010c2a8c5d11583ba32d4af3c83b9a637eb69fd95dc3c8e61c3ace22bb6ccb12a036
|
data/LICENSE.txt
ADDED
@@ -0,0 +1,21 @@
|
|
1
|
+
The MIT License (MIT)
|
2
|
+
|
3
|
+
Copyright (c) 2020 kojix2
|
4
|
+
|
5
|
+
Permission is hereby granted, free of charge, to any person obtaining a copy
|
6
|
+
of this software and associated documentation files (the "Software"), to deal
|
7
|
+
in the Software without restriction, including without limitation the rights
|
8
|
+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
9
|
+
copies of the Software, and to permit persons to whom the Software is
|
10
|
+
furnished to do so, subject to the following conditions:
|
11
|
+
|
12
|
+
The above copyright notice and this permission notice shall be included in
|
13
|
+
all copies or substantial portions of the Software.
|
14
|
+
|
15
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
16
|
+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
17
|
+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
18
|
+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
19
|
+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
20
|
+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
21
|
+
THE SOFTWARE.
|
data/README.md
ADDED
data/lib/miniflow.rb
ADDED
@@ -0,0 +1,11 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
require_relative 'miniflow/version'
|
4
|
+
require_relative 'miniflow/tty_command'
|
5
|
+
require_relative 'miniflow/filecheck'
|
6
|
+
require_relative 'miniflow/flow'
|
7
|
+
require_relative 'miniflow/tool'
|
8
|
+
|
9
|
+
module Miniflow
|
10
|
+
TTYCMD = TTYCommand.new
|
11
|
+
end
|
@@ -0,0 +1,43 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
require 'fileutils'
|
4
|
+
|
5
|
+
module Miniflow
|
6
|
+
module FileCheck
|
7
|
+
module_function
|
8
|
+
|
9
|
+
# Checks that the file exists and that the extension is correct.
|
10
|
+
# @params path [String] The path to the file to check if it exists
|
11
|
+
# @params extnames [Array, String] File extensions to check.
|
12
|
+
# Multiple extensions can be specified in an array.
|
13
|
+
def check_file(path, extnames)
|
14
|
+
check_file_extname(path, extnames)
|
15
|
+
check_file_exist(path)
|
16
|
+
end
|
17
|
+
|
18
|
+
# Checks if the file exists in the specified path.
|
19
|
+
# @params path [String] The path to the file to check if it exists.
|
20
|
+
def check_file_exist(path)
|
21
|
+
raise "Cannot find: #{path}" unless File.exist?(path)
|
22
|
+
end
|
23
|
+
|
24
|
+
# Make sure that the file has the specified extension.
|
25
|
+
# @params path [String] The path to the file.
|
26
|
+
# @params extnames [Array, String] File extensions to check.
|
27
|
+
def check_file_extname(path, extnames)
|
28
|
+
case extnames
|
29
|
+
when Array
|
30
|
+
raise "Extension is not #{extnames}: #{path}" unless extnames.include?(File.extname(path))
|
31
|
+
when File.extname(path)
|
32
|
+
true
|
33
|
+
else
|
34
|
+
raise "Extension is not #{extnames}: #{path}"
|
35
|
+
end
|
36
|
+
end
|
37
|
+
|
38
|
+
# Creates a directory and all its parent directories.
|
39
|
+
def mkdir_p(*arg)
|
40
|
+
FileUtils.mkdir_p(*arg)
|
41
|
+
end
|
42
|
+
end
|
43
|
+
end
|
@@ -0,0 +1,127 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
require 'tty-tree'
|
4
|
+
require 'tty-screen'
|
5
|
+
|
6
|
+
module Miniflow
|
7
|
+
# Base class for all flows in Miniflow
|
8
|
+
# The input file must be specified as an absolute path.
|
9
|
+
# Each flow has one output directory
|
10
|
+
class Flow
|
11
|
+
include FileCheck
|
12
|
+
|
13
|
+
# Define the initialize method according to the following rules
|
14
|
+
# * Take file paths as arguments. The file paths can be either absolute or
|
15
|
+
# relative.
|
16
|
+
# * Other arguments are keyword arguments.
|
17
|
+
def initialize
|
18
|
+
raise NotImplementedError
|
19
|
+
end
|
20
|
+
|
21
|
+
def cmd
|
22
|
+
TTYCMD
|
23
|
+
end
|
24
|
+
|
25
|
+
# This section is mainly for file validation.
|
26
|
+
def before_run; end
|
27
|
+
|
28
|
+
# This section is mainly used to validate the generated files, display
|
29
|
+
# runtime information, etc.
|
30
|
+
def after_run
|
31
|
+
check_output_files
|
32
|
+
show_results
|
33
|
+
end
|
34
|
+
|
35
|
+
# The main process. It must be implemented.
|
36
|
+
def main_run
|
37
|
+
raise NotImplementedError
|
38
|
+
end
|
39
|
+
|
40
|
+
# If you have a reason, you can overwrite it.
|
41
|
+
# Normally, you should not change it.
|
42
|
+
def run
|
43
|
+
show_start
|
44
|
+
before_run
|
45
|
+
main_run
|
46
|
+
after_run
|
47
|
+
rescue TTY::Command::ExitError => e
|
48
|
+
show_exit_error
|
49
|
+
raise e
|
50
|
+
rescue Errno::ENOENT => e # Maybe we should expand the scope of the error.
|
51
|
+
show_exit_error
|
52
|
+
raise e
|
53
|
+
end
|
54
|
+
|
55
|
+
# Show the banner when the workflow starts.
|
56
|
+
def show_start
|
57
|
+
@start_time = Time.now
|
58
|
+
puts TTY::Box.frame(self.class.name,
|
59
|
+
"Start : #{@start_time}",
|
60
|
+
width: TTY::Screen.width, padding: 1,
|
61
|
+
border: { left: false, right: false })
|
62
|
+
end
|
63
|
+
|
64
|
+
# Show the banner when the workflow is finished.
|
65
|
+
def show_results(generated_files: true)
|
66
|
+
@end_time = Time.now
|
67
|
+
tree = if generated_files
|
68
|
+
[' ',
|
69
|
+
"Generated files: #{@out_dir}",
|
70
|
+
' ',
|
71
|
+
TTY::Tree.new(@out_dir).render]
|
72
|
+
else
|
73
|
+
''
|
74
|
+
end
|
75
|
+
puts
|
76
|
+
puts TTY::Box.frame("Start : #{@start_time}",
|
77
|
+
"End : #{@end_time}",
|
78
|
+
"Time : #{@end_time - @start_time} sec",
|
79
|
+
*tree,
|
80
|
+
title: { top_left: " #{self.class.name} " },
|
81
|
+
width: TTY::Screen.width, padding: 1)
|
82
|
+
end
|
83
|
+
|
84
|
+
# Show the banner when an error occurs and the workflow is abnormally interrupted.
|
85
|
+
def show_exit_error
|
86
|
+
@end_time = Time.now
|
87
|
+
puts TTY::Box.error(
|
88
|
+
"Flow : #{self.class.name}\n" \
|
89
|
+
"Start : #{@start_time}\n" \
|
90
|
+
"End : #{@end_time}\n" \
|
91
|
+
"Time : #{@end_time - @start_time} sec",
|
92
|
+
width: TTY::Screen.width, padding: 1
|
93
|
+
)
|
94
|
+
end
|
95
|
+
|
96
|
+
# Returns the path in the output directory.
|
97
|
+
# The file path is recorded. When the workflow is finished, the output
|
98
|
+
# files are checked for existence in the `check_output_files` method.
|
99
|
+
def odir(file_name)
|
100
|
+
@output_files ||= []
|
101
|
+
file_path = File.join(@out_dir, file_name)
|
102
|
+
@output_files << file_path
|
103
|
+
file_path
|
104
|
+
end
|
105
|
+
|
106
|
+
# Returns the path in the output directory.
|
107
|
+
def dir(file_name)
|
108
|
+
File.join(@out_dir, file_name)
|
109
|
+
end
|
110
|
+
|
111
|
+
# When the workflow is finished, make sure that all the registered output
|
112
|
+
# files are present.Currently, the error does not occur even if the output
|
113
|
+
# file does not exist. A warning will be shown.
|
114
|
+
def check_output_files
|
115
|
+
return if @output_files.nil?
|
116
|
+
|
117
|
+
flag = true
|
118
|
+
@output_files.uniq.each do |file_path|
|
119
|
+
unless File.exist?(file_path)
|
120
|
+
warn "Output file not found: #{file_path}"
|
121
|
+
flag = false
|
122
|
+
end
|
123
|
+
end
|
124
|
+
puts 'All output file exist.' if flag
|
125
|
+
end
|
126
|
+
end
|
127
|
+
end
|
@@ -0,0 +1,54 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
require 'tty-box'
|
4
|
+
require 'tty-screen'
|
5
|
+
|
6
|
+
module Miniflow
|
7
|
+
# Burrow-Wheeler Aligner for short-read alignment.
|
8
|
+
class Tool
|
9
|
+
include FileCheck
|
10
|
+
|
11
|
+
# Use the version options to check if the command is available
|
12
|
+
def available?(command)
|
13
|
+
# puts Pastel.new.magenta("Check #{self.class.name}")
|
14
|
+
pastel = Pastel.new
|
15
|
+
class_name = self.class.name.split('::').last
|
16
|
+
begin
|
17
|
+
result = cmd.run!(command)
|
18
|
+
rescue Errno::ENOENT => e
|
19
|
+
pastel = Pastel.new
|
20
|
+
msg = "\n" \
|
21
|
+
"Please make sure that the #{class_name} is available.\n\n"
|
22
|
+
e.message << msg
|
23
|
+
raise e
|
24
|
+
end
|
25
|
+
if result.failure?
|
26
|
+
msg = "The exit status of #{command} is not zero.\n" \
|
27
|
+
"Please make sure that the #{command} is available.\n\n"
|
28
|
+
raise Errno::ENOENT, msg # FIXME
|
29
|
+
else
|
30
|
+
puts pastel.green.bold("✔ #{class_name}")
|
31
|
+
end
|
32
|
+
end
|
33
|
+
|
34
|
+
# Get tool options
|
35
|
+
def [](key)
|
36
|
+
@options[key]
|
37
|
+
end
|
38
|
+
|
39
|
+
def cmd
|
40
|
+
TTYCMD
|
41
|
+
end
|
42
|
+
|
43
|
+
# Calling the Ruby method executes a subcommand with the same name.
|
44
|
+
# Since the Ruby methods are called first, care must be taken to avoid
|
45
|
+
# name collisions. For example, subcommands such as `call` need to be
|
46
|
+
# redefined.
|
47
|
+
def method_missing(name, *args)
|
48
|
+
cmd.run2(@command, name, *args)
|
49
|
+
end
|
50
|
+
|
51
|
+
# respond_to_missing?(sym, include_private)g
|
52
|
+
# end
|
53
|
+
end
|
54
|
+
end
|
@@ -0,0 +1,57 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
require 'tty-command'
|
4
|
+
|
5
|
+
module Miniflow
|
6
|
+
# Miniflow uses tty-command to execute the command.
|
7
|
+
# Please see the following website for more information.
|
8
|
+
# https://ttytoolkit.org/
|
9
|
+
class TTYCommand < TTY::Command
|
10
|
+
# TTY::Command custom printer
|
11
|
+
# * change default colors.
|
12
|
+
# https://github.com/piotrmurach/tty-command#34-custom-printer
|
13
|
+
class CustomPretty < Printers::Pretty
|
14
|
+
def print_command_start(cmd, *args)
|
15
|
+
message = ["Running #{decorate(cmd.to_command, :cyan)}"]
|
16
|
+
message << args.map(&:chomp).join(' ') unless args.empty?
|
17
|
+
write(cmd, message.join)
|
18
|
+
end
|
19
|
+
|
20
|
+
def print_command_err_data(cmd, *args)
|
21
|
+
message = args.map(&:chomp).join(' ')
|
22
|
+
write(cmd, "\t#{decorate(message, :white)}", err_data)
|
23
|
+
end
|
24
|
+
|
25
|
+
def write(cmd, message, data = nil)
|
26
|
+
cmd_set_uuid = cmd.options.fetch(:uuid, true)
|
27
|
+
uuid_needed = cmd.options[:uuid].nil? ? @uuid : cmd_set_uuid
|
28
|
+
out = []
|
29
|
+
out << "[#{decorate(cmd.uuid, :green)}] " if uuid_needed && !cmd.uuid.nil?
|
30
|
+
out << "#{message}\n"
|
31
|
+
target = cmd.only_output_on_error && !data.nil? ? data : output
|
32
|
+
target << out.join
|
33
|
+
end
|
34
|
+
end
|
35
|
+
|
36
|
+
def initialize(*args)
|
37
|
+
# Do not output uuid
|
38
|
+
super(*args, printer: CustomPretty, uuid: true)
|
39
|
+
end
|
40
|
+
|
41
|
+
# run2 can execute the command in which the UNIX pipeline is used.
|
42
|
+
def run2(*args)
|
43
|
+
args.map!(&:to_s)
|
44
|
+
command = args.join(' ')
|
45
|
+
if include_meta_character?(command)
|
46
|
+
run(command)
|
47
|
+
else
|
48
|
+
run(*args)
|
49
|
+
end
|
50
|
+
end
|
51
|
+
|
52
|
+
def include_meta_character?(str)
|
53
|
+
['*', '?', '{', '}', '[', ']', '<', '>', '(', ')', '~', '&', '|', '\\',
|
54
|
+
'$', ';', "'", '`', '"', "\n"].any? { |i| str.include?(i) }
|
55
|
+
end
|
56
|
+
end
|
57
|
+
end
|
metadata
ADDED
@@ -0,0 +1,191 @@
|
|
1
|
+
--- !ruby/object:Gem::Specification
|
2
|
+
name: miniflow
|
3
|
+
version: !ruby/object:Gem::Version
|
4
|
+
version: 0.0.1
|
5
|
+
platform: ruby
|
6
|
+
authors:
|
7
|
+
- kojix2
|
8
|
+
autorequire:
|
9
|
+
bindir: bin
|
10
|
+
cert_chain: []
|
11
|
+
date: 2020-12-11 00:00:00.000000000 Z
|
12
|
+
dependencies:
|
13
|
+
- !ruby/object:Gem::Dependency
|
14
|
+
name: tty-box
|
15
|
+
requirement: !ruby/object:Gem::Requirement
|
16
|
+
requirements:
|
17
|
+
- - ">="
|
18
|
+
- !ruby/object:Gem::Version
|
19
|
+
version: '0'
|
20
|
+
type: :runtime
|
21
|
+
prerelease: false
|
22
|
+
version_requirements: !ruby/object:Gem::Requirement
|
23
|
+
requirements:
|
24
|
+
- - ">="
|
25
|
+
- !ruby/object:Gem::Version
|
26
|
+
version: '0'
|
27
|
+
- !ruby/object:Gem::Dependency
|
28
|
+
name: tty-command
|
29
|
+
requirement: !ruby/object:Gem::Requirement
|
30
|
+
requirements:
|
31
|
+
- - ">="
|
32
|
+
- !ruby/object:Gem::Version
|
33
|
+
version: '0'
|
34
|
+
type: :runtime
|
35
|
+
prerelease: false
|
36
|
+
version_requirements: !ruby/object:Gem::Requirement
|
37
|
+
requirements:
|
38
|
+
- - ">="
|
39
|
+
- !ruby/object:Gem::Version
|
40
|
+
version: '0'
|
41
|
+
- !ruby/object:Gem::Dependency
|
42
|
+
name: tty-screen
|
43
|
+
requirement: !ruby/object:Gem::Requirement
|
44
|
+
requirements:
|
45
|
+
- - ">="
|
46
|
+
- !ruby/object:Gem::Version
|
47
|
+
version: '0'
|
48
|
+
type: :runtime
|
49
|
+
prerelease: false
|
50
|
+
version_requirements: !ruby/object:Gem::Requirement
|
51
|
+
requirements:
|
52
|
+
- - ">="
|
53
|
+
- !ruby/object:Gem::Version
|
54
|
+
version: '0'
|
55
|
+
- !ruby/object:Gem::Dependency
|
56
|
+
name: tty-tree
|
57
|
+
requirement: !ruby/object:Gem::Requirement
|
58
|
+
requirements:
|
59
|
+
- - ">="
|
60
|
+
- !ruby/object:Gem::Version
|
61
|
+
version: '0'
|
62
|
+
type: :runtime
|
63
|
+
prerelease: false
|
64
|
+
version_requirements: !ruby/object:Gem::Requirement
|
65
|
+
requirements:
|
66
|
+
- - ">="
|
67
|
+
- !ruby/object:Gem::Version
|
68
|
+
version: '0'
|
69
|
+
- !ruby/object:Gem::Dependency
|
70
|
+
name: bundler
|
71
|
+
requirement: !ruby/object:Gem::Requirement
|
72
|
+
requirements:
|
73
|
+
- - ">="
|
74
|
+
- !ruby/object:Gem::Version
|
75
|
+
version: '0'
|
76
|
+
type: :development
|
77
|
+
prerelease: false
|
78
|
+
version_requirements: !ruby/object:Gem::Requirement
|
79
|
+
requirements:
|
80
|
+
- - ">="
|
81
|
+
- !ruby/object:Gem::Version
|
82
|
+
version: '0'
|
83
|
+
- !ruby/object:Gem::Dependency
|
84
|
+
name: minitest
|
85
|
+
requirement: !ruby/object:Gem::Requirement
|
86
|
+
requirements:
|
87
|
+
- - ">="
|
88
|
+
- !ruby/object:Gem::Version
|
89
|
+
version: '0'
|
90
|
+
type: :development
|
91
|
+
prerelease: false
|
92
|
+
version_requirements: !ruby/object:Gem::Requirement
|
93
|
+
requirements:
|
94
|
+
- - ">="
|
95
|
+
- !ruby/object:Gem::Version
|
96
|
+
version: '0'
|
97
|
+
- !ruby/object:Gem::Dependency
|
98
|
+
name: rake
|
99
|
+
requirement: !ruby/object:Gem::Requirement
|
100
|
+
requirements:
|
101
|
+
- - ">="
|
102
|
+
- !ruby/object:Gem::Version
|
103
|
+
version: '0'
|
104
|
+
type: :development
|
105
|
+
prerelease: false
|
106
|
+
version_requirements: !ruby/object:Gem::Requirement
|
107
|
+
requirements:
|
108
|
+
- - ">="
|
109
|
+
- !ruby/object:Gem::Version
|
110
|
+
version: '0'
|
111
|
+
- !ruby/object:Gem::Dependency
|
112
|
+
name: rubocop
|
113
|
+
requirement: !ruby/object:Gem::Requirement
|
114
|
+
requirements:
|
115
|
+
- - ">="
|
116
|
+
- !ruby/object:Gem::Version
|
117
|
+
version: '0'
|
118
|
+
type: :development
|
119
|
+
prerelease: false
|
120
|
+
version_requirements: !ruby/object:Gem::Requirement
|
121
|
+
requirements:
|
122
|
+
- - ">="
|
123
|
+
- !ruby/object:Gem::Version
|
124
|
+
version: '0'
|
125
|
+
- !ruby/object:Gem::Dependency
|
126
|
+
name: simplecov
|
127
|
+
requirement: !ruby/object:Gem::Requirement
|
128
|
+
requirements:
|
129
|
+
- - ">="
|
130
|
+
- !ruby/object:Gem::Version
|
131
|
+
version: '0'
|
132
|
+
type: :development
|
133
|
+
prerelease: false
|
134
|
+
version_requirements: !ruby/object:Gem::Requirement
|
135
|
+
requirements:
|
136
|
+
- - ">="
|
137
|
+
- !ruby/object:Gem::Version
|
138
|
+
version: '0'
|
139
|
+
- !ruby/object:Gem::Dependency
|
140
|
+
name: yard
|
141
|
+
requirement: !ruby/object:Gem::Requirement
|
142
|
+
requirements:
|
143
|
+
- - ">="
|
144
|
+
- !ruby/object:Gem::Version
|
145
|
+
version: '0'
|
146
|
+
type: :development
|
147
|
+
prerelease: false
|
148
|
+
version_requirements: !ruby/object:Gem::Requirement
|
149
|
+
requirements:
|
150
|
+
- - ">="
|
151
|
+
- !ruby/object:Gem::Version
|
152
|
+
version: '0'
|
153
|
+
description: A very small tool to help you execute workflows
|
154
|
+
email:
|
155
|
+
- 2xijok@gmail.com
|
156
|
+
executables: []
|
157
|
+
extensions: []
|
158
|
+
extra_rdoc_files: []
|
159
|
+
files:
|
160
|
+
- LICENSE.txt
|
161
|
+
- README.md
|
162
|
+
- lib/miniflow.rb
|
163
|
+
- lib/miniflow/filecheck.rb
|
164
|
+
- lib/miniflow/flow.rb
|
165
|
+
- lib/miniflow/tool.rb
|
166
|
+
- lib/miniflow/tty_command.rb
|
167
|
+
- lib/miniflow/version.rb
|
168
|
+
homepage: https://github.com/kojix2/miniflow
|
169
|
+
licenses:
|
170
|
+
- MIT
|
171
|
+
metadata: {}
|
172
|
+
post_install_message:
|
173
|
+
rdoc_options: []
|
174
|
+
require_paths:
|
175
|
+
- lib
|
176
|
+
required_ruby_version: !ruby/object:Gem::Requirement
|
177
|
+
requirements:
|
178
|
+
- - ">="
|
179
|
+
- !ruby/object:Gem::Version
|
180
|
+
version: 2.4.0
|
181
|
+
required_rubygems_version: !ruby/object:Gem::Requirement
|
182
|
+
requirements:
|
183
|
+
- - ">="
|
184
|
+
- !ruby/object:Gem::Version
|
185
|
+
version: '0'
|
186
|
+
requirements: []
|
187
|
+
rubygems_version: 3.1.4
|
188
|
+
signing_key:
|
189
|
+
specification_version: 4
|
190
|
+
summary: A very small tool to help you execute workflows
|
191
|
+
test_files: []
|