├── .gitignore ├── README.md ├── lib ├── lingex.ex └── mix.ex ├── mix.exs ├── mix.lock └── test ├── lingex_test.exs └── test_helper.exs /.gitignore: -------------------------------------------------------------------------------- 1 | /ebin 2 | /deps 3 | erl_crash.dump 4 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # Lingex 2 | 3 | ** TODO: Add description ** 4 | -------------------------------------------------------------------------------- /lib/lingex.ex: -------------------------------------------------------------------------------- 1 | defmodule Lingex do 2 | def start do 3 | :ok = :application.start(:lingex) 4 | end 5 | end 6 | -------------------------------------------------------------------------------- /lib/mix.ex: -------------------------------------------------------------------------------- 1 | defmodule Mix.Tasks.Lingex do 2 | def start_build(project, files, opts) do 3 | case check_opts opts do 4 | {copts, bopts} -> 5 | start_build project, files, copts, bopts; 6 | error -> 7 | {:error,error} 8 | end 9 | end 10 | 11 | defp start_build(project, files, copts, bopts) do 12 | Mix.shell.info "Compressing #{length files} file(s)" 13 | any_name = 'tmptmp.zip' 14 | zip_files = Enum.map files, fn file -> :erlang.binary_to_list file end 15 | {:ok, {_, zip_data}} = :zip.zip(any_name, zip_files, [:memory]) 16 | 17 | Mix.shell.info "Uploading project archive [#{byte_size zip_data} byte(s)]" 18 | 19 | :ok = call_build_service :put, '/projects/#{project}', [], 20 | {'application/zip', zip_data}, copts 21 | Mix.shell.info "Project archive uploaded" 22 | 23 | apps = for {:import_lib, app} <- bopts, do: app 24 | app_list = Enum.map_join apps, ",", fn(x) -> "\"#{x}\"" end 25 | 26 | if bopts[:elixir_lib] do 27 | req_body = "{\"import_lib\":[#{app_list}],\"elixir_lib\":true}" 28 | else 29 | Mix.shell.info "Warning: elixir_lib:true option missing" 30 | req_body = "{\"import_lib\":[#{app_list}]}" 31 | end 32 | 33 | Mix.shell.info "Build started for #{project}" 34 | {:ok, banner} = call_build_service :post, "/build/#{project}", [], 35 | {'application/json', req_body}, copts 36 | Mix.shell.info "LBS: #{banner}" 37 | 38 | :ok 39 | end 40 | 41 | defp check_opts(opts) do 42 | check_opts opts, [], [] 43 | end 44 | 45 | defp check_opts([], copts, bopts) do 46 | {copts, bopts} 47 | end 48 | defp check_opts([{:build_host, _host} =opt|opts], copts, bopts) do 49 | check_opts opts, [opt|copts], bopts 50 | end 51 | defp check_opts([{:username, _name} =opt|opts], copts, bopts) do 52 | check_opts opts, [opt|copts], bopts 53 | end 54 | defp check_opts([{:password, _pwd} =opt|opts], copts, bopts) do 55 | check_opts opts, [opt|copts], bopts 56 | end 57 | defp check_opts([{:import, _pat} =opt|opts], copts, bopts) do 58 | check_opts opts, copts, [opt|bopts] 59 | end 60 | defp check_opts([{:import_lib, _lib} =opt|opts], copts, bopts) do 61 | check_opts opts, copts, [opt|bopts] 62 | end 63 | defp check_opts([{:elixir_lib, _} =opt|opts], copts, bopts) do 64 | check_opts opts, copts, [opt|bopts] 65 | end 66 | defp check_opts([opt|_opts], _copts, _bopts) do 67 | Mix.shell.error "invalid option: #{inspect opt}" 68 | :invalid 69 | end 70 | 71 | def retrieve_image(project, copts) do 72 | case call_build_service :get, "/build/#{project}/image", [], 73 | :none, copts do 74 | {:ok, resp_body} -> 75 | image_file = "vmling" 76 | image_bin = :erlang.list_to_binary resp_body 77 | Mix.shell.info "Saving image to #{image_file} [#{byte_size image_bin} byte(s)]" 78 | File.write! image_file, image_bin 79 | Mix.shell.info "LBS: image saved to #{image_file}" 80 | 81 | _other -> 82 | Mix.shell.error "LBS: image is not (yet?) available" 83 | end 84 | end 85 | 86 | def get_build_status(project, copts) do 87 | case call_build_service :get, "/build/#{project}/status", [], 88 | :none, copts do 89 | {:ok,'0'} -> 90 | :ok 91 | 92 | {:ok,'1'} -> 93 | receive do 94 | after 3000 -> 95 | :ok 96 | end 97 | get_build_status project, copts 98 | 99 | {:ok,'99'} -> 100 | :failed 101 | end 102 | end 103 | 104 | defp call_build_service(method, slug, hdrs, body, copts) do 105 | 106 | :ssl.start 107 | :inets.start 108 | 109 | build_host = copts[:build_host] 110 | user_name = copts[:username] 111 | password = copts[:password] 112 | 113 | encoded = :base64.encode_to_string '#{user_name}:#{password}' 114 | auth_header = {'Authorization', 'Basic #{encoded}'} 115 | headers = [auth_header] ++ hdrs 116 | 117 | location = 'https://#{build_host}/1#{slug}' 118 | request = case body do 119 | :none -> 120 | {location, headers} 121 | {ctype, body_data} -> 122 | {location, headers, ctype, body_data} 123 | end 124 | 125 | case :httpc.request method, request, [{:timeout, :infinity}], [] do 126 | {:ok, {{_, 200, _}, _, resp_body}} -> 127 | {:ok, resp_body} 128 | {:ok, {{_, 204, _}, _, _}} -> 129 | :ok 130 | {:ok, {{_, 403, _}, _, _}} -> 131 | :forbidden 132 | {:ok, {{_, 404, _}, _, _}} -> 133 | :not_found 134 | other -> 135 | Mix.shell.error "LBS: error: #{inspect other}" 136 | end 137 | end 138 | 139 | def collect_files(config, opts) do 140 | compile_path = Mix.Project.compile_path config 141 | 142 | files = Path.wildcard Path.join compile_path, "*" 143 | 144 | deps_path = config[:deps_path] 145 | files = Enum.reduce config[:deps], files, fn(x, acc) -> 146 | collect_dep_files(deps_path, x, acc) 147 | end 148 | 149 | misc_paths = for {:import, path} <- opts, do: path 150 | Enum.reduce misc_paths, files, fn(path, acc) -> 151 | acc ++ Path.wildcard path 152 | end 153 | end 154 | 155 | defp collect_dep_files(_deps_path, {:lingex, _}, acc), do: acc 156 | defp collect_dep_files(_deps_path, {:lingex, _, _}, acc), do: acc 157 | defp collect_dep_files(deps_path, {name, _, opts}, acc) do 158 | collect_dep_files(deps_path, {name, opts}, acc) 159 | end 160 | defp collect_dep_files(deps_path, {name, _}, acc) do 161 | dir = Path.join [deps_path,name,"ebin/*"] 162 | acc ++ Path.wildcard dir 163 | end 164 | 165 | end 166 | 167 | defmodule Mix.Tasks.Lingex.Build do 168 | 169 | @moduledoc """ 170 | The task uploads *.beam files of the project to the Erlang on Xen Build Service 171 | and initiates the build process. 172 | """ 173 | 174 | def run(_args) do 175 | config = Mix.Project.config 176 | opts = config[:lingex_opts] 177 | 178 | files = Mix.Tasks.Lingex.collect_files config, opts 179 | 180 | project = config[:app] 181 | Mix.Tasks.Lingex.start_build project, files, opts 182 | end 183 | end 184 | 185 | defmodule Mix.Tasks.Lingex.Image do 186 | 187 | @moduledoc """ 188 | The task retrieves the built Xen image from the Erlang on Xen Build Service. 189 | """ 190 | 191 | def run(_args) do 192 | config = Mix.Project.config 193 | opts = config[:lingex_opts] 194 | project = config[:app] 195 | Mix.Tasks.Lingex.retrieve_image project, opts 196 | end 197 | end 198 | 199 | defmodule Mix.Tasks.Lingex.Build_image do 200 | 201 | @moduledoc """ 202 | The task builds a Xen image for the project using the Erlang on Xen Build 203 | Service. 204 | """ 205 | 206 | def run(_args) do 207 | config = Mix.Project.config 208 | opts = config[:lingex_opts] 209 | 210 | files = Mix.Tasks.Lingex.collect_files config, opts 211 | 212 | project = config[:app] 213 | Mix.Tasks.Lingex.start_build project, files, opts 214 | 215 | case Mix.Tasks.Lingex.get_build_status project, opts do 216 | :ok -> 217 | Mix.Tasks.Lingex.retrieve_image project, opts 218 | 219 | :failed -> 220 | Mix.shell.error "LBS: **** build failed ****" 221 | end 222 | end 223 | end 224 | -------------------------------------------------------------------------------- /mix.exs: -------------------------------------------------------------------------------- 1 | defmodule Lingex.Mixfile do 2 | use Mix.Project 3 | 4 | def project do 5 | [ app: :lingex, 6 | version: "0.0.1", 7 | deps: deps ] 8 | end 9 | 10 | # Configuration for the OTP application 11 | def application do 12 | [] 13 | end 14 | 15 | # Returns the list of dependencies in the format: 16 | # { :foobar, "0.1", git: "https://github.com/elixir-lang/foobar.git" } 17 | defp deps do 18 | [] 19 | end 20 | end 21 | -------------------------------------------------------------------------------- /mix.lock: -------------------------------------------------------------------------------- 1 | [ "exjson": {:git,"https://github.com/guedes/exjson.git","b84686310bc2b8471b7f9617de3602d4717106d1",[]} ] 2 | -------------------------------------------------------------------------------- /test/lingex_test.exs: -------------------------------------------------------------------------------- 1 | Code.require_file "../test_helper.exs", __FILE__ 2 | 3 | defmodule LingexTest do 4 | use ExUnit.Case 5 | 6 | test "the truth" do 7 | assert(true) 8 | end 9 | end 10 | -------------------------------------------------------------------------------- /test/test_helper.exs: -------------------------------------------------------------------------------- 1 | ExUnit.start 2 | --------------------------------------------------------------------------------