Clone of https://github.com/NixOS/nixpkgs.git (to stress-test knotserver)
at release-20.03 108 lines 4.1 kB view raw
1#!/usr/bin/env escript 2%% -*- erlang-indent-level: 4;indent-tabs-mode: nil -*- 3%%! -smp enable 4%%% --------------------------------------------------------------------------- 5%%% @doc 6%%% The purpose of this command is to prepare a mix project so that mix 7%%% understands that the dependencies are all already installed. If you want a 8%%% hygienic build on nix then you must run this command before running mix. I 9%%% suggest that you add a `Makefile` to your project and have the bootstrap 10%%% command be a dependency of the build commands. See the nix documentation for 11%%% more information. 12%%% 13%%% This command designed to have as few dependencies as possible so that it can 14%%% be a dependency of root level packages like mix. To that end it does many 15%%% things in a fairly simplistic way. That is by design. 16%%% 17%%% ### Assumptions 18%%% 19%%% This command makes the following assumptions: 20%%% 21%%% * It is run in a nix-shell or nix-build environment 22%%% * that all dependencies have been added to the ERL_LIBS 23%%% Environment Variable 24 25-record(data, {version 26 , erl_libs 27 , root 28 , name}). 29-define(LOCAL_HEX_REGISTRY, "registry.ets"). 30 31main(Args) -> 32 {ok, RequiredData} = gather_required_data_from_the_environment(Args), 33 ok = bootstrap_libs(RequiredData). 34 35%% @doc 36%% This takes an app name in the standard OTP <name>-<version> format 37%% and returns just the app name. Why? Because rebar doesn't 38%% respect OTP conventions in some cases. 39-spec fixup_app_name(file:name()) -> string(). 40fixup_app_name(Path) -> 41 BaseName = filename:basename(Path), 42 case string:split(BaseName, "-") of 43 [Name, _Version] -> Name; 44 Name -> Name 45 end. 46 47 48-spec gather_required_data_from_the_environment([string()]) -> {ok, #data{}}. 49gather_required_data_from_the_environment(_) -> 50 {ok, #data{ version = guard_env("version") 51 , erl_libs = os:getenv("ERL_LIBS", []) 52 , root = code:root_dir() 53 , name = guard_env("name")}}. 54 55-spec guard_env(string()) -> string(). 56guard_env(Name) -> 57 case os:getenv(Name) of 58 false -> 59 stderr("Expected Environment variable ~s! Are you sure you are " 60 "running in a Nix environment? Either a nix-build, " 61 "nix-shell, etc?~n", [Name]), 62 erlang:halt(1); 63 Variable -> 64 Variable 65 end. 66 67-spec bootstrap_libs(#data{}) -> ok. 68bootstrap_libs(#data{erl_libs = ErlLibs}) -> 69 io:format("Bootstrapping dependent libraries~n"), 70 Target = "_build/prod/lib/", 71 Paths = string:tokens(ErlLibs, ":"), 72 CopiableFiles = 73 lists:foldl(fun(Path, Acc) -> 74 gather_directory_contents(Path) ++ Acc 75 end, [], Paths), 76 lists:foreach(fun (Path) -> 77 ok = link_app(Path, Target) 78 end, CopiableFiles). 79 80-spec gather_directory_contents(string()) -> [{string(), string()}]. 81gather_directory_contents(Path) -> 82 {ok, Names} = file:list_dir(Path), 83 lists:map(fun(AppName) -> 84 {filename:join(Path, AppName), fixup_app_name(AppName)} 85 end, Names). 86 87%% @doc 88%% Makes a symlink from the directory pointed at by Path to a 89%% directory of the same name in Target. So if we had a Path of 90%% {`foo/bar/baz/bash`, `baz`} and a Target of `faz/foo/foos`, the symlink 91%% would be `faz/foo/foos/baz`. 92-spec link_app({string(), string()}, string()) -> ok. 93link_app({Path, TargetFile}, TargetDir) -> 94 Target = filename:join(TargetDir, TargetFile), 95 ok = make_symlink(Path, Target). 96 97-spec make_symlink(string(), string()) -> ok. 98make_symlink(Path, TargetFile) -> 99 file:delete(TargetFile), 100 ok = filelib:ensure_dir(TargetFile), 101 io:format("Making symlink from ~s to ~s~n", [Path, TargetFile]), 102 ok = file:make_symlink(Path, TargetFile). 103 104%% @doc 105%% Write the result of the format string out to stderr. 106-spec stderr(string(), [term()]) -> ok. 107stderr(FormatStr, Args) -> 108 io:put_chars(standard_error, io_lib:format(FormatStr, Args)).