Compare commits

...

144 Commits

Author SHA1 Message Date
David Dollar
047f1ff5c4 0.45.0 2012-04-26 17:49:35 -04:00
David Dollar
26b54a62c5 Merge pull request #188 from technomancy/upstart-log-dir
Create and chown log dir in upstart export.
2012-04-24 17:50:42 -07:00
Phil Hagelberg
7b85ad7c1a Create and chown log dir in upstart export. 2012-04-24 17:24:53 -07:00
David Dollar
f46408e8be remove parka from dist files 2012-04-23 16:00:27 -04:00
David Dollar
93f04e42ac update docs 2012-04-23 15:57:06 -04:00
David Dollar
97c4582acc changelog 2012-04-23 15:57:00 -04:00
David Dollar
5689d75a87 0.44.0 2012-04-23 15:55:56 -04:00
David Dollar
1325b6750e make var output order repeatable 2012-04-23 15:53:59 -04:00
David Dollar
638005403f clean up file/directory interaction, add some tests 2012-04-23 15:50:23 -04:00
David Dollar
55f274532f Merge pull request #183 from technomancy/app_root
Look for .env and app_root in the same dir as the Procfile.
2012-04-23 12:20:10 -07:00
Phil Hagelberg
66f76c2036 Look for .env and app_root in the same dir as the Procfile. 2012-04-20 20:59:37 -07:00
David Dollar
865cabb525 update docs 2012-04-20 19:33:14 -04:00
David Dollar
7c3c4bc58f add more options to the start docs 2012-04-20 19:33:11 -04:00
David Dollar
2dbe8c733b update docs 2012-04-20 17:42:47 -04:00
David Dollar
84352b82cc changelog 2012-04-20 17:42:33 -04:00
David Dollar
383c1f87af 0.43.0 2012-04-20 17:41:08 -04:00
David Dollar
ce3003b026 factor out wrap_environment 2012-04-20 17:40:53 -04:00
David Dollar
e06f4b2f9e Merge pull request #182 from leahpar/master
Supervisord Export fix for environments containing commas
2012-04-20 14:36:26 -07:00
Raphael Randschau
b721fd894e per default wrap every environment value in quotes 2012-04-20 21:15:43 +02:00
Raphael Randschau
b8ea6fd4b3 fix typo in spec description 2012-04-20 09:14:12 +02:00
Raphael Randschau
dbda63263b fix supervisord export for environments containing commas 2012-04-20 09:11:25 +02:00
David Dollar
93cdc31be0 update docs 2012-04-18 13:04:45 -04:00
David Dollar
4dfbe46690 update changelog 2012-04-18 13:03:58 -04:00
David Dollar
0033f9caeb 0.42.0 2012-04-18 13:02:51 -04:00
David Dollar
74839800a9 Merge pull request #181 from technomancy/master
Public read_environment
2012-04-18 10:01:38 -07:00
Phil Hagelberg
b75337e21e Move read_environment to a public class method. 2012-04-18 09:56:17 -07:00
David Dollar
d94f941189 update gemfile.lock 2012-04-18 12:49:33 -04:00
David Dollar
0b34f067cb Revert "Merge pull request #176 from rtyler/feature/156-foreman-stop-command"
Rewriting using a better Process API

This reverts commit dbe51832b0, reversing
changes made to 69216b4c5e.
2012-04-18 12:48:51 -04:00
David Dollar
dbe51832b0 Merge pull request #176 from rtyler/feature/156-foreman-stop-command
Adding #stop method to Foreman::Engine
2012-04-11 10:29:54 -07:00
R. Tyler Croy
3a2a53be95 Remove ALL_PROCESSES and default the name arguments to #start/#stop to nil 2012-04-11 10:25:58 -07:00
R. Tyler Croy
b2bf95479e Refactor #stop to reference ALL_PROCESSES for a bit clearer readability 2012-04-10 20:35:59 -07:00
R. Tyler Croy
48f764e347 Refactor #spawn_processes into #start(name)
When passed nil (aka ALL_PROCESSES) #start will start all processes in the
Procfile as per existing behavior
2012-04-10 20:35:59 -07:00
R. Tyler Croy
de62d0655e Re-name the main Foreman::Engine method to #run to avoid a name collision with #start(name) 2012-04-10 20:35:59 -07:00
R. Tyler Croy
38aecff886 When executing #stop(nil), all processes should be sent the signal 2012-04-10 20:35:58 -07:00
R. Tyler Croy
e4a3215257 Re-implement #terminate_gracefully with #stop(name) 2012-04-10 20:19:23 -07:00
R. Tyler Croy
c705b5fbef Add #stop method on Foreman::Engine for stopping certain named processes
This will make embedding foreman "nicer" since the embedder can then stop
a specific process (e.g. turning off a service for an integration fail-over test)
2012-04-10 20:10:51 -07:00
David Dollar
69216b4c5e Merge pull request #171 from technomancy/0.41.0-deparkaed
Drop parka dependency to make things easier on the build slaves.
2012-03-26 15:05:35 -07:00
Phil Hagelberg
5d2930745a Drop parka dependency to make things easier on the build slaves. 2012-03-26 15:01:04 -07:00
David Dollar
8fc3d1ef24 Merge pull request #161 from leahpar/master
Supervisord Support (Update & Bugfix)
2012-03-16 18:47:15 -07:00
David Dollar
d33e4fb0ed update changelog 2012-03-16 16:36:16 -04:00
David Dollar
39b48b566f 0.41.0 2012-03-16 16:34:32 -04:00
David Dollar
2f982ff9c7 replace term-ansicolor with built-in colorization 2012-03-16 16:34:14 -04:00
Raphael Randschau
1217ef1b56 fix typo 2012-03-05 15:51:10 +01:00
Raphael Randschau
c9943d70ec add group support for supervisord 2012-03-05 15:48:40 +01:00
Raphael Randschau
08dca57eb4 fix enviroment export 2012-02-25 17:24:27 +01:00
David Dollar
bb3377407a Merge pull request #160 from leahpar/master
supervisord support
2012-02-24 11:49:55 -08:00
Raphael Randschau
084b9493d1 revert bundle update 2012-02-24 20:31:07 +01:00
Raphael Randschau
279a251c78 fix whitespaces 2012-02-24 20:29:16 +01:00
Raphael Randschau
a49ef286e8 all specs are passing 2012-02-24 20:18:38 +01:00
Raphael Randschau
0b3da59947 passing first export 2012-02-24 19:52:18 +01:00
David Dollar
1f725dd68a let github show authors 2012-02-24 11:34:34 -05:00
David Dollar
2272f76479 authors 2012-02-24 11:33:33 -05:00
David Dollar
cf4762071c changelog 2012-02-24 11:33:18 -05:00
David Dollar
d86b0bed1f 0.40.0 2012-02-24 11:32:00 -05:00
David Dollar
12f825204b support various quoting styles in .env 2012-02-24 11:31:21 -05:00
David Dollar
62c9d1db45 remove load_env! as it's made unnecessary by foreman run 2012-02-24 11:31:21 -05:00
Raphael Randschau
1127551369 rename supervisord base template to app
add supervisord stub
2012-02-23 17:24:08 +01:00
Raphael Randschau
8cb58b8517 require supervisord export 2012-02-23 17:11:19 +01:00
Raphael Randschau
d03e931b67 add supervisord export engine 2012-02-23 17:10:57 +01:00
Raphael Randschau
9ba2b32b36 add supervisord base template 2012-02-23 17:02:59 +01:00
David Dollar
cf5689a77a Merge pull request #155 from rtyler/bug/152-check-exception-no-procfile
Provide a useful error if `foreman check` fails to find a Procfile
2012-02-21 17:40:20 -08:00
R. Tyler Croy
c23dbb79af Provide a useful error if foreman check fails to find a Procfile
Fixes #152
2012-02-21 17:27:15 -08:00
David Dollar
7e55d8d3e2 update docs 2012-02-21 11:58:57 -05:00
David Dollar
d4f23d45a4 add run to docs 2012-02-21 11:58:52 -05:00
David Dollar
93fa1645e7 update docs 2012-02-21 11:50:11 -05:00
David Dollar
7bdada4a10 update docs 2012-02-21 11:49:57 -05:00
David Dollar
2b47d24ab7 Travis doesn't support cext. Revert "try java again"
This reverts commit 24695348fb.
2012-02-09 19:16:14 -05:00
David Dollar
24695348fb try java again 2012-02-09 19:12:11 -05:00
David Dollar
38b6482af5 changelog 2012-02-07 11:19:12 -05:00
David Dollar
501bc138c5 authors 2012-02-07 11:18:06 -05:00
David Dollar
df8c05cd6c 0.39.0 2012-02-07 11:17:59 -05:00
David Dollar
edcc4f3567 move to foreman-runner 2012-02-07 11:17:44 -05:00
David Dollar
3759dbb463 fix tgz release 2012-02-07 11:16:07 -05:00
David Dollar
b673931c05 Double Revert "Revert "bundle update hpricot""
This reverts commit 137e43b040.
2012-02-04 19:47:48 -05:00
David Dollar
137e43b040 Revert "bundle update hpricot"
This reverts commit 16d4b84a5d.
2012-02-04 19:25:01 -05:00
David Dollar
79211d9bbf Merge pull request #147 from jfirebaugh/rubinius
bundle update hpricot
2012-02-04 14:05:06 -08:00
John Firebaugh
16d4b84a5d bundle update hpricot
0.8.2 doesn't compile on Rubinius; 0.8.6 does.
2012-02-04 13:46:48 -08:00
David Dollar
5ea4537046 remove version from inner pkg 2012-02-02 21:31:58 -05:00
David Dollar
d51433ff82 fix foreman pkg builder 2012-02-02 21:08:01 -05:00
David Dollar
54ab74d305 fix release tasks 2012-02-02 17:32:52 -05:00
David Dollar
e8b8f34f41 changelog 2012-02-02 17:27:56 -05:00
David Dollar
7535f1d3d8 0.38.0 2012-02-02 17:26:42 -05:00
David Dollar
3af0dfb4ae bring back single process starting 2012-02-02 17:26:25 -05:00
David Dollar
78547b8175 foreman + jruby + travis = nope 2012-02-01 13:24:43 -05:00
David Dollar
976fbc0bb0 stub out proctitle/termtitle 2012-02-01 10:19:33 -05:00
David Dollar
28a9aa774f try ci on jruby 2012-02-01 10:06:25 -05:00
David Dollar
51f5ff3842 latest jruby fixed non-excutable to raise EACCESS 2012-01-31 18:01:53 -05:00
David Dollar
e1e18f62bb remove jruby until we figure out what's going on with travis 2012-01-30 11:42:41 -05:00
David Dollar
0a09117328 set JRUBY_OPTS for travis 2012-01-29 23:02:48 -05:00
David Dollar
c3df12746f ignore .rbenv-version 2012-01-29 23:02:40 -05:00
David Dollar
2ec6a23fb3 force to binary encoding if supported 2012-01-29 23:02:20 -05:00
David Dollar
0d6b784de1 disable test in jruby 2012-01-29 23:02:10 -05:00
David Dollar
2dcd2c03db wait for process termination instead of sleeping 2012-01-29 23:02:03 -05:00
David Dollar
9d6d0bbb7d add bundler setup to rakefile 2012-01-29 22:45:50 -05:00
David Dollar
89c1314abe try jruby with travis 2012-01-29 22:37:07 -05:00
David Dollar
f33211d100 clean up gems 2012-01-29 21:35:51 -05:00
David Dollar
4317079bf3 tweak changelog 2012-01-29 21:29:11 -05:00
David Dollar
c745c282c9 update docs 2012-01-29 21:28:49 -05:00
David Dollar
7dca45db57 0.37.2 2012-01-29 21:28:30 -05:00
David Dollar
de3c47fe21 handle directories with spaces in runner 2012-01-29 21:28:11 -05:00
David Dollar
a8a255db4a update docs 2012-01-29 14:06:09 -05:00
David Dollar
307d63b631 changelog 2012-01-29 14:05:59 -05:00
David Dollar
de54f6a5a5 0.37.1 2012-01-29 14:03:45 -05:00
David Dollar
0dff116340 use a 1.8-compatbiel method for IO.pipe 2012-01-29 14:01:13 -05:00
David Dollar
e053dc8434 cleanup 2012-01-29 13:58:16 -05:00
David Dollar
20f6ba1563 use binary pipes 2012-01-29 13:56:57 -05:00
David Dollar
557a08ea77 add utf8 test to engine 2012-01-29 13:56:51 -05:00
David Dollar
8eccc819d6 remove nonfunctional utf8 test 2012-01-29 13:56:42 -05:00
David Dollar
347d4a0184 factor out poll_readers 2012-01-29 13:56:35 -05:00
David Dollar
0147f5d284 set up example procfile with utf8 item 2012-01-29 13:56:22 -05:00
David Dollar
1da034ce66 try to add failing test for utf8 2012-01-29 10:03:31 -05:00
David Dollar
5fc7552572 refactor resource_file 2012-01-29 10:03:14 -05:00
David Dollar
083efe3ae9 sleep longer after loading scripts 2012-01-29 10:03:03 -05:00
David Dollar
9d2382a2d2 remove autotest 2012-01-29 02:06:01 -05:00
David Dollar
f731daae1a update docs 2012-01-29 01:55:44 -05:00
David Dollar
b7f0e3f573 typo 2012-01-29 01:55:14 -05:00
David Dollar
e7c523dab7 cleanup 2012-01-29 01:52:30 -05:00
David Dollar
9f4f15a29c update docs 2012-01-29 01:51:52 -05:00
David Dollar
b2dc89c50e fix up authors 2012-01-29 01:51:00 -05:00
David Dollar
389bf05800 cleanup 2012-01-29 01:47:05 -05:00
David Dollar
a632a62efd update docs 2012-01-29 01:45:57 -05:00
David Dollar
2edf6e1c68 pedantry 2012-01-29 01:41:21 -05:00
David Dollar
56158e881b add changelog 2012-01-29 01:40:36 -05:00
David Dollar
6b5ed495d5 fix up packaging after moving tasks 2012-01-29 01:38:21 -05:00
David Dollar
9652c285f1 fix up changelog task 2012-01-29 01:32:20 -05:00
David Dollar
ba171cc10d curate changelog 2012-01-29 01:26:21 -05:00
David Dollar
ebb191adba better changelog task 2012-01-29 01:26:14 -05:00
David Dollar
8c3ef1a7af 0.37.0 2012-01-29 01:13:27 -05:00
David Dollar
cf69c31ae3 raw changelog 2012-01-29 01:13:02 -05:00
David Dollar
e16a35da4b fix changelog script 2012-01-29 01:12:56 -05:00
David Dollar
2490dd2a5b put an entire line of output inside a single mutex so we don't cross the streams 2012-01-29 00:09:44 -05:00
David Dollar
2705520496 fix race condition with process termination 2012-01-29 00:09:28 -05:00
David Dollar
522fee5e9e pedantry 2012-01-29 00:08:58 -05:00
David Dollar
c462473a25 fix simplecov 2012-01-28 18:53:43 -05:00
David Dollar
224fe94dc2 add more tests 2012-01-28 18:48:26 -05:00
David Dollar
7cb73f5c36 rearrange tasks, add coverage 2012-01-28 18:48:13 -05:00
David Dollar
1537ddbcc9 tweak simplecov entry 2012-01-28 16:27:02 -05:00
David Dollar
b04c81dd06 add simplecov 2012-01-28 16:26:12 -05:00
David Dollar
ae22d34967 Merge pull request #144 from technomancy/debian
Drop the S3 publishing rake tasks.
2012-01-26 17:02:42 -08:00
Phil Hagelberg
9a359efbf7 Drop the S3 publishing rake tasks. 2012-01-26 17:00:07 -08:00
David Dollar
9632227d29 0.37.0.pre5 2012-01-24 08:34:48 -08:00
David Dollar
288d118ca4 Merge pull request #142 from apollo13/master
Fix bash string comparision
2012-01-24 08:29:38 -08:00
David Dollar
576455b8d7 rename readme 2012-01-24 08:14:50 -08:00
Florian Apolloner
e1d3955d3c Fix the test for an empty string in bin/runner 2012-01-24 09:51:16 +01:00
57 changed files with 1166 additions and 418 deletions

