fiveman 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 (136) hide show
  1. checksums.yaml +7 -0
  2. data/README.md +11 -0
  3. data/bin/fiveman +7 -0
  4. data/bin/fiveman-runner +41 -0
  5. data/data/example/Procfile +4 -0
  6. data/data/example/Procfile.without_colon +2 -0
  7. data/data/example/error +7 -0
  8. data/data/example/log/neverdie.log +4 -0
  9. data/data/example/spawnee +14 -0
  10. data/data/example/spawner +7 -0
  11. data/data/example/ticker +14 -0
  12. data/data/example/utf8 +11 -0
  13. data/data/export/bluepill/master.pill.erb +28 -0
  14. data/data/export/daemon/master.conf.erb +14 -0
  15. data/data/export/daemon/process.conf.erb +8 -0
  16. data/data/export/daemon/process_master.conf.erb +2 -0
  17. data/data/export/launchd/launchd.plist.erb +33 -0
  18. data/data/export/runit/log/run.erb +7 -0
  19. data/data/export/runit/run.erb +4 -0
  20. data/data/export/supervisord/app.conf.erb +31 -0
  21. data/data/export/systemd/master.target.erb +5 -0
  22. data/data/export/systemd/process.service.erb +21 -0
  23. data/data/export/upstart/master.conf.erb +2 -0
  24. data/data/export/upstart/process.conf.erb +15 -0
  25. data/data/export/upstart/process_master.conf.erb +2 -0
  26. data/lib/fiveman/cli.rb +162 -0
  27. data/lib/fiveman/distribution.rb +9 -0
  28. data/lib/fiveman/engine/cli.rb +101 -0
  29. data/lib/fiveman/engine.rb +494 -0
  30. data/lib/fiveman/env.rb +29 -0
  31. data/lib/fiveman/export/base.rb +171 -0
  32. data/lib/fiveman/export/bluepill.rb +12 -0
  33. data/lib/fiveman/export/daemon.rb +28 -0
  34. data/lib/fiveman/export/inittab.rb +42 -0
  35. data/lib/fiveman/export/launchd.rb +22 -0
  36. data/lib/fiveman/export/runit.rb +34 -0
  37. data/lib/fiveman/export/supervisord.rb +16 -0
  38. data/lib/fiveman/export/systemd.rb +34 -0
  39. data/lib/fiveman/export/upstart.rb +46 -0
  40. data/lib/fiveman/export.rb +36 -0
  41. data/lib/fiveman/helpers.rb +45 -0
  42. data/lib/fiveman/process.rb +80 -0
  43. data/lib/fiveman/procfile.rb +94 -0
  44. data/lib/fiveman/vendor/thor/lib/thor/actions/create_file.rb +103 -0
  45. data/lib/fiveman/vendor/thor/lib/thor/actions/create_link.rb +59 -0
  46. data/lib/fiveman/vendor/thor/lib/thor/actions/directory.rb +118 -0
  47. data/lib/fiveman/vendor/thor/lib/thor/actions/empty_directory.rb +135 -0
  48. data/lib/fiveman/vendor/thor/lib/thor/actions/file_manipulation.rb +327 -0
  49. data/lib/fiveman/vendor/thor/lib/thor/actions/inject_into_file.rb +103 -0
  50. data/lib/fiveman/vendor/thor/lib/thor/actions.rb +318 -0
  51. data/lib/fiveman/vendor/thor/lib/thor/base.rb +656 -0
  52. data/lib/fiveman/vendor/thor/lib/thor/command.rb +133 -0
  53. data/lib/fiveman/vendor/thor/lib/thor/core_ext/hash_with_indifferent_access.rb +85 -0
  54. data/lib/fiveman/vendor/thor/lib/thor/core_ext/io_binary_read.rb +12 -0
  55. data/lib/fiveman/vendor/thor/lib/thor/core_ext/ordered_hash.rb +129 -0
  56. data/lib/fiveman/vendor/thor/lib/thor/error.rb +32 -0
  57. data/lib/fiveman/vendor/thor/lib/thor/group.rb +281 -0
  58. data/lib/fiveman/vendor/thor/lib/thor/invocation.rb +177 -0
  59. data/lib/fiveman/vendor/thor/lib/thor/line_editor/basic.rb +35 -0
  60. data/lib/fiveman/vendor/thor/lib/thor/line_editor/readline.rb +88 -0
  61. data/lib/fiveman/vendor/thor/lib/thor/line_editor.rb +17 -0
  62. data/lib/fiveman/vendor/thor/lib/thor/parser/argument.rb +70 -0
  63. data/lib/fiveman/vendor/thor/lib/thor/parser/arguments.rb +175 -0
  64. data/lib/fiveman/vendor/thor/lib/thor/parser/option.rb +146 -0
  65. data/lib/fiveman/vendor/thor/lib/thor/parser/options.rb +220 -0
  66. data/lib/fiveman/vendor/thor/lib/thor/parser.rb +4 -0
  67. data/lib/fiveman/vendor/thor/lib/thor/rake_compat.rb +71 -0
  68. data/lib/fiveman/vendor/thor/lib/thor/runner.rb +322 -0
  69. data/lib/fiveman/vendor/thor/lib/thor/shell/basic.rb +436 -0
  70. data/lib/fiveman/vendor/thor/lib/thor/shell/color.rb +149 -0
  71. data/lib/fiveman/vendor/thor/lib/thor/shell/html.rb +126 -0
  72. data/lib/fiveman/vendor/thor/lib/thor/shell.rb +81 -0
  73. data/lib/fiveman/vendor/thor/lib/thor/util.rb +268 -0
  74. data/lib/fiveman/vendor/thor/lib/thor/version.rb +3 -0
  75. data/lib/fiveman/vendor/thor/lib/thor.rb +492 -0
  76. data/lib/fiveman/version.rb +5 -0
  77. data/lib/fiveman.rb +17 -0
  78. data/man/fiveman.1 +284 -0
  79. data/spec/fiveman/cli_spec.rb +111 -0
  80. data/spec/fiveman/engine_spec.rb +114 -0
  81. data/spec/fiveman/export/base_spec.rb +19 -0
  82. data/spec/fiveman/export/bluepill_spec.rb +37 -0
  83. data/spec/fiveman/export/daemon_spec.rb +97 -0
  84. data/spec/fiveman/export/inittab_spec.rb +40 -0
  85. data/spec/fiveman/export/launchd_spec.rb +31 -0
  86. data/spec/fiveman/export/runit_spec.rb +36 -0
  87. data/spec/fiveman/export/supervisord_spec.rb +38 -0
  88. data/spec/fiveman/export/systemd_spec.rb +155 -0
  89. data/spec/fiveman/export/upstart_spec.rb +118 -0
  90. data/spec/fiveman/export_spec.rb +24 -0
  91. data/spec/fiveman/helpers_spec.rb +26 -0
  92. data/spec/fiveman/process_spec.rb +71 -0
  93. data/spec/fiveman/procfile_spec.rb +57 -0
  94. data/spec/fiveman_spec.rb +16 -0
  95. data/spec/helper_spec.rb +19 -0
  96. data/spec/resources/Procfile +5 -0
  97. data/spec/resources/Procfile.bad +2 -0
  98. data/spec/resources/bin/echo +2 -0
  99. data/spec/resources/bin/env +2 -0
  100. data/spec/resources/bin/test +2 -0
  101. data/spec/resources/bin/utf8 +2 -0
  102. data/spec/resources/export/bluepill/app-concurrency.pill +49 -0
  103. data/spec/resources/export/bluepill/app.pill +81 -0
  104. data/spec/resources/export/daemon/app-alpha-1.conf +7 -0
  105. data/spec/resources/export/daemon/app-alpha-2.conf +7 -0
  106. data/spec/resources/export/daemon/app-alpha.conf +2 -0
  107. data/spec/resources/export/daemon/app-bravo-1.conf +7 -0
  108. data/spec/resources/export/daemon/app-bravo.conf +2 -0
  109. data/spec/resources/export/daemon/app.conf +14 -0
  110. data/spec/resources/export/inittab/inittab.concurrency +4 -0
  111. data/spec/resources/export/inittab/inittab.default +6 -0
  112. data/spec/resources/export/launchd/launchd-a.default +29 -0
  113. data/spec/resources/export/launchd/launchd-b.default +29 -0
  114. data/spec/resources/export/launchd/launchd-c.default +30 -0
  115. data/spec/resources/export/runit/app-alpha-1/log/run +7 -0
  116. data/spec/resources/export/runit/app-alpha-1/run +4 -0
  117. data/spec/resources/export/runit/app-alpha-2/log/run +7 -0
  118. data/spec/resources/export/runit/app-alpha-2/run +4 -0
  119. data/spec/resources/export/runit/app-bravo-1/log/run +7 -0
  120. data/spec/resources/export/runit/app-bravo-1/run +4 -0
  121. data/spec/resources/export/supervisord/app-alpha-1.conf +42 -0
  122. data/spec/resources/export/supervisord/app-alpha-2.conf +22 -0
  123. data/spec/resources/export/systemd/app-alpha.1.service +18 -0
  124. data/spec/resources/export/systemd/app-alpha.2.service +18 -0
  125. data/spec/resources/export/systemd/app-alpha.target +2 -0
  126. data/spec/resources/export/systemd/app-bravo.1.service +18 -0
  127. data/spec/resources/export/systemd/app-bravo.target +2 -0
  128. data/spec/resources/export/systemd/app.target +5 -0
  129. data/spec/resources/export/upstart/app-alpha-1.conf +11 -0
  130. data/spec/resources/export/upstart/app-alpha-2.conf +11 -0
  131. data/spec/resources/export/upstart/app-alpha.conf +2 -0
  132. data/spec/resources/export/upstart/app-bravo-1.conf +11 -0
  133. data/spec/resources/export/upstart/app-bravo.conf +2 -0
  134. data/spec/resources/export/upstart/app.conf +2 -0
  135. data/spec/spec_helper.rb +177 -0
  136. metadata +177 -0
