haveapi-fs 0.1.0

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.
Files changed (89) hide show
  1. checksums.yaml +7 -0
  2. data/.yardopts +1 -0
  3. data/CHANGELOG +2 -0
  4. data/Gemfile +3 -0
  5. data/LICENSE.txt +21 -0
  6. data/README.md +338 -0
  7. data/Rakefile +1 -0
  8. data/assets/css/bootstrap.min.css +6 -0
  9. data/assets/css/local.css +11 -0
  10. data/bin/haveapi-fs +5 -0
  11. data/haveapi-fs.gemspec +30 -0
  12. data/lib/core_ext/string.rb +9 -0
  13. data/lib/haveapi/fs/auth/base.rb +56 -0
  14. data/lib/haveapi/fs/auth/basic.rb +29 -0
  15. data/lib/haveapi/fs/auth/noauth.rb +9 -0
  16. data/lib/haveapi/fs/auth/token.rb +39 -0
  17. data/lib/haveapi/fs/cache.rb +71 -0
  18. data/lib/haveapi/fs/cleaner.rb +56 -0
  19. data/lib/haveapi/fs/component.rb +237 -0
  20. data/lib/haveapi/fs/components/action_dir.rb +106 -0
  21. data/lib/haveapi/fs/components/action_errors.rb +49 -0
  22. data/lib/haveapi/fs/components/action_exec.rb +12 -0
  23. data/lib/haveapi/fs/components/action_exec_edit.rb +90 -0
  24. data/lib/haveapi/fs/components/action_input.rb +40 -0
  25. data/lib/haveapi/fs/components/action_message.rb +19 -0
  26. data/lib/haveapi/fs/components/action_output.rb +79 -0
  27. data/lib/haveapi/fs/components/action_status.rb +32 -0
  28. data/lib/haveapi/fs/components/cache_stats.rb +19 -0
  29. data/lib/haveapi/fs/components/component_list.rb +24 -0
  30. data/lib/haveapi/fs/components/create_action_dir.rb +15 -0
  31. data/lib/haveapi/fs/components/delete_action_dir.rb +22 -0
  32. data/lib/haveapi/fs/components/directory.rb +45 -0
  33. data/lib/haveapi/fs/components/directory_reset.rb +8 -0
  34. data/lib/haveapi/fs/components/executable.rb +75 -0
  35. data/lib/haveapi/fs/components/file.rb +43 -0
  36. data/lib/haveapi/fs/components/groff_help_file.rb +9 -0
  37. data/lib/haveapi/fs/components/help_file.rb +28 -0
  38. data/lib/haveapi/fs/components/html_help_file.rb +24 -0
  39. data/lib/haveapi/fs/components/index_filter.rb +63 -0
  40. data/lib/haveapi/fs/components/info_files.rb +19 -0
  41. data/lib/haveapi/fs/components/instance_create.rb +20 -0
  42. data/lib/haveapi/fs/components/instance_edit.rb +49 -0
  43. data/lib/haveapi/fs/components/list_item.rb +28 -0
  44. data/lib/haveapi/fs/components/md_help_file.rb +24 -0
  45. data/lib/haveapi/fs/components/meta_dir.rb +42 -0
  46. data/lib/haveapi/fs/components/meta_file.rb +21 -0
  47. data/lib/haveapi/fs/components/parameter.rb +132 -0
  48. data/lib/haveapi/fs/components/pry.rb +9 -0
  49. data/lib/haveapi/fs/components/remote_control_file.rb +92 -0
  50. data/lib/haveapi/fs/components/resource_action_dir.rb +72 -0
  51. data/lib/haveapi/fs/components/resource_dir.rb +161 -0
  52. data/lib/haveapi/fs/components/resource_id.rb +15 -0
  53. data/lib/haveapi/fs/components/resource_instance_dir.rb +146 -0
  54. data/lib/haveapi/fs/components/rfuse_check.rb +3 -0
  55. data/lib/haveapi/fs/components/root.rb +75 -0
  56. data/lib/haveapi/fs/components/save_instance.rb +11 -0
  57. data/lib/haveapi/fs/components/unsaved_list.rb +24 -0
  58. data/lib/haveapi/fs/components/update_action_dir.rb +31 -0
  59. data/lib/haveapi/fs/context.rb +43 -0
  60. data/lib/haveapi/fs/exceptions.rb +0 -0
  61. data/lib/haveapi/fs/factory.rb +59 -0
  62. data/lib/haveapi/fs/fs.rb +198 -0
  63. data/lib/haveapi/fs/help.rb +91 -0
  64. data/lib/haveapi/fs/main.rb +134 -0
  65. data/lib/haveapi/fs/remote_control.rb +29 -0
  66. data/lib/haveapi/fs/version.rb +5 -0
  67. data/lib/haveapi/fs/worker.rb +77 -0
  68. data/lib/haveapi/fs.rb +65 -0
  69. data/templates/help/html/action_dir.erb +33 -0
  70. data/templates/help/html/action_errors.erb +4 -0
  71. data/templates/help/html/action_input.erb +40 -0
  72. data/templates/help/html/action_output.erb +21 -0
  73. data/templates/help/html/index_filter.erb +16 -0
  74. data/templates/help/html/layout.erb +45 -0
  75. data/templates/help/html/resource_action_dir.erb +18 -0
  76. data/templates/help/html/resource_dir.erb +18 -0
  77. data/templates/help/html/resource_instance_dir.erb +64 -0
  78. data/templates/help/html/root.erb +42 -0
  79. data/templates/help/md/action_dir.erb +29 -0
  80. data/templates/help/md/action_errors.erb +2 -0
  81. data/templates/help/md/action_input.erb +23 -0
  82. data/templates/help/md/action_output.erb +11 -0
  83. data/templates/help/md/index_filter.erb +11 -0
  84. data/templates/help/md/layout.erb +14 -0
  85. data/templates/help/md/resource_action_dir.erb +10 -0
  86. data/templates/help/md/resource_dir.erb +15 -0
  87. data/templates/help/md/resource_instance_dir.erb +42 -0
  88. data/templates/help/md/root.erb +34 -0
  89. metadata +231 -0
