kit 0.0.5 → 0.0.6

Sign up to get free protection for your applications and to get access to all the features.
data/README CHANGED
@@ -1,26 +1,52 @@
1
1
  = Kit
2
2
 
3
- Kit is a framework for making simple management tools called kits.
3
+ Kit is a framework for making simple management tools called kits. Read about why I wrote kit below for an idea of what Kit can do for you.
4
4
 
5
- * Kit is brand new and still very much under construction (a lot of which still included documentation such as this README file).
6
- * The gem includes a skeleton kit for managing web projects: clone, deploy upgrades, and push git updates to your web apps.
5
+ == What is Kit?
6
+
7
+ Kit's in it's infant stage and still changing too much to document everything it does or will do. The best way to understand what Kit is about is to read the motivation behind it (see below). Of course, you can always read the yard docs or source code if you want to see how it's coming.
8
+
9
+ === Why I wrote kit
10
+
11
+ Here are two independent problems Kit will solve (each will be a separate kit).
12
+
13
+ ==== Apache server running multiple virtual hosts (vhosts)
14
+
15
+ * Each time a vhost is added things have to happen, e.g. config files need to be made, directories created, etc.
16
+ * Depending on the type of vhost, these tasks may be different e.g. what directories are made, how the conifg files look, etc.
17
+ * If vhosts are removed or moved from one type to another, things need to be archived, cleaned up, etc.
18
+ * If the config file template changes, etc., the vhosts should all get updated.
19
+
20
+ ==== Web development server-side site management
21
+
22
+ Unless you're strictly using a development framework, testing and deploying new code is non-trivial. Exporting your code from your git repo may be more complicated then running cp -R, e.g. compressing JavaScript and CSS. Sometimes, the only place to test a project on is in production environment . I needed a tool that made testing and updating a site running a mix of differnt web software, i.e.
23
+
24
+ * Clone my production site to one of many testing sites.
25
+ * Push update packages to any of the production or testing sites.
26
+ * Push a git branch to any of the production or testing sites.
27
+ * Allow other developers access to all of these functions without giving them shell access or elevated user privileges.
28
+
29
+ == Building your own kit
30
+
31
+ For instructions on how to build your own kit go to
32
+ * https://github.com/razor-x/kit/wiki/Building-your-own-kit
7
33
 
8
34
  == Installation
9
35
 
10
36
  === Gem Installation
11
37
 
12
- Download and install kit with the following.
38
+ Download and install Kit with the following.
13
39
 
14
- gem install kit
40
+ gem install kit
15
41
 
16
42
  == Development
17
43
 
18
44
  === Source Repository
19
45
 
20
- kit is currently hosted at github. The github web page is
21
- https://github.com/razor-x/kit. The public git clone URL is
46
+ Kit is currently hosted at github. The github web page is
47
+ https://github.com/razor-x/kit. To clone the project run
22
48
 
23
- * git://github.com/razor-x/kit.git
49
+ git clone git://github.com/razor-x/kit.git
24
50
 
25
51
  == License
26
52
 
data/kits/my_kit/bit.rb CHANGED
@@ -1,17 +1,34 @@
1
1
  class Bit
2
2
 
3
+ def lookup_id uniq
4
+ @@db.select_info_by_criteria :bits, [:rowid], uniq
5
+ end
6
+
3
7
  def insert_new
4
- @project_id = insert_new_project unless @project_id
5
8
 
6
- data = { :name => @name, :project => @project_id, :root => @root, :commit => nil, :commit_time => nil }
9
+ if @project_id.nil?
10
+
11
+ p = @@db.select_info_by_name :projects, [ :rowid ], @project_name
12
+
13
+ @project_id = if p.nil? then insert_new_project else p[:rowid] end
14
+
15
+ end
16
+
17
+ uniq = { :name => @name, :project => @project_id }
18
+ data = { :root => @root, :commit => nil, :commit_time => nil }
19
+
20
+ fail DuplicateElement if lookup_id uniq
21
+
22
+ data.merge! uniq
23
+
7
24
  @@db.insert_info :bits, data
8
25
  end
9
26
 
10
27
  def insert_new_project
11
28
 
