summaryrefslogtreecommitdiff
path: root/lib/leap_cli/bootstrap.rb
blob: b7bc8e9367ece62801e1807a53f0c507020410dd (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
#
# Initial bootstrap loading of all the necessary things that needed
# for the `leap` command.
#

module LeapCli
  module Bootstrap
    extend LeapCli::Log
    extend self

    #
    # the argument leapfile_path is only used for tests
    #
    def setup(argv, leapfile_path=nil)
      setup_logging(argv)
      setup_leapfile(argv, leapfile_path)
    end

    #
    # print out the version string and exit.
    # called from leap executable.
    #
    def handle_version(app)
      puts "leap #{LeapCli::VERSION}, ruby #{RUBY_VERSION}"
      begin
        log_version
      rescue StandardError => exc
        puts exc.to_s
        raise exc if DEBUG
      end
      exit(0)
    end

    #
    # load the commands.
    # called from leap executable.
    #
    def load_libraries(app)
      if LeapCli.log_level >= 2
        log_version
      end
      load_commands(app)
      load_macros
    end

    #
    # initialize the global options.
    # called from pre.rb
    #
    def setup_global_options(app, global)
      if global[:force]
        global[:yes] = true
      end
      if Process::Sys.getuid == 0
        Util.bail! "`leap` should not be run as root."
      end
    end

    private

    #
    # Initial logging
    #
    # This is called very early by leap executable, because
    # everything depends on the log file and log options
    # being set correctly before any work is done.
    #
    # The Leapfile might later load additional logging
    # options.
    #
    def setup_logging(argv)
      options = parse_logging_options(argv)
      verbose = (options[:verbose] || 1).to_i
      if verbose
        LeapCli.set_log_level(verbose)
      end
      if options[:log]
        LeapCli.log_file = options[:log]
        LeapCli::Util.log_raw(:log) { $0 + ' ' + argv.join(' ')}
      end
      unless options[:color].nil?
        LeapCli.log_in_color = options[:color]
      end
    end

    #
    # load the leapfile and set the Path variables.
    #
    def setup_leapfile(argv, leapfile_path)
      LeapCli.leapfile.load(leapfile_path)
      if LeapCli.leapfile.valid?
        Path.set_platform_path(LeapCli.leapfile.platform_directory_path)
        Path.set_provider_path(LeapCli.leapfile.provider_directory_path)
        if !Path.provider || !File.directory?(Path.provider)
          bail! { log :missing, "provider directory '#{Path.provider}'" }
        end
        if !Path.platform || !File.directory?(Path.platform)
          bail! { log :missing, "platform directory '#{Path.platform}'" }
        end
        if LeapCli.log_file.nil? && LeapCli.leapfile.log
          LeapCli.log_file = LeapCli.leapfile.log
        end
      elsif !leapfile_optional?(argv)
        puts
        puts " ="
        log :note, "There is no `Leapfile` in this directory, or any parent directory.\n"+
                   " =       "+
                   "Without this file, most commands will not be available."
        puts " ="
        puts
      end
    end

    #
    # Add a log entry for the leap command and leap platform versions.
    #
    def log_version(force=false)
      str = "leap command v#{LeapCli::VERSION}"
      if Util.is_git_directory?(LEAP_CLI_BASE_DIR)
        str << " (%s %s)" % [Util.current_git_branch(LEAP_CLI_BASE_DIR),
          Util.current_git_commit(LEAP_CLI_BASE_DIR)]
      else
        str << " (%s)" % LEAP_CLI_BASE_DIR
      end
      log str
      if LeapCli.leapfile.valid?
        str = "leap platform v#{Leap::Platform.version}"
        if Util.is_git_directory?(Path.platform)
          str << " (%s %s)" % [Util.current_git_branch(Path.platform), Util.current_git_commit(Path.platform)]
        end
        log str
      end
    end

    def parse_logging_options(argv)
      argv = argv.dup
      options = {:color => true, :verbose => 1}
      loop do
        current = argv.shift
        case current
          when '--verbose'  then options[:verbose] = argv.shift;
          when /-v[0-9]/    then options[:verbose] = current[-1];
          when '--log'      then options[:log] = argv.shift;
          when '--no-color' then options[:color] = false;
          when nil          then break;
        end
      end
      options
    end

    #
    # Returns true if loading the Leapfile is optional.
    #
    # We could make the 'new' command skip the 'pre' command, and then load Leapfile
    # from 'pre', but for various reasons we want the Leapfile loaded even earlier
    # than that. So, we need a way to test to see if loading the leapfile is optional
    # before any of the commands are loaded and the argument list is parsed by GLI.
    # Yes, hacky.
    #
    def leapfile_optional?(argv)
      if argv.include?('--version')
        return true
      else
        without_flags = argv.select {|i| i !~ /^-/}
        if without_flags.first == 'new'
          return true
        end
      end
      return false
    end

    #
    # loads the GLI command definition files
    #
    def load_commands(app)
      app.commands_from('leap_cli/commands')
      if Path.platform
        app.commands_from(Path.platform + '/lib/leap_cli/commands')
      end
    end

    #
    # loads the platform's macro definition files
    #
    def load_macros
      if Path.platform
        platform_macro_files = Dir[Path.platform + '/lib/leap_cli/macros/*.rb']
        if platform_macro_files.any?
          platform_macro_files.each do |macro_file|
            require macro_file
          end
        end
      end
    end

  end
end