volley 0.1.0.alpha1

Sign up to get free protection for your applications and to get access to all the features.
@@ -0,0 +1,94 @@
1
+
2
+ module Volley
3
+ module Dsl
4
+ class Project
5
+ class << self
6
+ attr_reader :projects
7
+ def project(name, o={}, &block)
8
+ n = name.to_sym
9
+ @projects ||= {}
10
+ if @projects[n]
11
+ #raise "defining project #{name} more than once"
12
+ else
13
+ @projects[n] = new(n)
14
+ @projects[n].instance_eval &block if block_given?
15
+ end
16
+ @projects[n]
17
+ end
18
+
19
+ def get(name)
20
+ @projects[name.to_sym]
21
+ end
22
+
23
+ def config
24
+ Volley.config
25
+ end
26
+
27
+ def exists?(name)
28
+ n = name.to_sym
29
+ @projects.keys.include?(n)
30
+ end
31
+ end
32
+
33
+ attr_reader :plans
34
+ attr_reader :name
35
+ attr_reader :source
36
+
37
+ def initialize(name)
38
+ @name = name
39
+ @plans = {}
40
+ end
41
+
42
+ def config
43
+ @config ||= OpenStruct.new
44
+ end
45
+
46
+ def plan(name, o={}, &block)
47
+ n = name.to_sym
48
+ options = {
49
+ :project => self
50
+ }.merge(o)
51
+ if block_given?
52
+ @plans[n] ||= Volley::Dsl::Plan.new(name, options, &block)
53
+ end
54
+ @plans[n]
55
+ end
56
+
57
+ def plan?(name)
58
+ n = name.to_sym
59
+ @plans.keys.include?(n)
60
+ end
61
+
62
+ def scm(name, o={}, &block)
63
+ n = name.to_s
64
+ require "volley/scm/#{n}"
65
+ klass = "Volley::Scm::#{n.camelize}".constantize
66
+ @source = klass.new(o)
67
+ end
68
+
69
+ #def encrypt(tf, o={})
70
+ # options = {
71
+ # :enabled => tf,
72
+ # :overwrite => false,
73
+ # :key => "",
74
+ # }.merge(o)
75
+ # config.encrypt = OpenStruct.new(options)
76
+ #
77
+ # key = config.encrypt.key
78
+ # if File.file?(key)
79
+ # key = File.read(key).chomp
80
+ # end
81
+ #
82
+ # config.encrypt.key = key
83
+ #end
84
+ #
85
+ #def pack(tf, o={})
86
+ # options = {
87
+ # :enabled => tf,
88
+ # :type => "tgz",
89
+ # }.merge(o)
90
+ # config.pack = OpenStruct.new(options)
91
+ #end
92
+ end
93
+ end
94
+ end
@@ -0,0 +1,25 @@
1
+
2
+ module Volley
3
+ module Dsl
4
+ class Publisher
5
+ class << self
6
+ def publisher(name, o={}, &block)
7
+ n = name.to_sym
8
+
9
+ if @publisher
10
+ raise "only one publisher can be defined at a time"
11
+ else
12
+ klass = "Volley::Publisher::#{name.to_s.camelize}"
13
+ Volley::Log.info "loading publisher: #{name} (#{klass})" if Volley.config.debug
14
+ require "volley/publisher/#{name}"
15
+ @publisher = klass.constantize.new(o)
16
+ end
17
+ end
18
+
19
+ def get
20
+ @publisher
21
+ end
22
+ end
23
+ end
24
+ end
25
+ end
data/lib/volley/dsl.rb ADDED
@@ -0,0 +1,27 @@
1
+ d = "#{File.dirname(__FILE__)}/dsl/*"
2
+ Dir[d].select{|e| e =~ /\.rb$/}.each do |file|
3
+ f = file.gsub(/\.rb$/, '')
4
+ require f
5
+ end
6
+
7
+ module Volley
8
+ module Dsl
9
+ class << self
10
+ def publisher
11
+ Volley::Dsl::Publisher.get
12
+ end
13
+
14
+ def project(name)
15
+ Volley::Dsl::Project.get(name)
16
+ end
17
+
18
+ def project?(name)
19
+ Volley::Dsl::Project.exists?(name)
20
+ end
21
+
22
+ def projects
23
+ Volley::Dsl::Project.projects
24
+ end
25
+ end
26
+ end
27
+ end
data/lib/volley/log.rb ADDED
@@ -0,0 +1,31 @@
1
+ require "yell"
2
+
3
+ module Volley
4
+ class Log
5
+ class << self
6
+ def init
7
+ @loggers = []
8
+ @loggers << Yell.new(STDOUT, :level => [:info,:warn], :format => Yell::NoFormat)
9
+ @loggers << Yell.new(STDERR, :level => [:error,:fatal], :format => Yell::NoFormat)
10
+ end
11
+
12
+ def add(level, dest, format=Yell::DefaultFormat)
13
+ if [STDOUT,STDERR].include?(dest)
14
+ @loggers << Yell.new(dest, :level => level, :format => format)
15
+ else
16
+ @loggers << Yell.new(:datefile, dest, :level => level, :format => format,
17
+ :keep => 7, :symlink_original_filename => true)
18
+ end
19
+ end
20
+
21
+ %w{debug info warn error fatal}.each do |method_name|
22
+ class_eval(<<-METHOD_DEFN, __FILE__, __LINE__)
23
+ def #{method_name}(msg=nil, &block)
24
+ @loggers.each {|l| l.#{method_name}(msg, &block) }
25
+ end
26
+ METHOD_DEFN
27
+ end
28
+ end
29
+ end
30
+ end
31
+ Volley::Log.init
@@ -0,0 +1,123 @@
1
+ require 'fog'
2
+
3
+ module Volley
4
+ module Publisher
5
+ class Amazons3 < Base
6
+ attr_accessor :key, :secret
7
+
8
+ def files
9
+ hash = {:desc => {}, :all => {}, :latest => {}}
10
+ @connection.directories.get(@bucket).files.collect{|e| e.key}.each do |e|
11
+ (pr, br, vr) = e.split(/\//)
12
+ hash[:desc][pr] ||= {}
13
+ hash[:desc][pr][br] ||= {}
14
+ hash[:desc][pr][br][vr] ||= []
15
+ hash[:desc][pr][br][vr] << e
16
+ hash[:all] ||= {}
17
+ hash[:latest] ||= {}
18
+ v = "#{pr}/#{br}/#{vr}"
19
+ hash[:latest]["#{pr}/#{br}"] ||= latest(pr, br)
20
+ hash[:all][v] = hash["latest"] == v
21
+ end
22
+ #ap hash
23
+ hash
24
+ end
25
+
26
+ def all
27
+ files[:all]
28
+ end
29
+
30
+ def projects
31
+ data = files
32
+ data[:desc].keys
33
+ #files.collect{|e| e.split(/\//).first }.uniq
34
+ rescue => e
35
+ Volley::Log.warn "error getting project list from publisher: #{e.message} at #{e.backtrace.first}"
36
+ []
37
+ end
38
+
39
+ def branches(pr)
40
+ puts "branches for #{pr}"
41
+ files[:desc][pr].keys
42
+ #files.select{|e| e.split(/\//).first == pr}.collect{|e| e.split(/\//)[1]}
43
+ rescue => e
44
+ Volley::Log.warn "error getting branch list from publisher: #{e.message}"
45
+ []
46
+ end
47
+
48
+ def versions(pr,br)
49
+ files[:desc][pr][br].keys
50
+ #raise "not implemented"
51
+ rescue => e
52
+ Volley::Log.warn "error getting version list from publisher: #{e.message}"
53
+ []
54
+ end
55
+
56
+ def contents(pr, br, vr)
57
+ files[:desc][pr][br][vr]
58
+ end
59
+
60
+ def latest(pr, br)
61
+ @project = pr
62
+ @branch = br
63
+ f = @connection.directories.get(@bucket).files.get("#{branch}/latest")
64
+ f.body
65
+ end
66
+
67
+ private
68
+
69
+ def load_configuration
70
+ @key = requires(:aws_access_key_id)
71
+ @secret = requires(:aws_secret_access_key)
72
+ @bucket = requires(:bucket)
73
+ @local = requires(:local)
74
+ @debug = optional(:debug, false)
75
+ @encrypted = optional(:encrypted, false)
76
+ connect
77
+ end
78
+
79
+ def remote_file
80
+ "#@branch-#@version.tgz#{".cpt" if @encrypted}"
81
+ end
82
+
83
+ def push_file(name, dir, contents)
84
+ Volley::Log.info ".. #{name}"
85
+ file = File.basename(name)
86
+ path = "#{dir}/#{file}"
87
+ Volley::Log.info ".. -> s3:#@bucket/#{path}"
88
+ @dir ||= @connection.directories.create({ :key => @bucket })
89
+ s3f = @dir.files.create(
90
+ :key => "#{path}",
91
+ :body => contents,
92
+ :public => true
93
+ )
94
+ Volley::Log.info ".. => #{s3f.public_url.gsub("%2F", "/")}"
95
+ "#{path}"
96
+ end
97
+
98
+ def pull_file(name, dir, ldir=nil)
99
+ Volley::Log.info ".. <- s3:#@bucket/#{dir}/#{name}"
100
+ if ldir
101
+ FileUtils.mkdir_p(ldir)
102
+ end
103
+ f = @connection.directories.get(@bucket).files.get("#{dir}/#{name}")
104
+ contents = f.body
105
+ if ldir
106
+ lfile = "#{ldir}/#{name}"
107
+ File.open(lfile, "w") { |lf| lf.write(contents) }
108
+ Volley::Log.info ".. <= #{lfile}"
109
+ else
110
+ contents
111
+ end
112
+ end
113
+
114
+ def connect
115
+ @connection ||= Fog::Storage.new(
116
+ :provider => "AWS",
117
+ :aws_access_key_id => @key,
118
+ :aws_secret_access_key => @secret,
119
+ )
120
+ end
121
+ end
122
+ end
123
+ end
@@ -0,0 +1,102 @@
1
+ module Volley
2
+ module Publisher
3
+ class Base
4
+ def initialize(options={ })
5
+ @options = {
6
+ :overwrite => false,
7
+ }.merge(options)
8
+ load_configuration
9
+ end
10
+
11
+ def projects
12
+ raise "not implemented"
13
+ end
14
+
15
+ def volleyfile(desc={ })
16
+ @project = desc[:project]
17
+ @branch = desc[:branch]
18
+ @version = desc[:version] && desc[:version] != 'latest' ? desc[:version] : get_latest(@project, @branch)
19
+ contents = pull_file("Volleyfile", version)
20
+ dest = @options[:destination] || "/tmp/Volleyfile-#{Time.now.to_i}-#{$$}"
21
+ raise "File #{dest} already exists" if File.exists?(dest)
22
+ Volley::Log.debug("saving Volleyfile: #{dest}")
23
+ File.open(dest, "w") { |f| f.write(contents) }
24
+ dest
25
+ end
26
+
27
+ def push(project, br, ver, localfiles)
28
+ @project = project
29
+ @branch = br
30
+ @version = ver
31
+
32
+ localfiles = [*localfiles].flatten
33
+ Volley::Log.info ".. pushing:" if @debug
34
+
35
+ localfiles.each do |localfile|
36
+ Volley::Log.info ".. .. #{localfile}" if @debug
37
+ push_file(localfile, version, File.open(localfile))
38
+ end
39
+ push_file("latest", branch, version)
40
+ push_file("Volleyfile", version, File.open(Volley.config.volleyfile))
41
+ end
42
+
43
+ def pull(project, branch, ver="latest")
44
+ @project = project
45
+ @branch = branch
46
+ @version = ver
47
+
48
+ if @version == "latest"
49
+ @version = get_latest(@project, @branch)
50
+ end
51
+
52
+ Volley::Log.info "remote: #{version}" if @debug
53
+ Volley::Log.info "remote_file: #{remote_file}" if @debug
54
+ pull_file(remote_file, version, "#@local/#{version}")
55
+
56
+ "#@local/#{version}/#{remote_file}"
57
+ end
58
+
59
+ def get_latest(project, branch)
60
+ cur = pull_file("latest", "#{project}/#{branch}")
61
+ (p, n, v) = cur.split(/\//)
62
+ v
63
+ end
64
+
65
+ private
66
+ def me
67
+ self.class.name.split("::").last
68
+ end
69
+
70
+ def branch
71
+ "#@project/#@branch"
72
+ end
73
+
74
+ def version
75
+ "#{branch}/#@version"
76
+ end
77
+
78
+ def requires(name)
79
+ v = get_option(name)
80
+ if v.nil?
81
+ #ap @options
82
+ raise "Publisher #{me} requires option #{name}"
83
+ end
84
+ v
85
+ end
86
+
87
+ def optional(name, default)
88
+ get_option(name) || default
89
+ end
90
+
91
+ def get_option(name)
92
+ n = name.to_sym
93
+ @options[n]
94
+ end
95
+
96
+ def get_config(name)
97
+ n = name.to_sym
98
+ Volley.config.send(n)
99
+ end
100
+ end
101
+ end
102
+ end
@@ -0,0 +1,61 @@
1
+ module Volley
2
+ module Publisher
3
+ class Local < Base
4
+
5
+ def projects
6
+ puts "#@directory"
7
+ Dir["#@directory/*"].map {|e| e.gsub(/#@directory\//,"")}
8
+ end
9
+
10
+ def branches(pr)
11
+ Dir["#@directory/#{pr}/*"].map {|e| e.gsub(/#@directory\/#{pr}\//,"")}
12
+ end
13
+
14
+ def versions(pr, br)
15
+ Dir["#@directory/#{pr}/#{br}/*"].map {|e| e.gsub(/#@directory\/#{pr}\/#{br}\//,"")}
16
+ end
17
+
18
+ private
19
+
20
+ def load_configuration
21
+ @directory = requires(:directory)
22
+ @local = requires(:local)
23
+ @debug = optional(:debug, false)
24
+ end
25
+
26
+ def remote_file
27
+ "#@branch-#@version.tgz#{".cpt" if @encrypted}"
28
+ end
29
+
30
+ def push_file(local, path, content = nil)
31
+ Volley::Log.debug "content=#{content.inspect}"
32
+ local = File.basename(local) if local =~ /^\//
33
+ dest = "#@directory/#{path}"
34
+ file = "#{dest}/#{local}"
35
+ Volley::Log.info".. -> #{dest}"
36
+ FileUtils.mkdir_p(File.dirname(file))
37
+ content = content.read if content.is_a?(File)
38
+ if content
39
+ File.open(file, "w") { |f| f.write(content) }
40
+ else
41
+ FileUtils.copy(local, file)
42
+ end
43
+ Volley::Log.info".. => #{file}"
44
+ end
45
+
46
+ def pull_file(file, path, ldir=nil)
47
+ remote = "#@directory/#{path}"
48
+ Volley::Log.info".. <- #{remote}/#{file}"
49
+ if ldir
50
+ FileUtils.mkdir_p(ldir)
51
+ end
52
+ if ldir
53
+ Volley::Log.info".. <= #@local/#{path}/#{file}"
54
+ FileUtils.copy("#{remote}/#{file}", "#@local/#{path}")
55
+ else
56
+ File.open("#{remote}/#{file}") { |f| f.read }
57
+ end
58
+ end
59
+ end
60
+ end
61
+ end
@@ -0,0 +1,8 @@
1
+
2
+ module Volley
3
+ module Scm
4
+ class Base
5
+
6
+ end
7
+ end
8
+ end
@@ -0,0 +1,31 @@
1
+ require 'volley/scm/base'
2
+
3
+ module Volley
4
+ module Scm
5
+ class Git < Base
6
+ def initialize(opt={ })
7
+ @options = {
8
+ :update => false
9
+ }.merge(opt)
10
+ end
11
+
12
+ def branch
13
+ @branch ||= `git branch`.lines.select {|e| e =~ /^\*/}.first.chomp.split[1]
14
+ rescue => e
15
+ Volley::Log.error "git: could not get branch: #{e.message}"
16
+ Volley::Log.debug e
17
+ end
18
+
19
+ def revision
20
+ @revision ||= `git log --format='%h' --max-count=1`.chomp
21
+ end
22
+
23
+ def update
24
+ @options.delete(:update)
25
+ up = %x{git pull --rebase}
26
+ @branch = nil
27
+ @revision = nil
28
+ end
29
+ end
30
+ end
31
+ end
@@ -0,0 +1,45 @@
1
+ require 'volley/scm/base'
2
+
3
+ module Volley
4
+ module Scm
5
+ class Subversion < Base
6
+ def initialize(opt={ })
7
+ @options = {
8
+ :update => false
9
+ }.merge(opt)
10
+ end
11
+
12
+ def data
13
+ @data ||= begin
14
+ update if @options[:update]
15
+ YAML::load(%x{svn info})
16
+ end
17
+ end
18
+
19
+ def branch
20
+ @branch ||= begin
21
+ if data["URL"] =~ /\/trunk/
22
+ "trunk"
23
+ elsif data["URL"] =~ /\/branches\//
24
+ m = data["URL"].match(/\/branches\/([^\/]+)\/*/)
25
+ m[1]
26
+ else
27
+ nil
28
+ end
29
+ end
30
+ end
31
+
32
+ def revision
33
+ @revision ||= begin
34
+ data["Revision"]
35
+ end
36
+ end
37
+
38
+ def update
39
+ @options.delete(:update)
40
+ up = %x{svn update}
41
+ @data = nil
42
+ end
43
+ end
44
+ end
45
+ end
@@ -0,0 +1,10 @@
1
+ unless defined?(Volley::Version)
2
+ module Volley
3
+ module Version
4
+ MAJOR = 0
5
+ MINOR = 1
6
+ TINY = 0
7
+ STRING = [MAJOR, MINOR, TINY].join('.')
8
+ end
9
+ end
10
+ end
@@ -0,0 +1,45 @@
1
+ module Volley
2
+ module VolleyFile
3
+ class << self
4
+ def init
5
+ @loaded = {}
6
+ ["~/.Volleyfile", "/etc/Volleyfile", "../../../conf/common.volleyfile"].each do |f|
7
+ file = File.expand_path(f, __FILE__)
8
+ @loaded[file] ||= load(file, :optional => true)
9
+ end
10
+ end
11
+
12
+ def load(filename, options={ })
13
+ Volley::Log.debug "LOAD: #{filename} #{options.inspect}"
14
+ @projects ||= { }
15
+ file = File.expand_path(filename)
16
+ config.volleyfile = file if options[:primary]
17
+
18
+ if File.file?(file)
19
+ @loaded[file] ||= instance_eval(File.read(file), file)
20
+ else
21
+ raise "cannot read file" unless options[:optional]
22
+ end
23
+ end
24
+
25
+ def config
26
+ Volley.config
27
+ end
28
+
29
+ # TOP LEVEL DSL METHODS
30
+
31
+ def project(name, o={}, &block)
32
+ Volley::Log.debug "project: #{name}"
33
+ Volley::Dsl::Project.project(name, o, &block)
34
+ end
35
+
36
+ def publisher(name, o={}, &block)
37
+ Volley::Dsl::Publisher.publisher(name, o, &block)
38
+ end
39
+
40
+ def log(level, dest)
41
+ Volley::Log.add(level, dest)
42
+ end
43
+ end
44
+ end
45
+ end
data/lib/volley.rb ADDED
@@ -0,0 +1,58 @@
1
+ require "awesome_print"
2
+ require "ostruct"
3
+ require "active_support/all"
4
+
5
+ require "volley/version"
6
+ require "volley/config"
7
+ require "volley/log"
8
+ require "volley/volley_file"
9
+ require "volley/publisher/base"
10
+
11
+ require "volley/dsl"
12
+
13
+ module Volley
14
+ class << self
15
+ def process(opts)
16
+ project = opts[:project]
17
+ plan = opts[:plan]
18
+ branch = opts[:branch]
19
+ version = opts[:version]
20
+ args = opts[:args]
21
+
22
+ begin
23
+ if Volley::Dsl.project?(project)
24
+ # we have the project locally
25
+ pr = Volley::Dsl.project(project)
26
+ if pr.plan?(plan)
27
+ # plan is defined
28
+ pl = pr.plan(plan)
29
+ pl.call(:rawargs => args)
30
+ else
31
+ # plan is not defined
32
+ raise "could not find plan #{plan} in project #{project}"
33
+ end
34
+ else
35
+ # we dont have the project locally, search the publisher
36
+ pub = Volley::Dsl.publisher
37
+ if pub
38
+ if pub.projects.include?(project)
39
+ vf = pub.volleyfile(opts)
40
+ puts "VF:#{vf}"
41
+ else
42
+ raise "project #{project} does not exist in configured publisher #{pub.class}"
43
+ end
44
+ else
45
+ raise "project #{project} does not exist locally, and no publisher is configured."
46
+ end
47
+ end
48
+ rescue => e
49
+ Volley::Log.error "error while processing: #{e.message}"
50
+ Volley::Log.debug e
51
+ end
52
+
53
+ #if Volley.config.debug
54
+ # ap Volley::Dsl::Project.projects
55
+ #end
56
+ end
57
+ end
58
+ end
data/volley.gemspec ADDED
@@ -0,0 +1,23 @@
1
+ # -*- encoding: utf-8 -*-
2
+ require File.expand_path('../lib/volley/version', __FILE__)
3
+
4
+ Gem::Specification.new do |gem|
5
+ gem.authors = ["Shawn Catanzarite"]
6
+ gem.email = ["scatanzarite@gmail.com"]
7
+ gem.description = %q{PubSub Deployment tool}
8
+ gem.summary = %q{PubSub Deployment tool}
9
+ gem.homepage = "http://github.com/shawncatz/volley"
10
+
11
+ gem.files = `git ls-files`.split($\)
12
+ gem.executables = gem.files.grep(%r{^bin/}).map{ |f| File.basename(f) }
13
+ gem.test_files = gem.files.grep(%r{^(test|spec|features)/})
14
+ gem.name = "volley"
15
+ gem.require_paths = ["lib"]
16
+ gem.version = "#{Volley::Version::STRING}.alpha1"
17
+
18
+ gem.add_dependency "clamp"
19
+ gem.add_dependency "fog"
20
+ gem.add_dependency "activesupport"
21
+ gem.add_dependency "mixlib-shellout"
22
+ gem.add_dependency "yell"
23
+ end