12
- fail DuplicateAttr if @@db.select_info_by_name :projects, [ :name ], @project_name
29
+ fail DuplicateElement if @@db.select_info_by_name :projects, [ :name ], @project_name
13
30
 
14
- data = { :project => @project_name, :git => @git }
31
+ data = { :name => @project_name, :git => @git }
15
32
  @@db.insert_info :projects, data
16
33
  end
17
34
 
@@ -19,6 +36,8 @@ class Bit
19
36
 
20
37
  info = @@db.select_info_by_id :bits, @@info[:bits], @id
21
38
 
39
+ fail NoElement unless info
40
+
22
41
  @name = info[:name]
23
42
  @project_id = info[:project]
24
43
 
@@ -2,7 +2,6 @@ module Actions
2
2
 
3
3
  def clones options
4
4
  src = Bit.new options[:src]
5
- # fail ProjectMismatch unless @project_id == src.project_id
6
5
  puts "cloning #{src.project_name}.#{src.name} to #{@project_name}.#{@name}"
7
6
  end
8
7
 
@@ -27,10 +27,10 @@
27
27
  :projects: [ :rowid, :name, :git ]
28
28
  #
29
29
  # Each table in the :actions: database must be of the form
30
- # :table_name: [ :rowid, :status, :column_name_1, :column_name_2 ]
31
- # where :rowid and :status are required columns.
30
+ # :table_name: [ :rowid, :bit, :status, :column_name_1, :column_name_2 ]
31
+ # where :rowid, :bit, and :status are required columns.
32
32
  #
33
33
  :actions:
