konstant 0.0.8

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (45) hide show
  1. checksums.yaml +7 -0
  2. data/.gitignore +17 -0
  3. data/.rspec +3 -0
  4. data/.ruby-version +1 -0
  5. data/Gemfile +4 -0
  6. data/LICENSE.txt +22 -0
  7. data/README.md +125 -0
  8. data/Rakefile +7 -0
  9. data/bin/konstant +87 -0
  10. data/data/templates/data_dir/konstant.js +16 -0
  11. data/data/templates/data_dir/projects/.gitkeep +0 -0
  12. data/data/templates/project/build +8 -0
  13. data/data/templates/project/cleanup +5 -0
  14. data/data/templates/project/deploy +4 -0
  15. data/data/templates/project/run.txt +0 -0
  16. data/konstant.gemspec +29 -0
  17. data/lib/konstant/build.rb +86 -0
  18. data/lib/konstant/builder.rb +108 -0
  19. data/lib/konstant/cli.rb +37 -0
  20. data/lib/konstant/project.rb +75 -0
  21. data/lib/konstant/runner.rb +50 -0
  22. data/lib/konstant/scheduler.rb +50 -0
  23. data/lib/konstant/version.rb +3 -0
  24. data/lib/konstant/web.rb +39 -0
  25. data/lib/konstant.rb +81 -0
  26. data/public/assets/angular.min.js +216 -0
  27. data/public/assets/app.js +60 -0
  28. data/public/assets/bootstrap-theme.min.css +5 -0
  29. data/public/assets/bootstrap.min.css +5 -0
  30. data/public/assets/bootstrap.min.js +6 -0
  31. data/public/assets/glyphicons-halflings-regular.eot +0 -0
  32. data/public/assets/glyphicons-halflings-regular.svg +229 -0
  33. data/public/assets/glyphicons-halflings-regular.ttf +0 -0
  34. data/public/assets/glyphicons-halflings-regular.woff +0 -0
  35. data/public/assets/jquery-2.1.1.min.js +4 -0
  36. data/public/assets/style.css +3 -0
  37. data/public/index.html +175 -0
  38. data/spec/file_spec.rb +28 -0
  39. data/spec/fixtures/projects/test_project_01/build +6 -0
  40. data/spec/fixtures/projects/test_project_02/build +3 -0
  41. data/spec/konstant/builder_spec.rb +21 -0
  42. data/spec/konstant/runner_spec.rb +14 -0
  43. data/spec/konstant_spec.rb +23 -0
  44. data/spec/spec_helper.rb +27 -0
  45. metadata +208 -0
