disloku 0.2.0 → 0.4.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (40) hide show
  1. checksums.yaml +4 -4
  2. data/lib/disloku/BaseCommand.rb +79 -0
  3. data/lib/disloku/ChangeSet.rb +13 -1
  4. data/lib/disloku/CliAdapter.rb +36 -0
  5. data/lib/disloku/Constants.rb +4 -0
  6. data/lib/disloku/FileChange.rb +7 -2
  7. data/lib/disloku/Log.rb +39 -12
  8. data/lib/disloku/Repository.rb +10 -1
  9. data/lib/disloku/SysCmd.rb +2 -2
  10. data/lib/disloku/commands/Build.rb +30 -0
  11. data/lib/disloku/commands/Config.rb +17 -0
  12. data/lib/disloku/commands/Deploy.rb +38 -0
  13. data/lib/disloku/config/Connection.rb +34 -0
  14. data/lib/disloku/config/ConnectionStore.rb +19 -0
  15. data/lib/disloku/config/Mapping.rb +84 -0
  16. data/lib/disloku/config/MappingStore.rb +19 -0
  17. data/lib/disloku/config/NamedConfigStore.rb +41 -0
  18. data/lib/disloku/config/Options.rb +51 -0
  19. data/lib/disloku/config/Target.rb +37 -0
  20. data/lib/disloku/config/YamlConfig.rb +54 -0
  21. data/lib/disloku/git/ChangeSetProvider.rb +19 -6
  22. data/lib/disloku/git/Repository.rb +16 -2
  23. data/lib/disloku/svn/ChangeSetProvider.rb +44 -41
  24. data/lib/disloku/svn/Repository.rb +24 -21
  25. data/lib/disloku/tasks/FolderTask.rb +5 -5
  26. data/lib/disloku/tasks/NetSftpTask.rb +39 -29
  27. data/lib/disloku/util/File.rb +9 -3
  28. data/lib/disloku.rb +24 -10
  29. metadata +20 -15
  30. data/lib/disloku/Commit.rb +0 -7
  31. data/lib/disloku/Config.rb +0 -52
  32. data/lib/disloku/Connection.rb +0 -31
  33. data/lib/disloku/ConnectionStore.rb +0 -16
  34. data/lib/disloku/Disloku.rb +0 -103
  35. data/lib/disloku/Mapping.rb +0 -81
  36. data/lib/disloku/MappingStore.rb +0 -16
  37. data/lib/disloku/NamedConfigStore.rb +0 -39
  38. data/lib/disloku/Options.rb +0 -46
  39. data/lib/disloku/Target.rb +0 -35
  40. data/lib/disloku/tasks/PsFtpTask.rb +0 -58
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA1:
3
- metadata.gz: 2f64d1e3ee54cc8b840c1c8d2a3e38093b71e35a
4
- data.tar.gz: 03382e354613f9d820ff86ef242dbf4d156de129
3
+ metadata.gz: bf136697293ab97e26248c87878fc31f0cd6b12b
4
+ data.tar.gz: cfada9605a593237c98add5e05ee495c9478df98
5
5
  SHA512:
6
- metadata.gz: 92fbd584e6295b784211813fd578caa6a9f276f52b3059ac6824ab1f1ac3e4020292ace0b87b28cb5e1ce37fbfcb96549eab94a7f56cc1de4546571bc07cd860
7
- data.tar.gz: bf16508627508a393ac4dc89755a13a21491660a00d015e3286be7d74aba55c36213f5fae16a621d250c66f91dddb174a38fc90bfafdc3ea4dcdb119f931b272
6
+ metadata.gz: efb0820d1c241f39aa8d178e8cc19824e80d31f5f11e1bd1594de56885df268e73add14d5f7a483a3a08cf41aebfd96e5c521a7444316227f5a30f0d47ba4464
7
+ data.tar.gz: e988e227b042f025c133ffc3ab3b9de7489ae7e58c889786e0a462ac33deb9a2076d3a2cbf0713dbf2255a8c3d52aa8b884f9cb397b70be066c2a2948011ac72
@@ -0,0 +1,79 @@
1
+ require_relative('DislokuError')
2
+ require_relative('Log')
3
+ require_relative('config/YamlConfig')
4
+ require_relative('config/Options')
5
+ require_relative('config/MappingStore')
6
+ require_relative('config/ConnectionStore')
7
+ require_relative('config/Target')
8
+ require_relative('git/Repository')
9
+
10
+ module Disloku
11
+
12
+ class BaseCommand
13
+ attr_accessor :repository, :config, :options
14
+
15
+ def initialize(cliOptions)
16
+ processGlobalOptions(cliOptions)
17
+
18
+ @repository = @scmImplementation.new(cliOptions[:dir])
19
+ @config = loadConfiguration()
20
+ @options = Config::Options.new(@config["options"], cliOptions)
21
+ @mappingStore = Config::MappingStore.new(@config["mappings"])
22
+ @connectionStore = Config::ConnectionStore.new(@config["connections"])
23
+
24
+ Log.instance.addLogTarget(:logfile, File.join(repository.root, "disloku.log"), Logger::INFO)
25
+ end
26
+
27
+ def loadConfiguration()
28
+ repoConfig = File.join(repository.root, 'disloku.config')
29
+ if (!File.exists?(repoConfig))
30
+ raise DislokuError.new("There is no disloku.config file in #{repository.root}")
31
+ end
32
+
33
+ config = Config::YamlConfig.new(repoConfig)
34
+
35
+ userHome = File.expand_path("~")
36
+ userConfig = File.join(userHome, ".disloku.config")
37
+ if (File.exists?(userConfig))
38
+ base = Config::YamlConfig.new(userConfig)
39
+ config.merge(base)
40
+ end
41
+
42
+ return config
43
+ end
44
+
45
+ def processGlobalOptions(cliOptions)
46
+ if (cliOptions[:scm].nil? || cliOptions[:scm] == "git")
47
+ @scmImplementation = Git::Repository
48
+ end
49
+
50
+ if (cliOptions[:debug])
51
+ Log.instance.level(:default, Logger::DEBUG)
52
+ elsif (cliOptions[:verbose])
53
+ Log.instance.level(:default, Logger::INFO)
54
+ else
55
+ Log.instance.level(:default, Logger::WARN)
56
+ end
57
+ end
58
+
59
+ def resolveTargets(targets)
60
+ actualTargets = []
61
+
62
+ while (targets.count > 0)
63
+ current = targets.shift()
64
+ targetConfig = @config["targets"][current]
65
+ if (targetConfig != nil)
66
+ if (targetConfig["targets"] != nil)
67
+ targetConfig["targets"].value().each() { |x| targets.push(x.value()) }
68
+ next
69
+ end
70
+
71
+ actualTargets.push(Config::Target.new(current, targetConfig, @mappingStore, @connectionStore))
72
+ end
73
+ end
74
+
75
+ return actualTargets
76
+ end
77
+ end
78
+
79
+ end
@@ -7,8 +7,20 @@ module Disloku
7
7
  extend Forwardable
8
8
  def_delegators :@changes, :each, :<<
9
9
 
10
- def initialize()
10
+ attr_accessor :idFrom, :idTo
11
+
12
+ def initialize(idFrom = "", idTo = "")
11
13
  @changes = Array.new()
14
+ @idFrom = idFrom
15
+ @idTo = idTo
16
+ end
17
+
18
+ def dirty?()
19
+ return @changes.any?() { |f| f.dirty }
20
+ end
21
+
22
+ def to_s()
23
+ return "#{idFrom} -> #{idTo} (#{dirty? ? 'dirty' : 'clean'})"
12
24
  end
13
25
  end
14
26
  end
