cbt 0.0.1

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.
@@ -0,0 +1,19 @@
1
+ components:
2
+ utils:
3
+ lua_modules: [util, timer]
4
+ tag: utils
5
+ LiveObject:
6
+ tag: ui.base
7
+ Panel:
8
+ lua_modules: [Panel<LiveObject]
9
+ tag: ui.full
10
+
11
+ tags:
12
+ _default: {shape: record, style: filled, fillcolor: beige}
13
+ utils: {fillcolor: bisque3}
14
+ ui: {shape: Mrecord}
15
+ ui.base: {fillcolor: bisque3}
16
+ ui.full: {fillcolor: cornflowerblue}
17
+
18
+ # relations: -- for erd
19
+
data/lib/cbt.rb ADDED
@@ -0,0 +1,13 @@
1
+ require "cbt/girc"
2
+ require "cbt/component"
3
+ require "cbt/digester"
4
+ require "cbt/app"
5
+ require "cbt/creator"
6
+ require "cbt/checkout"
7
+ require "cbt/cleanup"
8
+ require "cbt/diagram"
9
+
10
+ require "luobo/cbt"
11
+ require "luobo/lua"
12
+ require "luobo/spec"
13
+ require "luobo/settings"
data/lib/cbt/app.rb ADDED
@@ -0,0 +1,93 @@
1
+ require 'find'
2
+ require 'logger'
3
+ require 'yaml'
4
+
5
+ module Cbt
6
+ class App
7
+ attr_accessor :options, :git, :components
8
+ def initialize options = {}
9
+ @options = options
10
+ @git = Girc.new('git', @options[:verbose])
11
+
12
+ # initialize logger
13
+ @logger = Logger.new(STDOUT)
14
+ @logger.level = @options[:verbose] ? Logger::INFO : Logger::WARN
15
+ @logger.formatter = proc {|severity, datetime, progname, msg| "#{msg.to_s}\n"}
16
+
17
+ @config = YAML.load(File.open(@options[:config_file]).read)
18
+ # parse a components name=>object list
19
+ @components = Hash.new
20
+ @config["components"].each do |name, conf|
21
+ @components[name] = Component.new(name, conf)
22
+ end
23
+
24
+ # merge tag attributes recursively
25
+ @config["tags"].each do |t,v|
26
+ tv = @config["tags"]["_default"].clone || {}
27
+ p = nil
28
+ t.split('.').each do |pt|
29
+ p = p ? [p, pt].join('.') : pt # merge in order: tv < a < a.b < a.b.c, ...
30
+ # puts "merge from #{p} to #{t}"
31
+ tv.merge! @config["tags"][p] if @config["tags"][p]
32
+ end
33
+ @config["tags"][t] = tv
34
+ end
35
+
36
+ # check uniqueness for assets and lua module
37
+ luam, assets = Hash.new, Hash.new
38
+ @components.each do |cname, comp|
39
+ comp.assets.each do |aname, asset|
40
+ error "asset #{aname} defined in both components #{cname} and #{assets[aname]}" if assets[aname]
41
+ assets[aname] = cname
42
+ end
43
+
44
+ comp.modules.each do |mname, lua|
45
+ error "lua module #{mname} defined in both components #{cname} and #{luam[mname]}" if luam[mname]
46
+ luam[mname] = cname
47
+ end
48
+ end
49
+ end
50
+
51
+ # log message handler
52
+ # ------------------------------
53
+ def error msg
54
+ @logger.fatal ("[ERROR] " + msg).bold.red
55
+ exit
56
+ end
57
+
58
+ def warn msg
59
+ @logger.warn ("[WARN] " + msg).yellow
60
+ end
61
+
62
+ def info msg
63
+ @logger.info "[INFO] " + msg
64
+ end
65
+
66
+ # find current components from the command line option
67
+ # or from the git branch name
68
+ def current_component_names
69
+ component_list = Array.new
70
+ error "you can not specify component name with '--all' option" if @options[:component] and @options[:all]
71
+
72
+ if @options[:component]
73
+ component_list = @options[:component].split(",")
74
+ elsif @options[:all]
75
+ component_list = @components.keys
76
+ else
77
+ if @git.in_git_dir? and /^(comp|component|ct)\/.+/.match(@git.current_branch)
78
+ info "parse component names from git branch (#{@git.current_branch})"
79
+ component_list << @git.current_branch.gsub(/^(comp|component|ct)\//, '')
80
+ end
81
+ end
82
+
83
+ component_list.each { |n| error "unknown component name '#{n}'" unless @components[n] }
84
+ component_list
85
+ end
86
+
87
+ # return the tag definition from config file.
88
+ def tags tag
89
+ @config["tags"][tag.to_s] || {}
90
+ end
91
+
92
+ end
93
+ end
@@ -0,0 +1,155 @@
1
+ require 'fileutils'
2
+
3
+ module Cbt
4
+ class Checkout < App
5
+
6
+ # copy file from s to t, use luobo if convert class defined
7
+ def cp_file s, t
8
+ converted = false
9
+ if /\.(?<ext_>\w+)$/ =~ s
10
+ if ext_
11
+ begin
12
+ klass = Module.const_get(ext_.capitalize + 'Luobo')
13
+ rescue Exception => e
14
+ end
15
+
16
+ if klass and klass.is_a?(Class)
17
+ info "Use #{klass} to convert #{s}"
18
+ klass.cp! s, t, @options[:platform]
19
+ converted = true
20
+ end
21
+ end
22
+ end
23
+
24
+ # if no any luobo class converted the file, copy as it is
25
+ FileUtils.cp s, t unless converted
26
+
27
+ # add to consistency list
28
+ @digester.add_history s
29
+ @digester.add_history t
30
+ end
31
+
32
+ def add_copy_list sfile, tfile
33
+ # only add source file that has changed unless no_consistency_check
34
+ @file_list[sfile] = tfile if @options[:no_consistency_check] or @digester.changed?(sfile)
35
+ if @file_list[sfile] and @digester.changed?(tfile) and File.exists? tfile
36
+ error "target file #{tfile} changed. use --force to force overwrite" unless @options[:force]
37
+ end
38
+ end
39
+
40
+ # copy asset files for all components
41
+ def copy_assets! comp, ws_dir
42
+ comp.assets.each do |aname, asset|
43
+ comp_dir = comp.dir(@options[:components_dir])
44
+
45
+ # detect if an asset file saved both in global and component space
46
+ sfile = asset.path([comp_dir], @options[:platform])
47
+ global_file = asset.path([@options[:assets_dir]], @options[:platform])
48
+ warn "#{sfile} will overwrite #{global_file}" if sfile and global_file
49
+
50
+ sfile = global_file unless sfile
51
+ error "asset file for #{aname}, component #{comp.name} not found" unless sfile
52
+
53
+ tfile = m.target(ws_dir)
54
+ add_copy_list sfile, tfile
55
+ end
56
+ end
57
+
58
+ # copy required component assets and files
59
+ def copy_require! comp, ws_dir
60
+ comp.modules.each do |mname, m|
61
+ next if mname == 'main' # skip main file from the application core component
62
+ comp_dir = comp.dir(@options[:components_dir])
63
+
64
+ sfile = m.path([comp_dir], @options[:require_platform])
65
+ tfile = m.target(ws_dir)
66
+ error "no file find for module lua file #{mname}, component #{comp.name}" unless sfile
67
+
68
+ # add lua module file int copy waiting list
69
+ add_copy_list sfile, tfile
70
+ end
71
+ # copy all
72
+ end
73
+
74
+ # copy lua/spec files for a component
75
+ def process_component! comp
76
+ info "checkout component #{comp.name}"
77
+
78
+ # the copy candidate files list
79
+ @file_list = Hash.new
80
+
81
+ comp_dir = comp.dir(@options[:components_dir])
82
+ ws_dir = comp.ws_dir(@options[:workspace_dir], @options[:platform])
83
+ unless File.directory? ws_dir
84
+ info "create workspace directory #{ws_dir}"
85
+ FileUtils.mkdir_p ws_dir
86
+ end
87
+
88
+ @digester = Digester.new(ws_dir + ".yml")
89
+
90
+ # copy assets files for all components
91
+ @components.each do |cname, c|
92
+ copy_assets! c, ws_dir unless cname == comp.name
93
+ end
94
+ copy_assets! comp, ws_dir # copy the current component at last
95
+
96
+ # copy require files for all components other than current component
97
+ @components.each do |cname, c|
98
+ copy_require! c, ws_dir unless cname == comp.name
99
+ end
100
+
101
+ # for each lua module, error if no file
102
+ comp.modules['main'] = LuaModule.new(comp.name, 'main') unless comp.modules['main']
103
+ comp.modules.each do |mname, m|
104
+ sfile = m.path([comp_dir], @options[:platform])
105
+ tfile = m.target(ws_dir)
106
+ error "no file find for module lua file #{mname}, component #{comp.name}" unless sfile
107
+
108
+ # add lua module file int copy waiting list
109
+ add_copy_list sfile, tfile
110
+ end
111
+
112
+ # for all spec files
113
+ spec_dir = comp_dir
114
+ spec_dir = @options[:components_dir] if @options[:all_spec]
115
+ Dir[spec_dir + "/*_spec.lua"].each do |lua|
116
+ add_copy_list lua, File.join(ws_dir, File.basename(lua))
117
+ end
118
+
119
+ # check if t registered twice
120
+ tlist = Hash.new
121
+ @file_list.each do |s,t|
122
+ warn "#{s} will overwrite #{tlist[t]} (for #{t})" if tlist[t]
123
+ tlist[t] = s
124
+
125
+ if @options[:simulation]
126
+ puts "#{s} -> #{t}"
127
+ else
128
+ info "copy #{s} -> #{t}"
129
+ cp_file s, t
130
+ @digester.add_history s
131
+ @digester.add_history t
132
+ end
133
+ end
134
+ end
135
+
136
+ # wrap for all components
137
+ def process!
138
+ unless File.directory? @options[:workspace_dir]
139
+ info "create workspace directory #{@options[:workspace_dir]}"
140
+ FileUtils.mkdir_p @options[:workspace_dir]
141
+ end
142
+
143
+ if @options[:build] == true
144
+ warn "set require platform to #{@options[:platform]}" unless @options[:require_platform] == @options[:platform]
145
+ @options[:require_platform] = @options[:platform]
146
+ end
147
+
148
+ # process for all component
149
+ current_component_names.each do |cname|
150
+ comp = @components[cname]
151
+ process_component! comp
152
+ end
153
+ end
154
+ end
155
+ end
@@ -0,0 +1,7 @@
1
+ module Cbt
2
+ class Cleanup < App
3
+ def process!
4
+
5
+ end
6
+ end
7
+ end
@@ -0,0 +1,91 @@
1
+ module Cbt
2
+
3
+ # handle file platform versinn and copy
4
+ class SrcFile
5
+ attr_accessor :component_name
6
+ def initialize component_name, basename, ext=nil
7
+ unless ext
8
+ if /^(?<basename_>.+?)\.(?<ext_>\w+)$/ =~ basename
9
+ basename, ext = basename_, ext_
10
+ end
11
+ end
12
+ @component_name, @basename, @ext = component_name, basename, ext
13
+ end
14
+
15
+ # search up for the source file for the current file object
16
+ # with @name as the basename
17
+ def path dir = [], platform = 'debug'
18
+ # search up for each dir in row
19
+ dir.each do |d|
20
+ [".#{platform}.", "."].each do |filename|
21
+ file_path = File.join(d, @basename + filename + @ext)
22
+ # end search and return the file first found in the given directories
23
+ # return File.expand_path(file_path) if File.exists? file_path
24
+ return file_path if File.exists? file_path
25
+ end
26
+ end
27
+ nil
28
+ end
29
+
30
+ # file copy to under workspace
31
+ def target workspace_dir
32
+ File.join(workspace_dir, @basename + '.' + @ext)
33
+ end
34
+
35
+ end # class file
36
+
37
+ # module lua file object holds file contents digest to
38
+ # prevent accedental over-write
39
+ class LuaModule < SrcFile
40
+ attr_accessor :name, :super_class
41
+
42
+ def initialize component_name, name
43
+ @name, @super_class = name.split("<")
44
+ super(component_name, @name, 'lua')
45
+ end
46
+ end
47
+
48
+ # assets files
49
+ class AssetFile < SrcFile
50
+
51
+ end
52
+
53
+ class Component
54
+ attr_accessor :name, :modules, :assets
55
+
56
+ def initialize name, conf
57
+ @name, @conf = name, conf
58
+
59
+ # if no modules defined, use the name as default
60
+ @conf["lua_modules"] = Array.new unless @conf["lua_modules"]
61
+ @conf["lua_modules"] << @name if @conf["lua_modules"].size == 0
62
+
63
+ @conf["assets"] = Array.new unless @conf["assets"]
64
+
65
+ # parse module definitions, convert to objects
66
+ @modules, @assets = {}, {} # name => object pair
67
+ @conf["lua_modules"].each do |lname|
68
+ raise "invalid lua module name '#{lname}'" unless /^[a-zA-Z][\<a-zA-Z_0-9]+$/.match(lname)
69
+ @modules[lname] = LuaModule.new(@name, lname)
70
+ end
71
+
72
+ @conf["assets"].each do |asset|
73
+ @assets[asset] = AssetFile.new(@name, asset)
74
+ end
75
+ end
76
+
77
+ def tag
78
+ @conf["tag"]
79
+ end
80
+
81
+ # where the module/asset files are located
82
+ def dir base_dir
83
+ File.join(base_dir, @name).gsub(/\/$/, '')
84
+ end
85
+
86
+ # target working space directory
87
+ def ws_dir base_dir, platform
88
+ File.join(base_dir, @name + '_' + platform).gsub(/\/$/, '')
89
+ end
90
+ end
91
+ end
@@ -0,0 +1,75 @@
1
+ require "fileutils"
2
+ require "erubis"
3
+
4
+ module Cbt
5
+ class Creator < App
6
+
7
+ # find the template file from local or gem folders
8
+ def find_tpl_file tt
9
+ # first find the template under the current folder
10
+ tpl = File.join("template", tt)
11
+
12
+ # if not find there, use the default template come from the gem
13
+ unless File.exists? tpl
14
+ tpl = File.expand_path(File.dirname(__FILE__)) + "/../../templates/" + tt
15
+ end
16
+ File.expand_path(tpl)
17
+ end
18
+
19
+ # find template file name
20
+ def find_tpl luamod, mock = false
21
+ tt = ""
22
+ if luamod.name =~ /^[A-Z]/
23
+ tt = luamod.super_class ? "Class_with_super" : "Class"
24
+ else
25
+ tt = luamod.super_class ? "part_with_super" : "part"
26
+ end
27
+
28
+ tt = mock ? tt + ".mock.lua.erb" : tt + ".lua.erb"
29
+ find_tpl_file(tt)
30
+ end
31
+
32
+ # create skeleton files based on filename, module objects and template filename
33
+ def create! filename, luamod, template
34
+ if (not File.exists?(filename)) or @options[:force]
35
+ info "create file #{filename}"
36
+ fh = File.open(filename, 'w:utf-8')
37
+ fh.puts Erubis::Eruby.new(File.open(template, 'r:utf-8').read).result({
38
+ "super_class" => luamod.super_class, "name" => luamod.name,
39
+ "label" => sprintf("(component: %s)", luamod.component_name)
40
+ })
41
+ fh.close
42
+ else
43
+ info "skip existing file #{filename}"
44
+ end
45
+ end
46
+
47
+ # create initial lua files based on templates
48
+ def process!
49
+ comps = current_component_names
50
+ warn "no component specified." unless comps.size > 0
51
+ comps.each do |cname|
52
+ comp = @components[cname]
53
+ raise "undefined components #{cname}" unless comp
54
+
55
+ # create each module lua files
56
+ rep_dir = comp.dir(@options[:components_dir])
57
+ comp.modules.each do |name, mod|
58
+ unless File.directory? rep_dir
59
+ info "create directory #{rep_dir}"
60
+ FileUtils.mkdir_p rep_dir
61
+ end
62
+
63
+ # create file:
64
+ create!(File.join(rep_dir, mod.name + ".mock.lua"), mod, find_tpl(mod, true))
65
+ create!(File.join(rep_dir, mod.name + ".lua"), mod, find_tpl(mod, false))
66
+ create!(File.join(rep_dir, mod.name + "_spec.lua"), mod, find_tpl_file('spec.lua.erb')) unless name == 'main'
67
+ end
68
+
69
+ create!(File.join(rep_dir, "main.lua"), LuaModule.new(cname, 'main'), find_tpl_file('main.lua.erb')) unless comp.modules['main']
70
+ end # component names
71
+ end
72
+
73
+ end
74
+ end
75
+