@@ -0,0 +1,50 @@
1
+ class Konstant::Runner
2
+
3
+ def initialize(build, task)
4
+ @build = build
5
+ @task = task
6
+ end
7
+
8
+ attr_reader :build, :task
9
+
10
+ def run
11
+ if task == "build" || File.exists?("#{build.project.path}/#{task}")
12
+ duration = Konstant.measure do
13
+ build.create
14
+ File.open status_file, "w" do |f|
15
+ Bundler.with_clean_env do
16
+ system environment, "#{build.project.path}/#{task} > #{stdout_file} 2> #{stderr_file}"
17
+ f.puts $?.exitstatus
18
+ end
19
+ end
20
+ end
21
+ File.open "#{build.path}/#{task}.duration", "w" do |f|
22
+ f.puts duration
23
+ end
24
+
25
+ build.status(task) == 0
26
+ else
27
+ false
28
+ end
29
+ end
30
+
31
+ def environment
32
+ return {
33
+ "KONSTANT_PROJECT_ROOT" => File.expand_path(build.project.path),
34
+ "KONSTANT_TIMESTAMP" => build.timestamp
35
+ }
36
+ end
37
+
38
+ def stdout_file
39
+ "#{build.path}/#{task}.stdout"
40
+ end
41
+
42
+ def stderr_file
43
+ "#{build.path}/#{task}.stderr"
44
+ end
45
+
46
+ def status_file
47
+ "#{build.path}/#{task}.status"
48
+ end
49
+
50
+ end
@@ -0,0 +1,50 @@
1
+ class Konstant::Scheduler
2
+
3
+ def run
4
+ @threads = {}
5
+
6
+ until Konstant.shutdown? do
7
+ project_paths = Dir["#{Konstant.config['data_dir']}/projects/*"]
8
+ project_ids = project_paths.map{|path| path.split('/').last}
9
+
10
+ (project_ids - @threads.keys).each do |project_id|
11
+ @threads[project_id] = project_worker(project_id)
12
+ end
13
+
14
+ (@threads.keys - project_ids).each do |project_id|
15
+ thread = @thread.delete project_id
16
+ thread.kill
17
+ Konstant.logger.info "stopped worker for project '#{project_id}'"
18
+ end
19
+
20
+ sleep Konstant.config['new_projects_interval']
21
+ end
22
+ end
23
+
24
+ def project_worker(project_id)
25
+ Thread.new do
26
+ project = Konstant::Project.new(project_id)
27
+ Konstant.logger.info "started worker for project '#{project.id}'"
28
+
29
+ until Konstant.shutdown? do
30
+ Konstant.logger.debug "polling project '#{project.id}'"
31
+ if File.exists?("#{project.path}/run.txt")
32
+ system "rm #{project.path}/run.txt"
33
+
34
+ begin
35
+ system "touch #{project.path}/running.txt"
36
+ Konstant::Builder.new(project).run
37
+ rescue => e
38
+ puts e.message
39
+ puts e.backtrace
40
+ ensure
41
+ system "rm #{project.path}/running.txt"
42
+ end
43
+ else
44
+ sleep Konstant.config["build_check_interval"]
45
+ end
46
+ end
47
+ end
48
+ end
49
+
50
+ end
@@ -0,0 +1,3 @@
1
+ module Konstant
2
+ VERSION = "0.0.8"
3
+ end
@@ -0,0 +1,39 @@
1
+ require "rack"
2
+
3
+ class Konstant::Web
4
+
5
+ def self.call(env)
6
+ new(env).route
7
+ end
8
+
9
+ def initialize(env)
10
+ @env = env
11
+ end
12
+
13
+ def request
14
+ @request ||= Rack::Request.new(@env)
15
+ end
16
+
17
+ def route
18
+ if request.path.match(/^\/projects$/)
19
+ [200, {"Content-type" => "application/json"}, [Konstant::Project.all.to_json]]
20
+ elsif m = request.path.match(/^\/projects\/([^\/]+)\/builds\/(\d+)$/)
21
+ project = Konstant::Project.new m[1]
22
+ build = Konstant::Build.new project, m[2]
23
+ [200, {"Content-type" => "application/json"}, [build.to_json]]
24
+ elsif request.path.match(/^\/config$/)
25
+ [200, {"Content-type" => "application/json"}, [Konstant.config.to_json]]
26
+ elsif m = request.path.match(/^\/projects\/([^\/]+)\/builds$/)
27
+ project = Konstant::Project.new m[1]
28
+ [200, {"Content-type" => "application/json"}, [project.builds.to_json]]
29
+ elsif m = request.path.match(/^\/projects\/([^\/]+)\/build$/)
30
+ project = Konstant::Project.new m[1]
31
+ project.build!
32
+ message = {"message" => "ok"}
33
+ [200, {"Content-type" => "application/json"}, [message.to_json]]
34
+ else
35
+ [404, {"Content-type" => "text/plain"}, ["not found"]]
36
+ end
37
+ end
38
+
39
+ end
data/lib/konstant.rb ADDED
@@ -0,0 +1,81 @@
1
+ require "konstant/version"
2
+
3
+ require "logger"
4
+ require "json"
5
+ require "mail"
6
+
7
+ module Konstant
8
+
9
+ autoload :Build, "konstant/build"
10
+ autoload :Builder, "konstant/builder"
11
+ autoload :Cli, "konstant/cli"
12
+ autoload :Project, "konstant/project"
13
+ autoload :Scheduler, "konstant/scheduler"
14
+ autoload :Runner, "konstant/runner"
15
+ autoload :Web, "konstant/web"
16
+
17
+ def self.config
18
+ @config ||= {}
19
+ end
20
+
21
+ def self.configure(new_config)
22
+ case new_config
23
+ when Hash then config.merge! new_config
24
+ when String then config.merge! JSON.parse(File.read new_config)
25
+ end
26
+ end
27
+
28
+ def self.reset_config
29
+ @config = nil
30
+ end
31
+
32
+ def self.reset_data_dir
33
+ system "rm -rf #{config['data_dir']}"
34
+ end
35
+
36
+ def self.copy_fixture_projects
37
+ system "cp -a #{root}/data/templates/data_dir #{config['data_dir']}/"
38
+ system "cp -a #{root}/spec/fixtures/projects/* #{config['data_dir']}/projects/"
39
+ end
40
+
41
+ def self.env
42
+ ENV["RUBY_ENV"] || "development"
43
+ end
44
+
45
+ def self.root
46
+ File.expand_path(File.dirname(__FILE__) + "/..")
47
+ end
48
+
49
+ def self.shutdown!
50
+ @shutdown = true
51
+ end
52
+
53
+ def self.shutdown?
54
+ @shutdown
55
+ end
56
+
57
+ def self.shutdown_handlers
58
+ @shutdown_handlers ||= [
59
+ Proc.new { Konstant.shutdown! }
60
+ ]
61
+ end
62
+
63
+ def self.logger
64
+ @logger ||= begin
65
+ result = Logger.new(STDOUT)
66
+ result.level = Logger::INFO
67
+ result
68
+ end
69
+ end
70
+
71
+ def self.logger=(value)
72
+ @logger = value
73
+ end
74
+
75
+ def self.measure
76
+ started_at = Time.now
77
+ yield
78
+ Time.now - started_at
79
+ end
80
+
81
+ end