Module: Prick

Defined in:
lib/prick.rb,
lib/prick/diff.rb,
lib/prick/state.rb,
lib/prick-command.rb,
lib/prick-command.rb,
lib/prick-command.rb,
lib/prick/version.rb,
lib/prick/constants.rb,
lib/prick/local/git.rb,
lib/prick/environment.rb,
lib/prick/builder/node.rb,
lib/prick/builder/batch.rb,
lib/prick/prick_version.rb,
lib/prick/builder/parser.rb,
lib/prick/builder/builder.rb,
lib/prick/builder/node_pool.rb,
lib/prick/subcommand/prick-create.rb,
lib/prick/subcommand/prick-migrate.rb,
lib/prick/subcommand/prick-release.rb

Overview

Project related code starts here

Defined Under Namespace

Modules: Build, Git, SubCommand Classes: Diff, Environment, Environments, Error, Failure, PrickVersion, State

Constant Summary collapse

VERSION =
"0.45.1"
EPOCH =

TIME

Time.at(0).utc
SHARE_PATH =

Shared files (part of the installation)

"#{File.dirname(File.dirname(__dir__))}/lib/prick/share"
LIBEXEC_PATH =
"#{File.dirname(File.dirname(__dir__))}/lib/prick/libexec"
DIRS =

Project directories (relative to PRICK_DIR)

[
  MIGRATION_DIR = "migration",
  SCHEMA_DIR = "schema",
  SCHEMA_PRICK_DIR = "#{SCHEMA_DIR}/prick",
  PUBLIC_DIR = "#{SCHEMA_DIR}/public",
  BIN_DIR = "bin",
  LIBEXEC_DIR = "libexec",
  VAR_DIR = "var",
  CACHE_DIR = "#{VAR_DIR}/cache",
  SPOOL_DIR = "#{VAR_DIR}/spool",
  TMP_DIR = "tmp",
  CLONE_DIR = "tmp/clones",
  SPEC_DIR = "spec"
]
PRICK_PROJECT_FILE =

Project filename

"prick.yml"
PRICK_DIR =
begin
  dir = Dir.getwd
  while dir != "/" && !File.exist?("#{dir}/prick.yml")
    dir = File.dirname(dir)
  end
  if dir == "/"
    defined?(RSpec) or raise ArgumentError, "Can't find prick project directory"
    dir = ""
  end
  dir
end
PRICK_PROJECT_PATH =

Project file path

File.join(PRICK_DIR, PRICK_PROJECT_FILE)
PRICK_ENVIRONMENT_FILE =

Environment file

"prick.environment.yml"
PRICK_ENVIRONMENT_PATH =
File.join(PRICK_DIR, PRICK_ENVIRONMENT_FILE)
PRICK_STATE_FILE =

State file

".prick.state.yml"
PRICK_STATE_PATH =
File.join(PRICK_DIR, PRICK_STATE_FILE)
FOX_STATE_FILE =

Fox state file (contains anchors and table sizes)

".fox-state.yml"
FOX_STATE_PATH =
File.join(PRICK_DIR, FOX_STATE_FILE)
PG_META_STATE_FILE =

PgMeta snapshot. Is deleted at the start of each build

".pg_meta-state.yml"
PG_META_STATE_PATH =
File.join(PRICK_DIR, PG_META_STATE_FILE)
REFLECTIONS_FILE =

Reflections file

"reflections.yml"
REFLECTIONS_PATH =
File.join(SCHEMA_DIR, REFLECTIONS_FILE)
SCHEMA_VERSION_FILE =

Schema data file

"data.sql"
SCHEMA_VERSION_PATH =
File.join(SCHEMA_PRICK_DIR, SCHEMA_VERSION_FILE)
SPEC_TMP_DIR =

Rspec temporary directory

"spec"
SPEC_TMP_PATH =
File.join(TMP_DIR, SPEC_TMP_DIR)
DIFF_FILE =

Migration diff files

"diff.sql"
DIFF_FILES =
[
  BEFORE_TABLES_DIFF_FILE = "diff.before-tables.sql",
  TABLES_DIFF_FILE = "diff.tables.sql",
  AFTER_TABLES_DIFF_FILE = "diff.after-tables.sql"
]
DEFAULT_ENVIRONMENT =

