Class: Promotion::Evolver

Inherits:
Object
  • Object
show all
Defined in:
lib/promotion/evolver.rb

Overview

The Evolver class evolves the database by executing migration scripts from the evolve folder of the project being promoted

This class may be invoked via promote or via evolve or devolve commands

Instance Method Summary collapse

Constructor Details

#initialize(appname, evolve = true, targetVersion = nil) ⇒ Evolver

Creates a new Evolver



9
10
11
12
13
14
15
16
17
18
# File 'lib/promotion/evolver.rb', line 9

def initialize(appname, evolve=true, targetVersion=nil)
	@appname = appname
	@evolve = (evolve == true)
	@target = targetVersion.to_i()
	@currentVersion = nil
	@spec = get_spec()
	db = @spec.elements["Database"]
	@dbms = db.text()
	@database = db.attributes["database"] || ""
end

Instance Method Details

#devolveObject

Returns the database to an earlier schema version:

  • find all of the relevant schema migration files in the devolve folder

  • execute in sequence all migrations from the current version down to the target version

  • update the version file with the new version number



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/promotion/evolver.rb', line 95

def devolve()
	$log.info("\n#{'_'*40}\nDevolving the database #{@database}\n")
	devolveFolder = File.expand_path("#{@appname}/devolve", Folders::Staging)
	Dir.chdir(devolveFolder)
	migrations = Dir["*.sql"].collect { |f| f.sub(".sql","").to_i() }.sort()
	migrations.reject! { |v| v > @currentVersion }
	migrations.reject! { |v| v <= @target }		# after devolving we are at the previous version
	migrations.reverse!
	if @target < @currentVersion
		print("Devolving the database")
	else
		puts("Already at version #{@currentVersion}.")
		exit 0
	end
	completed = @currentVersion
	migrations.each { |v|
		success = system("#{@dbms} #{@database} < #{v}.sql")
		if success
			$log.info("Devolved the database from version #{v}")
			completed = v
		else
			$log.error("Failed to devolve the database from version #{v}.")
			break
		end
	}
	return(completed-1)	# after devolving we are at the previous version
end

#evolveObject

Starts the database evolution:

  • find all of the relevant schema migration files in the evolve folder

  • execute in sequence all migrations after the current version, updating the version file with the latest successful version number



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
# File 'lib/promotion/evolver.rb', line 64

def evolve()
	$log.info("\n#{'_'*40}\nEvolving the database #{@database}\n")
	evolveFolder = File.expand_path("#{@appname}/evolve", Folders::Staging)
	Dir.chdir(evolveFolder)
	migrations = Dir["*.sql"].collect { |f| f.sub(".sql","").to_i() }.sort()
	migrations.reject! { |v| v <= @currentVersion }
	migrations.reject! { |v| v > @target } unless @target == 0
	@target = migrations.last.to_i
	if @target <= @currentVersion
		puts("Already at version #{@currentVersion}.")
		exit 0
	end
	completed = @currentVersion
	migrations.each { |v|
		success = system("#{@dbms} #{@database} < #{v}.sql")
		if success
			$log.info("Evolved the database to version #{v}")
			completed = v
		else
			$log.error("Failed to evolve the database to version #{v}.")
			break
		end
	}
	return(completed)
end

#get_specObject

The deployment descriptor for an application should contain a single Database element in order to make use of the evolve command. SQLite3 also needs a database attribute to specify the file to operate on. <Database>/usr/bin/mysql</Database> <Database database=“/var/myapp/myapp.db”>/usr/bin/sqlite3</Database>



25
26
27
28
29
30
31
32
33
34
35
# File 'lib/promotion/evolver.rb', line 25

def get_spec()
	appFolder = File.expand_path(@appname, Folders::Staging)
	Dir.chdir(appFolder)
	specfile = File.expand_path(Files::Spec, appFolder)
	unless File.exist?(specfile)
		puts("\nSpecification file #{specfile} does not exist.\n" )
		exit 1
	end
	doc = REXML::Document.new(File.new(specfile))
	doc.root
end

#startObject

Gets the current version from the version file and calls evolve or devolve as required



38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
# File 'lib/promotion/evolver.rb', line 38

def start()
	versionFilename = File.expand_path("@version.#{@appname}", Folders::Staging)
	if !File.exist?(versionFilename)
		puts("We expect a version file at #{versionFilename} containing a single line")
		puts("with the current version of the database (eg. 1001)")
		exit 1
	end
	versionFile = File.new(versionFilename, 'r')
	@currentVersion = versionFile.gets.chomp().to_i()
	versionFile.close()
	completed = @currentVersion
	if @evolve
		completed = evolve()
	else
		completed = devolve()
	end
	versionFile = File.new(versionFilename, 'w')
	versionFile.puts(completed)
	versionFile.close()
	puts("Evolved the database to version #{completed} ")
end