34
- :clones: [ :rowid, :status, :src, :site ]
35
- :upgrades: [ :rowid, :status, :site, :component, :file ]
36
- :commits: [ :rowid, :status, :site, :requested_commit ]
34
+ :clones: [ :rowid, :bit, :status, :src ]
35
+ :upgrades: [ :rowid, :bit, :status, :component, :file ]
36
+ :commits: [ :rowid, :bit, :status, :commit ]
@@ -12,5 +12,5 @@ CREATE TABLE upgrades (
12
12
  CREATE TABLE commits (
13
13
  "bit" INTEGER NOT NULL,
14
14
  "status" TEXT NOT NULL DEFAULT ('pending'),
15
- "requested_commit" TEXT
15
+ "commit" TEXT
16
16
  );
data/lib/kit.rb CHANGED
@@ -1,11 +1,13 @@
1
- class Kit
1
+ require 'yaml'
2
2
 
3
+ class Kit
4
+ # Loads the settings for the kit.
5
+ # @param [String, Hash] config path to kit config file or hash of kit settings
3
6
  def initialize config
4
7
 
5
8
  config = load_config_file config if File.exists? config
6
9
 
7
- fail StandardError unless config.is_a? Hash
8
- fail StandardError unless config[:kits_path]
10
+ fail "No path to kit set" unless config[:kits_path]
9
11
 
10
12
  @@kit_path = config[:kits_path]
11
13
 
@@ -21,64 +23,100 @@ class Kit
21
23
  @@actions = config[:actions]
22
24
  end
23
25
 
26
+ def action_types
27
+ @@actions.keys
28
+ end
29
+
30
+ # Converts a kit config file into a hash of kit settings.
31
+ # @param [String] file path to a kit config file in yaml format
32
+ # @return [Hash] kit settings
24
33
  def load_config_file file
25
34
 
26
35
  config = YAML.load File.read file
27
36
  @@config_path = File.absolute_path File.dirname file
28
37
 
29
38
  dir = config[:kits_path]
30
- if config[:kits_path].nil?
31
- dir = @@config_path
32
- else
33
- dir = File.absolute_path @@config_path + config[:kits_path] unless [ "/", "~" ].include? config[:kits_path][0]
34
- end
39
+ dir = if config[:kits_path].nil?
40
+ @@config_path
41
+ else
42
+ File.absolute_path @@config_path + config[:kits_path] unless [ "/", "~" ].include? config[:kits_path][0]
43
+ end
35
44
 
36
45
  config[:kits_path] = dir
37
46
  return config
38
47
  end
39
48
 
49
+ # Deletes the kit's databases
40
50
  def delete_dbs
41
51
  @@db.db_paths.each do |key, f|
42
52
  File.delete f
43
53
  end
44
54
  end
45
55
 
56
+ # Creates bit object if it is unique enough.
57
+ # @param [Hash] info requested initial properties of the bit
58
+ # @return [Bit, nil] the new bit or nil if too similar to a bit that already exists
46
59
  def add_bit info
47
- Bit.new info
60
+ begin
61
+ Bit.new info
62
+ rescue Bit::DuplicateElement
63
+ nil
64
+ end
65
+ end
66
+
67
+ def get_bit info
68
+ begin
69
+ if info.is_a? Integer
70
+ Bit.new info
71
+ elsif info_is_a? Hash
72
+ Bit.new Bit::lookup_id info
73
+ end
74
+ rescue NoElement
75
+ nil
76
+ end
48
77
  end
49
78
 
79
+ # Adds a new task to the corresponding action table.
80
+ # @param [Symbol] action name of the action type
81
+ # @param [Hash] options options for the corresponding action type
50
82
  def add_task action, options
51
83
  fail NoAction unless @@actions.include? action
52
84
  @@db.insert_action action, options
53
85
  end
54
86
 
87
+ # Runs all pending tasks.
55
88
  def run_tasks
56
-
57
89
  collect_tasks_by_bit.each do |bit, tasks|
58
- s = Bit.new bit
90
+ b = Bit.new bit
59
91
 
60
92
  actions = tasks.group_by { |t| t[:action] } . keys
61
93
 
62
94
  actions.each do |a|
63
- load @@kit_path + "/#{a}/#{s.project_name}.rb"
64
- s.extend Actions
95
+ load @@kit_path + "/#{a}/#{b.project_name}.rb"
96
+ b.extend Actions
65
97
  end
66
98
 
67
99
  tasks.each do |t|
68
- s.add_task t
100
+ b.queue_task t
69
101
  end
70
102
 
71
- s.run_all
72
-
103
+ b.run_all
104
+ # TODO try and use yields here to set status to running and then complete / failed as each task runs and finishes
73
105
  end
74
106
  end
75
107
 
108
+ def get_tasks_by_status action, status
109
+ @@db.select_all_actions_by_status action, @@actions[action], status
110
+ end
111
+
76
112
  private
113
+ # Gets all tasks and groups them by bit.
114
+ # @return [Hash{Integer => Hash}] tasks grouped by bit id
77
115
  def collect_tasks_by_bit
78
116
 
79
117
  tasks = []
80
118
  @@actions.each_key do |action|
81
- tasks.push @@db.select_all_actions_by_status action, @@actions[action], :pending
119
+ tasks.push get_tasks_by_status action, :pending
82
120
  end
83
121
  tasks.flatten!
84
122
 
@@ -90,4 +128,4 @@ class Kit
90
128
 
91
129
  end
92
130
 
93
- require 'kit/bit'
131
+ require 'kit/bit'
data/lib/kit/bit.rb CHANGED
@@ -2,19 +2,22 @@ class Bit < Kit
2
2
 
3
3
  attr_reader :id
4
4
 
5
+ # Loads all bit info from database, or attempts to add new bit to database
6
+ # @param [Integer, Hash] info id of bit or info for new bit
5
7
  def initialize info
6
8
 
7
- if info.is_a? Integer
8
- @id = info
9
- else
10
- make_ivars info
11
- @id = insert_new
12
- end
9
+ @id = if info.is_a? Integer
10
+ info
11
+ else
12
+ make_ivars info
13
+ insert_new
14
+ end
13
15
 
14
16
  load_info
15
17
 
16
18
  end
17
19
 
20
+ # Sets instance variables for each key => value pair
18
21
  def make_ivars hash
19
22
  hash.each do |ivar, val|
20
23
  self.class.send :attr_accessor, ivar unless respond_to? ivar
@@ -23,57 +26,43 @@ class Bit < Kit
23
26
  end
24
27
 
25
28
  # Add a task to the array of pending tasks in @tasks.
26
- #
27
- # ==== Attributes
28
- #
29
- # * +task+ - Hash that describes the task. Must contain the keys :rowid and :action.
30
- #
31
- # ==== Examples
32
- #
33
- # Adding a task to clone site 2 from site 1
34
- #
35
- # s = Site.new 42
36
- # t = {:rowid=>1, :src=>1, :site=>2, :action=>:clones}
37
- # s.add_task t
38
- def add_task task
29
+ # @param [Hash] task info for task
30
+ def queue_task task
39
31
  @tasks = [] unless @tasks
40
32
  @tasks << task
41
33
  end
42
34
 
43
- # Removes a task from list of pending tasks in @tasks
44
- #
45
- # ==== Attributes
46
- #
47
- # * +task+ - Hash that describes the task. Must contain the keys :rowid and :action.
48
- #
49
- # ==== Examples
50
- #
51
- # Removing a task to clone site 2 from site 1
52
- #
53
- # s = Site.new 42
54
- # t = {:rowid=>1, :src=>1, :site=>2, :action=>:clones}
55
- # s.clear_task t
56
35
  def clear_task task
57
-
58
- action = task[:action]
59
- id = task[:rowid]
60
-
61
- @@db.delete_action_by_id action, id
36
+ # action = task[:action]
37
+ # id = task[:rowid]
38
+ #
39
+ # @@db.delete_action_by_id action, id
62
40
  end
63
41
 
64
- # Runs all tasks in the list of pending tasks in @tasks. Removes the task on sucess or BadTask.
42
+ # Runs all tasks in the list of pending tasks in @tasks and returns the status of each run task.
43
+ # @return [Hash] key is task id
65
44
  def run_all
66
-
67
45
  tasks = @tasks
68
-
46
+ status = {}
69
47
 
70
48
  tasks.each do |t|
71
- self.send t[:action], t
72
- clear_task t
49
+ a = t[:action]
50
+ begin
51
+ self.send a, t
52
+ status[a] = "complete"
53
+ rescue
54
+ status[a] = "failed"
55
+ end
56
+ status
73
57
  end
58
+
59
+
60
+ end
61
+
62
+ class DuplicateElement < RuntimeError
74
63
  end
75
64
 
76
- class DuplicateAttr < RuntimeError
65
+ class NoElement < RuntimeError
77
66
  end
78
67
 
79
68
  end
@@ -1,23 +1,51 @@
1
1
  require 'sqlite3'
2
2
 
3
+ # Methods to make sqlite3 interation more consice
3
4
  module SQLite3Tools
4
5
  class ::Array
6
+ # Converts an array of symbols to a string of backquoted strings for use in SELECT statement
7
+ # @return [String]
8
+ # @example
9
+ # a = [ :col_1, :col_2 ]
10
+ # a.sqlite3_to_str #=> "`col_1`, `col_2`"
5
11
  def sqlite3_to_str
6
12
  self.map { |sym| "`" + sym.to_s + "`" }.join(", ")
7
13
  end
14
+
15
+ # Converts an sqlite3 result array to a hash.
16
+ # @param keys [Array]
17
+ # @return [Hash]
18
+ # @example
19
+ # a = [ "val_1", 42 ]
20
+ # k = [ :col_1, :col_2 ]
21
+ # a.to_hash k #=> { :col_1 => "val_1", :col_2 => 42 }
22
+ def to_hash keys
23
+ Hash[ *( 0...self.size ).inject( [] ) { |arr, ix| arr.push( keys[ix], self[ix] ) } ]
24
+ end
8
25
  end
9
26
 
10
- class ::Array
11
- def to_hash other
12
- Hash[ *( 0...self.size() ).inject( [] ) { |arr, ix| arr.push( other[ix], self[ix] ) } ]
27
+ class ::Integer
28
+ # Generates placeholder string for INSERT statements.
29
+ # @return String placeholder
30
+ # @example
31
+ # 3.make_placeholders #=> "?, ?, ?"
32
+ def make_placeholders
33
+ n = self - 1
34
+ placeholders = "?"
35
+ n.times { placeholders << ", ?" }
36
+ placeholders
13
37
  end
14
38
  end
15
39
 
16
40
  class SQLite3::Database
41
+ # Selects given columns using given query and converts results to to hashes.
42
+ # @param [Array<Symbol>] columns names of columns to select
43
+ # @param [String] query sqlite3 query fragment to append to SELECT part of query
44
+ # @return [Array<Hash>] results with each row a hash in :col => value form
17
45
  def select columns, query
18
46
  result = [];
19
47
  self.execute "SELECT #{columns.sqlite3_to_str} #{query}" do |row|
20
- result.push ( row.to_hash columns )
48
+ result.push row.to_hash columns
21
49
  end
22
50
  result
23
51
  end
@@ -30,6 +58,7 @@ class Backend < Kit
30
58
 
31
59
  attr_reader :db_paths
32
60
 
61
+ # (see #db_prepare)
33
62
  def initialize db_paths
34
63
  db_paths.each do |key, db|
35
64
  name = File.basename db
@@ -46,8 +75,13 @@ class Backend < Kit
46
75
  end
47
76
 
48
77
  private
78
+ # Loads existing database files or creates new ones with kit database schema
79
+ # @param [Hash] db_paths absolute or relitive paths to database files
49
80
  def db_prepare db_paths
50
81
 
82
+ # Makes kit database schema
83
+ # @param [Symbol] type name of database
84
+ # @param db [SQLite3::Database] database object to load schema into
51
85
  def db_initialize type, db
52
86
  sql = File.read @@kit_path + "/sqlite3_#{type}.sql"
53
87
  db.execute_batch sql
@@ -79,14 +113,6 @@ class Backend < Kit
79
113
 
80
114
  end
81
115
 
82
- private
83
- def make_placeholders n
84
- n = n - 1
85
- placeholders = "?"
86
- n.times { placeholders << ", ?" }
87
- placeholders
88
- end
89
-
90
116
  public
91
117
  def select_all_actions_by_status action, fields, status
92
118
  query = "FROM `#{action}` WHERE `status` = '#{status}'"
@@ -97,7 +123,8 @@ class Backend < Kit
97
123
  end
98
124
 
99
125
  def insert_action table, data
100
- @action_db.execute "INSERT INTO #{table} VALUES ( ?, #{make_placeholders data.length} )", ( data.values.insert 1, "pending" )
126
+ data.merge! ( { :status => "pending" } )
127
+ @action_db.execute "INSERT INTO #{table} ( `#{data.keys.join "`, `"}` ) VALUES ( #{data.length.make_placeholders} )", data.values
101
128
  @action_db.last_insert_row_id
102
129
  end
103
130
 
@@ -115,8 +142,19 @@ class Backend < Kit
115
142
  info.first
116
143
  end
117
144
 
145
+ def select_info_by_criteria table, fields, criteria
146
+
147
+ q = []
148
+ criteria.each do |key, value|
149
+ q << "`#{key}` = '#{value}'"
150
+ end
151
+
152
+ info = @info_db.select fields, "FROM `#{table}` WHERE #{q.join " AND "}"
153
+ info.first
154
+ end
155
+
118
156
  def insert_info table, data
119
- @info_db.execute "INSERT INTO #{table} VALUES ( #{make_placeholders data.length} )", data.values
157
+ @info_db.execute "INSERT INTO #{table} ( `#{data.keys.join "`, `"}` ) VALUES ( #{data.length.make_placeholders} )", data.values
120
158
  @info_db.last_insert_row_id
121
159
  end
122
160
  end
data/spec/my_kit_spec.rb CHANGED
@@ -8,7 +8,7 @@ describe Kit do
8
8
  @kit = Kit.new MY_KIT_CONFIG
9
9
  end
10
10
 
11
- it "adds a new bit" do
11
+ it "adds a new bit to new project" do
12
12
  new_bit = { :name => "live", :project_name => "my_project", :root => "./my_kit_spec/my_project", :git => "git path" }
13
13
  b = @kit.add_bit new_bit
14
14
 
@@ -19,6 +19,46 @@ describe Kit do
19
19
  end
20
20
  end
21
21
 
22
+ it "doen not add a existing bit to project" do
23
+ new_bit = { :name => "live", :project_name => "my_project", :root => "./my_kit_spec/my_project/live" }
24
+ b = @kit.add_bit new_bit
25
+
26
+ b.should == nil
27
+
28
+ end
29
+
30
+ it "adds a new task of each type" do
31
+
32
+ # old_bit = { :name => "live", :project_name => "my_project" }
33
+ # puts Kit::Bit.lookup_id old_bit
34
+
35
+ new_bit_2 = { :name => "beta", :project_name => "my_project", :root => "./my_kit_spec/my_project/beta" }
36
+ b = @kit.add_bit new_bit_2
37
+
38
+ actions = {
39
+ :clones => { :bit => 1, :src => 2 },
40
+ :upgrades => { :bit => 1, :component => "my_component", :file => "my_file" },
41
+ :commits => { :bit => 1, :commit => "3456ABF" }
42
+ }
43
+
44
+ tasks = {}
45
+ actions.each do |key, value|
46
+ tasks[key] = @kit.add_task key, value
47
+ end
48
+
49
+ @kit.action_types.each do |t|
50
+ a = @kit.get_tasks_by_status t, :pending
51
+ actions[t].merge! ( { :rowid => tasks[t], :action => t, :status => "pending" } )
52
+ a.first.should == actions[t]
53
+ end
54
+
55
+ end
56
+
57
+ it "runs added tasks" do
58
+ @kit.run_tasks
59
+ end
60
+
61
+
22
62
  after :all do
23
63
  @kit.delete_dbs
24
64
  end
metadata CHANGED
@@ -5,8 +5,8 @@ version: !ruby/object:Gem::Version
5
5
  segments:
6
6
  - 0
7
7
  - 0
8
- - 5
9
- version: 0.0.5
8
+ - 6
9
+ version: 0.0.6
10
10
  platform: ruby
11
11
  authors:
12
12
  - Evan Boyd Sosenko
@@ -14,7 +14,7 @@ autorequire:
14
14
  bindir: bin
15
15
  cert_chain: []
16
16
 
17
- date: 2011-04-28 00:00:00 -07:00
17
+ date: 2011-05-01 00:00:00 -07:00
18
18
  default_executable:
19
19
  dependencies:
20
20
  - !ruby/object:Gem::Dependency
@@ -32,21 +32,6 @@ dependencies:
32
32
  version: 1.3.3
33
33
  type: :runtime
34
34
  version_requirements: *id001
35
- - !ruby/object:Gem::Dependency
36
- name: yaml
37
- prerelease: false
38
- requirement: &id002 !ruby/object:Gem::Requirement
39
- none: false
40
- requirements:
41
- - - ">="
42
- - !ruby/object:Gem::Version
43
- segments:
44
- - 1
45
- - 3
46
- - 3
47
- version: 1.3.3
48
- type: :runtime
49
- version_requirements: *id002
50
35
  description: "\t\tKit is a framework for making simple management tools called kits. Includes a skeleton kit for managing web projects: clone, deploy upgrades, and push git updates to your web apps.\n"
51
36
  email:
52
37
  executables: []
@@ -56,19 +41,19 @@ extensions: []
56
41
  extra_rdoc_files: []
57
42
 
58
43
  files:
44
+ - lib/kit.rb
59
45
  - lib/kit/bit.rb
60
46
  - lib/kit/db_sqlite3.rb
61
- - lib/kit.rb
62
47
  - README
63
- - kits/my_kit/commits/my_project.rb
64
- - kits/my_kit/clones/my_project.rb
65
- - kits/my_kit/config.yml
66
- - kits/my_kit/sqlite3_actions.sql
67
- - kits/my_kit/bit.rb
68
48
  - kits/my_kit/sqlite3_info.sql
69
49
  - kits/my_kit/upgrades/my_project.rb
70
- - spec/my_kit_spec.rb
50
+ - kits/my_kit/sqlite3_actions.sql
51
+ - kits/my_kit/bit.rb
52
+ - kits/my_kit/config.yml
53
+ - kits/my_kit/commits/my_project.rb
54
+ - kits/my_kit/clones/my_project.rb
71
55
  - spec/my_kit/my_kit.yml
56
+ - spec/my_kit_spec.rb
72
57
  has_rdoc: true
73
58
  homepage:
74
59
  licenses: