Class: Cigale::CLI

Inherits:
Exts
  • Object
show all
Includes:
Generator
Defined in:
lib/cigale/cli.rb

Overview

Command-line interface, need to be exploded further

Instance Method Summary collapse

Methods included from Generator

#insert_raw, #method_for_translate, #translate, #translate_flow_project, #translate_job, #translate_matrix_project, #translate_maven_moduleset

Methods inherited from Exts

#asplode, #boolp, #dig, #first_pair, #toa, #toh

Constructor Details

#initialize(args) ⇒ CLI

Returns a new instance of CLI.



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
# File 'lib/cigale/cli.rb', line 25

def initialize (args)
  @numjobs = 0

  opts = Slop.parse args do |o|
    o.banner = "Usage: cigale [options] [command] [spec_file.yml]"

    o.string "-o", "output", "Output directory", :default => "."
    o.bool "--fixture", "fixture", "Enable fixture mode", :default => false
    o.bool "--masquerade", "masquerade", "Try to pass off as jenkins-job-builder", :default => false
    o.integer "--blowup", "blowup", "Max macro expansion rounds", :default => 1023
    o.string "--test-category", "test_category", "Test category"
    o.string "-l", "loglevel", "Logger level", :default => "INFO"
  end
  @opts = opts

  logger.level = Logger.const_get opts[:loglevel]

  if opts.arguments.empty?
    logger.error "No command given"
    print_usage!
    return
  end

  cmd, input = opts.arguments
  case cmd
  when "test", "dump", "update"
    # all good
  else
    logger.error "Unknown command: #{cmd}"
    exit 1
  end

  unless input
    logger.error "No input given"
    print_usage!
    exit 1
  end

  inputs = if File.directory? input
    Dir.glob(File.join(input, "**", "*.y{a,}ml"))
  else
    [input]
  end

  entries = []

  for input in inputs
    logger.info "Parsing #{input}"
    parsed = YAML.load_file(input)

    unless Array === parsed
      raise "Top-level entity in YAML must be an array" unless opts[:fixture]
      parsed = [{"job" => parsed}]
    end

    entries += parsed
  end

  # sort out macro definitions from actual entries
  @library = {}
  @definitions = []

  for entry in entries
    etype, edef = first_pair(entry)

    case etype
    when Symbol
      # ruby's yaml parses `:key: val` as `:key => val` rather
      # than `":key" => val`, so macro definitions in cigale have symbol keys
      @library[etype.to_s] = edef
    else
      @definitions.push entry
    end
  end

  logger.info "Parsed #{@library.size} macros, #{@definitions.size} job definitions."

  output = opts[:output]
  client = nil

  case cmd
  when "test", "dump"
    logger.info "Creating directory #{output}"
    FileUtils.mkdir_p output
  when "update"
    client = get_client!
    all_jobs = client.job.list_all
    logger.info "Before update, job list: "
    all_jobs.each { |x| logger.info "  - #{x}" }
  end

  expanded_entries = []
  integrate_defs(expanded_entries, @definitions)

  for entry in expanded_entries
    etype, edef = first_pair(entry)
    if edef["name"].nil?
      raise "Jobs must have names: #{edef.inspect}" unless opts[:fixture]
      edef["name"] = "fixture"
      edef["project-type"] ||= "project"
    end

    job_name = edef["name"]
    job_path = File.join(output, job_name)

    case etype
    when "job"
      @numjobs += 1
      case cmd
      when "dump"
        File.open(job_path + ".yml", "w") do |f|
          f.write entry.to_yaml
        end
      else
        xml = ::Builder::XmlMarkup.new(:indent => 2)
        xml.instruct! :xml, :version => "1.0", :encoding => "utf-8"
        translate_job xml, edef

        case cmd
        when "test"
          File.open(job_path + ".xml", "w") do |f|
            f.write(xml.target!)
          end
        when "update"
          client.job.create_or_update(job_name, xml.target!)
        end
      end
    else
      raise "Unknown top-level type: #{etype}"
    end
  end

  logger.info "Generated #{@numjobs} jobs."
end

Instance Method Details

#fully_expand(entry) ⇒ Object



171
172
173
174
175
176
177
178
179
180
181
182
183
184
# File 'lib/cigale/cli.rb', line 171

def fully_expand (entry)
  original = entry
  iterations = 0

  # TODO detect circular dependencies instead
  while iterations < @opts[:blowup]
    ctx = MacroContext.new :library => @library
    entry = ctx.expand(entry)
    return entry unless ctx.had_expansions?
    iterations += 1
  end

  raise "Blew up while trying to expand #{original.inspect}"
end

#get_client!Object



195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
# File 'lib/cigale/cli.rb', line 195

def get_client!
  config_path = "secret/cigale.yml"
  config = {}

  begin
    config = YAML.load_file(config_path)
  rescue Errno::ENOENT => e
    logger.error "Config file missing: #{config_path}"
    logger.error "Please create one. The `server` section can have any of the fields listed at:"
    logger.error " http://github.arangamani.net/jenkins_api_client/JenkinsApi/Client.html#initialize-instance_method"
    exit 1
  end

  JenkinsApi::Client.new(config["server"])
end

#integrate_defs(expanded_entries, defs) ⇒ Object



160
161
162
163
164
165
166
167
168
169
# File 'lib/cigale/cli.rb', line 160

def integrate_defs (expanded_entries, defs)
  for entry in defs
    case e = fully_expand(entry)
    when Cigale::Splat
      integrate_defs(expanded_entries, e.elems)
    else
      expanded_entries << e
    end
  end
end

#loggerObject



19
20
21
22
23
# File 'lib/cigale/cli.rb', line 19

def logger
  @logger ||= Logger.new($stdout).tap do |log|
    log.progname = "cigale"
  end
end


190
191
192
193
# File 'lib/cigale/cli.rb', line 190

def print_usage!
  puts "cigale v#{VERSION}"
  puts "Usage: cigale [test] -o output/directory [spec file or directory]"
end

#underize(name) ⇒ Object



186
187
188
# File 'lib/cigale/cli.rb', line 186

def underize (name)
  name.gsub(/-/, '_')
end