prick 0.17.0 → 0.20.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.
Files changed (112) hide show
  1. checksums.yaml +4 -4
  2. data/Gemfile +10 -4
  3. data/README.md +7 -7
  4. data/Rakefile +3 -1
  5. data/TODO +13 -11
  6. data/bin/console +2 -1
  7. data/doc/build-yml.txt +14 -0
  8. data/exe/prick +264 -28
  9. data/lib/builder/batch.rb +147 -0
  10. data/lib/builder/builder.rb +122 -0
  11. data/lib/builder/node.rb +189 -0
  12. data/lib/builder/node_pool.rb +105 -0
  13. data/lib/builder/parser.rb +120 -0
  14. data/lib/local/command.rb +193 -0
  15. data/lib/{prick → local}/git.rb +148 -22
  16. data/lib/local/timer.rb +98 -0
  17. data/lib/prick/constants.rb +54 -66
  18. data/lib/prick/diff.rb +28 -18
  19. data/lib/prick/prick_version.rb +161 -0
  20. data/lib/prick/state.rb +80 -165
  21. data/lib/prick/version.rb +2 -163
  22. data/lib/prick.rb +43 -27
  23. data/lib/share/init/.gitignore +10 -0
  24. data/lib/share/init/.prick-context +2 -0
  25. data/lib/share/init/.rspec +3 -0
  26. data/{share/schema/schema/public → lib/share/init/migration}/.keep +0 -0
  27. data/lib/share/init/prick.yml +6 -0
  28. data/lib/share/init/schema/.keep +0 -0
  29. data/lib/share/init/schema/build.yml +2 -0
  30. data/lib/share/init/schema/prick/.keep +0 -0
  31. data/lib/share/init/schema/prick/build.yml +5 -0
  32. data/lib/share/init/schema/prick/data.sql +6 -0
  33. data/{share/schema → lib/share/init}/schema/prick/tables.sql +2 -3
  34. data/lib/share/init/schema/public/.keep +0 -0
  35. data/lib/share/init/spec/prick_helper.rb +1 -0
  36. data/lib/share/init/spec/prick_spec.rb +6 -0
  37. data/lib/share/init/spec/spec_helper.rb +50 -0
  38. data/lib/share/migrate/migration/build.yml +4 -0
  39. data/lib/share/migrate/migration/diff.after-tables.sql +0 -0
  40. data/lib/share/migrate/migration/diff.before-tables.sql +0 -0
  41. data/lib/share/migrate/migration/diff.tables.sql +0 -0
  42. data/lib/subcommand/prick-build.rb +55 -0
  43. data/lib/subcommand/prick-create.rb +78 -0
  44. data/lib/subcommand/prick-drop.rb +25 -0
  45. data/lib/subcommand/prick-fox.rb +62 -0
  46. data/lib/subcommand/prick-init.rb +46 -0
  47. data/lib/subcommand/prick-make.rb +202 -0
  48. data/lib/subcommand/prick-migrate.rb +37 -0
  49. data/lib/subcommand/prick-release.rb +23 -0
  50. data/lib/subcommand/prick-setup.rb +20 -0
  51. data/lib/subcommand/prick-teardown.rb +18 -0
  52. data/prick.gemspec +43 -16
  53. metadata +161 -72
  54. data/.gitignore +0 -29
  55. data/.travis.yml +0 -7
  56. data/doc/create_release.txt +0 -17
  57. data/doc/flow.txt +0 -98
  58. data/doc/migra +0 -1
  59. data/doc/migrations.txt +0 -172
  60. data/doc/notes.txt +0 -116
  61. data/doc/prick.txt +0 -114
  62. data/doc/sh.prick +0 -316
  63. data/lib/ext/algorithm.rb +0 -14
  64. data/lib/ext/fileutils.rb +0 -26
  65. data/lib/ext/forward_method.rb +0 -18
  66. data/lib/ext/pg.rb +0 -18
  67. data/lib/ext/shortest_path.rb +0 -44
  68. data/lib/prick/archive.rb +0 -124
  69. data/lib/prick/branch.rb +0 -254
  70. data/lib/prick/builder.rb +0 -202
  71. data/lib/prick/cache.rb +0 -34
  72. data/lib/prick/command.rb +0 -93
  73. data/lib/prick/database.rb +0 -82
  74. data/lib/prick/dsort.rb +0 -151
  75. data/lib/prick/ensure.rb +0 -119
  76. data/lib/prick/exceptions.rb +0 -25
  77. data/lib/prick/head.rb +0 -183
  78. data/lib/prick/migration.rb +0 -70
  79. data/lib/prick/program.rb +0 -506
  80. data/lib/prick/project.rb +0 -626
  81. data/lib/prick/rdbms.rb +0 -137
  82. data/lib/prick/schema.rb +0 -27
  83. data/lib/prick/share.rb +0 -64
  84. data/libexec/strip-comments +0 -33
  85. data/make_releases +0 -72
  86. data/make_schema +0 -10
  87. data/share/diff/diff.after-tables.sql +0 -4
  88. data/share/diff/diff.before-tables.sql +0 -4
  89. data/share/diff/diff.tables.sql +0 -8
  90. data/share/features/diff.sql +0 -2
  91. data/share/features/feature/diff.sql +0 -2
  92. data/share/features/feature/migrate.sql +0 -2
  93. data/share/features/features.sql +0 -2
  94. data/share/features/features.yml +0 -2
  95. data/share/features/migrations.sql +0 -4
  96. data/share/gitignore +0 -2
  97. data/share/migration/diff.tables.sql +0 -8
  98. data/share/migration/features.yml +0 -6
  99. data/share/migration/migrate.sql +0 -3
  100. data/share/migration/migrate.yml +0 -8
  101. data/share/migration/tables.sql +0 -3
  102. data/share/schema/build.yml +0 -14
  103. data/share/schema/schema/build.yml +0 -3
  104. data/share/schema/schema/prick/build.yml +0 -14
  105. data/share/schema/schema/prick/data.sql +0 -7
  106. data/share/schema/schema/prick/schema.sql +0 -3
  107. data/share/schema/schema/public/build.yml +0 -13
  108. data/share/schema/schema.sql +0 -3
  109. data/test_assorted +0 -192
  110. data/test_feature +0 -112
  111. data/test_refactor +0 -34
  112. data/test_single_dev +0 -83
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: 70b51ae69f1d1cb0c2c27666273b0564d78f950de870104865203362258d40a2
4
- data.tar.gz: e3b46dbc411282c05977940551246a8bfff7689889648ac7e481974c67ef326f
3
+ metadata.gz: 2abdd6978f9dce4cf9570d2ad5165fef65541ed5e69bd6150086a30b232498a5
4
+ data.tar.gz: bb1accf8f541d7197c73b14407401d91d5e3b9475b205bad46bea8851d2825c6
5
5
  SHA512:
6
- metadata.gz: 0431efaa5b92fe0497f642bb5bd4f115f533417122c9f7f71d6de17aa7c65128d79c4a74cfe82ac8fa18b88d9b3aff6905744a3129f62b63f865c64d0e63292f
7
- data.tar.gz: 8e01993d41040f3d4db9f10d4aa461b420b81a5116836ba1cbb0cb298b75b2e9beaeb61ce3982ed21496ee459ab76e3f28ddf98c6f40fa17ad28c5f49ffcc97e
6
+ metadata.gz: 951dee9f87d7ba9475bf70512b35d29720a30ec5371e2c03c00575c21a94163f3aa43bf28bfbb6a5fe80e0da63cb1154bd84f29ae671651b7aa54de0e45630e2
7
+ data.tar.gz: cc5ef462d6c9ae5e1add6bb9fc53ffc4a6684c64020d24fad39327cd80218f01c031060f7c2e14a125a94caad305c658994e2ea53845f211909a4764a72f8d75
data/Gemfile CHANGED
@@ -1,9 +1,15 @@
1
- source "https://rubygems.org"
1
+ # frozen_string_literal: true
2
2
 
3
- git_source(:github) {|repo_name| "https://github.com/clrgit/#{repo_name}" }
3
+ source "https://rubygems.org"
4
4
 
5
- # Specify your gem's dependencies in prick.gemspec
5
+ # Specify your gem's dependencies in prick_build.gemspec
6
6
  gemspec
7
7
 