@@ -0,0 +1,59 @@
1
+ module HaveAPI::Fs
2
+ # The Factory is used to create instances of new components and can be used
3
+ # to replace specific components by different ones, thus allowing to change
4
+ # their behaviour.
5
+ class Factory
6
+ class << self
7
+ # @!attribute replacements
8
+ # @return [Hash] collection of all replacements
9
+ attr_accessor :replacements
10
+
11
+ # Replace a component class by a different class. This method has two
12
+ # forms. Either call it with a hash of replacements or with two arguments,
13
+ # where the first is the class to be replaced and the second the class
14
+ # to replace it with.
15
+ def replace(*args)
16
+ @replacements ||= {}
17
+
18
+ if args.size == 2
19
+ @replacements[args[0]] = args[1]
20
+
21
+ else
22
+ @replacements.update(args.first)
23
+ end
24
+ end
25
+
26
+ # Resolves the class for component `klass`, i.e. it checks if there is a
27
+ # replacement for `klass` to return instead.
28
+ #
29
+ # @return [Class]
30
+ def component(klass)
31
+ if @replacements && @replacements.has_key?(klass)
32
+ @replacements[klass]
33
+
34
+ else
35
+ klass
36
+ end
37
+ end
38
+
39
+ # Create a new component with `klass` and its constructor's arguments
40
+ # in `args`.
41
+ #
42
+ # @param [HaveAPI::Fs::Context] context
43
+ # @param [Symbol] name
44
+ # @param [Class] klass
45
+ # @param [Array] args
46
+ # @return [Component]
47
+ def create(context, name, klass, *args)
48
+ child = component(klass).new(*args)
49
+ c_name = klass.component || klass.name.split('::').last.underscore.to_sym
50
+
51
+ child.context = context.clone
52
+ child.context[c_name] = child
53
+ child.context.file_path << name.to_s if name
54
+ child.setup
55
+ child
56
+ end
57
+ end
58
+ end
59
+ end
@@ -0,0 +1,198 @@
1
+ require 'thread'
2
+ require 'rfusefs'
3
+ require 'haveapi/client'
4
+
5
+ module HaveAPI::Fs
6
+ # Interface with RFuseFS API. Methods called by RFuseFS are redirected to
7
+ # appropriate components.
8
+ class Fs
9
+ CHECK_FILE = FuseFS::Fuse::Root::CHECK_FILE[1..-1].to_sym
10
+
11
+ attr_reader :api
12
+
13
+ def initialize(api, opts)
14
+ @api = api
15
+
16
+ @mutex = Mutex.new
17
+
18
+ @path_cache = Cache.new(self)
19
+ @context = Context.new
20
+ @context.opts = opts
21
+ @context.url = opts[:device]
22
+ @context.mountpoint = ::File.realpath(opts[:mountpoint])
23
+ @context.cache = @path_cache
24
+ @context[:fs] = self
25
+
26
+ @root = Factory.create(@context, nil, Components::Root)
27
+ # @root.context = @context.clone
28
+ # @root.context[:root] = @root
29
+ @root.setup
30
+
31
+ Thread.abort_on_exception = true
32
+ @cleaner = Cleaner.new(self, @root)
33
+ @cleaner.start
34
+ @path_cache.start
35
+ end
36
+
37
+ def contents(path)
38
+ puts "contents"
39
+ p path
40
+
41
+ guard { find_component(path).contents }
42
+ end
43
+
44
+ def directory?(path)
45
+ puts "directory?"
46
+ p path
47
+
48
+ guard { find_component(path).directory? }
49
+ end
50
+
51
+ def file?(path)
52
+ puts "file?"
53
+ p path
54
+
55
+ guard {find_component(path).file? }
56
+ end
57
+
58
+ def can_read?(path)
59
+ puts "can_read?"
60
+ p path
61
+
62
+ guard { find_component(path).readable? }
63
+ end
64
+
65
+ def can_write?(path)
66
+ puts "can_write?"
67
+ p path
68
+
69
+ guard { find_component(path).writable? }
70
+ end
71
+
72
+ def executable?(path)
73
+ puts "executable?"
74
+ p path
75
+
76
+ guard { find_component(path).executable? }
77
+ end
78
+
79
+ def times(path)
80
+ puts "times"
81
+ p path
82
+
83
+ guard { find_component(path).times }
84
+ end
85
+
86
+ def size(path)
87
+ puts "size"
88
+ p path
89
+
90
+ guard { find_component(path).size }
91
+ end
92
+
93
+ def read_file(path)
94
+ puts "read_file"
95
+ p path
96
+
97
+ guard { find_component(path).read }
98
+ end
99
+
100
+ def write_to(path, str)
101
+ puts "write_to"
102
+ p path
103
+
104
+ guard { find_component(path).write(str) }
105
+ end
106
+
107
+ def raw_open(path, *args)
108
+ puts "raw_open"
109
+ p path
110
+
111
+ guard { find_component(path).raw_open(path, *args) }
112
+ end
113
+
114
+ def raw_read(path, *args)
115
+ puts "raw_read"
116
+ p path
117
+
118
+ guard { find_component(path).raw_read(path, *args) }
119
+ end
120
+
121
+ def raw_write(path, *args)
122
+ puts "raw_write"
123
+ p path
124
+
125
+ guard { find_component(path).raw_write(path, *args) }
126
+ end
127
+
128
+ def raw_sync(path, *args)
129
+ puts "raw_sync"
130
+ p path
131
+
132
+ guard { find_component(path).raw_sync(path, *args) }
133
+ end
134
+
135
+ def raw_truncate(path, *args)
136
+ puts "raw_truncate"
137
+ p path
138
+
139
+ guard { find_component(path).raw_truncate(path, *args) }
140
+ end
141
+
142
+ def raw_close(path, *args)
143
+ puts "raw_close"
144
+ p path
145
+
146
+ guard { find_component(path).raw_close(path, *args) }
147
+ end
148
+
149
+ def unmounted
150
+ puts "unmounted"
151
+
152
+ @cleaner.stop
153
+ @path_cache.stop
154
+ end
155
+
156
+ def synchronize
157
+ @mutex.synchronize { yield }
158
+ end
159
+
160
+ protected
161
+ def find_component(path)
162
+ @path_cache.get(path) do
163
+ t = Time.now
164
+
165
+ names = path.split('/').map { |v| v.to_sym }[1..-1]
166
+ tmp = @root
167
+
168
+ next(tmp) unless names
169
+
170
+ names.each do |n|
171
+ tmp = tmp.find(n)
172
+
173
+ if tmp.nil?
174
+ raise Errno::ENOENT, "'#{path}' not found"
175
+
176
+ else
177
+ tmp.atime = t
178
+ end
179
+ end
180
+
181
+ next(tmp)
182
+ end
183
+ end
184
+
185
+ def guard
186
+ synchronize { yield }
187
+
188
+ rescue => e
189
+ raise e if e.is_a?(::SystemCallError)
190
+
191
+ warn "Exception #{e.class}"
192
+ warn e.backtrace.join("\n")
193
+ warn e.message
194
+
195
+ raise Errno::EIO, e.message
196
+ end
197
+ end
198
+ end
@@ -0,0 +1,91 @@
1
+ module HaveAPI::Fs
2
+ # Included this module to a {Component} to provide help files. All components
3
+ # based on {Components::Directory} already have this module included.
4
+ module Help
5
+ # When searching for a help file, all directories in this list are checked.
6
+ # Add paths to this list for help files of third-party components.
7
+ SEARCH_PATH = [
8
+ ::File.realpath(::File.join(
9
+ ::File.dirname(__FILE__),
10
+ '..', '..', '..',
11
+ 'templates',
12
+ 'help',
13
+ ))
14
+ ]
15
+
16
+ module ClassMethods
17
+ # Specify a name of a help file for this component. By default, the class
18
+ # name is used.
19
+ # @param [Symbol, nil] name
20
+ # @return [Symbol] if name is nil
21
+ def help_file(name = nil)
22
+ if name
23
+ @help_file = name
24
+
25
+ else
26
+ @help_file
27
+ end
28
+ end
29
+ end
30
+
31
+ module InstanceMethods
32
+ protected
33
+ # List of help files in all formats as symbols.
34
+ # @return [Array<Symbol>]
35
+ def help_files
36
+ %i(html txt md man).map { |v| :"help.#{v}" }
37
+ end
38
+
39
+ # List of help files in all formats as strings.
40
+ # @return [Array<String>]
41
+ def help_contents
42
+ help_files.map(&:to_s)
43
+ end
44
+
45
+ # Check if `name` is a help file.
46
+ # @param [Symbol] name
47
+ def help_file?(name)
48
+ help_files.include?(name)
49
+ end
50
+
51
+ # @return [Components::HelpFile] the recipe for a subclass, as
52
+ # {Component#new_child}
53
+ def help_file(name)
54
+ format = name.to_s.split('.').last.to_sym
55
+
56
+ case format
57
+ when :html
58
+ [Components::HtmlHelpFile, self, format]
59
+
60
+ when :txt, :md
61
+ [Components::MdHelpFile, self, :md]
62
+
63
+ when :man
64
+ [Components::GroffHelpFile, self, :md]
65
+
66
+ else
67
+ return nil
68
+ end
69
+ end
70
+ end
71
+
72
+ class << self
73
+ def included(klass)
74
+ klass.send(:extend, ClassMethods)
75
+ klass.send(:include, InstanceMethods)
76
+ end
77
+
78
+ # Search for `name` in paths defined in {SEARCH_PATH}.
79
+ # @return [String]
80
+ def find!(name)
81
+ SEARCH_PATH.each do |s|
82
+ path = ::File.join(s, name)
83
+
84
+ return path if ::File.exists?(path)
85
+ end
86
+
87
+ raise Errno::ENOENT, "help file '#{name}' not found"
88
+ end
89
+ end
90
+ end
91
+ end
@@ -0,0 +1,134 @@
1
+ require 'uri'
2
+ require 'yaml'
3
+
4
+ module HaveAPI::Fs
5
+ # A list of accepted mount options
6
+ OPTIONS = %i(api version auth_method user password token nodaemonize log
7
+ index_limit)
8
+ USAGE = <<END
9
+ version=VERSION API version to use
10
+ auth_method=METHOD Authentication method (basic, token, noauth)
11
+ user Username
12
+ password Password
13
+ token Authentication token
14
+ nodaemonize Stay in the foreground
15
+ log Enable logging while daemonized
16
+ index_limit=LIMIT Limit number of objects in resource directory
17
+ END
18
+
19
+
20
+ # Every authentication provider must register using this method.
21
+ # @param [Symbol] name
22
+ # @param [Class] klass
23
+ def self.register_auth(name, klass)
24
+ @auth_methods ||= {}
25
+ @auth_methods[name] = klass
26
+ end
27
+
28
+ # Return authentication method based on mount options or return the default
29
+ # one.
30
+ # @param [Hash] opts mount options
31
+ # @param [Symbol] default name of the default authentication method
32
+ def self.auth_method(opts, default)
33
+ return @auth_methods[opts[:auth_method].to_sym] if opts[:auth_method]
34
+
35
+ @auth_methods.each_value do |m|
36
+ return m if m.use?(opts)
37
+ end
38
+
39
+ default ? @auth_methods[default] : @auth_methods.values.first
40
+ end
41
+
42
+ # @return [Hash] if the config exists
43
+ # @return [nil] if the config does not exist
44
+ def self.read_config
45
+ config_path = "#{Dir.home}/.haveapi-client.yml"
46
+
47
+ if File.exists?(config_path)
48
+ YAML.load_file(config_path)
49
+
50
+ else
51
+ nil
52
+ end
53
+ end
54
+
55
+ # Return configuration of a particular server from the config hash.
56
+ # @param [String] url URL of the API server
57
+ def self.server_config(url)
58
+ cfg = read_config
59
+ return nil if cfg.nil? || cfg[:servers].nil?
60
+
61
+ cfg[:servers].detect { |s| s[:url] == url }
62
+ end
63
+
64
+ # Perform a double-fork to make the process independent. Stdout and stderr
65
+ # are redirected either to a log file or to /dev/null.
66
+ #
67
+ # @param [Hash] opts mount options
68
+ def self.daemonize(opts)
69
+ home = ::File.join(Dir.home, '.haveapi-fs', URI(opts[:device]).host)
70
+ FileUtils.mkpath(home)
71
+
72
+ pid = Process.fork
73
+
74
+ if pid
75
+ exit # Parent 1
76
+
77
+ else
78
+ pid = Process.fork
79
+ exit if pid # Parent 2
80
+ end
81
+
82
+ # Only the child gets here
83
+ STDIN.close
84
+
85
+ f = File.open(
86
+ opts[:log] ? File.join(home, 'haveapi-fs.log') : '/dev/null',
87
+ 'w'
88
+ )
89
+
90
+ STDOUT.reopen(f)
91
+ STDERR.reopen(f)
92
+ end
93
+
94
+ # Create and setup an instance of HaveAPI::Client::Client based on the mount
95
+ # options, calls self.daemonize if not configured otherwise.
96
+ #
97
+ # @param [Hash] opts mount options
98
+ # @return [HaveAPI::Client::Client]
99
+ def self.client(opts)
100
+ cfg = server_config(opts[:device])
101
+ client = HaveAPI::Client::Client.new(
102
+ opts[:device],
103
+ opts[:version],
104
+ identity: 'haveapi-fs',
105
+ )
106
+
107
+ auth_klass = auth_method(opts, cfg && cfg[:last_auth])
108
+
109
+ auth = auth_klass.new(
110
+ (cfg && cfg[:auth][auth_klass.method_name]) || {},
111
+ opts,
112
+ )
113
+ auth.validate
114
+ auth.authenticate(client)
115
+
116
+ # Fetch API description, must be done especially after authentication
117
+ client.setup
118
+
119
+ # Verify that authentication works
120
+ auth.check(client)
121
+
122
+ daemonize(opts) unless opts[:nodaemonize]
123
+ client
124
+ end
125
+
126
+ # Calls FuseFS.main with an instance of {HaveAPI::Fs::Fs}.
127
+ def self.main(options = OPTIONS, usage = USAGE)
128
+ FuseFS.main(ARGV, OPTIONS, USAGE, 'api_url') do |opts|
129
+ fail "provide argument 'api_url'" unless opts[:device]
130
+
131
+ HaveAPI::Fs.new(client(opts), opts)
132
+ end
133
+ end
134
+ end
@@ -0,0 +1,29 @@
1
+ module HaveAPI::Fs
2
+ # The purpose of this class is to handle commands received via the
3
+ # {Components::RemoteControlFile}.
4
+ class RemoteControl
5
+ # Call method #exec of a component at `path`.
6
+ #
7
+ # @param [Context] context
8
+ # @param [String] path
9
+ def self.execute(context, path)
10
+ c = context.fs.send(:find_component, path)
11
+
12
+ ret = c.exec
13
+
14
+ case ret
15
+ when true
16
+ {status: true}
17
+
18
+ when HaveAPI::Client::Response
19
+ {status: ret.ok?, message: ret.message, errors: ret.errors}
20
+
21
+ when HaveAPI::Client::ValidationError
22
+ {status: false, message: ret.message, errors: ret.errors}
23
+
24
+ else
25
+ {status: false, message: 'unknown response'}
26
+ end
27
+ end
28
+ end
29
+ end
@@ -0,0 +1,5 @@
1
+ module HaveAPI
2
+ module Fs
3
+ VERSION = '0.1.0'
4
+ end
5
+ end
@@ -0,0 +1,77 @@
1
+ require 'thread'
2
+
3
+ module HaveAPI::Fs
4
+ # Base class for classes that perform some regular work in a separate thread.
5
+ class Worker
6
+ attr_reader :runs
7
+
8
+ # @param [HaveAPI::Fs::Fs] fs
9
+ def initialize(fs)
10
+ @fs = fs
11
+ @run = true
12
+ @pipe_r, @pipe_w = IO.pipe
13
+ @runs = 0
14
+ @mutex = Mutex.new
15
+ end
16
+
17
+ # Start the work thread.
18
+ def start
19
+ @thread = Thread.new do
20
+ @mutex.synchronize { @next_time = Time.now + start_delay }
21
+ wait(start_delay)
22
+
23
+ while @run do
24
+ @fs.synchronize { work }
25
+
26
+ @runs += 1
27
+ @mutex.synchronize do
28
+ @last_time = Time.now
29
+ @next_time = @last_time + work_period
30
+ end
31
+
32
+ wait(work_period)
33
+ end
34
+ end
35
+ end
36
+
37
+ # Stop and join the work thread.
38
+ def stop
39
+ @run = false
40
+ @pipe_w.write('CLOSE')
41
+ @thread.join
42
+
43
+ @pipe_r.close
44
+ @pipe_w.close
45
+ end
46
+
47
+ # The time when the work method was last run.
48
+ def last_time
49
+ @mutex.synchronize { @last_time }
50
+ end
51
+
52
+ # The time when the work method will be run next.
53
+ def next_time
54
+ @mutex.synchronize { @next_time }
55
+ end
56
+
57
+ protected
58
+ def wait(n)
59
+ IO.select([@pipe_r], [], [], n)
60
+ end
61
+
62
+ # @return [Integer] number of seconds to wait before the first work
63
+ def start_delay
64
+ raise NotImplementedError
65
+ end
66
+
67
+ # @return [Integer] number of seconds to wait between working
68
+ def work_period
69
+ raise NotImplementedError
70
+ end
71
+
72
+ # This method is regularly called to perform the work.
73
+ def work
74
+ raise NotImplementedError
75
+ end
76
+ end
77
+ end
data/lib/haveapi/fs.rb ADDED
@@ -0,0 +1,65 @@
1
+ module HaveAPI
2
+ module Fs
3
+ module Auth ; end
4
+
5
+ def self.new(*args)
6
+ HaveAPI::Fs::Fs.new(*args)
7
+ end
8
+ end
9
+ end
10
+
11
+ require_relative '../core_ext/string'
12
+ require_relative 'fs/main'
13
+ require_relative 'fs/fs'
14
+ require_relative 'fs/context'
15
+ require_relative 'fs/worker'
16
+ require_relative 'fs/cleaner'
17
+ require_relative 'fs/cache'
18
+ require_relative 'fs/component'
19
+ require_relative 'fs/factory'
20
+ require_relative 'fs/help'
21
+ require_relative 'fs/remote_control'
22
+ require_relative 'fs/version'
23
+ require_relative 'fs/auth/base'
24
+ require_relative 'fs/auth/basic'
25
+ require_relative 'fs/auth/token'
26
+ require_relative 'fs/auth/noauth'
27
+ require_relative 'fs/components/directory'
28
+ require_relative 'fs/components/file'
29
+ require_relative 'fs/components/executable'
30
+ require_relative 'fs/components/remote_control_file'
31
+ require_relative 'fs/components/directory_reset'
32
+ require_relative 'fs/components/root'
33
+ require_relative 'fs/components/resource_dir'
34
+ require_relative 'fs/components/index_filter'
35
+ require_relative 'fs/components/resource_instance_dir'
36
+ require_relative 'fs/components/save_instance'
37
+ require_relative 'fs/components/resource_action_dir'
38
+ require_relative 'fs/components/action_dir'
39
+ require_relative 'fs/components/create_action_dir'
40
+ require_relative 'fs/components/delete_action_dir'
41
+ require_relative 'fs/components/update_action_dir'
42
+ require_relative 'fs/components/action_input'
43
+ require_relative 'fs/components/action_output'
44
+ require_relative 'fs/components/list_item'
45
+ require_relative 'fs/components/action_status'
46
+ require_relative 'fs/components/action_message'
47
+ require_relative 'fs/components/action_errors'
48
+ require_relative 'fs/components/action_exec'
49
+ require_relative 'fs/components/action_exec_edit'
50
+ require_relative 'fs/components/parameter'
51
+ require_relative 'fs/components/resource_id'
52
+ require_relative 'fs/components/help_file'
53
+ require_relative 'fs/components/html_help_file'
54
+ require_relative 'fs/components/md_help_file'
55
+ require_relative 'fs/components/groff_help_file'
56
+ require_relative 'fs/components/instance_create'
57
+ require_relative 'fs/components/instance_edit'
58
+ require_relative 'fs/components/unsaved_list'
59
+ require_relative 'fs/components/component_list'
60
+ require_relative 'fs/components/meta_dir'
61
+ require_relative 'fs/components/meta_file'
62
+ require_relative 'fs/components/info_files'
63
+ require_relative 'fs/components/cache_stats'
64
+ require_relative 'fs/components/pry'
65
+ require_relative 'fs/components/rfuse_check'
@@ -0,0 +1,33 @@
1
+ <p><%= @c.action.description %></p>
2
+ <h2>Contents</h2>
3
+ <p>
4
+ This directory is used to prepare input parameters, execute the action and retrieve
5
+ output parameters.
6
+ </p>
7
+ <dl>
8
+ <dt><a href="input/help.html">input/</a></dt>
9
+ <dd>Stage area for input parameters.</dd>
10
+
11
+ <dt><a href="output/help.html">output/</a></dt>
12
+ <dd>Contains output parameters after the action was executed.</dd>
13
+
14
+ <dt>exec</dt>
15
+ <dd>Write <code>1</code> to this file to execute the action.</dd>
16
+
17
+ <dt>exec.yml</dt>
18
+ <dd>Editable YAML file with input parameters. The action is executed when the file
19
+ is saved and closed.</dd>
20
+
21
+ <dt>status</dt>
22
+ <dd>Read action status. <code>1</code> if successful, <code>0</code> if not, empty
23
+ if not yet run.</dd>
24
+
25
+ <dt>message</dt>
26
+ <dd>Error message returned from the API.</dd>
27
+
28
+ <dt><a href="errors/help.html">errors/</a></dt>
29
+ <dd>List of parameter errors.</dd>
30
+
31
+ <dt>reset</dt>
32
+ <dd>Reset input parameters.</dd>
33
+ </dl>
@@ -0,0 +1,4 @@
1
+ <p>
2
+ This directory contains a list of errors for every parameter, where a parameter
3
+ is represented by a file, one error per line.
4
+ </p>