Module: Prick::SubCommand
- Defined in:
- lib/prick-command.rb,
lib/prick/subcommand/prick-fox.rb,
lib/prick/subcommand/prick-run.rb,
lib/prick/subcommand/prick-set.rb,
lib/prick/subcommand/prick-bash.rb,
lib/prick/subcommand/prick-drop.rb,
lib/prick/subcommand/prick-init.rb,
lib/prick/subcommand/prick-list.rb,
lib/prick/subcommand/prick-make.rb,
lib/prick/subcommand/subcommand.rb,
lib/prick/subcommand/prick-build.rb,
lib/prick/subcommand/prick-clean.rb,
lib/prick/subcommand/prick-setup.rb,
lib/prick/subcommand/prick-touch.rb,
lib/prick/subcommand/prick-create.rb,
lib/prick/subcommand/prick-migrate.rb,
lib/prick/subcommand/prick-release.rb,
lib/prick/subcommand/prick-snapshot.rb,
lib/prick/subcommand/prick-teardown.rb
Constant Summary collapse
- PRICK_BUILD_FILES =
FIXME FIXME FIXME HARDCODED
%w(tables.sql views.sql functions.sql)
Class Method Summary collapse
- .bash(main: false) ⇒ Object
- .build(database, username, schema, builddir: Prick.state.schema_dir, force: false, step: false, timer: nil, dump: nil) ⇒ Object
-
.clean(database, exclude: %w(prick))) ⇒ Object
Drop users and hollow-out database.
- .create_database(database, username, environment) ⇒ Object
- .create_migration(username, from_version, force: false, file: nil) ⇒ Object
-
.drop_data(database, schemas = nil) ⇒ Object
Drop data not in snapshot.
-
.drop_database(database) ⇒ Object
Drop a database.
-
.drop_owner(username) ⇒ Object
Drop database owner.
-
.drop_schema(database, schemas = []) ⇒ Object
Empty the database.
-
.drop_users(database) ⇒ Object
Drop all users associated with the given database except the owner.
- .exist_database?(database) ⇒ Boolean
- .fox(database, username, files, builddir: Prick.state.schema_dir, reset: false, exclude: nil) ⇒ Object
-
.init(project_file, dir, name, title) ⇒ Object
FIXME: Ignores -p, -e, -s, -f options.
-
.init_database(database, username, environment) ⇒ Object
Setup prick schema.
- .list_databases(format: :long) ⇒ Object
- .list_environments(format: :long) ⇒ Object
- .list_owners(format: :long) ⇒ Object
- .list_users ⇒ Object
- .list_variables(format: :long, all: false) ⇒ Object
- .make(database, username, schema, step: false, timer: nil, dump: nil) ⇒ Object
-
.migrate(database, username, file: nil) ⇒ Object
def self.migrate(database, username, file) TODO.
- .owner_conn ⇒ Object
- .release(kind) ⇒ Object
- .run(database, username, path, step: false, timer: nil, dump: nil, schema: nil) ⇒ Object
- .set(variable, value = nil, arg = nil) ⇒ Object
-
.set_database(database, environment = nil) ⇒ Object
If the environment is nil, it is initialized from the database on next build.
- .set_duration(make_start) ⇒ Object
- .set_environment(environment) ⇒ Object
- .setup(database, username, environment) ⇒ Object
- .snapshot(database, username, builddir: Prick.state.schema_dir) ⇒ Object
- .super_conn ⇒ Object
- .teardown(*databases, remove_state_file: false) ⇒ Object
- .touch(success) ⇒ Object
Class Method Details
.bash(main: false) ⇒ Object
18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 |
# File 'lib/prick/subcommand/prick-bash.rb', line 18 def self.bash(main: false) # IO.capture { env = Prick.state.environment # Shorthands envs = Prick.state.environments puts "#!/usr/bin/bash" puts puts "# This file is auto-generated by prick. Please don't touch" puts puts ". bash.include" puts # Emit environment. PRICK_ENVIRONMENT_BUILD is excluded because its value # is bash source that is hard to escape and there is no use for this # variable anyway puts "### ENVIRONMENT by state.rb" puts puts Prick.state.bash_source(scope: :global) puts # Emit script if env envs.bash_command env else envs.bash_command end if main puts "### MAIN by prick-load.rb" puts puts "build" end # } end |
.build(database, username, schema, builddir: Prick.state.schema_dir, force: false, step: false, timer: nil, dump: nil) ⇒ Object
6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 |
# File 'lib/prick/subcommand/prick-build.rb', line 6 def self.build( database, username, schema, builddir: Prick.state.schema_dir, force: false, # Build all schemas step: false, timer: nil, dump: nil) Timer.on! if timer Timer.time "Prick::Command#build" do begin super_conn = State.connection # Used to create new databases (doesn't make a # difference right now as the database user is # a superuser anyway conn = nil builder = nil constrain super_conn.rdbms.exist?(database), true # FIXME Same problem as below Timer.time "Load build object" do if super_conn.rdbms.exist? database # FIXME Why create database? Setup should have done this exist = true else super_conn.rdbms.create database, owner: username exist = false end conn = Prick.state.connection builder = Prick::Build::Builder.new(conn, builddir, step: step) if exist # Empty (part of) the database if force # Drop all schemas and re-create the public schema. The prick # schema is only dropped if :force is true # builder.pool.delete_schema("prick") if super_conn.schema.exist?("prick") && !force # super_conn.rdbms.empty!(database, public: false, exclude: (force ? [] : ["prick"])) # Drop all schemas except the prick schema and re-creates the # public schema # builder.pool.delete_schema("prick") if super_conn.schema.exist?("prick") # super_conn.rdbms.empty!(database, public: false, exclude: ["prick"]) super_conn.rdbms.empty!(database, public: false) Prick::SubCommand::init_database(database, username) else # Find all schemas refresh_schemas = conn.schema.list # Find existing keep-schemas (but exclude target schema) keep_schemas = builder.keep_schemas.select { |s| conn.schema.exist?(s) && (schema.nil? || schema != s) } # Remove keep-schemas from list of schemas refresh_schemas -= keep_schemas # Also remove keep-schemas from the build pool. TODO Why don't we # use the pool tracker's list of keep schemas? builder.pool.delete_schema(keep_schemas) # Drop refresh schemes refresh_schemas.each { |s| conn.schema.drop(s, cascade: true) } end end # Delete schemas that comes after the target in the build sequence if # 'prick build' was given a schema builder.pool.delete_schema(builder.pool.after_schema(schema)) if schema end case dump when :nodes; builder.nodes.reject { |node| node.is_a?(Build::BuildNode) }.map &:dump when :allnodes; builder.nodes.map &:dump when :batches; builder.dump when nil; else Prick.error "Illegal dump type: #{dump.inspect}" end && exit Timer.time "Execute build object" do builder.execute conn end # rescue Prick::Error => ex # $stderr.puts ex.message # exit 1 rescue ::Command::Error => ex $stderr.puts ex. exit 1 ensure super_conn&.terminate conn&.terminate end end end |
.clean(database, exclude: %w(prick))) ⇒ Object
Drop users and hollow-out database. This has the same as effect as teardown+setup but without recreating the database owner and the database which would otherwise terminate all user sessions
9 10 11 12 13 14 |
# File 'lib/prick/subcommand/prick-clean.rb', line 9 def self.clean(database, exclude: %w(prick)) Prick::SubCommand.drop_users(database) State.connection { |conn| conn.rdbms.empty!(database, exclude: exclude) if conn.rdbms.exist?(database) } end |
.create_database(database, username, environment) ⇒ Object
9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 |
# File 'lib/prick/subcommand/prick-create.rb', line 9 def self.create_database(database, username, environment) super_conn = State.connection # Create user if absent if !super_conn.role.exist? username # FIXME Should not be created as superuser but we can't do that before we # have a super: option in build so that superuser-requiring function # definitions can be built super_conn.role.create username, superuser: true, can_login: true, create_role: true end # Create database super_conn.rdbms.create database, owner: username # Initialize prick schema init_database database, username, environment end |
.create_migration(username, from_version, force: false, file: nil) ⇒ Object
50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 |
# File 'lib/prick/subcommand/prick-create.rb', line 50 def self.create_migration(username, from_version, force: false, file: nil) constrain from_version, PrickVersion Git.clean? or raise "Won't migrate: Repository is dirty" Git.synchronized? or raise "Won't migrate: Repository is not synchronized" from_version != PrickVersion.zero or Prick.error "Can't migrate from release 0.0.0" to_version = Prick.state.version migration_dir = "#{MIGRATION_DIR}/#{from_version}" migration_exist = File.directory? migration_dir force || file || !migration_exist or Prick.failure "Migration #{from_version} exists" $quiet = true if file if file && migration_exist File.open(file, "w") { |file| for diff_file in DIFF_FILES file.write File.read("#{migration_dir}/#{diff_file}") end } else from_version != to_version or Prick.failure "Can't migrate to same release" from_version < to_version or Prick.failure "Can't migrate backwards (why not?)" diff = nil if force || !migration_exist from_db = "#{Prick.state.name}-#{from_version}" to_db = "#{Prick.state.name}-#{to_version}" mesg "Migrating from #{from_version} to #{to_version}" begin origin = Git.origin # Local repos are supported to ease testing if File.directory?(origin) origin = File.(origin) end diff = Dir.mktmpdir { |tmpdir| Dir.chdir(tmpdir) { mesg " Building #{from_db}" Git.clone(origin, from_version, branch: from_version) Dir.chdir(from_version.to_s) { build(from_db, username, nil) } } mesg " Building #{to_db}" build(to_db, username, nil) mesg " Creating diff" Diff.new(from_db, to_db) } !diff.same? or Prick.failure "No changes" ensure drop_all(from_db) # FIXME This will fail, maybe use teardown instead? drop_all(to_db) end end diff.write(file) if file end if file File.open(file, "a") { |f| f.puts "-- UPDATE VERSION" f.puts File.readlines(SCHEMA_VERSION_PATH).grep_v(/^--/) } else FileUtils.rm_rf migration_dir if force FileUtils.mkdir_p migration_dir Command.command "cp -a #{SHARE_PATH}/migrate/migration/. #{migration_dir}" Dir.chdir(migration_dir) { diff.write(*DIFF_FILES, mark: true) } end end |
.drop_data(database, schemas = nil) ⇒ Object
Drop data not in snapshot
46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 |
# File 'lib/prick/subcommand/prick-drop.rb', line 46 def self.drop_data(database, schemas = nil) conn = Prick.state.conn conn.session.triggers(false) { if schemas.nil? builder = Prick::Build::Builder.new(conn, Prick.state.schema_dir) pool = builder.pool schemas = pool.refresh_schemas end schema_list = conn.quote_values(schemas) schema_expr = schemas ? "true = true" : "schema_name in (#{schema_list})" tables = conn.tuples %( select schema_name, table_name, max_id from prick.snapshots where #{schema_expr} ) tables.each { |schema, table, max_id| uid = "#{schema}.#{table}" if max_id conn.exec "delete from #{uid} where id > #{max_id}" conn.schema.set_serial(schema, table, max_id) if conn.schema.sequence(schema, table) else conn.exec "delete from #{uid}" conn.schema.set_serial(schema, table, nil) if conn.schema.sequence(schema, table) end } } end |
.drop_database(database) ⇒ Object
Drop a database
40 41 42 43 |
# File 'lib/prick/subcommand/prick-drop.rb', line 40 def self.drop_database(database) State.connection.session.terminate(database, nil) State.connection { |conn| conn.rdbms.drop database } end |
.drop_owner(username) ⇒ Object
Drop database owner
7 8 9 10 11 12 13 |
# File 'lib/prick/subcommand/prick-drop.rb', line 7 def self.drop_owner(username) # No database at this point so no session is running and no cascade. A nop # if the user is the current user or owns objects in other databases if username != ENV['USER'] super_conn.role.drop(username, fail: false, silent: true) end end |
.drop_schema(database, schemas = []) ⇒ Object
Empty the database
75 76 77 78 79 80 81 82 83 84 85 |
# File 'lib/prick/subcommand/prick-drop.rb', line 75 def self.drop_schema(database, schemas = []) constrain database, String constrain schemas, [String] if schemas.empty? State.connection { |conn| conn.rdbms.empty!(database, exclude: "prick") } else Prick.state.connection { |conn| schemas.each { |schema| conn.schema.drop(schema, cascade: true) } } end end |
.drop_users(database) ⇒ Object
Drop all users associated with the given database except the owner. We assume that users can only be connected to the project database and that they don’t own objects in other databases
18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 |
# File 'lib/prick/subcommand/prick-drop.rb', line 18 def self.drop_users(database) constrain database, String conn = super_conn if conn.rdbms.exist? database users = conn.role.list(database: database).reject { _1 == conn.rdbms.owner(database) } conn.session.terminate(database, users) if conn.rdbms.exist?(database) # Connect to database to make cascade work. Run in a block to close connection afterwards PgConn.new(database) { |conn| conn.role.drop(users, cascade: true) } else conn.rdbms.role.drop(users) end else # We don't terminate sessions because we assume one-database-users # FIXME: users is undefined raise NotImpementedError conn.role.drop(users, cascade: true) # Fails if the users owns objects in other databases end end |
.exist_database?(database) ⇒ Boolean
5 6 7 |
# File 'lib/prick/subcommand/prick-create.rb', line 5 def self.exist_database?(database) State.connection.rdbms.exist? database end |
.fox(database, username, files, builddir: Prick.state.schema_dir, reset: false, exclude: nil) ⇒ Object
6 7 8 9 10 11 12 13 14 15 16 17 18 19 |
# File 'lib/prick/subcommand/prick-fox.rb', line 6 def self.fox(database, username, files, builddir: Prick.state.schema_dir, reset: false, exclude: nil) self.drop_data(database) if reset # In prick-drop conn = Prick.state.connection builder = Prick::Build::Builder.new(conn, builddir) exclude = (exclude || []) + builder.pg_graph_ignore_schemas opts = { state: FOX_STATE_PATH, delete: "none", exec: true, exclude: (exclude ? exclude.join(',') : nil), reflections: Prick.state.reflections_file }.reject { |k,v| v.nil? }.map { |k,v| "--#{k}#{v == true ? "" : "=#{v}"}" }.join(" ") Command.command "fox #{opts} #{database} #{files.join(" ")}" end |
.init(project_file, dir, name, title) ⇒ Object
FIXME: Ignores -p, -e, -s, -f options
5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 |
# File 'lib/prick/subcommand/prick-init.rb', line 5 def self.init(project_file, dir, name, title) # dir, name, and title can be nil cwd = Dir.getwd if dir !File.exist?(dir) or Prick.error "Directory #{dir} exists" FileUtils.mkdir_p(dir) Dir.chdir(dir) else dir = "." end dirname = File.basename(Dir.getwd) name ||= dirname title ||= name.gsub(/[_-]/, " ").capitalize # Note that the initial project file is invalid and is removed again after # the initial commit Command.command %( git init . dir=#{SHARE_PATH}/init for path in $dir/*; do source_file=$(basename $path) dest_file=$(sed 's/^dot\././' <<<$source_file) cp -a $dir/$source_file $dest_file done git add . git commit -am "Initial import" rm -f #{project_file} ), fail: false Command.status == 0 or Prick.failure "Failed creating initial import" # Write (valid) configuration file state = State.new(project_file, nil, nil, nil, nil) state.name = name state.title = title state.prick_version = PrickVersion.new VERSION state.version = PrickVersion.new("0.0.0") state.save_project # Commit configuration file and create initial release Command.command %( set -e git add #{project_file} git commit -am "Release 0.0.0" git tag --message "Initial Release" v0.0.0 ), fail: false Command.status == 0 or Prick.failure "Failed creating initial release" Dir.chdir(cwd) [dir, name] end |
.init_database(database, username, environment) ⇒ Object
Setup prick schema. Used when we rebuild the prick schema without disconnecting users
29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 |
# File 'lib/prick/subcommand/prick-create.rb', line 29 def self.init_database(database, username, environment) # Setup Prick schema. Note that this is hardcoded, the prick build file # is ignored conn = PgConn.new(database, username) # Can't use Prick.state.connection on a new database conn.schema.create("prick") PRICK_BUILD_FILES.each { |file| conn.exec(IO.read("#{SCHEMA_PRICK_DIR}/#{file}")) } # Add initial build record state = Prick.state # shorthand conn.insert "prick.builds", name: state.title, version: state.version, prick: state.prick_version, branch: state.branch, rev: state.rev(kind: :short), clean: state.clean?, environment: environment || Prick::DEFAULT_ENVIRONMENT, built_at: nil, success: nil end |
.list_databases(format: :long) ⇒ Object
37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 |
# File 'lib/prick/subcommand/prick-list.rb', line 37 def self.list_databases(format: :long) constrain format, :long, :short conn = State.connection # databases = conn.values "select datname from pg_database where datistemplate = false order by datname;" if format == :short puts Prick.databases else # Timestamp of newest file under git control newest_file = Command.command("ls -tr #{Git.list.join(" ")} | tail -1", stderr: false, fail: false).last fs_time = File.mtime(newest_file) git_branch = Git.branch.current git_rev = Git.id[0...8] rows = [] current_database_row = nil Prick.databases { |database, conn| row = conn.record(%( select '#{database}' as "database", name, version, branch, rev, clean, environment, built_at, success from prick.versions )) # Detect if this is the current database if Prick.state.database == database is_current_database = true current_database_row = rows.size end if row[:success] clean = row[:clean] same_revision = row[:branch] == git_branch && row[:rev] == git_rev up2date = fs_time <= row[:built_at] # Set state row[:state] = case [clean, same_revision, up2date] in [true, true, true]; "clean" # Built from clean repo in [true, true, false]; "ok" # Clean repo but doesn't include latest uncommitted changes in [true, false, _]; "clean" # Clean repo but different revision in [false, true, true]; "edge" # Dirty repo, work-in-progress in [false, true, false]; "dirty" # Dirty repo and doesn't include latest changes in [false, false, _]; "stale" # Dirty repo, no way back end elsif row[:success] == false row[:state] = "fail" else row[:state] = "-" end # Convert built_at to string row[:built_at] = row[:built_at]&.strftime("%Y-%m-%d %H:%M") # Add current database marker last_column = (is_current_database ? "*" : "") rows << row.values + [last_column] } headers = %w(database project version branch rev clean environment built success state) + [" "] Fmt.puts_table(headers, rows, bold: current_database_row) end end |
.list_environments(format: :long) ⇒ Object
2 3 4 5 6 7 8 9 10 11 |
# File 'lib/prick/subcommand/prick-list.rb', line 2 def self.list_environments(format: :long) environments = Prick.state.environments.values.select { |env| env.comment } if format == :short puts environments.map(&:name) else headers = %w(Environment Description) rows = environments.map { |env| [env.name, env.comment] } Fmt.puts_table(headers, rows) end end |
.list_owners(format: :long) ⇒ Object
108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 |
# File 'lib/prick/subcommand/prick-list.rb', line 108 def self.list_owners(format: :long) owners = {} Prick.databases.each { |database| # owner = super_conn.rdbms.exist?(d) ? super_conn.rdbms.owner(d) : d owner = super_conn.rdbms.owner(database) (owners[owner] ||= []) << database } if format == :short puts owners.keys else headers = %w(username databases) + [" "] rows = owners.map { |owner, databases| current_user_mark = (Prick.state.username == owner ? '*' : "") [owner, databases.join(","), current_user_mark] } Fmt.puts_table(headers, rows) end end |
.list_users ⇒ Object
104 105 106 |
# File 'lib/prick/subcommand/prick-list.rb', line 104 def self.list_users puts State.connection.role.list(database: Prick.state.database) end |
.list_variables(format: :long, all: false) ⇒ Object
13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 |
# File 'lib/prick/subcommand/prick-list.rb', line 13 def self.list_variables(format: :long, all: false) if format == :short puts Prick.state.bash_environment(all: all).keys else headers = %w(variable value) vars = Prick.state.bash_environment(all: all).reject { |k,v| k == "PATH" } rows = vars.map # rows = vars.map { |k,v| # if v.is_a?(Array) # if v.first&.is_a?(Array) # v = v.first # else # v = v.join(" ") # end # else # v = v.to_s # end # # [k, v] # } Fmt.puts_table(headers, rows) end end |
.make(database, username, schema, step: false, timer: nil, dump: nil) ⇒ Object
6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 |
# File 'lib/prick/subcommand/prick-make.rb', line 6 def self.make(database, username, schema, step: false, timer: nil, dump: nil) Timer.on! if timer Timer.time "Prick::Command#make" do begin super_conn = State.connection conn = nil builder = nil last_built_at = EPOCH clean = false create_schemas = [] Timer.time "Load build object" do if super_conn.rdbms.exist? database conn = Prick.state.connection if conn.schema.exist_relation?("prick", "versions") && !conn.empty?("prick.versions") last_built_at = conn.value("select built_at from prick.versions") end else super_conn.rdbms.create database, owner: username conn = Prick.state.connection clean = true end builder = Prick::Build::Builder.new(conn, "schema", clean, step: step) if schema after_schemas = builder.pool.after_schema(schema) refresh_schemas = builder.pool.refresh_schemas conn.schema.drop(schema, cascade: true) # Marks it dirty # Nuke later schemas # FIXME Not a good idea when sitting on a leaf schema. # Forced-delete could be requested using 'prick make schema' # (after_schemas & refresh_schemas).each { |drop_schema| conn.schema.drop(drop_schema, cascade: true) } after_schemas.each { |delete_schema| builder.pool.delete_schema(delete_schema) } end touched_nodes = builder.nodes.select { |node| last_built_at.nil? || File.mtime(node.path) > last_built_at } touched_phases = touched_nodes.map(&:phase).uniq.compact touched_kinds = touched_nodes.map(&:kind).uniq.compact touched_schema = touched_nodes.first&.schema missing_schema = builder.schemas.find { |schema| !conn.schema.exist?(schema) } build_schema = builder.schemas.find { |schema| [touched_schema, missing_schema].include? schema } if build_schema.nil? puts "#{database} is up to date" exit end if touched_phases.include?(:decl) || touched_phases.empty? create_schemas = [build_schema] + builder.pool.after_schema(build_schema) create_schemas.each { |schema| conn.schema.drop(schema, cascade: true) } builder.pool.delete_schema(builder.pool.before_schema(build_schema), exclude: [:seed]) elsif touched_phases.include?(:init) || touched_phases.include?(:term) builder.pool.clear(:decl, :seed) elsif touched_phases.include?(:seed) builder.pool.clear(:init, :decl, :term) end # builder.group end case dump when :nodes; builder.nodes.reject { |node| node.is_a?(Build::BuildNode) }.map &:dump when :allnodes; builder.nodes.map &:dump when :batches; builder.dump when nil; else Prick.error "Illegal dump type: #{dump.inspect}" end exit if dump Timer.time "Execute build object" do builder.execute(conn, create_schemas: create_schemas) end rescue Prick::Build::Error => ex $stderr.puts ex. exit 1 rescue Command::Error => ex $stderr.puts ex. exit 1 end end end |
.migrate(database, username, file: nil) ⇒ Object
def self.migrate(database, username, file) TODO
5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 |
# File 'lib/prick/subcommand/prick-migrate.rb', line 5 def self.migrate(database, username, file: nil) conn = Prick.state.connection # PgConn.new(database, username) { |conn| conn.schema.exist_relation? "prick", "versions" or Prick.failure "Can't read version from database" from_version = PrickVersion.new(conn.value "select version from prick.versions") or Prick.failure "Illegal version in table prick.versions" if file conn.transaction { conn.exec File.read(file) } else to_version = Prick.state.version from_version != to_version or Prick.failure "Already up to date" from_version < to_version or Prick.failure "Can't migrate backwards" migration_dir = "#{MIGRATION_DIR}/#{from_version}" File.directory? migration_dir or Prick.failure "Can't migrate from #{from_version} to #{to_version}" puts "Migrating from #{from_version} to #{to_version}" builder = Prick::Build::Builder.new(conn, migration_dir) conn.transaction { builder.execute conn conn.exec File.read(SCHEMA_VERSION_PATH) } end # } end |
.owner_conn ⇒ Object
119 |
# File 'lib/prick-command.rb', line 119 def self.owner_conn = Prick.owner_conn |
.release(kind) ⇒ Object
4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 |
# File 'lib/prick/subcommand/prick-release.rb', line 4 def self.release(kind) constrain kind, :major, :minor, :patch Git.clean? or raise "Won't release: Repository is dirty" Git.synchronized? or raise "Won't release: Repository is not synchronized with origin" version = Prick.state.version.increment!(kind).to_s Prick.state.save_project(overwrite: true) Git.add(Prick.state.project_file) Git.add(Prick.state.schema_file) Git.commit "Release #{version}" Git.tag.create "v#{version}" Git.branch.create version Git.push # TODO TODO TODO puts version end |
.run(database, username, path, step: false, timer: nil, dump: nil, schema: nil) ⇒ Object
6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 |
# File 'lib/prick/subcommand/prick-run.rb', line 6 def self.run(database, username, path, step: false, timer: nil, dump: nil, schema: nil) Timer.on! if timer Timer.time "Prick::Command#build" do begin super_conn = State.connection # Used to create new databases (doesn't make a # difference right now as the database user is # a superuser anyway conn = nil builder = nil constrain super_conn.rdbms.exist?(database), true # FIXME Same problem as below. Also in other commands Timer.time "Load build object" do if super_conn.rdbms.exist? database # FIXME Why create database? Setup should have done this exist = true else super_conn.rdbms.create database, owner: username exist = false end conn = Prick.state.connection # Parse builder = Prick::Build::Builder.new(conn, path, single: true, load_pool: false, step: step) # Register if a build file is referenced and normalize path to # include build.yml of directories if File.directory?(path) path = File.join(path, "build.yml") is_build_file = true elsif File.basename(path) == "build.yml" is_build_file = true else is_build_file = false end # Read schema from build file if possible and decide if schema should # be dropped beforehand if is_build_file if builder.root.has_schema !schema or Prick.error "Can't use --schema when doing a schema build" is_schema_rebuild = true schema = build_node.schema else is_schema_rebuild = false end else is_schema_rebuild = false end # Infer schema from path if !schema abspath = File.realpath(path) schemapath = File.realpath(Prick.state.schema_dir) if abspath =~ /^#{schemapath}\/([^\/]+)(?:\/.*)$/ schema = $1 else Prick.error "Can't find schema" # No default schema to avoid unintended runs end end # Write back schema to builder builder.root.schema = schema # Drop schema if needed if is_schema_rebuild conn.schema.drop schema, cascade: true end # Create schema if absent if !conn.schema.exist?(schema) conn.schema.create(schema) end end if dump builder.load_pool case dump when :nodes; builder.nodes.reject { |node| node.is_a?(Build::BuildNode) }.map &:dump when :allnodes; builder.nodes.map &:dump when :batches; builder.dump else Prick.error "Illegal dump type: #{dump.inspect}" end else Timer.time "Execute build object" do builder.execute conn end end # FIXME # rescue Prick::Error => ex # $stderr.puts ex.message # exit 1 # # rescue ::Command::Error => ex # $stderr.puts ex.message # exit 1 ensure super_conn&.terminate conn&.terminate end end end |
.set(variable, value = nil, arg = nil) ⇒ Object
4 5 6 7 8 9 10 11 12 13 |
# File 'lib/prick/subcommand/prick-set.rb', line 4 def self.set(variable, value = nil, arg = nil) case variable when "database"; set_database(value, arg) when "environment"; set_environment(value) when "duration"; set_duration(value) else return false end true end |
.set_database(database, environment = nil) ⇒ Object
If the environment is nil, it is initialized from the database on next build
25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 |
# File 'lib/prick/subcommand/prick-set.rb', line 25 def self.set_database(database, environment = nil) if database conn = State.connection conn.rdbms.exist? database or Prick.error "Database '#{database}' does not exist" username = conn.rdbms.owner database Prick.state.database = database Prick.state.username = username if environment.nil? Prick.state.connection # Implicitly initialize database enviroment if present environment = Prick.state.database_environment # or Prick.error "Can't find environment" end Prick.state.environment = environment Prick.state.save_state else puts Prick.state.database end end |
.set_duration(make_start) ⇒ Object
45 46 47 48 49 50 |
# File 'lib/prick/subcommand/prick-set.rb', line 45 def self.set_duration(make_start) conn = Prick.state.connection built_at = conn.value "select built_at from prick.versions" duration = Time.now - Time.iso8601(make_start) conn.exec "update prick.versions set make_duration = #{duration}" end |
.set_environment(environment) ⇒ Object
15 16 17 18 19 20 21 22 |
# File 'lib/prick/subcommand/prick-set.rb', line 15 def self.set_environment(environment) if environment Prick.state.environment = environment Prick.state.save_state else puts Prick.state.environment end end |
.setup(database, username, environment) ⇒ Object
6 7 8 9 |
# File 'lib/prick/subcommand/prick-setup.rb', line 6 def self.setup(database, username, environment) create_database(database, username, environment) set_database(database, environment) end |
.snapshot(database, username, builddir: Prick.state.schema_dir) ⇒ Object
6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 |
# File 'lib/prick/subcommand/prick-snapshot.rb', line 6 def self.snapshot( database, username, builddir: Prick.state.schema_dir) conn = Prick.state.connection builder = Prick::Build::Builder.new(conn, builddir) pool = builder.pool schemas = pool.refresh_schemas # Clear snapshots table conn.exec "delete from prick.snapshots" # Fill it again records = [] for schema in schemas conn.schema.list_tables(schema).each { |table| max_id = conn.value "select max(id) from #{schema}.#{table}" records << { schema_name: schema, table_name: table, max_id: max_id} } end conn.insert("prick", "snapshots", records) # Patch fox state file state = YAML.load(IO.read(Prick.state.fox_state_file)) for record in records state[:ids][record[:schema_name] + '.' + record[:table_name]] = record[:max_id] if record[:max_id] end IO.write(Prick.state.fox_state_file, YAML.dump(state)) end |
.super_conn ⇒ Object
120 121 |
# File 'lib/prick-command.rb', line 120 def self.super_conn = Prick.super_conn # def self.conn = Prick.conn |
.teardown(*databases, remove_state_file: false) ⇒ Object
6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 |
# File 'lib/prick/subcommand/prick-teardown.rb', line 6 def self.teardown(*databases, remove_state_file: false) databases = Array(databases).flatten owners = databases.map { |d| super_conn.rdbms.exist?(d) ? super_conn.rdbms.owner(d) : d }.uniq users = databases.map { |d| super_conn.role.list(database: d) }.flatten.uniq databases.each { |d| drop_database(d) } super_conn.role.drop(users) super_conn.role.drop(owners, fail: false) owners.each { |o| drop_owner(o) } FileUtils.rm_f Prick.state.state_file if remove_state_file # TODO Run builder teardown scrips end |