Class: Prick::State

Inherits:
Object
  • Object
show all
Defined in:
lib/prick/state.rb

Overview

There is only one State object: Prick.state

FIXME Not how it is done The prick.state file contains the current database, username, and environment. It is controlled by prick(1) but you can set its values by using ‘prick database=asdf

Instance Attribute Summary collapse

Class Method Summary collapse

Instance Method Summary collapse

Constructor Details

#initialize(project_file, environment_file, reflections_file, state_file, fox_state_file) ⇒ State

Returns a new instance of State.



106
107
108
109
110
111
112
113
114
115
116
117
118
119
# File 'lib/prick/state.rb', line 106

def initialize(project_file, environment_file, reflections_file, state_file, fox_state_file)
  @project_file, @environment_file, @reflections_file, @state_file, @fox_state_file =
      project_file, environment_file, reflections_file, state_file, fox_state_file
  @project_loaded = @state_loaded = @environment_loaded = false

  if @project_file && File.exist?(@project_file)
    load_project_file
    load_state_file if @state_file && File.exist?(@state_file)
  end

  # FIXME The environment file should be loaded on-demand but it is hard to
  # do when the environments are accessed through a class-interface
  load_environment_file if @environment_file && File.exist?(@environment_file)
end

Instance Attribute Details

#databaseObject

Database name. nil if state file is absent



60
61
62
# File 'lib/prick/state.rb', line 60

def database
  @database
end

#database_environmentObject

Environment from PRICK.VERSIONS. Initialized by #connection



87
88
89
# File 'lib/prick/state.rb', line 87

def database_environment
  @database_environment
end

#database_prick_versionObject

Prick version from PRICK.VERSIONS. Initialized by #connection



84
85
86
# File 'lib/prick/state.rb', line 84

def database_prick_version
  @database_prick_version
end

#database_versionObject

Project version from PRICK.VERSIONS. Initialized by #connection



81
82
83
# File 'lib/prick/state.rb', line 81

def database_version
  @database_version
end

#environment_fileObject (readonly)

Environment file. Default ‘prick.environment’. Note that the file can be absent if the project doesn’t use environments



26
27
28
# File 'lib/prick/state.rb', line 26

def environment_file
  @environment_file
end

#environmentsObject (readonly)

Map from environment name to environment object



67
68
69
# File 'lib/prick/state.rb', line 67

def environments
  @environments
end

#fox_state_fileObject (readonly)

Fox state file. Default ‘.fox-state.yml’



36
37
38
# File 'lib/prick/state.rb', line 36

def fox_state_file
  @fox_state_file
end

#nameObject

Used as an identifier and the default database and username



47
48
49
# File 'lib/prick/state.rb', line 47

def name
  @name
end

#prick_versionObject

Version of prick in prick.yml. Note that this can be different than the current version of prick



57
58
59
# File 'lib/prick/state.rb', line 57

def prick_version
  @prick_version
end

#project_fileObject (readonly)

Project file. Default ‘prick.yml’



22
23
24
# File 'lib/prick/state.rb', line 22

def project_file
  @project_file
end

#reflections_fileObject (readonly)

Reflections file. Default ‘schema/reflections.yml’. May be nil if the file is absent



30
31
32
# File 'lib/prick/state.rb', line 30

def reflections_file
  @reflections_file
end

#state_fileObject (readonly)

State file. Default ‘.prick-state.yml’



33
34
35
# File 'lib/prick/state.rb', line 33

def state_file
  @state_file
end

#titleObject

Capitalized name of project



50
51
52
# File 'lib/prick/state.rb', line 50

def title
  @title
end

#usernameObject

Database owner name. Typically the same as the database name. nil if database is absent



64
65
66
# File 'lib/prick/state.rb', line 64

def username
  @username
end

#versionObject

Project version in prick.yml. Can be nil FIXME Can it?



53
54
55
# File 'lib/prick/state.rb', line 53

def version
  @version
end

Class Method Details