@@ -0,0 +1,36 @@
1
+ require('io/console')
2
+
3
+ module Disloku
4
+
5
+ class CliAdapter
6
+ class << self
7
+
8
+ @@in = $stdin
9
+ @@out = $stdout
10
+
11
+ def queryYesNo(question)
12
+ @@out.puts()
13
+ @@out.puts("#{question} (Y/N)?")
14
+
15
+ char = @@in.getch()
16
+ return !char.match(/^[Yy]/).nil?
17
+ end
18
+
19
+ def queryYesNo!(question)
20
+ if (queryYesNo(question))
21
+ yield
22
+ end
23
+ end
24
+
25
+ def puts(output = nil)
26
+ @@out.puts(output)
27
+ end
28
+
29
+ def print(output = nil)
30
+ @@out.print(output)
31
+ end
32
+
33
+ end
34
+ end
35
+
36
+ end
@@ -0,0 +1,4 @@
1
+
2
+ module Disloku
3
+ VERSION = "0.4.0"
4
+ end
@@ -2,16 +2,21 @@ require_relative('util/File')
2
2
 
3
3
  module Disloku
4
4
  class FileChange
5
- attr_accessor :repository, :changeType
5
+ attr_accessor :repository, :changeType, :dirty
6
6
 
7
- def initialize(repository, fullPath, changeType)
7
+ def initialize(repository, fullPath, changeType, dirty)
8
8
  @repository = repository
9
9
  @fullPath = fullPath
10
10
  @changeType = changeType
11
+ @dirty = dirty
11
12
  end
12
13
 
13
14
  def getFile(target)
14
15
  return Util::File.new(@fullPath, @repository.root, target, self)
15
16
  end
17
+
18
+ def to_s()
19
+ return "<#{@changeType}> #{@fullPath}" + (@dirty ? " (dirty)" : "")
20
+ end
16
21
  end
17
22
  end
data/lib/disloku/Log.rb CHANGED
@@ -4,41 +4,68 @@ require('logger')
4
4
 
5
5
  module Disloku
6
6
  class Log
7
+
7
8
  include Singleton
8
9
 
9
10
  def initialize()
10
- @logger = Logger.new(STDOUT)
11
- @logger.formatter = proc { |severity, datetime, progname, msg|
11
+ @loggers = {}
12
+
13
+ addLogTarget(:default, STDOUT, Logger::INFO) do |severity, datetime, progname, msg|
12
14
  "#{msg}\n"
13
- }
15
+ end
16
+
17
+ @scope = [[:default]]
18
+ end
19
+
20
+ def addLogTarget(key, io, level, &block)
21
+ @loggers[key] = Logger.new(io)
22
+ if (!block.nil?)
23
+ @loggers[key].formatter = block
24
+ end
14
25
  end
15
26
 
16
- def level()
17
- return @logger.level
27
+ def getLogTarget(key)
28
+ return @loggers[key]
18
29
  end
19
30
 
20
- def level=(level)
21
- @logger.level = level
31
+ def scope(scopeTargets)
32
+ if (scopeTargets.kind_of?(Symbol))
33
+ scopeTargets = [scopeTargets]
34
+ end
35
+
36
+ @scope.push(scopeTargets)
37
+ yield
38
+ @scope.pop()
39
+ end
40
+
41
+ def level(key, level)
42
+ @loggers[key].level = level
22
43
  end
23
44
 
24
45
  def debug(message)
25
- @logger.debug(message)
46
+ log(:debug, message)
26
47
  end
27
48
 
28
49
  def info(message)
29
- @logger.debug(message)
50
+ log(:info, message)
30
51
  end
31
52
 
32
53
  def warn(message)
33
- @logger.debug(message)
54
+ log(:warn, message)
34
55
  end
35
56
 
36
57
  def error(message)
37
- @logger.debug(message)
58
+ log(:error, message)
38
59
  end
39
60
 
40
61
  def fatal(message)
41
- @logger.debug(message)
62
+ log(:fatal, message)
63
+ end
64
+
65
+ def log(method, message)
66
+ @scope.last().each() do |targetKey|
67
+ @loggers[targetKey].send(method, message) if !@loggers[targetKey].nil?
68
+ end
42
69
  end
43
70
  end
44
71
  end
@@ -1,3 +1,4 @@
1
+ require_relative('Log')
1
2
  require_relative('util/File')