3
.gitignore vendored
View File

@@ -1,8 +1,9 @@
/.bundle
/.rbenv-version
/coverage
/example/log/*
/man/*.html
/man/*.markdown
/pkg
/tags
/vendor
/vendor

View File

@@ -1,11 +0,0 @@
0.26.1 12/05/2011 6160246da0fafe9cf8fde188d94bbc6babc667dc
==========================================================
Merge pull request #103 from csquared/load_env_from_irb [David Dollar]
refactor load_env to apply_environment [Chris Continanza]
rename load! to load_env! [Chris Continanza]
use ./.env as default [Chris Continanza]
load contents from env file [Chris Continanza]
refactor engine to expose env methods [Chris Continanza]
disable email notifications [David Dollar]
add travis config [David Dollar]

196
Changelog.md Normal file
View File

@@ -0,0 +1,196 @@
## 0.44.0 (2012-04-23)
* make var output order repeatable in supervisord export [David Dollar]
* make --procfile and --app-root influence each other in a more intuitive way [David Dollar]
* Look for .env and app_root in the same dir as the Procfile. [Phil Hagelberg]
## 0.43.0 (2012-04-20)
* wrap supervisord env vars in quotes [Raphael Randschau]
## 0.42.0 (2012-04-18)
* Move read_environment to a public class method. [Phil Hagelberg]
* Drop parka dependency [Phil Hagelberg]
* add group support for supervisord [Raphael Randschau]
* fix enviroment export [Raphael Randschau]
## 0.41.0 (2012-03-16)
* replace term-ansicolor with built-in colorization [David Dollar]
* supervisord export template [Raphael Randschau]
## 0.40.0 (2012-02-24)
* support various quoting styles in .env [David Dollar]
* remove load_env! as it's made unnecessary by foreman run [David Dollar]
* Provide a useful error if `foreman check` fails to find a Procfile [R. Tyler Croy]
* update docs [David Dollar]
## 0.39.0 (2012-02-07)
* rename bin/runner to bin/foreman-runner [David Dollar]
* fix tgz release [David Dollar]
* bundle update hpricot [John Firebaugh]
* touch up .pkg release tasks [David Dollar]
## 0.38.0 (2012-02-02)
* bring back single process starting [David Dollar]
* more attempts at getting ci working with jruby [David Dollar]
* ignore .rbenv-version [David Dollar]
* force to binary encoding if supported [David Dollar]
## 0.37.2 (2012-01-29)
* handle directories with spaces in runner [David Dollar]
* update docs [David Dollar]
## 0.37.1 (2012-01-29)
* use binary pipes to better handle UTF-8 data [David Dollar]
* set up example procfile with UTF-8 item [David Dollar]
* remove autotest [David Dollar]
* fix up authors generation [David Dollar]
* fix up packaging after moving tasks [David Dollar]
* fix up changelog tasks [David Dollar]
## 0.37.0 (2012-01-29)
* put an entire line of output inside a single mutex so we don't cross the streams [David Dollar]
* fix race condition with process termination [David Dollar]
* allow external custom exporters [Chris Lowder]
* fix the test for an empty string in bin/runner [Florian Apolloner]
* ensure we have non-nil data, fixes #111 [David Dollar]
* make sure error method exists, fixes #104 [David Dollar]
* clean up chdir usage [David Dollar]
* normalize platform names [David Dollar]
* add windows support [David Dollar]
* add jruby support [David Dollar]
* pass basedir along to the runner script [David Dollar]
* harden runner script [David Dollar]
* add many missing specs [brainopia]
* clean up fakefs usage in specs [brainopia]
* runit creates a full path to export directory. [Fletcher Nichol]
## 0.36.1 (2012-01-18)
* 0.36.1 [David Dollar]
* bump term-ansicolor in gemspec [David Dollar]
## 0.36.0 (2012-01-17)
* 0.36.0 [David Dollar]
* sync the writer stream [David Dollar]
* capture stderr as well [David Dollar]
## 0.35.0 (2012-01-16)
* update rake [David Dollar]
* 0.35.0 [David Dollar]
* Merge pull request #132 from Viximo/feature/concurrency [David Dollar]
* Fix export specs [Matt Griffin]
* Merge branch 'master' of https://github.com/michaeldwan/foreman into feature/concurrency [Matt Griffin]
* default process concurrency is 0 when concurrency options specified, otherwise default concurrency is 1 [Michael Dwan]
## 0.34.1 (2012-01-16)
* 0.34.1 [David Dollar]
* fix missing start desc [David Dollar]
## 0.34.0 (2012-01-16)
* 0.34.0 [David Dollar]
* update man page [David Dollar]
* update docs for -d [David Dollar]
* Merge pull request #101 from ndbroadbent/foreman [David Dollar]
* Wrap around to the first colour when all the colours are used [Craig R Webster]
* run specs in random order [David Dollar]
* update rspec [David Dollar]
* pedantry [David Dollar]
* Set executable bit on runit run scripts. [Matthijs Langenberg]
* Merge pull request #114 from gburt/master [David Dollar]
* add more colors [Gabriel Burt]
* Added option to specify app_root, if executing a Procfile from a shared location [Nathan Broadbent]
## 0.33.1 (2012-01-16)
* 0.33.1 [David Dollar]
* Merge pull request #129 from fnichol/resolve-home-template [David Dollar]
* Expand template path under user's home directory. [Fletcher Nichol]
## 0.33.0 (2012-01-15)
* 0.33.0 [David Dollar]
* Revert "Merge pull request #125 from brainopia/master" [David Dollar]
## 0.32.0 (2012-01-12)
* 0.32.0 [David Dollar]
* Merge pull request #125 from brainopia/master [David Dollar]
* Merge pull request #121 from Viximo/feature/run [David Dollar]
* Return some whitespace that was accidentally removed [Matt Griffin]
* Steal the run method back from Thor so that it can be used in place for exec for running commands in the foreman environment. [Matt Griffin]
* Remove old cruft [brainopia]
* In case someone wants to use bin/runner directly [brainopia]
* Fix for double fork [brainopia]
* Use ruby exec which works with escaped cmd and replaces shell [brainopia]
* Fix foreman to work with cmds containing pipes and redirects [brainopia]
* Add "exec" action to allow execution of arbitrary commands with the app's environment. [Matt Griffin]
* tweak readme [David Dollar]
## 0.31.0 (2012-01-04)
* 0.31.0 [David Dollar]
* make fork more robust [David Dollar]
* remove unnecessary debug [David Dollar]
* add more information when shutting down [David Dollar]
* Merge pull request #110 from lstoll/master [David Dollar]
* Use different port ranges for each process type [Lincoln Stoll]
## 0.30.1 (2011-12-23)
* 0.30.1 [David Dollar]
* require thread for mutex [David Dollar]
## 0.30.0 (2011-12-22)
* 0.30.0 [David Dollar]
* compatibility with ruby 1.8 [David Dollar]
## 0.29.0 (2011-12-22)
* 0.29.0 [David Dollar]
* 0.28.0.pre2 [David Dollar]
* fix pipe error [David Dollar]
* 0.28.0.pre1 [David Dollar]
* Merge branch 'fork' [David Dollar]
* wip [David Dollar]
* wip [David Dollar]
* wip [David Dollar]
* wip [David Dollar]
* wip [David Dollar]
## 0.27.0 (2011-12-05)
* 0.27.0 [David Dollar]
* add changelog [David Dollar]
* Merge pull request #103 from csquared/load_env_from_irb [David Dollar]
* refactor load_env to apply_environment [Chris Continanza]
* rename load! to load_env! [Chris Continanza]
* use ./.env as default [Chris Continanza]
* load contents from env file [Chris Continanza]
* refactor engine to expose env methods [Chris Continanza]
* disable email notifications [David Dollar]
* add travis config [David Dollar]
## 0.26.1 2011-12-05
* Merge pull request #103 from csquared/load_env_from_irb [David Dollar]
* refactor load_env to apply_environment [Chris Continanza]
* rename load! to load_env! [Chris Continanza]
* use ./.env as default [Chris Continanza]
* load contents from env file [Chris Continanza]
* refactor engine to expose env methods [Chris Continanza]
* disable email notifications [David Dollar]
* add travis config [David Dollar]

View File

@@ -11,14 +11,11 @@ platform :jruby do
end
group :development do
gem 'parka'
gem 'aws-s3'
gem 'rake'
gem 'ronn'
gem 'fakefs', '~> 0.3.2'
gem 'rcov', '~> 0.9.8'
gem 'rr', '~> 1.0.2'
gem 'rspec', '~> 2.0'
gem 'ZenTest'
gem 'aws-s3'
gem "rubyzip"
gem "simplecov", :require => false
end

View File

@@ -1,37 +1,27 @@
PATH
remote: .
specs:
foreman (0.37.0.pre4)
term-ansicolor (~> 1.0.7)
foreman (0.45.0)
thor (>= 0.13.6)
GEM
remote: http://rubygems.org/
specs:
ZenTest (4.6.2)
aws-s3 (0.6.2)
builder
mime-types
xml-simple
builder (3.0.0)
crack (0.1.8)
diff-lcs (1.1.3)
fakefs (0.3.2)
hpricot (0.8.2)
hpricot (0.8.2-java)
hpricot (0.8.6)
hpricot (0.8.6-java)
mime-types (1.16)
multi_json (1.0.4)
mustache (0.11.2)
parka (0.6.2)
crack
rest-client
thor
posix-spawn (0.3.6)
rake (0.9.2.2)
rcov (0.9.8)
rcov (0.9.8-java)
rdiscount (1.6.5)
rest-client (1.6.1)
mime-types (>= 1.16)
ronn (0.7.3)
hpricot (>= 0.8.2)
mustache (>= 0.7.0)
@@ -45,8 +35,10 @@ GEM
rspec-expectations (2.8.0)
diff-lcs (~> 1.1.2)
rspec-mocks (2.8.0)
rubyzip (0.9.4)
term-ansicolor (1.0.7)
simplecov (0.5.4)
multi_json (~> 1.0.3)
simplecov-html (~> 0.5.3)
simplecov-html (0.5.3)
thor (0.14.6)
win32console (1.3.0-x86-mingw32)
xml-simple (1.0.15)
@@ -57,16 +49,13 @@ PLATFORMS
x86-mingw32
DEPENDENCIES
ZenTest
aws-s3
fakefs (~> 0.3.2)
foreman!
parka
posix-spawn (~> 0.3.6)
rake
rcov (~> 0.9.8)
ronn
rr (~> 1.0.2)
rspec (~> 2.0)
rubyzip
simplecov
win32console (~> 1.3.0)

View File

@@ -25,6 +25,7 @@ Manage Procfile-based applications
* [man page](http://ddollar.github.com/foreman)
* [wiki](http://github.com/ddollar/foreman/wiki)
* [changelog](https://github.com/ddollar/foreman/blob/master/Changelog.md)
## Authors
@@ -32,7 +33,7 @@ Manage Procfile-based applications
David Dollar
#### Patches contributed by
Adam Wiggins, Chris Continanza, Chris Lowder, Craig R Webster, Dan Farina, Dan Peterson, David Dollar, Fletcher Nichol, Gabriel Burt, Gamaliel Toro, Greg Reinacker, Hugues Le Gendre, Hunter Nield, Iain Hecker, Jay Zeschin, Keith Rarick, Khaja Minhajuddin, Lincoln Stoll, Marcos Muino Garcia, Mark McGranaghan, Matt Griffin, Matt Haynes, Matthijs Langenberg, Michael Dwan, Michael van Rooijen, Mike Javorski, Nathan Broadbent, Nathan L Smith, Nick Zadrozny, Phil Hagelberg, Ricardo Chimal, Jr, Thom May, Tom Ward, brainopia, clifff, jc00ke
[Contributor List](https://github.com/ddollar/foreman/contributors)
## License

190
Rakefile
View File

@@ -1,192 +1,8 @@
require "rake"
require "rspec"
require "rspec/core/rake_task"
$:.unshift File.expand_path("../lib", __FILE__)
require "foreman"
task :default => :spec
task :release => :man
require "bundler/setup"
desc "Run all specs"
RSpec::Core::RakeTask.new(:spec) do |t|
t.pattern = 'spec/**/*_spec.rb'
end
desc "Generate RCov code coverage report"
task :rcov => "rcov:build" do
%x{ open coverage/index.html }
end
RSpec::Core::RakeTask.new("rcov:build") do |t|
t.pattern = 'spec/**/*_spec.rb'
t.rcov = true
t.rcov_opts = [ "--exclude", ".bundle", "--exclude", "spec" ]
end
desc 'Build the manual'
task :man do
ENV['RONN_MANUAL'] = "Foreman Manual"
ENV['RONN_ORGANIZATION'] = "Foreman #{Foreman::VERSION}"
sh "ronn -w -s toc -r5 --markdown man/*.ronn"
end
desc "Commit the manual to git"
task "man:commit" => :man do
sh "git add README.markdown"
sh "git commit -m 'update readme' || echo 'nothing to commit'"
end
desc "Generate the Github docs"
task :pages => "man:commit" do
sh %{
cp man/foreman.1.html /tmp/foreman.1.html
git checkout gh-pages
rm ./index.html
cp /tmp/foreman.1.html ./index.html
git add -u index.html
git commit -m "saving man page to github docs"
git push origin -f gh-pages
git checkout master
}
end
task :authors do
authors = %x{ git log --pretty=format:"%an" | sort -u }.split("\n")
puts authors.join(", ")
end
## dist
require "erb"
require "fileutils"
require "tmpdir"
def assemble(source, target, perms=0644)
FileUtils.mkdir_p(File.dirname(target))
File.open(target, "w") do |f|
f.puts ERB.new(File.read(source)).result(binding)
end
File.chmod(perms, target)
end
def assemble_distribution(target_dir=Dir.pwd)
distribution_files.each do |source|
target = source.gsub(/^#{project_root}/, target_dir)
FileUtils.mkdir_p(File.dirname(target))
FileUtils.cp(source, target)
end
end
GEM_BLACKLIST = %w( bundler foreman )
def assemble_gems(target_dir=Dir.pwd)
lines = %x{ bundle show }.strip.split("\n")
raise "error running bundler" unless $?.success?
%x{ env BUNDLE_WITHOUT="development:test" bundle show }.split("\n").each do |line|
if line =~ /^ \* (.*?) \((.*?)\)/
next if GEM_BLACKLIST.include?($1)
puts "vendoring: #{$1}-#{$2}"
gem_dir = %x{ bundle show #{$1} }.strip
FileUtils.mkdir_p "#{target_dir}/vendor/gems"
%x{ cp -R "#{gem_dir}" "#{target_dir}/vendor/gems" }
end
end.compact
end
def beta?
Foreman::VERSION.to_s =~ /pre/
end
def clean(file)
rm file if File.exists?(file)
end
def distribution_files(type=nil)
require "foreman/distribution"
base_files = Foreman::Distribution.files
type_files = type ?
Dir[File.expand_path("../dist/resources/#{type}/**/*", __FILE__)] :
[]
base_files.concat(type_files)
end
def mkchdir(dir)
FileUtils.mkdir_p(dir)
Dir.chdir(dir) do |dir|
yield(File.expand_path(dir))
end
end
def pkg(filename)
File.expand_path("../pkg/#{filename}", __FILE__)
end
def project_root
File.dirname(__FILE__)
end
def resource(name)
File.expand_path("../dist/resources/#{name}", __FILE__)
end
def s3_connect
return if @s3_connected
require "aws/s3"
unless ENV["DAVID_RELEASE_ACCESS"] && ENV["DAVID_RELEASE_SECRET"]
puts "please set DAVID_RELEASE_ACCESS and DAVID_RELEASE_SECRET in your environment"
exit 1
end
AWS::S3::Base.establish_connection!(
:access_key_id => ENV["DAVID_RELEASE_ACCESS"],
:secret_access_key => ENV["DAVID_RELEASE_SECRET"]
)
@s3_connected = true
end
def store(package_file, filename, bucket="assets.foreman.io")
s3_connect
puts "storing: #{filename}"
AWS::S3::S3Object.store(filename, File.open(package_file), bucket, :access => :public_read)
end
def tempdir
Dir.mktmpdir do |dir|
Dir.chdir(dir) do
yield(dir)
end
end
end
def version
require "foreman/version"
Foreman::VERSION
end
Dir[File.expand_path("../dist/**/*.rake", __FILE__)].each do |rake|
import rake
end
task :changelog do
timestamp = Time.now.utc.strftime('%m/%d/%Y')
sha = `git log | head -1`.split(' ').last
changelog = ["#{version} #{timestamp} #{sha}"]
changelog << ('=' * changelog[0].length)
changelog << ''
last_sha = `cat Changelog | head -1`.split(' ').last
shortlog = `git log #{last_sha}..HEAD --pretty=format:'%s [%an]'`
changelog << shortlog.split("\n")
changelog.concat ['', '', '']
old_changelog = File.read('Changelog')
File.open('Changelog', 'w') do |file|
file.write(changelog.join("\n"))
file.write(old_changelog)
end
Dir[File.expand_path("../tasks/*.rake", __FILE__)].each do |task|
load task
end

View File

@@ -1 +0,0 @@
Autotest.add_discovery { "rspec2" }

View File

@@ -1,6 +1,6 @@
#!/bin/sh
#
#/ Usage: runner [-d <dir>] <command>
#/ Usage: foreman-runner [-d <dir>] <command>
#/
#/ Run a command with exec, optionally changing directory first
@@ -18,7 +18,7 @@ usage() {
while getopts ":hd:" OPT; do
case $OPT in
d) cd $OPTARG ;;
d) cd "$OPTARG" ;;
h) usage ;;
\?) error "invalid option: -$OPTARG" ;;
:) error "option -$OPTARG requires an argument" ;;
@@ -29,7 +29,7 @@ shift $((OPTIND-1))
command=$1
if [ "$1" == "" ]; then
if [ -z "$1" ]; then
usage
fi