Default environment

"default"
PROJECT_STATE_FILE =

The project state file

".prick-project"
PROJECT_STATE_PATH =
File.join(PRICK_DIR, PROJECT_STATE_FILE)
PRICK_MIGRATION_FILE =

The the .prick-migration file

".prick-migration"
PRICK_MIGRATION_PATH =
File.join(MIGRATION_DIR, PRICK_MIGRATION_FILE)
PRICK_FEATURE_FILE =

The the .prick-feature file

".prick-feature"
PRICK_FEATURE_PATH =
File.join(MIGRATION_DIR, PRICK_FEATURE_FILE)
STRIP_COMMENTS_NAME =

The strip-comments executable

"strip-comments"
STRIP_COMMENTS_PATH =
File.join(LIBEXEC_PATH, "strip-comments")
DUMP_EXT =

Dump files

"dump.gz"
DUMP_GLOB =
"*-[0-9]*.#{DUMP_EXT}"
NAME_SUB_RE =

Matches a system name. System names are used for objects that are external to prick (like usernames)

/[a-z][a-z0-9_-]*/
NAME_RE =
/^#{NAME_SUB_RE}$/
IDENT_SUB_RE =

Matches an identifier. Identifiers consist of lower case letters, digits and underscores but not dashes because they’re used as separators

/[a-z][a-z0-9_]*/
IDENT_RE =
/^#{IDENT_SUB_RE}$/
PROJECT_NAME_SUB_RE =

Matches a project name

IDENT_SUB_RE
PROJECT_NAME_RE =
IDENT_RE
CUSTOM_NAME_SUB_RE =

Matches a custom name

IDENT_SUB_RE
CUSTOM_NAME_RE =
IDENT_RE
FEATURE_NAME_SUB_RE =

Matches a feature name

/(?!initial)#{IDENT_SUB_RE}/
FEATURE_NAME_RE =
/^#{FEATURE_NAME_SUB_RE}$/
USER_NAME_SUB_RE =

Matches a postgres user name

NAME_SUB_RE
USER_NAME_RE =
NAME_RE
MMP_SEMVER_SUB_RE =

Matches a major.minor.patch (‘MMP’) version

The *_SEMVER REs are derived from the canonical RE

/

(0|[1-9]\d*)\.(0|[1-9]\d*)\.(0|[1-9]\d*)
(?:-((?:0|[1-9]\d*|\d*[a-zA-Z-][0-9a-zA-Z-]*)(?:\.(?:0|[1-9]\d*|\d*[a-zA-Z-][0-9a-zA-Z-]*))*))?
(?:\+([0-9a-zA-Z-]+(?:\.[0-9a-zA-Z-]+)*))?

/x

semver.org/#is-there-a-suggested-regular-expression-regex-to-check-a-semver-string.

/(?:0|[1-9]\d*)\.(?:0|[1-9]\d*)\.(?:0|[1-9]\d*)/
MMP_SEMVER_RE =
/^#{MMP_SEMVER_SUB_RE}$/
PRE_SEMVER_SUB_RE =

Matches the prelease part of a semantic version

/pre\.\d+/
PRE_SEMVER_RE =
/^#{PRE_SEMVER_SUB_RE}$/
SEMVER_SUB_RE =

Matches a semantic version

/#{MMP_SEMVER_SUB_RE}(?:-#{PRE_SEMVER_SUB_RE})?/
SEMVER_RE =
/^#{SEMVER_SUB_RE}$/
TAG_SUB_RE =

Tag RE. The general syntax for a tag is ‘<custom>-v<version>_<feature>’

The RE defines the following captures:

$1 - custom name, can be nil
$2 - semantic version
$3 - feature name, can be nil
/
    (?:(#{CUSTOM_NAME_SUB_RE})-)?
    v
    (#{SEMVER_SUB_RE})
    (?:_(#{FEATURE_NAME_SUB_RE}))?
/x
TAG_RE =
/^#{TAG_SUB_RE}$/
BRANCH_SUB_RE =

Branch RE. The general syntax for a branch is ‘<custom>-<version>_<feature>’

The RE defines the following captures:

$1 - custom name, can be nil
$2 - semantic version
$3 - feature name, can be nil
/
    (?:(#{CUSTOM_NAME_SUB_RE})-)?
    (#{SEMVER_SUB_RE})
    (?:_(#{FEATURE_NAME_SUB_RE}))?
/x
BRANCH_RE =
/^#{BRANCH_SUB_RE}$/
VERSION_SUB_RE =

Tag or branch RE. The general syntax for a branch is ‘<custom>-v?<version>_<feature>’

The RE defines the following captures:

$1 - custom name, can be nil
$2 - tag, nil or 'v'
$3 - semantic version
$4 - feature name, can be nil
/
    (?:(#{CUSTOM_NAME_SUB_RE})-)?
    (v)?
    (#{SEMVER_SUB_RE})
    (?:_(#{FEATURE_NAME_SUB_RE}))?
/x
VERSION_RE =
/^#{VERSION_SUB_RE}$/
ABSTRACT_RELEASE_SUB_RE =

Matches an abstract release (either a release or a prerelease)

The RE defines the following captures:

$1 - custom name, can be nil
$2 - semantic version
/
    (?:(#{CUSTOM_NAME_SUB_RE})-)?
    (#{SEMVER_SUB_RE})
/x
ABSTRACT_RELEASE_RE =
/^#{ABSTRACT_RELEASE_SUB_RE}$/
PROJECT_SUB_RE =

Project release RE. The general syntax is ‘<project>-<custom>-<version>’

The RE defines the following captures:

$1 - project
$2 - version
$3 - custom name, can be nil
$4 - semantic version
/(#{PROJECT_NAME_SUB_RE})-(#{ABSTRACT_RELEASE_SUB_RE})/
PROJECT_RE =
/^#{PROJECT_SUB_RE}$/
DATABASE_SUB_RE =

Matches versioned databases. Note that databases never include the feature name. Features use the project database instead of a feature-specific database

The RE defines the following captures

$1 - project
$2 - version
$3 - custom name, can be nil
$4 - semantic version
PROJECT_SUB_RE
DATABASE_RE =
/^#{DATABASE_SUB_RE}$/
ALL_DATABASES_SUB_RE =

Matches project database and versioned databases

The RE defines the following captures

$1 - project
$2 - version, can be nil
$3 - custom name, can be nil
$4 - semantic version, can be nil
/(#{PROJECT_NAME_SUB_RE})(?:-(#{ABSTRACT_RELEASE_SUB_RE}))?/
ALL_DATABASES_RE =
/^#{ALL_DATABASES_SUB_RE}$/
TMP_DATABASES_SUB_RE =

Matches temporary databases. Mostly useful when debugging because temporary databases should be deleted on exit

/#{PROJECT_NAME_SUB_RE}-(?:base|next)/
TMP_DATABASES_RE =
/^#{TMP_DATABASES_SUB_RE}$/

Class Method Summary collapse

Instance Method Summary collapse

Class Method Details

.all_databases_re(project_name) ⇒ Object



283
# File 'lib/prick/constants.rb', line 283

def self.all_databases_re(project_name) /^#{all_databases_sub_re(project_name)}$/ end

.all_databases_sub_re(project_name) ⇒ Object



282
# File 'lib/prick/constants.rb', line 282

def self.all_databases_sub_re(project_name) /(#{project_name})(?:-(#{ABSTRACT_RELEASE_SUB_RE}))?/ end

.call(ruby_script) ⇒ Object

Call a ruby script using fork. This is much faster than calling the script using #system and it shares the database connection with the current process

The script is supposed to require ‘prick.rb’ to get access to the Prick.conn function that returns the current database when run in a Prick environment

require 'prick.rb'
conn = Prick.conn database, username


106
107
108
109
110
111
112
113
114
115
# File 'lib/prick-command.rb', line 106

def self.call(ruby_script)
  File.exist?(ruby_script) or raise ArgumentError, "Can't find script '#{ruby_script}' in Prick.call"

  pid = fork do
    require(File.join(Dir.getwd, ruby_script))
  end
  Process.wait(pid)
  $?.exitstatus == 0 or raise ArgumentError, "Ruby script '#{ruby_script}' failed"
  owner_conn.reset
end

.conn(database, username = nil) ⇒ Object



13
14
15
16
17
18
19
20
21
22
23
24
# File 'lib/prick.rb', line 13

def self.conn(database, username = nil)
  if self.respond_to?(:owner_conn)
    self.owner_conn
  elsif database
    PgConn.new(database, username || database)
  elsif File.exist?(Prick::PRICK_STATE_PATH)
    hash = State.load_yaml(Prick::PRICK_STATE_PATH, %w(database username), %w(environment))
    PgConn.new(hash["database"], hash["username"])
  else
    raise ArgumentError, "No database given"
  end
end

.database_re(project_name) ⇒ Object



270
# File 'lib/prick/constants.rb', line 270

def self.database_re(project_name) /^#{database_sub_re(project_name)}$/ end

.database_sub_re(project_name) ⇒ Object



269
# File 'lib/prick/constants.rb', line 269

def self.database_sub_re(project_name) project_sub_re(project_name) end

.databases(&block) ⇒ Object

Return list of prick databases. If a block is given it is called with a connection to each of the databases



76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
# File 'lib/prick-command.rb', line 76

def self.databases(&block)
  databases = super_conn.values %(
    select datname from pg_database where datistemplate = false order by datname
  )
  databases.select! { |database|
    PgConn.new(database) { |conn|
      is_prick_database = conn.exist?(%(
          select 1
          from information_schema.tables
          where table_schema = 'prick'
          and table_name = 'builds'
      ))
      yield(database, conn) if is_prick_database && block_given?
      is_prick_database
    }
  }
  databases
end

.dump_glob(project_name) ⇒ Object



129
# File 'lib/prick/constants.rb', line 129

def self.dump_glob(project_name) "#{project_name}-*.#{DUMP_EXT}" end

.error(*args) ⇒ Object



67
# File 'lib/prick-command.rb', line 67

def self.error(*args) raise Prick::Error.new *args end

.failure(*args) ⇒ Object



68
# File 'lib/prick-command.rb', line 68

def self.failure(*args) raise Prick::Failure.new *args end

.mesg(*msgs) ⇒ Object



38
# File 'lib/prick-command.rb', line 38

def self.mesg(*msgs) puts msgs.join(" ") if !$quiet end

.owner_connObject



70
# File 'lib/prick-command.rb', line 70

def self.owner_conn = state.connection

.project_sub_re(project_name) ⇒ Object



253
254
255
# File 'lib/prick/constants.rb', line 253

def self.project_sub_re(project_name)
  /(#{Regexp.escape(project_name)})(-#{VERSION_SUB_RE})/
end

.release_re(project_name) ⇒ Object



256
# File 'lib/prick/constants.rb', line 256

def self.release_re(project_name) /^#{project_sub_re(project_name)}$/ end

.stateObject



64
# File 'lib/prick-command.rb', line 64

def self.state() @state or raise ArgumentError end

.state=(state) ⇒ Object



65
# File 'lib/prick-command.rb', line 65

def self.state=(state) @state = state end

.state?Boolean

Returns:

  • (Boolean)


63
# File 'lib/prick-command.rb', line 63

def self.state?() !@state.nil? end

.super_connObject



71
72
# File 'lib/prick-command.rb', line 71

def self.super_conn = State.connection
# def self.conn = owner_conn

.tmp_databases_re(project_name) ⇒ Object



290
# File 'lib/prick/constants.rb', line 290

def self.tmp_databases_re(project_name) /^#{tmp_databases_sub_re(project_name)}$/ end

.tmp_databases_sub_re(project_name) ⇒ Object



289
# File 'lib/prick/constants.rb', line 289

def self.tmp_databases_sub_re(project_name) /#{project_name}-(?:base|next)/ end

.verb(*msgs) ⇒ Object



39
# File 'lib/prick-command.rb', line 39

def self.verb(*msgs) puts msgs.join(" ") if $verbose && !$quiet end

Instance Method Details

#mesg(*msgs) ⇒ Object



36
# File 'lib/prick-command.rb', line 36

def mesg(*msgs) = Prick.mesg(*msgs)

#verb(*msgs) ⇒ Object



37
# File 'lib/prick-command.rb', line 37

def verb(*msgs) = Prick.verb(*msgs)