brut 0.0.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- checksums.yaml +7 -0
- data/.gitignore +7 -0
- data/CODE_OF_CONDUCT.txt +99 -0
- data/Dockerfile.dx +32 -0
- data/Gemfile +6 -0
- data/Gemfile.lock +133 -0
- data/LICENSE.txt +370 -0
- data/README.md +21 -0
- data/Rakefile +1 -0
- data/bin/bin_kit.rb +39 -0
- data/bin/rake +27 -0
- data/bin/setup +145 -0
- data/brut.gemspec +60 -0
- data/docker-compose.dx.yml +16 -0
- data/dx/build +26 -0
- data/dx/docker-compose.env +22 -0
- data/dx/dx.sh.lib +24 -0
- data/dx/exec +58 -0
- data/dx/prune +19 -0
- data/dx/setupkit.sh.lib +144 -0
- data/dx/show-help-in-app-container-then-wait.sh +38 -0
- data/dx/start +30 -0
- data/dx/stop +23 -0
- data/lib/brut/back_end/action.rb +3 -0
- data/lib/brut/back_end/result.rb +46 -0
- data/lib/brut/back_end/seed_data.rb +24 -0
- data/lib/brut/back_end/validator.rb +3 -0
- data/lib/brut/back_end/validators/form_validator.rb +37 -0
- data/lib/brut/cli/app.rb +130 -0
- data/lib/brut/cli/app_runner.rb +219 -0
- data/lib/brut/cli/apps/build_assets.rb +123 -0
- data/lib/brut/cli/apps/db.rb +279 -0
- data/lib/brut/cli/apps/scaffold.rb +256 -0
- data/lib/brut/cli/apps/test.rb +200 -0
- data/lib/brut/cli/command.rb +130 -0
- data/lib/brut/cli/error.rb +12 -0
- data/lib/brut/cli/execution_results.rb +81 -0
- data/lib/brut/cli/executor.rb +37 -0
- data/lib/brut/cli/options.rb +46 -0
- data/lib/brut/cli/output.rb +30 -0
- data/lib/brut/cli.rb +24 -0
- data/lib/brut/factory_bot.rb +20 -0
- data/lib/brut/framework/app.rb +55 -0
- data/lib/brut/framework/config.rb +415 -0
- data/lib/brut/framework/container.rb +190 -0
- data/lib/brut/framework/errors/abstract_method.rb +9 -0
- data/lib/brut/framework/errors/bug.rb +14 -0
- data/lib/brut/framework/errors/not_found.rb +10 -0
- data/lib/brut/framework/errors.rb +14 -0
- data/lib/brut/framework/fussy_type_enforcement.rb +50 -0
- data/lib/brut/framework/mcp.rb +215 -0
- data/lib/brut/framework/project_environment.rb +18 -0
- data/lib/brut/framework.rb +13 -0
- data/lib/brut/front_end/asset_metadata.rb +76 -0
- data/lib/brut/front_end/component.rb +213 -0
- data/lib/brut/front_end/components/form_tag.rb +71 -0
- data/lib/brut/front_end/components/i18n_translations.rb +36 -0
- data/lib/brut/front_end/components/input.rb +13 -0
- data/lib/brut/front_end/components/inputs/csrf_token.rb +8 -0
- data/lib/brut/front_end/components/inputs/select.rb +100 -0
- data/lib/brut/front_end/components/inputs/text_field.rb +63 -0
- data/lib/brut/front_end/components/inputs/textarea.rb +51 -0
- data/lib/brut/front_end/components/locale_detection.rb +25 -0
- data/lib/brut/front_end/components/page_identifier.rb +13 -0
- data/lib/brut/front_end/components/timestamp.rb +33 -0
- data/lib/brut/front_end/download.rb +23 -0
- data/lib/brut/front_end/flash.rb +57 -0
- data/lib/brut/front_end/form.rb +171 -0
- data/lib/brut/front_end/forms/constraint_violation.rb +39 -0
- data/lib/brut/front_end/forms/input.rb +119 -0
- data/lib/brut/front_end/forms/input_definition.rb +100 -0
- data/lib/brut/front_end/forms/validity_state.rb +36 -0
- data/lib/brut/front_end/handler.rb +48 -0
- data/lib/brut/front_end/handlers/csp_reporting_handler.rb +11 -0
- data/lib/brut/front_end/handlers/locale_detection_handler.rb +22 -0
- data/lib/brut/front_end/handling_results.rb +14 -0
- data/lib/brut/front_end/http_method.rb +33 -0
- data/lib/brut/front_end/http_status.rb +16 -0
- data/lib/brut/front_end/middleware.rb +7 -0
- data/lib/brut/front_end/middlewares/reload_app.rb +31 -0
- data/lib/brut/front_end/page.rb +47 -0
- data/lib/brut/front_end/request_context.rb +82 -0
- data/lib/brut/front_end/route_hook.rb +15 -0
- data/lib/brut/front_end/route_hooks/age_flash.rb +8 -0
- data/lib/brut/front_end/route_hooks/csp_no_inline_scripts.rb +17 -0
- data/lib/brut/front_end/route_hooks/csp_no_inline_styles_or_scripts.rb +46 -0
- data/lib/brut/front_end/route_hooks/locale_detection.rb +24 -0
- data/lib/brut/front_end/route_hooks/setup_request_context.rb +11 -0
- data/lib/brut/front_end/routing.rb +236 -0
- data/lib/brut/front_end/session.rb +56 -0
- data/lib/brut/front_end/template.rb +32 -0
- data/lib/brut/front_end/templates/block_filter.rb +60 -0
- data/lib/brut/front_end/templates/erb_engine.rb +26 -0
- data/lib/brut/front_end/templates/erb_parser.rb +84 -0
- data/lib/brut/front_end/templates/escapable_filter.rb +18 -0
- data/lib/brut/front_end/templates/html_safe_string.rb +40 -0
- data/lib/brut/i18n/base_methods.rb +168 -0
- data/lib/brut/i18n/for_cli.rb +4 -0
- data/lib/brut/i18n/for_html.rb +4 -0
- data/lib/brut/i18n/http_accept_language.rb +68 -0
- data/lib/brut/i18n.rb +6 -0
- data/lib/brut/instrumentation/basic.rb +66 -0
- data/lib/brut/instrumentation/event.rb +19 -0
- data/lib/brut/instrumentation/http_event.rb +5 -0
- data/lib/brut/instrumentation/subscriber.rb +41 -0
- data/lib/brut/instrumentation.rb +11 -0
- data/lib/brut/junk_drawer.rb +88 -0
- data/lib/brut/sinatra_helpers.rb +183 -0
- data/lib/brut/spec_support/component_support.rb +49 -0
- data/lib/brut/spec_support/flash_support.rb +7 -0
- data/lib/brut/spec_support/general_support.rb +18 -0
- data/lib/brut/spec_support/handler_support.rb +7 -0
- data/lib/brut/spec_support/matcher.rb +9 -0
- data/lib/brut/spec_support/matchers/be_a_bug.rb +14 -0
- data/lib/brut/spec_support/matchers/be_page_for.rb +14 -0
- data/lib/brut/spec_support/matchers/be_routing_for.rb +11 -0
- data/lib/brut/spec_support/matchers/have_constraint_violation.rb +56 -0
- data/lib/brut/spec_support/matchers/have_html_attribute.rb +69 -0
- data/lib/brut/spec_support/matchers/have_rendered.rb +20 -0
- data/lib/brut/spec_support/matchers/have_returned_http_status.rb +27 -0
- data/lib/brut/spec_support/session_support.rb +3 -0
- data/lib/brut/spec_support.rb +12 -0
- data/lib/brut/version.rb +3 -0
- data/lib/brut.rb +38 -0
- data/lib/sequel/extensions/brut_instrumentation.rb +37 -0
- data/lib/sequel/extensions/brut_migrations.rb +98 -0
- data/lib/sequel/plugins/created_at.rb +14 -0
- data/lib/sequel/plugins/external_id.rb +45 -0
- data/lib/sequel/plugins/find_bang.rb +13 -0
- data/lib/sequel/plugins.rb +3 -0
- metadata +484 -0
data/bin/bin_kit.rb
ADDED
|
@@ -0,0 +1,39 @@
|
|
|
1
|
+
require "pathname"
|
|
2
|
+
require "fileutils"
|
|
3
|
+
require "open3"
|
|
4
|
+
|
|
5
|
+
# We don't want the setup method to have to do all this error
|
|
6
|
+
# checking, and we also want to explicitly log what we are
|
|
7
|
+
# executing. Thus, we use this method instead of Kernel#system
|
|
8
|
+
def system!(*args)
|
|
9
|
+
if ENV["BRUT_BIN_KIT_DEBUG"] == "true"
|
|
10
|
+
log "Executing #{args}"
|
|
11
|
+
out,err,status = Open3.capture3(*args)
|
|
12
|
+
if status.success?
|
|
13
|
+
log "#{args} succeeded"
|
|
14
|
+
else
|
|
15
|
+
log "#{args} failed"
|
|
16
|
+
log "STDOUT:"
|
|
17
|
+
$stdout.puts out
|
|
18
|
+
log "STDERR:"
|
|
19
|
+
$stderr.puts err
|
|
20
|
+
abort
|
|
21
|
+
end
|
|
22
|
+
else
|
|
23
|
+
log "Executing #{args}"
|
|
24
|
+
if system(*args)
|
|
25
|
+
log "#{args} succeeded"
|
|
26
|
+
else
|
|
27
|
+
log "#{args} failed"
|
|
28
|
+
abort
|
|
29
|
+
end
|
|
30
|
+
end
|
|
31
|
+
end
|
|
32
|
+
|
|
33
|
+
# It's helpful to know what messages came from this
|
|
34
|
+
# script, so we'll use log instead of `puts`
|
|
35
|
+
def log(message)
|
|
36
|
+
puts "[ #{$0} ] #{message}"
|
|
37
|
+
end
|
|
38
|
+
|
|
39
|
+
ROOT_DIR = ((Pathname(__dir__) / ".." ).expand_path)
|
data/bin/rake
ADDED
|
@@ -0,0 +1,27 @@
|
|
|
1
|
+
#!/usr/bin/env ruby
|
|
2
|
+
# frozen_string_literal: true
|
|
3
|
+
|
|
4
|
+
#
|
|
5
|
+
# This file was generated by Bundler.
|
|
6
|
+
#
|
|
7
|
+
# The application 'rake' is installed as part of a gem, and
|
|
8
|
+
# this file is here to facilitate running it.
|
|
9
|
+
#
|
|
10
|
+
|
|
11
|
+
ENV["BUNDLE_GEMFILE"] ||= File.expand_path("../Gemfile", __dir__)
|
|
12
|
+
|
|
13
|
+
bundle_binstub = File.expand_path("bundle", __dir__)
|
|
14
|
+
|
|
15
|
+
if File.file?(bundle_binstub)
|
|
16
|
+
if File.read(bundle_binstub, 300).include?("This file was generated by Bundler")
|
|
17
|
+
load(bundle_binstub)
|
|
18
|
+
else
|
|
19
|
+
abort("Your `bin/bundle` was not generated by Bundler, so this binstub cannot run.
|
|
20
|
+
Replace `bin/bundle` by running `bundle binstubs bundler --force`, then run this command again.")
|
|
21
|
+
end
|
|
22
|
+
end
|
|
23
|
+
|
|
24
|
+
require "rubygems"
|
|
25
|
+
require "bundler/setup"
|
|
26
|
+
|
|
27
|
+
load Gem.bin_path("rake", "rake")
|
data/bin/setup
ADDED
|
@@ -0,0 +1,145 @@
|
|
|
1
|
+
#!/usr/bin/env ruby
|
|
2
|
+
|
|
3
|
+
require_relative "bin_kit"
|
|
4
|
+
require "optparse"
|
|
5
|
+
require "pathname"
|
|
6
|
+
require "fileutils"
|
|
7
|
+
|
|
8
|
+
def setup(update_gems:,setup_credentials:)
|
|
9
|
+
if update_gems
|
|
10
|
+
log "Updating gems"
|
|
11
|
+
system! "bundle update"
|
|
12
|
+
else
|
|
13
|
+
log "Installing gems"
|
|
14
|
+
# Only do bundle install if the much-faster
|
|
15
|
+
# bundle check indicates we need to
|
|
16
|
+
system! "bundle check --no-color || bundle install --no-color --quiet"
|
|
17
|
+
end
|
|
18
|
+
|
|
19
|
+
if setup_credentials
|
|
20
|
+
project_root = Pathname($0).dirname / ".."
|
|
21
|
+
credentials_dir = project_root / "dx" / "credentials"
|
|
22
|
+
if credentials_dir.exist?
|
|
23
|
+
if credentials_dir.directory?
|
|
24
|
+
log "#{credentials_dir} exists"
|
|
25
|
+
else
|
|
26
|
+
log "#{credentials_dir} is not a directory - please delete it or move it elsewhere and re-run this script"
|
|
27
|
+
exit 1
|
|
28
|
+
end
|
|
29
|
+
else
|
|
30
|
+
log "#{credentials_dir} doesn't exist - creating"
|
|
31
|
+
FileUtils.mkdir_p credentials_dir
|
|
32
|
+
end
|
|
33
|
+
|
|
34
|
+
# https://docs.github.com/en/authentication/connecting-to-github-with-ssh/generating-a-new-ssh-key-and-adding-it-to-the-ssh-agent?platform=linux
|
|
35
|
+
key_file = credentials_dir / "id_ed25519"
|
|
36
|
+
|
|
37
|
+
if key_file.exist?
|
|
38
|
+
log "#{key_file} exists already"
|
|
39
|
+
else
|
|
40
|
+
git_config_command = "git config --get user.email"
|
|
41
|
+
email = `#{git_config_command}`.chomp
|
|
42
|
+
if !$?.success?
|
|
43
|
+
log "Could not determine your email via #{git_config_command} - is your git set up properly?"
|
|
44
|
+
exit 1
|
|
45
|
+
end
|
|
46
|
+
log "Creating your key in #{key_file} using email #{email}."
|
|
47
|
+
log "You will be prompted for a passphrase, which you are encouraged to provide"
|
|
48
|
+
system! "ssh-keygen -t ed25519 -C #{email} -f \"#{key_file}\""
|
|
49
|
+
log ""
|
|
50
|
+
log "You must now add this to your GitHub profile in order to perform Git commands"
|
|
51
|
+
log ""
|
|
52
|
+
log "The key you just generated has a public key that should be available on your computer at"
|
|
53
|
+
log ""
|
|
54
|
+
log " #{key_file.relative_path_from(project_root)}.pub"
|
|
55
|
+
log ""
|
|
56
|
+
log "Copy its contents and head to:"
|
|
57
|
+
log ""
|
|
58
|
+
log " https://github.com/settings/keys"
|
|
59
|
+
log ""
|
|
60
|
+
log "Click 'New SSH key' and paste your key in, giving it a name like 'Brut Dev Env'"
|
|
61
|
+
log ""
|
|
62
|
+
log "(if this doesn't look right, check https://docs.github.com/en/authentication/connecting-to-github-with-ssh/adding-a-new-ssh-key-to-your-github-account)"
|
|
63
|
+
log ""
|
|
64
|
+
log "Hit return when done"
|
|
65
|
+
x = gets
|
|
66
|
+
end
|
|
67
|
+
|
|
68
|
+
log "Adding your SSH key to ssh-agent - you must provide your passphrase"
|
|
69
|
+
system! "ssh-add #{key_file}"
|
|
70
|
+
|
|
71
|
+
known_hosts_dest = Pathname("/") / "root" / ".ssh" / "known_hosts"
|
|
72
|
+
if known_hosts_dest.exist?
|
|
73
|
+
log "#{known_hosts_dest} exists, your ssh key should work with GitHub"
|
|
74
|
+
else
|
|
75
|
+
log "#{known_hosts_dest} does not exist"
|
|
76
|
+
known_hosts_source = credentials_dir / "known_hosts"
|
|
77
|
+
if known_hosts_source.exist?
|
|
78
|
+
log "#{known_hosts_source} exists - copying it to #{known_hosts_dest}"
|
|
79
|
+
FileUtils.mkdir_p known_hosts_dest.dirname
|
|
80
|
+
FileUtils.chmod(0700,known_hosts_dest.dirname)
|
|
81
|
+
FileUtils.cp known_hosts_source, known_hosts_dest
|
|
82
|
+
FileUtils.chmod(0600,known_hosts_dest)
|
|
83
|
+
else
|
|
84
|
+
log "#{known_hosts_source} also does not exist. To create it, we'll connect to github.com"
|
|
85
|
+
log "NOTE: it will show you a fingerprint to verify authenticity. You should check it against:"
|
|
86
|
+
log ""
|
|
87
|
+
log " https://docs.github.com/en/authentication/keeping-your-account-and-data-secure/githubs-ssh-key-fingerprints"
|
|
88
|
+
log ""
|
|
89
|
+
log " and proceed ONLY if the values match"
|
|
90
|
+
log ""
|
|
91
|
+
system("ssh -T git@github.com") # NOT system! because this may exit nonzero but still have succeeded
|
|
92
|
+
if $?.exitstatus == 255
|
|
93
|
+
log "SOMETHING MAY HAVE GONE WRONG!"
|
|
94
|
+
end
|
|
95
|
+
if known_hosts_dest.exist?
|
|
96
|
+
log "Copying #{known_hosts_dest} back to #{known_hosts_source} to use in the future"
|
|
97
|
+
FileUtils.cp known_hosts_dest,known_hosts_source
|
|
98
|
+
else
|
|
99
|
+
log "For some reason #{known_hosts_dest} was not created. Future ssh commands may ask you to verify GitHub's fingerprint"
|
|
100
|
+
end
|
|
101
|
+
end
|
|
102
|
+
end
|
|
103
|
+
log "Your ssh key looks good"
|
|
104
|
+
|
|
105
|
+
gem_credentials_dest = Pathname("/") / "root" / ".gem" / "credentials"
|
|
106
|
+
if gem_credentials_dest.exist?
|
|
107
|
+
log "Gem credentials look good"
|
|
108
|
+
else
|
|
109
|
+
log "#{gem_credentials_dest} doesn't exist - creating"
|
|
110
|
+
FileUtils.mkdir_p gem_credentials_dest.dirname
|
|
111
|
+
gem_credentials_source = credentials_dir / "rubygems.credentials"
|
|
112
|
+
if gem_credentials_source.exist?
|
|
113
|
+
log "#{gem_credentials_source} exists - copying it to #{gem_credentials_dest}"
|
|
114
|
+
FileUtils.cp gem_credentials_source,gem_credentials_dest
|
|
115
|
+
else
|
|
116
|
+
log "#{gem_credentials_source} must contain a RubyGems credentials file"
|
|
117
|
+
log ""
|
|
118
|
+
log "Follow the instructions here:"
|
|
119
|
+
log ""
|
|
120
|
+
log " https://guides.rubygems.org/api-key-scopes/#creating-from-gem-cli"
|
|
121
|
+
log ""
|
|
122
|
+
log "Then copy ~/.gem/credentials into #{gem_credentials_source} and re-run this script"
|
|
123
|
+
exit 1
|
|
124
|
+
end
|
|
125
|
+
end
|
|
126
|
+
else
|
|
127
|
+
log "Not setting up GitHub or RubyGems credentials. You won't be able to push the gem"
|
|
128
|
+
end
|
|
129
|
+
end
|
|
130
|
+
|
|
131
|
+
|
|
132
|
+
options = {
|
|
133
|
+
update_gems: false,
|
|
134
|
+
setup_credentials: true,
|
|
135
|
+
}
|
|
136
|
+
OptionParser.new do |opts|
|
|
137
|
+
opts.on("--update-gems","Update gems get the latest versions consistent with Gemfile / gemspec.") do
|
|
138
|
+
options[:update_gems] = true
|
|
139
|
+
end
|
|
140
|
+
opts.on("--no-credentials","If set, no GitHub or RubyGems credentials are required, but you can't push gems") do
|
|
141
|
+
options[:setup_credentials] = false
|
|
142
|
+
end
|
|
143
|
+
end.parse!
|
|
144
|
+
|
|
145
|
+
setup(**options)
|
data/brut.gemspec
ADDED
|
@@ -0,0 +1,60 @@
|
|
|
1
|
+
lib = File.expand_path("../lib", __FILE__)
|
|
2
|
+
$LOAD_PATH.unshift(lib) unless $LOAD_PATH.include?(lib)
|
|
3
|
+
require "brut/version"
|
|
4
|
+
|
|
5
|
+
Gem::Specification.new do |spec|
|
|
6
|
+
spec.name = "brut"
|
|
7
|
+
spec.version = Brut::VERSION
|
|
8
|
+
spec.authors = ["David Bryant Copeland"]
|
|
9
|
+
spec.email = ["davec@thirdtank.com"]
|
|
10
|
+
|
|
11
|
+
spec.summary = %q{NOT YET RELEASED - Web Framework Built around Ruby, Web Standards, Simplicity, and Object-Orientation}
|
|
12
|
+
spec.description = %q{NOT YET RELEASED - An opinionated web framework build on web standards}
|
|
13
|
+
spec.homepage = "https://naildrivin5.com"
|
|
14
|
+
|
|
15
|
+
# Prevent pushing this gem to RubyGems.org. To allow pushes either set the 'allowed_push_host'
|
|
16
|
+
# to allow pushing to a single host or delete this section to allow pushing to any host.
|
|
17
|
+
if spec.respond_to?(:metadata)
|
|
18
|
+
spec.metadata["allowed_push_host"] = "https://rubygems.org"
|
|
19
|
+
|
|
20
|
+
spec.metadata["homepage_uri"] = spec.homepage
|
|
21
|
+
spec.metadata["source_code_uri"] = "https://naildrivin5.com"
|
|
22
|
+
spec.metadata["changelog_uri"] = "https://naildrivin5.com"
|
|
23
|
+
else
|
|
24
|
+
raise "RubyGems 2.0 or newer is required to protect against " \
|
|
25
|
+
"public gem pushes."
|
|
26
|
+
end
|
|
27
|
+
|
|
28
|
+
# Specify which files should be added to the gem when it is released.
|
|
29
|
+
# The `git ls-files -z` loads the files in the RubyGem that have been added into git.
|
|
30
|
+
spec.files = Dir.chdir(File.expand_path('..', __FILE__)) do
|
|
31
|
+
`git ls-files -z`.split("\x0").reject { |f| f.match(%r{^(test|spec|features)/}) }
|
|
32
|
+
end
|
|
33
|
+
spec.bindir = "exe"
|
|
34
|
+
spec.executables = spec.files.grep(%r{^exe/}) { |f| File.basename(f) }
|
|
35
|
+
spec.require_paths = ["lib"]
|
|
36
|
+
|
|
37
|
+
spec.add_runtime_dependency "dotenv"
|
|
38
|
+
spec.add_runtime_dependency "ostruct" # squelch some warning - this is not used
|
|
39
|
+
spec.add_runtime_dependency "factory_bot"
|
|
40
|
+
spec.add_runtime_dependency "faker"
|
|
41
|
+
spec.add_runtime_dependency "i18n"
|
|
42
|
+
spec.add_runtime_dependency "nokogiri"
|
|
43
|
+
spec.add_runtime_dependency "prism"
|
|
44
|
+
spec.add_runtime_dependency "rack-protection"
|
|
45
|
+
spec.add_runtime_dependency "rackup"
|
|
46
|
+
spec.add_runtime_dependency "rexml"
|
|
47
|
+
spec.add_runtime_dependency "semantic_logger"
|
|
48
|
+
spec.add_runtime_dependency "sequel"
|
|
49
|
+
spec.add_runtime_dependency "sinatra"
|
|
50
|
+
spec.add_runtime_dependency "temple"
|
|
51
|
+
spec.add_runtime_dependency "tilt"
|
|
52
|
+
spec.add_runtime_dependency "tzinfo"
|
|
53
|
+
spec.add_runtime_dependency "tzinfo-data"
|
|
54
|
+
spec.add_runtime_dependency "zeitwerk"
|
|
55
|
+
|
|
56
|
+
spec.add_development_dependency "activesupport"
|
|
57
|
+
spec.add_development_dependency "rspec", "~> 3.0"
|
|
58
|
+
spec.add_development_dependency "bundler"
|
|
59
|
+
spec.add_development_dependency "rake"
|
|
60
|
+
end
|
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
services:
|
|
2
|
+
app:
|
|
3
|
+
image: ${IMAGE}
|
|
4
|
+
pull_policy: "missing"
|
|
5
|
+
init: true
|
|
6
|
+
volumes:
|
|
7
|
+
- type: bind
|
|
8
|
+
source: "./"
|
|
9
|
+
target: "/root/work"
|
|
10
|
+
consistency: "consistent"
|
|
11
|
+
- type: bind
|
|
12
|
+
source: ${GIT_CONFIG}
|
|
13
|
+
target: "/root/.gitconfig"
|
|
14
|
+
entrypoint: /root/show-help-in-app-container-then-wait.sh
|
|
15
|
+
working_dir: /root/work
|
|
16
|
+
|
data/dx/build
ADDED
|
@@ -0,0 +1,26 @@
|
|
|
1
|
+
#!/bin/bash
|
|
2
|
+
|
|
3
|
+
set -e
|
|
4
|
+
|
|
5
|
+
SCRIPT_DIR=$( cd -- "$( dirname -- "${0}" )" > /dev/null 2>&1 && pwd )
|
|
6
|
+
|
|
7
|
+
. "${SCRIPT_DIR}/dx.sh.lib"
|
|
8
|
+
|
|
9
|
+
require_command "docker"
|
|
10
|
+
load_docker_compose_env
|
|
11
|
+
|
|
12
|
+
usage_on_help "Builds the Docker image based on the Dockerfile" "" "build.pre" "build.post" "${@}"
|
|
13
|
+
|
|
14
|
+
exec_hook_if_exists "build.pre" Dockerfile.dx "${IMAGE}"
|
|
15
|
+
|
|
16
|
+
docker build \
|
|
17
|
+
--file Dockerfile.dx \
|
|
18
|
+
--tag "${IMAGE}" \
|
|
19
|
+
./
|
|
20
|
+
|
|
21
|
+
exec_hook_if_exists "build.post" Dockerfile.dx "${IMAGE}"
|
|
22
|
+
|
|
23
|
+
log "đ" "Your Docker image has been built tagged '${IMAGE}'"
|
|
24
|
+
log "đ" "You can now run dx/start to start it up, though you may need to stop it first with Ctrl-C"
|
|
25
|
+
|
|
26
|
+
# vim: ft=bash
|
|
@@ -0,0 +1,22 @@
|
|
|
1
|
+
# IMAGE is the name of the image to be built for running
|
|
2
|
+
# your app. The recommended format is ORG/REPO:TAG
|
|
3
|
+
#
|
|
4
|
+
# ORG - your org on GitHub or DockerHub
|
|
5
|
+
# REPO - the name of the repo on GitHub or the app name
|
|
6
|
+
# TAG - a version identifier. Recommend you avoid latest as this is confusing
|
|
7
|
+
IMAGE=thirdtank/brut-dev:ruby-3.3
|
|
8
|
+
|
|
9
|
+
# This is used to tell docker compose what the name
|
|
10
|
+
# of your project is for the purpose of naming
|
|
11
|
+
# containers. It can be anything and is mostly
|
|
12
|
+
# used for pruning containers via bin/prune
|
|
13
|
+
PROJECT_NAME=brut-dev
|
|
14
|
+
|
|
15
|
+
# Use this to override the service name for your
|
|
16
|
+
# app in docker-compose.dx.yml
|
|
17
|
+
DEFAULT_SERVICE=app
|
|
18
|
+
|
|
19
|
+
# Path to the git configuration to use
|
|
20
|
+
GIT_CONFIG=~/.gitconfig
|
|
21
|
+
|
|
22
|
+
# vim: ft=bash
|
data/dx/dx.sh.lib
ADDED
|
@@ -0,0 +1,24 @@
|
|
|
1
|
+
# shellcheck shell=bash
|
|
2
|
+
|
|
3
|
+
. "${SCRIPT_DIR}/setupkit.sh.lib"
|
|
4
|
+
|
|
5
|
+
require_command "realpath"
|
|
6
|
+
require_command "cat"
|
|
7
|
+
|
|
8
|
+
ENV_FILE=$(realpath "${SCRIPT_DIR}")/docker-compose.env
|
|
9
|
+
|
|
10
|
+
load_docker_compose_env() {
|
|
11
|
+
. "${ENV_FILE}"
|
|
12
|
+
}
|
|
13
|
+
|
|
14
|
+
exec_hook_if_exists() {
|
|
15
|
+
script_name=$1
|
|
16
|
+
shift
|
|
17
|
+
if [ -x "${SCRIPT_DIR}"/"${script_name}" ]; then
|
|
18
|
+
log "đĒ" "${script_name} exists - executing"
|
|
19
|
+
"${SCRIPT_DIR}"/"${script_name}" "${@}"
|
|
20
|
+
else
|
|
21
|
+
debug "${script_name} does not exist"
|
|
22
|
+
fi
|
|
23
|
+
}
|
|
24
|
+
# vim: ft=bash
|
data/dx/exec
ADDED
|
@@ -0,0 +1,58 @@
|
|
|
1
|
+
#!/bin/bash
|
|
2
|
+
|
|
3
|
+
set -e
|
|
4
|
+
|
|
5
|
+
SCRIPT_DIR=$( cd -- "$( dirname -- "${0}" )" > /dev/null 2>&1 && pwd )
|
|
6
|
+
|
|
7
|
+
. "${SCRIPT_DIR}/dx.sh.lib"
|
|
8
|
+
|
|
9
|
+
require_command "docker"
|
|
10
|
+
load_docker_compose_env
|
|
11
|
+
|
|
12
|
+
usage_description="Execute a command inside the app's container with ssh-agent active."
|
|
13
|
+
usage_args="[-s service] [-A] command"
|
|
14
|
+
usage_pre="exec.pre"
|
|
15
|
+
usage_on_help "${usage_description}" "${usage_args}" "${usage_pre}" "" "${@}"
|
|
16
|
+
|
|
17
|
+
SERVICE="${SERVICE_NAME:-${DEFAULT_SERVICE}}"
|
|
18
|
+
SSH_AGENT="ssh-agent "
|
|
19
|
+
while getopts "s:A" opt "${@}"; do
|
|
20
|
+
case ${opt} in
|
|
21
|
+
s )
|
|
22
|
+
SERVICE="${OPTARG}"
|
|
23
|
+
;;
|
|
24
|
+
A )
|
|
25
|
+
SSH_AGENT=""
|
|
26
|
+
;;
|
|
27
|
+
\? )
|
|
28
|
+
log "đ" "Unknown option: ${opt}"
|
|
29
|
+
usage "${description}" "${usage_args}" "${usage_pre}"
|
|
30
|
+
;;
|
|
31
|
+
: )
|
|
32
|
+
log "đ" "Invalid option: ${opt} requires an argument"
|
|
33
|
+
usage "${description}" "${usage_args}" "${usage_pre}"
|
|
34
|
+
;;
|
|
35
|
+
esac
|
|
36
|
+
done
|
|
37
|
+
shift $((OPTIND -1))
|
|
38
|
+
|
|
39
|
+
if [ $# -eq 0 ]; then
|
|
40
|
+
log "đ" "You must provide a command e.g. bash or ls -l"
|
|
41
|
+
usage "${description}" "${usage_args}" "${usage_pre}"
|
|
42
|
+
fi
|
|
43
|
+
|
|
44
|
+
|
|
45
|
+
exec_hook_if_exists "exec.pre"
|
|
46
|
+
|
|
47
|
+
log "đ" "Running '${*}' inside container with service name '${SERVICE}'"
|
|
48
|
+
|
|
49
|
+
docker \
|
|
50
|
+
compose \
|
|
51
|
+
--file docker-compose.dx.yaml \
|
|
52
|
+
--project-name "${PROJECT_NAME}" \
|
|
53
|
+
--env-file "${ENV_FILE}" \
|
|
54
|
+
exec \
|
|
55
|
+
"${SERVICE}" \
|
|
56
|
+
${SSH_AGENT} "${@}"
|
|
57
|
+
|
|
58
|
+
# vim: ft=bash
|
data/dx/prune
ADDED
|
@@ -0,0 +1,19 @@
|
|
|
1
|
+
#!/bin/bash
|
|
2
|
+
|
|
3
|
+
set -e
|
|
4
|
+
|
|
5
|
+
SCRIPT_DIR=$( cd -- "$( dirname -- "${0}" )" > /dev/null 2>&1 && pwd )
|
|
6
|
+
|
|
7
|
+
. "${SCRIPT_DIR}/dx.sh.lib"
|
|
8
|
+
require_command "docker"
|
|
9
|
+
load_docker_compose_env
|
|
10
|
+
|
|
11
|
+
usage_on_help "Prune containers for this repo" "" "" "" "${@}"
|
|
12
|
+
|
|
13
|
+
for container_id in $(docker container ls -a -f "name=^${PROJECT_NAME}-.*-1$" --format="{{.ID}}"); do
|
|
14
|
+
log "đ" "Removing container with id '${container_id}'"
|
|
15
|
+
docker container rm "${container_id}"
|
|
16
|
+
done
|
|
17
|
+
echo "đ§ŧ" "Containers removed"
|
|
18
|
+
|
|
19
|
+
# vim: ft=bash
|
data/dx/setupkit.sh.lib
ADDED
|
@@ -0,0 +1,144 @@
|
|
|
1
|
+
# shellcheck shell=bash
|
|
2
|
+
|
|
3
|
+
fatal() {
|
|
4
|
+
remainder=${*:2}
|
|
5
|
+
if [ -z "$remainder" ]; then
|
|
6
|
+
log "đ" "${@}"
|
|
7
|
+
else
|
|
8
|
+
log "${@}"
|
|
9
|
+
fi
|
|
10
|
+
exit 1
|
|
11
|
+
}
|
|
12
|
+
|
|
13
|
+
log() {
|
|
14
|
+
emoji=$1
|
|
15
|
+
remainder=${*:2}
|
|
16
|
+
if [ -z "${NO_EMOJI}" ]; then
|
|
17
|
+
echo "[ ${0} ] ${*}"
|
|
18
|
+
else
|
|
19
|
+
# if remainder is empty that means no emoji was passed
|
|
20
|
+
if [ -z "$remainder" ]; then
|
|
21
|
+
echo "[ ${0} ] ${*}"
|
|
22
|
+
else # emoji was passed, but we ignore it
|
|
23
|
+
echo "[ ${0} ] ${remainder}"
|
|
24
|
+
fi
|
|
25
|
+
fi
|
|
26
|
+
}
|
|
27
|
+
|
|
28
|
+
debug() {
|
|
29
|
+
message=$1
|
|
30
|
+
if [ -z "${DOCKBOX_DEBUG}" ]; then
|
|
31
|
+
return
|
|
32
|
+
fi
|
|
33
|
+
log "đ" "${message}"
|
|
34
|
+
}
|
|
35
|
+
|
|
36
|
+
usage() {
|
|
37
|
+
description=$1
|
|
38
|
+
arg_names=$2
|
|
39
|
+
pre_hook=$3
|
|
40
|
+
post_hook=$4
|
|
41
|
+
echo "usage: ${0} [-h] ${arg_names}"
|
|
42
|
+
if [ -n "${description}" ]; then
|
|
43
|
+
echo
|
|
44
|
+
echo "DESCRIPTION"
|
|
45
|
+
echo " ${description}"
|
|
46
|
+
fi
|
|
47
|
+
if [ -n "${pre_hook}" ] || [ -n "${post_hook}" ]; then
|
|
48
|
+
echo
|
|
49
|
+
echo "HOOKS"
|
|
50
|
+
if [ -n "${pre_hook}" ]; then
|
|
51
|
+
echo " ${pre_hook} - if present, called before the main action"
|
|
52
|
+
fi
|
|
53
|
+
if [ -n "${post_hook}" ]; then
|
|
54
|
+
echo " ${post_hook} - if present, called after the main action"
|
|
55
|
+
fi
|
|
56
|
+
fi
|
|
57
|
+
exit 0
|
|
58
|
+
}
|
|
59
|
+
|
|
60
|
+
usage_on_help() {
|
|
61
|
+
description=$1
|
|
62
|
+
arg_names=$2
|
|
63
|
+
pre_hook=$3
|
|
64
|
+
post_hook=$4
|
|
65
|
+
# These are the args passed to the invocation so this
|
|
66
|
+
# function can determine if the user requested help
|
|
67
|
+
cli_args=( "${@:5}" )
|
|
68
|
+
|
|
69
|
+
for arg in "${cli_args[@]}"; do
|
|
70
|
+
if [ "${arg}" = "-h" ] || [ "${arg}" = "--help" ]; then
|
|
71
|
+
usage "${description}" "${arg_names}" "${pre_hook}" "${post_hook}"
|
|
72
|
+
fi
|
|
73
|
+
done
|
|
74
|
+
}
|
|
75
|
+
|
|
76
|
+
# Read user input into the variable 'INPUT'
|
|
77
|
+
#
|
|
78
|
+
# Args:
|
|
79
|
+
#
|
|
80
|
+
# [1] - an emoji to use for messages
|
|
81
|
+
# [2] - the message explaining what input is being requested
|
|
82
|
+
# [3] - a default value to use if no value is provided
|
|
83
|
+
#
|
|
84
|
+
# Respects NO_EMOJI when outputing messages to the user
|
|
85
|
+
user_input() {
|
|
86
|
+
emoji=$1
|
|
87
|
+
message=$2
|
|
88
|
+
default=$3
|
|
89
|
+
prompt=$4
|
|
90
|
+
|
|
91
|
+
if [ -z "$message" ]; then
|
|
92
|
+
echo "user_input requires a message"
|
|
93
|
+
exit 1
|
|
94
|
+
fi
|
|
95
|
+
|
|
96
|
+
INPUT=
|
|
97
|
+
|
|
98
|
+
if [ -z "${prompt}" ]; then
|
|
99
|
+
prompt=$(log "${emoji}" "Value: ")
|
|
100
|
+
if [ -n "${default}" ]; then
|
|
101
|
+
prompt=$(log "${emoji}" "Value (or hit return to use '${default}'): ")
|
|
102
|
+
fi
|
|
103
|
+
fi
|
|
104
|
+
|
|
105
|
+
while [ -z "${INPUT}" ]; do
|
|
106
|
+
|
|
107
|
+
log "$emoji" "$message"
|
|
108
|
+
read -r -p "${prompt}" INPUT
|
|
109
|
+
if [ -z "$INPUT" ]; then
|
|
110
|
+
INPUT=$default
|
|
111
|
+
fi
|
|
112
|
+
if [ -z "$INPUT" ]; then
|
|
113
|
+
log "đļ", "You must provide a value"
|
|
114
|
+
fi
|
|
115
|
+
done
|
|
116
|
+
}
|
|
117
|
+
|
|
118
|
+
user_confirm() {
|
|
119
|
+
user_input "$1" "$2" "$3" "y/n> "
|
|
120
|
+
}
|
|
121
|
+
|
|
122
|
+
require_not_exist() {
|
|
123
|
+
file=$1
|
|
124
|
+
message=$2
|
|
125
|
+
if [ -e "${file}" ]; then
|
|
126
|
+
fatal "$message"
|
|
127
|
+
fi
|
|
128
|
+
}
|
|
129
|
+
require_exist() {
|
|
130
|
+
file=$1
|
|
131
|
+
message=$2
|
|
132
|
+
if [ ! -e "${file}" ]; then
|
|
133
|
+
fatal "$message"
|
|
134
|
+
fi
|
|
135
|
+
}
|
|
136
|
+
|
|
137
|
+
require_command() {
|
|
138
|
+
command_name=$1
|
|
139
|
+
if ! command -v "${command_name}" >/dev/null 2>&1; then
|
|
140
|
+
fatal "Command '${command_name}' not found - it is required for this script to run"
|
|
141
|
+
fi
|
|
142
|
+
}
|
|
143
|
+
|
|
144
|
+
# vim: ft=bash
|
|
@@ -0,0 +1,38 @@
|
|
|
1
|
+
#!/bin/bash
|
|
2
|
+
|
|
3
|
+
set -e
|
|
4
|
+
|
|
5
|
+
# Ideally, the message below is shown after everything starts up. We can't
|
|
6
|
+
# achieve this using healtchecks because the interval for a healtcheck is
|
|
7
|
+
# also an initial delay, and we don't really want to do healthchecks on
|
|
8
|
+
# our DB or Redis every 2 seconds. So, we sleep just a bit to let
|
|
9
|
+
# the other containers start up and vomit out their output first.
|
|
10
|
+
sleep 2
|
|
11
|
+
# Output some helpful messaging when invoking `dx/start` (which itself is
|
|
12
|
+
# a convenience script for `docker compose up`.
|
|
13
|
+
#
|
|
14
|
+
# Adding this to work around the mild inconvenience of the `app` container's
|
|
15
|
+
# entrypoint generating no output.
|
|
16
|
+
#
|
|
17
|
+
cat <<-'PROMPT'
|
|
18
|
+
|
|
19
|
+
|
|
20
|
+
|
|
21
|
+
đ Dev Environment Initialized! đ
|
|
22
|
+
|
|
23
|
+
âšī¸ To use this environment, open a new terminal and run
|
|
24
|
+
|
|
25
|
+
dx/exec bash
|
|
26
|
+
|
|
27
|
+
đš Use `ctrl-c` to exit.
|
|
28
|
+
|
|
29
|
+
|
|
30
|
+
|
|
31
|
+
PROMPT
|
|
32
|
+
|
|
33
|
+
# Using `sleep infinity` instead of `tail -f /dev/null`. This may be a
|
|
34
|
+
# performance improvement based on the conversation on a semi-related
|
|
35
|
+
# StackOverflow page.
|
|
36
|
+
#
|
|
37
|
+
# @see https://stackoverflow.com/a/41655546
|
|
38
|
+
sleep infinity
|
data/dx/start
ADDED
|
@@ -0,0 +1,30 @@
|
|
|
1
|
+
#!/bin/bash
|
|
2
|
+
|
|
3
|
+
set -e
|
|
4
|
+
|
|
5
|
+
SCRIPT_DIR=$( cd -- "$( dirname -- "${0}" )" > /dev/null 2>&1 && pwd )
|
|
6
|
+
|
|
7
|
+
. "${SCRIPT_DIR}/dx.sh.lib"
|
|
8
|
+
require_command "docker"
|
|
9
|
+
load_docker_compose_env
|
|
10
|
+
|
|
11
|
+
usage_on_help "Starts all services, including a container in which to run your app" "" "" "" "${@}"
|
|
12
|
+
|
|
13
|
+
log "đ" "Starting docker-compose.dx.yml"
|
|
14
|
+
|
|
15
|
+
BUILD=--build
|
|
16
|
+
if [ "${1}" == "--no-build" ]; then
|
|
17
|
+
BUILD=
|
|
18
|
+
fi
|
|
19
|
+
|
|
20
|
+
docker \
|
|
21
|
+
compose \
|
|
22
|
+
--file docker-compose.dx.yml \
|
|
23
|
+
--project-name "${PROJECT_NAME}" \
|
|
24
|
+
--env-file "${ENV_FILE}" \
|
|
25
|
+
up \
|
|
26
|
+
"${BUILD}" \
|
|
27
|
+
--timestamps \
|
|
28
|
+
--force-recreate
|
|
29
|
+
|
|
30
|
+
# vim: ft=bash
|
data/dx/stop
ADDED
|
@@ -0,0 +1,23 @@
|
|
|
1
|
+
#!/bin/bash
|
|
2
|
+
|
|
3
|
+
set -e
|
|
4
|
+
|
|
5
|
+
SCRIPT_DIR=$( cd -- "$( dirname -- "${0}" )" > /dev/null 2>&1 && pwd )
|
|
6
|
+
|
|
7
|
+
. "${SCRIPT_DIR}/dx.sh.lib"
|
|
8
|
+
require_command "docker"
|
|
9
|
+
load_docker_compose_env
|
|
10
|
+
|
|
11
|
+
usage_on_help "Stops all services, the container in which to run your app and removes any volumes" "" "" "" "${@}"
|
|
12
|
+
|
|
13
|
+
log "đ" "Stopping docker-compose.dx.yml"
|
|
14
|
+
|
|
15
|
+
docker \
|
|
16
|
+
compose \
|
|
17
|
+
--file docker-compose.dx.yml \
|
|
18
|
+
--project-name "${PROJECT_NAME}" \
|
|
19
|
+
--env-file "${ENV_FILE}" \
|
|
20
|
+
down \
|
|
21
|
+
--volumes
|
|
22
|
+
|
|
23
|
+
# vim: ft=bash
|