View File

@@ -1,2 +1,3 @@
ticker: ruby ./ticker $PORT
error: ruby ./error
utf8: ruby ./utf8

11
data/example/utf8 Executable file
View File

@@ -0,0 +1,11 @@
#!/usr/bin/env ruby
# encoding: BINARY
$stdout.sync = true
while true
puts "\u65e5\u672c\u8a9e\u6587\u5b57\u5217"
puts "\u0915\u0932\u094d\u0907\u0928\u0643\u0637\u0628\u041a\u0430\u043b\u0438\u043d\u0430"
puts "\xff\x03"
sleep 1
end

View File

@@ -0,0 +1,27 @@
<%
app_names = []
engine.procfile.entries.each do |process|
next if (conc = self.concurrency[process.name]) < 1
1.upto(self.concurrency[process.name]) do |num|
port = engine.port_for(process, num, self.port)
name = if (conc > 1); "#{process.name}-#{num}" else process.name; end
environment = (engine.environment.keys.sort.map{ |var| %{#{var.upcase}="#{engine.environment[var]}"} } + [%{PORT="#{port}"}])
app_name = "#{app}-#{name}"
app_names << app_name
%>
[program:<%= app_name %>]
command=<%= process.command %>
autostart=true
autorestart=true
stopsignal=QUIT
stdout_logfile=<%= log_root %>/<%=process.name%>-<%=num%>-out.log
stderr_logfile=<%= log_root %>/<%=process.name%>-<%=num%>-err.log
user=<%= user %>
directory=<%= engine.directory %>
environment=<%= environment.join(',') %><%
end
end
%>
[group:<%= app %>]
programs=<%= app_names.join(',') %>

17
dist/deb.rake vendored
View File

@@ -4,7 +4,7 @@ file pkg("/apt-#{version}/foreman-#{version}.deb") => distribution_files("deb")
assemble_distribution
assemble_gems
assemble resource("deb/foreman"), "bin/foreman", 0755
File.chmod 0755, "bin/runner"
File.chmod 0755, "bin/foreman-runner"
end
assemble resource("deb/control"), "control"
@@ -20,12 +20,6 @@ file pkg("/apt-#{version}/foreman-#{version}.deb") => distribution_files("deb")
deb = File.basename(t.name)
sh "ar -r #{t.name} debian-binary control.tar.gz data.tar.gz"
touch "Sources"
sh "apt-ftparchive packages . > Packages"
sh "gzip -c Packages > Packages.gz"
sh "apt-ftparchive release . > Release"
sh "gpg -abs -u 0F1B0520 -o Release.gpg Release"
end
end
@@ -37,12 +31,3 @@ task "deb:clean" do
clean pkg("foreman-#{version}.deb")
FileUtils.rm_rf("pkg/apt-#{version}") if Dir.exists?("pkg/apt-#{version}")
end
desc "Publish .deb to S3."
task "deb:release" => "deb:build" do |t|
Dir["pkg/apt-#{version}/*"].each do |file|
unless File.directory?(file)
store file, "apt/#{File.basename(file)}"
end
end
end

2
dist/gem.rake vendored
View File

@@ -10,5 +10,5 @@ task "gem:clean" do
end
task "gem:release" => "gem:build" do |t|
sh "parka push -f #{pkg("foreman-#{version}.gem")}"
sh "gem push #{pkg("foreman-#{version}.gem")} || echo 'error'"
end

6
dist/jruby.rake vendored
View File

@@ -1,5 +1,7 @@
file pkg("foreman-#{version}-jruby.gem") => distribution_files do |t|
sh "env PLATFORM=java gem build foreman.gemspec"
Bundler.with_clean_env do
sh "env PLATFORM=java gem build foreman.gemspec"
end
sh "mv foreman-#{version}-java.gem #{t.name}"
end
@@ -10,5 +12,5 @@ task "jruby:clean" do
end
task "jruby:release" => "jruby:build" do |t|
sh "parka push -f #{pkg("foreman-#{version}-jruby.gem")}"
sh "gem push #{pkg("foreman-#{version}-jruby.gem")} || echo 'error'"
end

6
dist/mingw32.rake vendored
View File

@@ -1,5 +1,7 @@
file pkg("foreman-#{version}-mingw32.gem") => distribution_files do |t|
sh "env PLATFORM=mingw32 gem build foreman.gemspec"
Bundler.with_clean_env do
sh "env PLATFORM=mingw32 gem build foreman.gemspec"
end
sh "mv foreman-#{version}-mingw32.gem #{t.name}"
end
@@ -10,5 +12,5 @@ task "mingw32:clean" do
end
task "mingw32:release" => "mingw32:build" do |t|
sh "parka push -f #{pkg("foreman-#{version}-mingw32.gem")}"
sh "gem push #{pkg("foreman-#{version}-mingw32.gem")} || echo 'error'"
end

15
dist/pkg.rake vendored
View File

@@ -13,7 +13,7 @@ file pkg("foreman-#{version}.pkg") => distribution_files do |t|
mkdir_p "pkg"
mkdir_p "pkg/Resources"
mkdir_p "pkg/foreman-#{version}.pkg"
mkdir_p "pkg/foreman.pkg"
dist = File.read(resource("pkg/Distribution.erb"))
dist = ERB.new(dist).result(binding)
@@ -21,20 +21,21 @@ file pkg("foreman-#{version}.pkg") => distribution_files do |t|
dist = File.read(resource("pkg/PackageInfo.erb"))
dist = ERB.new(dist).result(binding)
File.open("pkg/foreman-#{version}.pkg/PackageInfo", "w") { |f| f.puts dist }
File.open("pkg/foreman.pkg/PackageInfo", "w") { |f| f.puts dist }
mkdir_p "pkg/foreman-#{version}.pkg/Scripts"
cp resource("pkg/postinstall"), "pkg/foreman-#{version}.pkg/Scripts/postinstall"
chmod 0755, "pkg/foreman-#{version}.pkg/Scripts/postinstall"
mkdir_p "pkg/foreman.pkg/Scripts"
cp resource("pkg/postinstall"), "pkg/foreman.pkg/Scripts/postinstall"
chmod 0755, "pkg/foreman.pkg/Scripts/postinstall"
sh %{ mkbom -s foreman pkg/foreman-#{version}.pkg/Bom }
sh %{ mkbom -s foreman pkg/foreman.pkg/Bom }
Dir.chdir("foreman") do
sh %{ pax -wz -x cpio . > ../pkg/foreman-#{version}.pkg/Payload }
sh %{ pax -wz -x cpio . > ../pkg/foreman.pkg/Payload }
end
sh %{ pkgutil --flatten pkg foreman-#{version}.pkg }
FileUtils.mkdir_p(File.dirname(t.name))
cp_r "foreman-#{version}.pkg", t.name
end
end

View File

@@ -10,14 +10,14 @@
]]></script>
<choices-outline>
<line choice="git"/>
<line choice="foreman-<%= version %>"/>
<line choice="foreman"/>
</choices-outline>
<choice id="git" title="git" start_selected="false" start_enabled="false" selected="needs_git()" enabled="needs_git()">
<pkg-ref id="git.pkg" />
</choice>
<choice id="foreman-<%= version %>" title="foreman">
<choice id="foreman" title="foreman">
<pkg-ref id="io.foreman.installer"/>
</choice>
<pkg-ref id="io.foreman.installer" installKBytes="<%= kbytes %>" version="<%= version %>" auth="Root">#foreman-<%= version %>.pkg</pkg-ref>
<pkg-ref id="io.foreman.installer" installKBytes="<%= kbytes %>" version="<%= version %>" auth="Root">#foreman.pkg</pkg-ref>
</installer-script>

View File

@@ -4,4 +4,3 @@
<postinstall file="./postinstall"/>
</scripts>
</pkg-info>

2
dist/tgz.rake vendored
View File

@@ -3,7 +3,7 @@ file pkg("foreman-#{version}.tgz") => distribution_files do |t|
mkchdir("foreman") do
assemble_distribution
assemble_gems
rm_rf "bin"
rm_f "bin/foreman"
assemble resource("tgz/foreman"), "foreman", 0755
end

View File

@@ -16,8 +16,7 @@ Gem::Specification.new do |gem|
gem.files = Dir["**/*"].select { |d| d =~ %r{^(README|bin/|data/|ext/|lib/|spec/|test/)} }
gem.files << "man/foreman.1"
gem.add_dependency 'term-ansicolor', '~> 1.0.7'
gem.add_dependency 'thor', '>= 0.13.6'
gem.add_dependency 'thor', '>= 0.13.6'
if ENV["PLATFORM"] == "java"
gem.add_dependency "posix-spawn", "~> 0.3.6"

View File

@@ -4,14 +4,8 @@ module Foreman
class AppDoesNotExist < Exception; end
# load contents of env_file into ENV
def self.load_env!(env_file = './.env')
require 'foreman/engine'
Foreman::Engine.load_env!(env_file)
end
def self.runner
File.expand_path("../../bin/runner", __FILE__)
File.expand_path("../../bin/foreman-runner", __FILE__)
end
def self.jruby?

View File

@@ -10,7 +10,7 @@ class Foreman::CLI < Thor
class_option :procfile, :type => :string, :aliases => "-f", :desc => "Default: Procfile"
desc "start", "Start the application"
desc "start [PROCESS]", "Start the application (or a specific PROCESS)"
class_option :procfile, :type => :string, :aliases => "-f", :desc => "Default: Procfile"
class_option :app_root, :type => :string, :aliases => "-d", :desc => "Default: Procfile directory"
@@ -27,8 +27,9 @@ class Foreman::CLI < Thor
end
end
def start
def start(process=nil)
check_procfile!
engine.options[:concurrency] = "#{process}=1" if process
engine.start
end
@@ -40,22 +41,11 @@ class Foreman::CLI < Thor
method_option :port, :type => :numeric, :aliases => "-p"
method_option :user, :type => :string, :aliases => "-u"
method_option :template, :type => :string, :aliases => "-t"
method_option :concurrency, :type => :string, :aliases => "-c",
:banner => '"alpha=5,bar=3"'
method_option :concurrency, :type => :string, :aliases => "-c", :banner => '"alpha=5,bar=3"'
def export(format, location=nil)
check_procfile!
begin
require "foreman/export/#{ format.tr('-', '_') }"
classy_format = classify(format)
formatter = constantize("Foreman::Export::#{ classy_format }")
rescue NameError => ex
error "Unknown export format: #{format} (no class Foreman::Export::#{ classy_format })."
rescue LoadError => ex
error "Unknown export format: #{format} (unable to load file 'foreman/export/#{ format.tr('-', '_') }')."
end
formatter = Foreman::Export.formatter(format)
formatter.new(location, engine, options).export
rescue Foreman::Export::Exception => ex
error ex.message
@@ -64,8 +54,9 @@ class Foreman::CLI < Thor
desc "check", "Validate your application's Procfile"
def check
check_procfile!
error "no processes defined" unless engine.procfile.entries.length > 0
display "valid procfile detected (#{engine.procfile.process_names.join(', ')})"
puts "valid procfile detected (#{engine.procfile.process_names.join(', ')})"
end
desc "run COMMAND", "Run a command using your application's environment"
@@ -92,11 +83,11 @@ private ######################################################################
end
def procfile
options[:procfile] || "Procfile"
end
def display(message)
puts message
case
when options[:procfile] then options[:procfile]
when options[:app_root] then File.expand_path(File.join(options[:app_root], "Procfile"))
else "Procfile"
end
end
def error(message)
@@ -104,10 +95,6 @@ private ######################################################################
exit 1
end
def procfile_exists?(procfile)
File.exist?(procfile)
end
def options
original_options = super
return original_options unless File.exists?(".foreman")

40
lib/foreman/color.rb Normal file
View File

@@ -0,0 +1,40 @@
require "foreman"
module Foreman::Color
ANSI = {
:reset => 0,
:black => 30,
:red => 31,
:green => 32,
:yellow => 33,
:blue => 34,
:magenta => 35,
:cyan => 36,
:white => 37,
:bright_black => 30,
:bright_red => 31,
:bright_green => 32,
:bright_yellow => 33,
:bright_blue => 34,
:bright_magenta => 35,
:bright_cyan => 36,
:bright_white => 37,
}
def self.enable(io)
io.extend(self)
end
def color?
return false unless self.respond_to?(:isatty)
self.isatty && ENV["TERM"]
end
def color(name)
return "" unless color?
return "" unless ansi = ANSI[name.to_sym]
"\e[#{ansi}m"
end
end

View File

@@ -1,36 +1,33 @@
require "foreman"
require "foreman/color"
require "foreman/process"
require "foreman/procfile"
require "foreman/utils"
require "tempfile"
require "timeout"
require "term/ansicolor"
require "fileutils"
require "thread"
class Foreman::Engine
attr_reader :environment
attr_reader :procfile
attr_reader :directory
attr_reader :options
extend Term::ANSIColor
COLORS = %w( cyan yellow green magenta red blue intense_cyan intense_yellow
intense_green intense_magenta intense_red, intense_blue )
COLORS = [ cyan, yellow, green, magenta, red, blue,
intense_cyan, intense_yellow, intense_green, intense_magenta,
intense_red, intense_blue ]
Foreman::Color.enable($stdout)
def initialize(procfile, options={})
@procfile = Foreman::Procfile.new(procfile)
@directory = options[:app_root] || File.expand_path(File.dirname(procfile))
@options = options
@environment = read_environment_files(options[:env])
@options = options.dup
@output_mutex = Mutex.new
end
def self.load_env!(env_file)
@environment = read_environment_files(env_file)
apply_environment!
@options[:env] ||= default_env
@environment = read_environment_files(@options[:env])
end
def start
@@ -52,13 +49,33 @@ class Foreman::Engine
base_port.to_i + offset + num - 1
end
def apply_environment!
environment.each { |k,v| ENV[k] = v }
end
def self.read_environment(filename)
return {} unless File.exists?(filename)
File.read(filename).split("\n").inject({}) do |hash, line|
if line =~ /\A([A-Za-z_0-9]+)=(.*)\z/
key, val = [$1, $2]
case val
when /\A'(.*)'\z/ then hash[key] = $1
when /\A"(.*)"\z/ then hash[key] = $1.gsub(/\\(.)/, '\1')
else hash[key] = val
end
end
hash
end
end
private ######################################################################
def spawn_processes
concurrency = Foreman::Utils.parse_concurrency(@options[:concurrency])
procfile.entries.each do |entry|
reader, writer = IO.pipe
reader, writer = (IO.method(:pipe).arity == 0 ? IO.pipe : IO.pipe("BINARY"))
entry.spawn(concurrency[entry.name], writer, @directory, @environment, port_for(entry, 1, base_port)).each do |process|
running_processes[process.pid] = process
readers[process] = reader
@@ -78,27 +95,40 @@ private ######################################################################
end
def terminate_gracefully
return if @terminating
@terminating = true
info "sending SIGTERM to all processes"
kill_all "SIGTERM"
Timeout.timeout(5) { Process.waitall }
Timeout.timeout(5) do
while running_processes.length > 0
pid, status = Process.wait2
process = running_processes.delete(pid)
info "process terminated", process.name
end
end
rescue Timeout::Error
info "sending SIGKILL to all processes"
kill_all "SIGKILL"
end
def poll_readers
rs, ws = IO.select(readers.values, [], [], 1)
(rs || []).each do |r|
data = r.gets
next unless data
data.force_encoding("BINARY") if data.respond_to?(:force_encoding)
ps, message = data.split(",", 2)
color = colors[ps.split(".").first]
info message, ps, color
end
end
def watch_for_output
Thread.new do
require "win32console" if Foreman.windows?
begin
loop do
rs, ws = IO.select(readers.values, [], [], 1)
(rs || []).each do |r|
data = r.gets
next unless data
ps, message = data.split(",", 2)
color = colors[ps.split(".").first]
info message, ps, color
end
poll_readers
end
rescue Exception => ex
puts ex.message
@@ -112,16 +142,16 @@ private ######################################################################
process = running_processes.delete(pid)
info "process terminated", process.name
terminate_gracefully
kill_all
rescue Errno::ECHILD
end
def info(message, name="system", color=Term::ANSIColor.white)
print color
print "#{Time.now.strftime("%H:%M:%S")} #{pad_process_name(name)} | "
print Term::ANSIColor.reset
print message.chomp
puts ""
def info(message, name="system", color=:white)
output = ""
output += $stdout.color(color)
output += "#{Time.now.strftime("%H:%M:%S")} #{pad_process_name(name)} | "
output += $stdout.color(:reset)
output += message.chomp
puts output
end
def print(message=nil)
@@ -169,8 +199,8 @@ private ######################################################################
end
def assign_colors
procfile.entries.each do |entry|
colors[entry.name] = next_color
procfile.entries.each_with_index do |entry, idx|
colors[entry.name] = COLORS[idx % COLORS.length]
end
end
@@ -178,49 +208,20 @@ private ######################################################################
readers.invert[reader]
end
def next_color
@current_color ||= -1
@current_color += 1
@current_color = 0 if COLORS.length < @current_color
COLORS[@current_color]
def read_environment_files(filenames)
environment = {}
(filenames || "").split(",").map(&:strip).each do |filename|
error "No such file: #{filename}" unless File.exists?(filename)
environment.merge!(Foreman::Engine.read_environment(filename))
end
environment
end
module Env
attr_reader :environment
def read_environment_files(filenames)
environment = {}
(filenames || "").split(",").map(&:strip).each do |filename|
error "No such file: #{filename}" unless File.exists?(filename)
environment.merge!(read_environment(filename))
end
environment.merge!(read_environment(".env")) unless filenames
environment
end
def read_environment(filename)
return {} unless File.exists?(filename)
File.read(filename).split("\n").inject({}) do |hash, line|
if line =~ /\A([A-Za-z_0-9]+)=(.*)\z/
hash[$1] = $2
end
hash
end
end
def apply_environment!
@environment.each { |k,v| ENV[k] = v }
end
def error(message)
puts "ERROR: #{message}"
exit 1
end
def default_env
env = File.join(directory, ".env")
File.exists?(env) ? env : ""
end
include Env
extend Env
end

View File

@@ -1,11 +1,34 @@
require "foreman"
require "foreman/helpers"
module Foreman::Export
extend Foreman::Helpers
class Exception < ::Exception; end
def self.formatter(format)
begin
require "foreman/export/#{ format.tr('-', '_') }"
classy_format = classify(format)
formatter = constantize("Foreman::Export::#{ classy_format }")
rescue NameError => ex
error "Unknown export format: #{format} (no class Foreman::Export::#{ classy_format })."
rescue LoadError => ex
error "Unknown export format: #{format} (unable to load file 'foreman/export/#{ format.tr('-', '_') }')."
end
end
def self.error(message)
raise Foreman::Export::Exception.new(message)
end
end
require "foreman/export/base"
require "foreman/export/inittab"
require "foreman/export/upstart"
require "foreman/export/bluepill"
require "foreman/export/runit"
require "foreman/export/supervisord"

View File

@@ -24,12 +24,12 @@ class Foreman::Export::Inittab < Foreman::Export::Base
inittab = inittab.join("\n") + "\n"
if fname
if location == "-"
puts inittab
else
FileUtils.mkdir_p(log_root) rescue error "could not create #{log_root}"
FileUtils.chown(user, nil, log_root) rescue error "could not chown #{log_root} to #{user}"
write_file(fname, inittab)
else
puts inittab
write_file(location, inittab)
end
end

View File

@@ -0,0 +1,26 @@
require "erb"
require "foreman/export"
class Foreman::Export::Supervisord < Foreman::Export::Base
def export
error("Must specify a location") unless location
FileUtils.mkdir_p location
app = self.app || File.basename(engine.directory)
user = self.user || app
log_root = self.log || "/var/log/#{app}"
template_root = self.template
Dir["#{location}/#{app}*.conf"].each do |file|
say "cleaning up: #{file}"
FileUtils.rm(file)
end
app_template = export_template("supervisord", "app.conf.erb", template_root)
app_config = ERB.new(app_template, 0, '<').result(binding)
write_file "#{location}/#{app}.conf", app_config
end
end

View File

@@ -36,6 +36,8 @@ class Foreman::Export::Upstart < Foreman::Export::Base
write_file "#{location}/#{app}-#{process.name}-#{num}.conf", process_config
end
end
end
FileUtils.mkdir_p(log_root) rescue error "could not create #{log_root}"
FileUtils.chown(user, nil, log_root) rescue error "could not chown #{log_root} to #{user}"
end
end

View File

@@ -6,9 +6,8 @@ module Foreman::Helpers
# classify('job-name') # => 'JobName'
def classify(dashed_word)
dashed_word.split('-').each { |part| part[0] = part[0].chr.upcase }.join
end
end # Tries to find a constant with the name specified in the argument string:
# Tries to find a constant with the name specified in the argument string:
#
# constantize("Module") # => Module
# constantize("Test::Unit") # => Test::Unit
@@ -28,10 +27,6 @@ module Foreman::Helpers
def constantize(camel_cased_word)
camel_cased_word = camel_cased_word.to_s
if camel_cased_word.include?('-')
camel_cased_word = classify(camel_cased_word)
end
names = camel_cased_word.split('::')
names.shift if names.empty? || names.first.empty?
@@ -47,4 +42,4 @@ module Foreman::Helpers
end
constant
end
end
end

View File

@@ -63,7 +63,7 @@ private
$stderr.reopen writer
reader.close
exec Foreman.runner, "-d", basedir, command
end
end
end
[ reader, pid ]
end

View File

@@ -1,5 +1,5 @@
module Foreman
VERSION = "0.37.0.pre4"
VERSION = "0.45.0"
end

View File

@@ -1,7 +1,7 @@
.\" generated with Ronn/v0.7.3
.\" http://github.com/rtomayko/ronn/tree/0.7.3
.
.TH "FOREMAN" "1" "January 2012" "Foreman 0.33.1" "Foreman Manual"
.TH "FOREMAN" "1" "April 2012" "Foreman 0.44.0" "Foreman Manual"
.
.SH "NAME"
\fBforeman\fR \- manage Procfile\-based applications
@@ -10,10 +10,13 @@
\fBforeman start [process]\fR
.
.br
\fBforeman run <command>\fR
.
.br
\fBforeman export <format> [location]\fR
.
.SH "DESCRIPTION"
\fBForeman\fR is a manager for Procfile\-based applications\. Its aim is to abstract away the details of the Procfile format, and allow you to either run your application directly or export it to some other process management format\.
Foreman is a manager for Procfile\-based applications\. Its aim is to abstract away the details of the Procfile format, and allow you to either run your application directly or export it to some other process management format\.
.
.SH "RUNNING"
\fBforeman start\fR is used to run your application directly from the command line\.
@@ -32,9 +35,20 @@ The following options control how the application is run:
Specify the number of each process type to run\. The value passed in should be in the format \fBprocess=num,process=num\fR
.
.TP
\fB\-e\fR, \fB\-\-env\fR
Specify one or more \.env files to load
.
.TP
\fB\-f\fR, \fB\-\-procfile\fR
Specify an alternate Procfile to load, implies \fB\-d\fR at the Procfile root\.
.
.TP
\fB\-p\fR, \fB\-\-port\fR
Specify which port to use as the base for this application\. Should be a multiple of 1000\.
.
.P
\fBforeman run\fR is used to run one\-off commands using the same environment as your defined processes\.
.
.SH "EXPORTING"
\fBforeman export\fR is used to export your application to another process management format\.
.
@@ -61,10 +75,14 @@ Specify the directory to place process logs in\.
Specify which port to use as the base for this application\. Should be a multiple of 1000\.
.
.TP
\fB\-t\fR, \fB\-\-template\fR
Specify an alternate template to use for creating export files\. See \fIhttps://github\.com/ddollar/foreman/tree/master/data/export\fR for examples\.
.
.TP
\fB\-u\fR, \fB\-\-user\fR
Specify the user the application should be run as\. Defaults to the app name
.
.SH "OPTIONS"
.SH "GLOBAL OPTIONS"
These options control all modes of foreman\'s operation\.
.
.TP

View File

@@ -4,11 +4,12 @@ foreman(1) -- manage Procfile-based applications
## SYNOPSIS
`foreman start [process]`<br>
`foreman run <command>`<br>
`foreman export <format> [location]`
## DESCRIPTION
**Foreman** is a manager for Procfile-based applications. Its aim is to
Foreman is a manager for Procfile-based applications. Its aim is to
abstract away the details of the Procfile format, and allow you to either run
your application directly or export it to some other process management
format.
@@ -29,10 +30,19 @@ The following options control how the application is run:
Specify the number of each process type to run. The value passed in
should be in the format `process=num,process=num`
* `-e`, `--env`:
Specify one or more .env files to load
* `-f`, `--procfile`:
Specify an alternate Procfile to load, implies `-d` at the Procfile root.
* `-p`, `--port`:
Specify which port to use as the base for this application. Should be
a multiple of 1000.
`foreman run` is used to run one-off commands using the same environment
as your defined processes.
## EXPORTING
`foreman export` is used to export your application to another process
@@ -58,11 +68,15 @@ The following options control how the application is run:
Specify which port to use as the base for this application. Should be
a multiple of 1000.
* `-t`, `--template`:
Specify an alternate template to use for creating export files.
See <https://github.com/ddollar/foreman/tree/master/data/export> for examples.
* `-u`, `--user`:
Specify the user the application should be run as. Defaults to the
app name
## OPTIONS
## GLOBAL OPTIONS
These options control all modes of foreman's operation.

View File

@@ -3,6 +3,8 @@ require "foreman/cli"
describe "Foreman::CLI", :fakefs do
subject { Foreman::CLI.new }
let(:engine) { subject.send(:engine) }
let(:entries) { engine.procfile.entries.inject({}) { |h,e| h.update(e.name => e) } }
describe "start" do
describe "with a non-existent Procfile" do
@@ -22,11 +24,38 @@ describe "Foreman::CLI", :fakefs do
mock.instance_of(Foreman::Engine).start
subject.start
end
it "can run a single process" do
dont_allow(subject).error
stub(engine).watch_for_output
stub(engine).watch_for_termination
mock(entries["alpha"]).spawn(1, is_a(IO), engine.directory, {}, 5000) { [] }
mock(entries["bravo"]).spawn(0, is_a(IO), engine.directory, {}, 5100) { [] }
subject.start("alpha")
end
end
describe "with an alternate root" do
it "reads the Procfile from that root" do
write_procfile "/some/app/Procfile"
mock(Foreman::Procfile).new("/some/app/Procfile")
mock.instance_of(Foreman::Engine).start
foreman %{ start -d /some/app }
end
end
end
describe "export" do
describe "options" do
it "uses .foreman" do
write_procfile
File.open(".foreman", "w") { |f| f.puts "concurrency: alpha=2" }
mock_export = mock(Foreman::Export::Upstart)
mock(Foreman::Export::Upstart).new("/upstart", is_a(Foreman::Engine), { "concurrency" => "alpha=2" }) { mock_export }
mock_export.export
foreman %{ export upstart /upstart }
end
it "respects --env" do
write_procfile
write_env("envfile")
@@ -49,10 +78,18 @@ describe "Foreman::CLI", :fakefs do
describe "with a Procfile" do
before(:each) { write_procfile }
describe "with an invalid formatter" do
describe "with a formatter with a generic error" do
before do
mock(Foreman::Export).formatter("errorful") { Class.new(Foreman::Export::Base) do
def export
raise Foreman::Export::Exception.new("foo")
end
end }
end
it "prints an error" do
mock_error(subject, "Unknown export format: invalidformatter (unable to load file 'foreman/export/invalidformatter').") do
subject.export("invalidformatter")
mock_error(subject, "foo") do
subject.export("errorful")
end
end
end
@@ -76,7 +113,7 @@ describe "Foreman::CLI", :fakefs do
before { write_procfile }
it "displays the jobs" do
mock(subject).display("valid procfile detected (alpha, bravo)")
mock(subject).puts("valid procfile detected (alpha, bravo)")
subject.check
end
end
@@ -92,6 +129,14 @@ describe "Foreman::CLI", :fakefs do
end
end
end
describe "without a Procfile" do
it "displays an error" do
mock_error(subject, "Procfile does not exist.") do
subject.check
end
end
end
end
describe "run" do

View File

@@ -0,0 +1,31 @@
require "spec_helper"
require "foreman/color"
describe Foreman::Color do
let(:io) { Object.new }
it "should extend an object with colorization" do
Foreman::Color.enable(io)
io.should respond_to(:color)
end
it "should not colorize if the object does not respond to isatty" do
mock(io).respond_to?(:isatty) { false }
Foreman::Color.enable(io)
io.color(:white).should == ""
end
it "should not colorize if the object is not a tty" do
mock(io).isatty { false }
Foreman::Color.enable(io)
io.color(:white).should == ""
end
it "should colorize if the object is a tty" do
mock(io).isatty { true }
Foreman::Color.enable(io)
io.color(:white).should == "\e[37m"
end
end

View File

@@ -4,6 +4,13 @@ require "foreman/engine"
describe "Foreman::Engine", :fakefs do
subject { Foreman::Engine.new("Procfile", {}) }
before do
any_instance_of(Foreman::Engine) do |engine|
stub(engine).proctitle
stub(engine).termtitle
end
end
describe "initialize" do
describe "without an existing Procfile" do
it "raises an error" do
@@ -42,18 +49,28 @@ describe "Foreman::Engine", :fakefs do
end
end
describe "directories" do
it "has the directory default relative to the Procfile" do
write_procfile "/some/app/Procfile"
engine = Foreman::Engine.new("/some/app/Procfile")
engine.directory.should == "/some/app"
end
end
describe "environment" do
before(:each) do
write_procfile
stub(Process).fork
any_instance_of(Foreman::Engine) do |engine|
stub(engine).info
stub(engine).spawn_processes
stub(engine).watch_for_termination
end
end
it "should read if specified" do
File.open("/tmp/env", "w") { |f| f.puts("FOO=baz") }
engine = Foreman::Engine.new("Procfile", :env => "/tmp/env")
stub(engine).info
mock(engine).spawn_processes
mock(engine).watch_for_termination
engine.environment.should == {"FOO"=>"baz"}
engine.start
end
@@ -62,13 +79,21 @@ describe "Foreman::Engine", :fakefs do
File.open("/tmp/env1", "w") { |f| f.puts("FOO=bar") }
File.open("/tmp/env2", "w") { |f| f.puts("BAZ=qux") }
engine = Foreman::Engine.new("Procfile", :env => "/tmp/env1,/tmp/env2")
stub(engine).info
mock(engine).spawn_processes
mock(engine).watch_for_termination
engine.environment.should == { "FOO"=>"bar", "BAZ"=>"qux" }
engine.start
end
it "should handle quoted values" do
File.open("/tmp/env", "w") do |f|
f.puts 'FOO=bar'
f.puts 'BAZ="qux"'
f.puts "FRED='barney'"
f.puts 'OTHER="escaped\"quote"'
end
engine = Foreman::Engine.new("Procfile", :env => "/tmp/env")
engine.environment.should == { "FOO" => "bar", "BAZ" => "qux", "FRED" => "barney", "OTHER" => 'escaped"quote' }
end
it "should fail if specified and doesnt exist" do
mock.instance_of(Foreman::Engine).error("No such file: /tmp/env")
engine = Foreman::Engine.new("Procfile", :env => "/tmp/env")
@@ -77,10 +102,36 @@ describe "Foreman::Engine", :fakefs do
it "should read .env if none specified" do
File.open(".env", "w") { |f| f.puts("FOO=qoo") }
engine = Foreman::Engine.new("Procfile")
mock(engine).spawn_processes
mock(engine).watch_for_termination
engine.environment.should == {"FOO"=>"qoo"}
engine.start
end
it "should be loaded relative to the Procfile" do
FileUtils.mkdir_p "/some/app"
File.open("/some/app/.env", "w") { |f| f.puts("FOO=qoo") }
write_procfile "/some/app/Procfile"
engine = Foreman::Engine.new("/some/app/Procfile")
engine.environment.should == {"FOO"=>"qoo"}
engine.start
end
end
describe "utf8" do
before(:each) do
File.open("Procfile", "w") do |file|
file.puts "utf8: #{resource_path("bin/utf8")}"
end
end
it "should spawn" do
stub(subject).watch_for_output
stub(subject).watch_for_termination
subject.start
Process.waitall
mock(subject).info(/started with pid \d+/, "utf8.1", anything)
mock(subject).info("\xff\x03\n", "utf8.1", anything)
subject.send(:poll_readers)
subject.send(:poll_readers)
end
end
end

View File

@@ -0,0 +1,22 @@
require "spec_helper"
require "foreman/export/base"
describe "Foreman::Export::Base" do
let(:procfile) { FileUtils.mkdir_p("/tmp/app"); write_procfile("/tmp/app/Procfile") }
let(:location) { "/tmp/init" }
let(:engine) { Foreman::Engine.new(procfile) }
let(:subject) { Foreman::Export::Base.new(location, engine) }
it "has a say method for displaying info" do
mock(subject).puts("[foreman export] foo")
subject.send(:say, "foo")
end
it "export needs to be overridden" do
lambda { subject.export }.should raise_error("export method must be overridden")
end
it "raises errors as a Foreman::Export::Exception" do
lambda { subject.send(:error, "foo") }.should raise_error(Foreman::Export::Exception, "foo")
end
end

View File

@@ -17,7 +17,14 @@ describe Foreman::Export::Bluepill, :fakefs do
normalize_space(File.read("/tmp/init/app.pill")).should == normalize_space(example_export_file("bluepill/app.pill"))
end
context "with concurrency" do
it "cleans up if exporting into an existing dir" do
mock(FileUtils).rm("/tmp/init/app.pill")
bluepill.export
bluepill.export
end
context "with concurrency" do
let(:options) { Hash[:concurrency => "alpha=2"] }
it "exports to the filesystem with concurrency" do

View File

@@ -0,0 +1,40 @@
require "spec_helper"
require "foreman/engine"
require "foreman/export/inittab"
require "tmpdir"
describe Foreman::Export::Inittab, :fakefs do
let(:location) { "/tmp/inittab" }
let(:procfile) { FileUtils.mkdir_p("/tmp/app"); write_procfile("/tmp/app/Procfile") }
let(:location) { "/tmp/inittab" }
let(:engine) { Foreman::Engine.new(procfile) }
let(:options) { Hash.new }
let(:inittab) { Foreman::Export::Inittab.new(location, engine, options) }
before(:each) { load_export_templates_into_fakefs("inittab") }
before(:each) { stub(inittab).say }
it "exports to the filesystem" do
inittab.export
File.read("/tmp/inittab").should == example_export_file("inittab/inittab.default")
end
context "to stdout" do
let(:location) { "-" }
it "exports to stdout" do
mock(inittab).puts example_export_file("inittab/inittab.default")
inittab.export
end
end
context "with concurrency" do
let(:options) { Hash[:concurrency => "alpha=2"] }
it "exports to the filesystem with concurrency" do
inittab.export
File.read("/tmp/inittab").should == example_export_file("inittab/inittab.concurrency")
end
end
end

View File

@@ -0,0 +1,85 @@
require "spec_helper"
require "foreman/engine"
require "foreman/export/supervisord"
require "tmpdir"
describe Foreman::Export::Supervisord, :fakefs do
let(:procfile) { FileUtils.mkdir_p("/tmp/app"); write_procfile("/tmp/app/Procfile") }
let(:engine) { Foreman::Engine.new(procfile) }
let(:options) { Hash.new }
let(:supervisord) { Foreman::Export::Supervisord.new("/tmp/init", engine, options) }
before(:each) { load_export_templates_into_fakefs("supervisord") }
before(:each) { stub(supervisord).say }
it "exports to the filesystem" do
supervisord.export
File.read("/tmp/init/app.conf").should == example_export_file("supervisord/app.conf")
end
it "cleans up if exporting into an existing dir" do
mock(FileUtils).rm("/tmp/init/app.conf")
supervisord.export
supervisord.export
end
context "with concurrency" do
let(:options) { Hash[:concurrency => "alpha=2"] }
it "exports to the filesystem with concurrency" do
supervisord.export
File.read("/tmp/init/app.conf").should == example_export_file("supervisord/app-alpha-2.conf")
end
end
context "with alternate templates" do
let(:template_root) { "/tmp/alternate" }
let(:supervisord) { Foreman::Export::Supervisord.new("/tmp/init", engine, :template => template_root) }
before do
FileUtils.mkdir_p template_root
File.open("#{template_root}/app.conf.erb", "w") { |f| f.puts "alternate_template" }
end
it "can export with alternate template files" do
supervisord.export
File.read("/tmp/init/app.conf").should == "alternate_template\n"
end
end
context "with alternate templates from home dir" do
let(:default_template_root) {File.expand_path("#{ENV['HOME']}/.foreman/templates")}
before do
ENV['_FOREMAN_SPEC_HOME'] = ENV['HOME']
ENV['HOME'] = "/home/appuser"
FileUtils.mkdir_p default_template_root
File.open("#{default_template_root}/app.conf.erb", "w") { |f| f.puts "default_alternate_template" }
end
after do
ENV['HOME'] = ENV.delete('_FOREMAN_SPEC_HOME')
end
it "can export with alternate template files" do
supervisord.export
File.read("/tmp/init/app.conf").should == "default_alternate_template\n"
end
end
context "environment export" do
it "correctly translates environment when exporting" do
File.open("/tmp/supervisord_env", "w") { |f| f.puts("QUEUE=fastqueue,slowqueue\nVERBOSE=1") }
engine = Foreman::Engine.new(procfile,:env => "/tmp/supervisord_env")
supervisor = Foreman::Export::Supervisord.new("/tmp/init", engine, options)
stub(supervisor).say
supervisor.export
File.read("/tmp/init/app.conf").should == example_export_file("supervisord/app-env-with-comma.conf")
end
end
end

View File

@@ -22,6 +22,17 @@ describe Foreman::Export::Upstart, :fakefs do
File.read("/tmp/init/app-bravo-1.conf").should == example_export_file("upstart/app-bravo-1.conf")
end
it "cleans up if exporting into an existing dir" do
mock(FileUtils).rm("/tmp/init/app.conf")
mock(FileUtils).rm("/tmp/init/app-alpha.conf")
mock(FileUtils).rm("/tmp/init/app-alpha-1.conf")
mock(FileUtils).rm("/tmp/init/app-bravo.conf")
mock(FileUtils).rm("/tmp/init/app-bravo-1.conf")
upstart.export
upstart.export
end
context "with concurrency" do
let(:options) { Hash[:concurrency => "alpha=2"] }

View File

@@ -1,2 +1,24 @@
require "spec_helper"
require "foreman/export"
describe "Foreman::Export" do
subject { Foreman::Export }
describe "with a formatter that doesn't declare the appropriate class" do
it "prints an error" do
mock(subject).require("foreman/export/invalidformatter")
mock_export_error("Unknown export format: invalidformatter (no class Foreman::Export::Invalidformatter).") do
subject.formatter("invalidformatter")
end
end
end
describe "with an invalid formatter" do
it "prints an error" do
mock_export_error("Unknown export format: invalidformatter (unable to load file 'foreman/export/invalidformatter').") do
subject.formatter("invalidformatter")
end
end
end
end

View File

@@ -0,0 +1,26 @@
require "spec_helper"
require "foreman/helpers"
describe "Foreman::Helpers" do
before do
module Foo
class Bar; end
end
end
after do
Object.send(:remove_const, :Foo)
end
subject { o = Object.new; o.extend(Foreman::Helpers); o }
it "should classify words" do
subject.classify("foo").should == "Foo"
subject.classify("foo-bar").should == "FooBar"
end
it "should constantize words" do
subject.constantize("Object").should == Object
subject.constantize("Foo::Bar").should == Foo::Bar
end
end

View File

@@ -36,6 +36,7 @@ describe Foreman::Process do
def run_file(executable, code)
file = File.open("#{basedir}/script", 'w') {|it| it << code }
run "#{executable} #{file.path}"
sleep 1
end
context 'options' do
@@ -98,7 +99,6 @@ describe Foreman::Process do
trap "TERM", "IGNORE"
loop { sleep 1 }
CODE
sleep 1 # wait for ruby to start
subject.should be_alive
subject.kill 'TERM'
subject.should be_alive

View File

@@ -8,21 +8,9 @@ describe Foreman do
it { should be_a String }
end
describe "::load_env!(env_file)", :fakefs do
after do
ENV['FOO'] = nil
end
it "should load env_file into ENV" do
File.open("/tmp/env1", "w") { |f| f.puts("FOO=bar") }
Foreman.load_env!("/tmp/env1")
ENV['FOO'].should == 'bar'
end
it "should assume env_file in ./.env" do
File.open("./.env", "w") { |f| f.puts("FOO=bar") }
Foreman.load_env!
ENV['FOO'].should == 'bar'
describe "runner" do
it "should exist" do
File.exists?(Foreman.runner).should == true
end
end
end

2
spec/resources/bin/utf8 Executable file
View File

@@ -0,0 +1,2 @@
#!/usr/bin/env ruby
puts "\xff\x03"

View File

@@ -0,0 +1,4 @@
# ----- foreman app processes -----
AP01:4:respawn:/bin/su - app -c 'PORT=5000 ./alpha >> /var/log/app/alpha-1.log 2>&1'
AP02:4:respawn:/bin/su - app -c 'PORT=5001 ./alpha >> /var/log/app/alpha-2.log 2>&1'
# ----- end foreman app processes -----

View File

@@ -0,0 +1,4 @@
# ----- foreman app processes -----
AP01:4:respawn:/bin/su - app -c 'PORT=5000 ./alpha >> /var/log/app/alpha-1.log 2>&1'
AP02:4:respawn:/bin/su - app -c 'PORT=5100 ./bravo >> /var/log/app/bravo-1.log 2>&1'
# ----- end foreman app processes -----

View File

@@ -0,0 +1,24 @@
[program:app-alpha-1]
command=./alpha
autostart=true
autorestart=true
stopsignal=QUIT
stdout_logfile=/var/log/app/alpha-1-out.log
stderr_logfile=/var/log/app/alpha-1-err.log
user=app
directory=/tmp/app
environment=PORT="5000"
[program:app-alpha-2]
command=./alpha
autostart=true
autorestart=true
stopsignal=QUIT
stdout_logfile=/var/log/app/alpha-2-out.log
stderr_logfile=/var/log/app/alpha-2-err.log
user=app
directory=/tmp/app
environment=PORT="5001"
[group:app]
programs=app-alpha-1,app-alpha-2

View File

@@ -0,0 +1,24 @@
[program:app-alpha]
command=./alpha
autostart=true
autorestart=true
stopsignal=QUIT
stdout_logfile=/var/log/app/alpha-1-out.log
stderr_logfile=/var/log/app/alpha-1-err.log
user=app
directory=/tmp/app
environment=QUEUE="fastqueue,slowqueue",VERBOSE="1",PORT="5000"
[program:app-bravo]
command=./bravo
autostart=true
autorestart=true
stopsignal=QUIT
stdout_logfile=/var/log/app/bravo-1-out.log
stderr_logfile=/var/log/app/bravo-1-err.log
user=app
directory=/tmp/app
environment=QUEUE="fastqueue,slowqueue",VERBOSE="1",PORT="5100"
[group:app]
programs=app-alpha,app-bravo

View File

@@ -0,0 +1,21 @@
[program:app-alpha]
command=./alpha
autostart=true
autorestart=true
stopsignal=QUIT
stdout_logfile=/var/log/app/alpha-1-out.log
stderr_logfile=/var/log/app/alpha-1-err.log
user=app
directory=/tmp/app
environment=FOO="bar",PORT="5000"
[program:app-bravo]
command=./bravo
autostart=true
autorestart=true
stopsignal=QUIT
stdout_logfile=/var/log/app/bravo-1-out.log
stderr_logfile=/var/log/app/bravo-1-err.log
user=app
directory=/tmp/app
environment=FOO="bar",PORT="5100"

View File

@@ -0,0 +1,24 @@
[program:app-alpha]
command=./alpha
autostart=true
autorestart=true
stopsignal=QUIT
stdout_logfile=/var/log/app/alpha-1-out.log
stderr_logfile=/var/log/app/alpha-1-err.log
user=app
directory=/tmp/app
environment=PORT="5000"
[program:app-bravo]
command=./bravo
autostart=true
autorestart=true
stopsignal=QUIT
stdout_logfile=/var/log/app/bravo-1-out.log
stderr_logfile=/var/log/app/bravo-1-err.log
user=app
directory=/tmp/app
environment=PORT="5100"
[group:app]
programs=app-alpha,app-bravo

View File

@@ -1,10 +1,20 @@
require "rubygems"
require "simplecov"
SimpleCov.start do
add_filter "/spec/"
end
require "rspec"
require "fakefs/safe"
require "fakefs/spec_helpers"
$:.unshift File.expand_path("../../lib", __FILE__)
def mock_export_error(message)
lambda { yield }.should raise_error(Foreman::Export::Exception, message)
end
def mock_error(subject, message)
mock_exit do
mock(subject).puts("ERROR: #{message}")
@@ -37,9 +47,11 @@ def write_procfile(procfile="Procfile", alpha_env="")
File.expand_path(procfile)
end
def write_env(env=".env")
def write_env(env=".env", options={"FOO"=>"bar"})
File.open(env, "w") do |file|
file.puts "FOO=bar"
options.each do |key, val|
file.puts "#{key}=#{val}"
end
end
end
@@ -56,9 +68,13 @@ def load_export_templates_into_fakefs(type)
end
end
def resource_path(filename)
File.expand_path("../resources/#{filename}", __FILE__)
end
def example_export_file(filename)
FakeFS.deactivate!
data = File.read(File.expand_path("../resources/export/#{filename}", __FILE__))
data = File.read(File.expand_path(resource_path("export/#{filename}"), __FILE__))
FakeFS.activate!
data
end

112
tasks/dist.rake Normal file
View File

@@ -0,0 +1,112 @@
require "erb"
require "fileutils"
require "tmpdir"
def assemble(source, target, perms=0644)
FileUtils.mkdir_p(File.dirname(target))
File.open(target, "w") do |f|
f.puts ERB.new(File.read(source)).result(binding)
end
File.chmod(perms, target)
end
def assemble_distribution(target_dir=Dir.pwd)
distribution_files.each do |source|
target = source.gsub(/^#{project_root}/, target_dir)
FileUtils.mkdir_p(File.dirname(target))
FileUtils.cp(source, target)
end
end
GEM_BLACKLIST = %w( bundler foreman )
def assemble_gems(target_dir=Dir.pwd)
lines = %x{ cd #{project_root} && bundle show }.strip.split("\n")
raise "error running bundler" unless $?.success?
%x{ env BUNDLE_WITHOUT="development:test" bundle show }.split("\n").each do |line|
if line =~ /^ \* (.*?) \((.*?)\)/
next if GEM_BLACKLIST.include?($1)
puts "vendoring: #{$1}-#{$2}"
gem_dir = %x{ bundle show #{$1} }.strip
FileUtils.mkdir_p "#{target_dir}/vendor/gems"
%x{ cp -R "#{gem_dir}" "#{target_dir}/vendor/gems" }
end
end.compact
end
def beta?
Foreman::VERSION.to_s =~ /pre/
end
def clean(file)
rm file if File.exists?(file)
end
def distribution_files(type=nil)
require "foreman/distribution"
base_files = Foreman::Distribution.files
type_files = type ?
Dir[File.expand_path("../../dist/resources/#{type}/**/*", __FILE__)] : []
base_files.concat(type_files)
end
def mkchdir(dir)
FileUtils.mkdir_p(dir)
Dir.chdir(dir) do |dir|
yield(File.expand_path(dir))
end
end
def pkg(filename)
File.expand_path("../../pkg/#{filename}", __FILE__)
end
def project_root
File.expand_path("../..", __FILE__)
end
def resource(name)
File.expand_path("../../dist/resources/#{name}", __FILE__)
end
def s3_connect
return if @s3_connected
require "aws/s3"
unless ENV["DAVID_RELEASE_ACCESS"] && ENV["DAVID_RELEASE_SECRET"]
puts "please set DAVID_RELEASE_ACCESS and DAVID_RELEASE_SECRET in your environment"
exit 1
end
AWS::S3::Base.establish_connection!(
:access_key_id => ENV["DAVID_RELEASE_ACCESS"],
:secret_access_key => ENV["DAVID_RELEASE_SECRET"]
)
@s3_connected = true
end
def store(package_file, filename, bucket="assets.foreman.io")
s3_connect
puts "storing: #{filename}"
AWS::S3::S3Object.store(filename, File.open(package_file), bucket, :access => :public_read)
end
def tempdir
Dir.mktmpdir do |dir|
Dir.chdir(dir) do
yield(dir)
end
end
end
def version
require "foreman/version"
Foreman::VERSION
end
Dir[File.expand_path("../../dist/**/*.rake", __FILE__)].each do |rake|
import rake
end

66
tasks/release.rake Normal file
View File

@@ -0,0 +1,66 @@
require "time"
desc "Build the manual"
task :man do
ENV['RONN_MANUAL'] = "Foreman Manual"
ENV['RONN_ORGANIZATION'] = "Foreman #{Foreman::VERSION}"
sh "ronn -w -s toc -r5 --markdown man/*.ronn"
end
desc "Commit the manual to git"
task "man:commit" => :man do
sh "git add README.md"
sh "git commit -am 'update docs' || echo 'nothing to commit'"
end
desc "Generate the Github docs"
task :pages => "man:commit" do
sh %{
cp man/foreman.1.html /tmp/foreman.1.html
git checkout gh-pages
rm ./index.html
cp /tmp/foreman.1.html ./index.html
git add -u index.html
git commit -m "saving man page to github docs"
git push origin -f gh-pages
git checkout master
}
end
def latest_release
latest = File.read("Changelog.md").split("\n").first.split(" ")[1]
end
def newer_release
tags = %x{ git tag --contains v#{latest_release} }.split("\n").sort_by do |tag|
Gem::Version.new(tag[1..-1])
end
tags.reject { |tag| Gem::Version.new(tag[1..-1]).prerelease? }[1]
end
desc "Generate a Changelog"
task :changelog do
while release = newer_release
entry = %x{ git show --format="%cd" #{release} | head -n 1 }
date = Time.parse(entry.chomp).strftime("%Y-%m-%d")
message = "## #{release[1..-1]} (#{date})\n\n"
message += %x{ git log --format="* %s [%an]" v#{latest_release}..#{release} }
changelog = File.read("Changelog.md")
changelog = message + "\n" + changelog
puts release
File.open("Changelog.md", "w") do |file|
file.print changelog
end
end
end
desc "Cut a release"
task :release do
Rake::Task["authors"].invoke
Rake::Task["changelog"].invoke
Rake::Task["pages"].invoke
end

8
tasks/rspec.rake Normal file
View File

@@ -0,0 +1,8 @@
require "rspec/core/rake_task"
task :default => :spec
desc "Run all specs"
RSpec::Core::RakeTask.new(:spec) do |t|
t.pattern = 'spec/**/*_spec.rb'
end