2
3
 
3
4
  module Disloku
@@ -24,7 +25,15 @@ module Disloku
24
25
  end
25
26
 
26
27
  def getChangeSets(from = nil, to = nil)
27
- return @provider.getChangeSets(from, to)
28
+ changeSets = @provider.getChangeSets(from, to)
29
+
30
+ Log.instance.scope([:default, :logfile]) do
31
+ changeSets.each() do |changeSet|
32
+ Log.instance.info("gathered change set #{changeSet.to_s()}")
33
+ end
34
+ end
35
+
36
+ return changeSets
28
37
  end
29
38
  end
30
39
  end
@@ -6,9 +6,9 @@ module Disloku
6
6
  def initialize(cmd)
7
7
  @cmd = cmd
8
8
  end
9
-
9
+
10
10
  def execute()
11
- Log.instance.info("executing '#{@cmd}'")
11
+ Log.instance.debug("executing '#{@cmd}'")
12
12
  return SysCmdResult.new(%x(#{@cmd}), $?)
13
13
  end
14
14
  end
@@ -0,0 +1,30 @@
1
+ require_relative('../BaseCommand')
2
+ require_relative('../tasks/FolderTask')
3
+
4
+ module Disloku
5
+ module Commands
6
+
7
+ class Build < BaseCommand
8
+ def initialize(cliOptions)
9
+ super(cliOptions)
10
+ end
11
+
12
+ def execute(from, to)
13
+ changesets = @repository.getChangeSets(from, to)
14
+
15
+ folderInput = {
16
+ :options => @options,
17
+ :changesets => changesets,
18
+ :target => nil,
19
+ }
20
+
21
+ resolveTargets([@options.target]).each() do |t|
22
+ folderInput[:target] = t
23
+
24
+ result = Tasks::FolderTask.new(folderInput).execute()
25
+ end
26
+ end
27
+ end
28
+
29
+ end
30
+ end
@@ -0,0 +1,17 @@
1
+ require_relative('../BaseCommand')
2
+
3
+ module Disloku
4
+ module Commands
5
+
6
+ class Config < BaseCommand
7
+ def initialize(cliOptions)
8
+ super(cliOptions)
9
+ end
10
+
11
+ def execute()
12
+ puts(config.to_yaml())
13
+ end
14
+ end
15
+
16
+ end
17
+ end
@@ -0,0 +1,38 @@
1
+ require_relative('../BaseCommand')
2
+ require_relative('../tasks/FolderTask')
3
+ require_relative('../tasks/NetSftpTask')
4
+
5
+ module Disloku
6
+ module Commands
7
+
8
+ class Deploy < BaseCommand
9
+ def initialize(cliOptions)
10
+ super(cliOptions)
11
+ end
12
+
13
+ def execute(from, to)
14
+ changesets = @repository.getChangeSets(from, to)
15
+
16
+ folderInput = {
17
+ :options => @options,
18
+ :changesets => changesets,
19
+ }
20
+
21
+ resolveTargets([@options.target]).each() do |t|
22
+ folderInput[:target] = t
23
+
24
+ result = Tasks::FolderTask.new(folderInput).execute()
25
+
26
+ sftpInput = result.merge({
27
+ :repository => @repository,
28
+ :options => @options,
29
+ :target => t,
30
+ })
31
+
32
+ result = Tasks::NetSftpTask.new(sftpInput).execute()
33
+ end
34
+ end
35
+ end
36
+
37
+ end
38
+ end
@@ -0,0 +1,34 @@
1
+ require('net/sftp')
2
+ require('digest/sha1')
3
+
4
+ module Disloku
5
+ module Config
6
+
7
+ class Connection
8
+ attr_accessor :hash, :host, :user, :options
9
+
10
+ def initialize(config)
11
+ @host = config["host"].value()
12
+ @user = config["user"].value() if !config["user"].nil?
13
+ @options = {}
14
+ addOption(config, :password)
15
+ addOption(config, :port)
16
+ addOption(config, :keys, true)
17
+
18
+ @hash = Digest::SHA1.hexdigest([@host, @user, @options].join())
19
+ end
20
+
21
+ def addOption(config, key, unwrap = false)
22
+ value = config[key.to_s()]
23
+ if (!value.nil?)
24
+ if (unwrap)
25
+ @options[key] = value.value().map() { |e| e.value() }
26
+ else
27
+ @options[key] = value.value()
28
+ end
29
+ end
30
+ end
31
+ end
32
+
33
+ end
34
+ end
@@ -0,0 +1,19 @@
1
+ require_relative('NamedConfigStore')
2
+ require_relative('Connection')
3
+
4
+ module Disloku
5
+ module Config
6
+
7
+ class ConnectionStore < NamedConfigStore
8
+
9
+ def initialize(config = nil)
10
+ super(config)
11
+ end
12
+
13
+ def transformConfig(yamlConfig)
14
+ return Connection.new(yamlConfig)
15
+ end
16
+ end
17
+
18
+ end
19
+ end
@@ -0,0 +1,84 @@
1
+ require_relative('../util/Hash')
2
+ require_relative('../util/File')
3
+
4
+ module Disloku
5
+ module Config
6
+
7
+ class Mapping
8
+
9
+ def initialize(config, mappingStore = nil, allowDefault = true)
10
+ @mapping = {}
11
+
12
+ mappingConfig = config["mapping"]
13
+ if (!mappingConfig.nil?)
14
+ mappingConfig.value().each() do |m|
15
+ node = @mapping
16
+ src = m["src"].value()
17
+
18
+ if (src.kind_of?(Symbol))
19
+ segments = [src]
20
+ else
21
+ segments = Util::File.getSegments(src)
22
+
23
+ segments[0..-2].each() do |segment|
24
+ if (!node.has_key?(segment))
25
+ node[segment] = {}
26
+ end
27
+ node = node[segment]
28
+ end
29
+ end
30
+
31
+ if (!m["block"].nil? && m["block"].value())
32
+ node[segments[-1]] = :block
33
+ else
34
+ dst = m["dst"].value()
35
+ if (dst.kind_of?(Symbol))
36
+ node[segments[-1]] = dst
37
+ else
38
+ node[segments[-1]] = Util::File.getSegments(m["dst"].value())
39
+ end
40
+ end
41
+ end
42
+ elsif (allowDefault)
43
+ @mapping[:any] = :keep
44
+ end
45
+
46
+ baseMapping = config["baseMapping"].nil? ? nil : config["baseMapping"].value()
47
+
48
+ if (!baseMapping.nil?)
49
+ if (mappingStore.nil?)
50
+ raise ArgumentError.new("mapping has a base but no mapping manager was passed")
51
+ else
52
+ @mapping = mappingStore.get(baseMapping).getTree().recursive_merge(@mapping)
53
+ end
54
+ end
55
+ end
56
+
57
+ def getTree()
58
+ return @mapping
59
+ end
60
+
61
+ def mapPath(pathSegments)
62
+ node = @mapping
63
+ for i in 0..pathSegments.count
64
+ if (node.has_key?(pathSegments[i]))
65
+ node = node[pathSegments[i]]
66
+ elsif (node.has_key?(:any))
67
+ node = node[:any]
68
+ else
69
+ return nil
70
+ end
71
+
72
+ if (node == :block)
73
+ return nil
74
+ elsif (node == :keep)
75
+ return pathSegments
76
+ elsif (node.kind_of?(Array))
77
+ return Array.new(node).concat(pathSegments[(i + 1)..-1])
78
+ end
79
+ end
80
+ end
81
+ end
82
+
83
+ end
84
+ end
@@ -0,0 +1,19 @@
1
+ require_relative('NamedConfigStore')
2
+ require_relative('Mapping')
3
+
4
+ module Disloku
5
+ module Config
6
+
7
+ class MappingStore < NamedConfigStore
8
+
9
+ def initialize(config = nil)
10
+ super(config)
11
+ end
12
+
13
+ def transformConfig(yamlConfig)
14
+ return Mapping.new(yamlConfig, self, false)
15
+ end
16
+ end
17
+
18
+ end
19
+ end
@@ -0,0 +1,41 @@
1
+ require_relative('../DislokuError')
2
+ require_relative('Connection')
3
+
4
+ module Disloku
5
+ module Config
6
+ class NamedConfigStore
7
+
8
+ def initialize(config = nil)
9
+ @store = {}
10
+ if (!config.nil?)
11
+ load(config)
12
+ end
13
+ end
14
+
15
+ def get(name)
16
+ if (@store.has_key?(name))
17
+ return @store[name]
18
+ else
19
+ raise DislokuError.new("There is no stored object with the name '#{name}' in this store")
20
+ end
21
+ end
22
+
23
+ def add(name, yamlConfig)
24
+ @store[name] = transformConfig(yamlConfig)
25
+ end
26
+
27
+ def load(config)
28
+ if (!config.nil?)
29
+ config.value().each_key() do |key|
30
+ add(key, config[key])
31
+ end
32
+ end
33
+ end
34
+
35
+ def transformConfig(yamlConfig)
36
+ return yamlConfig
37
+ end
38
+ end
39
+
40
+ end
41
+ end
@@ -0,0 +1,51 @@
1
+ require_relative('../Log')
2
+ require('tmpdir')
3
+ require('fileutils')
4
+
5
+ module Disloku
6
+ module Config
7
+
8
+ class Options
9
+
10
+ def initialize(config, cliOptions)
11
+ @options = {
12
+ :ignoreDeleteErrors => false,
13
+ :createDeletesFile => false,
14
+ :allowOverride => false,
15
+ :target => "default",
16
+ :packageDir => :temp,
17
+ }
18
+
19
+ @options.each_key() do |key|
20
+ if (cliOptions.has_key?(key.to_s()))
21
+ @options[key] = cliOptions[key.to_s()]
22
+ elsif (config[key.to_s()] != nil)
23
+ @options[key] = config[key.to_s()].value()
24
+ end
25
+ end
26
+
27
+ if (@options[:packageDir] == :temp)
28
+ @options[:packageDir] = Dir.mktmpdir("disloku")
29
+ Log.instance.debug("Creating tmp directory #{@options[:packageDir]}")
30
+
31
+ # make sure the temp directory is deleted when the program exists
32
+ at_exit {
33
+ Log.instance.debug("Removing tmp directory #{@options[:packageDir]}")
34
+ FileUtils.rm_r(@options[:packageDir], :force => true)
35
+ }
36
+ else
37
+ @options[:packageDir] = File.expand_path(@options[:packageDir])
38
+ end
39
+ end
40
+
41
+ def method_missing(name, *args, &block)
42
+ if (!@options.has_key?(name))
43
+ raise ArgumentError.new("There's no option '#{name}' here")
44
+ end
45
+
46
+ return @options[name]
47
+ end
48
+ end
49
+
50
+ end
51
+ end
@@ -0,0 +1,37 @@
1
+ require_relative('Mapping')
2
+ require_relative('Connection')
3
+
4
+ module Disloku
5
+ module Config
6
+
7
+ class Target
8
+ attr_accessor :name, :connection
9
+
10
+ def initialize(name, targetConfig, mappingStore, connectionStore)
11
+ @name = name
12
+ @config = targetConfig
13
+
14
+ if (@config["connection"].value().kind_of?(String))
15
+ @connection = connectionStore.get(@config["connection"].value())
16
+ else
17
+ @connection = Connection.new(@config["connection"])
18
+ end
19
+
20
+ @mapping = Mapping.new(@config, mappingStore)
21
+ end
22
+
23
+ def mapPath(pathSegments)
24
+ return @mapping.mapPath(pathSegments)
25
+ end
26
+
27
+ def method_missing(name, *args, &block)
28
+ if (!@config.has?(name.to_s()))
29
+ return nil
30
+ end
31
+
32
+ return @config[name.to_s()].value()
33
+ end
34
+ end
35
+
36
+ end
37
+ end