You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

149 lines
4.7 KiB

10 years ago
  1. #!/usr/bin/env escript
  2. %% -*- mode: erlang;erlang-indent-level: 4;indent-tabs-mode: nil -*-
  3. %% ex: ft=erlang ts=4 sw=4 et
  4. main(Args) ->
  5. case lists:member("--help", Args) of
  6. true ->
  7. usage(),
  8. halt(0);
  9. false ->
  10. ok
  11. end,
  12. %% Get a string repr of build time
  13. Built = build_time(),
  14. %% Get a string repr of first matching VCS changeset
  15. VcsInfo = vcs_info([{hg, ".hg", "hg identify -i", "hg status"},
  16. {git, ".git", "git describe --always --tags",
  17. "git status -s"}]),
  18. %% Check for force=1 flag to force a rebuild
  19. case lists:member("force=1", Args) of
  20. true ->
  21. rm("ebin/*.beam");
  22. false ->
  23. rm("ebin/rebar.beam")
  24. end,
  25. %% Add check for debug flag
  26. DebugFlag = case lists:member("debug", Args) of
  27. true -> debug_info;
  28. false -> undefined
  29. end,
  30. %% Extract the system info of the version of OTP we use to compile rebar
  31. OtpInfo = string:strip(erlang:system_info(otp_release), both, $\n),
  32. %% Types dict:dict() and digraph:digraph() have been introduced in
  33. %% Erlang 17.
  34. %% At the same time, their counterparts dict() and digraph() are to be
  35. %% deprecated in Erlang 18. namespaced_types option is used to select
  36. %% proper type name depending on the OTP version used.
  37. NamespacedTypes = case is_otp(OtpInfo, "^[0-9]+") of
  38. true -> {d, namespaced_types};
  39. false -> undefined
  40. end,
  41. %% Compile all src/*.erl to ebin
  42. case make:files(filelib:wildcard("src/*.erl"),
  43. [{outdir, "ebin"}, {i, "include"},
  44. DebugFlag,
  45. NamespacedTypes,
  46. {d, 'BUILD_TIME', Built},
  47. {d, 'VCS_INFO', VcsInfo},
  48. {d, 'OTP_INFO', OtpInfo}]) of
  49. up_to_date ->
  50. ok;
  51. error ->
  52. io:format("Failed to compile rebar files!\n"),
  53. halt(1)
  54. end,
  55. %% Make sure file:consult can parse the .app file
  56. case file:consult("ebin/rebar.app") of
  57. {ok, _} ->
  58. ok;
  59. {error, Reason} ->
  60. io:format("Invalid syntax in ebin/rebar.app: ~p\n", [Reason]),
  61. halt(1)
  62. end,
  63. %% Add ebin/ to our path
  64. true = code:add_path("ebin"),
  65. %% Run rebar compile to do proper .app validation etc.
  66. %% and rebar escriptize to create the rebar script
  67. RebarArgs = Args -- ["debug"], %% Avoid trying to run 'debug' command
  68. rebar:main(["compile", "escriptize"] ++ RebarArgs),
  69. %% Finally, update executable perms for our script on *nix,
  70. %% or write out script files on win32.
  71. case os:type() of
  72. {unix,_} ->
  73. [] = os:cmd("chmod u+x rebar"),
  74. ok;
  75. {win32,_} ->
  76. write_windows_scripts(),
  77. ok;
  78. _ ->
  79. ok
  80. end,
  81. %% Add a helpful message
  82. io:format("Congratulations! You now have a self-contained script called"
  83. " \"rebar\" in\n"
  84. "your current working directory. "
  85. "Place this script anywhere in your path\n"
  86. "and you can use rebar to build OTP-compliant apps.\n").
  87. usage() ->
  88. io:format("Usage: bootstrap [OPTION]...~n"),
  89. io:format(" force=1 unconditional build~n"),
  90. io:format(" debug add debug information~n").
  91. is_otp(OtpInfo, Regex) ->
  92. case re:run(OtpInfo, Regex, [{capture, none}]) of
  93. match -> true;
  94. nomatch -> false
  95. end.
  96. rm(Path) ->
  97. NativePath = filename:nativename(Path),
  98. Cmd = case os:type() of
  99. {unix,_} -> "rm -f ";
  100. {win32,_} -> "del /q "
  101. end,
  102. [] = os:cmd(Cmd ++ NativePath),
  103. ok.
  104. build_time() ->
  105. {{Y, M, D}, {H, Min, S}} = calendar:now_to_universal_time(now()),
  106. lists:flatten(io_lib:format("~4..0w~2..0w~2..0w_~2..0w~2..0w~2..0w",
  107. [Y, M, D, H, Min, S])).
  108. vcs_info([]) ->
  109. "No VCS info available.";
  110. vcs_info([{Id, Dir, VsnCmd, StatusCmd} | Rest]) ->
  111. case filelib:is_dir(Dir) of
  112. true ->
  113. Vsn = string:strip(os:cmd(VsnCmd), both, $\n),
  114. Status = case string:strip(os:cmd(StatusCmd), both, $\n) of
  115. [] ->
  116. "";
  117. _ ->
  118. "-dirty"
  119. end,
  120. lists:concat([Id, " ", Vsn, Status]);
  121. false ->
  122. vcs_info(Rest)
  123. end.
  124. write_windows_scripts() ->
  125. CmdScript=
  126. "@echo off\r\n"
  127. "setlocal\r\n"
  128. "set rebarscript=%~f0\r\n"
  129. "escript.exe \"%rebarscript:.cmd=%\" %*\r\n",
  130. ok = file:write_file("rebar.cmd", CmdScript).