8
- gem "rake", "~> 12.0"
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
- # Prick
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/prick`. To experiment with that code, run `bin/console` for an interactive prompt.
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 'prick'
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 prick
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 tags, and push the `.gem` file to [rubygems.org](https://rubygems.org).
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]/prick.
35
+ Bug reports and pull requests are welcome on GitHub at https://github.com/[USERNAME]/prick_build.
data/Rakefile CHANGED
@@ -1,6 +1,8 @@
1
+ # frozen_string_literal: true
2
+
1
3
  require "bundler/gem_tasks"
2
4
  require "rspec/core/rake_task"
3
5
 
4
6
  RSpec::Core::RakeTask.new(:spec)
5
7
 
6
- task :default => :spec
8
+ task default: :spec
data/TODO CHANGED
@@ -1,13 +1,15 @@
1
1
 
2
- o Add a top-level 'global' directory for stuff that doesn't belong to a schema or that
3
- require superuser privileges. prick-build should then execute the content of that
4
- directory first before switching to the database user
5
- o Check for commits to tags
6
- o Accumulate version history in prick.versions instead of just having the newest
7
- o Using rc's in migration syntax: fork-version-fork-version.rc1 ?
8
- o Make it possible to execute prick in any subdirecty instead of only in the root
9
- o Hack migra to create separate file(s) for table changes
10
- o Also execute subject/ directory if only a subject.sql is found. subject.yml
11
- should still override everything
12
- o Track included files - this will make dependency checks much easier
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 "prick"
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
@@ -0,0 +1,14 @@
1
+
2
+ Format
3
+
4
+ ---
5
+ - schema: schema-name
6
+ - file
7
+ - seed: file
8
+ - seed:
9
+ - file
10
+ - file
11
+ - schema_init: file
12
+ - schema_term: file
13
+ - init: file
14
+ - term: file
data/exe/prick CHANGED
@@ -1,38 +1,250 @@
1
1
  #!/usr/bin/env ruby
2
2
 
3
- require 'prick.rb'
4
- require 'prick/program.rb'
3
+ #$LOAD_PATH.unshift "/home/clr/prj/shellopts/lib"
5
4
 
6
- require 'shellopts'
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 'tempfile'
18
+ require 'prick.rb'
19
+ require 'shellopts'
9
20
 
10
21
  include ShellOpts
11
22
  include Prick
12
23
 
13
- SPEC = %(
14
- -n,name=NAME
15
- Name of project. Defauls to the environment variable `PRICK_PROJECT` if
16
- set and else the name of the current directory
17
-
18
- -C,directory=DIR
19
- Change to directory DIR before doing anything else
24
+ TIME = false
20
25
 
21
- -h,help COMMAND...
22
- Print this page
26
+ SPEC = %(
27
+ @ Prick project command
23
28
 
24
29
  +v,verbose
25
- Be verbose. Repeated --verbose options increase the verbosity level
30
+ Be verbose. Repeated -v options increase the verbosity level
26
31
 
27
32
  -q,quiet
28
33
  Be quiet
29
34
 
30
- --version
31
- Print prick version
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)
190
+
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
32
244
 
33
- init! -u,user=USER [DIR]
34
- Initialize a project in the given directory. DIR defaults to the current
35
- directory. The USER is the postgres user, it defaults to the project name
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
36
248
 
37
249
  info!
38
250
  Print project information
@@ -51,11 +263,13 @@ SPEC = %(
51
263
  list.cache!
52
264
  List cache files
53
265
 
54
- build! -d,database=DATABASE -C,no-cache [TAG]
55
- Build the current database from the content in the schemas/ directory.
56
- With a tag the version is built into the associated versioned database
57
- and the result is saved to cache unless the -C option is given. The -d
58
- option overrides the default database
266
+ build! -d,database=DATABASE -s,state=FILE -C,no-cache [TAG]
267
+ Drop all users associated with the database before building the current
268
+ database from the content in the schemas/ directory. With a tag the
269
+ version is built into the associated versioned database and the result is
270
+ saved to cache unless the -C option is given. The -d option overrides the
271
+ default database and the -s option overrides the default state file
272
+ (fox.state)
59
273
 
60
274
  make! -d,database=DATABASE -C,no-cache [TAG]
61
275
  Build the current database from the content in the schemas/ directory.
@@ -77,8 +291,12 @@ SPEC = %(
77
291
  given file
78
292
 
79
293
  drop! -a,all [DATABASE]
80
- Drop the given database or all versioned databases. The --all option also
81
- drops the project database
294
+ Drop the given database or all versioned databases. Users with a username
295
+ on the form <database>__<username> are also dropped. The --all option
296
+ also drops the project database
297
+
298
+ drop.users! [DATABASE]
299
+ Drop users with a username on the form <database>__<username>
82
300
 
83
301
  diff! -m,mark -t,tables -T,notables
84
302
  diff [FROM-DATABASE|FROM-VERSION [TO-DATABASE|TO-VERSION]]
@@ -153,8 +371,15 @@ SPEC = %(
153
371
  in the var/spool directory
154
372
  )
155
373
 
374
+ __END__
375
+
376
+
377
+
156
378
 
157
379
 
380
+
381
+ DEFAULT_STATE_FILE = "fox.state"
382
+
158
383
  opts, args = ShellOpts.process(SPEC, ARGV)
159
384
 
160
385
  # Handle --help
@@ -185,6 +410,7 @@ begin
185
410
 
186
411
  # Create program object
187
412
  program = Program.new(quiet: opts.quiet?, verbose: opts.verbose?)
413
+ $verbose = opts.verbose? ? opts.verbose : nil
188
414
 
189
415
  # Handle init command
190
416
  if opts.subcommand == :init
@@ -236,7 +462,9 @@ begin
236
462
 
237
463
  when :build
238
464
  version = args.expect(0..1)
239
- program.build(opts.build!.database, version, opts.build!.no_cache?)
465
+ state_file = File.expand_path(opts.build!.state || DEFAULT_STATE_FILE)
466
+ FileUtils.rm_f(state_file)
467
+ program.build(opts.build!.database, version, state_file, opts.build!.no_cache?)
240
468
 
241
469
  when :make
242
470
  command = opts.make!
@@ -258,7 +486,15 @@ begin
258
486
  program.save(version, file)
259
487
 
260
488
  when :drop
261
- program.drop(args.expect(0..1), opts.drop!.all?)
489
+ command = opts.drop!
490
+ case command.subcommand
491
+ when :users
492
+ database = args.extract(0..1) || program.project.database.name
493
+ args.expect(0)
494
+ program.drop_users(database)
495
+ else
496
+ program.drop(args.expect(0..1), opts.drop!.all?)
497
+ end
262
498
 
263
499
  when :diff
264
500
  mark = opts.diff!.mark
@@ -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
+