prick 0.19.0 → 0.20.1
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/Gemfile +10 -4
- data/README.md +7 -7
- data/Rakefile +3 -1
- data/TODO +13 -11
- data/bin/console +2 -1
- data/doc/build-yml.txt +14 -0
- data/exe/prick +237 -19
- data/lib/builder/batch.rb +147 -0
- data/lib/builder/builder.rb +122 -0
- data/lib/builder/node.rb +189 -0
- data/lib/builder/node_pool.rb +105 -0
- data/lib/builder/parser.rb +120 -0
- data/lib/local/command.rb +193 -0
- data/lib/{prick → local}/git.rb +148 -22
- data/lib/local/timer.rb +98 -0
- data/lib/prick/constants.rb +54 -66
- data/lib/prick/diff.rb +28 -18
- data/lib/prick/prick_version.rb +161 -0
- data/lib/prick/state.rb +80 -165
- data/lib/prick/version.rb +2 -163
- data/lib/prick.rb +38 -24
- data/lib/share/init/.gitignore +10 -0
- data/lib/share/init/.prick-context +2 -0
- data/lib/share/init/.rspec +3 -0
- data/{share/schema/schema/public → lib/share/init/migration}/.keep +0 -0
- data/lib/share/init/prick.yml +6 -0
- data/lib/share/init/schema/.keep +0 -0
- data/lib/share/init/schema/build.yml +2 -0
- data/lib/share/init/schema/prick/.keep +0 -0
- data/lib/share/init/schema/prick/build.yml +5 -0
- data/lib/share/init/schema/prick/data.sql +6 -0
- data/{share/schema → lib/share/init}/schema/prick/tables.sql +2 -3
- data/lib/share/init/schema/public/.keep +0 -0
- data/lib/share/init/spec/prick_helper.rb +1 -0
- data/lib/share/init/spec/prick_spec.rb +6 -0
- data/lib/share/init/spec/spec_helper.rb +50 -0
- data/lib/share/migrate/migration/build.yml +4 -0
- data/lib/share/migrate/migration/diff.after-tables.sql +0 -0
- data/lib/share/migrate/migration/diff.before-tables.sql +0 -0
- data/lib/share/migrate/migration/diff.tables.sql +0 -0
- data/lib/subcommand/prick-build.rb +55 -0
- data/lib/subcommand/prick-create.rb +78 -0
- data/lib/subcommand/prick-drop.rb +25 -0
- data/lib/subcommand/prick-fox.rb +62 -0
- data/lib/subcommand/prick-init.rb +46 -0
- data/lib/subcommand/prick-make.rb +202 -0
- data/lib/subcommand/prick-migrate.rb +37 -0
- data/lib/subcommand/prick-release.rb +23 -0
- data/lib/subcommand/prick-setup.rb +20 -0
- data/lib/subcommand/prick-teardown.rb +18 -0
- data/prick.gemspec +32 -21
- metadata +95 -76
- data/.gitignore +0 -29
- data/.travis.yml +0 -7
- data/doc/create_release.txt +0 -17
- data/doc/flow.txt +0 -98
- data/doc/migra +0 -1
- data/doc/migrations.txt +0 -172
- data/doc/notes.txt +0 -116
- data/doc/prick.txt +0 -114
- data/doc/sh.prick +0 -316
- data/lib/ext/algorithm.rb +0 -14
- data/lib/ext/fileutils.rb +0 -26
- data/lib/ext/forward_method.rb +0 -18
- data/lib/ext/pg.rb +0 -18
- data/lib/ext/shortest_path.rb +0 -44
- data/lib/prick/archive.rb +0 -124
- data/lib/prick/branch.rb +0 -265
- data/lib/prick/builder.rb +0 -246
- data/lib/prick/cache.rb +0 -34
- data/lib/prick/command.rb +0 -104
- data/lib/prick/database.rb +0 -82
- data/lib/prick/dsort.rb +0 -151
- data/lib/prick/ensure.rb +0 -119
- data/lib/prick/exceptions.rb +0 -25
- data/lib/prick/head.rb +0 -189
- data/lib/prick/migration.rb +0 -70
- data/lib/prick/program.rb +0 -287
- data/lib/prick/project.rb +0 -626
- data/lib/prick/rdbms.rb +0 -137
- data/lib/prick/schema.rb +0 -27
- data/lib/prick/share.rb +0 -64
- data/libexec/strip-comments +0 -33
- data/make_releases +0 -72
- data/make_schema +0 -10
- data/share/diff/diff.after-tables.sql +0 -4
- data/share/diff/diff.before-tables.sql +0 -4
- data/share/diff/diff.tables.sql +0 -8
- data/share/features/diff.sql +0 -2
- data/share/features/feature/diff.sql +0 -2
- data/share/features/feature/migrate.sql +0 -2
- data/share/features/features.sql +0 -2
- data/share/features/features.yml +0 -2
- data/share/features/migrations.sql +0 -4
- data/share/gitignore +0 -2
- data/share/migration/diff.tables.sql +0 -8
- data/share/migration/features.yml +0 -6
- data/share/migration/migrate.sql +0 -3
- data/share/migration/migrate.yml +0 -8
- data/share/migration/tables.sql +0 -3
- data/share/schema/build.yml +0 -14
- data/share/schema/schema/build.yml +0 -3
- data/share/schema/schema/prick/build.yml +0 -14
- data/share/schema/schema/prick/data.sql +0 -7
- data/share/schema/schema/prick/schema.sql +0 -3
- data/share/schema/schema/public/build.yml +0 -13
- data/share/schema/schema.sql +0 -3
- data/test_assorted +0 -192
- data/test_feature +0 -112
- data/test_refactor +0 -34
- data/test_single_dev +0 -83
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 2abdd6978f9dce4cf9570d2ad5165fef65541ed5e69bd6150086a30b232498a5
|
4
|
+
data.tar.gz: bb1accf8f541d7197c73b14407401d91d5e3b9475b205bad46bea8851d2825c6
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 951dee9f87d7ba9475bf70512b35d29720a30ec5371e2c03c00575c21a94163f3aa43bf28bfbb6a5fe80e0da63cb1154bd84f29ae671651b7aa54de0e45630e2
|
7
|
+
data.tar.gz: cc5ef462d6c9ae5e1add6bb9fc53ffc4a6684c64020d24fad39327cd80218f01c031060f7c2e14a125a94caad305c658994e2ea53845f211909a4764a72f8d75
|
data/Gemfile
CHANGED
@@ -1,9 +1,15 @@
|
|
1
|
-
|
1
|
+
# frozen_string_literal: true
|
2
2
|
|
3
|
-
|
3
|
+
source "https://rubygems.org"
|
4
4
|
|
5
|
-
# Specify your gem's dependencies in
|
5
|
+
# Specify your gem's dependencies in prick_build.gemspec
|
6
6
|
gemspec
|
7
7
|
|
8
|
-
gem "rake", "~>
|
8
|
+
gem "rake", "~> 13.0"
|
9
9
|
gem "rspec", "~> 3.0"
|
10
|
+
|
11
|
+
gem 'shellopts', :github => 'clrgit/shellopts', branch: "master"
|
12
|
+
gem 'pg_graph', :github => 'clrgit/pg_graph', branch: "master"
|
13
|
+
gem 'pg_meta', :github => 'clrgit/pg_meta', branch: "master"
|
14
|
+
gem 'pg_conn', :github => 'clrgit/pg_conn', branch: "master"
|
15
|
+
|
data/README.md
CHANGED
@@ -1,6 +1,6 @@
|
|
1
|
-
#
|
1
|
+
# PrickBuild
|
2
2
|
|
3
|
-
Welcome to your new gem! In this directory, you'll find the files you need to be able to package up your Ruby library into a gem. Put your Ruby code in the file `lib/
|
3
|
+
Welcome to your new gem! In this directory, you'll find the files you need to be able to package up your Ruby library into a gem. Put your Ruby code in the file `lib/prick_build`. To experiment with that code, run `bin/console` for an interactive prompt.
|
4
4
|
|
5
5
|
TODO: Delete this and the text above, and describe your gem
|
6
6
|
|
@@ -9,16 +9,16 @@ TODO: Delete this and the text above, and describe your gem
|
|
9
9
|
Add this line to your application's Gemfile:
|
10
10
|
|
11
11
|
```ruby
|
12
|
-
gem '
|
12
|
+
gem 'prick_build'
|
13
13
|
```
|
14
14
|
|
15
15
|
And then execute:
|
16
16
|
|
17
|
-
$ bundle
|
17
|
+
$ bundle install
|
18
18
|
|
19
19
|
Or install it yourself as:
|
20
20
|
|
21
|
-
$ gem install
|
21
|
+
$ gem install prick_build
|
22
22
|
|
23
23
|
## Usage
|
24
24
|
|
@@ -28,8 +28,8 @@ TODO: Write usage instructions here
|
|
28
28
|
|
29
29
|
After checking out the repo, run `bin/setup` to install dependencies. Then, run `rake spec` to run the tests. You can also run `bin/console` for an interactive prompt that will allow you to experiment.
|
30
30
|
|
31
|
-
To install this gem onto your local machine, run `bundle exec rake install`. To release a new version, update the version number in `version.rb`, and then run `bundle exec rake release`, which will create a git tag for the version, push git commits and
|
31
|
+
To install this gem onto your local machine, run `bundle exec rake install`. To release a new version, update the version number in `version.rb`, and then run `bundle exec rake release`, which will create a git tag for the version, push git commits and the created tag, and push the `.gem` file to [rubygems.org](https://rubygems.org).
|
32
32
|
|
33
33
|
## Contributing
|
34
34
|
|
35
|
-
Bug reports and pull requests are welcome on GitHub at https://github.com/[USERNAME]/
|
35
|
+
Bug reports and pull requests are welcome on GitHub at https://github.com/[USERNAME]/prick_build.
|
data/Rakefile
CHANGED
data/TODO
CHANGED
@@ -1,13 +1,15 @@
|
|
1
1
|
|
2
|
-
o
|
3
|
-
|
4
|
-
|
5
|
-
|
6
|
-
|
7
|
-
o
|
8
|
-
|
9
|
-
o
|
10
|
-
|
11
|
-
|
12
|
-
|
2
|
+
o Store fox.state, reflections, and reflections in the database so third-party
|
3
|
+
programs can use them when testing
|
4
|
+
o 'prick make <resource>' should build everything up the resource, then commit
|
5
|
+
before trying to build the resource upon the database. Then it is easy to
|
6
|
+
re-run the failed (sql-)script in psql to see why it failed
|
7
|
+
o 'prick make' should build everything up a touched file, then commit before
|
8
|
+
proceeding
|
9
|
+
o Build functions after schema so that there are no order dependencies on
|
10
|
+
functions. Problem is to detect function files
|
11
|
+
o Build views after schema so that there are no order dependencies on
|
12
|
+
views. Problem is to detect view files
|
13
13
|
|
14
|
+
+ prick release major|minor|patch
|
15
|
+
+ Check modification time of build.yml files too
|
data/bin/console
CHANGED
@@ -1,7 +1,8 @@
|
|
1
1
|
#!/usr/bin/env ruby
|
2
|
+
# frozen_string_literal: true
|
2
3
|
|
3
4
|
require "bundler/setup"
|
4
|
-
require "
|
5
|
+
require "prick_build"
|
5
6
|
|
6
7
|
# You can add fixtures and/or initialization code here to make experimenting
|
7
8
|
# with your gem easier. You can also use a different console, if you like.
|
data/doc/build-yml.txt
ADDED
data/exe/prick
CHANGED
@@ -1,39 +1,250 @@
|
|
1
1
|
#!/usr/bin/env ruby
|
2
2
|
|
3
|
-
|
4
|
-
require 'prick/program.rb'
|
3
|
+
#$LOAD_PATH.unshift "/home/clr/prj/shellopts/lib"
|
5
4
|
|
6
|
-
require '
|
5
|
+
require 'bootsnap'
|
6
|
+
begin
|
7
|
+
cache_dir = "/run/user/" + `id -u`.chomp
|
8
|
+
Bootsnap.setup(
|
9
|
+
cache_dir: cache_dir, # Path to your cache
|
10
|
+
development_mode: true, # Current working environment, e.g. RACK_ENV, RAILS_ENV, etc
|
11
|
+
load_path_cache: true, # Optimize the LOAD_PATH with a cache
|
12
|
+
compile_cache_iseq: true, # Compile Ruby code into ISeq cache, breaks coverage reporting.
|
13
|
+
compile_cache_yaml: true # Compile YAML into a cache
|
14
|
+
)
|
15
|
+
Bootsnap.instrumentation = ->(event, path) { puts "#{event} #{path}" }
|
16
|
+
end
|
7
17
|
|
8
|
-
require '
|
18
|
+
require 'prick.rb'
|
19
|
+
require 'shellopts'
|
9
20
|
|
10
21
|
include ShellOpts
|
11
22
|
include Prick
|
12
23
|
|
24
|
+
TIME = false
|
13
25
|
|
14
26
|
SPEC = %(
|
15
|
-
|
16
|
-
Name of project. Defauls to the environment variable `PRICK_PROJECT` if
|
17
|
-
set and else the name of the current directory
|
18
|
-
|
19
|
-
-C,directory=DIR
|
20
|
-
Change to directory DIR before doing anything else
|
21
|
-
|
22
|
-
-h,help COMMAND...
|
23
|
-
Print this page
|
27
|
+
@ Prick project command
|
24
28
|
|
25
29
|
+v,verbose
|
26
|
-
Be verbose. Repeated
|
30
|
+
Be verbose. Repeated -v options increase the verbosity level
|
27
31
|
|
28
32
|
-q,quiet
|
29
33
|
Be quiet
|
30
34
|
|
31
|
-
|
32
|
-
|
35
|
+
-C,directory=EDIR
|
36
|
+
Change to directory DIR before doing anything else
|
37
|
+
|
38
|
+
-d,database=DATABASE
|
39
|
+
Override database name from prick.yml
|
40
|
+
|
41
|
+
-U,username=USERNAME
|
42
|
+
Override username from from prick.yml
|
43
|
+
|
44
|
+
version!
|
45
|
+
Print project version
|
46
|
+
|
47
|
+
init! -n,name=NAME -t,title=TITLE [DIRECTORY]
|
48
|
+
Initializes a prick project
|
49
|
+
|
50
|
+
setup!
|
51
|
+
Create the database user (if necessary) and an empty database
|
52
|
+
|
53
|
+
teardown!
|
54
|
+
Drop the database and the database user. TODO: Also run teardown scripts
|
55
|
+
|
56
|
+
create.data!
|
57
|
+
create.schema!
|
58
|
+
create.database!
|
59
|
+
create.users!
|
60
|
+
create.all!
|
61
|
+
Create an object. Fails if migration exist unless the --force flag is given
|
62
|
+
|
63
|
+
create.migration! -f,force -o,file=FILE -- VERSION
|
64
|
+
Create a migration from VERSION to the current and write it to
|
65
|
+
migration/VERSION. Fails if migration exist unless the --force flag is
|
66
|
+
given. If --file is given, the migration is written to FILE instead of
|
67
|
+
the migration directory. This doesn't require you to be on a release
|
68
|
+
branch and can be used to create ad-hoc migration scripts
|
69
|
+
|
70
|
+
drop! -- [KIND]
|
71
|
+
@ Drop objects
|
72
|
+
|
73
|
+
Kind can be 'users', 'data', 'schema', 'database' (the default), or 'all'. It is
|
74
|
+
not an error if the object doesn't exist. TODO Only 'users' is currently defined
|
75
|
+
|
76
|
+
build! -t,time --dump=KIND? -- [SCHEMA]
|
77
|
+
Build the project. If SCHEMA is defined, later schemas are excluded.
|
78
|
+
KIND can be 'nodes', 'allnodes' or 'batches' (the default)
|
79
|
+
|
80
|
+
make! -t,time --dump=KIND? -- [SCHEMA]
|
81
|
+
@ Only rebuild changed files
|
82
|
+
|
83
|
+
Checks file timestamps against the time of the last build and only
|
84
|
+
rebuild affected parts of the project. KIND can be 'nodes', 'allnodes' or
|
85
|
+
'batches'
|
86
|
+
|
87
|
+
fox! -- FILE...
|
88
|
+
Load fox file data. Data are reset to their initial state after build
|
89
|
+
before the fox data are loaded
|
90
|
+
|
91
|
+
release! -- KIND
|
92
|
+
Create a release of the given kind. KIND can be 'major', 'minor', or
|
93
|
+
'patch'. Release checks that the current repo is clean and up to date
|
94
|
+
with the origin
|
95
|
+
|
96
|
+
migrate! -f,file=FILE
|
97
|
+
Execute a migration
|
98
|
+
|
99
|
+
dump.type!
|
100
|
+
dump.data!
|
101
|
+
dump.schema!
|
102
|
+
dump.database!
|
103
|
+
TODO
|
104
|
+
|
105
|
+
dump.migration! --force -- VERSION
|
106
|
+
)
|
107
|
+
|
108
|
+
opts, args = ShellOpts.process(SPEC, ARGV, exception: true)
|
109
|
+
|
110
|
+
begin
|
111
|
+
# Handle verbose and quiet
|
112
|
+
$verbose = opts.verbose
|
113
|
+
$quiet = opts.quiet?
|
114
|
+
|
115
|
+
# Honor -C option
|
116
|
+
if opts.directory?
|
117
|
+
if File.exist?(opts.directory)
|
118
|
+
begin
|
119
|
+
Dir.chdir(opts.directory)
|
120
|
+
rescue Errno::ENOENT
|
121
|
+
raise Prick::Error, "Can't cd to '#{opts.directory}'"
|
122
|
+
end
|
123
|
+
else
|
124
|
+
raise Prick::Error, "Can't find directory: #{opts.directory}"
|
125
|
+
end
|
126
|
+
end
|
127
|
+
|
128
|
+
# Get subcommand
|
129
|
+
cmd = opts.subcommand!
|
130
|
+
|
131
|
+
# Process init command
|
132
|
+
if opts.subcommand == :init
|
133
|
+
dir, state = Prick::SubCommand.init(args.expect(0..1), cmd.name, cmd.title, opts.database, opts.username)
|
134
|
+
puts "Initialized prick project '#{state.name}' in #{dir}"
|
135
|
+
if opts.database.nil? || opts.username.nil?
|
136
|
+
puts
|
137
|
+
puts "Please check database/username in #{PRICK_CONTEXT_FILE}"
|
138
|
+
end
|
139
|
+
exit
|
140
|
+
end
|
141
|
+
|
142
|
+
# Check state
|
143
|
+
File.exist?(PRICK_PROJECT_FILE) or raise Prick::Error, "Not in a prick project directory"
|
144
|
+
|
145
|
+
# Load state
|
146
|
+
Prick.state = State.load
|
147
|
+
|
148
|
+
# Handle -d and -U options
|
149
|
+
database = opts.database || Prick.state.database
|
150
|
+
username = opts.username || Prick.state.username
|
151
|
+
|
152
|
+
# Expect a sub-command
|
153
|
+
cmd = opts.subcommand! or raise Prick::Error, "Subcomand expected"
|
154
|
+
|
155
|
+
# Process subcommands
|
156
|
+
case opts.subcommand
|
157
|
+
when :version!
|
158
|
+
puts "#{Prick.state.name}-#{Prick.state.version}"
|
159
|
+
|
160
|
+
when :setup!
|
161
|
+
Prick::SubCommand.setup(database, username)
|
162
|
+
|
163
|
+
when :teardown!
|
164
|
+
Prick::SubCommand.teardown(database, username)
|
165
|
+
|
166
|
+
when :create!
|
167
|
+
create_command = opts.create!
|
168
|
+
case create_command.subcommand
|
169
|
+
when :migration
|
170
|
+
arg = args.expect(1)
|
171
|
+
version = PrickVersion.try(arg) or raise Prick::Error, "Illegal version: #{arg}"
|
172
|
+
Prick::SubCommand.create_migration(
|
173
|
+
username, version,
|
174
|
+
force: create_command.subcommand!.force?,
|
175
|
+
file: create_command.subcommand!.file)
|
176
|
+
else
|
177
|
+
raise NotImplementedError
|
178
|
+
end
|
179
|
+
|
180
|
+
when :build!
|
181
|
+
dump = cmd.dump("batches")&.to_sym
|
182
|
+
Prick::SubCommand.build(database, username, args.expect(0..1), timer: cmd.time?, dump: dump)
|
183
|
+
|
184
|
+
when :make!
|
185
|
+
dump = cmd.dump("batches")&.to_sym
|
186
|
+
Prick::SubCommand.make(database, username, args.expect(0..1), timer: cmd.time?, dump: dump)
|
187
|
+
|
188
|
+
when :fox!
|
189
|
+
Prick::SubCommand.fox(database, username, args)
|
33
190
|
|
34
|
-
|
35
|
-
|
36
|
-
|
191
|
+
when :drop!
|
192
|
+
case subject = args.expect(1).to_sym
|
193
|
+
when :all
|
194
|
+
Prick::SubCommand.drop_all(database)
|
195
|
+
when :users
|
196
|
+
Prick::SubCommand.drop_users(database)
|
197
|
+
when :database
|
198
|
+
Prick::SubCommand.drop_database(database)
|
199
|
+
when :data, :schema, :database, :all
|
200
|
+
raise NotImplementedError
|
201
|
+
else
|
202
|
+
raise Prick::Error, "Unknown subject: #{subject}"
|
203
|
+
end
|
204
|
+
|
205
|
+
when :release!
|
206
|
+
kind = args.expect(1).to_sym
|
207
|
+
constrain? kind, :major, :minor, :patch or
|
208
|
+
raise Prick::Fail, "Expected 'major', 'minor', or 'patch' argument, got '#{kind}'"
|
209
|
+
Prick::SubCommand.release(kind)
|
210
|
+
|
211
|
+
when :migrate!
|
212
|
+
args.expect(0)
|
213
|
+
Prick::SubCommand.migrate(database, username, file: cmd.file)
|
214
|
+
|
215
|
+
when :dump!
|
216
|
+
subject = cmd.subcommand!
|
217
|
+
case cmd.subcommand
|
218
|
+
when :migration
|
219
|
+
arg = args.expect(1)
|
220
|
+
version = PrickVersion.try(arg) or raise "Illegal version number: #{arg}"
|
221
|
+
Prick::SubCommand.create_migration(username, version, force: subject.force?, file: "/dev/stdout")
|
222
|
+
when :data, :schema, :database
|
223
|
+
raise NotImplementedError
|
224
|
+
else
|
225
|
+
raise Prick::Error, "Unknown subject: #{subject}"
|
226
|
+
end
|
227
|
+
|
228
|
+
else
|
229
|
+
raise Prick::Fail, "Internal error: Unhandled command - #{opts.subcommand.inspect}"
|
230
|
+
end
|
231
|
+
|
232
|
+
rescue ShellOpts::Failure, Prick::Fail, Prick::Build::PostgresError => ex
|
233
|
+
ShellOpts.failure(ex.message)
|
234
|
+
|
235
|
+
rescue ShellOpts::Error, Prick::Error => ex
|
236
|
+
ShellOpts.error(ex.message)
|
237
|
+
end
|
238
|
+
|
239
|
+
__END__
|
240
|
+
|
241
|
+
-n,name=NAME
|
242
|
+
Name of project. Defauls to the environment variable `PRICK_PROJECT` if
|
243
|
+
set and else the name of the current directory
|
244
|
+
|
245
|
+
init! -u,user=USER [NAME]
|
246
|
+
Initialize a project in the given directory. The USER is the postgres
|
247
|
+
user and defaults to the project name
|
37
248
|
|
38
249
|
info!
|
39
250
|
Print project information
|
@@ -160,6 +371,13 @@ SPEC = %(
|
|
160
371
|
in the var/spool directory
|
161
372
|
)
|
162
373
|
|
374
|
+
__END__
|
375
|
+
|
376
|
+
|
377
|
+
|
378
|
+
|
379
|
+
|
380
|
+
|
163
381
|
DEFAULT_STATE_FILE = "fox.state"
|
164
382
|
|
165
383
|
opts, args = ShellOpts.process(SPEC, ARGV)
|
@@ -0,0 +1,147 @@
|
|
1
|
+
module Prick
|
2
|
+
module Build
|
3
|
+
class BuildBatch
|
4
|
+
include Timer
|
5
|
+
|
6
|
+
attr_reader :builder
|
7
|
+
forward_to :builder, :conn
|
8
|
+
|
9
|
+
def kind() @nodes.first&.kind end
|
10
|
+
attr_reader :nodes
|
11
|
+
|
12
|
+
def initialize(builder)
|
13
|
+
@builder = builder
|
14
|
+
@nodes = []
|
15
|
+
end
|
16
|
+
|
17
|
+
def execute(&block)
|
18
|
+
name = self.class.to_s.sub(/.*::/, "").split(/(?=[A-Z])/).map(&:downcase).join(" ")
|
19
|
+
time "Execute #{name} (nodes: #{nodes.size})" do
|
20
|
+
yield
|
21
|
+
end
|
22
|
+
end
|
23
|
+
|
24
|
+
def dump
|
25
|
+
puts kind.upcase
|
26
|
+
indent { nodes.each(&:dump) }
|
27
|
+
end
|
28
|
+
end
|
29
|
+
|
30
|
+
class SqlBatch < BuildBatch
|
31
|
+
def execute
|
32
|
+
super {
|
33
|
+
begin
|
34
|
+
sql = []
|
35
|
+
if nodes.first.is_a?(ExeNode)
|
36
|
+
time "Execute script" do
|
37
|
+
sql = [nodes.first.source]
|
38
|
+
end
|
39
|
+
end
|
40
|
+
conn.execute sql + nodes[sql.size..-1].map(&:source)
|
41
|
+
|
42
|
+
rescue PG::SyntaxError, PG::Error => ex
|
43
|
+
error, line, pos = parse_pg_message(ex.message)
|
44
|
+
if line
|
45
|
+
if line < nodes.first.lines
|
46
|
+
node = nodes.first;
|
47
|
+
else
|
48
|
+
line -= nodes.first.lines
|
49
|
+
node = nodes[1..-1].find { |node|
|
50
|
+
line -= 1
|
51
|
+
if line < node.lines
|
52
|
+
line -= 2
|
53
|
+
true
|
54
|
+
else
|
55
|
+
line -= node.lines
|
56
|
+
false
|
57
|
+
end
|
58
|
+
}
|
59
|
+
end
|
60
|
+
|
61
|
+
if node.is_a?(SqlNode)
|
62
|
+
message = ["prick: #{error} in #{node.path}", line, pos].compact.join(":")
|
63
|
+
else
|
64
|
+
message = "prick: #{error} from #{node.path}"
|
65
|
+
end
|
66
|
+
else
|
67
|
+
raise
|
68
|
+
end
|
69
|
+
raise PostgresError.new(message)
|
70
|
+
end
|
71
|
+
}
|
72
|
+
end
|
73
|
+
|
74
|
+
private
|
75
|
+
# Returns [error, line, pos] tuple
|
76
|
+
def parse_pg_message(message)
|
77
|
+
message =~ /ERROR:\s*(.*?)\n(LINE (\d+): ).*?\n(\s*\^)/m or return nil
|
78
|
+
[$1, $3.to_i, $4.size - $2.size]
|
79
|
+
end
|
80
|
+
end
|
81
|
+
|
82
|
+
class ModuleBatch < BuildBatch
|
83
|
+
def execute
|
84
|
+
super {
|
85
|
+
nodes.each { |node|
|
86
|
+
sql = node&.call
|
87
|
+
conn.execute sql if sql
|
88
|
+
}
|
89
|
+
}
|
90
|
+
end
|
91
|
+
end
|
92
|
+
|
93
|
+
class FoxBatch < BuildBatch
|
94
|
+
# Inlining Fox instead of using command line program as it saves some deciseconds
|
95
|
+
def execute
|
96
|
+
t_type = t_fox = t_exe = nil
|
97
|
+
|
98
|
+
super {
|
99
|
+
timer = Timer.new "Execute fox batch (nodes: #{nodes.size}, clean: #{builder.clean})"
|
100
|
+
t_type = Timer.new " Load data model"
|
101
|
+
|
102
|
+
files = nodes.map(&:path)
|
103
|
+
|
104
|
+
# Load meta object
|
105
|
+
meta = PgMeta.new(conn)
|
106
|
+
|
107
|
+
# Create type object
|
108
|
+
type = PgGraph::Type.new(meta, builder.reflections_file)
|
109
|
+
|
110
|
+
t_type.stop
|
111
|
+
t_fox = Timer.new " Parse files"
|
112
|
+
|
113
|
+
# Create fox object
|
114
|
+
fox = FixtureFox::Fox.new(type)
|
115
|
+
|
116
|
+
# Parse files
|
117
|
+
for file in files
|
118
|
+
source, lines = fox.tokenize(file)
|
119
|
+
fox.parse(source, lines)
|
120
|
+
end
|
121
|
+
|
122
|
+
# Analyze
|
123
|
+
fox.assign_types
|
124
|
+
fox.generate
|
125
|
+
|
126
|
+
# Dump state file
|
127
|
+
fox.write_state(FOX_STATE_PATH)
|
128
|
+
|
129
|
+
t_fox.stop
|
130
|
+
t_exe = Timer.new " Execute SQL"
|
131
|
+
|
132
|
+
delete = builder.clean ? :none : :touched
|
133
|
+
begin
|
134
|
+
conn.execute fox.to_sql(format: :exec, delete: delete)
|
135
|
+
conn.execute "update prick.versions set built_at = now() at time zone 'UTC'"
|
136
|
+
rescue PG::SyntaxError, PG::Error => ex
|
137
|
+
raise PostgresError, "prick: #{error} from #{node.path}"
|
138
|
+
end
|
139
|
+
}
|
140
|
+
t_type.emit
|
141
|
+
t_fox.emit
|
142
|
+
t_exe.emit
|
143
|
+
end
|
144
|
+
end
|
145
|
+
end
|
146
|
+
end
|
147
|
+
|
@@ -0,0 +1,122 @@
|
|
1
|
+
require 'local/command'
|
2
|
+
|
3
|
+
require 'builder/node.rb'
|
4
|
+
require 'builder/node_pool.rb'
|
5
|
+
require 'builder/batch.rb'
|
6
|
+
require 'builder/parser.rb'
|
7
|
+
|
8
|
+
include Constrain
|
9
|
+
|
10
|
+
module Prick
|
11
|
+
module Build
|
12
|
+
class Error < StandardError; end
|
13
|
+
class PostgresError < Error; end
|
14
|
+
|
15
|
+
class Builder
|
16
|
+
# PgConn object
|
17
|
+
attr_reader :conn
|
18
|
+
|
19
|
+
# Root schema directory
|
20
|
+
attr_reader :dir
|
21
|
+
|
22
|
+
# Reflections YAML file
|
23
|
+
attr_reader :reflections_file
|
24
|
+
|
25
|
+
# True if database is initially clean - ie. all tables are empty
|
26
|
+
attr_accessor :clean
|
27
|
+
|
28
|
+
# Root build node
|
29
|
+
attr_reader :root
|
30
|
+
|
31
|
+
# Pool of nodes. Initialized by #load_pool
|
32
|
+
attr_reader :pool
|
33
|
+
|
34
|
+
forward_to :pool, :nodes, :decl_nodes, :init_nodes, :term_nodes,
|
35
|
+
:seed_nodes, :fox_seed_nodes, :sql_seed_nodes,
|
36
|
+
:schemas
|
37
|
+
|
38
|
+
def batches() @batches ||= group end
|
39
|
+
|
40
|
+
def initialize(conn, dir, clean = true, touched: false)
|
41
|
+
@conn = conn
|
42
|
+
@dir = dir
|
43
|
+
@reflections_file = REFLECTIONS_PATH
|
44
|
+
@clean = clean
|
45
|
+
@pool = NodePool.new
|
46
|
+
@root = Parser.parse(conn, dir)
|
47
|
+
load_pool(@root) # Collect nodes into pool
|
48
|
+
@batches = nil # Initialized by #group
|
49
|
+
end
|
50
|
+
|
51
|
+
# Group sources into batches
|
52
|
+
def group
|
53
|
+
@batches = []
|
54
|
+
kind = nil
|
55
|
+
batch = nil
|
56
|
+
|
57
|
+
for node in [init_nodes, decl_nodes, fox_seed_nodes, sql_seed_nodes, term_nodes].flatten
|
58
|
+
case node.kind
|
59
|
+
when :module
|
60
|
+
if batch&.kind != :module
|
61
|
+
@batches << batch if batch
|
62
|
+
batch = ModuleBatch.new(self)
|
63
|
+
end
|
64
|
+
when :exe # Exe sources always create a new batch
|
65
|
+
@batches << batch if batch
|
66
|
+
batch = SqlBatch.new(self)
|
67
|
+
when batch&.kind
|
68
|
+
;
|
69
|
+
when :sql || node.kind == :inline
|
70
|
+
if batch&.kind != :exe
|
71
|
+
@batches << batch if batch
|
72
|
+
batch = SqlBatch.new(self)
|
73
|
+
end
|
74
|
+
when :inline
|
75
|
+
@batches << batch if batch
|
76
|
+
batch = SqlBatch.new(self)
|
77
|
+
when :fox
|
78
|
+
@batches << batch if batch
|
79
|
+
batch = FoxBatch.new(self)
|
80
|
+
when :yml
|
81
|
+
next
|
82
|
+
else
|
83
|
+
raise Error, "Unexpected node kind: #{node.kind}"
|
84
|
+
end
|
85
|
+
batch.nodes << node
|
86
|
+
end
|
87
|
+
@batches << batch if batch
|
88
|
+
end
|
89
|
+
|
90
|
+
def execute(conn, create_schemas: schemas)
|
91
|
+
group if batches.nil?
|
92
|
+
conn.exec create_schemas.grep_v("public").map { |schema| "create schema #{schema}" }
|
93
|
+
for batch in batches
|
94
|
+
batch.execute
|
95
|
+
end
|
96
|
+
end
|
97
|
+
|
98
|
+
# def setup
|
99
|
+
# end
|
100
|
+
|
101
|
+
# def teardown
|
102
|
+
# end
|
103
|
+
|
104
|
+
def dump
|
105
|
+
batches ? batches.each(&:dump) : pool.dump
|
106
|
+
end
|
107
|
+
|
108
|
+
private
|
109
|
+
def load_pool(build_node)
|
110
|
+
pool.add(build_node.init_nodes)
|
111
|
+
build_node.decl_nodes.each { |node|
|
112
|
+
pool.add node
|
113
|
+
load_pool(node) if node.kind == :yml
|
114
|
+
}
|
115
|
+
pool.add(build_node.seed_nodes)
|
116
|
+
pool.add(build_node.term_nodes)
|
117
|
+
end
|
118
|
+
end
|
119
|
+
end
|
120
|
+
end
|
121
|
+
|
122
|
+
|