.connection(&block) ⇒ Object

Superuser connection. This is a connection to Postgres using the current user’s credentials. It is assumed that the current user has a postgres superuser account with the same name as the user’s. Memoized to connect only once



154
155
156
157
158
159
160
161
# File 'lib/prick/state.rb', line 154

def self.connection(&block)
  @@connection ||= PgConn.new("postgres")
  if block_given?
    yield @@connection
  else
    @@connection
  end
end

.load_yaml(file, mandatory_keys, optional_keys = []) ⇒ Object

To give lib/prick.rb access



331
332
333
334
335
336
337
338
339
340
341
# File 'lib/prick/state.rb', line 331

def self.load_yaml(file, mandatory_keys, optional_keys =  [])
  mandatory_keys = mandatory_keys.map(&:to_s)
  optional_keys = optional_keys.map(&:to_s)
  hash = read_yaml(file) or Prick.error "Not a valid YAML file - #{file}"
  for key in mandatory_keys
    !hash[key].to_s.empty? or Prick.error "Can't find '#{key}' in #{file}"
  end
  (unknown = (hash.keys - mandatory_keys - optional_keys).first) and
      Prick.error "Illegal key '#{unknown}' in #{file}"
  hash
end

.read_yaml(file) ⇒ Object

To give lib/prick.rb access



322
323
324
325
326
327
328
# File 'lib/prick/state.rb', line 322

def self.read_yaml(file)
  begin
    YAML.load File.read(file).sub(/^__END__\n.*/m, "")
  rescue Errno::ENOENT
    Prick.error "Can't read #{file}"
  end
end

Instance Method Details

#bash_environment(all: true) ⇒ Object

Create a bash(1) environment (Hash). It is used for in-prick expansion of variables and is also injected into the enviroment of subprocesses

FIXME: Problems with BUNDLE_* variables FIXME Still a problem?

TODO: Explain handling of PRICK_<STANDARD-DIRECTORY>



177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
# File 'lib/prick/state.rb', line 177

def bash_environment(all: true)
  @bash_environment ||= begin
    hash = {
      "PATH" => Prick.state.executable_search_path
    }

    if all
      hash.merge!({
        "PRICK_DIR" => Prick.state.prick_dir,
        "PRICK_SCHEMADIR" =>  File.join(Prick.state.prick_dir, SCHEMA_DIR),
        "PRICK_BINDIR" =>  File.join(Prick.state.prick_dir, BIN_DIR),
        "PRICK_LIBEXECDIR" =>  File.join(Prick.state.prick_dir, LIBEXEC_DIR),
        "PRICK_VARDIR" =>  File.join(Prick.state.prick_dir, VAR_DIR),
        "PRICK_CACHEDIR" =>  File.join(Prick.state.prick_dir, CACHE_DIR),
        "PRICK_SPOOLDIR" =>  File.join(Prick.state.prick_dir, SPOOL_DIR),
        "PRICK_TMPDIR" =>  File.join(Prick.state.prick_dir, TMP_DIR),
        "PRICK_CLONEDIR" =>  File.join(Prick.state.prick_dir, CLONE_DIR),
        "PRICK_SPECDIR" =>  File.join(Prick.state.prick_dir, BIN_DIR),
      })
    end

    hash.merge!({
      "DATABASE" =>  Prick.state.database, # FIXME: Yt
      "USERNAME" =>  Prick.state.username, # FIXME: Yt
      "ENVIRONMENT" =>  Prick.state.environment.to_s, # FIXME: Yt except in build.yml parser
      "PRICK_NAME" => Prick.state.name,
      "PRICK_TITLE" => Prick.state.title,
      "PRICK_VERSION" => Prick.state.version,
      "PRICK_DATABASE" =>  Prick.state.database,
      "PRICK_USERNAME" =>  Prick.state.username,
      "PRICK_ENVIRONMENT" =>  Prick.state.environment&.to_s, # may be the empty string
    })

    # PRICK_ENVIRONMENT_* variables. Only defined if the environment is known
    if !Prick.state.environment.nil? && environments.key?(environment)
      hash.merge! environments[environment].bash_environment
    end
  end
end

#bash_source(vars = nil, scope: nil) ⇒ Object

declared local), or nil (variables are global but not exported)

Only non-text variables are emitted



221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
# File 'lib/prick/state.rb', line 221

def bash_source(vars = nil, scope: nil)
  exclude = Array(exclude || []).flatten.map { _1.to_s }
  case scope
    when :global; prefix="export "
    when :local; prefix="local "
    when nil; prefix=""
  else
    raise ArgumentError, "Illegal value for scope: #{scope.inspect}"
  end

  vars ||= bash_environment&.keys || []
  assignments = []
  vars.each { |var|
    val = bash_environment[var]
#       next if val =~ /['"\n]/m # We don't quote
    if val.is_a?(Array)
      if val.first.is_a?(Array)
        val = val.map { |v| v.join("\n") }.join("\n")
      else
        val = val.join(" ")
      end
    end
    assignments << "#{prefix}#{var}='#{val}'\n"
  }
  assignments.join
end

#branchObject

Git branch. Lazy-evaluated



90
# File 'lib/prick/state.rb', line 90

def branch() @branch ||= Git.branch.current end

#clean?Boolean

True if the git repository is clean (not modified). Lazy-evaluated

Returns:

  • (Boolean)


101
102
103
104
# File 'lib/prick/state.rb', line 101

def clean?()
  return @clean if defined?(@clean)
  @clean = Git.clean?
end

#connection(database: nil, username: nil, environment: nil, &block) ⇒ Object Also known as: conn

Project user (owner) connection. Memoized to connect only once. TODO Rename. Also rename self.connection



123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
# File 'lib/prick/state.rb', line 123

def connection(database: nil, username: nil, environment: nil, &block)
  if @connection.nil?
    database ||= self.database
    username ||= self.username
    environment ||= self.environment
    !database.nil? or Prick.error "Can't connect to Postgres - no database specified"
#       exist_database_environment? or Prick.error "Database '#{database}' is not initialized"

    @connection = PgConn.new(database, username)

    # Set database_version/environment/prick members
    load_database_environment

    # Set environment if undefined and not overridden by :environment
    self.environment =
        environment ||
        Prick.state.environment ||
        environments.key?(database_environment) && database_environment ||
        DEFAULT_ENVIRONMENT
  end
  if block_given?
    yield @connection
  else
    @connection
  end
end

#dumpObject



308
309
310
311
312
313
314
315
316
317
318
319
# File 'lib/prick/state.rb', line 308

def dump
  puts "State"
  indent {
    for method in [
        :name, :title, :prick_version, :project_version,
        :database_version, :database_environment, :database, :username]
      puts "#{method}: #{self.send method}"
    end
    puts "environments:"
    indent { environments.dump }
  }
end

#environmentObject

Name of current environment. If not set in the state file, the enviroment is read from the database when the first connection is established by the #connection method. Use ‘#environments’ to get the corresponding Environment object



73
# File 'lib/prick/state.rb', line 73

def environment() @environment end

#environment=(env) ⇒ Object



74
75
76
77
78
# File 'lib/prick/state.rb', line 74

def environment=(env)
  constrain env, String, nil
  env.nil? || environments.key?(env) or raise "Illegal environment: '#{env}'"
  @environment = env
end

#environment_loaded?Boolean

Returns:

  • (Boolean)


44
# File 'lib/prick/state.rb', line 44

def environment_loaded? = @environment_loaded

#executable_search_pathObject

Prick executable search_path. This includes the bin and libexec directories



167
168
169
# File 'lib/prick/state.rb', line 167

def executable_search_path
  @executable_search_path ||= "#{ENV['PATH']}:#{prick_dir}/#{BIN_DIR}:#{prick_dir}/#{LIBEXEC_DIR}"
end

#prick_dirObject

Prick project dir. This is not a constant because prick can change directory through the -C option or the ‘init’ command



16
# File 'lib/prick/state.rb', line 16

def prick_dir() @prick_dir ||= Dir.getwd end

#project_loaded?Boolean

True if the configuration files has been loaded

Returns:

  • (Boolean)


42
# File 'lib/prick/state.rb', line 42

def project_loaded? = @project_loaded

#rev(kind: :long) ⇒ Object

Git revision (commit ID). Lazy-evaluated



93
94
95
96
97
98
# File 'lib/prick/state.rb', line 93

def rev(kind: :long)
  case kind
    when :short; @rev_short ||= rev()[0...8]
    when :long; @rev_long ||= Git.id
  end
end

#save_build(success = true) ⇒ Object



298
299
300
301
302
303
304
305
306
# File 'lib/prick/state.rb', line 298

def save_build(success = true)
  insert_record(
    "prick.builds",
        name: name,
        version: version.to_s, prick: Prick::VERSION,
        branch: branch, rev: rev(kind: :short), clean: clean?,
        environment: environment,
        success: success)
end

#save_build_beginObject

Save build-start information to PRICK.BUILDS. It is a nop if PRICK.BUILDS doesn’t exist, this happens on first build in a completely empty database



270
271
272
273
274
275
276
277
278
279
280
281
# File 'lib/prick/state.rb', line 270

def save_build_begin
  @build_id = nil # Used by save_build_end
  if conn.schema.exist_table?("prick", "builds")
    @build_id = insert_record(
        "prick.builds",
        name: name,
        version: version.to_s, prick: Prick::VERSION,
        branch: branch, rev: rev(kind: :short), clean: clean?,
        environment: environment)
  end
#           version: version.to_s, prick: prick_version,
end

#save_build_end(success, duration) ⇒ Object



283
284
285
286
287
288
289
290
291
292
293
294
295
296
# File 'lib/prick/state.rb', line 283

def save_build_end(success, duration)
  dt = Time.now - TIME
  if @build_id
    update_record("prick.builds", @build_id, success: success, duration: duration, prick_duration: dt)
  else
    insert_record(
        "prick.builds",
        name: name,
        version: version.to_s, prick: Prick::VERSION,
        branch: branch, rev: rev(kind: :short), clean: clean?,
        environment: environment,
        success: success, duration: duration, prick_duration: dt)
  end
end

#save_project(overwrite: false) ⇒ Object

It is an error if the project file exists.



249
250
251
252
253
# File 'lib/prick/state.rb', line 249

def save_project(overwrite: false)
  overwrite || !File.exists?(project_file) or Prick.error "Won't overwrite '#{project_file}'"
  hash = { name: name, title: title, version: version.to_s, prick: Prick::VERSION }
  save_yaml(project_file, hash)
end

#save_state(database = nil, username = nil, environment = nil) ⇒ Object

Used by ‘prick setup’



261
262
263
264
265
266
# File 'lib/prick/state.rb', line 261

def save_state(database = nil, username = nil, environment = nil)
  database ||= self.database or raise ArgumentError
  username ||= self.username or raise ArgumentError
  environment ||= self.environment
  save_yaml(state_file, database: database, username: username, environment: environment)
end

#save_versionObject

FIXME: Ugly



256
257
258
# File 'lib/prick/state.rb', line 256

def save_version
  system("sed -i 's/^version:.*/version: #{version.to_s} #{project_file}/'")
end

#schema_dirObject

Prick schema dir



19
# File 'lib/prick/state.rb', line 19

def schema_dir() @schema_dir ||= File.join(prick_dir, SCHEMA_DIR) end

#schema_fileObject

Schema data file. FIXME What is this?



39
# File 'lib/prick/state.rb', line 39

def schema_file() SCHEMA_VERSION_PATH end

#state_loaded?Boolean

Returns:

  • (Boolean)


43
# File 'lib/prick/state.rb', line 43

def state_loaded? = @state_loaded