summaryrefslogtreecommitdiff
path: root/baserockimport/exts/omnibus.to_chunk
blob: 0c56ea25c4480dffbf140b0161b83f08fe511a00 (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
#!/usr/bin/env ruby
#
# Create a chunk morphology to build Omnibus software in Baserock
#
# Copyright (C) 2014  Codethink Limited
#
# This program is free software; you can redistribute it and/or modify
# it under the terms of the GNU General Public License as published by
# the Free Software Foundation; version 2 of the License.
#
# This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
# GNU General Public License for more details.
#
# You should have received a copy of the GNU General Public License along
# with this program; if not, write to the Free Software Foundation, Inc.,
# 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.

require_relative 'importer_base'
require_relative 'importer_omnibus_extensions'

BANNER = "Usage: omnibus.to_chunk PROJECT_DIR PROJECT_NAME SOURCE_DIR SOFTWARE_NAME"

DESCRIPTION = <<-END
Generate a .morph file for a given Omnibus software component.
END

class OmnibusChunkMorphologyGenerator < Importer::Base
  def parse_options(arguments)
    opts = create_option_parser(BANNER, DESCRIPTION)

    parsed_arguments = opts.parse!(arguments)

    if parsed_arguments.length != 4 and parsed_arguments.length != 5
      STDERR.puts "Expected 4 or 5 arguments, got #{parsed_arguments}."
      opts.parse(['-?'])
      exit 255
    end

    project_dir, project_name, source_dir, software_name, expected_version = \
      parsed_arguments
    # Not yet implemented
    #if expected_version != nil
    #  expected_version = Gem::Version.new(expected_version)
    #end
    [project_dir, project_name, source_dir, software_name, expected_version]
  end

  class SubprocessError < RuntimeError
  end

  def run_tool_capture_output(tool_name, *args)
    scripts_dir = File.dirname(__FILE__)
    tool_path = File.join(scripts_dir, tool_name)

    # FIXME: something breaks when we try to share this FD, it's not
    # ideal that the subprocess doesn't log anything, though.
    env_changes = {'MORPH_LOG_FD' => nil}

    command = [[tool_path, tool_name], *args]
    log.info("Running #{command.join(' ')} in #{scripts_dir}")

    text = IO.popen(
      env_changes, command, :chdir => scripts_dir, :err => [:child, :out]
    ) do |io|
      io.read
    end

    if $? == 0
      text
    else
      raise SubprocessError, text
    end
  end

  def generate_chunk_morph_for_rubygems_software(software, source_dir)
    # This is a better heuristic for getting the name of the Gem
    # than the software name, it seems ...
    gem_name = software.relative_path

    text = run_tool_capture_output('rubygems.to_chunk', source_dir, gem_name)
    log.debug("Text from output: #{text}, result #{$?}")

    morphology = YAML::load(text)
    return morphology
  rescue SubprocessError => e
    error "Tried to import #{software.name} as a RubyGem, got the " \
          "following error from rubygems.to_chunk: #{e.message}"
    exit 1
  end

  def generate_chunk_morph_for_software(project, software, source_dir)
    if software.builder.built_gemspec != nil
      morphology = generate_chunk_morph_for_rubygems_software(software,
                                                              source_dir)
    else
      morphology = {
        "name" => software.name,
        "kind" => "chunk",
        "description" => "Automatically generated by omnibus.to_chunk"
      }
    end

    # Possibly this tool should look at software.build and
    # generate suitable configure, build and install-commands.
    # For now: don't bother!

    if software.description
      morphology['description'] = software.description + '\n\n' +
        morphology['description']
    end

    morphology
  end

  def run
    project_dir, project_name, source_dir, software_name = parse_options(ARGV)

    log.info("Creating chunk morph for #{software_name} from project " +
             "#{project_name}, defined in #{project_dir}")

    Dir.chdir(project_dir)

    project = Omnibus::Project.load(project_name)

    software = Omnibus::Software.load(@project, software_name)

    morph = generate_chunk_morph_for_software(project, software, source_dir)
    write_morph(STDOUT, morph)
  end
end

OmnibusChunkMorphologyGenerator.new.run