app_stack 1.2.1 → 1.3.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.
- checksums.yaml +15 -0
- data/.app_stack.yml +14 -0
- data/Gemfile +1 -0
- data/Gemfile.lock +2 -0
- data/README.md +14 -0
- data/app_stack.gemspec +1 -0
- data/bin/config_assets +3 -0
- data/bin/stackup +8 -0
- data/file.erb +0 -0
- data/lib/app_stack/cli_options.rb +52 -0
- data/lib/app_stack/copy_list_builder.rb +144 -0
- data/lib/app_stack/local_files_parser.rb +95 -0
- data/lib/app_stack/stack_app.rb +114 -0
- data/lib/app_stack/version.rb +1 -1
- data/lib/app_stack.rb +13 -22
- data/tags +45 -0
- metadata +16 -62
- data/doc/coverage/.last_run.json +0 -1
- data/doc/coverage/.resultset.json +0 -1
- data/doc/coverage/assets/0.7.1/application.css +0 -1110
- data/doc/coverage/assets/0.7.1/application.js +0 -626
- data/doc/coverage/assets/0.7.1/fancybox/blank.gif +0 -0
- data/doc/coverage/assets/0.7.1/fancybox/fancy_close.png +0 -0
- data/doc/coverage/assets/0.7.1/fancybox/fancy_loading.png +0 -0
- data/doc/coverage/assets/0.7.1/fancybox/fancy_nav_left.png +0 -0
- data/doc/coverage/assets/0.7.1/fancybox/fancy_nav_right.png +0 -0
- data/doc/coverage/assets/0.7.1/fancybox/fancy_shadow_e.png +0 -0
- data/doc/coverage/assets/0.7.1/fancybox/fancy_shadow_n.png +0 -0
- data/doc/coverage/assets/0.7.1/fancybox/fancy_shadow_ne.png +0 -0
- data/doc/coverage/assets/0.7.1/fancybox/fancy_shadow_nw.png +0 -0
- data/doc/coverage/assets/0.7.1/fancybox/fancy_shadow_s.png +0 -0
- data/doc/coverage/assets/0.7.1/fancybox/fancy_shadow_se.png +0 -0
- data/doc/coverage/assets/0.7.1/fancybox/fancy_shadow_sw.png +0 -0
- data/doc/coverage/assets/0.7.1/fancybox/fancy_shadow_w.png +0 -0
- data/doc/coverage/assets/0.7.1/fancybox/fancy_title_left.png +0 -0
- data/doc/coverage/assets/0.7.1/fancybox/fancy_title_main.png +0 -0
- data/doc/coverage/assets/0.7.1/fancybox/fancy_title_over.png +0 -0
- data/doc/coverage/assets/0.7.1/fancybox/fancy_title_right.png +0 -0
- data/doc/coverage/assets/0.7.1/fancybox/fancybox-x.png +0 -0
- data/doc/coverage/assets/0.7.1/fancybox/fancybox-y.png +0 -0
- data/doc/coverage/assets/0.7.1/fancybox/fancybox.png +0 -0
- data/doc/coverage/assets/0.7.1/favicon_green.png +0 -0
- data/doc/coverage/assets/0.7.1/favicon_red.png +0 -0
- data/doc/coverage/assets/0.7.1/favicon_yellow.png +0 -0
- data/doc/coverage/assets/0.7.1/loading.gif +0 -0
- data/doc/coverage/assets/0.7.1/magnify.png +0 -0
- data/doc/coverage/assets/0.7.1/smoothness/images/ui-bg_flat_0_aaaaaa_40x100.png +0 -0
- data/doc/coverage/assets/0.7.1/smoothness/images/ui-bg_flat_75_ffffff_40x100.png +0 -0
- data/doc/coverage/assets/0.7.1/smoothness/images/ui-bg_glass_55_fbf9ee_1x400.png +0 -0
- data/doc/coverage/assets/0.7.1/smoothness/images/ui-bg_glass_65_ffffff_1x400.png +0 -0
- data/doc/coverage/assets/0.7.1/smoothness/images/ui-bg_glass_75_dadada_1x400.png +0 -0
- data/doc/coverage/assets/0.7.1/smoothness/images/ui-bg_glass_75_e6e6e6_1x400.png +0 -0
- data/doc/coverage/assets/0.7.1/smoothness/images/ui-bg_glass_95_fef1ec_1x400.png +0 -0
- data/doc/coverage/assets/0.7.1/smoothness/images/ui-bg_highlight-soft_75_cccccc_1x100.png +0 -0
- data/doc/coverage/assets/0.7.1/smoothness/images/ui-icons_222222_256x240.png +0 -0
- data/doc/coverage/assets/0.7.1/smoothness/images/ui-icons_2e83ff_256x240.png +0 -0
- data/doc/coverage/assets/0.7.1/smoothness/images/ui-icons_454545_256x240.png +0 -0
- data/doc/coverage/assets/0.7.1/smoothness/images/ui-icons_888888_256x240.png +0 -0
- data/doc/coverage/assets/0.7.1/smoothness/images/ui-icons_cd0a0a_256x240.png +0 -0
- data/doc/coverage/index.html +0 -2480
- data/lib/app_stack/config.rb +0 -132
checksums.yaml
ADDED
@@ -0,0 +1,15 @@
|
|
1
|
+
---
|
2
|
+
!binary "U0hBMQ==":
|
3
|
+
metadata.gz: !binary |-
|
4
|
+
ZTJmNjU5OThhNjgwMjg5MzJjZGVmNjQ2MGU2ZTkzMDNkZGY0NGM5NQ==
|
5
|
+
data.tar.gz: !binary |-
|
6
|
+
ZTA1ODI2N2RlM2U3MTNiZmFkM2NjMmI5ZTdhNWU5NzRiNTE1NDhlMw==
|
7
|
+
!binary "U0hBNTEy":
|
8
|
+
metadata.gz: !binary |-
|
9
|
+
YzAzMmQ5YzEwNWIzZTI3MDk1MmE1MzMzOWZhOGQ5YWFkMWNkZTJhY2E5OGJl
|
10
|
+
ZjgwOTNiZGRhYjY2MWM3MDdmMGRjOWNmYTVhYjg5ZDE4NGIzMmI0NTNmMTA1
|
11
|
+
ZTUwMWFhZDNkMTg5MzAyYjdmYmMzOTI4ZGUyM2QxYWIyMDk1NTI=
|
12
|
+
data.tar.gz: !binary |-
|
13
|
+
MjVjNDgwNmE1OWQ2YTlhODZhZDgxNDYzZGM4ZGY3YzQ4MjdjMDE5NmNkNTdh
|
14
|
+
NWY2ZWNiYzViYmRmNDkzNTA4MGM2NmU1ZDM2N2RlMDk4OTM5ZWY2MTFkZTI4
|
15
|
+
OWNmNWJjNjk3NDYwYjYxYWUxZGNlNzk0ZDdjZjc0NmRmZTEwN2E=
|
data/.app_stack.yml
ADDED
@@ -0,0 +1,14 @@
|
|
1
|
+
stack:
|
2
|
+
- la-sinatra: [default, { Gemfile: Gemfile, Procfile: Procfile.imp }]
|
3
|
+
- la-mongoid: [default, mixins]
|
4
|
+
- la-mancha-models-syobu-p1
|
5
|
+
- la-assets-helper
|
6
|
+
export: []
|
7
|
+
exclude:
|
8
|
+
- '*sample_files/**/*'
|
9
|
+
attrs:
|
10
|
+
application_code: ficus_syobu_p1
|
11
|
+
application_name: Ficus Web Framework
|
12
|
+
gems:
|
13
|
+
default: {}
|
14
|
+
development: {}
|
data/Gemfile
CHANGED
data/Gemfile.lock
CHANGED
@@ -9,6 +9,7 @@ GEM
|
|
9
9
|
tzinfo (~> 0.3.37)
|
10
10
|
atomic (1.1.13)
|
11
11
|
diff-lcs (1.2.4)
|
12
|
+
diffy (3.0.1)
|
12
13
|
i18n (0.6.5)
|
13
14
|
minitest (4.7.5)
|
14
15
|
multi_json (1.8.0)
|
@@ -37,6 +38,7 @@ PLATFORMS
|
|
37
38
|
|
38
39
|
DEPENDENCIES
|
39
40
|
activesupport (>= 3.2.14)
|
41
|
+
diffy
|
40
42
|
rspec (>= 2.14.1)
|
41
43
|
simplecov (>= 0.7.1)
|
42
44
|
term-ansicolor (>= 1.2.2)
|
data/README.md
CHANGED
@@ -62,6 +62,20 @@ Define directory where the source code of stack modules located. Default is `../
|
|
62
62
|
|
63
63
|
Default as above (refer to document below).
|
64
64
|
|
65
|
+
Then run:
|
66
|
+
|
67
|
+
$ stackup [config_file]
|
68
|
+
|
69
|
+
Default configuration file is `.app_stack.yml`
|
70
|
+
|
71
|
+
Command line options:
|
72
|
+
|
73
|
+
- `-h, --help` show help message
|
74
|
+
- `--verbose` show more informations
|
75
|
+
- `-s, --simulate` only show the copy list, do not actually copy
|
76
|
+
- `-f, --force` force overwrite new files (only import new file and
|
77
|
+
ask for updated files by default)
|
78
|
+
|
65
79
|
## Copy Precedence
|
66
80
|
|
67
81
|
For a module chain `a, b, c, ...`, files exported by `b` will over-write
|
data/app_stack.gemspec
CHANGED
@@ -8,6 +8,7 @@ Gem::Specification.new 'app_stack', AppStack::VERSION do |s|
|
|
8
8
|
s.email = 'huangw@7lime.com'
|
9
9
|
s.homepage = 'https://github.com/7lime/app_stack-gem'
|
10
10
|
s.files = `git ls-files`.split("\n") - %w[.gitignore .rspec Rakefile]
|
11
|
+
s.executables << 'stackup'
|
11
12
|
s.license = 'MIT'
|
12
13
|
s.test_files = Dir.glob('{spec,test}/**/*.rb')
|
13
14
|
|
data/bin/config_assets
ADDED
data/bin/stackup
ADDED
data/file.erb
ADDED
File without changes
|
@@ -0,0 +1,52 @@
|
|
1
|
+
# encoding: utf-8
|
2
|
+
|
3
|
+
require 'optparse'
|
4
|
+
|
5
|
+
# parse command line options based
|
6
|
+
# rubocop:disable MethodLength
|
7
|
+
class CliOptions
|
8
|
+
attr_accessor :force, :simulate, :verbose, :conf_file
|
9
|
+
|
10
|
+
def initialize(argv = ARGV)
|
11
|
+
parse_opt!(argv)
|
12
|
+
case argv.size
|
13
|
+
when 1 then self.conf_file = argv.shift
|
14
|
+
when 0 then self.conf_file = AppStack::DEFAULT_CONF_FILE
|
15
|
+
else fail "too many configuration files (#{argv.join(', ')})."
|
16
|
+
end
|
17
|
+
end
|
18
|
+
|
19
|
+
# parse command line options
|
20
|
+
def parse_opt!(argv)
|
21
|
+
opt_parser = OptionParser.new do |opts|
|
22
|
+
opts.banner = 'Usage: appstack [options] [config_file]'
|
23
|
+
|
24
|
+
opts.separator ''
|
25
|
+
opts.separator 'Available options:'
|
26
|
+
|
27
|
+
opts.on('-f', '--force', 'force overwrite') do
|
28
|
+
self.force = true
|
29
|
+
end
|
30
|
+
|
31
|
+
opts.on('-s', '--simulate', 'simulate only, do not copy') do
|
32
|
+
self.simulate = true
|
33
|
+
end
|
34
|
+
|
35
|
+
opts.on('--verbose', 'show debug messages') do
|
36
|
+
self.verbose = true
|
37
|
+
end
|
38
|
+
|
39
|
+
opts.on_tail('-h', '--help', 'show this message') do
|
40
|
+
puts opts
|
41
|
+
exit
|
42
|
+
end
|
43
|
+
|
44
|
+
opts.on_tail('-v', '--version', 'show version number') do
|
45
|
+
puts AppStack::VERSION
|
46
|
+
exit
|
47
|
+
end
|
48
|
+
end
|
49
|
+
|
50
|
+
opt_parser.parse!(argv)
|
51
|
+
end
|
52
|
+
end
|
@@ -0,0 +1,144 @@
|
|
1
|
+
# encoding: utf-8
|
2
|
+
|
3
|
+
require 'diffy'
|
4
|
+
require 'tilt'
|
5
|
+
require 'ostruct'
|
6
|
+
|
7
|
+
module AppStack
|
8
|
+
# import from outside apps
|
9
|
+
module CopyListBuilder
|
10
|
+
# get exported source file list from app, filtered by import_conf
|
11
|
+
def import_files(import_conf)
|
12
|
+
file_list = {}
|
13
|
+
import_conf.each do |c|
|
14
|
+
if c.is_a?(String) # group name
|
15
|
+
echo "import from group #{c.bold.blue}"
|
16
|
+
file_list.merge! export_files(c)
|
17
|
+
elsif c.is_a?(Hash)
|
18
|
+
echo "import form file: ", c
|
19
|
+
file_list.merge! glob_files(c, true)
|
20
|
+
else
|
21
|
+
fail 'unknown import options: ' + c.inspect
|
22
|
+
end
|
23
|
+
end
|
24
|
+
file_list
|
25
|
+
end
|
26
|
+
|
27
|
+
# render/copy file list
|
28
|
+
def check_mtime
|
29
|
+
@render_files, @copy_candidates = {}, {}
|
30
|
+
@copy_list.each do |f, t|
|
31
|
+
type, f = f.split ':', 2
|
32
|
+
|
33
|
+
# exclude file in the exclude list
|
34
|
+
excluded = false
|
35
|
+
@config[:exclude].each do |patt|
|
36
|
+
if File.fnmatch?(patt, t)
|
37
|
+
echo "exclude #{short_path(t)} by patthern ", patt
|
38
|
+
excluded = true
|
39
|
+
break
|
40
|
+
end
|
41
|
+
end
|
42
|
+
next if excluded
|
43
|
+
|
44
|
+
# check modification time
|
45
|
+
if type == 'c'
|
46
|
+
if newer?(f, t)
|
47
|
+
@copy_candidates[t] = f
|
48
|
+
else
|
49
|
+
echo "skip copy #{short_path(t).blue} (mtime or existence)."
|
50
|
+
end
|
51
|
+
elsif type == 'r'
|
52
|
+
if newer?(f, t) or @attr_mtime > File.mtime(t)
|
53
|
+
@render_files[t] = f
|
54
|
+
else
|
55
|
+
echo "skip render #{short_path(t).blue} (mtime or existence)."
|
56
|
+
end
|
57
|
+
else
|
58
|
+
fail "unknown operation type #{type} for #{short_path(t)}"
|
59
|
+
end
|
60
|
+
end
|
61
|
+
end
|
62
|
+
|
63
|
+
def check_diff
|
64
|
+
@copy_files, @diffs = {}, {}
|
65
|
+
@copy_candidates.each do |t, f|
|
66
|
+
if File.exists?(t)
|
67
|
+
diff = Diffy::Diff.new(f, t, :source => 'files')
|
68
|
+
if diff
|
69
|
+
@diffs[t] = diff
|
70
|
+
@copy_files[t] = f
|
71
|
+
else
|
72
|
+
echo "Skip copy #{short_path(t).blue} (no diff)."
|
73
|
+
end
|
74
|
+
else
|
75
|
+
@copy_files[t] = f
|
76
|
+
end
|
77
|
+
end
|
78
|
+
end
|
79
|
+
|
80
|
+
def merge!
|
81
|
+
check_mtime
|
82
|
+
check_diff
|
83
|
+
echo 'final copy list: ', @copy_files
|
84
|
+
echo 'final diff list: ', @diffs
|
85
|
+
echo 'final render lists: ', @render_files
|
86
|
+
|
87
|
+
if @diffs.keys.size > 0
|
88
|
+
ask_diffs # quit, copy and show diffs special files
|
89
|
+
else
|
90
|
+
do_copy!
|
91
|
+
do_render!
|
92
|
+
end
|
93
|
+
end
|
94
|
+
|
95
|
+
def ask_diffs
|
96
|
+
puts "These files are changed remotely:"
|
97
|
+
i = 1
|
98
|
+
@diffs.each do |t, diff|
|
99
|
+
puts "[#{i.to_s.bold}] " + short_path(t).blue
|
100
|
+
puts "from: #{@copy_files[t].blue}"
|
101
|
+
puts diff.to_s(:color)
|
102
|
+
end
|
103
|
+
|
104
|
+
puts "use -f (--option) option to overwrite all files,"
|
105
|
+
puts "or 'touch' local file to disable warn for specific file."
|
106
|
+
end
|
107
|
+
|
108
|
+
def do_copy!
|
109
|
+
@copy_files.each { |to, fr| copy_file!(fr, to) }
|
110
|
+
end
|
111
|
+
|
112
|
+
def do_render!
|
113
|
+
@render_files.each { |to, fr| render_file!(fr, to) }
|
114
|
+
end
|
115
|
+
|
116
|
+
# if f1 newer than f2, or f2 not exits but f1 does.
|
117
|
+
def newer?(f1, f2)
|
118
|
+
return false unless File.exists?(f1)
|
119
|
+
return true unless File.exists?(f2)
|
120
|
+
File.mtime(f1) > File.mtime(f2)
|
121
|
+
end
|
122
|
+
|
123
|
+
def copy_file!(fr, to)
|
124
|
+
target_dir = File.dirname(to)
|
125
|
+
FileUtils.mkdir_p target_dir unless File.directory?(target_dir)
|
126
|
+
puts "copied #{fr.blue} \n to: " + to.green.bold
|
127
|
+
FileUtils.copy fr, to
|
128
|
+
end
|
129
|
+
|
130
|
+
def render_file!(fr, to)
|
131
|
+
oh = File.open(to, 'wb')
|
132
|
+
if fr.match(/\.liquid$/)
|
133
|
+
require 'liquid'
|
134
|
+
oh.write Liquid::Template.parse(File.open(fr,
|
135
|
+
'r:utf-8').read).render(attrs)
|
136
|
+
else
|
137
|
+
tilt = Tilt.new(fr)
|
138
|
+
oh.write tilt.render(OpenStruct.new(attrs))
|
139
|
+
end
|
140
|
+
oh.close
|
141
|
+
puts "readered #{fr.blue}\n to: " + to.green.bold
|
142
|
+
end
|
143
|
+
end
|
144
|
+
end
|
@@ -0,0 +1,95 @@
|
|
1
|
+
# encoding: utf-8
|
2
|
+
|
3
|
+
module AppStack
|
4
|
+
# parse local files from a local app directory
|
5
|
+
module LocalFilesParser
|
6
|
+
def attrs
|
7
|
+
@config[:attrs]
|
8
|
+
end
|
9
|
+
|
10
|
+
def directory
|
11
|
+
File.expand_path('../', @file)
|
12
|
+
end
|
13
|
+
|
14
|
+
# use the direct name of the config file as app name
|
15
|
+
def app_name
|
16
|
+
File.basename(directory)
|
17
|
+
end
|
18
|
+
|
19
|
+
def full_path(file)
|
20
|
+
File.expand_path(file, directory)
|
21
|
+
end
|
22
|
+
|
23
|
+
def short_path(path)
|
24
|
+
lpath = path.sub(/^((c|r)\:)?#{directory}\/?/, '')
|
25
|
+
lpath.sub(/^\//, '')
|
26
|
+
end
|
27
|
+
|
28
|
+
# get export files list (copy_from => copy_to hash) for a specific group
|
29
|
+
def export_files(group = 'default')
|
30
|
+
@export_files ||= parse_export_files
|
31
|
+
group = 'default' if group.to_s == 'defaults' # back-compatibility
|
32
|
+
@export_files[group.to_s]
|
33
|
+
end
|
34
|
+
|
35
|
+
# get all exported files in groups
|
36
|
+
def parse_export_files
|
37
|
+
# 'file_group_name' => { copy_from => copy_to_base_name }
|
38
|
+
@export_files ||= {}
|
39
|
+
@config[:export].each do |p_list| # pattern list
|
40
|
+
if p_list.is_a?(Hash) # group, file list
|
41
|
+
p_list.each do |n, p|
|
42
|
+
@export_files[n] ||= {}
|
43
|
+
@export_files[n].merge! find_files(p)
|
44
|
+
end
|
45
|
+
elsif p_list.is_a?(String)
|
46
|
+
@export_files['default'] ||= {}
|
47
|
+
@export_files['default'].merge! find_files([p_list])
|
48
|
+
else
|
49
|
+
fail 'invalid export option ' + p_list.inspect
|
50
|
+
end
|
51
|
+
end
|
52
|
+
@export_files
|
53
|
+
end
|
54
|
+
|
55
|
+
def switch_to_tpl(file)
|
56
|
+
f = full_path(file)
|
57
|
+
tpl_file = nil
|
58
|
+
@config[:tpl_ext].each { |ex| tpl_file = f + ex if File.exists?(f + ex) }
|
59
|
+
tpl_file ? 'r:' + tpl_file : 'c:' + f
|
60
|
+
end
|
61
|
+
|
62
|
+
# from file pattern to copy_from => copy_to (remove directory header) hash
|
63
|
+
def glob_files(dir, allow_hash = false)
|
64
|
+
fhsh = {}
|
65
|
+
if dir.is_a?(Hash)
|
66
|
+
raise 'Can not use hash here for ' + dir.keys.join.to_s + ' in file ' +
|
67
|
+
filename unless allow_hash
|
68
|
+
dir.each do |f, t|
|
69
|
+
t = '/' + t.gsub(/^\//, '')
|
70
|
+
fhsh[switch_to_tpl(f)] = t
|
71
|
+
echo "found: #{short_path(switch_to_tpl(f)).blue} to: ",
|
72
|
+
short_path(t)
|
73
|
+
end
|
74
|
+
else
|
75
|
+
Dir[File.expand_path(dir, directory)].each do |f|
|
76
|
+
fhsh[switch_to_tpl(f)] = f.gsub(/^#{directory}/, '')
|
77
|
+
echo "found: #{short_path(switch_to_tpl(f)).blue} to: ",
|
78
|
+
short_path(short_path(f.gsub(/^#{directory}/, '')))
|
79
|
+
end
|
80
|
+
end
|
81
|
+
|
82
|
+
fhsh
|
83
|
+
end
|
84
|
+
|
85
|
+
# from array (or string) of file patterns, glob files and build a
|
86
|
+
# large array
|
87
|
+
def find_files(plist)
|
88
|
+
fhsh = {}
|
89
|
+
plist.each do |file_pattern|
|
90
|
+
fhsh.merge! glob_files(file_pattern)
|
91
|
+
end
|
92
|
+
fhsh
|
93
|
+
end
|
94
|
+
end
|
95
|
+
end
|
@@ -0,0 +1,114 @@
|
|
1
|
+
# encoding: utf-8
|
2
|
+
|
3
|
+
require 'yaml'
|
4
|
+
require 'pp'
|
5
|
+
|
6
|
+
module AppStack
|
7
|
+
# content parse error
|
8
|
+
class ParseError < RuntimeError; end
|
9
|
+
|
10
|
+
# represent a single stacked application
|
11
|
+
class StackApp
|
12
|
+
attr_reader :file_mtime
|
13
|
+
|
14
|
+
include LocalFilesParser
|
15
|
+
include CopyListBuilder
|
16
|
+
|
17
|
+
def initialize(filename, options)
|
18
|
+
@filename, @options = filename, options
|
19
|
+
@file = File.expand_path(filename)
|
20
|
+
@file_mtime = File.mtime(@file)
|
21
|
+
|
22
|
+
# default configuration, also restrict known keys and data type
|
23
|
+
@config = {
|
24
|
+
stack: [],
|
25
|
+
export: [],
|
26
|
+
exclude: [],
|
27
|
+
attrs: {},
|
28
|
+
stack_dir: '..',
|
29
|
+
tpl_ext: %w[.erb .haml .liquid]
|
30
|
+
}
|
31
|
+
|
32
|
+
echo "load app #{app_name.bold} from file:", @file
|
33
|
+
# use yaml file to set configuration
|
34
|
+
YAML.load(File.open(@file, 'r:utf-8').read).each do |k, v|
|
35
|
+
fail ParseError,
|
36
|
+
"unkown option `#{k}` in #{@filename}" unless @config[k.to_sym]
|
37
|
+
fail ParseError,
|
38
|
+
"'#{k}' must be a #{@config[k.to_sym].class.to_s}" unless
|
39
|
+
v.is_a?(@config[k.to_sym].class)
|
40
|
+
echo "set #{k.blue} to: ", v
|
41
|
+
@config[k.to_sym] = v
|
42
|
+
end
|
43
|
+
end
|
44
|
+
|
45
|
+
# load definitions from all apps in the stack config
|
46
|
+
def load_stack
|
47
|
+
unless @stack
|
48
|
+
@stack = { } # stack_app => import list
|
49
|
+
@config[:stack].each do |app_conf|
|
50
|
+
if app_conf.is_a?(String)
|
51
|
+
app_name, groups = app_conf, ['default']
|
52
|
+
elsif app_conf.is_a?(Hash)
|
53
|
+
fail 'invalid app: ' + app_conf.inspect if app_conf.keys.size > 1
|
54
|
+
app_conf.each { |an, ac| app_name, groups = an, ac }
|
55
|
+
else
|
56
|
+
fail 'invalid stack app: ' + app_conf.inspect
|
57
|
+
end
|
58
|
+
|
59
|
+
conf_file = @config[:stack_dir].sub(/\/?$/, '/') + app_name
|
60
|
+
conf_file += '/' + File.basename(@file)
|
61
|
+
app = StackApp.new(conf_file, @options)
|
62
|
+
@stack[app] = groups
|
63
|
+
end
|
64
|
+
end
|
65
|
+
@stack
|
66
|
+
end
|
67
|
+
|
68
|
+
# entry point: copy or simulate copy
|
69
|
+
def stackup!
|
70
|
+
@copy_list = {} # from_file_full_path => copy item
|
71
|
+
new_attrs, @attr_mtime = {}, file_mtime
|
72
|
+
load_stack.each do |app, import_conf|
|
73
|
+
echo 'load files from ' + app.app_name.bold.blue
|
74
|
+
|
75
|
+
# get file list from app
|
76
|
+
app.import_files(import_conf).each do |f, t|
|
77
|
+
@copy_list[f] = full_path(short_path(t))
|
78
|
+
end
|
79
|
+
|
80
|
+
# update global attrs
|
81
|
+
new_attrs.deep_merge! app.attrs
|
82
|
+
@attr_mtime = app.file_mtime if app.file_mtime > @attr_mtime
|
83
|
+
end
|
84
|
+
|
85
|
+
@config[:attrs] = new_attrs.deep_merge attrs
|
86
|
+
echo 'the merged attributes', attrs
|
87
|
+
|
88
|
+
# add local template files the copy list
|
89
|
+
Dir[directory + "/**/*{#{@config[:tpl_ext].join(',')}}"].each do |f|
|
90
|
+
@copy_list['r:' + f] = f.gsub(/#{@config[:tpl_ext].join('|')}$/, '')
|
91
|
+
echo 'found local template file: ',
|
92
|
+
short_path(f) + ' -> ' + short_path(@copy_list['r:' + f])
|
93
|
+
end
|
94
|
+
|
95
|
+
merge!
|
96
|
+
end
|
97
|
+
|
98
|
+
# echo message only if verbose specified to be true
|
99
|
+
def echo(msg, var = nil)
|
100
|
+
return unless @options.verbose
|
101
|
+
|
102
|
+
msg = "[#{app_name || self.class.name}] ".green + msg
|
103
|
+
msg += "\n" if var && var.inspect.size > 30
|
104
|
+
|
105
|
+
print msg
|
106
|
+
if var
|
107
|
+
print Term::ANSIColor.bold
|
108
|
+
var.inspect.size > 30 ? PP.pp(var) : PP.singleline_pp(var)
|
109
|
+
print Term::ANSIColor.reset
|
110
|
+
end
|
111
|
+
puts unless var && var.inspect.size > 30
|
112
|
+
end
|
113
|
+
end
|
114
|
+
end
|
data/lib/app_stack/version.rb
CHANGED
data/lib/app_stack.rb
CHANGED
@@ -1,34 +1,25 @@
|
|
1
1
|
# encoding: utf-8
|
2
2
|
|
3
|
-
require 'yaml'
|
4
|
-
require 'find'
|
5
|
-
require 'fileutils'
|
6
|
-
require 'ostruct'
|
7
|
-
require 'tilt'
|
8
|
-
require 'pathname'
|
9
|
-
require 'active_support/core_ext/hash/deep_merge'
|
10
|
-
|
11
3
|
require 'term/ansicolor'
|
12
4
|
# mixin String class for term-color methods
|
13
5
|
class String; include Term::ANSIColor end
|
14
6
|
|
15
|
-
require '
|
16
|
-
# require 'app_stack/copier'
|
17
|
-
require 'app_stack/merger'
|
18
|
-
|
19
|
-
## A namespace for app-stack based modules
|
20
|
-
module AppStack
|
21
|
-
CONF_FILE = './.app_stack.yml'
|
7
|
+
require 'active_support/core_ext/hash/deep_merge'
|
22
8
|
|
9
|
+
require 'app_stack/version'
|
10
|
+
require 'app_stack/cli_options'
|
11
|
+
require 'app_stack/local_files_parser'
|
12
|
+
require 'app_stack/copy_list_builder'
|
13
|
+
require 'app_stack/stack_app'
|
23
14
|
|
24
|
-
|
25
|
-
|
26
|
-
|
27
|
-
conf_file ||= CONF_FILE
|
28
|
-
mger = Merger.new(conf_file)
|
15
|
+
# module functions for handle stackup
|
16
|
+
module AppStack
|
17
|
+
DEFAULT_CONF_FILE = '.app_stack.yml'
|
29
18
|
|
30
|
-
|
31
|
-
|
19
|
+
# handle the execution to main class:
|
20
|
+
def stackup!(argv = ARGV)
|
21
|
+
@options = CliOptions.new(argv)
|
22
|
+
StackApp.new(@options.conf_file, @options).stackup!
|
32
23
|
end
|
33
24
|
|
34
25
|
module_function :stackup!
|
data/tags
ADDED
@@ -0,0 +1,45 @@
|
|
1
|
+
!_TAG_FILE_FORMAT 2 /extended format; --format=1 will not append ;" to lines/
|
2
|
+
!_TAG_FILE_SORTED 1 /0=unsorted, 1=sorted, 2=foldcase/
|
3
|
+
!_TAG_PROGRAM_AUTHOR Darren Hiebert /dhiebert@users.sourceforge.net/
|
4
|
+
!_TAG_PROGRAM_NAME Exuberant Ctags //
|
5
|
+
!_TAG_PROGRAM_URL http://ctags.sourceforge.net /official site/
|
6
|
+
!_TAG_PROGRAM_VERSION 5.8 //
|
7
|
+
AppStack lib/app_stack.rb /^module AppStack$/;" m
|
8
|
+
AppStack lib/app_stack/copy_list_builder.rb /^module AppStack$/;" m
|
9
|
+
AppStack lib/app_stack/local_files_parser.rb /^module AppStack$/;" m
|
10
|
+
AppStack lib/app_stack/merger.rb /^module AppStack$/;" m
|
11
|
+
AppStack lib/app_stack/stack_app.rb /^module AppStack$/;" m
|
12
|
+
AppStack lib/app_stack/version.rb /^module AppStack$/;" m
|
13
|
+
CliOptions lib/app_stack/cli_options.rb /^class CliOptions$/;" c
|
14
|
+
CopyListBuilder lib/app_stack/copy_list_builder.rb /^ module CopyListBuilder$/;" m class:AppStack
|
15
|
+
CopyListItem lib/app_stack/stack_app.rb /^ class CopyListItem$/;" c class:AppStack
|
16
|
+
LocalFilesParser lib/app_stack/local_files_parser.rb /^ module LocalFilesParser$/;" m class:AppStack
|
17
|
+
Merger lib/app_stack/merger.rb /^ class Merger$/;" c class:AppStack
|
18
|
+
ParseError lib/app_stack/stack_app.rb /^ class ParseError < RuntimeError; end$/;" c class:AppStack
|
19
|
+
StackApp lib/app_stack/stack_app.rb /^ class StackApp$/;" c class:AppStack
|
20
|
+
String lib/app_stack.rb /^class String; include Term::ANSIColor end$/;" c
|
21
|
+
app_name lib/app_stack/local_files_parser.rb /^ def app_name$/;" f class:AppStack.LocalFilesParser
|
22
|
+
attr_mod? lib/app_stack/merger.rb /^ def attr_mod?(to)$/;" f class:AppStack.Merger
|
23
|
+
copy_file! lib/app_stack/merger.rb /^ def copy_file!(fr, to)$/;" f class:AppStack.Merger
|
24
|
+
directory lib/app_stack/local_files_parser.rb /^ def directory$/;" f class:AppStack.LocalFilesParser
|
25
|
+
echo lib/app_stack/stack_app.rb /^ def echo(msg, var = nil)$/;" f class:AppStack.StackApp
|
26
|
+
export_files lib/app_stack/local_files_parser.rb /^ def export_files(group = 'default')$/;" f class:AppStack.LocalFilesParser
|
27
|
+
find_files lib/app_stack/local_files_parser.rb /^ def find_files(plist)$/;" f class:AppStack.LocalFilesParser
|
28
|
+
full_path lib/app_stack/local_files_parser.rb /^ def full_path(file)$/;" f class:AppStack.LocalFilesParser
|
29
|
+
glob_files lib/app_stack/local_files_parser.rb /^ def glob_files(dir, allow_hash = false)$/;" f class:AppStack.LocalFilesParser
|
30
|
+
import_files lib/app_stack/copy_list_builder.rb /^ def import_files(import_conf)$/;" f class:AppStack.CopyListBuilder
|
31
|
+
initialize lib/app_stack/cli_options.rb /^ def initialize(argv = ARGV)$/;" f class:CliOptions
|
32
|
+
initialize lib/app_stack/merger.rb /^ def initialize(conf_file, verbose = false)$/;" f class:AppStack.Merger
|
33
|
+
initialize lib/app_stack/stack_app.rb /^ def initialize(filename, options)$/;" f class:AppStack.StackApp
|
34
|
+
load_stack lib/app_stack/merger.rb /^ def load_stack(stack_name, groups)$/;" f class:AppStack.Merger
|
35
|
+
load_stack lib/app_stack/stack_app.rb /^ def load_stack$/;" f class:AppStack.StackApp
|
36
|
+
merge! lib/app_stack/merger.rb /^ def merge!$/;" f class:AppStack.Merger
|
37
|
+
newer? lib/app_stack/merger.rb /^ def newer?(f1, f2)$/;" f class:AppStack.Merger
|
38
|
+
parse_export_files lib/app_stack/local_files_parser.rb /^ def parse_export_files$/;" f class:AppStack.LocalFilesParser
|
39
|
+
parse_opt! lib/app_stack/cli_options.rb /^ def parse_opt!(argv)$/;" f class:CliOptions
|
40
|
+
parse_stacks lib/app_stack/merger.rb /^ def parse_stacks$/;" f class:AppStack.Merger
|
41
|
+
prepare lib/app_stack/merger.rb /^ def prepare(verbose = false)$/;" f class:AppStack.Merger
|
42
|
+
render_file! lib/app_stack/merger.rb /^ def render_file!(fr, to)$/;" f class:AppStack.Merger
|
43
|
+
short_path lib/app_stack/local_files_parser.rb /^ def short_path(path)$/;" f class:AppStack.LocalFilesParser
|
44
|
+
stackup! lib/app_stack.rb /^ def stackup!(argv = ARGV)$/;" f class:AppStack
|
45
|
+
stackup! lib/app_stack/stack_app.rb /^ def stackup!$/;" f class:AppStack.StackApp
|