disloku 0.2.0 → 0.4.0

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 (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