@@ -0,0 +1,40 @@
1
+ require "spec_helper"
2
+ require "fiveman/engine"
3
+ require "fiveman/export/inittab"
4
+ require "tmpdir"
5
+
6
+ describe Fiveman::Export::Inittab, :fakefs do
7
+ let(:procfile) { FileUtils.mkdir_p("/tmp/app"); write_procfile("/tmp/app/Procfile") }
8
+ let(:location) { "/tmp/inittab" }
9
+ let(:formation) { nil }
10
+ let(:engine) { Fiveman::Engine.new(:formation => formation).load_procfile(procfile) }
11
+ let(:options) { Hash.new }
12
+ let(:inittab) { Fiveman::Export::Inittab.new(location, engine, options) }
13
+
14
+ before(:each) { load_export_templates_into_fakefs("inittab") }
15
+ before(:each) { allow(inittab).to receive(:say) }
16
+
17
+ it "exports to the filesystem" do
18
+ inittab.export
19
+ expect(File.read("/tmp/inittab")).to eq(example_export_file("inittab/inittab.default"))
20
+ end
21
+
22
+ context "to stdout" do
23
+ let(:location) { "-" }
24
+
25
+ it "exports to stdout" do
26
+ expect(inittab).to receive(:puts).with(example_export_file("inittab/inittab.default"))
27
+ inittab.export
28
+ end
29
+ end
30
+
31
+ context "with concurrency" do
32
+ let(:formation) { "alpha=2" }
33
+
34
+ it "exports to the filesystem with concurrency" do
35
+ inittab.export
36
+ expect(File.read("/tmp/inittab")).to eq(example_export_file("inittab/inittab.concurrency"))
37
+ end
38
+ end
39
+
40
+ end
@@ -0,0 +1,31 @@
1
+ require "spec_helper"
2
+ require "fiveman/engine"
3
+ require "fiveman/export/launchd"
4
+ require "tmpdir"
5
+
6
+ describe Fiveman::Export::Launchd, :fakefs do
7
+ let(:procfile) { FileUtils.mkdir_p("/tmp/app"); write_procfile("/tmp/app/Procfile") }
8
+ let(:options) { Hash.new }
9
+ let(:engine) { Fiveman::Engine.new().load_procfile(procfile) }
10
+ let(:launchd) { Fiveman::Export::Launchd.new("/tmp/init", engine, options) }
11
+
12
+ before(:each) { load_export_templates_into_fakefs("launchd") }
13
+ before(:each) { allow(launchd).to receive(:say) }
14
+
15
+ it "exports to the filesystem" do
16
+ launchd.export
17
+ expect(File.read("/tmp/init/app-alpha-1.plist")).to eq(example_export_file("launchd/launchd-a.default"))
18
+ expect(File.read("/tmp/init/app-bravo-1.plist")).to eq(example_export_file("launchd/launchd-b.default"))
19
+ end
20
+
21
+ context "with multiple command arguments" do
22
+ let(:procfile) { FileUtils.mkdir_p("/tmp/app"); write_procfile("/tmp/app/Procfile", "charlie") }
23
+
24
+ it "splits each command argument" do
25
+ launchd.export
26
+ expect(File.read("/tmp/init/app-alpha-1.plist")).to eq(example_export_file("launchd/launchd-c.default"))
27
+ end
28
+
29
+ end
30
+
31
+ end
@@ -0,0 +1,36 @@
1
+ require "spec_helper"
2
+ require "fiveman/engine"
3
+ require "fiveman/export/runit"
4
+ require "tmpdir"
5
+
6
+ describe Fiveman::Export::Runit, :fakefs do
7
+ let(:procfile) { FileUtils.mkdir_p("/tmp/app"); write_procfile("/tmp/app/Procfile", 'bar=baz') }
8
+ let(:engine) { Fiveman::Engine.new(:formation => "alpha=2,bravo=1").load_procfile(procfile) }
9
+ let(:options) { Hash.new }
10
+ let(:runit) { Fiveman::Export::Runit.new('/tmp/init', engine, options) }
11
+
12
+ before(:each) { load_export_templates_into_fakefs("runit") }
13
+ before(:each) { allow(runit).to receive(:say) }
14
+ before(:each) { allow(FakeFS::FileUtils).to receive(:chmod) }
15
+
16
+ it "exports to the filesystem" do
17
+ engine.env["BAR"] = "baz"
18
+ runit.export
19
+
20
+ expect(File.read("/tmp/init/app-alpha-1/run")).to eq(example_export_file('runit/app-alpha-1/run'))
21
+ expect(File.read("/tmp/init/app-alpha-1/log/run")).to eq(example_export_file('runit/app-alpha-1/log/run'))
22
+ expect(File.read("/tmp/init/app-alpha-1/env/PORT")).to eq("5000\n")
23
+ expect(File.read("/tmp/init/app-alpha-1/env/BAR")).to eq("baz\n")
24
+ expect(File.read("/tmp/init/app-alpha-2/run")).to eq(example_export_file('runit/app-alpha-2/run'))
25
+ expect(File.read("/tmp/init/app-alpha-2/log/run")).to eq(example_export_file('runit/app-alpha-2/log/run'))
26
+ expect(File.read("/tmp/init/app-alpha-2/env/PORT")).to eq("5001\n")
27
+ expect(File.read("/tmp/init/app-alpha-2/env/BAR")).to eq("baz\n")
28
+ expect(File.read("/tmp/init/app-bravo-1/run")).to eq(example_export_file('runit/app-bravo-1/run'))
29
+ expect(File.read("/tmp/init/app-bravo-1/log/run")).to eq(example_export_file('runit/app-bravo-1/log/run'))
30
+ expect(File.read("/tmp/init/app-bravo-1/env/PORT")).to eq("5100\n")
31
+ end
32
+
33
+ it "creates a full path to the export directory" do
34
+ expect { runit.export }.to_not raise_error
35
+ end
36
+ end
@@ -0,0 +1,38 @@
1
+ require "spec_helper"
2
+ require "fiveman/engine"
3
+ require "fiveman/export/supervisord"
4
+ require "tmpdir"
5
+
6
+ describe Fiveman::Export::Supervisord, :fakefs do
7
+ let(:procfile) { FileUtils.mkdir_p("/tmp/app"); write_procfile("/tmp/app/Procfile") }
8
+ let(:formation) { nil }
9
+ let(:engine) { Fiveman::Engine.new(:formation => formation).load_procfile(procfile) }
10
+ let(:options) { Hash.new }
11
+ let(:supervisord) { Fiveman::Export::Supervisord.new("/tmp/init", engine, options) }
12
+
13
+ before(:each) { load_export_templates_into_fakefs("supervisord") }
14
+ before(:each) { allow(supervisord).to receive(:say) }
15
+
16
+ it "exports to the filesystem" do
17
+ write_env(".env", "FOO"=>"bar", "URL"=>"http://example.com/api?foo=bar&baz=1")
18
+ supervisord.engine.load_env('.env')
19
+ supervisord.export
20
+ expect(File.read("/tmp/init/app.conf")).to eq(example_export_file("supervisord/app-alpha-1.conf"))
21
+ end
22
+
23
+ it "cleans up if exporting into an existing dir" do
24
+ expect(FileUtils).to receive(:rm).with("/tmp/init/app.conf")
25
+ supervisord.export
26
+ supervisord.export
27
+ end
28
+
29
+ context "with concurrency" do
30
+ let(:formation) { "alpha=2" }
31
+
32
+ it "exports to the filesystem with concurrency" do
33
+ supervisord.export
34
+ expect(File.read("/tmp/init/app.conf")).to eq(example_export_file("supervisord/app-alpha-2.conf"))
35
+ end
36
+ end
37
+
38
+ end
@@ -0,0 +1,155 @@
1
+ require "spec_helper"
2
+ require "fiveman/engine"
3
+ require "fiveman/export/systemd"
4
+ require "tmpdir"
5
+
6
+ describe Fiveman::Export::Systemd, :fakefs, :aggregate_failures do
7
+ let(:procfile) { write_procfile("/tmp/app/Procfile") }
8
+ let(:formation) { nil }
9
+ let(:engine) { Fiveman::Engine.new(:formation => formation).load_procfile(procfile) }
10
+ let(:options) { Hash.new }
11
+ let(:systemd) { Fiveman::Export::Systemd.new("/tmp/init", engine, options) }
12
+
13
+ before(:each) { load_export_templates_into_fakefs("systemd") }
14
+ before(:each) { allow(systemd).to receive(:say) }
15
+
16
+ it "exports to the filesystem" do
17
+ systemd.export
18
+
19
+ expect(File.read("/tmp/init/app.target")).to eq(example_export_file("systemd/app.target"))
20
+ expect(File.read("/tmp/init/app-alpha.1.service")).to eq(example_export_file("systemd/app-alpha.1.service"))
21
+ expect(File.read("/tmp/init/app-bravo.1.service")).to eq(example_export_file("systemd/app-bravo.1.service"))
22
+ end
23
+
24
+ context "when systemd export was run using the previous version of systemd export" do
25
+ before do
26
+ write_file("/tmp/init/app.target")
27
+
28
+ write_file("/tmp/init/app-alpha@.service")
29
+ write_file("/tmp/init/app-alpha.target")
30
+ write_file("/tmp/init/app-alpha.target.wants/app-alpha@5000.service")
31
+
32
+ write_file("/tmp/init/app-bravo.target")
33
+ write_file("/tmp/init/app-bravo@.service")
34
+ write_file("/tmp/init/app-bravo.target.wants/app-bravo@5100.service")
35
+
36
+ write_file("/tmp/init/app-foo_bar.target")
37
+ write_file("/tmp/init/app-foo_bar@.service")
38
+ write_file("/tmp/init/app-foo_bar.target.wants/app-foo_bar@5200.service")
39
+
40
+ write_file("/tmp/init/app-foo-bar.target")
41
+ write_file("/tmp/init/app-foo-bar@.service")
42
+ write_file("/tmp/init/app-foo-bar.target.wants/app-foo-bar@5300.service")
43
+ end
44
+
45
+ it "cleans up service files created by systemd export" do
46
+ expect(FileUtils).to receive(:rm).with("/tmp/init/app.target")
47
+
48
+ expect(FileUtils).to receive(:rm).with("/tmp/init/app-alpha@.service")
49
+ expect(FileUtils).to receive(:rm).with("/tmp/init/app-alpha.target")
50
+ expect(FileUtils).to receive(:rm).with("/tmp/init/app-alpha.target.wants/app-alpha@5000.service")
51
+ expect(FileUtils).to receive(:rm_r).with("/tmp/init/app-alpha.target.wants")
52
+
53
+ expect(FileUtils).to receive(:rm).with("/tmp/init/app-bravo.target")
54
+ expect(FileUtils).to receive(:rm).with("/tmp/init/app-bravo@.service")
55
+ expect(FileUtils).to receive(:rm).with("/tmp/init/app-bravo.target.wants/app-bravo@5100.service")
56
+ expect(FileUtils).to receive(:rm_r).with("/tmp/init/app-bravo.target.wants")
57
+
58
+ expect(FileUtils).to receive(:rm).with("/tmp/init/app-foo_bar.target")
59
+ expect(FileUtils).to receive(:rm).with("/tmp/init/app-foo_bar@.service")
60
+ expect(FileUtils).to receive(:rm).with("/tmp/init/app-foo_bar.target.wants/app-foo_bar@5200.service")
61
+ expect(FileUtils).to receive(:rm_r).with("/tmp/init/app-foo_bar.target.wants")
62
+
63
+ expect(FileUtils).to receive(:rm).with("/tmp/init/app-foo-bar.target")
64
+ expect(FileUtils).to receive(:rm).with("/tmp/init/app-foo-bar@.service")
65
+ expect(FileUtils).to receive(:rm).with("/tmp/init/app-foo-bar.target.wants/app-foo-bar@5300.service")
66
+ expect(FileUtils).to receive(:rm_r).with("/tmp/init/app-foo-bar.target.wants")
67
+
68
+ systemd.export
69
+ end
70
+ end
71
+
72
+ context "when systemd export was run using the current version of systemd export" do
73
+ before do
74
+ systemd.export
75
+ end
76
+
77
+ it "cleans up service files created by systemd export" do
78
+ expect(FileUtils).to receive(:rm).with("/tmp/init/app.target")
79
+ expect(FileUtils).to receive(:rm).with("/tmp/init/app-alpha.1.service")
80
+ expect(FileUtils).to receive(:rm).with("/tmp/init/app-bravo.1.service")
81
+ expect(FileUtils).to receive(:rm).with("/tmp/init/app-foo_bar.1.service")
82
+ expect(FileUtils).to receive(:rm).with("/tmp/init/app-foo-bar.1.service")
83
+
84
+ systemd.export
85
+ end
86
+ end
87
+
88
+ it "includes environment variables" do
89
+ engine.env['KEY'] = 'some "value"'
90
+ systemd.export
91
+ expect(File.read("/tmp/init/app-alpha.1.service")).to match(/KEY=some "value"/)
92
+ end
93
+
94
+ it "includes ExecStart line" do
95
+ engine.env['KEY'] = 'some "value"'
96
+ systemd.export
97
+ expect(File.read("/tmp/init/app-alpha.1.service")).to match(/^ExecStart=/)
98
+ end
99
+
100
+ context "with a custom formation specified" do
101
+ let(:formation) { "alpha=2" }
102
+
103
+ it "exports only those services that are specified in the formation" do
104
+ systemd.export
105
+
106
+ expect(File.read("/tmp/init/app.target")).to include("Wants=app-alpha.1.service app-alpha.2.service\n")
107
+ expect(File.read("/tmp/init/app-alpha.1.service")).to eq(example_export_file("systemd/app-alpha.1.service"))
108
+ expect(File.read("/tmp/init/app-alpha.2.service")).to eq(example_export_file("systemd/app-alpha.2.service"))
109
+ expect(File.exist?("/tmp/init/app-bravo.1.service")).to be_falsey
110
+ end
111
+ end
112
+
113
+ context "with alternate template directory specified" do
114
+ let(:template) { "/tmp/alternate" }
115
+ let(:options) { { :app => "app", :template => template } }
116
+
117
+ before do
118
+ FileUtils.mkdir_p template
119
+ File.open("#{template}/master.target.erb", "w") { |f| f.puts "alternate_template" }
120
+ end
121
+
122
+ it "uses template files found in the alternate directory" do
123
+ systemd.export
124
+ expect(File.read("/tmp/init/app.target")).to eq("alternate_template\n")
125
+ end
126
+
127
+ context "with alternate templates in the user home directory" do
128
+ before do
129
+ FileUtils.mkdir_p File.expand_path("~/.fiveman/templates/systemd")
130
+ File.open(File.expand_path("~/.fiveman/templates/systemd/master.target.erb"), "w") do |file|
131
+ file.puts "home_dir_template"
132
+ end
133
+ end
134
+
135
+ it "uses template files found in the alternate directory" do
136
+ systemd.export
137
+ expect(File.read("/tmp/init/app.target")).to eq("alternate_template\n")
138
+ end
139
+ end
140
+ end
141
+
142
+ context "with alternate templates in the user home directory" do
143
+ before do
144
+ FileUtils.mkdir_p File.expand_path("~/.fiveman/templates/systemd")
145
+ File.open(File.expand_path("~/.fiveman/templates/systemd/master.target.erb"), "w") do |file|
146
+ file.puts "home_dir_template"
147
+ end
148
+ end
149
+
150
+ it "uses template files found in the user home directory" do
151
+ systemd.export
152
+ expect(File.read("/tmp/init/app.target")).to eq("home_dir_template\n")
153
+ end
154
+ end
155
+ end
@@ -0,0 +1,118 @@
1
+ require "spec_helper"
2
+ require "fiveman/engine"
3
+ require "fiveman/export/upstart"
4
+ require "tmpdir"
5
+
6
+ describe Fiveman::Export::Upstart, :fakefs do
7
+ let(:procfile) { write_procfile("/tmp/app/Procfile") }
8
+ let(:formation) { nil }
9
+ let(:engine) { Fiveman::Engine.new(:formation => formation).load_procfile(procfile) }
10
+ let(:options) { Hash.new }
11
+ let(:upstart) { Fiveman::Export::Upstart.new("/tmp/init", engine, options) }
12
+
13
+ before(:each) { load_export_templates_into_fakefs("upstart") }
14
+ before(:each) { allow(upstart).to receive(:say) }
15
+
16
+ it "exports to the filesystem" do
17
+ upstart.export
18
+
19
+ expect(File.read("/tmp/init/app.conf")).to eq(example_export_file("upstart/app.conf"))
20
+ expect(File.read("/tmp/init/app-alpha.conf")).to eq(example_export_file("upstart/app-alpha.conf"))
21
+ expect(File.read("/tmp/init/app-alpha-1.conf")).to eq(example_export_file("upstart/app-alpha-1.conf"))
22
+ expect(File.read("/tmp/init/app-bravo.conf")).to eq(example_export_file("upstart/app-bravo.conf"))
23
+ expect(File.read("/tmp/init/app-bravo-1.conf")).to eq(example_export_file("upstart/app-bravo-1.conf"))
24
+ end
25
+
26
+ it "cleans up if exporting into an existing dir" do
27
+ expect(FileUtils).to receive(:rm).with("/tmp/init/app.conf")
28
+ expect(FileUtils).to receive(:rm).with("/tmp/init/app-alpha.conf")
29
+ expect(FileUtils).to receive(:rm).with("/tmp/init/app-alpha-1.conf")
30
+ expect(FileUtils).to receive(:rm).with("/tmp/init/app-bravo.conf")
31
+ expect(FileUtils).to receive(:rm).with("/tmp/init/app-bravo-1.conf")
32
+ expect(FileUtils).to receive(:rm).with("/tmp/init/app-foo-bar.conf")
33
+ expect(FileUtils).to receive(:rm).with("/tmp/init/app-foo-bar-1.conf")
34
+ expect(FileUtils).to receive(:rm).with("/tmp/init/app-foo_bar.conf")
35
+ expect(FileUtils).to receive(:rm).with("/tmp/init/app-foo_bar-1.conf")
36
+
37
+ upstart.export
38
+ upstart.export
39
+ end
40
+
41
+ it "does not delete exported files for similarly named applications" do
42
+ FileUtils.mkdir_p "/tmp/init"
43
+
44
+ ["app2", "app2-alpha", "app2-alpha-1"].each do |name|
45
+ path = "/tmp/init/#{name}.conf"
46
+ FileUtils.touch(path)
47
+ expect(FileUtils).to_not receive(:rm).with(path)
48
+ end
49
+
50
+ upstart.export
51
+ end
52
+
53
+ it 'does not delete exported files for app which share name prefix' do
54
+ FileUtils.mkdir_p "/tmp/init"
55
+
56
+ ["app-worker", "app-worker-worker", "app-worker-worker-1"].each do |name|
57
+ path = "/tmp/init/#{name}.conf"
58
+ FileUtils.touch(path)
59
+ expect(FileUtils).to_not receive(:rm).with(path)
60
+ end
61
+
62
+ upstart.export
63
+ expect(File.exist?('/tmp/init/app.conf')).to be true
64
+ expect(File.exist?('/tmp/init/app-worker.conf')).to be true
65
+ end
66
+
67
+ it "quotes and escapes environment variables" do
68
+ engine.env['KEY'] = 'd"\|d'
69
+ upstart.export
70
+ expect("foobarfoo").to include "bar"
71
+ expect(File.read("/tmp/init/app-alpha-1.conf")).to match(/KEY='d"\\\|d'/)
72
+ end
73
+
74
+ context "with a formation" do
75
+ let(:formation) { "alpha=2" }
76
+
77
+ it "exports to the filesystem with concurrency" do
78
+ upstart.export
79
+
80
+ expect(File.read("/tmp/init/app.conf")).to eq(example_export_file("upstart/app.conf"))
81
+ expect(File.read("/tmp/init/app-alpha.conf")).to eq(example_export_file("upstart/app-alpha.conf"))
82
+ expect(File.read("/tmp/init/app-alpha-1.conf")).to eq(example_export_file("upstart/app-alpha-1.conf"))
83
+ expect(File.read("/tmp/init/app-alpha-2.conf")).to eq(example_export_file("upstart/app-alpha-2.conf"))
84
+ expect(File.exists?("/tmp/init/app-bravo-1.conf")).to eq(false)
85
+ end
86
+ end
87
+
88
+ context "with alternate templates" do
89
+ let(:template) { "/tmp/alternate" }
90
+ let(:options) { { :app => "app", :template => template } }
91
+
92
+ before do
93
+ FileUtils.mkdir_p template
94
+ File.open("#{template}/master.conf.erb", "w") { |f| f.puts "alternate_template" }
95
+ end
96
+
97
+ it "can export with alternate template files" do
98
+ upstart.export
99
+ expect(File.read("/tmp/init/app.conf")).to eq("alternate_template\n")
100
+ end
101
+ end
102
+
103
+ context "with alternate templates from home dir" do
104
+
105
+ before do
106
+ FileUtils.mkdir_p File.expand_path("~/.fiveman/templates/upstart")
107
+ File.open(File.expand_path("~/.fiveman/templates/upstart/master.conf.erb"), "w") do |file|
108
+ file.puts "default_alternate_template"
109
+ end
110
+ end
111
+
112
+ it "can export with alternate template files" do
113
+ upstart.export
114
+ expect(File.read("/tmp/init/app.conf")).to eq("default_alternate_template\n")
115
+ end
116
+ end
117
+
118
+ end
@@ -0,0 +1,24 @@
1
+ require "spec_helper"
2
+ require "fiveman/export"
3
+
4
+ describe "Fiveman::Export" do
5
+ subject { Fiveman::Export }
6
+
7
+ describe "with a formatter that doesn't declare the appropriate class" do
8
+ it "prints an error" do
9
+ expect(subject).to receive(:require).with("fiveman/export/invalidformatter")
10
+ mock_export_error("Unknown export format: invalidformatter (no class Fiveman::Export::Invalidformatter).") do
11
+ subject.formatter("invalidformatter")
12
+ end
13
+ end
14
+ end
15
+
16
+ describe "with an invalid formatter" do
17
+
18
+ it "prints an error" do
19
+ mock_export_error("Unknown export format: invalidformatter (unable to load file 'fiveman/export/invalidformatter').") do
20
+ subject.formatter("invalidformatter")
21
+ end
22
+ end
23
+ end
24
+ end
@@ -0,0 +1,26 @@
1
+ require "spec_helper"
2
+ require "fiveman/helpers"
3
+
4
+ describe "Fiveman::Helpers" do
5
+ before do
6
+ module Foo
7
+ class Bar; end
8
+ end
9
+ end
10
+
11
+ after do
12
+ Object.send(:remove_const, :Foo)
13
+ end
14
+
15
+ subject { o = Object.new; o.extend(Fiveman::Helpers); o }
16
+
17
+ it "should classify words" do
18
+ expect(subject.classify("foo")).to eq("Foo")
19
+ expect(subject.classify("foo-bar")).to eq("FooBar")
20
+ end
21
+
22
+ it "should constantize words" do
23
+ expect(subject.constantize("Object")).to eq(Object)
24
+ expect(subject.constantize("Foo::Bar")).to eq(Foo::Bar)
25
+ end
26
+ end
@@ -0,0 +1,71 @@
1
+ require 'spec_helper'
2
+ require 'fiveman/process'
3
+ require 'ostruct'
4
+ require 'timeout'
5
+ require 'tmpdir'
6
+
7
+ describe Fiveman::Process do
8
+
9
+ def run(process, options={})
10
+ rd, wr = IO.method(:pipe).arity.zero? ? IO.pipe : IO.pipe("BINARY")
11
+ process.run(options.merge(:output => wr))
12
+ rd.gets
13
+ end
14
+
15
+ describe "#run" do
16
+
17
+ it "runs the process" do
18
+ process = Fiveman::Process.new(resource_path("bin/test"))
19
+ expect(run(process)).to eq("testing\n")
20
+ end
21
+
22
+ it "can set environment" do
23
+ process = Fiveman::Process.new(resource_path("bin/env FOO"), :env => { "FOO" => "bar" })
24
+ expect(run(process)).to eq("bar\n")
25
+ end
26
+
27
+ it "can set per-run environment" do
28
+ process = Fiveman::Process.new(resource_path("bin/env FOO"))
29
+ expect(run(process, :env => { "FOO" => "bar "})).to eq("bar\n")
30
+ end
31
+
32
+ it "can handle env vars in the command" do
33
+ process = Fiveman::Process.new(resource_path("bin/echo $FOO"), :env => { "FOO" => "bar" })
34
+ expect(run(process)).to eq("bar\n")
35
+ end
36
+
37
+ it "can handle per-run env vars in the command" do
38
+ process = Fiveman::Process.new(resource_path("bin/echo $FOO"))
39
+ expect(run(process, :env => { "FOO" => "bar" })).to eq("bar\n")
40
+ end
41
+
42
+ it "should output utf8 properly" do
43
+ process = Fiveman::Process.new(resource_path("bin/utf8"))
44
+ expect(run(process)).to eq(Fiveman.ruby_18? ? "\xFF\x03\n" : "\xFF\x03\n".force_encoding('binary'))
45
+ end
46
+
47
+ it "can expand env in the command" do
48
+ process = Fiveman::Process.new("command $FOO $BAR", :env => { "FOO" => "bar" })
49
+ expect(process.expanded_command).to eq("command bar $BAR")
50
+ end
51
+
52
+ it "can expand extra env in the command" do
53
+ process = Fiveman::Process.new("command $FOO $BAR", :env => { "FOO" => "bar" })
54
+ expect(process.expanded_command("BAR" => "qux")).to eq("command bar qux")
55
+ end
56
+
57
+ it "can execute" do
58
+ expect(Kernel).to receive(:exec).with("bin/command")
59
+ process = Fiveman::Process.new("bin/command")
60
+ process.exec
61
+ end
62
+
63
+ it "can execute with env" do
64
+ expect(Kernel).to receive(:exec).with("bin/command bar")
65
+ process = Fiveman::Process.new("bin/command $FOO")
66
+ process.exec(:env => { "FOO" => "bar" })
67
+ end
68
+
69
+ end
70
+
71
+ end
@@ -0,0 +1,57 @@
1
+ require 'spec_helper'
2
+ require 'fiveman/procfile'
3
+ require 'pathname'
4
+ require 'tmpdir'
5
+
6
+ describe Fiveman::Procfile, :fakefs do
7
+ subject { Fiveman::Procfile.new }
8
+
9
+ it "can load from a file" do
10
+ write_procfile
11
+ subject.load "Procfile"
12
+ expect(subject["alpha"]).to eq("./alpha")
13
+ expect(subject["bravo"]).to eq("./bravo")
14
+ end
15
+
16
+ it "loads a passed-in Procfile" do
17
+ write_procfile
18
+ procfile = Fiveman::Procfile.new("Procfile")
19
+ expect(procfile["alpha"]).to eq("./alpha")
20
+ expect(procfile["bravo"]).to eq("./bravo")
21
+ expect(procfile["foo-bar"]).to eq("./foo-bar")
22
+ expect(procfile["foo_bar"]).to eq("./foo_bar")
23
+ end
24
+
25
+ it 'only creates Procfile entries for lines matching regex' do
26
+ write_procfile
27
+ procfile = Fiveman::Procfile.new("Procfile")
28
+ keys = procfile.instance_variable_get(:@entries).map(&:first)
29
+ expect(keys).to match_array(%w[alpha bravo foo-bar foo_bar])
30
+ end
31
+
32
+ it "returns nil when attempting to retrieve an non-existing entry" do
33
+ write_procfile
34
+ procfile = Fiveman::Procfile.new("Procfile")
35
+ expect(procfile["unicorn"]).to eq(nil)
36
+ end
37
+
38
+ it "can have a process appended to it" do
39
+ subject["charlie"] = "./charlie"
40
+ expect(subject["charlie"]).to eq("./charlie")
41
+ end
42
+
43
+ it "can write to a string" do
44
+ subject["foo"] = "./foo"
45
+ subject["bar"] = "./bar"
46
+ expect(subject.to_s).to eq("foo: ./foo\nbar: ./bar")
47
+ end
48
+
49
+ it "can write to a file" do
50
+ subject["foo"] = "./foo"
51
+ subject["bar"] = "./bar"
52
+ Dir.mkdir('/tmp')
53
+ subject.save "/tmp/proc"
54
+ expect(File.read("/tmp/proc")).to eq("foo: ./foo\nbar: ./bar\n")
55
+ end
56
+
57
+ end
@@ -0,0 +1,16 @@
1
+ require "spec_helper"
2
+ require "fiveman"
3
+
4
+ describe Fiveman do
5
+
6
+ describe "VERSION" do
7
+ subject { Fiveman::VERSION }
8
+ it { is_expected.to be_a String }
9
+ end
10
+
11
+ describe "runner" do
12
+ it "should exist" do
13
+ expect(File.exist?(Fiveman.runner)).to eq(true)
14
+ end
15
+ end
16
+ end
@@ -0,0 +1,19 @@
1
+ require "spec_helper"
2
+
3
+ describe "spec helpers" do
4
+ describe "#preserving_env" do
5
+ after { ENV.delete "FOO" }
6
+
7
+ it "should remove added environment vars" do
8
+ old = ENV["FOO"]
9
+ preserving_env { ENV["FOO"] = "baz" }
10
+ expect(ENV["FOO"]).to eq(old)
11
+ end
12
+
13
+ it "should reset modified environment vars" do
14
+ ENV["FOO"] = "bar"
15
+ preserving_env { ENV["FOO"] = "baz"}
16
+ expect(ENV["FOO"]).to eq("bar")
17
+ end
18
+ end
19
+ end
@@ -0,0 +1,5 @@
1
+ echo: bin/echo echoing
2
+ env: bin/env FOO
3
+ test: bin/test
4
+ utf8: bin/utf8
5
+ ps: bin/echo PS env var is $PS
@@ -0,0 +1,2 @@
1
+ good: sleep 1
2
+ bad: false
@@ -0,0 +1,2 @@
1
+ #!/bin/sh
2
+ echo $*
@@ -0,0 +1,2 @@
1
+ #!/bin/bash
2
+ echo ${!1}
@@ -0,0 +1,2 @@
1
+ #!/bin/sh
2
+ echo "testing"
@@ -0,0 +1,2 @@
1
+ #!/usr/bin/env ruby
2
+ puts "\xff\x03"