islo 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.
checksums.yaml ADDED
@@ -0,0 +1,7 @@
1
+ ---
2
+ SHA1:
3
+ metadata.gz: b73d49fca1c9bbc70e94c8127f312cfa7710d435
4
+ data.tar.gz: 61ab656bc1d910a4d59036e0dd13add441a2da3b
5
+ SHA512:
6
+ metadata.gz: 016bb45985d99b0814010a4719aa124701d4675c4c2ef74098150a32ae13ff4c628eb677cdb9908a1b5577d9c86c38116a77a02b73079e05fb8f81cb99f07fcf
7
+ data.tar.gz: d60f682ee982622d098294b0052efec9554f398b12ab136ab4237c7f2d8617eff6d907da1d023eb48a23e4229e445434761a5ec3801f003920c8de3fb9ecf61b
data/.gitignore ADDED
@@ -0,0 +1,2 @@
1
+ *.gem
2
+ Gemfile.lock
data/Gemfile ADDED
@@ -0,0 +1,3 @@
1
+ source 'https://rubygems.org'
2
+
3
+ gemspec
data/LICENSE ADDED
@@ -0,0 +1,20 @@
1
+ Copyright (c) 2014 Loic Nageleisen
2
+
3
+ Permission is hereby granted, free of charge, to any person obtaining
4
+ a copy of this software and associated documentation files (the
5
+ "Software"), to deal in the Software without restriction, including
6
+ without limitation the rights to use, copy, modify, merge, publish,
7
+ distribute, sublicense, and/or sell copies of the Software, and to
8
+ permit persons to whom the Software is furnished to do so, subject to
9
+ the following conditions:
10
+
11
+ The above copyright notice and this permission notice shall be
12
+ included in all copies or substantial portions of the Software.
13
+
14
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
15
+ EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
16
+ MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
17
+ NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
18
+ LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
19
+ OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
20
+ WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
data/README.md ADDED
@@ -0,0 +1,74 @@
1
+ # Islo - Self-contained apps
2
+
3
+ Make apps completely self-contained by abstracting service process settings and execution.
4
+
5
+ ## Quick, show me how to use my favorite daemon!
6
+
7
+ First, install Islo:
8
+
9
+ ```
10
+ $ gem install islo
11
+ ```
12
+
13
+ Then, a nice example might be worth a thousand words, so here goes:
14
+
15
+ ### MySQL or MariaDB
16
+
17
+ ```
18
+ $ islo mysql_install_db # creates database in db/mysql
19
+ $ islo mysqld # starts server without daemonizing[^1]
20
+ $ islo mysql # connects to running server via unix socket in tmp/sockets
21
+ ```
22
+
23
+ ### Redis
24
+
25
+ ```
26
+ $ islo redis-init # creates directory in db/redis
27
+ $ islo redis-server # starts server without daemonizing[^1]
28
+ $ islo redis-cli # connects to server via unix socket in tmp/sockets
29
+ ```
30
+
31
+ ### PostgreSQL
32
+
33
+ ```
34
+ $ islo initdb # creates directory in db/postgres
35
+ $ islo postgres # starts server without daemonizing[^1]
36
+ $ islo psql # connects to server via unix socket in tmp/sockets
37
+ ```
38
+
39
+ [^1]: Best used in a [Procfile](https://github.com/ddollar/foreman)
40
+
41
+ ## What's more to know?
42
+
43
+ - Additional arguments are passed to the command.
44
+
45
+ Run `islo --help` for details.
46
+
47
+ - Servers will listen only on unix sockets, TCP will be disabled.
48
+
49
+ This saves headaches when you have to handle multiple projects, and thus
50
+ conflicting ports. Also, it's too easy to forget not to listen for the world.
51
+
52
+ ## My service is installed in a non-standard location/I want to use different versions in different projects
53
+
54
+ Configuration is a pending item, which will make locations selectable.
55
+
56
+ ## I don't like how it assumes a Rails project layout
57
+
58
+ Configuration is a pending item, which will help set relevant paths.
59
+
60
+ ## I've got a super service you don't seem to know about
61
+
62
+ Some configuration may help you soon. Also, contributions are welcome.
63
+
64
+ ## I can't be bothered/always forget to type *islo* before my commands every single time!
65
+
66
+ Look soon enough under `support` for a few optional helpers for your favorite shell.
67
+
68
+ ## I want to contribute. How?
69
+
70
+ Great! Write specs, have them all pass, respect rubocop, rebase on master and make your PR.
71
+
72
+ ## License
73
+
74
+ MIT, see [LICENSE](LICENSE).
data/Rakefile ADDED
File without changes
data/bin/islo ADDED
@@ -0,0 +1,5 @@
1
+ #!/usr/bin/env ruby
2
+
3
+ require 'islo/cli'
4
+
5
+ Islo::CLI.start
data/islo.gemspec ADDED
@@ -0,0 +1,29 @@
1
+ # -*- encoding: utf-8 -*-
2
+ $LOAD_PATH.push File.expand_path('../lib', __FILE__)
3
+ require 'islo/version'
4
+
5
+ Gem::Specification.new do |s|
6
+ s.name = 'islo'
7
+ s.version = Islo::VERSION
8
+ s.authors = ['Loic Nageleisen']
9
+ s.email = ['loic.nageleisen@gmail.com']
10
+ s.homepage = 'http://github.com/lloeki/islo'
11
+ s.summary = %q(Self-contained apps)
12
+ s.description = <<-EOT
13
+ Makes app completely self-contained by abstracting
14
+ service process settings and execution
15
+ EOT
16
+ s.license = 'MIT'
17
+ s.files = `git ls-files`.split("\n")
18
+ s.test_files = `git ls-files -- {test,spec,features}/*`.split("\n")
19
+ s.executables = `git ls-files -- bin/*`.split("\n")
20
+ .map { |f| File.basename(f) }
21
+ s.require_paths = ['lib']
22
+
23
+ s.add_dependency 'rainbow', '~> 2.0'
24
+ s.add_dependency 'slop'
25
+
26
+ s.add_development_dependency 'rspec', '~> 2.14'
27
+ s.add_development_dependency 'rake', '~> 10.3'
28
+ s.add_development_dependency 'pry'
29
+ end
data/lib/islo.rb ADDED
@@ -0,0 +1,21 @@
1
+ # Islo - application isolator
2
+ module Islo
3
+ class << self
4
+ def commands
5
+ @commands ||= {}
6
+ end
7
+
8
+ def register(command)
9
+ commands[command.name.to_sym] = command
10
+ end
11
+
12
+ def command(args, options = {})
13
+ name = File.basename(args[0]).to_sym
14
+ (commands[name] || Command).new(args, options)
15
+ end
16
+ end
17
+ end
18
+
19
+ [:mysql, :postgres, :redis].each do |c|
20
+ require "islo/commands/#{c}"
21
+ end
data/lib/islo/cli.rb ADDED
@@ -0,0 +1,91 @@
1
+ require 'slop'
2
+ require 'islo'
3
+ require 'rainbow/ext/string'
4
+
5
+ module Islo
6
+ # Handle and run the command line interface
7
+ class CLI
8
+ NAME = File.basename($PROGRAM_NAME)
9
+
10
+ # See sysexits(3)
11
+ RC = { ok: 0,
12
+ error: 1,
13
+ usage: 64,
14
+ data: 65,
15
+ noinput: 66,
16
+ nouser: 67,
17
+ nohost: 68,
18
+ unavailable: 69,
19
+ software: 70,
20
+ oserr: 71,
21
+ osfile: 72,
22
+ cantcreat: 73,
23
+ ioerr: 74,
24
+ tempfail: 75,
25
+ protocol: 76,
26
+ noperm: 77,
27
+ config: 78 }
28
+
29
+ # Shortcut for Islo::CLI.new.start
30
+ def self.start
31
+ new.start
32
+ end
33
+
34
+ attr_reader :args
35
+
36
+ def opts
37
+ @opts.to_hash
38
+ end
39
+
40
+ def initialize(args = ARGV)
41
+ @args, @opts = parse(args)
42
+ rescue Slop::InvalidOptionError => e
43
+ die(:usage, e.message)
44
+ rescue Slop::MissingArgumentError => e
45
+ die(:usage, e.message)
46
+ end
47
+
48
+ # Start execution based on options
49
+ def start
50
+ Islo.command(args, title: opts[:title]).exec
51
+ rescue Islo::Command::Error => e
52
+ die(:oserr, e.message)
53
+ end
54
+
55
+ private
56
+
57
+ # Stop with a popping message and exit with a return code
58
+ def die(rc, message)
59
+ $stderr.puts('Error: '.color(:red) << message)
60
+ exit(rc.is_a?(Symbol) ? RC[rc] : rc)
61
+ end
62
+
63
+ # Stop with a nice message
64
+ def bye(message)
65
+ $stdout.puts message
66
+ exit
67
+ end
68
+
69
+ def version_string
70
+ "#{NAME} v#{Islo::VERSION}"
71
+ end
72
+
73
+ # Parse arguments and set options
74
+ # rubocop:disable MethodLength
75
+ def parse(args)
76
+ args = args.dup
77
+
78
+ opts = Slop.parse!(args, strict: true, help: true) do
79
+ banner "Usage: #{NAME} [options] [--] command arguments"
80
+
81
+ on 't', 'title=', 'String displayed in process list', argument: true
82
+ on 'd', 'directory=', 'Change working directory', argument: true
83
+ on 'v', 'version', 'Print the version', -> { bye(version_string) }
84
+ end
85
+
86
+ fail Slop::MissingArgumentError, 'missing an argument' if args.empty?
87
+
88
+ [args, opts]
89
+ end
90
+ end
91
+ end
@@ -0,0 +1,36 @@
1
+ module Islo
2
+ # Generic command execution
3
+ class Command
4
+ class Error < StandardError; end
5
+
6
+ attr_reader :title, :wd
7
+ attr_reader :command, :args
8
+
9
+ def initialize(args, title: nil, wd: nil)
10
+ @command = args.shift
11
+ @args = args
12
+ @title = title unless title.nil? || title.empty?
13
+ @wd = Pathname.new(wd || Dir.pwd)
14
+ end
15
+
16
+ def title?
17
+ !title.nil?
18
+ end
19
+
20
+ def exec
21
+ Dir.chdir(wd.to_s)
22
+ Kernel.exec(*args_for_exec)
23
+ rescue SystemCallError => e
24
+ raise Command::Error, e.message
25
+ end
26
+
27
+ private
28
+
29
+ def args_for_exec
30
+ command = (title? ? [@command, title] : @command)
31
+ args = self.args
32
+
33
+ [command] + args
34
+ end
35
+ end
36
+ end
@@ -0,0 +1,70 @@
1
+ require 'islo/command'
2
+
3
+ module Islo
4
+ # MySQL support
5
+ module Mysql
6
+ # MySQL client
7
+ class Client < Command
8
+ def self.name
9
+ :mysql
10
+ end
11
+
12
+ def args
13
+ %W(
14
+ --socket=#{wd}/tmp/sockets/mysql.sock
15
+ -uroot
16
+ ) + super
17
+ end
18
+
19
+ Islo.register(self)
20
+ end
21
+
22
+ # MySQL server
23
+ class Server < Command
24
+ def self.name
25
+ :mysqld
26
+ end
27
+
28
+ def args
29
+ %W(
30
+ --no-defaults
31
+ --datadir=#{wd}/db/mysql
32
+ --pid-file=#{wd}/tmp/pids/mysqld.pid
33
+ --socket=#{wd}/tmp/sockets/mysql.sock
34
+ --skip-networking
35
+ ) + super
36
+ end
37
+
38
+ Islo.register(self)
39
+ end
40
+
41
+ # MySQL initializer
42
+ class Init < Command
43
+ def self.name
44
+ :mysql_install_db
45
+ end
46
+
47
+ def args
48
+ %W(
49
+ --no-defaults
50
+ --basedir=#{Mysql.basedir}
51
+ --datadir=#{wd}/db/mysql
52
+ --pid-file=#{wd}/tmp/pids/mysqld.pid
53
+ ) + super
54
+ end
55
+
56
+ Islo.register(self)
57
+ end
58
+
59
+ def self.basedir
60
+ path = %x(which mysql)
61
+
62
+ fail Command::Error, 'could not find mysql' if path.empty?
63
+
64
+ path = File.dirname(path)
65
+ path = File.dirname(path)
66
+
67
+ path
68
+ end
69
+ end
70
+ end
@@ -0,0 +1,50 @@
1
+ require 'islo/command'
2
+
3
+ module Islo
4
+ # PostgreSQL support
5
+ module Postgres
6
+ # PostgreSQL client
7
+ class Client < Command
8
+ def self.name
9
+ :psql
10
+ end
11
+
12
+ def args
13
+ %W(--host=#{wd}/tmp/sockets) + super
14
+ end
15
+
16
+ Islo.register(self)
17
+ end
18
+
19
+ # PostgreSQL server
20
+ class Server < Command
21
+ def self.name
22
+ :postgres
23
+ end
24
+
25
+ def args
26
+ %W(
27
+ -D #{wd}/db/postgres
28
+ -k #{wd}/tmp/sockets
29
+ ) + ['-h', ''] + super
30
+ end
31
+
32
+ Islo.register(self)
33
+ end
34
+
35
+ # PostgreSQL initializer
36
+ class Init < Command
37
+ def self.name
38
+ :initdb
39
+ end
40
+
41
+ def args
42
+ %W(
43
+ -D #{wd}/db/postgres
44
+ ) + super
45
+ end
46
+
47
+ Islo.register(self)
48
+ end
49
+ end
50
+ end
@@ -0,0 +1,108 @@
1
+ require 'islo/command'
2
+
3
+ module Islo
4
+ # Redis support
5
+ module Redis
6
+ # Redis client
7
+ class Client < Command
8
+ def self.name
9
+ :'redis-cli'
10
+ end
11
+
12
+ def args
13
+ %w(-s redis.sock)
14
+ end
15
+
16
+ # Change working directory (makes for a nicer prompt)
17
+ def wd
18
+ super + 'tmp/sockets'
19
+ end
20
+
21
+ Islo.register(self)
22
+ end
23
+
24
+ # Redis server
25
+ class Server < Command
26
+ def self.name
27
+ :'redis-server'
28
+ end
29
+
30
+ def args
31
+ %W(#{wd}/db/redis/redis.conf)
32
+ end
33
+
34
+ Islo.register(self)
35
+ end
36
+
37
+ # Redis initializer
38
+ #
39
+ # Creates a minimal configuration because redis-server doesn't accept
40
+ # arguments allowing for paths to be set.
41
+ class Init < Command
42
+ def self.name
43
+ :'redis-init'
44
+ end
45
+
46
+ def exec
47
+ FileUtils.mkdir_p(wd + 'db/redis')
48
+
49
+ File.open(wd + 'db/redis/redis.conf', 'w') do |f|
50
+ f << template.gsub('${WORKING_DIR}', wd.to_s)
51
+ end
52
+ rescue SystemCallError => e
53
+ raise Command::Error, e.message
54
+ end
55
+
56
+ private
57
+
58
+ # rubocop:disable MethodLength,LineLength
59
+ def template
60
+ <<-EOT.gsub(/^ +/, '')
61
+ daemonize no
62
+ pidfile ${WORKING_DIR}/pids/redis.pid
63
+ port 0
64
+ bind 127.0.0.1
65
+ unixsocket ${WORKING_DIR}/tmp/sockets/redis.sock
66
+ unixsocketperm 700
67
+ timeout 0
68
+ tcp-keepalive 0
69
+ loglevel notice
70
+ databases 1
71
+ save 900 1
72
+ save 300 10
73
+ save 60 10000
74
+ stop-writes-on-bgsave-error yes
75
+ rdbcompression yes
76
+ rdbchecksum yes
77
+ dbfilename dump.rdb
78
+ dir ${WORKING_DIR}/db/redis
79
+ slave-serve-stale-data yes
80
+ slave-read-only yes
81
+ repl-disable-tcp-nodelay no
82
+ slave-priority 100
83
+ appendonly yes
84
+ appendfsync everysec
85
+ no-appendfsync-on-rewrite no
86
+ auto-aof-rewrite-percentage 100
87
+ auto-aof-rewrite-min-size 64mb
88
+ lua-time-limit 5000
89
+ slowlog-log-slower-than 10000
90
+ slowlog-max-len 128
91
+ hash-max-ziplist-entries 512
92
+ hash-max-ziplist-value 64
93
+ list-max-ziplist-entries 512
94
+ list-max-ziplist-value 64
95
+ set-max-intset-entries 512
96
+ zset-max-ziplist-entries 128
97
+ zset-max-ziplist-value 64
98
+ activerehashing yes
99
+ client-output-buffer-limit normal 0 0 0
100
+ client-output-buffer-limit slave 256mb 64mb 60
101
+ client-output-buffer-limit pubsub 32mb 8mb 60
102
+ EOT
103
+ end
104
+
105
+ Islo.register(self)
106
+ end
107
+ end
108
+ end
@@ -0,0 +1,3 @@
1
+ module Islo
2
+ VERSION = '0.1.0'
3
+ end
metadata ADDED
@@ -0,0 +1,131 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: islo
3
+ version: !ruby/object:Gem::Version
4
+ version: 0.1.0
5
+ platform: ruby
6
+ authors:
7
+ - Loic Nageleisen
8
+ autorequire:
9
+ bindir: bin
10
+ cert_chain: []
11
+ date: 2014-05-20 00:00:00.000000000 Z
12
+ dependencies:
13
+ - !ruby/object:Gem::Dependency
14
+ name: rainbow
15
+ requirement: !ruby/object:Gem::Requirement
16
+ requirements:
17
+ - - "~>"
18
+ - !ruby/object:Gem::Version
19
+ version: '2.0'
20
+ type: :runtime
21
+ prerelease: false
22
+ version_requirements: !ruby/object:Gem::Requirement
23
+ requirements:
24
+ - - "~>"
25
+ - !ruby/object:Gem::Version
26
+ version: '2.0'
27
+ - !ruby/object:Gem::Dependency
28
+ name: slop
29
+ requirement: !ruby/object:Gem::Requirement
30
+ requirements:
31
+ - - ">="
32
+ - !ruby/object:Gem::Version
33
+ version: '0'
34
+ type: :runtime
35
+ prerelease: false
36
+ version_requirements: !ruby/object:Gem::Requirement
37
+ requirements:
38
+ - - ">="
39
+ - !ruby/object:Gem::Version
40
+ version: '0'
41
+ - !ruby/object:Gem::Dependency
42
+ name: rspec
43
+ requirement: !ruby/object:Gem::Requirement
44
+ requirements:
45
+ - - "~>"
46
+ - !ruby/object:Gem::Version
47
+ version: '2.14'
48
+ type: :development
49
+ prerelease: false
50
+ version_requirements: !ruby/object:Gem::Requirement
51
+ requirements:
52
+ - - "~>"
53
+ - !ruby/object:Gem::Version
54
+ version: '2.14'
55
+ - !ruby/object:Gem::Dependency
56
+ name: rake
57
+ requirement: !ruby/object:Gem::Requirement
58
+ requirements:
59
+ - - "~>"
60
+ - !ruby/object:Gem::Version
61
+ version: '10.3'
62
+ type: :development
63
+ prerelease: false
64
+ version_requirements: !ruby/object:Gem::Requirement
65
+ requirements:
66
+ - - "~>"
67
+ - !ruby/object:Gem::Version
68
+ version: '10.3'
69
+ - !ruby/object:Gem::Dependency
70
+ name: pry
71
+ requirement: !ruby/object:Gem::Requirement
72
+ requirements:
73
+ - - ">="
74
+ - !ruby/object:Gem::Version
75
+ version: '0'
76
+ type: :development
77
+ prerelease: false
78
+ version_requirements: !ruby/object:Gem::Requirement
79
+ requirements:
80
+ - - ">="
81
+ - !ruby/object:Gem::Version
82
+ version: '0'
83
+ description: |2
84
+ Makes app completely self-contained by abstracting
85
+ service process settings and execution
86
+ email:
87
+ - loic.nageleisen@gmail.com
88
+ executables:
89
+ - islo
90
+ extensions: []
91
+ extra_rdoc_files: []
92
+ files:
93
+ - ".gitignore"
94
+ - Gemfile
95
+ - LICENSE
96
+ - README.md
97
+ - Rakefile
98
+ - bin/islo
99
+ - islo.gemspec
100
+ - lib/islo.rb
101
+ - lib/islo/cli.rb
102
+ - lib/islo/command.rb
103
+ - lib/islo/commands/mysql.rb
104
+ - lib/islo/commands/postgres.rb
105
+ - lib/islo/commands/redis.rb
106
+ - lib/islo/version.rb
107
+ homepage: http://github.com/lloeki/islo
108
+ licenses:
109
+ - MIT
110
+ metadata: {}
111
+ post_install_message:
112
+ rdoc_options: []
113
+ require_paths:
114
+ - lib
115
+ required_ruby_version: !ruby/object:Gem::Requirement
116
+ requirements:
117
+ - - ">="
118
+ - !ruby/object:Gem::Version
119
+ version: '0'
120
+ required_rubygems_version: !ruby/object:Gem::Requirement
121
+ requirements:
122
+ - - ">="
123
+ - !ruby/object:Gem::Version
124
+ version: '0'
125
+ requirements: []
126
+ rubyforge_project:
127
+ rubygems_version: 2.2.2
128
+ signing_key:
129
+ specification_version: 4
130
+ summary: Self-contained apps
131
+ test_files: []