From 0f5e3932920969dba70ae8d7edcdfa97bb472c28 Mon Sep 17 00:00:00 2001 From: Steven Gravell Date: Thu, 30 Jun 2011 22:50:56 +0100 Subject: [PATCH] look for new and old versions in the target parent The target_dir config in reltool allows you to put your release in a directory other than in ./NAME, so we should look in the parent directory of that to find the new and old versions instead of simply looking in ./ Move untaring and retaring into a temporary path instead of in ./ to prevent name collisions with "releases" and "lib" that might exist already. Having a subdirectory rel/releases/ can be useful. --- src/rebar_appups.erl | 20 +++++---- src/rebar_rel_utils.erl | 74 ++++++++++++++++++++++++++++----- src/rebar_reltool.erl | 61 ++++------------------------ src/rebar_upgrade.erl | 90 +++++++++++++++++++++++++---------------- 4 files changed, 138 insertions(+), 107 deletions(-) diff --git a/src/rebar_appups.erl b/src/rebar_appups.erl index 871c426..b702e92 100644 --- a/src/rebar_appups.erl +++ b/src/rebar_appups.erl @@ -40,11 +40,15 @@ 'generate-appups'(_Config, ReltoolFile) -> %% Get the old release path - OldVerPath = rebar_rel_utils:get_previous_release_path(), + ReltoolConfig = rebar_rel_utils:load_config(ReltoolFile), + TargetParentDir = rebar_rel_utils:get_target_parent_dir(ReltoolConfig), + + OldVerPath = filename:join([TargetParentDir, + rebar_rel_utils:get_previous_release_path()]), %% Get the new and old release name and versions {Name, _Ver} = rebar_rel_utils:get_reltool_release_info(ReltoolFile), - NewVerPath = filename:join([".", Name]), + NewVerPath = filename:join([TargetParentDir, Name]), {NewName, NewVer} = rebar_rel_utils:get_rel_release_info(Name, NewVerPath), {OldName, OldVer} = rebar_rel_utils:get_rel_release_info(Name, OldVerPath), @@ -60,7 +64,7 @@ %% Get a list of any appup files that exist in the new release NewAppUpFiles = rebar_utils:find_files( - filename:join([NewName, "lib"]), "^.*.appup$"), + filename:join([NewVerPath, "lib"]), "^.*.appup$"), %% Convert the list of appup files into app names AppUpApps = [file_to_name(File) || File <- NewAppUpFiles], @@ -69,7 +73,7 @@ UpgradeApps = genappup_which_apps(Upgraded, AppUpApps), %% Generate appup files for upgraded apps - generate_appup_files(Name, OldVerPath, UpgradeApps), + generate_appup_files(NewVerPath, OldVerPath, UpgradeApps), ok. @@ -124,10 +128,10 @@ genappup_which_apps(UpgradedApps, [First|Rest]) -> genappup_which_apps(Apps, []) -> Apps. -generate_appup_files(Name, OldVerPath, [{App, {OldVer, NewVer}}|Rest]) -> - OldEbinDir = filename:join([".", OldVerPath, "lib", +generate_appup_files(NewVerPath, OldVerPath, [{App, {OldVer, NewVer}}|Rest]) -> + OldEbinDir = filename:join([OldVerPath, "lib", atom_to_list(App) ++ "-" ++ OldVer, "ebin"]), - NewEbinDir = filename:join([".", Name, "lib", + NewEbinDir = filename:join([NewVerPath, "lib", atom_to_list(App) ++ "-" ++ NewVer, "ebin"]), {AddedFiles, DeletedFiles, ChangedFiles} = beam_lib:cmp_dirs(NewEbinDir, @@ -147,7 +151,7 @@ generate_appup_files(Name, OldVerPath, [{App, {OldVer, NewVer}}|Rest]) -> OldVer, Inst, OldVer])), ?CONSOLE("Generated appup for ~p~n", [App]), - generate_appup_files(Name, OldVerPath, Rest); + generate_appup_files(NewVerPath, OldVerPath, Rest); generate_appup_files(_, _, []) -> ?CONSOLE("Appup generation complete~n", []). diff --git a/src/rebar_rel_utils.erl b/src/rebar_rel_utils.erl index 0b14a28..627ce13 100644 --- a/src/rebar_rel_utils.erl +++ b/src/rebar_rel_utils.erl @@ -34,7 +34,11 @@ get_rel_apps/1, get_rel_apps/2, get_previous_release_path/0, - get_rel_file_path/2]). + get_rel_file_path/2, + load_config/1, + get_sys_tuple/1, + get_target_dir/1, + get_target_parent_dir/1]). -include("rebar.hrl"). @@ -51,16 +55,11 @@ is_rel_dir(Dir) -> end. %% Get release name and version from a reltool.config -get_reltool_release_info(ReltoolFile) -> - %% expect sys to be the first proplist in reltool.config - case file:consult(ReltoolFile) of - {ok, [{sys, Config}| _]} -> - %% expect the first rel in the proplist to be the one you want - {rel, Name, Ver, _} = proplists:lookup(rel, Config), - {Name, Ver}; - _ -> - ?ABORT("Failed to parse ~s~n", [ReltoolFile]) - end. +get_reltool_release_info(ReltoolConfig) -> + %% expect the first rel in the proplist to be the one you want + {sys, Config} = get_sys_tuple(ReltoolConfig), + {rel, Name, Ver, _} = proplists:lookup(rel, Config), + {Name, Ver}. %% Get release name and version from a rel file get_rel_release_info(RelFile) -> @@ -107,6 +106,59 @@ get_previous_release_path() -> OldVerPath end. +%% +%% Load terms from reltool.config +%% +load_config(ReltoolFile) -> + case file:consult(ReltoolFile) of + {ok, Terms} -> + Terms; + Other -> + ?ABORT("Failed to load expected config from ~s: ~p\n", + [ReltoolFile, Other]) + end. + +%% +%% Look for the {sys, [...]} tuple in the reltool.config file. +%% Without this present, we can't run reltool. +%% +get_sys_tuple(ReltoolConfig) -> + case lists:keyfind(sys, 1, ReltoolConfig) of + {sys, _} = SysTuple -> + SysTuple; + false -> + ?ABORT("Failed to find {sys, [...]} tuple in reltool.config.", []) + end. + +%% +%% Look for {target_dir, TargetDir} in the reltool config file; if none is +%% found, use the name of the release as the default target directory. +%% +get_target_dir(ReltoolConfig) -> + case rebar_config:get_global(target_dir, undefined) of + undefined -> + case lists:keyfind(target_dir, 1, ReltoolConfig) of + {target_dir, TargetDir} -> + filename:absname(TargetDir); + false -> + {sys, SysInfo} = get_sys_tuple(ReltoolConfig), + case lists:keyfind(rel, 1, SysInfo) of + {rel, Name, _Vsn, _Apps} -> + filename:absname(Name); + false -> + filename:absname("target") + end + end; + TargetDir -> + filename:absname(TargetDir) + end. + +get_target_parent_dir(ReltoolConfig) -> + case lists:reverse(tl(lists:reverse(filename:split(get_target_dir(ReltoolConfig))))) of + [] -> "."; + Components -> filename:join(Components) + end. + %% =================================================================== %% Internal functions %% =================================================================== diff --git a/src/rebar_reltool.erl b/src/rebar_reltool.erl index 72bfe49..b1b4a4c 100644 --- a/src/rebar_reltool.erl +++ b/src/rebar_reltool.erl @@ -42,14 +42,16 @@ generate(Config, ReltoolFile) -> check_vsn(), %% Load the reltool configuration from the file - ReltoolConfig = load_config(ReltoolFile), + ReltoolConfig = rebar_rel_utils:load_config(ReltoolFile), + + Sys = rebar_rel_utils:get_sys_tuple(ReltoolConfig), %% Spin up reltool server and load our config into it - {ok, Server} = reltool:start_server([sys_tuple(ReltoolConfig)]), + {ok, Server} = reltool:start_server([Sys]), %% Do some validation of the reltool configuration; error messages out of %% reltool are still pretty cryptic - validate_rel_apps(Server, sys_tuple(ReltoolConfig)), + validate_rel_apps(Server, Sys), %% Finally, run reltool case catch(run_reltool(Server, Config, ReltoolConfig)) of @@ -64,8 +66,8 @@ generate(Config, ReltoolFile) -> clean(_Config, ReltoolFile) -> - ReltoolConfig = load_config(ReltoolFile), - TargetDir = target_dir(ReltoolConfig), + ReltoolConfig = rebar_rel_utils:load_config(ReltoolFile), + TargetDir = rebar_rel_utils:get_target_dir(ReltoolConfig), rebar_file_utils:rm_rf(TargetDir), rebar_file_utils:delete_each(["reltool.spec"]). @@ -91,53 +93,6 @@ check_vsn() -> end end. -%% -%% Load terms from reltool.config -%% -load_config(ReltoolFile) -> - case file:consult(ReltoolFile) of - {ok, Terms} -> - Terms; - Other -> - ?ABORT("Failed to load expected config from ~s: ~p\n", - [ReltoolFile, Other]) - end. - -%% -%% Look for the {sys, [...]} tuple in the reltool.config file. -%% Without this present, we can't run reltool. -%% -sys_tuple(ReltoolConfig) -> - case lists:keyfind(sys, 1, ReltoolConfig) of - {sys, _} = SysTuple -> - SysTuple; - false -> - ?ABORT("Failed to find {sys, [...]} tuple in reltool.config.", []) - end. - -%% -%% Look for {target_dir, TargetDir} in the reltool config file; if none is -%% found, use the name of the release as the default target directory. -%% -target_dir(ReltoolConfig) -> - case rebar_config:get_global(target_dir, undefined) of - undefined -> - case lists:keyfind(target_dir, 1, ReltoolConfig) of - {target_dir, TargetDir} -> - filename:absname(TargetDir); - false -> - {sys, SysInfo} = sys_tuple(ReltoolConfig), - case lists:keyfind(rel, 1, SysInfo) of - {rel, Name, _Vsn, _Apps} -> - filename:absname(Name); - false -> - filename:absname("target") - end - end; - TargetDir -> - filename:absname(TargetDir) - end. - %% %% Look for overlay_vars file reference. If the user provides an overlay_vars on %% the command line (i.e. a global), the terms from that file OVERRIDE the one @@ -203,7 +158,7 @@ run_reltool(Server, _Config, ReltoolConfig) -> case reltool:get_target_spec(Server) of {ok, Spec} -> %% Pull the target dir and make sure it exists - TargetDir = target_dir(ReltoolConfig), + TargetDir = rebar_rel_utils:get_target_dir(ReltoolConfig), mk_target_dir(TargetDir), %% Dump the spec, if necessary diff --git a/src/rebar_upgrade.erl b/src/rebar_upgrade.erl index 0bf0338..009715e 100644 --- a/src/rebar_upgrade.erl +++ b/src/rebar_upgrade.erl @@ -38,29 +38,34 @@ 'generate-upgrade'(_Config, ReltoolFile) -> %% Get the old release path - OldVerPath = rebar_rel_utils:get_previous_release_path(), + ReltoolConfig = rebar_rel_utils:load_config(ReltoolFile), + TargetParentDir = rebar_rel_utils:get_target_parent_dir(ReltoolConfig), + TargetDir = rebar_rel_utils:get_target_dir(ReltoolConfig), + + OldVerPath = filename:join([TargetParentDir, + rebar_rel_utils:get_previous_release_path()]), %% Run checks to make sure that building a package is possible - {NewName, NewVer} = run_checks(OldVerPath, ReltoolFile), + {NewVerPath, NewName, NewVer} = run_checks(OldVerPath, ReltoolConfig), NameVer = NewName ++ "_" ++ NewVer, %% Save the code path prior to doing anything OrigPath = code:get_path(), %% Prepare the environment for building the package - ok = setup(OldVerPath, NewName, NewVer, NameVer), + ok = setup(OldVerPath, NewVerPath, NewName, NewVer, NameVer), %% Build the package run_systools(NameVer, NewName), %% Boot file changes - {ok, _} = boot_files(NewVer, NewName), + {ok, _} = boot_files(TargetDir, NewVer, NewName), %% Extract upgrade and tar it back up with changes make_tar(NameVer), %% Clean up files that systools created - ok = cleanup(NameVer, NewName, NewVer), + ok = cleanup(NameVer), %% Restore original path true = code:set_path(OrigPath), @@ -71,18 +76,19 @@ %% Internal functions %% ================================================================== -run_checks(OldVerPath, ReltoolFile) -> +run_checks(OldVerPath, ReltoolConfig) -> true = rebar_utils:prop_check(filelib:is_dir(OldVerPath), "Release directory doesn't exist (~p)~n", [OldVerPath]), - {Name, Ver} = rebar_rel_utils:get_reltool_release_info(ReltoolFile), + {Name, Ver} = rebar_rel_utils:get_reltool_release_info(ReltoolConfig), - NamePath = filename:join([".", Name]), - true = rebar_utils:prop_check(filelib:is_dir(NamePath), - "Release directory doesn't exist (~p)~n", [NamePath]), + NewVerPath = filename:join([ + rebar_rel_utils:get_target_parent_dir(ReltoolConfig), + Name]), + true = rebar_utils:prop_check(filelib:is_dir(NewVerPath), + "Release directory doesn't exist (~p)~n", [NewVerPath]), - {NewName, NewVer} = NewNameAndVer = - rebar_rel_utils:get_rel_release_info(Name, NamePath), + {NewName, NewVer} = rebar_rel_utils:get_rel_release_info(Name, NewVerPath), {OldName, OldVer} = rebar_rel_utils:get_rel_release_info(Name, OldVerPath), true = rebar_utils:prop_check(NewName == OldName, @@ -94,11 +100,10 @@ run_checks(OldVerPath, ReltoolFile) -> true = rebar_utils:prop_check(Ver == NewVer, "Reltool and .rel versions do not match~n", []), - NewNameAndVer. + {NewVerPath, NewName, NewVer}. -setup(OldVerPath, NewName, NewVer, NameVer) -> - NewRelPath = filename:join([".", NewName]), - Src = filename:join([NewRelPath, "releases", +setup(OldVerPath, NewVerPath, NewName, NewVer, NameVer) -> + Src = filename:join([NewVerPath, "releases", NewVer, NewName ++ ".rel"]), Dst = filename:join([".", NameVer ++ ".rel"]), {ok, _} = file:copy(Src, Dst), @@ -108,9 +113,9 @@ setup(OldVerPath, NewName, NewVer, NameVer) -> "releases", "*"])), filelib:wildcard(filename:join([OldVerPath, "lib", "*", "ebin"])), - filelib:wildcard(filename:join([NewRelPath, + filelib:wildcard(filename:join([NewVerPath, "lib", "*", "ebin"])), - filelib:wildcard(filename:join([NewRelPath, "*"])) + filelib:wildcard(filename:join([NewVerPath, "*"])) ])). run_systools(NewVer, Name) -> @@ -135,30 +140,35 @@ run_systools(NewVer, Name) -> end end. -boot_files(Ver, Name) -> - ok = file:make_dir(filename:join([".", "releases"])), - ok = file:make_dir(filename:join([".", "releases", Ver])), +boot_files(TargetDir, Ver, Name) -> + Tmp = "_tmp", + ok = file:make_dir(filename:join([".", Tmp])), + ok = file:make_dir(filename:join([".", Tmp, "releases"])), + ok = file:make_dir(filename:join([".", Tmp, "releases", Ver])), ok = file:make_symlink( filename:join(["start.boot"]), - filename:join([".", "releases", Ver, Name ++ ".boot"])), + filename:join([".", Tmp, "releases", Ver, Name ++ ".boot"])), {ok, _} = file:copy( - filename:join([".", Name, "releases", Ver, "start_clean.boot"]), - filename:join([".", "releases", Ver, "start_clean.boot"])). + filename:join([TargetDir, "releases", Ver, "start_clean.boot"]), + filename:join([".", Tmp, "releases", Ver, "start_clean.boot"])). make_tar(NameVer) -> Filename = NameVer ++ ".tar.gz", - ok = erl_tar:extract(Filename, [compressed]), - ok = file:delete(Filename), - {ok, Tar} = erl_tar:open(Filename, [write, compressed]), + {ok, Cwd} = file:get_cwd(), + Absname = filename:join([Cwd, Filename]), + ok = file:set_cwd("_tmp"), + ok = erl_tar:extract(Absname, [compressed]), + ok = file:delete(Absname), + {ok, Tar} = erl_tar:open(Absname, [write, compressed]), ok = erl_tar:add(Tar, "lib", []), ok = erl_tar:add(Tar, "releases", []), ok = erl_tar:close(Tar), + ok = file:set_cwd(Cwd), ?CONSOLE("~s upgrade package created~n", [NameVer]). -cleanup(NameVer, Name, Ver) -> +cleanup(NameVer) -> ?DEBUG("Removing files needed for building the upgrade~n", []), Files = [ - filename:join([".", "releases", Ver, Name ++ ".boot"]), filename:join([".", NameVer ++ ".rel"]), filename:join([".", NameVer ++ ".boot"]), filename:join([".", NameVer ++ ".script"]), @@ -166,18 +176,17 @@ cleanup(NameVer, Name, Ver) -> ], lists:foreach(fun(F) -> ok = file:delete(F) end, Files), - ok = remove_dir_tree("releases"), - ok = remove_dir_tree("lib"). + ok = remove_dir_tree("_tmp"). -%% taken from http://www.erlang.org/doc/system_principles/create_target.html +%% adapted from http://www.erlang.org/doc/system_principles/create_target.html remove_dir_tree(Dir) -> remove_all_files(".", [Dir]). remove_all_files(Dir, Files) -> lists:foreach(fun(File) -> FilePath = filename:join([Dir, File]), - {ok, FileInfo} = file:read_file_info(FilePath), - case FileInfo#file_info.type of - directory -> + {ok, FileInfo, Link} = file_info(FilePath), + case {Link, FileInfo#file_info.type} of + {false, directory} -> {ok, DirFiles} = file:list_dir(FilePath), remove_all_files(FilePath, DirFiles), file:del_dir(FilePath); @@ -185,3 +194,14 @@ remove_all_files(Dir, Files) -> file:delete(FilePath) end end, Files). + +file_info(Path) -> + case file:read_file_info(Path) of + {ok, Info} -> + {ok, Info, false}; + {error, enoent} -> + {ok, Info} = file:read_link_info(Path), + {ok, Info, true}; + Error -> + Error + end.