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
         
     |